Beispiel #1
0
        public void RecalculateTrade(Trade trade, IBrokersCandlesService candleService, IMarketDetailsService marketsService, IBroker broker)
        {
            // Update price per pip
            if (trade.EntryQuantity != null && trade.EntryDateTime != null)
            {
                trade.PricePerPip = candleService.GetGBPPerPip(marketsService, broker, trade.Market,
                                                               trade.EntryQuantity.Value, trade.EntryDateTime.Value, true);
            }

            // Update risk
            if (trade.InitialStopInPips == null || trade.PricePerPip == null)
            {
                trade.RiskPercentOfBalance = null;
                trade.RiskAmount           = null;
                trade.RiskPercentOfBalance = null;
            }
            else
            {
                trade.RiskAmount = trade.PricePerPip.Value * trade.InitialStopInPips.Value;

                var balance = GetBalance(trade.StartDateTime);
                if (balance != 0.0M)
                {
                    var startTime = trade.OrderDateTime ?? trade.EntryDateTime;
                    trade.RiskPercentOfBalance = (trade.RiskAmount * 100M) / GetBalance(startTime);
                }
                else
                {
                    trade.RiskPercentOfBalance = null;
                }
            }
        }
        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));
        }
 public StrategyRunner(IBrokersCandlesService candleService, IMarketDetailsService marketDetailsService, IBroker broker, MarketDetails market)
 {
     _candleService        = candleService;
     _marketDetailsService = marketDetailsService;
     _broker = broker;
     _market = market;
 }
        public static decimal GetGBPPerPip(
            this IBrokersCandlesService candleService,
            IMarketDetailsService marketsService,
            IBroker broker, string market, decimal lotSize,
            DateTime date, bool updateCandles)
        {
            var     marketDetails = marketsService.GetMarketDetails(broker.Name, market);
            decimal price         = 0M;

            // If market contains GBP, then use the market for the price
            if (market.Contains("GBP"))
            {
                price = (decimal)candleService.GetLastClosedCandle(market, broker, Timeframe.D1, date, updateCandles).Value.OpenBid;

                if (market.StartsWith("GBP"))
                {
                    price = 1M / price;
                }
            }
            else
            {
                // Try to get GBP candle, if it exists
                var marketForPrice = !market.Contains("/") ? $"GBP/{marketDetails.Currency}" : $"GBP/{market.Split('/')[1]}";

                if (!marketsService.HasMarketDetails(broker.Name, marketForPrice))
                {
                    marketForPrice = $"{marketForPrice.Split('/')[1]}/{marketForPrice.Split('/')[0]}";
                }

                if (marketForPrice == "GBP/GBP")
                {
                    price = 1M;
                }
                else
                {
                    // Get candle price, if it exists
                    if (marketsService.HasMarketDetails(broker.Name, marketForPrice))
                    {
                        price = (decimal)candleService.GetLastClosedCandle(marketForPrice, broker, Timeframe.D1, date, updateCandles).Value.OpenBid;
                    }
                    else
                    {
                        // Otherwise, try to get the USD candle and convert back to GBP
                        // Try to get $ candle and convert to £
                        var usdCandle    = candleService.GetLastClosedCandle($"USD/{market.Split('/')[1]}", broker, Timeframe.D1, date, updateCandles);
                        var gbpUSDCandle = candleService.GetLastClosedCandle("GBP/USD", broker, Timeframe.D1, date, updateCandles);
                        price = (decimal)gbpUSDCandle.Value.OpenBid / (decimal)usdCandle.Value.OpenBid;
                    }
                }

                if (marketForPrice.StartsWith("GBP"))
                {
                    price = 1M / price;
                }
            }

            return(lotSize * (decimal)marketDetails.ContractMultiplier * (decimal)marketDetails.PointSize * price);
        }
        /// <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 #6
0
 public StrategyRunner(
     IBrokersCandlesService candleService,
     IBroker broker,
     IBrokersService brokersService)
 {
     _candleService  = candleService;
     _broker         = broker;
     _brokersService = brokersService;
 }
Beispiel #7
0
        public bool UpdateAccount(
            IBrokerAccount account,
            IBrokersCandlesService candlesService,
            IMarketDetailsService marketsService,
            Action <string> updateProgressAction,
            out List <Trade> addedOrUpdatedTrades)
        {
            addedOrUpdatedTrades = new List <Trade>();

            var limit = 500;

            foreach (var symbol in GetSymbols())
            {
                Log.Debug($"Updating account for {symbol}");

                // Get highest order ID
                var maxId = account.Trades.Count(t => t.CloseDateTime != null && t.Market == symbol) == 0 ? 1 : account.Trades
                            .Where(t => t.CloseDateTime != null && t.Market == symbol)
                            .Max(t => Convert.ToInt64(t.Id));
                WebCallResult <IEnumerable <BinanceOrder> > orders = null;

                // Get orders
                while (orders == null || orders.Data.Count() == limit)
                {
                    orders = _client.Spot.Order.GetAllOrders(symbol, orderId: maxId);

                    if (orders.Success == false && orders.Error.Code == -1003)
                    {
                        Log.Info("Too many Binance requests - pausing requests");
                        // -1003 = Too many requests
                        Thread.Sleep(60 * 1000);
                        orders = null;
                        continue;
                    }

                    if (orders.Success)
                    {
                        AddOrUpdateOrders(account, addedOrUpdatedTrades, orders);
                    }
                    else
                    {
                        Log.Error($"Unable to get orders for symbol {symbol} - {orders.Error.Message}");
                        break;
                    }

                    maxId = account.Trades.Count(t => t.CloseDateTime != null && t.Market == symbol) == 0 ? 1 : account.Trades
                            .Where(t => t.CloseDateTime != null && t.Market == symbol)
                            .Max(t => Convert.ToInt64(t.Id));
                }
            }

            Log.Info($"Binance account updated - {addedOrUpdatedTrades} trades added or updated");


            return(true);
        }
Beispiel #8
0
        public void UpdateBrokerAccount(
            IBroker broker,
            IBrokersCandlesService candleService,
            IMarketDetailsService marketsService,
            ITradeDetailsAutoCalculatorService tradeCalculateService,
            UpdateOption option = UpdateOption.OnlyIfNotRecentlyUpdated)
        {
            void UpdateProgressAction(string txt)
            {
            }

            UpdateBrokerAccount(broker, candleService, marketsService, tradeCalculateService, UpdateProgressAction, option);
        }
        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();
            }
        }
Beispiel #10
0
        public Trainer(IBrokersCandlesService candlesService, IBrokersService brokersService)
        {
            _candlesService = candlesService;
            _brokersService = brokersService;

            _dataGenerator = new DataGenerator(_candlesService, _brokersService);
            ManualResetEvent dispatcherReadyEvent = new ManualResetEvent(false);

            new Thread(new ThreadStart(() =>
            {
                _modelDispatcher = Dispatcher.CurrentDispatcher;
                dispatcherReadyEvent.Set();
                Dispatcher.Run();
            })).Start();

            dispatcherReadyEvent.WaitOne();
        }
Beispiel #11
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);
        }
Beispiel #12
0
        public static decimal GetProfitForLatestDay(this Trade trade, IBrokersCandlesService candlesService, IBrokersService brokersService, IMarketDetailsService marketDetailsService)
        {
            var broker = brokersService.Brokers.FirstOrDefault(x => x.Name == trade.Broker);

            if (broker != null)
            {
                var marketDetails = marketDetailsService.GetMarketDetails(broker.Name, trade.Market);

                var now     = DateTime.UtcNow;
                var endDate = trade.CloseDateTime != null
                    ? new DateTime(trade.CloseDateTime.Value.Year, trade.CloseDateTime.Value.Month, trade.CloseDateTime.Value.Day, 23,
                                   59, 59, DateTimeKind.Utc)
                    : new DateTime(now.Year, now.Month, now.Day, 23, 59, 59, DateTimeKind.Utc);
                var startDate = new DateTime(endDate.Year, endDate.Month, endDate.Day, 0, 0, 0, DateTimeKind.Utc);
                return(trade.GetTradeProfit(endDate, Basics.Timeframe.D1, candlesService, marketDetails, broker, false)
                       - trade.GetTradeProfit(startDate, Basics.Timeframe.D1, candlesService, marketDetails, broker, false));
            }

            return(decimal.MinValue);
        }
Beispiel #13
0
        public void UpdateBrokerAccount(
            IBroker broker,
            IBrokersCandlesService candleService,
            IMarketDetailsService marketsService,
            ITradeDetailsAutoCalculatorService tradeCalculateService,
            Action <string> updateProgressAction,
            UpdateOption option = UpdateOption.OnlyIfNotRecentlyUpdated)
        {
            if (option == UpdateOption.OnlyIfNotRecentlyUpdated && (AccountLastUpdated != null && (DateTime.UtcNow - AccountLastUpdated.Value).TotalHours < 24))
            {
                return;
            }

            Log.Debug($"Updating {broker.Name} account");

            foreach (var t in Trades)
            {
                tradeCalculateService.RemoveTrade(t);
            }

            try
            {
                broker.UpdateAccount(this, candleService, marketsService, updateProgressAction, out var addedOrUpdatedTrades);

                foreach (var trade in addedOrUpdatedTrades)
                {
                    RecalculateTrade(trade, candleService, marketsService, broker);
                }
            }
            catch (Exception ex)
            {
                Log.Error("Unable to update account", ex);
                MessageBox.Show($"Unable to update account - {ex.Message}", "Unable to update account", MessageBoxButtons.OK);
            }

            AccountLastUpdated = DateTime.UtcNow;

            Log.Debug($"Completed updating {broker.Name} trades");
            _brokerAccountUpdatedSubject.OnNext(new BrokerAccountUpdated(this));
        }
Beispiel #14
0
        public static decimal GetTradeProfit(this Trade trade, DateTime dateTimeUTC, Timeframe candlesTimeframe,
                                             IBrokersCandlesService candlesService, MarketDetails marketDetails, IBroker broker, bool updateCandles)
        {
            if (trade.EntryPrice == null || trade.EntryDateTime == null)
            {
                return(0M);
            }

            if (trade.CloseDateTime != null && trade.CloseDateTime.Value <= dateTimeUTC)
            {
                return(trade.Profit ?? 0M);
            }

            if (trade.EntryDateTime >= dateTimeUTC)
            {
                return(0M);
            }

            var latestCandle = candlesService.GetLastClosedCandle(
                trade.Market, broker, candlesTimeframe, dateTimeUTC, updateCandles);

            if (latestCandle != null && trade.PricePerPip != null)
            {
                var closePriceToUse = trade.TradeDirection == TradeDirection.Long
                    ? (decimal)latestCandle.Value.CloseBid
                    : (decimal)latestCandle.Value.CloseAsk;
                var profitPips       = PipsHelper.GetPriceInPips(trade.TradeDirection == TradeDirection.Long ? closePriceToUse - trade.EntryPrice.Value : trade.EntryPrice.Value - closePriceToUse, marketDetails);
                var totalRunningTime = (DateTime.UtcNow - trade.EntryDateTime.Value).TotalDays;
                var runningTime      = (trade.EntryDateTime.Value - dateTimeUTC).TotalDays;

                var tradeProfit = trade.PricePerPip.Value * profitPips +
                                  (!totalRunningTime.Equals(0.0) && trade.Rollover != null
                                      ? trade.Rollover.Value * (decimal)(runningTime / totalRunningTime)
                                      : 0M);

                return(tradeProfit);
            }

            return(0M);
        }
Beispiel #15
0
        public static void UpdateCandles(IBroker broker, IBrokersCandlesService candlesService,
                                         IEnumerable <string> markets, IEnumerable <Timeframe> timeframes, int threads = 3, Action <string> updateProgressAction = null)
        {
            var completed        = 0;
            var total            = 0;
            var producerConsumer =
                new ProducerConsumer <(string Market, Timeframe Timeframe)>(threads,
                                                                            d =>
            {
                Log.Info($"Updating {d.Data.Timeframe} candles for {d.Data.Market}");
                candlesService.UpdateCandles(broker, d.Data.Market, d.Data.Timeframe);
                candlesService.UnloadCandles(d.Data.Market, d.Data.Timeframe, broker);
                Log.Info($"Updated {d.Data.Timeframe} candles for {d.Data.Market}");

                Interlocked.Increment(ref completed);

                updateProgressAction?.Invoke($"Updated {completed}/{total} markets/timeframes");

                return(ProducerConsumerActionResult.Success);
            });


            foreach (var market in markets)
            {
                foreach (var timeframe in timeframes)
                {
                    total++;
                    producerConsumer.Add((market, timeframe));
                }
            }

            updateProgressAction?.Invoke($"Updating {total} markets/timeframes");

            producerConsumer.SetProducerCompleted();
            producerConsumer.Start();
            producerConsumer.WaitUntilConsumersFinished();
            Log.Info("Updated FX candles");
        }
 public DerivedMarketCandles(IBroker broker, IBrokersCandlesService candlesService)
 {
     _broker         = broker;
     _candlesService = candlesService;
 }
Beispiel #17
0
 public bool UpdateAccount(IBrokerAccount account, IBrokersCandlesService candlesService, IMarketDetailsService marketsService,
                           Action <string> updateProgressAction, out List <Trade> addedOrUpdatedTrades)
 {
     throw new NotImplementedException();
 }
        public static List <Trade> Run(
            Type strategyType, Func <bool> stopFunc,
            IBrokersCandlesService candlesService, IMarketDetailsService marketDetailsService,
            IBroker broker, int threads)
        {
            var stopwatch      = Stopwatch.StartNew();
            var strategyMarket = new Dictionary <string, StrategyBase>();
            var completed      = 0;
            var trades         = new List <Trade>();

            var producerConsumer = new ProducerConsumer <(Type StrategyType, MarketDetails Market)>(
                threads, d =>
            {
                if (stopFunc?.Invoke() ?? false)
                {
                    return(ProducerConsumerActionResult.Stop);
                }

                var strategyTester =
                    new StrategyRunner(candlesService, marketDetailsService, broker,
                                       d.Market);

                var strategy = StrategyHelper.CreateStrategyInstance(d.StrategyType);

                lock (strategyMarket)
                {
                    strategyMarket[d.Market.Name] = strategy;
                }

                var marketTrades = strategyTester.Run(strategy, stopFunc, strategy.StartTime, strategy.EndTime);

                if (marketTrades != null)
                {
                    lock (trades)
                    {
                        trades.AddRange(marketTrades);
                    }

                    // _results.AddResult(result);

                    // Adding trades to UI in realtime slows down the UI too much with strategies with many trades

                    completed++;
                    Log.Info($"Completed {completed}/{strategy.Markets.Length}");
                }

                return(ProducerConsumerActionResult.Success);
            });

            foreach (var market in StrategyHelper.GetStrategyMarkets(strategyType))
            {
                producerConsumer.Add((strategyType, marketDetailsService.GetMarketDetails(broker.Name, market)));
            }

            producerConsumer.Start();
            producerConsumer.SetProducerCompleted();
            producerConsumer.WaitUntilConsumersFinished();

            //var trades = _results.Results.ToList();

            // Set trade profits
            var balance = 10000M;

            foreach (var t in trades.OrderBy(z => z.OrderDateTime ?? z.EntryDateTime))
            {
                var riskAmount = (strategyMarket[t.Market].RiskEquityPercent / 100M) * balance;
                var profit     = t.RMultiple * riskAmount ?? 0M;
                t.NetProfitLoss = profit;
                t.RiskAmount    = riskAmount;
                balance        += profit;

                if (balance < 0)
                {
                    balance = 0M;
                }
            }

            stopwatch.Stop();
            Log.Info($"Simulation run completed in {stopwatch.Elapsed.TotalSeconds}s");

            return(trades);
        }
        public static List <(DateTime Time, decimal Value)> GetDailyTotalNetMoneyIn(IBroker broker, BrokerAccount account, IBrokersCandlesService candlesService)
        {
            var ret = new List <(DateTime Time, decimal Value)>();

            /*for (var date = new DateTime(2018, 1, 1); date <= DateTime.UtcNow; date = date.AddDays(1))
             * {
             *  var netMoneyIn = 0.0M;
             *  foreach (var depositWithdrawal in account.DepositsWithdrawals.Where(x => x.Time <= date))
             *  {
             *      netMoneyIn += CryptoValueHelper.GetAssetUsdValue(candlesService, broker, depositWithdrawal.Asset, depositWithdrawal.Time, depositWithdrawal.Amount);
             *  }
             *
             *  ret.Add((date, netMoneyIn));
             * }*/

            return(ret);
        }
 public DataGenerator(IBrokersCandlesService candlesService, IBrokersService brokersService)
 {
     _candlesService = candlesService;
     _brokersService = brokersService;
 }
        public static List <(DateTime Time, decimal Value)> GetDailyTotalValues(IBroker broker, BrokerAccount account, IBrokersCandlesService candlesService)
        {
            var ret = new List <(DateTime Time, decimal Value)>();

            /*var now = DateTime.UtcNow;
             *
             * for (var date = new DateTime(2018, 1, 1); date <= now; date = date.AddDays(1))
             * {
             *  var assetBalances = account.GetAssetBalances(broker, candlesService, date);
             *
             *  if (date == now)
             *  {
             *  }
             *
             *  // Convert to USDs
             *  var value = 0.0M;
             *  foreach (var assetBalance in assetBalances)
             *  {
             *      value += CryptoValueHelper.GetAssetUsdValue(candlesService, broker, assetBalance.Asset, date, assetBalance.Amount);
             *  }
             *
             *  ret.Add((date, value));
             * }*/

            return(ret);
        }
Beispiel #22
0
 public CryptoTransactionsUSDTCalculator(IBrokersCandlesService candlesService, IBroker binanceBroker)
 {
     _candlesService = candlesService;
     _binanceBroker  = binanceBroker;
 }
Beispiel #23
0
 public MLDataWriter(IBroker broker, IBrokersCandlesService candlesService)
 {
     _broker         = broker;
     _candlesService = candlesService;
 }
 static TradeCalculator()
 {
     _candlesService = DependencyContainer.Container.GetExportedValue <IBrokersCandlesService>();
     _brokersService = DependencyContainer.Container.GetExportedValue <IBrokersService>();
     _marketsService = DependencyContainer.Container.GetExportedValue <IMarketDetailsService>();
 }
        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);
        }