public void AddPlot(PlotHelper plot) { if (!_Plots.Contains(plot)) { _Plots.Add(plot); } }
public void Start() { if (Started) { return; } this.BenchmarkStats = new Statistics(); this.BotStats = new Statistics(); Logger.Info($"Backtesting {Algo.Version} from {StartTime} - {EndTime} with configuration:\n" + JObject.FromObject(algoConfig).ToString()); Stopwatch sw = new Stopwatch(); sw.Start(); Started = true; this.Algo.Start(true).Wait(); int steps = 1; decimal BalancePeak = 0; var startingBal = -1m; var currentBenchmarkVal = 0.0; while (MarketSimulator.NextTick() && MarketSimulator.Time < EndTime) { if (startingBal < 0) { startingBal = MarketSimulator.GetEquity(BaseAsset); } Algo.OnTickAsync().Wait(); steps++; //---- update equity and benchmark ---------- if (steps % 30 == 0) { var balance = MarketSimulator.GetEquity(BaseAsset); BotStats.Update(MarketSimulator.Time, (double)balance); //--- calculate benchmark change double changeSum = 0; int changeCount = 0; foreach (var symData in Algo.SymbolsData.Values) { if (symData.Feed != null && symData.Feed.Ask > 0 && symData.Feed.Bid > 0) { var sk = symData.Feed.Symbol.Key; if (symData.Feed != null && LastPrices.ContainsKey(sk)) { changeCount++; changeSum += (symData.Feed.Bid - LastPrices[sk]) / LastPrices[sk]; } LastPrices[sk] = symData.Feed.Ask; } } if (changeCount > 0) { currentBenchmarkVal += changeSum * 100 / changeCount; BenchmarkStats.Update(MarketSimulator.Time, currentBenchmarkVal); } } } var totalBal = MarketSimulator.GetEquity(BaseAsset); //get the total fee paid calculated on commission asset var feeList = MarketSimulator.Trades.Select( tr => { if (tr.Symbol.EndsWith(tr.CommissionAsset)) { return(tr.Commission); } else { return(tr.Commission * tr.Price); } }); var lostInFee = feeList.Sum(); //get profit sw.Stop(); Logger.Info($"Test terminated in {sw.ElapsedMilliseconds} ms."); Logger.Info($"Balance: {totalBal} - Trades:{MarketSimulator.Trades.Count()} - Lost in fee:{lostInFee}"); var operations = Algo.ActiveOperations.Concat(Algo.ClosedOperations).Where(o => o.AmountInvested > 0).ToList(); if (operations.Count > 0) { Logger.Info($"Algorithm => Profit/MDD: {BotStats.Profit / BotStats.MaxDrowDown} - MaxDrawDown: {BotStats.MaxDrowDown} - Profit/oper: {BotStats.Profit / operations.Count:F8} "); Logger.Info($"BenchMark => Profit/MDD: {BenchmarkStats.Profit / BenchmarkStats.MaxDrowDown} - MaxDrawDown: {BenchmarkStats.MaxDrowDown} "); } foreach (var p in Algo.Plots) { ShowPlotCallback?.Invoke(p); } if (Config.PlotResults) { PlotHelper plot = new PlotHelper("Equity"); int skipCount = (BotStats.EquityHistory.Count + 2000) / 2000; List <IndicatorDataPoint> botPoints = new List <IndicatorDataPoint>(); List <IndicatorDataPoint> benchPoints = new List <IndicatorDataPoint>(); for (int i = 0; i < BotStats.EquityHistory.Count; i += skipCount) { var e = BotStats.EquityHistory[i]; botPoints.Add(new IndicatorDataPoint(e.Time, e.Value)); if (BenchmarkStats.EquityHistory.Count > i) { e = BenchmarkStats.EquityHistory[i]; benchPoints.Add(new IndicatorDataPoint(e.Time, e.Value)); } } plot.PlotLine(botPoints, ARGBColors.Purple); plot.PlotLine(benchPoints, ARGBColors.MediumPurple, "asdasd"); plot.InitialView = (Config.StartTime, Config.EndTime); ShowPlotCallback?.Invoke(plot); } }