Пример #1
0
        /// <summary>Stop the subscription</summary>
        public async Task Stop()
        {
            // Stop if in the running state
            if (State != EState.Running && State != EState.Starting)
            {
                return;
            }

            try
            {
                // Only disconnect from the same web socket
                if (WebSocket == null || WebSocket != Api.WebSocket)
                {
                    return;
                }

                // Disconnect if open
                if (WebSocket.State == WebSocketState.Open && ChannelId != null)
                {
                    // Send the unsubscribe request
                    State = EState.Stopping;
                    var json_request = UnsubscribeRequest();
                    using (Task_.NoSyncContext())
                        await Api.WebSocket.SendAsync(json_request, Api.Shutdown);
                }
            }
            catch
            {
                State = EState.Initial;
                throw;
            }
        }
Пример #2
0
        private void AddTaskButton(object sender, RoutedEventArgs e)
        {
            if (NameOfTaskTB.Text == "" || TypeComboBox.Text == "" || DueDateOfTaskDP.SelectedDate == null ||
                EndDateOfTaskDP.SelectedDate == null)
            {
                MessageBox.Show("Please enter all information");
            }
            else
            {
                bool     reocurring = false;
                string   taskName   = NameOfTaskTB.Text;
                string   type       = Convert.ToString(TypeComboBox.Text);
                DateTime dueDate    = (DateTime)DueDateOfTaskDP.SelectedDate;
                DateTime endDate    = (DateTime)EndDateOfTaskDP.SelectedDate;

                if (YesRB.IsChecked == true)
                {
                    reocurring = true;
                }

                Task_ task = new Task_(taskName, type, reocurring, dueDate, endDate);
                student.AddTask(task);
                FileReadWrite file = new FileReadWrite();
                file.AddTaskToFile(student, task);
                homeScreen home = new homeScreen(student);

                this.Close();
                home.Show();
            }
        }
Пример #3
0
        private void editTaskCB_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            index      = editTaskCB.SelectedIndex;
            reocurring = student.TaskList[index].ReoccuringTask;

            NameOfTaskTB.Text            = student.TaskList[index].TaskName;
            TypeComboBox.SelectedItem    = student.TaskList[index].Type;
            DueDateOfTaskDP.SelectedDate = student.TaskList[index].DueDate;
            EndDateOfTaskDP.SelectedDate = student.TaskList[index].DueDateEnd;
            if (reocurring)
            {
                YesRB.IsChecked = true;
            }
            else
            {
                NoRB.IsChecked = true;
            }

            if (YesRB.IsChecked == true)
            {
                reocurring = true;
            }
            else
            {
                reocurring = false;
            }

            for (int i = 0; i < student.TaskList.Count; i++)
            {
                if (student.TaskList[i].TaskName == NameOfTaskTB.Text)
                {
                    oldTask = student.TaskList[i];
                }
            }
        }
Пример #4
0
        /// <summary>Subscribe to the channel. Must be called when an open web socket connection is available</summary>
        public async Task Start()
        {
            if (State != EState.Initial)
            {
                throw new Exception($"Cannot start a subscription from state: {State}");
            }

            // Prevent duplicate subscriptions
            await Stop();

            try
            {
                // Record the web socket used to subscribe with.
                WebSocket = Api.WebSocket;
                if (WebSocket?.State == WebSocketState.Open)
                {
                    // Send the subscription request
                    State = EState.Starting;
                    var json_request = SubscribeRequest();
                    using (Task_.NoSyncContext())
                        await WebSocket.SendAsync(json_request, Api.Shutdown);
                }
            }
            catch
            {
                State = EState.Initial;
                throw;
            }
        }
Пример #5
0
        private void save_task_button(object sender, RoutedEventArgs e)
        {
            if (NameOfTaskTB.Text == "" || TypeComboBox.Text == "" || DueDateOfTaskDP.SelectedDate == null ||
                EndDateOfTaskDP.SelectedDate == null)
            {
                MessageBox.Show("Please enter all information");
            }
            else
            {
                string        taskName = NameOfTaskTB.Text;
                string        type     = Convert.ToString(TypeComboBox.Text);
                DateTime      dueDate  = (DateTime)DueDateOfTaskDP.SelectedDate;
                DateTime      endDate  = (DateTime)EndDateOfTaskDP.SelectedDate;
                FileReadWrite file     = new FileReadWrite();


                Task_ editTask = new Task_(taskName, type, reocurring, dueDate, endDate);

                student.TaskList[index] = editTask;
                file.EditTaskToFile(student, editTask, oldTask);
                homeScreen hs = new homeScreen(student);
                this.Close();
                hs.Show();
            }
        }
Пример #6
0
        private void ShowListTask()
        {
            Task_        list     = new Task_();
            List <Tasks> taskList = list.FindTask();

            foreach (var elem in taskList)
            {
                var element = new ListViewItem(new string[] { ordinalNumber++.ToString(), elem.Category.CategoryName, elem.Title, elem.Content, elem.CreateDate.ToString(), elem.DateLimit.ToString() });
                listViewTask.Items.Add(element);
            }
        }
Пример #7
0
        public static Task[] FromTSObject(dynamic[] tsArray)
        {
            if (tsArray is null)
            {
                return(null);
            }
            var list = new System.Collections.Generic.List <Task>();

            foreach (var tsItem in tsArray)
            {
                list.Add(Task_.FromTSObject(tsItem));
            }
            return(list.ToArray());
        }
Пример #8
0
        public static dynamic GetTSObject(Task[] dynArray)
        {
            if (dynArray is null)
            {
                return(null);
            }
            var list = new System.Collections.Generic.List <dynamic>();

            foreach (var dynItem in dynArray)
            {
                list.Add(Task_.GetTSObject(dynItem));
            }
            return(list.ToArray());
        }
Пример #9
0
        /// <summary>Helper for POSTs</summary>
        private async Task <JToken> PostData(string method, string command, CancellationToken?cancel, Params parameters = null)
        {
            // If called from the UI thread, disable the SynchronisationContext
            // to prevent deadlocks when waiting for Async results.
            using (Task_.NoSyncContext())
            {
                // Poloniex requires the 'nonce' values to be strictly increasing.
                // That means all POSTs must be serialised to avoid a race condition
                // when POSTing two messages in quick succession.
                var cancel_token = CancellationTokenSource.CreateLinkedTokenSource(Shutdown, cancel ?? CancellationToken.None).Token;
                using (RequestThrottle.Lock(cancel_token))                 // Limit requests to the required rate
                {
                    await RequestThrottle.Wait(cancel_token);

                    // Add the command parameter
                    parameters            = parameters ?? new Params();
                    parameters["command"] = command;
                    parameters["nonce"]   = Misc.Nonce;

                    // Create the content to POST
                    var post_data_string = Http_.UrlEncode(parameters).TrimStart('?');
                    var content          = new StringContent(post_data_string, Encoding.UTF8, "application/x-www-form-urlencoded");
                    var msg_hash         = Hasher.ComputeHash(Encoding.UTF8.GetBytes(post_data_string));
                    var signature        = Misc.ToStringHex(msg_hash);
                    content.Headers.Add("Sign", signature);

                    var url = $"{Client.BaseAddress}{method}{Http_.UrlEncode(parameters)}";

                    // Submit the request
                    // Result Codes:
                    //  - 422 Un-processable Entity:
                    //    Status code is directly reported by Poloniex server. It means the server understands the content type of the request entity,
                    //    and the syntax of the request entity is correct, but was unable to process the contained instructions.
                    var response = await Client.PostAsync(url, content, cancel_token);

                    if (!response.IsSuccessStatusCode)
                    {
                        throw new HttpException((int)response.StatusCode, response.ReasonPhrase);
                    }

                    // Interpret the reply
                    var reply = await response.Content.ReadAsStringAsync();

                    return(JToken.Parse(reply));
                }
            }
        }
Пример #10
0
 private void delete_button_Click(object sender, RoutedEventArgs e)
 {
     if (deleteCB.SelectedItem == null)
     {
         MessageBox.Show("Please select an item to delete.");
     }
     else
     {
         FileReadWrite file = new FileReadWrite();
         oldTask = student.TaskList[deleteCB.SelectedIndex];
         student.DeleteTask(deleteCB.SelectedIndex);
         file.DeleteTaskToFile(student, oldTask);
         homeScreen hs = new homeScreen(student);
         this.Close();
         hs.Show();
     }
 }
Пример #11
0
        /// <summary>Helper for GETs</summary>
        private async Task <JToken> GetData(string method, string command, CancellationToken?cancel, Params parameters = null)
        {
            // If called from the UI thread, disable the SynchronisationContext
            // to prevent deadlocks when waiting for Async results.
            using (Task_.NoSyncContext())
            {
                var cancel_token = CancellationTokenSource.CreateLinkedTokenSource(Shutdown, cancel ?? CancellationToken.None).Token;
                using (RequestThrottle.Lock(cancel_token))                 // Limit requests to the required rate
                {
                    await RequestThrottle.Wait(cancel_token);

                    // Add the API key for non-public methods
                    parameters = parameters ?? new Params();
                    if (method != Method.Public)
                    {
                        parameters["apikey"] = Key;
                        parameters["nonce"]  = Misc.Nonce;
                    }

                    // Create the URL for the command + parameters
                    var url = $"{UrlRestAddress}api/v1.1/{method}/{command}{Http_.UrlEncode(parameters)}";

                    // Construct the GET request
                    var req = new HttpRequestMessage(HttpMethod.Get, url);
                    if (method != Method.Public)
                    {
                        var hash = Hasher.ComputeHash(Encoding.UTF8.GetBytes(url));
                        req.Headers.Add("apisign", Misc.ToStringHex(hash));
                    }

                    // Submit the request
                    var response = await Client.SendAsync(req, cancel_token);

                    if (!response.IsSuccessStatusCode)
                    {
                        throw new HttpException((int)response.StatusCode, response.ReasonPhrase);
                    }

                    // Interpret the reply
                    var reply = await response.Content.ReadAsStringAsync();

                    return(JToken.Parse(reply));
                }
            }
        }
Пример #12
0
        /// <summary>Helper for GETs</summary>
        private async Task <JToken> GetData(string method, string command, CancellationToken?cancel, Params parameters = null)
        {
            // If called from the UI thread, disable the SynchronisationContext
            // to prevent deadlocks when waiting for Async results.
            using (Task_.NoSyncContext())
            {
                // Poloniex requires the 'nonce' values to be strictly increasing.
                // That means all POSTs must be serialised to avoid a race condition
                // when POSTing two messages in quick succession.
                var cancel_token = CancellationTokenSource.CreateLinkedTokenSource(Shutdown, cancel ?? CancellationToken.None).Token;
                using (RequestThrottle.Lock(cancel_token))                 // Limit requests to the required rate
                {
                    await RequestThrottle.Wait(cancel_token);

                    // Add the command to the parameters
                    parameters            = parameters ?? new Params();
                    parameters["command"] = command;

                    // Create the URL for the command + parameters
                    var url = $"{UrlRestAddress}{method}{Http_.UrlEncode(parameters)}";

                    // Submit the request
                    var response = await Client.GetAsync(url, cancel_token);

                    if (!response.IsSuccessStatusCode)
                    {
                        throw new HttpException((int)response.StatusCode, response.ReasonPhrase);
                    }

                    // Interpret the reply
                    var reply = await response.Content.ReadAsStringAsync();

                    return(JToken.Parse(reply));
                }
            }
        }
Пример #13
0
        /// <summary>Helper for GETs</summary>
        private async Task <JToken> GetData(HttpMethod method, ESecurityType security, string command, CancellationToken?cancel, Params parameters = null, bool timestamp = false, bool log_trace = false)
        {
            // If called from the UI thread, disable the SynchronisationContext
            // to prevent deadlocks when waiting for Async results.
            using (Task_.NoSyncContext())
            {
                // Poloniex requires the 'nonce' values to be strictly increasing.
                // That means all POSTs must be serialised to avoid a race condition
                // when POSTing two messages in quick succession.
                var cancel_token = CancellationTokenSource.CreateLinkedTokenSource(Shutdown, cancel ?? CancellationToken.None).Token;
                using (RequestThrottle.Lock(cancel_token))                 // Limit requests to the required rate
                {
                    await RequestThrottle.Wait(cancel_token);

                    // Add fields to the request based on 'security'
                    parameters = parameters ?? new Params();
                    if (timestamp)
                    {
                        // Needs to be added after waiting on the throttle
                        parameters["timestamp"] = RequestTimestamp;
                    }
                    if (security == ESecurityType.TRADE || security == ESecurityType.USER_DATA)
                    {
                        var query_string = Http_.UrlEncode(parameters).TrimStart('?');
                        var hash         = Hasher.ComputeHash(Encoding.UTF8.GetBytes(query_string));
                        parameters["signature"] = Misc.ToStringHex(hash);
                    }

                    // Create the request
                    var url = $"{UrlRestAddress}{command}{Http_.UrlEncode(parameters)}";
                    var req = new HttpRequestMessage(method, url);
                    if (security == ESecurityType.TRADE || security == ESecurityType.USER_DATA || security == ESecurityType.USER_STREAM || security == ESecurityType.MARKET_DATA)
                    {
                        req.Headers.Add("X-MBX-APIKEY", Key);
                    }

                    if (log_trace)
                    {
                        Log.Write(ELogLevel.Debug, req.ToString());
                    }

                    // Submit the request
                    var sw       = new Stopwatch().StartNow();
                    var response = await Client.SendAsync(req, cancel_token);

                    var reply = await response.Content.ReadAsStringAsync();

                    Log.Write(ELogLevel.Debug, $"Req time: {sw.Elapsed.ToPrettyString(min_unit: TimeSpan_.ETimeUnits.Milliseconds)} - {url}");

                    if (log_trace)
                    {
                        Log.Write(ELogLevel.Debug, reply.ToString());
                    }

                    // Check the API usage weight
                    if (response.Headers.TryGetValues("X-MBX-USED-WEIGHT", out var weights))
                    {
                        RequestThrottle.UsedWeight = long.Parse(weights.First());
                        if (RequestThrottle.UsedWeight > 0.5 * RequestThrottle.WeightLimit)
                        {
                            Debug.Assert(false);
                        }
                    }

                    // Interpret the reply
                    if (!response.IsSuccessStatusCode)
                    {
                        // Check for an error
                        var jobj = reply != null?JObject.Parse(reply) : null;

                        if (jobj != null &&
                            jobj["code"]?.Value <int>() is int code &&
                            jobj["msg"]?.Value <string>() is string msg)
                        {
                            throw new BinanceException((EErrorCode)code, msg);
                        }
                        else
                        {
                            throw new HttpException((int)response.StatusCode, response.ReasonPhrase);
                        }
                    }

                    return(JToken.Parse(reply));
                }
            }
Пример #14
0
        /// <summary>
        /// Determine if executing trades in 'loop' should result in a profit.
        /// Returns true if profitable and a copy of this loop in 'loop'</summary>
        public bool IsProfitable(bool forward, Fund fund, out Loop loop)
        {
            // How to think about this:
            // - We want to see what happens if we convert some currency to each of the coins
            //   in the loop, ending up back at the initial currency. If the result is more than
            //   we started with, then it's a profitable loop.
            // - We can go in either direction around the loop.
            // - We want to execute each trade around a profitable loop at the same time, so we're
            //   limited to the smallest balance for the coins in the loop.
            // - The rate by volume does not depend on our account balance. We calculate the effective
            //   rate at each of the offered volumes then determine if any of those volumes are profitable
            //   and whether we have enough balance for the given volumes.
            // - The 'Bid' table contains the amounts of base currency people want to buy, ordered by price.
            // - The 'Ask' table contains the amounts of base currency people want to sell, ordered by price.
            loop = null;

            // Construct an "order book" of volumes and complete-loop prices (e.g. BTC to BTC price for each volume)
            var dir  = forward ? +1 : -1;
            var coin = forward ? Beg : End;
            var tt   = forward ? ETradeType.B2Q : ETradeType.Q2B;
            var obk  = new OrderBook(coin, coin, tt)
            {
                new Offer(1m, decimal.MaxValue._(coin.Symbol))
            };

            foreach (var pair in EnumPairs(dir))
            {
                // Limit the volume calculated, there's no point in calculating large volumes if we can't trade them
                Unit <decimal> bal = 0m;
                OrderBook      b2q = null, q2b = null;
                using (Task_.NoSyncContext())
                {
                    Misc.RunOnMainThread(() =>
                    {
                        bal = coin.Balances[fund].Available;
                        b2q = new OrderBook(pair.MarketDepth.B2Q);
                        q2b = new OrderBook(pair.MarketDepth.Q2B);
                    }).Wait();
                }

                // Note: the trade prices are in quote currency
                if (pair.Base == coin)
                {
                    obk = MergeRates(obk, b2q, bal, invert: false);
                }
                else if (pair.Quote == coin)
                {
                    obk = MergeRates(obk, q2b, bal, invert: true);
                }
                else
                {
                    throw new Exception($"Pair {pair} does not include Coin {coin}. Loop is invalid.");
                }

                // Get the next coin in the loop
                coin = pair.OtherCoin(coin);
            }
            if (obk.Count == 0)
            {
                return(false);
            }

            // Save the best profit ratio for this loop (as an indication)
            if (forward)
            {
                ProfitRatioFwd = obk[0].PriceQ2B;
            }
            else
            {
                ProfitRatioBck = obk[0].PriceQ2B;
            }

            // Look for any volumes that have a nett gain
            var amount_gain = obk.Where(x => x.PriceQ2B > 1).Sum(x => x.PriceQ2B * x.AmountBase);

            if (amount_gain == 0)
            {
                return(false);
            }

            // Create a copy of the loop for editing (with the direction set)
            loop = new Loop(this, obk, dir);

            // Find the maximum profitable volume to trade
            var amount = 0m._(loop.Beg);

            foreach (var ordr in loop.Rate.Where(x => x.PriceQ2B > 1))
            {
                amount += ordr.AmountBase;
            }

            // Calculate the effective fee in initial coin currency.
            // Do all trades assuming no fee, but accumulate the fee separately
            var fee            = 0m._(loop.Beg);
            var initial_volume = amount;

            // Trade each pair in the loop (in the given direction) to check
            // that the trade is still profitable after fees. Record each trade
            // so that we can determine the trade scale
            coin = loop.Beg;
            var trades = new List <Trade>();

            foreach (var pair in loop.EnumPairs(loop.Direction))
            {
                // If we trade 'volume' using 'pair' that will result in a new volume
                // in the new currency. There will also be a fee charged (in quote currency).
                // If we're trading to quote currency, the new volume is reduced by the fee.
                // If we're trading to base currency, the cost is increased by the fee.

                // Calculate the result of the trade
                var new_coin = pair.OtherCoin(coin);
                var trade    = pair.Base == coin
                                        ? pair.BaseToQuote(fund, amount)
                                        : pair.QuoteToBase(fund, amount);

                // Record the trade amount.
                trades.Add(trade);

                // Convert the fee so far to the new coin using the effective rate,
                // and add on the fee for this trade.
                var rate = trade.AmountOut / trade.AmountIn;
                fee = fee * rate + trade.AmountOut * pair.Fee;

                // Advance to the next pair
                coin   = new_coin;
                amount = trade.AmountOut;
            }

            // Record the volume to trade, the scale, and the expected profit.
            // If the new volume is greater than the initial volume, WIN!
            // Update the profitability of the loop now we've accounted for fees.
            loop.TradeScale   = 1m;
            loop.Tradeability = string.Empty;
            loop.TradeVolume  = initial_volume;
            loop.Profit       = (amount - fee) - initial_volume;
            if (forward)
            {
                loop.ProfitRatioFwd = ProfitRatioFwd = (amount - fee) / initial_volume;
            }
            else
            {
                loop.ProfitRatioBck = ProfitRatioBck = (amount - fee) / initial_volume;
            }
            if (loop.ProfitRatio <= 1m)
            {
                return(false);
            }

            // Determine the trade scale based on the available balances
            foreach (var trade in trades)
            {
                var pair = trade.Pair;

                // Get the balance available for this trade and determine a trade scaling factor.
                // Increase the required volume to allow for the fee
                // Reduce the available balance slightly to deal with rounding errors
                var bal   = trade.CoinIn.Balances[fund].Available * 0.999m;
                var req   = trade.AmountIn * (1 + pair.Fee);
                var scale = Math_.Clamp((decimal)(bal / req), 0m, 1m);
                if (scale < loop.TradeScale)
                {
                    loop.TradeScale   = Math_.Clamp(scale, 0, loop.TradeScale);
                    loop.LimitingCoin = trade.CoinIn;
                }
            }

            // Check that all traded volumes are within the limits
            var all_trades_valid = EValidation.Valid;

            foreach (var trade in trades)
            {
                // Check the unscaled amount, if that's too small we'll ignore this loop
                var validation0 = trade.Validate();
                all_trades_valid |= validation0;

                // Record why the base trade isn't valid
                if (validation0 != EValidation.Valid)
                {
                    loop.Tradeability += $"{trade.Description} - {validation0}\n";
                }

                // If the volume to trade, multiplied by the trade scale, is outside the
                // allowed range of trading volume, set the scale to zero. This is to prevent
                // loops being traded where part of the loop would be rejected.
                var validation1 = new Trade(trade, loop.TradeScale).Validate();
                if (validation1.HasFlag(EValidation.AmountInOutOfRange))
                {
                    loop.Tradeability += $"Not enough {trade.CoinIn} to trade\n";
                }
                if (validation1.HasFlag(EValidation.AmountOutOutOfRange))
                {
                    loop.Tradeability += $"Trade result volume of {trade.CoinOut} is too small\n";
                }
                if (validation1 != EValidation.Valid)
                {
                    loop.TradeScale = 0m;
                }
            }

            // Return the profitable loop (even if scaled to 0)
            return(all_trades_valid == EValidation.Valid);
        }
Пример #15
0
 /// <summary>Shutdown async</summary>
 public Task ShutdownAsync()
 {
     Running = false;
     return(Task_.WaitWhile(() => Running));
 }