public static IPeriodCode ToPeriodCode(this KlineInterval interval) { switch (interval) { case KlineInterval.OneMinute: return(PeriodCode.MINUTE); case KlineInterval.FiveMinutes: return(PeriodCode.FIVE_MINUTES); case KlineInterval.FifteenMinutes: return(PeriodCode.QUARTER_HOUR); case KlineInterval.ThirtyMinutes: return(PeriodCode.HALF_HOUR); case KlineInterval.OneHour: return(PeriodCode.HOUR); case KlineInterval.FourHour: return(PeriodCode.FOUR_HOUR); case KlineInterval.OneDay: return(PeriodCode.DAY); default: throw new Exception($"Not supported perion {interval.ToString()}"); } }
public static string Convert(KlineInterval interval) { var s = interval.ToString(); StringBuilder sb = new StringBuilder(); sb.Append(s[1]); sb.Append(s[0]); return(sb.ToString()); }
public static bool CandlesAvailable(string symbolName, KlineInterval interval, DateTime wantedStartDate, DateTime wantedEndDate, out DateTime SmallestDateAvailable, out DateTime BiggestDateAvailable, out List <CandleInfo> FoundCandles) { if (wantedEndDate.Date == DateTime.Today.Date) { //endDate = DateTime.Today.Date.AddDays(1); } wantedEndDate = wantedEndDate.ToUniversalTime(); wantedStartDate = wantedStartDate.ToUniversalTime(); var currentDate = DateTime.Now.ToUniversalTime(); var firstDateAVailableInDB = GetFirstCandleDate(symbolName); if (wantedStartDate < firstDateAVailableInDB) { wantedStartDate = firstDateAVailableInDB; } var dt = DBHelper.GetDataTable("SELECT * FROM Candles WHERE Symbol='" + symbolName.ToUpper() + "' AND Interval='" + interval.ToString() + "' order by OpenTime ASC"); var smallestAvailableDate = DateTime.MaxValue; var biggestAvailableDate = DateTime.MinValue; FoundCandles = new List <CandleInfo>(); var openDates = new List <DateTime>(); foreach (DataRow row in dt.Rows) { var tempDate = row["OpenTime"].ToString().ToSqlDateTime(); if (tempDate <= wantedEndDate && tempDate >= wantedStartDate) { openDates.Add(tempDate); FoundCandles.Add(new CandleInfo(symbolName.ToUpper(), float.Parse(row["Open"].ToString()), float.Parse(row["Close"].ToString()), float.Parse(row["High"].ToString()), float.Parse(row["Low"].ToString()), float.Parse(row["Volume"].ToString()), tempDate)); } if (tempDate > biggestAvailableDate) { biggestAvailableDate = tempDate; } if (tempDate < smallestAvailableDate) { smallestAvailableDate = tempDate; } } FoundCandles = FoundCandles.OrderBy(o => o.OpenTime).ToList(); if (dt.Rows.Count == 0) { SmallestDateAvailable = DateTime.MinValue; BiggestDateAvailable = DateTime.MinValue; } else { SmallestDateAvailable = smallestAvailableDate; BiggestDateAvailable = biggestAvailableDate; } bool smallOK = openDates.Count != 0 && smallestAvailableDate <= wantedStartDate; // true bool bigOK = BiggestDateAvailable >= wantedEndDate.MinusKlineInterval(interval); bool noGaps = true; openDates.Sort(); var BINANCE_UPGRADE_DAYS = new List <DateTime>() { new DateTime(2019, 11, 13), new DateTime(2019, 11, 25) }; var lastOpen = DateTime.MinValue; if (openDates.Count > 2) { lastOpen = openDates[0]; for (int i = 1; i < openDates.Count; i++) { var item = openDates[i]; if (item.MinusKlineInterval(interval) != lastOpen && (item - lastOpen).TotalDays > 1) { // more than 1 day of gap = GAP // otherwise we have some binance upgrades, which mean we will NOT get any candles for short spans of time // BOOYA noGaps = false; break; } else { lastOpen = item; } } } if (smallOK && bigOK && openDates.Count != 0 && noGaps == true) // && openDates.First().Date == startDate.Date&& openDates.Last().Date >= endDate.MinusKlineInterval(interval) { return(true); } else { return(false); } return(smallOK && bigOK && openDates.Count != 0); }
public static void RetrieveCandles(string symbolName, KlineInterval interval, DateTime startDate, DateTime endDate) { startDate = startDate.AddDays(-1); endDate = endDate.AddDays(1); startDate = startDate.ToUniversalTime(); endDate = endDate.ToUniversalTime(); //endDate = DateTime.Today.AddDays(1); // ALWAYS get until the end. Hack but good hack DateTime smallestDateAvailable = DateTime.MinValue; DateTime biggestDateAvailable = DateTime.MinValue; List <CandleInfo> allAvailableCandles = null; if (CandlesAvailable(symbolName, interval, startDate, endDate, out smallestDateAvailable, out biggestDateAvailable, out allAvailableCandles)) { // we have all the candles we needdadad return; } var tempFirstDate = CandleHelper.GetFirstCandleDate(symbolName.ToUpper()); // if wanted start date is < than the first available candle in Binance if (startDate < tempFirstDate) { startDate = tempFirstDate; } bool isDone = false; Dictionary <DateTime, BinanceKline> candles = new Dictionary <DateTime, BinanceKline>(); DateTime latestOpenDate = DateTime.MinValue; var newStartDate = startDate; var newEndDate = endDate; while (!isDone) { var tempCandles = CryptoGlobals.adminBinanceClient.GetKlines(symbolName, interval, newStartDate, newEndDate, 1000); foreach (var c in tempCandles.Data) { var cOpenTime = c.OpenTime; if (!candles.ContainsKey(cOpenTime)) { candles[cOpenTime] = c; if (cOpenTime > latestOpenDate) { latestOpenDate = cOpenTime; } } } var testDate = DateTime.MinValue; testDate = newEndDate.MinusKlineInterval(interval); // we are asking for 1000 MAX candles. // If the result is not 1000, means we have gotten them all. if (tempCandles.Data.Count() != 1000 || latestOpenDate >= testDate) { isDone = true; } else { if (latestOpenDate != DateTime.MinValue) { newStartDate = latestOpenDate; } isDone = false; } } var list = new List <SQLiteCommand>(); foreach (var temp in candles) { var candle = temp.Value; SQLiteCommand com = new SQLiteCommand(); com.CommandText = "INSERT OR IGNORE INTO Candles (Symbol,Interval,Volume,Close,High,Low,Open,OpenTime) " + "VALUES (@Symbol,@Interval,@Volume,@Close,@High,@Low,@Open,@OpenTime)"; com.Parameters.AddWithValue("@Symbol", symbolName); com.Parameters.AddWithValue("@Interval", interval.ToString()); com.Parameters.AddWithValue("@Volume", candle.Volume); com.Parameters.AddWithValue("@Close", candle.Close); com.Parameters.AddWithValue("@High", candle.High); com.Parameters.AddWithValue("@Low", candle.Low); com.Parameters.AddWithValue("@Open", candle.Open); com.Parameters.AddWithValue("@OpenTime", candle.OpenTime.ToSqlDateString()); list.Add(com); } DBHelper.BulkExecuteNonQuery(list); }
public static CandleInfo LastCandleInDB(string market, KlineInterval interval) { var dt = DBHelper.GetDataTable("SELECT * FROM Candles WHERE Symbol='" + market + "' and Interval=" + interval.ToString() + " order by Id desc LIMIT 1"); if (dt.Rows.Count > 0) { return(new CandleInfo(dt.Rows[dt.Rows.Count - 1])); } else { return(null); } }
public async Task <IWebSocket> GetWebsocketKlines(IEnumerable <string> streamTickers, KlineInterval interval) { string combined = string.Join("/", streamTickers.Select(s => s.ToLower() + "@" + interval.ToString())); return(await api.ConnectWebSocketAsync($"/stream?streams={combined}", (_socket, msg) => { string json = msg.ToStringFromUTF8(); //logger.Trace($"Kline Data:{json}"); var klinedata = JsonConvert.DeserializeObject <KlineStream>(json); DateTime dt = CryptoUtility.ParseTimestamp(klinedata.Data.EventTime, TimestampType.UnixMilliseconds); /* * logger.Trace($"EventTime:" + dt); * logger.Trace($"KLineData:{klinedata.Data.kline.kLineClosed}:{klinedata.Data.MarketSymbol}:{klinedata.Data.kline.OpenTimestamp}"); * logger.Trace($"KLineData:{klinedata.Data.kline.kLineClosed}:{klinedata.Data.MarketSymbol}:{klinedata.Data.kline.Open}:{klinedata.Data.kline.High}:{klinedata.Data.kline.Low}:{klinedata.Data.kline.Close}"); * logger.Trace($"KLineData:{klinedata.Data.kline.kLineClosed}:{klinedata.Data.MarketSymbol}:{klinedata.Data.kline.BaseVolume}:{klinedata.Data.kline.QuoteVolume}"); * logger.Trace($"KLineData:{klinedata.Data.kline.kLineClosed}:{klinedata.Data.MarketSymbol}:{klinedata.Data.kline.TakerBaseVolume}:{klinedata.Data.kline.TakerQuoteVolume}"); */ if (klinedata.Data.kline.kLineClosed == true) { /* * logger.Trace($"EventTime:" + dt); * logger.Trace($"KLineData:{klinedata.Data.kline.kLineClosed}:{klinedata.Data.MarketSymbol}:{klinedata.Data.kline.OpenTimestamp}"); * logger.Trace($"KLineData:{klinedata.Data.kline.kLineClosed}:{klinedata.Data.MarketSymbol}:{klinedata.Data.kline.Open}:{klinedata.Data.kline.High}:{klinedata.Data.kline.Low}:{klinedata.Data.kline.Close}"); * logger.Trace($"KLineData:{klinedata.Data.kline.kLineClosed}:{klinedata.Data.MarketSymbol}:{klinedata.Data.kline.BaseVolume}:{klinedata.Data.kline.QuoteVolume}"); * logger.Trace($"KLineData:{klinedata.Data.kline.kLineClosed}:{klinedata.Data.MarketSymbol}:{klinedata.Data.kline.TakerBaseVolume}:{klinedata.Data.kline.TakerQuoteVolume}"); */ MarketCandle candle = new MarketCandle(); candle.OpenPrice = klinedata.Data.kline.Open; candle.HighPrice = klinedata.Data.kline.High; candle.LowPrice = klinedata.Data.kline.Low; candle.ClosePrice = klinedata.Data.kline.Close; candle.PeriodSeconds = (int)interval; candle.BaseCurrencyVolume = (double)klinedata.Data.kline.BaseVolume; candle.QuoteCurrencyVolume = (double)klinedata.Data.kline.QuoteVolume; /* * candle.BaseCurrencyVolume = (double)klinedata.Data.kline.TakerBaseVolume; * candle.QuoteCurrencyVolume = (double)klinedata.Data.kline.TakerQuoteVolume; */ candle.Timestamp = klinedata.Data.kline.OpenTimestamp; if (!TickerKLines.ContainsKey(klinedata.Data.MarketSymbol)) { TickerKLines[klinedata.Data.MarketSymbol] = new List <MarketCandle>(); } TickerKLines[klinedata.Data.MarketSymbol].Add(candle); } /* * string marketSymbol = update.Data.MarketSymbol; * ExchangeOrderBook book = new ExchangeOrderBook { SequenceId = update.Data.FinalUpdate, MarketSymbol = marketSymbol, LastUpdatedUtc = CryptoUtility.UnixTimeStampToDateTimeMilliseconds(update.Data.EventTime) }; * foreach (List<object> ask in update.Data.Asks) * { * var depth = new ExchangeOrderPrice { Price = ask[0].ConvertInvariant<decimal>(), Amount = ask[1].ConvertInvariant<decimal>() }; * book.Asks[depth.Price] = depth; * } * foreach (List<object> bid in update.Data.Bids) * { * var depth = new ExchangeOrderPrice { Price = bid[0].ConvertInvariant<decimal>(), Amount = bid[1].ConvertInvariant<decimal>() }; * book.Bids[depth.Price] = depth; * } * callback(book); */ return Task.CompletedTask; }, (_sock) => { logger.Trace("KLine socket connected"); return Task.CompletedTask; })); }