// ReSharper disable once ParameterOnlyUsedForPreconditionCheck.Local private void MergeCandle(string assetPair, CandleTimeInterval interval, ICandle candle) { if (candle.AssetPairId != assetPair) { throw new InvalidOperationException($"Candle {candle.ToJson()} has invalid AssetPriceId"); } if (candle.TimeInterval != interval) { throw new InvalidOperationException($"Candle {candle.ToJson()} has invalid TimeInterval"); } if (candle.PriceType != PriceType) { throw new InvalidOperationException($"Candle {candle.ToJson()} has invalid PriceType"); } // 1. Check if candle with specified time already exist // 2. If found - merge, else - add to list var tick = GetIntervalTick(candle.Timestamp, interval); // Considering that Candles is ordered by Tick for (var i = 0; i < Candles.Count; ++i) { var currentCandle = Candles[i]; // While currentCandle.Tick < tick - just skipping // That's it, merge to existing candle if (currentCandle.Tick == tick) { currentCandle.InplaceMergeWith(candle); return; } // No candle is found but there are some candles after, so we should insert candle right before them if (currentCandle.Tick > tick) { Candles.Insert(i, candle.ToItem(tick)); return; } } // No candle is found, and no candles after, so just add to the end Candles.Add(candle.ToItem(tick)); }
/// <summary> /// Creates mid candle of two candles (ask and bid) /// </summary> /// <param name="askCandle">first candle</param> /// <param name="bidCandle">second candle</param> public static ICandle Create(ICandle askCandle, ICandle bidCandle) { if (askCandle == null || bidCandle == null) { return(askCandle ?? bidCandle); } if (askCandle.AssetPairId != bidCandle.AssetPairId) { throw new InvalidOperationException($"Can't create mid candle of different asset pairs. candle1={askCandle.ToJson()}, candle2={bidCandle.ToJson()}"); } if (askCandle.PriceType != CandlePriceType.Ask) { throw new InvalidOperationException($"Ask candle should has according price type. candle={askCandle.ToJson()}"); } if (bidCandle.PriceType != CandlePriceType.Bid) { throw new InvalidOperationException($"Bid candle should has according price type. candle={bidCandle.ToJson()}"); } if (askCandle.TimeInterval != bidCandle.TimeInterval) { throw new InvalidOperationException($"Can't create mid candle of different time intervals. candle1={askCandle.ToJson()}, candle2={bidCandle.ToJson()}"); } if (askCandle.Timestamp != bidCandle.Timestamp) { throw new InvalidOperationException($"Can't create mid candle from candles with different timestamps. candle1={askCandle.ToJson()}, candle2={bidCandle.ToJson()}"); } return(Candle.Create( open: (askCandle.Open + bidCandle.Open) / 2, close: (askCandle.Close + bidCandle.Close) / 2, high: (askCandle.High + bidCandle.High) / 2, low: (askCandle.Low + bidCandle.Low) / 2, assetPair: askCandle.AssetPairId, priceType: CandlePriceType.Mid, timeInterval: askCandle.TimeInterval, timestamp: askCandle.Timestamp, tradingVolume: askCandle.LastUpdateTimestamp > bidCandle.LastUpdateTimestamp ? askCandle.TradingVolume : bidCandle.TradingVolume, tradingOppositeVolume: askCandle.LastUpdateTimestamp > bidCandle.LastUpdateTimestamp ? askCandle.TradingOppositeVolume : bidCandle.TradingOppositeVolume, lastTradePrice: askCandle.LastUpdateTimestamp > bidCandle.LastUpdateTimestamp ? askCandle.LastTradePrice : bidCandle.LastTradePrice, lastUpdateTimestamp: askCandle.LastUpdateTimestamp > bidCandle.LastUpdateTimestamp ? askCandle.LastUpdateTimestamp : bidCandle.LastUpdateTimestamp)); }