예제 #1
0
        public async Task <BinanceExchangeInfo> GetAvailableSymbols()
        {
            using (var httpClient = new HttpClient())
            {
                BinanceExchangeInfo exchangeInfo = new BinanceExchangeInfo();
                HttpRequestMessage  request      = new HttpRequestMessage(HttpMethod.Get, binanceExchInfo);
                HttpResponseMessage response     = await httpClient.SendAsync(request);

                if (response.IsSuccessStatusCode)
                {
                    var responseStr = await response.Content.ReadAsStringAsync();

                    exchangeInfo = JsonConvert.DeserializeObject <BinanceExchangeInfo>(responseStr);
                }

                return(exchangeInfo);
            }
        }
예제 #2
0
        public async Task CollectStreamData(bool bestPricesForTopCurrencies, bool bookTickers, bool userStreamUpdates, bool continuousKlines,
                                            int initMarketDataLimit,
                                            string quoteAsset = "USDT", List <string> symbols = null)
        {
            if (IsCollectingStreams)
            {
                return;
            }

            using (var wsClient = new ClientWebSocket())
            {
                try
                {
                    IsWholeMarketDataInitialized   = false;
                    IsWholeMarketKlinesInitialized = false;
                    string        channelsUrl = null;
                    List <string> usedSymbols = null;



                    if (symbols == null || symbols.Count == 0)
                    {
                        //IsScanningIndividualMiniTickers = false;
                        //channelsUrl = bestPricesForTopCurrencies && bookTickers ? "!miniTicker@arr/!bookTicker"
                        //    : bestPricesForTopCurrencies ? "!miniTicker@arr"
                        //    : bookTickers ? "!bookTicker" : null;

                        BinanceExchangeInfo exchInfo = await GetAvailableSymbols();

                        usedSymbols = exchInfo.Symbols.Where(s => s.QuoteAsset == quoteAsset && s.ContractType == "PERPETUAL")
                                      .Select(s => $"{s.BaseAsset.ToLower()}{s.QuoteAsset.ToLower()}").ToList();
                    }
                    else
                    {
                        usedSymbols = symbols;
                        //IsScanningIndividualMiniTickers = true;
                    }

                    string miniTickersUrl = string.Join("/", symbols.Select(s => $"{s.ToLower()}@miniTicker"));
                    string bookTickersUrl = string.Join("/", symbols.Select(s => $"{s.ToLower()}@bookTicker"));
                    string klinesUrl      = string.Join("/", symbols.Select(s => $"{s.ToLower()}_perpetual@continuousKline_1m"));

                    var channelsUrls = new List <string>();
                    if (bestPricesForTopCurrencies)
                    {
                        channelsUrls.Add(miniTickersUrl);
                    }
                    if (bookTickers)
                    {
                        channelsUrls.Add(bookTickersUrl);
                    }
                    if (continuousKlines)
                    {
                        channelsUrls.Add(klinesUrl);
                    }

                    channelsUrl = string.Join("/", channelsUrls);


                    string listenKey = null;
                    if (userStreamUpdates)
                    {
                        listenKey = await GetListenKey();

                        channelsUrl += $"{(!string.IsNullOrEmpty(channelsUrl) ? "/" : string.Empty)}{listenKey}";
                    }



                    if (channelsUrl == null)
                    {
                        return;
                    }

                    if (bestPricesForTopCurrencies)
                    {
                        await InitializeWholeMarketData(usedSymbols, initMarketDataLimit);

                        IsWholeMarketDataInitialized = true;
                    }

                    if (continuousKlines)
                    {
                        await InitializeWholeMarketKlines(usedSymbols, initMarketDataLimit);

                        IsWholeMarketKlinesInitialized = true;
                    }

                    UserStreamUpdates = new List <BinanceUserStreamResponse>();

                    LinesAddedInWholeMarketData = 0;

                    await wsClient.ConnectAsync(new Uri($"{binanceWsUrl}?streams={channelsUrl}"), CancellationToken.None);

                    IsCollectingStreams = true;
                    ArraySegment <byte> pingBuffer   = System.Text.Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(new { ping = "Pong?" }));
                    DateTime            lastPingSent = DateTime.UtcNow;

                    DateTime lastUserStreamPingSent = DateTime.UtcNow;

                    Debug.WriteLine($"Debut collecte données Websocket pour symboles: {string.Join(", ", usedSymbols)}");
                    while (wsClient.State == WebSocketState.Open && IsCollectingStreams)
                    {
                        byte[] streamBuffer           = new byte[_streamBufferSize];
                        WebSocketReceiveResult result = await wsClient.ReceiveAsync(streamBuffer, CancellationToken.None);

                        if (result.EndOfMessage)
                        {
                            string responseJson    = System.Text.Encoding.UTF8.GetString(streamBuffer);
                            var    rawStreamUpdate = JsonConvert.DeserializeObject(responseJson) as JToken;
                            if (rawStreamUpdate["stream"] != null && (Regex.Match(rawStreamUpdate["stream"].ToString(), @"\b\w*_perpetual@continuousKline_1m\b").Success) && continuousKlines)
                            {
                                TreatContinuousKline(rawStreamUpdate["data"].ToString(), usedSymbols);
                            }
                            else if (rawStreamUpdate["stream"] != null && (Regex.Match(rawStreamUpdate["stream"].ToString(), @"\b\w*@miniTicker\b").Success) && bestPricesForTopCurrencies)
                            {
                                TreatBestPricesForTopCurrencies(rawStreamUpdate["data"].ToString(), usedSymbols);
                            }
                            else if (rawStreamUpdate["stream"] != null && (Regex.Match(rawStreamUpdate["stream"].ToString(), @"\b\w*@bookTicker\b").Success) && bookTickers)
                            {
                                TreatRealTimeBookBestAskBids(rawStreamUpdate["data"].ToString());
                            }
                            else if (rawStreamUpdate["stream"] != null && userStreamUpdates && rawStreamUpdate["stream"].ToString() == listenKey)
                            {
                                TreatUserDataUpdates(rawStreamUpdate["data"].ToString());
                            }
                            else
                            {
                                Debug.WriteLine($"A ping frame? {responseJson} \n");
                            }
                        }

                        //if (lastPingSent < DateTime.UtcNow - TimeSpan.FromSeconds(PING_INTERVAL_IN_SEC))
                        //{
                        //    await wsClient.SendAsync(pingBuffer, WebSocketMessageType.Text, true, CancellationToken.None);
                        //    lastPingSent = DateTime.UtcNow;
                        //}

                        var utcNow = DateTime.UtcNow;
                        if (lastUserStreamPingSent < utcNow - TimeSpan.FromMinutes(KEEP_ALIVE_PING_USER_STREAM_DELAY_IN_MINS))
                        {
                            await SendUserStreamPing();

                            lastUserStreamPingSent = DateTime.UtcNow;
                        }
                    }
                    IsCollectingStreams = false;
                }
                catch (Exception ex)
                {
                    Debug.WriteLine($"[{DateTime.UtcNow.ToString("dd-MM-yyyy HH:mm:ss")}]Erreur dans CollectStreamData: {ex.Message}");
                    SendFailedWSMail(ex.Message);
                    //throw ex;
                }
            }
        }
        //public List<SingleAssetPosition> OrdersFilled { get; set; }

        public async Task StartBot()
        {
            CheckBotParameters();

            IsBotRunning = true;
            Debug.WriteLine($"[{DateTime.UtcNow.ToString("dd-MM-yyyy HH:mm:ss")}] Binance MS Bot démarré");

            List <BinanceAccountBalance> accountBalances = await _binanceWsClient.GetAccountBalance();

            InitPortfolioValue = accountBalances.First(x => x.Asset == "USDT").AvailableBalance;
            PortfolioValues    = new List <decimal>();
            PortfolioValues.Add(InitPortfolioValue);
            Debug.WriteLine($"Available balance: {InitPortfolioValue} usdt");
            MarketMeanPrices      = new List <decimal>();
            CumulatedMarketPerf   = 0.0m;
            CumulatedPotfolioPerf = 0.0m;

            PastTransactions = new List <BinanceTransaction>();
            RealisedPNLs     = new List <decimal>();
            OrdersToProcess  = new List <BinanceBotOrder>();

            _binanceWsClient.SetMaxLinesWholeMarketData((_parameters.MovingAveragePeriods + 2) * _parameters.TimeWindowInMin);
            ExchangeInfo = await _binanceWsClient.GetAvailableSymbols();

            _binanceWsClient.UserStreamUpdateReceived += _binanceWsClient_UserStreamUpdateReceived;

            if (!_parameters.DoPlaceMarketOrders)
            {
                _binanceWsClient.NewTickerReceived += _binanceWsClient_NewTickerReceived;
            }

            TradedSymbols = _parameters.TradedSymbols ?? ExchangeInfo.Symbols
                            .Where(s => s.ContractType == "PERPETUAL" && s.QuoteAsset.ToLower() == "usdt")
                            .Select(s => $"{s.BaseAsset.ToLower()}{s.QuoteAsset.ToLower()}").ToList();
            Debug.WriteLine($"Traded symbols: {string.Join(" - ", TradedSymbols)}");

            var task = Task.Run(async() => await _binanceWsClient.CollectStreamData(false, !_parameters.DoPlaceMarketOrders, true, true,
                                                                                    _parameters.TimeWindowInMin * (_parameters.MovingAveragePeriods + 2),
                                                                                    _parameters.QuoteAsset, TradedSymbols));


            CurrentHoldBaseAssetPos = new Dictionary <string, SingleAssetPosition>();
            foreach (var symbol in TradedSymbols)
            {
                CurrentHoldBaseAssetPos.Add(symbol, new SingleAssetPosition
                {
                    Qty           = 0.0m,
                    AvgEntryPrice = 0.0m,
                    Side          = 0
                });
            }


            LastMovingAveragesRatios = new Dictionary <string, IList <decimal?> >();

            CurrRatios = new Dictionary <string, decimal?>();


            IsBurninPeriod     = true;
            NbTradeCycles      = 0;
            LastMinuteTimeMark = 0;

            if (IsBurninPeriod)
            {
                while (!_binanceWsClient.IsWholeMarketKlinesInitialized)
                {
                }

                ActualTradedSymbols = _binanceWsClient.WholeMarketKlines.Keys
                                      .Where(s => Math.Round(_parameters.FixedInvestedQuoteAssetQty / ((decimal)_binanceWsClient.WholeMarketKlines[s].Last().Kline.ClosePrice *(1 - 0.10m) * ((_parameters.MaxTakenRank - _parameters.MinTakenRank) * TradedSymbols.Count + 1)), ExchangeInfo.Symbols.FirstOrDefault(x => x.Symbol.ToLower() == s).QuantityPrecision, MidpointRounding.ToZero) > 0 &&
                                             ((decimal)Math.Pow(10, (-1) * ExchangeInfo.Symbols.FirstOrDefault(x => x.Symbol.ToLower() == s).QuantityPrecision)) * _binanceWsClient.WholeMarketKlines[s].Last().Kline.ClosePrice <= 1m)
                                      .ToList();
                Debug.WriteLine($"ACTUALLY traded symbols: {string.Join(" - ", ActualTradedSymbols)}");


                if (_parameters.Leverage != null)
                {
                    foreach (var tradedSymbol in ActualTradedSymbols)
                    {
                        await _binanceWsClient.ChangeLeverage(tradedSymbol, (int)_parameters.Leverage);
                    }
                }

                IsBurninPeriod = false;
            }

            MinutesSinceLastPosition = -1;
            _binanceWsClient.WholeMarketKlinesUpdated += ComputeRatiosAndTakePosition;
        }