Esempio n. 1
0
        public async Task <List <BackTestResult> > RunSingleStrategy(ITradingStrategy strategy, BacktestOptions backtestOptions, IDataStoreBacktest dataStore, string baseCurrency, bool saveSignals, decimal startingWallet, decimal tradeAmount)
        {
            var results    = new List <BackTestResult>();
            var allSignals = new List <TradeSignal>();

            // Go through our coinpairs and backtest them.
            foreach (string globalSymbol in backtestOptions.Coins)
            {
                var candleProvider = new DatabaseCandleProvider();
                backtestOptions.Coin = globalSymbol;

                // This creates a list of buy signals.
                var candles = await candleProvider.GetCandles(backtestOptions, dataStore);

                if (candles == null || !candles.Any())
                {
                    continue;
                }

                candles = await candles.FillCandleGaps((Period)Enum.Parse(typeof(Period), backtestOptions.CandlePeriod.ToString(), true));

                var backTestResult = new BackTestResult {
                    Market = globalSymbol
                };

                try
                {
                    var trend   = strategy.Prepare(candles);
                    var signals = new List <TradeSignal>();

                    for (int i = 0; i < trend.Count; i++)
                    {
                        if (trend[i] == TradeAdvice.Buy)
                        {
                            var id = Guid.NewGuid();

                            signals.Add(new TradeSignal
                            {
                                Id           = id,
                                MarketName   = globalSymbol,
                                Price        = candles[i].Close,
                                TradeAdvice  = TradeAdvice.Buy,
                                SignalCandle = candles[i],
                                Timestamp    = candles[i].Timestamp,
                                StrategyName = strategy.Name
                            });

                            // Calculate win/lose forwards from buy point
                            for (int j = i; j < trend.Count; j++)
                            {
                                // Sell as soon as the strategy tells us to..
                                if (trend[j] == TradeAdvice.Sell ||
                                    ShouldSell((double)candles[i].Close, (double)candles[j].Close, candles[j].Timestamp) != SellType.None
                                    )
                                {
                                    // We ignore fees for now. Goal of the backtester is to compare strategy efficiency.
                                    var currentProfitPercentage = ((candles[j].Close - candles[i].Close) / candles[i].Close) * 100;
                                    var quantity      = tradeAmount / candles[i].Close;
                                    var currentProfit = (candles[j].Close - candles[i].Close) * quantity;

                                    backTestResult.Trades.Add(new BackTestTradeResult
                                    {
                                        Market           = globalSymbol,
                                        Quantity         = quantity,
                                        OpenRate         = candles[i].Close,
                                        CloseRate        = candles[j].Close,
                                        ProfitPercentage = currentProfitPercentage,
                                        Profit           = currentProfit,
                                        Duration         = j - i,
                                        StartDate        = candles[i].Timestamp,
                                        EndDate          = candles[j].Timestamp
                                    });

                                    signals.Add(new TradeSignal
                                    {
                                        Id               = Guid.NewGuid(),
                                        ParentId         = id,
                                        MarketName       = globalSymbol,
                                        Price            = candles[j].Close,
                                        TradeAdvice      = TradeAdvice.Sell,
                                        SignalCandle     = candles[j],
                                        Profit           = currentProfit,
                                        PercentageProfit = currentProfitPercentage,
                                        Timestamp        = candles[j].Timestamp,
                                        StrategyName     = strategy.Name
                                    });

                                    if (backtestOptions.OnlyStartNewTradesWhenSold)
                                    {
                                        i = j;
                                    }

                                    break;
                                }
                            }
                        }
                    }

                    if (saveSignals)
                    {
                        await candleProvider.SaveTradeSignals(backtestOptions, dataStore, signals);
                    }

                    allSignals.AddRange(signals);
                }
                catch (Exception ex)
                {
                    ConsoleUtility.WriteColoredLine($"Error in Strategy: {strategy.Name}", ConsoleColor.Red);
                    ConsoleUtility.WriteColoredLine($"\t{ex.Message}", ConsoleColor.Red);
                }

                results.Add(backTestResult);
            }

            allSignals = allSignals.OrderBy(t => t != null).ThenBy(t => t.Timestamp).ToList();

            #region wallet trend

            var strategyTrades = new List <BackTestTradeResult>();
            foreach (var marketResult in results)
            {
                strategyTrades.AddRange(marketResult.Trades);
            }
            strategyTrades = strategyTrades.OrderBy(t => t.StartDate).ToList();

            decimal wallet    = startingWallet;
            decimal lowWallet = startingWallet;

            int cct = 0;
            int mct = 0;

            for (int i = 0; i < allSignals.Count(); i++)
            {
                var signal = allSignals[i];

                if (signal.TradeAdvice == TradeAdvice.Buy)
                {
                    cct = cct + 1;

                    if (cct > mct)
                    {
                        mct = cct;
                    }

                    wallet = wallet - tradeAmount;
                }
                else if (signal.TradeAdvice == TradeAdvice.Sell)
                {
                    cct = cct - 1;

                    wallet = wallet + (tradeAmount + signal.PercentageProfit * tradeAmount);

                    if (wallet < lowWallet)
                    {
                        lowWallet = wallet;
                    }
                }
            }

            var ff = results.FirstOrDefault();
            if (ff != null)
            {
                results.FirstOrDefault().ConcurrentTrades = mct;
                results.FirstOrDefault().Wallet           = wallet;
                results.FirstOrDefault().LowWallet        = lowWallet;
            }

            #endregion

            return(results);
        }
        public async Task <Tuple <DateTime, DateTime> > CacheAllData(ExchangeAPI api, Exchange exchange)
        {
            Global.Logger.Information($"Starting CacheAllData");
            var watch1 = System.Diagnostics.Stopwatch.StartNew();

            var exchangeCoins = api.GetMarketSymbolsMetadataAsync().Result.Where(m => m.BaseCurrency == Global.Configuration.TradeOptions.QuoteCurrency);

            // If there are items on the only trade list remove the rest
            if (Global.Configuration.TradeOptions.OnlyTradeList.Count > 0)
            {
                exchangeCoins = exchangeCoins.Where(m => Global.Configuration.TradeOptions.OnlyTradeList.Any(c => c.Contains(m.MarketSymbol))).ToList();
            }

            var currentExchangeOption = Global.Configuration.ExchangeOptions.FirstOrDefault();

            IExchangeAPI realExchange = ExchangeAPI.GetExchangeAPI(api.Name);

            var returns = new Tuple <DateTime, DateTime>(DateTime.MinValue, DateTime.MinValue);

            foreach (var coin in exchangeCoins)
            {
                var symbol = coin.MarketSymbol;

                if (realExchange is ExchangeBinanceAPI)
                {
                    symbol = await api.ExchangeMarketSymbolToGlobalMarketSymbolAsync(symbol);
                }

                var backtestOptions = new BacktestOptions
                {
                    DataFolder   = Global.DataPath,
                    Exchange     = exchange,
                    Coin         = symbol,
                    CandlePeriod = Int32.Parse(currentExchangeOption.SimulationCandleSize)
                };

                var key1  = api.Name + backtestOptions.Coin + backtestOptions.CandlePeriod;
                var data1 = Global.AppCache.Get <List <Candle> >(key1);
                if (data1 != null)
                {
                    returns = new Tuple <DateTime, DateTime>(data1.First().Timestamp, data1.Last().Timestamp);
                    continue;
                }

                Candle databaseFirstCandle = Global.DataStoreBacktest.GetBacktestFirstCandle(backtestOptions).Result;
                Candle databaseLastCandle  = Global.DataStoreBacktest.GetBacktestLastCandle(backtestOptions).Result;

                if (databaseFirstCandle == null || databaseLastCandle == null)
                {
                    continue;
                }

                backtestOptions.StartDate = databaseFirstCandle.Timestamp;
                backtestOptions.EndDate   = databaseLastCandle.Timestamp;

                var candleProvider = new DatabaseCandleProvider();
                var _candle15      = candleProvider.GetCandles(backtestOptions, Global.DataStoreBacktest).Result;
                _candle15 = await _candle15.FillCandleGaps((Period)Enum.Parse(typeof(Period), backtestOptions.CandlePeriod.ToString(), true));

                Global.AppCache.Remove(backtestOptions.Coin + backtestOptions.CandlePeriod);
                Global.AppCache.Add(api.Name + backtestOptions.Coin + backtestOptions.CandlePeriod, _candle15, new MemoryCacheEntryOptions());

                Global.Logger.Information($"   Cached {key1}");

                backtestOptions.CandlePeriod = 1;

                var key2 = api.Name + backtestOptions.Coin + backtestOptions.CandlePeriod;
                if (Global.AppCache.Get <List <Candle> >(key2) != null)
                {
                    continue;
                }

                Candle database1FirstCandle = Global.DataStoreBacktest.GetBacktestFirstCandle(backtestOptions).Result;
                Candle database1LastCandle  = Global.DataStoreBacktest.GetBacktestLastCandle(backtestOptions).Result;

                if (database1FirstCandle == null || database1LastCandle == null)
                {
                    continue;
                }

                backtestOptions.StartDate = database1FirstCandle.Timestamp;
                backtestOptions.EndDate   = database1LastCandle.Timestamp;

                var _candle1 = candleProvider.GetCandles(backtestOptions, Global.DataStoreBacktest).Result;
                _candle1 = await _candle1.FillCandleGaps((Period)Enum.Parse(typeof(Period), backtestOptions.CandlePeriod.ToString(), true));

                Global.AppCache.Remove(backtestOptions.Coin + backtestOptions.CandlePeriod);
                Global.AppCache.Add(api.Name + backtestOptions.Coin + backtestOptions.CandlePeriod, _candle1, new MemoryCacheEntryOptions());

                Global.Logger.Information($"   Cached {key2}");

                returns = new Tuple <DateTime, DateTime>(backtestOptions.StartDate, backtestOptions.EndDate);
            }

            watch1.Stop();
            Global.Logger.Warning($"Ended CacheAllData in #{watch1.Elapsed.TotalSeconds} seconds");

            return(returns);
        }
Esempio n. 3
0
        public async Task <List <BackTestResult> > RunSingleStrategy(ITradingStrategy strategy, BacktestOptions backtestOptions, IDataStoreBacktest dataStore)
        {
            var results = new List <BackTestResult>();

            // Go through our coinpairs and backtest them.
            foreach (string globalSymbol in backtestOptions.Coins)
            {
                var candleProvider = new DatabaseCandleProvider();
                backtestOptions.Coin = globalSymbol;

                // This creates a list of buy signals.
                var candles = await candleProvider.GetCandles(backtestOptions, dataStore);

                var backTestResult = new BackTestResult {
                    Market = globalSymbol
                };

                try
                {
                    var trend   = strategy.Prepare(candles);
                    var signals = new List <TradeSignal>();

                    for (int i = 0; i < trend.Count; i++)
                    {
                        if (trend[i] == TradeAdvice.Buy)
                        {
                            var id = Guid.NewGuid();

                            signals.Add(new TradeSignal
                            {
                                Id           = id,
                                MarketName   = globalSymbol,
                                Price        = candles[i].Close,
                                TradeAdvice  = TradeAdvice.Buy,
                                SignalCandle = candles[i],
                                Timestamp    = candles[i].Timestamp,
                                StrategyName = strategy.Name
                            });

                            // Calculate win/lose forwards from buy point
                            for (int j = i; j < trend.Count; j++)
                            {
                                // Sell as soon as the strategy tells us to..
                                if (trend[j] == TradeAdvice.Sell ||
                                    ShouldSell((double)candles[i].Close, (double)candles[j].Close, candles[j].Timestamp) != SellType.None
                                    )
                                {
                                    //if (candles[i].Close == 0 || candles[j].Close == 0)
                                    //    continue;

                                    // We ignore fees for now. Goal of the backtester is to compare strategy efficiency.
                                    var currentProfitPercentage = ((candles[j].Close - candles[i].Close) / candles[i].Close) * 100;
                                    var quantity      = backtestOptions.StakeAmount / candles[i].Close; // We always trade with 0.1 BTC.
                                    var currentProfit = (candles[j].Close - candles[i].Close) * quantity;

                                    backTestResult.Trades.Add(new BackTestTradeResult
                                    {
                                        Market           = globalSymbol,
                                        Quantity         = quantity,
                                        OpenRate         = candles[i].Close,
                                        CloseRate        = candles[j].Close,
                                        ProfitPercentage = currentProfitPercentage,
                                        Profit           = currentProfit,
                                        Duration         = j - i,
                                        StartDate        = candles[i].Timestamp,
                                        EndDate          = candles[j].Timestamp
                                    });

                                    signals.Add(new TradeSignal
                                    {
                                        Id               = Guid.NewGuid(),
                                        ParentId         = id,
                                        MarketName       = globalSymbol,
                                        Price            = candles[j].Close,
                                        TradeAdvice      = TradeAdvice.Sell,
                                        SignalCandle     = candles[j],
                                        Profit           = currentProfit,
                                        PercentageProfit = currentProfitPercentage,
                                        Timestamp        = candles[j].Timestamp,
                                        StrategyName     = strategy.Name
                                    });

                                    if (backtestOptions.OnlyStartNewTradesWhenSold)
                                    {
                                        i = j;
                                    }

                                    break;
                                }
                            }
                        }
                    }

                    await candleProvider.SaveTradeSignals(backtestOptions, dataStore, signals);
                }
                catch (Exception ex)
                {
                    ConsoleUtility.WriteColoredLine($"Error in Strategy: {strategy.Name}", ConsoleColor.Red);
                    ConsoleUtility.WriteColoredLine($"\t{ex.Message}", ConsoleColor.Red);
                }

                results.Add(backTestResult);
            }

            return(results);
        }