public void ConvertCandles(IBrokersCandlesService candlesService, IBroker broker, List <string> markets)
        {
            var candlesDirectory = Path.Combine(Path.GetDirectoryName(typeof(MainWindowViewModel).Assembly.Location), "Candles");

            if (!Directory.Exists(candlesDirectory))
            {
                Directory.CreateDirectory(candlesDirectory);
            }

            foreach (var market in markets)
            {
                if (File.Exists(GetCandlesPath(market, Timeframe.H2)) &&
                    File.Exists(GetCandlesPath(market, Timeframe.H4)) &&
                    File.Exists(GetCandlesPath(market, Timeframe.D1)) &&
                    File.Exists(GetCandlesPath(market, Timeframe.M5)))
                {
                    continue;
                }

                var allM5Candles = candlesService.GetCandles(broker, market, Timeframe.M5, false, cacheData: false);
                var allH2Candles = candlesService.GetCandles(broker, market, Timeframe.H2, false, cacheData: false);
                var allH4Candles = candlesService.GetCandles(broker, market, Timeframe.H4, false, cacheData: false);
                var allD1Candles = candlesService.GetCandles(broker, market, Timeframe.D1, false, cacheData: false);

                if (allD1Candles.Count == 0 || allH2Candles.Count == 0 || allH4Candles.Count == 0 || allM5Candles.Count == 0)
                {
                    continue;
                }

                var bytes = Compress(BrokersCandlesService.CandlesToBytes(allM5Candles));
                var path  = Path.Combine(candlesDirectory, $"{market.Replace("/", string.Empty)}_M5.dat");
                File.WriteAllBytes(path, bytes);

                bytes = Compress(BrokersCandlesService.CandlesToBytes(allH2Candles));
                path  = Path.Combine(candlesDirectory, $"{market.Replace("/", string.Empty)}_H2.dat");
                File.WriteAllBytes(path, bytes);

                bytes = Compress(BrokersCandlesService.CandlesToBytes(allH4Candles));
                path  = Path.Combine(candlesDirectory, $"{market.Replace("/", string.Empty)}_H4.dat");
                File.WriteAllBytes(path, bytes);

                bytes = Compress(BrokersCandlesService.CandlesToBytes(allD1Candles));
                path  = Path.Combine(candlesDirectory, $"{market.Replace("/", string.Empty)}_D1.dat");
                File.WriteAllBytes(path, bytes);

                GC.Collect();
            }
        }
        public static List <Candle> GetDerivedCandles(this IBrokersCandlesService candlesService,
                                                      IBroker broker, string firstSymbol, string secondSymbol, Timeframe timeframe,
                                                      bool updateCandles      = false, DateTime?minOpenTimeUtc = null, DateTime?maxCloseTimeUtc = null,
                                                      bool forceCreateDerived = false)
        {
            var pair = $"{firstSymbol}{secondSymbol}";

            if (!forceCreateDerived)
            {
                var candles = candlesService.GetCandles(broker, pair, timeframe, false, minOpenTimeUtc: minOpenTimeUtc, maxCloseTimeUtc: maxCloseTimeUtc);
                if (candles != null && candles.Count > 0)
                {
                    return(candles);
                }
            }

            var calculatedMarketCandles = new DerivedMarketCandles(broker, candlesService);

            return(calculatedMarketCandles.CreateCandlesSeries(
                       firstSymbol,
                       secondSymbol,
                       timeframe,
                       updateCandles,
                       minOpenTimeUtc,
                       maxCloseTimeUtc));
        }
        /// <summary>
        /// Uses a faster mechanism for finding candles.
        /// </summary>
        /// <param name="service"></param>
        /// <param name="market"></param>
        /// <param name="broker"></param>
        /// <param name="timeframe"></param>
        /// <param name="dateTime"></param>
        /// <param name="updateCandles"></param>
        /// <returns></returns>
        public static Candle?GetLastClosedCandle(this IBrokersCandlesService service, string market, IBroker broker, Timeframe timeframe, DateTime dateTime, bool updateCandles = false)
        {
            var candles = service.GetCandles(broker, market, timeframe, updateCandles);

            if (candles == null || candles.Count == 0)
            {
                return(null);
            }

            var maxItemsInRange = 20;

            if (candles.Count <= maxItemsInRange)
            {
                for (var i = candles.Count - 1; i >= 0; i--)
                {
                    if (candles[i].CloseTimeTicks <= dateTime.Ticks)
                    {
                        return(candles[i]);
                    }
                }

                return(null);
            }

            if (candles[candles.Count - 1].CloseTimeTicks <= dateTime.Ticks)
            {
                return(candles[candles.Count - 1]);
            }

            var range1Start = 0;
            var range2End   = candles.Count - 1;
            var range1End   = (range2End - range1Start) / 2;

            while (range2End - range1Start + 1 > maxItemsInRange)
            {
                var range2Start = range1End + 1;
                if (candles[range2Start].CloseTimeTicks > dateTime.Ticks)
                {
                    range2End = range1End;
                    range1End = range1Start + (range2End - range1Start) / 2;
                }
                else
                {
                    range1Start = range1End + 1;
                    range1End   = range1Start + (range2End - range1Start) / 2;
                }
            }

            for (var i = range2End; i >= range1Start; i--)
            {
                if (candles[i].CloseTimeTicks <= dateTime.Ticks)
                {
                    return(candles[i]);
                }
            }

            return(null);
        }
Beispiel #4
0
        public decimal CalculateUSDTValue(IBroker broker, DateTime currentTime)
        {
            var value = 0M;

            foreach (var assetBalance in CurrentAssetBalances)
            {
                if (assetBalance.Value.Asset == "USDT")
                {
                    value += assetBalance.Value.Balance;
                    continue;
                }

                var candles    = _candleService.GetCandles(broker, $"{assetBalance.Value.Asset}USDT", Timeframe.H1, false, maxCloseTimeUtc: currentTime);
                var candle     = candles.Last();
                var assetValue = assetBalance.Value.Balance * (decimal)candle.CloseBid;
                value += assetValue;
            }

            return(value);
        }
Beispiel #5
0
        /// <summary>
        /// Uses a faster mechanism for finding candles.
        /// </summary>
        /// <param name="service"></param>
        /// <param name="market"></param>
        /// <param name="broker"></param>
        /// <param name="timeframe"></param>
        /// <param name="dateTime"></param>
        /// <param name="updateCandles"></param>
        /// <returns></returns>
        public static Candle?GetLastClosedCandle(this IBrokersCandlesService service, string market, IBroker broker, Timeframe timeframe, DateTime dateTime, bool updateCandles = false)
        {
            var candles = service.GetCandles(broker, market, timeframe, updateCandles);

            if (candles == null || candles.Count == 0)
            {
                return(null);
            }

            var index = candles.BinarySearchGetItem(
                i => candles[i].CloseTimeTicks, 0, dateTime.Ticks,
                BinarySearchMethod.PrevLowerValueOrValue);

            if (index != -1)
            {
                return(candles[index]);
            }

            return(null);
        }
        public List <Trade> Run(StrategyBase strategy, Func <bool> getShouldStopFunc, DateTime?startTime = null, DateTime?endTime = null)
        {
            var logIntervalSeconds          = 5;
            var candleTimeframes            = strategy.Timeframes;
            var smallestNonM1Timeframe      = candleTimeframes.First();
            var candleTimeframesExcSmallest = candleTimeframes.Where(x => x != smallestNonM1Timeframe).ToList();
            var m1Candles              = _candleService.GetCandles(_broker, _market.Name, Timeframe.M1, false);
            var allCandles             = GetCandles(candleTimeframes);
            var timeframeCandleIndexes = new TimeframeLookup <int>();
            var currentCandles         = new TimeframeLookup <List <Candle> >();
            var trades      = new TradeWithIndexingCollection();
            var nextLogTime = DateTime.UtcNow.AddSeconds(logIntervalSeconds);
            var calls       = 0;

            strategy.SetSimulationParameters(trades, currentCandles, _market);

            foreach (var tf in candleTimeframes)
            {
                currentCandles[tf] = new List <Candle>(10000);
            }
            var smallestNonM1TimeframeCount = allCandles[smallestNonM1Timeframe].Count;

            var m1CandleIndex = 0;

            Candle smallestNonM1Candle;

            var startTimeTicks = startTime != null ? (long?)startTime.Value.Ticks : null;
            var endTimeTicks   = endTime != null ? (long?)endTime.Value.Ticks : null;

            strategy.SetInitialised();

            // Ignore M1 candles
            for (var smallestNonM1TfIndex = 0;
                 smallestNonM1TfIndex < smallestNonM1TimeframeCount;
                 smallestNonM1TfIndex++)
            {
                if (getShouldStopFunc != null && getShouldStopFunc())
                {
                    return(null);
                }

                // Progress smallest non-M1 candle
                smallestNonM1Candle = allCandles[smallestNonM1Timeframe][smallestNonM1TfIndex];
                currentCandles[smallestNonM1Timeframe].Add(smallestNonM1Candle);
                var newCandleTimeframes = new List <Timeframe> {
                    smallestNonM1Timeframe
                };

                if (DateTime.UtcNow > nextLogTime)
                {
                    LogProgress(trades, smallestNonM1Candle.CloseTimeTicks);
                    nextLogTime = DateTime.UtcNow.AddSeconds(logIntervalSeconds);
                }

                // Progress other timeframes
                foreach (var tf in candleTimeframesExcSmallest)
                {
                    for (var i = timeframeCandleIndexes[tf]; i < allCandles[tf].Count; i++)
                    {
                        var c = allCandles[tf][i];
                        if (c.CloseTimeTicks <= smallestNonM1Candle.CloseTimeTicks)
                        {
                            currentCandles[tf].Add(c);
                            newCandleTimeframes.Add(tf);
                            timeframeCandleIndexes[tf] = i + 1;
                        }
                        else
                        {
                            break;
                        }
                    }
                }

                // Process M1 candles if any trades are open or and orders
                if ((trades.AnyOpen || trades.AnyOrders) && m1CandleIndex < m1Candles.Count)
                {
                    // Include M1 candles
                    var nextIndex = m1Candles.BinarySearchGetItem(
                        i => m1Candles[i].CloseTimeTicks,
                        m1CandleIndex,
                        smallestNonM1TfIndex > 0 ? allCandles[smallestNonM1Timeframe][smallestNonM1TfIndex - 1].CloseTimeTicks : smallestNonM1Candle.OpenTimeTicks,
                        BinarySearchMethod.NextHigherValue);

                    if (nextIndex != -1 && m1Candles[nextIndex].CloseTimeTicks <= m1Candles[m1CandleIndex].CloseTimeTicks)
                    {
                        throw new ApplicationException("M1 candles are not running in order");
                    }

                    if (nextIndex != -1 && m1Candles[nextIndex].CloseTimeTicks <= smallestNonM1Candle.CloseTimeTicks)
                    {
                        m1CandleIndex = nextIndex;

                        for (var i = m1CandleIndex; i < m1Candles.Count; i++)
                        {
                            var m1 = m1Candles[i];
                            if (m1.CloseTimeTicks > smallestNonM1Candle.CloseTimeTicks)
                            {
                                break;
                            }

                            m1CandleIndex = i;
                            if (!trades.AnyOpen && !trades.AnyOrders)
                            {
                                break;
                            }

                            if (trades.AnyOrders)
                            {
                                FillOrders(trades, m1);
                            }
                            if (trades.AnyOpen)
                            {
                                TryCloseOpenTrades(trades, m1);
                                calls++;
                            }
                        }
                    }
                }

                // Process new completed candles in strategy
                try
                {
                    strategy.UpdateIndicators(newCandleTimeframes);
                    strategy.NewTrades.Clear();

                    if (startTimeTicks == null || (smallestNonM1Candle.CloseTimeTicks >= startTimeTicks && smallestNonM1Candle.CloseTimeTicks <= endTimeTicks))
                    {
                        strategy.ProcessCandles(newCandleTimeframes);
                    }
                }
                catch (Exception ex)
                {
                    Log.Error("Error processing new candles", ex);
                    return(null);
                }

                RemoveInvalidTrades(strategy.NewTrades, smallestNonM1Candle.CloseBid, smallestNonM1Candle.CloseAsk);

                // Add new trades
                foreach (var t in strategy.NewTrades)
                {
                    if (t.CloseDateTime != null)
                    {
                        trades.AddClosedTrade(t);
                    }
                    else if (t.EntryDateTime == null && t.OrderDateTime != null)
                    {
                        trades.AddOrderTrade(t);
                    }
                    else if (t.EntryDateTime != null)
                    {
                        trades.AddOpenTrade(t);
                    }
                }
            }

            LogProgress(trades, allCandles[smallestNonM1Timeframe][allCandles[smallestNonM1Timeframe].Count - 1].CloseTimeTicks);

            var ret = trades.AllTrades.Select(x => x.Trade).ToList();

            foreach (var t in ret)
            {
                TradeCalculator.UpdateInitialStopPips(t);
                TradeCalculator.UpdateInitialLimitPips(t);
                TradeCalculator.UpdateRMultiple(t);
            }

            return(ret);
        }
        private List <Candle> GetBTCCandles(string symbol,
                                            bool updateCandles, DateTime?minOpenTimeUtc = null, DateTime?maxCloseTimeUtc = null)
        {
            var candles = _candlesService.GetCandles(_broker, $"{symbol}BTC", Timeframe.M5, updateCandles, minOpenTimeUtc, maxCloseTimeUtc);

            if (candles != null && candles.Count > 0)
            {
                return(candles);
            }

            var usdtCandles = _candlesService.GetCandles(_broker, $"{symbol}USDT", Timeframe.M5, updateCandles, minOpenTimeUtc, maxCloseTimeUtc);

            if (usdtCandles != null && usdtCandles.Count > 0)
            {
                var btcUsdtCandles = _candlesService.GetCandles(_broker, "BTCUSDT", Timeframe.M5, updateCandles, minOpenTimeUtc, maxCloseTimeUtc);
                candles = new List <Candle>();
                int btcCandleIndex = 0;

                foreach (var c in usdtCandles)
                {
                    btcCandleIndex = btcUsdtCandles.BinarySearchGetItem(i => btcUsdtCandles[i].CloseTimeTicks,
                                                                        btcCandleIndex, c.CloseTimeTicks, BinarySearchMethod.PrevLowerValueOrValue);

                    var btcPrice = btcUsdtCandles[btcCandleIndex].OpenBid;
                    candles.Add(new Candle()
                    {
                        OpenBid        = c.OpenBid / btcPrice,
                        CloseBid       = c.CloseBid / btcPrice,
                        HighBid        = c.HighBid / btcPrice,
                        LowBid         = c.LowBid / btcPrice,
                        OpenTimeTicks  = c.OpenTimeTicks,
                        CloseTimeTicks = c.CloseTimeTicks
                    });
                }
            }
            else
            {
                var bnbCandles = _candlesService.GetCandles(_broker, $"{symbol}BNB", Timeframe.M5, updateCandles, minOpenTimeUtc, maxCloseTimeUtc);
                if (bnbCandles != null && bnbCandles.Count > 0)
                {
                    var bnbUsdtCandles = _candlesService.GetCandles(_broker, "BNBUSDT", Timeframe.M5, updateCandles, minOpenTimeUtc, maxCloseTimeUtc);
                    candles = new List <Candle>();
                    int bnbCandleIndex = 0;

                    foreach (var c in bnbCandles)
                    {
                        bnbCandleIndex = bnbUsdtCandles.BinarySearchGetItem(i => bnbUsdtCandles[i].CloseTimeTicks,
                                                                            bnbCandleIndex, c.CloseTimeTicks, BinarySearchMethod.PrevLowerValueOrValue);

                        if (bnbCandleIndex != -1)
                        {
                            var btcPrice = bnbUsdtCandles[bnbCandleIndex].OpenBid;
                            candles.Add(new Candle()
                            {
                                OpenBid        = c.OpenBid / btcPrice,
                                CloseBid       = c.CloseBid / btcPrice,
                                HighBid        = c.HighBid / btcPrice,
                                LowBid         = c.LowBid / btcPrice,
                                OpenTimeTicks  = c.OpenTimeTicks,
                                CloseTimeTicks = c.CloseTimeTicks
                            });
                        }
                    }
                }
            }

            return(candles);
        }
        public static List <Candle> GetCandlesUptoSpecificTime(this IBrokersCandlesService brokerCandles,
                                                               IBroker broker, string market,
                                                               Timeframe timeframe, bool updateCandles, DateTime?startUtc, DateTime?endUtc,
                                                               Timeframe smallestTimeframeForPartialCandle = Timeframe.M1)
        {
            var allLargeChartCandles     = brokerCandles.GetCandles(broker, market, timeframe, updateCandles, cacheData: false, minOpenTimeUtc: startUtc, maxCloseTimeUtc: endUtc);
            var smallestTimeframeCandles = brokerCandles.GetCandles(broker, market, smallestTimeframeForPartialCandle, updateCandles, cacheData: false, maxCloseTimeUtc: endUtc);

            var largeChartCandles = new List <Candle>();
            var endTicks          = endUtc?.Ticks ?? -1;
            var endTimeTicks      = endUtc?.Ticks;

            // Add complete candle
            for (var i = 0; i < allLargeChartCandles.Count; i++)
            {
                var currentCandle = allLargeChartCandles[i];
                if (endTimeTicks == null || currentCandle.CloseTimeTicks <= endTimeTicks)
                {
                    largeChartCandles.Add(currentCandle);
                }
            }

            // Add incomplete candle
            var   latestCandleTimeTicks = largeChartCandles[largeChartCandles.Count - 1].CloseTimeTicks;
            float?openBid = null, closeBid = null, highBid = null, lowBid = null;
            float?openAsk = null, closeAsk = null, highAsk = null, lowAsk = null;
            long? openTimeTicks = null, closeTimeTicks = null;

            foreach (var smallestTimeframeCandle in smallestTimeframeCandles)
            {
                if (smallestTimeframeCandle.OpenTimeTicks >= latestCandleTimeTicks && (smallestTimeframeCandle.CloseTimeTicks <= endTicks || endTicks == -1))
                {
                    if (openTimeTicks == null)
                    {
                        openTimeTicks = smallestTimeframeCandle.OpenTimeTicks;
                    }

                    if (openBid == null || smallestTimeframeCandle.OpenBid < openBid)
                    {
                        openBid = smallestTimeframeCandle.OpenBid;
                    }
                    if (highBid == null || smallestTimeframeCandle.HighBid > highBid)
                    {
                        highBid = smallestTimeframeCandle.HighBid;
                    }
                    if (lowBid == null || smallestTimeframeCandle.LowBid < lowBid)
                    {
                        lowBid = smallestTimeframeCandle.LowBid;
                    }
                    closeBid = smallestTimeframeCandle.CloseBid;

                    if (openAsk == null || smallestTimeframeCandle.OpenAsk < openAsk)
                    {
                        openAsk = smallestTimeframeCandle.OpenAsk;
                    }
                    if (highAsk == null || smallestTimeframeCandle.HighAsk > highAsk)
                    {
                        highAsk = smallestTimeframeCandle.HighAsk;
                    }
                    if (lowAsk == null || smallestTimeframeCandle.LowAsk < lowAsk)
                    {
                        lowAsk = smallestTimeframeCandle.LowAsk;
                    }
                    closeAsk = smallestTimeframeCandle.CloseAsk;

                    closeTimeTicks = smallestTimeframeCandle.CloseTimeTicks;
                }

                if (smallestTimeframeCandle.CloseTime() > endUtc)
                {
                    break;
                }
            }

            if (openBid != null)
            {
                largeChartCandles.Add(new Candle
                {
                    OpenBid        = openBid.Value,
                    CloseBid       = closeBid.Value,
                    HighBid        = highBid.Value,
                    LowBid         = lowBid.Value,
                    OpenAsk        = openAsk.Value,
                    CloseAsk       = closeAsk.Value,
                    HighAsk        = highAsk.Value,
                    LowAsk         = lowAsk.Value,
                    CloseTimeTicks = closeTimeTicks.Value,
                    OpenTimeTicks  = openTimeTicks.Value,
                    IsComplete     = 0
                });
            }

            return(largeChartCandles);
        }
        public static void UpdateRMultiple(Trade trade)
        {
            if (trade.RiskAmount != null && trade.RiskAmount.Value != 0M && trade.Profit != null)
            {
                trade.RMultiple = trade.Profit / trade.RiskAmount;
            }
            else if (trade.EntryPrice != null && trade.EntryDateTime != null && trade.ClosePrice != null && trade.StopPrices.Count > 0)
            {
                // Get stop price at entry
                DatePrice entryStop = null;
                foreach (var stop in trade.StopPrices)
                {
                    if (entryStop == null || stop.Date <= trade.EntryDateTime.Value)
                    {
                        entryStop = stop;
                    }
                    else
                    {
                        break;
                    }
                }

                if (entryStop?.Price != null)
                {
                    var oneR = Math.Abs(trade.EntryPrice.Value - entryStop.Price.Value);
                    if (trade.TradeDirection == TradeDirection.Long)
                    {
                        trade.RMultiple = oneR != 0 ? (decimal?)(trade.ClosePrice.Value - trade.EntryPrice.Value) / oneR : null;
                    }
                    else if (oneR != 0)
                    {
                        trade.RMultiple = trade.EntryPrice.Value != trade.ClosePrice.Value ? (trade.EntryPrice.Value - trade.ClosePrice.Value) / oneR : 0;
                    }
                    else
                    {
                        trade.RMultiple = null;
                    }
                }
            }
            else if (trade.EntryPrice != null && trade.EntryDateTime != null && trade.ClosePrice == null && trade.InitialStop != null && trade.CalculateOptions.HasFlag(CalculateOptions.IncludeOpenTradesInRMultipleCalculation))
            {
                var stopPrice     = trade.InitialStop.Value;
                var risk          = Math.Abs(stopPrice - trade.EntryPrice.Value);
                var currentCandle = _candlesService.GetCandles(_brokersService.GetBroker(trade.Broker), trade.Market, Timeframe.D1, false, cacheData: false).Last();
                var currentClose  = trade.TradeDirection == TradeDirection.Long
                    ? (decimal)currentCandle.CloseBid
                    : (decimal)currentCandle.CloseAsk;

                // Get stop price at entry
                DatePrice entryStop = null;
                foreach (var stop in trade.StopPrices)
                {
                    if (entryStop == null || stop.Date <= trade.EntryDateTime.Value)
                    {
                        entryStop = stop;
                    }
                    else
                    {
                        break;
                    }
                }

                if (entryStop?.Price != null)
                {
                    var oneR = Math.Abs(trade.EntryPrice.Value - entryStop.Price.Value);
                    if (trade.TradeDirection == TradeDirection.Long)
                    {
                        trade.RMultiple = (currentClose - trade.EntryPrice.Value) / oneR;
                    }
                    else
                    {
                        trade.RMultiple = (trade.EntryPrice.Value - currentClose) / oneR;
                    }
                }
            }
            else
            {
                trade.RMultiple = null;
            }
        }
        private void RunLive(string selectedStrategyFilename)
        {
            var trades                     = new TradeWithIndexingCollection();
            var strategyLookup             = new Dictionary <string, StrategyBase>();
            var candlesLookup              = new Dictionary <string, TimeframeLookup <List <Candle> > >();
            var accountSaveIntervalSeconds = 60;
            var accountLastSaveTime        = DateTime.UtcNow;

            Log.Info("Running live");

            // Get strategy type and markets
            var strategyType = CompileStrategyAndGetStrategyMarkets(selectedStrategyFilename, out var markets, out var timeframes);

            if (strategyType == null)
            {
                return;
            }

            // Update broker account
            Log.Info("Updating broker account");
            _brokerAccount.UpdateBrokerAccount(_fxcm, _candlesService, _marketDetailsService, _tradeDetailsAutoCalculatorService, UpdateOption.ForceUpdate);

            // Get candles
            Log.Info("Getting candles");
            foreach (var m in markets)
            {
                candlesLookup[m] = new TimeframeLookup <List <Candle> >();

                foreach (var t in timeframes)
                {
                    candlesLookup[m].Add(t, _candlesService.GetCandles(_fxcm, m, t, true, forceUpdate: true, cacheData: true));
                }
            }

            // Setup locks
            foreach (var market in markets)
            {
                _marketLock[market] = new object();
            }

            // Create strategies
            Log.Info("Setting up strategies");
            foreach (var market in markets)
            {
                var strategy       = (StrategyBase)Activator.CreateInstance(strategyType);
                var currentCandles = new TimeframeLookup <List <Candle> >();
                strategy.SetSimulationParameters(trades, currentCandles, _marketDetailsService.GetMarketDetails("FXCM", market));
                strategyLookup.Add(market, strategy);

                // Setup candles for strategy
                foreach (var t in timeframes)
                {
                    currentCandles.Add(t, candlesLookup[market][t].Where(c => c.IsComplete == 1).ToList());
                }
            }

            // Get live prices steams
            var priceMonitor = new MonitorLivePrices(_fxcm, p => ProcessNewPrice(markets, timeframes, p, candlesLookup));

            try
            {
                var checkFxcmConnectedIntervalSeconds = 60 * 5;
                var nextFxcmConnectedCheckTime        = DateTime.UtcNow.AddSeconds(checkFxcmConnectedIntervalSeconds);

                Log.Info("Running main processing loop");
                while (true)
                {
                    if (accountLastSaveTime < DateTime.UtcNow.AddSeconds(-accountSaveIntervalSeconds))
                    {
                        lock (_brokerAccount)
                        {
                            Log.Debug("Saving broker account");
                            _brokerAccount.SaveAccount(
                                DataDirectoryService.GetMainDirectoryWithApplicationName("TradeLog"));
                        }

                        accountLastSaveTime = DateTime.UtcNow;
                    }

                    // Re-connect if connect is lost
                    if (DateTime.UtcNow >= nextFxcmConnectedCheckTime)
                    {
                        nextFxcmConnectedCheckTime = DateTime.UtcNow.AddSeconds(checkFxcmConnectedIntervalSeconds);
                        if (_fxcm.Status == ConnectStatus.Disconnected)
                        {
                            Log.Warn("FXCM has disconnected - reconnecting");
                            try
                            {
                                priceMonitor?.Dispose();
                            }
                            catch (Exception ex)
                            {
                                Log.Error("Unable to dispose price monitor", ex);
                            }

                            priceMonitor = null;

                            _fxcm.Connect();

                            if (_fxcm.Status == ConnectStatus.Connected)
                            {
                                Log.Warn($"FXCM has reconnected");
                                priceMonitor = new MonitorLivePrices(_fxcm, p => ProcessNewPrice(markets, timeframes, p, candlesLookup));
                            }
                            else
                            {
                                Log.Warn($"FXCM hasn't re-connected - new status is: {_fxcm.Status}");
                            }
                        }
                    }

                    foreach (var strategy in strategyLookup.Values)
                    {
                        var newTimeframeCandles = new List <Timeframe>();

                        // Check if there is any new complete candles
                        foreach (var t in strategy.Timeframes)
                        {
                            lock (candlesLookup[strategy.Market.Name][t])
                            {
                                if (strategy.Candles[t].Count !=
                                    candlesLookup[strategy.Market.Name][t].Count(c => c.IsComplete == 1))
                                {
                                    newTimeframeCandles.Add(t);
                                    strategy.Candles[t].Clear();
                                    strategy.Candles[t].AddRange(candlesLookup[strategy.Market.Name][t]
                                                                 .Where(c => c.IsComplete == 1).ToList());
                                }
                            }
                        }

                        if (newTimeframeCandles.Any()) // TODO reduce times this is called and include save
                        {
                            // Update broker account
                            lock (_brokerAccount)
                            {
                                Log.Debug("Updating and saving broker account");
                                _brokerAccount.UpdateBrokerAccount(_fxcm, _candlesService, _marketDetailsService,
                                                                   _tradeDetailsAutoCalculatorService, UpdateOption.ForceUpdate);
                            }

                            var s = strategy;
                            Task.Run(() =>
                            {
                                if (Monitor.TryEnter(_marketLock[s.Market.Name]))
                                {
                                    try
                                    {
                                        Log.Info($"Found new candles for market: {s.Market.Name}");

                                        // Update indicators and do trades maintenance
                                        s.UpdateIndicators(newTimeframeCandles);
                                        s.NewTrades.Clear();
                                        s.Trades.MoveTrades();

                                        var beforeStopLossLookup =
                                            s.Trades.OpenTrades.ToDictionary(x => x.Trade.Id, x => x.Trade.StopPrice);

                                        // Process strategy
                                        s.ProcessCandles(newTimeframeCandles);

                                        // Create any new trades
                                        CreateNewFXCMTradesAndUpdateAccount(s);

                                        if (trades.OpenTrades.Count() > 5)
                                        {
                                            Log.Error("Too many trades");
                                        }

                                        // Update any stops
                                        UpdateFXCMOpenTradesStops(s, beforeStopLossLookup);
                                    }
                                    finally
                                    {
                                        Monitor.Exit(_marketLock[s.Market.Name]);
                                    }
                                }
                            });
                        }
                    }

                    Thread.Sleep(100);
                }
            }
            finally
            {
                priceMonitor.Dispose();
            }
        }