/// <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);
        }