private static ExecutionMessage CreateTick(CandleMessage candleMsg, Sides side, decimal price, decimal volume, decimal?openInterest = null) { return(new ExecutionMessage { LocalTime = candleMsg.LocalTime, SecurityId = candleMsg.SecurityId, ServerTime = candleMsg.OpenTime, //TradeId = _tradeIdGenerator.Next, TradePrice = price, Volume = volume, Side = side, ExecutionType = ExecutionTypes.Tick, OpenInterest = openInterest }); }
private void ProcessCandleMessage(CandleMessage message) { if (!UseExternalCandleSource) { return; } var security = GetSecurity(message.SecurityId); var series = _series.TryGetValue(security); if (series != null) { _newCandles.SafeInvoke(series, new[] { message.ToCandle(series) }); } }
/// <summary> /// To create tick trades from candle. /// </summary> /// <param name="candleMsg">Candle.</param> /// <param name="volumeStep">Volume step.</param> /// <param name="decimals">The number of decimal places for the volume.</param> /// <returns>Tick trades.</returns> public static IEnumerable <ExecutionMessage> ToTrades(this CandleMessage candleMsg, decimal volumeStep, int decimals) { if (candleMsg == null) { throw new ArgumentNullException(nameof(candleMsg)); } var vol = MathHelper.Round(candleMsg.TotalVolume / 4, volumeStep, decimals, MidpointRounding.AwayFromZero); var isUptrend = candleMsg.ClosePrice >= candleMsg.OpenPrice; ExecutionMessage o = null; ExecutionMessage h = null; ExecutionMessage l = null; ExecutionMessage c = null; if (candleMsg.OpenPrice == candleMsg.ClosePrice && candleMsg.LowPrice == candleMsg.HighPrice && candleMsg.OpenPrice == candleMsg.LowPrice || candleMsg.TotalVolume == 1) { // все цены в свече равны или объем равен 1 - считаем ее за один тик o = CreateTick(candleMsg, Sides.Buy, candleMsg.OpenPrice, candleMsg.TotalVolume, candleMsg.OpenInterest); } else if (candleMsg.TotalVolume == 2) { h = CreateTick(candleMsg, Sides.Buy, candleMsg.HighPrice, 1); l = CreateTick(candleMsg, Sides.Sell, candleMsg.LowPrice, 1, candleMsg.OpenInterest); } else if (candleMsg.TotalVolume == 3) { o = CreateTick(candleMsg, isUptrend ? Sides.Buy : Sides.Sell, candleMsg.OpenPrice, 1); h = CreateTick(candleMsg, Sides.Buy, candleMsg.HighPrice, 1); l = CreateTick(candleMsg, Sides.Sell, candleMsg.LowPrice, 1, candleMsg.OpenInterest); } else { o = CreateTick(candleMsg, isUptrend ? Sides.Buy : Sides.Sell, candleMsg.OpenPrice, vol); h = CreateTick(candleMsg, Sides.Buy, candleMsg.HighPrice, vol); l = CreateTick(candleMsg, Sides.Sell, candleMsg.LowPrice, vol); c = CreateTick(candleMsg, isUptrend ? Sides.Buy : Sides.Sell, candleMsg.ClosePrice, candleMsg.TotalVolume - 3 * vol, candleMsg.OpenInterest); } var ticks = candleMsg.ClosePrice > candleMsg.OpenPrice ? new[] { o, l, h, c } : new[] { o, h, l, c }; return(ticks.Where(t => t != null)); }
public IEnumerable <Tuple <Subscription, Candle> > UpdateCandles(CandleMessage message) { foreach (var subscriptionId in message.GetSubscriptionIds()) { SubscriptionInfo info; lock (_syncObject) { if (!_subscriptions.TryGetValue(subscriptionId, out info)) { TryWriteLog(subscriptionId); continue; } if (info.Security == null) { if (info.SecurityNotFound) { continue; } var security = _connector.TryGetSecurity(info.Subscription.SecurityId); if (security == null) { info.SecurityNotFound = true; _connector.AddWarningLog(LocalizedStrings.Str704Params.Put(info.Subscription.SecurityId)); continue; } info.Security = security; } } if (!info.UpdateLastTime(message.OpenTime)) { continue; } if (!info.UpdateCandle(message, out var candle)) { continue; } yield return(Tuple.Create(info.Subscription, candle)); } }
/// <summary> /// Update candle by new message. /// </summary> /// <param name="message">Message.</param> /// <param name="candle">Updated candle.</param> /// <returns>Candles series.</returns> public CandleSeries UpdateCandle(CandleMessage message, out Candle candle) { if (message == null) { throw new ArgumentNullException(nameof(message)); } var info = _holders.TryGetValue(message.OriginalTransactionId); if (info != null) { return(info.UpdateCandle(message, out candle)); } candle = null; return(null); }
private void ProcessCandle(SeriesInfo info, CandleMessage candleMsg) { if (info.CurrentCandle != null && info.CurrentCandle.OpenTime == candleMsg.OpenTime) { if (info.CurrentCandle.State == CandleStates.Finished) { return; } info.CurrentCandle.Update(candleMsg); } else { info.CurrentCandle = candleMsg.ToCandle(info.Series); } Processing?.Invoke(info.Series, info.CurrentCandle); }
private void ProcessCandle(CandleMessage candleMsg) { var info = _seriesInfosByTransactions.TryGetValue(candleMsg.OriginalTransactionId); if (info != null) { SendCandle(info, candleMsg); if (!info.IsHistory) { TryProcessCandles(candleMsg, info); } } else { //RaiseNewOutMessage(candleMsg); TryProcessCandles(candleMsg, null); } }
/// <summary> /// Update candle by new message. /// </summary> /// <param name="message">Message.</param> /// <param name="candle">Updated candle.</param> /// <returns>Candles series.</returns> public CandleSeries UpdateCandle(CandleMessage message, out Candle candle) { candle = null; if (_currentCandle != null && _currentCandle.OpenTime == message.OpenTime) { if (_currentCandle.State == CandleStates.Finished) { return(null); } _currentCandle.Update(message); } else { _currentCandle = message.ToCandle(Series); } candle = _currentCandle; return(Series); }
/// <summary> /// Update candles by new message. /// </summary> /// <param name="transactionId">Request identifier.</param> /// <param name="message">Message.</param> /// <returns>Candles series.</returns> public Tuple <CandleSeries, Candle> UpdateCandles(long transactionId, CandleMessage message) { if (message == null) { throw new ArgumentNullException(nameof(message)); } var info = _holders.TryGetValue(transactionId); if (info == null) { return(null); } if (!info.UpdateCandle(message, out var candle)) { return(null); } return(Tuple.Create(info.Series, candle)); }
/// <summary> /// To process the new data. /// </summary> /// <param name="message">The message contains information about the time-frame candle.</param> /// <returns>A new candles changes.</returns> public IEnumerable <CandleMessage> Process(CandleMessage message) { foreach (var builtCandle in ProcessCandlePart(Level1Fields.OpenPrice, message)) { yield return((TimeFrameCandleMessage)builtCandle); } foreach (var builtCandle in ProcessCandlePart(Level1Fields.HighPrice, message)) { yield return((TimeFrameCandleMessage)builtCandle); } foreach (var builtCandle in ProcessCandlePart(Level1Fields.LowPrice, message)) { yield return((TimeFrameCandleMessage)builtCandle); } foreach (var builtCandle in ProcessCandlePart(Level1Fields.ClosePrice, message)) { yield return((TimeFrameCandleMessage)builtCandle); } }
/// <summary> /// Update candles by new message. /// </summary> /// <param name="message">Message.</param> /// <returns>Candles series.</returns> public IEnumerable <Tuple <CandleSeries, Candle, long> > UpdateCandles(CandleMessage message) { if (message == null) { throw new ArgumentNullException(nameof(message)); } foreach (var subscriptionId in message.GetSubscriptionIds()) { var info = _holders.TryGetValue(subscriptionId); if (info == null) { continue; } if (!info.UpdateCandle(message, out var candle)) { continue; } yield return(Tuple.Create(info.Series, candle, subscriptionId)); } }
DateTimeOffset IMarketDataStorageInfo <CandleMessage> .GetTime(CandleMessage data) => ((IMarketDataStorageInfo <CandleMessage>)_original).GetTime(data);
DateTimeOffset IMarketDataStorageInfo <CandleMessage> .GetTime(CandleMessage data) { return(data.OpenTime); }
private void LoadData(CandleSeries series) { _currCandle = null; _historyLoaded = false; _allCandles.Clear(); _candleTransform.Process(new ResetMessage()); _candleBuilder = series.CandleType.ToCandleMessageType().ToCandleMarketDataType().CreateCandleBuilder(); Chart.Reset(new IChartElement[] { _candleElement }); var storage = new StorageRegistry(); BusyIndicator.IsBusy = true; var path = HistoryPath.Folder; var isBuild = BuildFromTicks.IsChecked == true; var format = Format.SelectedFormat; var maxDays = (isBuild || series.CandleType != typeof(TimeFrameCandle)) ? 5 : 30 * (int)((TimeSpan)series.Arg).TotalMinutes; _mdMsg = series.ToMarketDataMessage(true); Task.Factory.StartNew(() => { var date = DateTime.MinValue; if (isBuild) { foreach (var tick in storage.GetTickMessageStorage(series.Security, new LocalMarketDataDrive(path), format).Load()) { _tradeGenerator.Process(tick); if (_candleTransform.Process(tick)) { var candles = _candleBuilder.Process(_mdMsg, _currCandle, _candleTransform); lock (_lock) { foreach (var candle in candles) { _currCandle = candle; _updatedCandles[candle.OpenTime] = Tuple.Create(candle, candle.State == CandleStates.Finished); } } } _lastTime = tick.ServerTime; if (date != tick.ServerTime.Date) { date = tick.ServerTime.Date; var str = date.To <string>(); this.GuiAsync(() => BusyIndicator.BusyContent = str); maxDays--; if (maxDays == 0) { break; } } } } else { foreach (var candleMsg in storage.GetCandleMessageStorage(series.CandleType.ToCandleMessageType(), series.Security, series.Arg, new LocalMarketDataDrive(path), format).Load()) { lock (_updatedCandles.SyncRoot) { _currCandle = candleMsg; _updatedCandles[candleMsg.OpenTime] = Tuple.Create(candleMsg, true); } _lastTime = candleMsg.OpenTime; if (candleMsg is TimeFrameCandleMessage) { _lastTime += (TimeSpan)series.Arg; } _tradeGenerator.Process(new ExecutionMessage { ExecutionType = ExecutionTypes.Tick, SecurityId = series.Security.ToSecurityId(), ServerTime = _lastTime, TradePrice = candleMsg.ClosePrice, }); if (date != candleMsg.OpenTime.Date) { date = candleMsg.OpenTime.Date; var str = date.To <string>(); this.GuiAsync(() => BusyIndicator.BusyContent = str); maxDays--; if (maxDays == 0) { break; } } } } _historyLoaded = true; }) .ContinueWith(t => { if (t.Exception != null) { Error(t.Exception.Message); } this.GuiAsync(() => { BusyIndicator.IsBusy = false; Chart.IsAutoRange = false; //_areaComb.YAxises.First().AutoRange = false; }); }, TaskScheduler.FromCurrentSynchronizationContext()); }
private IEnumerator <ExecutionMessage> CreateEnumerator(CandleMessage candleMsg) { return(candleMsg.ToTrades(_volumeStep, _decimals).GetEnumerator()); }
private void RefreshCharts() { if (Dispatcher.CheckAccess()) { _dataThreadActions.Add(RefreshCharts); return; } CandleSeries series = null; this.GuiSync(() => { Chart.ClearAreas(); _areaComb = new ChartArea(); var yAxis = _areaComb.YAxises.First(); yAxis.AutoRange = true; Chart.IsAutoRange = true; Chart.IsAutoScroll = true; Chart.AddArea(_areaComb); var id = (SecurityId)Securities.SelectedItem; _security = new Security { Id = id.ToStringId(), PriceStep = id.SecurityCode.StartsWith("RI", StringComparison.InvariantCultureIgnoreCase) ? 10 : id.SecurityCode.Contains("ES") ? 0.25m : 0.01m, Board = ExchangeBoard.Associated }; _tradeGenerator = new RandomWalkTradeGenerator(id); _tradeGenerator.Init(); _tradeGenerator.Process(_security.ToMessage()); series = new CandleSeries( SeriesEditor.Settings.CandleType, _security, SeriesEditor.Settings.Arg) { IsCalcVolumeProfile = true }; _candleElement = new ChartCandleElement { FullTitle = "Candles" }; Chart.AddElement(_areaComb, _candleElement, series); _currCandle = null; _historyLoaded = false; _allCandles.Clear(); _updatedCandles.Clear(); _dataThreadActions.Clear(); }); Chart.Reset(new IChartElement[] { _candleElement }); this.GuiAsync(() => LoadData(series)); }
private void LoadData(CandleSeries series) { var msgType = series.CandleType.ToCandleMessageType(); _transactionId = _transactionIdGenerator.GetNextId(); _holder.Clear(); _holder.CreateCandleSeries(_transactionId, series); _candleTransform.Process(new ResetMessage()); _candleBuilder = _builderProvider.Get(msgType.ToCandleMarketDataType()); var storage = new StorageRegistry(); BusyIndicator.IsBusy = true; var path = HistoryPath.Folder; var isBuild = BuildFromTicks.IsChecked == true; var format = Format.SelectedFormat; var maxDays = (isBuild || series.CandleType != typeof(TimeFrameCandle)) ? 2 : 30 * (int)((TimeSpan)series.Arg).TotalMinutes; _mdMsg = series.ToMarketDataMessage(true); Task.Factory.StartNew(() => { var date = DateTime.MinValue; if (isBuild) { foreach (var tick in storage.GetTickMessageStorage(series.Security, new LocalMarketDataDrive(path), format).Load()) { _tradeGenerator.Process(tick); if (_candleTransform.Process(tick)) { var candles = _candleBuilder.Process(_mdMsg, _currCandle, _candleTransform); foreach (var candle in candles) { _currCandle = candle; _updatedCandles.Add((CandleMessage)candle.Clone()); } } _lastTime = tick.ServerTime; if (date != tick.ServerTime.Date) { date = tick.ServerTime.Date; var str = date.To <string>(); this.GuiAsync(() => BusyIndicator.BusyContent = str); maxDays--; if (maxDays == 0) { break; } } } } else { foreach (var candleMsg in storage.GetCandleMessageStorage(msgType, series.Security, series.Arg, new LocalMarketDataDrive(path), format).Load()) { if (candleMsg.State != CandleStates.Finished) { candleMsg.State = CandleStates.Finished; } _currCandle = candleMsg; _updatedCandles.Add(candleMsg); _lastTime = candleMsg.OpenTime; if (candleMsg is TimeFrameCandleMessage) { _lastTime += (TimeSpan)series.Arg; } _tradeGenerator.Process(new ExecutionMessage { ExecutionType = ExecutionTypes.Tick, SecurityId = series.Security.ToSecurityId(), ServerTime = _lastTime, TradePrice = candleMsg.ClosePrice, }); if (date != candleMsg.OpenTime.Date) { date = candleMsg.OpenTime.Date; var str = date.To <string>(); this.GuiAsync(() => BusyIndicator.BusyContent = str); maxDays--; if (maxDays == 0) { break; } } } } _historyLoaded = true; }) .ContinueWith(t => { if (t.Exception != null) { Error(t.Exception.Message); } BusyIndicator.IsBusy = false; Chart.IsAutoRange = false; ModifyAnnotationBtn.IsEnabled = true; NewAnnotationBtn.IsEnabled = true; }, TaskScheduler.FromCurrentSynchronizationContext()); }
/// <summary> /// Reset state. /// </summary> public void Reset() { CurrentCandle = null; }
private void FillIndexCandle(CandleMessage indexCandle, CandleMessage candleMsg, CandleMessage[] candles) { indexCandle.SecurityId = SecurityId; indexCandle.Arg = candleMsg.CloneArg(); indexCandle.OpenTime = candleMsg.OpenTime; indexCandle.CloseTime = candleMsg.CloseTime; try { indexCandle.OpenPrice = Calculate(candles, true, c => c.OpenPrice); indexCandle.ClosePrice = Calculate(candles, true, c => c.ClosePrice); indexCandle.HighPrice = Calculate(candles, true, c => c.HighPrice); indexCandle.LowPrice = Calculate(candles, true, c => c.LowPrice); if (BasketSecurity.CalculateExtended) { indexCandle.TotalVolume = Calculate(candles, false, c => c.TotalVolume); indexCandle.TotalPrice = Calculate(candles, true, c => c.TotalPrice); indexCandle.OpenVolume = Calculate(candles, false, c => c.OpenVolume ?? 0); indexCandle.CloseVolume = Calculate(candles, false, c => c.CloseVolume ?? 0); indexCandle.HighVolume = Calculate(candles, false, c => c.HighVolume ?? 0); indexCandle.LowVolume = Calculate(candles, false, c => c.LowVolume ?? 0); } } catch (ArithmeticException ex) { if (!BasketSecurity.IgnoreErrors) { throw; } ex.LogError(); return; } // если некоторые свечи имеют неполные данные, то и индекс будет таким же неполным if (indexCandle.OpenPrice == 0 || indexCandle.HighPrice == 0 || indexCandle.LowPrice == 0 || indexCandle.ClosePrice == 0) { var nonZeroPrice = indexCandle.OpenPrice; if (nonZeroPrice == 0) { nonZeroPrice = indexCandle.HighPrice; } if (nonZeroPrice == 0) { nonZeroPrice = indexCandle.LowPrice; } if (nonZeroPrice == 0) { nonZeroPrice = indexCandle.LowPrice; } if (nonZeroPrice != 0) { if (indexCandle.OpenPrice == 0) { indexCandle.OpenPrice = nonZeroPrice; } if (indexCandle.HighPrice == 0) { indexCandle.HighPrice = nonZeroPrice; } if (indexCandle.LowPrice == 0) { indexCandle.LowPrice = nonZeroPrice; } if (indexCandle.ClosePrice == 0) { indexCandle.ClosePrice = nonZeroPrice; } } } if (indexCandle.HighPrice < indexCandle.LowPrice) { var high = indexCandle.HighPrice; indexCandle.HighPrice = indexCandle.LowPrice; indexCandle.LowPrice = high; } if (indexCandle.OpenPrice > indexCandle.HighPrice) { indexCandle.HighPrice = indexCandle.OpenPrice; } else if (indexCandle.OpenPrice < indexCandle.LowPrice) { indexCandle.LowPrice = indexCandle.OpenPrice; } if (indexCandle.ClosePrice > indexCandle.HighPrice) { indexCandle.HighPrice = indexCandle.ClosePrice; } else if (indexCandle.ClosePrice < indexCandle.LowPrice) { indexCandle.LowPrice = indexCandle.ClosePrice; } indexCandle.State = CandleStates.Finished; }
/// <inheritdoc /> public override void Process(MarketDataMessage message, CandleMessage currentCandle, ICandleBuilderValueTransform transform, IList <CandleMessage> changes) { var currentRenkoCandle = (RenkoCandleMessage)currentCandle; var price = transform.Price; var volume = transform.Volume; var time = transform.Time; var side = transform.Side; var oi = transform.OpenInterest; var boxSize = (Unit)message.Arg; var renkoStep = (decimal)(1 * boxSize); if (currentRenkoCandle == null) { var openPrice = price.Floor(renkoStep); changes.Add(CreateCandle(message, boxSize, openPrice, renkoStep, price, volume, side, time, oi)); } else { if (currentRenkoCandle.LowPrice <= price && price <= currentRenkoCandle.HighPrice) { currentRenkoCandle.TotalTicks++; if (volume != null) { currentRenkoCandle.TotalVolume += volume.Value; currentRenkoCandle.TotalPrice += volume.Value * price; currentRenkoCandle.RelativeVolume += side == Sides.Buy ? volume : -volume; } currentRenkoCandle.CloseVolume = volume; currentRenkoCandle.CloseTime = time; currentRenkoCandle.VolumeProfile?.Update(price, volume, side); currentRenkoCandle.OpenInterest = oi; changes.Add(currentRenkoCandle); } else { currentRenkoCandle.State = CandleStates.Finished; changes.Add(currentRenkoCandle); int times; bool isUp; decimal openPrice; if (price < currentRenkoCandle.LowPrice) { times = (int)((currentRenkoCandle.LowPrice - price) / renkoStep) + 1; isUp = false; openPrice = currentRenkoCandle.LowPrice; } else { times = (int)((price - currentRenkoCandle.HighPrice) / renkoStep) + 1; isUp = true; openPrice = currentRenkoCandle.HighPrice; } for (var i = 0; i < times; i++) { if (isUp) { currentRenkoCandle = CreateCandle(message, boxSize, openPrice, renkoStep, price, volume, side, time, oi); changes.Add(currentRenkoCandle); openPrice += renkoStep; } else { currentRenkoCandle = CreateCandle(message, boxSize, openPrice, -renkoStep, price, volume, side, time, oi); changes.Add(currentRenkoCandle); openPrice -= renkoStep; } currentRenkoCandle.State = CandleStates.Finished; } currentRenkoCandle.State = CandleStates.Active; } } }
/// <inheritdoc /> public override void Process(MarketDataMessage message, CandleMessage currentCandle, ICandleBuilderValueTransform transform, IList <CandleMessage> changes) { var currentPnFCandle = (PnFCandleMessage)currentCandle; var price = transform.Price; var volume = transform.Volume; var time = transform.Time; var side = transform.Side; var oi = transform.OpenInterest; var pnf = (PnFArg)message.Arg; var pnfStep = (decimal)(1 * pnf.BoxSize); if (currentPnFCandle == null) { var openPrice = price.Floor(pnfStep); var highPrice = openPrice + pnfStep; changes.Add(CreateCandle(message, pnf, openPrice, highPrice, openPrice, highPrice, price, volume, side, time, oi)); } else { if (currentPnFCandle.LowPrice <= price && price <= currentPnFCandle.HighPrice) { UpdateCandle(currentPnFCandle, price, volume, time, side, oi); changes.Add(currentPnFCandle); } else { var isX = currentPnFCandle.OpenPrice < currentPnFCandle.ClosePrice; if (isX) { if (price > currentPnFCandle.HighPrice) { currentPnFCandle.HighPrice = currentPnFCandle.ClosePrice = price.Floor(pnfStep) + pnfStep; UpdateCandle(currentPnFCandle, price, volume, time, side, oi); changes.Add(currentPnFCandle); } else if (price < (currentPnFCandle.HighPrice - pnfStep * pnf.ReversalAmount)) { currentPnFCandle.State = CandleStates.Finished; changes.Add(currentPnFCandle); var highPrice = currentPnFCandle.HighPrice - pnfStep; var lowPrice = price.Floor(pnfStep); currentPnFCandle = CreateCandle(message, pnf, highPrice, highPrice, lowPrice, lowPrice, price, volume, side, time, oi); changes.Add(currentPnFCandle); } else { UpdateCandle(currentPnFCandle, price, volume, time, side, oi); changes.Add(currentPnFCandle); } } else { if (price < currentPnFCandle.LowPrice) { currentPnFCandle.LowPrice = currentPnFCandle.ClosePrice = price.Floor(pnfStep); UpdateCandle(currentPnFCandle, price, volume, time, side, oi); changes.Add(currentPnFCandle); } else if (price > (currentPnFCandle.LowPrice + pnfStep * pnf.ReversalAmount)) { currentPnFCandle.State = CandleStates.Finished; changes.Add(currentPnFCandle); var highPrice = price.Floor(pnfStep) + pnfStep; var lowPrice = currentPnFCandle.LowPrice + pnfStep; currentPnFCandle = CreateCandle(message, pnf, lowPrice, highPrice, lowPrice, highPrice, price, volume, side, time, oi); changes.Add(currentPnFCandle); } else { UpdateCandle(currentPnFCandle, price, volume, time, side, oi); changes.Add(currentPnFCandle); } } } } }
private void ChartUpdateTimerOnTick(object sender, EventArgs eventArgs) { if (_historyLoaded && IsRealtime.IsChecked == true) { var nextTick = (ExecutionMessage)_tradeGenerator.Process(new TimeMessage { ServerTime = _lastTime }); if (nextTick != null) { if (_candleTransform.Process(nextTick)) { var candles = _candleBuilder.Process(_mdMsg, _currCandle, _candleTransform); lock (_lock) { foreach (var candle in candles) { _currCandle = candle; _updatedCandles[candle.OpenTime] = Tuple.Create(candle, candle.State == CandleStates.Finished); } } } } _lastTime += TimeSpan.FromSeconds(RandomGen.GetInt(1, 10)); } Tuple <Candle, bool>[] candlesToUpdate; lock (_updatedCandles.SyncRoot) { candlesToUpdate = _updatedCandles.OrderBy(p => p.Key).Select(p => Tuple.Create(p.Value.Item1.ToCandle(_security), p.Value.Item2)).ToArray(); _updatedCandles.Clear(); } var lastCandle = _allCandles.LastOrDefault(); _allCandles.AddRange(candlesToUpdate.Where(c => lastCandle == null || c.Item1.OpenTime != lastCandle.OpenTime).Select(t => t.Item1)); ChartDrawData chartData = null; foreach (var tuple in candlesToUpdate) { var candle = tuple.Item1; var needToFinish = tuple.Item2; if (chartData == null) { chartData = new ChartDrawData(); } if (needToFinish && candle.State != CandleStates.Finished) { candle.State = CandleStates.Finished; } var chartGroup = chartData.Group(candle.OpenTime); lock (_lock) { chartGroup.Add(_candleElement, candle); } foreach (var pair in _indicators.CachedPairs) { chartGroup.Add(pair.Key, pair.Value.Process(candle)); } } if (chartData != null) { Chart.Draw(chartData); } }
private static DateTimeOffset SetTransactionId(CandleMessage msg, long transactionId) { msg.OriginalTransactionId = transactionId; return(msg.OpenTime); }
private void ProcessCandleMessage(CandleMessage message) { if (!UseExternalCandleSource) return; var security = GetSecurity(message.SecurityId); var series = _series.TryGetValue(security); if (series != null) { _newCandles.SafeInvoke(series, new[] { message.ToCandle(series) }); if (message.IsFinished) _stopped.SafeInvoke(series); } }