public async void BackTest() { logger.Trace("Starting BackTest"); IList <Asset> BackTestAssets = new List <Asset>(); IList <Asset> CompletedTrades = new List <Asset>(); // flags. bool hasTrade = false; MarketCandle buyCandle = null, sellCandle = null; var tickers = await api.GetTickersAsync(); tickers = tickers.Where(t => t.Value.Volume.QuoteCurrency == "USD" && !coinsToRemove.Contains(t.Value.Volume.BaseCurrency) ); foreach (var ticker in tickers) { BackTestAssets.Add(new Asset { Ticker = ticker.Key, BaseCurrency = ticker.Value.Volume.BaseCurrency }); } int numTickers = BackTestAssets.Count(); for (int idx = 0; idx < numTickers; idx++) { try { var asset = BackTestAssets[idx]; // get 4-hour candles var candles = (await api.GetCandlesAsync(asset.Ticker, 8 * 60 * 60, null, null)).ToArray(); IList <Quote> history = new List <Quote>(); foreach (var candle in candles) { history.Add(new Quote { Date = candle.Timestamp, Open = candle.OpenPrice, High = candle.HighPrice, Low = candle.LowPrice, Close = candle.ClosePrice, Volume = (decimal)candle.QuoteCurrencyVolume }); } // calculate RSI(14) IList <HeikinAshiResult> ha = Indicator.GetHeikinAshi(history).ToArray(); IList <HeikinAshi> ashiList = new List <HeikinAshi>(); foreach (var item in ha) { ashiList.Add(new HeikinAshi(item)); } // remember to throw out the last candle because that is the active candle that is not completed yet. hasTrade = false; for (int j = 1; j < candles.Length - 2; j++) { // remember to throw out the last candle because that is the active candle that is not completed yet. // var completedRSI = rsi[j]; // var previousRSI = rsi[j - 1]; var completedAshi = ashiList[j]; var previousAshi = ashiList[j - 1]; var isBuy = completedAshi.Signal == HeikinAshi.HeikinAshiSignal.STRONGBUY && previousAshi.Signal != HeikinAshi.HeikinAshiSignal.STRONGBUY; var isSellProfit = completedAshi.Signal == HeikinAshi.HeikinAshiSignal.STRONGSELL || previousAshi.Signal == HeikinAshi.HeikinAshiSignal.SELL; if (isBuy && !hasTrade) { hasTrade = true; buyCandle = candles[j + 1]; // Debug.WriteLine($"Buy, {buyCandle.OpenPrice}, {buyCandle.HighPrice}"); } if (isSellProfit && hasTrade) { hasTrade = false; sellCandle = candles[j + 1]; var lowPL = (sellCandle.LowPrice - buyCandle.HighPrice) / buyCandle.HighPrice * 100; var pl = (sellCandle.OpenPrice - buyCandle.OpenPrice) / buyCandle.OpenPrice * 100; Debug.WriteLine($"{asset.Ticker}, {buyCandle.Timestamp}, {sellCandle.Timestamp}, {sellCandle.LowPrice}, {sellCandle.HighPrice}, {lowPL:0.00}, {pl:0.00}"); } } // unclosed trades. if (hasTrade) { sellCandle = candles[candles.Length - 1]; var lowPL = (sellCandle.LowPrice - buyCandle.HighPrice) / buyCandle.HighPrice * 100; var pl = (sellCandle.OpenPrice - buyCandle.OpenPrice) / buyCandle.OpenPrice * 100; Debug.WriteLine($"{asset.Ticker}, {buyCandle.Timestamp}, {sellCandle.Timestamp}, {sellCandle.LowPrice}, {sellCandle.HighPrice}, {lowPL:0.00}, {pl:0.00}, Unclosed "); } } catch (Exception ex) { } } Debug.WriteLine("========= end backtesting ========="); }
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; })); }
public SymbolTrend(int timeframe) { TimeframeInHours = timeframe; TrendRaw = 0M; Candle = null; }
public static XCandle ToXCandle(this MarketCandle candle) { return(new XCandle(candle.ExchangeName, candle.Name, candle.Timestamp, candle.PeriodSeconds, candle.OpenPrice, candle.HighPrice, candle.LowPrice, candle.ClosePrice, (decimal)candle.BaseVolume, (decimal)candle.ConvertedVolume, candle.WeightedAverage)); }