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); } }
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; }