/// <summary> /// Static method that runs a simulation of a Market and bot runs for a given period, /// with the parameters and historical data supplied as parameters /// </summary> /// <param name="objSimulation">An instance of the simulation info class with properties defining how to perform the simulation</param> /// <param name="initialWallet">The Wallet to use at the start of the simulation</param> /// <param name="obStrategy">The existing strategy to use if the simulation object does not specify a custom strategy</param> /// <param name="objExchange">An instance of the Exchange parameters</param> /// <param name="exchangeHistory">Historical data for the Exchange object</param> /// <returns>the trading history computed from the simulation with resulting balance, issued and executed orders</returns> public static TradingHistory RunSimulation(SimulationInfo objSimulation, Wallet initialWallet , ITradingStrategy obStrategy, ExchangeInfo objExchange, IEnumerable <Trade> exchangeHistory) { var toReturn = new TradingHistory(); if (objSimulation.UseCustomStrategy) { obStrategy = objSimulation.CustomStrategy; } var objExchangeSimulator = new ExchangeSimulator() { Trades = exchangeHistory.ToList() }; var currentWallet = (Wallet)initialWallet.Clone(); //var lastBotMarket = new MarketInfo(DateTime.MinValue); var lastBotTicker = 0m; var lastBotTime = DateTime.MinValue; MarketInfo objMarket = null; int nbEmptyRuns = 0; foreach (var historicTrade in objExchangeSimulator.Trades .Where(objTrade => objTrade.Time > objSimulation.StartDate && objTrade.Time < objSimulation.EndDate)) { if ((currentWallet.OrderedAsks.Count > 0 && historicTrade.Price > currentWallet.LowestAsk.Price) || (currentWallet.OrderedBids.Count > 0 && historicTrade.Price < currentWallet.HighestBid.Price)) { nbEmptyRuns = 0; objMarket = objExchangeSimulator.GetMarket(historicTrade.Time); objExchange.ExecuteOrders(objMarket, ref currentWallet, ref toReturn); } if (historicTrade.Time.Subtract(lastBotTime) > objSimulation.BotPeriod.Value) { currentWallet.Time = historicTrade.Time; bool isBigVariation = Math.Abs((historicTrade.Price - lastBotTicker) / historicTrade.Price) > objSimulation.SkippedVariationRate / 100; if (!objSimulation.FastSimulation || nbEmptyRuns < objSimulation.SkippedMinVoidRuns || nbEmptyRuns >= objSimulation.SkippedMaxRuns || isBigVariation) { if (objMarket == null) { objMarket = objExchangeSimulator.GetMarket(historicTrade.Time); } var newOrders = obStrategy.ComputeNewOrders(currentWallet, objMarket, objExchange, toReturn); currentWallet.IntegrateOrders(newOrders.Orders.ToArray()); lastBotTicker = objMarket.Ticker.Last; if (newOrders.Orders.Count == 0 && !isBigVariation && nbEmptyRuns < objSimulation.SkippedMaxRuns) { nbEmptyRuns++; } else { nbEmptyRuns = 0; } } else { nbEmptyRuns++; } lastBotTime = historicTrade.Time; } objMarket = null; } return(toReturn); }