public IList <Candle> LoadCandles(string currencyPairId, CandlePeriod period, int limit, DateTime currentMoment) { var momentsByPeriod = GetMomentsByPeriod(period, limit, currentMoment).ToList(); momentsByPeriod.Sort(); IList <Candle> storedCandles; lock (DbOperationLocker) { storedCandles = _candleRepository.GetAll() .Where(entity => entity.CurrencyPair == currencyPairId && momentsByPeriod.Contains(entity.Moment)) .Select(entity => Tuple.Create(entity.ToModel(), entity.Period)) .ToList() .GroupBy(candle => candle.Item1.Moment) .Select(candleGroup => { var candle = candleGroup.FirstOrDefault(tuple => tuple.Item2 == period) ?? candleGroup.First(); return(candle.Item1); }) .OrderBy(candle => candle.Moment) .ToList(); } return(storedCandles); }
public void UpdateCandles(List <Candle> c, CandlePeriod p, string symbol) { ExchangeModel toUpdate = models.FirstOrDefault(x => x.Symbol.Value.symbol == symbol); if (p == CandlePeriod.M1) { this.UpdateCandles_M1(c, toUpdate); } else if (p == CandlePeriod.M5) { this.UpdateCandles_M5(c, toUpdate); } else if (p == CandlePeriod.M30) { this.UpdateCandles_M30(c, toUpdate); } else if (p == CandlePeriod.H1) { this.UpdateCandles_H1(c, toUpdate); } else if (p == CandlePeriod.H4) { this.UpdateCandles_H4(c, toUpdate); } else if (p == CandlePeriod.D1) { this.UpdateCandles_D1(c, toUpdate); } else if (p == CandlePeriod.W1) { this.UpdateCandles_W1(c, toUpdate); } }
public async Task SubscribeOnCandles(string currencyPairId, CandlePeriod period, Action <IList <Infrastructure.Common.Models.Market.Candle> > callback, int limit = 30) { var request = new SocketSubscriptionRequest <CandleRequestParameters> { RequestMethodName = "subscribeCandles", SnapshotMethodName = "snapshotCandles", NotificationMethodName = "updateCandles", UnsubscribeMethodName = "unsubscribeCandles", RequestParameters = new CandleRequestParameters { CurrencyPairId = currencyPairId, Period = period.ToInnerFormat(), Limit = limit } }; await _connection.Subscribe <CandleNotificationParameters>(request, notificationParameters => { var notificationCurrencyPairId = notificationParameters.CurrencyPairId; var notificationPeriod = CandlePeriodMap.ToOuterFormat(notificationParameters.Period); if (!(currencyPairId == notificationCurrencyPairId && notificationPeriod == period)) { return; } callback(notificationParameters.Candles .Select(CandleMap.ToOuterModel) .ToList()); }); }
public async Task InitializeCandles(int exchangeId) { using (var scope = _serviceProvider.GetRequiredService <IServiceScopeFactory>().CreateScope()) { var marketRepo = scope.ServiceProvider.GetRequiredService <IMarketRepository>(); var candleChartRepo = scope.ServiceProvider.GetRequiredService <ICandleChartRepository>(); var exchangeAccessService = scope.ServiceProvider.GetRequiredService <IExchangeAccessService>(); var marketSymbols = this.GetMarketsNeeded(); foreach (var symbol in marketSymbols) { var market = await marketRepo.GetByCurrencyPairAsync(symbol.Value, symbol.Key, exchangeId); if (market != null) { foreach (var period in CandlePeriod.List()) { var existingCandleChart = await candleChartRepo.GetByCurrencyPairAsync(symbol.Value, symbol.Key, exchangeId, period); if (existingCandleChart == null) { var toAdd = CandleChart.FromMarket(market, period); candleChartRepo.Add(toAdd); await candleChartRepo.UnitOfWork.SaveEntitiesAsync(); } } } } } }
public static CandleInterval ToInnerFormat(this CandlePeriod candlePeriod) { switch (candlePeriod) { case CandlePeriod.Minute1: return(CandleInterval.Minute); case CandlePeriod.Minute3: return(CandleInterval.ThreeMinutes); case CandlePeriod.Minute5: return(CandleInterval.FiveMinutes); case CandlePeriod.Minute15: return(CandleInterval.QuarterHour); case CandlePeriod.Minute30: return(CandleInterval.HalfHour); case CandlePeriod.Hour1: return(CandleInterval.Hour); case CandlePeriod.Day1: return(CandleInterval.Day); case CandlePeriod.Day7: return(CandleInterval.Week); case CandlePeriod.Month1: return(CandleInterval.Month); default: throw new ConnectorException("Undefined candle period", null); } }
public TraceStartedDomainEvent(string traceId, CandlePeriod idealCandlePeriod, TraceStatus traceStatus, DateTime dateStarted) { TraceId = traceId ?? throw new ArgumentNullException(nameof(traceId)); IdealCandlePeriod = idealCandlePeriod ?? throw new ArgumentNullException(nameof(idealCandlePeriod)); TraceStatus = traceStatus ?? throw new ArgumentNullException(nameof(traceStatus)); this.DateStarted = dateStarted; }
public static CandlePeriod GetLowerFramePeriod(this CandlePeriod targetPeriod) { switch (targetPeriod) { case CandlePeriod.Month1: return(CandlePeriod.Day7); case CandlePeriod.Day7: return(CandlePeriod.Day1); case CandlePeriod.Day1: return(CandlePeriod.Hour4); case CandlePeriod.Hour4: return(CandlePeriod.Hour1); case CandlePeriod.Hour1: return(CandlePeriod.Minute15); case CandlePeriod.Minute30: return(CandlePeriod.Minute5); case CandlePeriod.Minute15: return(CandlePeriod.Minute5); case CandlePeriod.Minute5: return(CandlePeriod.Minute1); case CandlePeriod.Minute3: return(CandlePeriod.Minute1); default: return(targetPeriod); } }
private long GetSinceUnixTime(CandlePeriod candlePeriod) { var utcNow = DateTimeOffset.UtcNow; var candlePeridInMinutes = (int)candlePeriod; var candleSizeInSeconds = candlePeridInMinutes * 60; return(utcNow.AddSeconds(-1 * (candleSizeInSeconds + utcNow.Second)).ToUnixTimeSeconds()); }
public CandleRequestPacket(int requestId, string symbol, CandlePeriod period, DateTime from, DateTime to) : base(APINetworkPacketType.CandleRequest) { RequestId = requestId; Symbol = symbol; Period = period; FromTime = from; ToTime = to; }
public async Task Handle(RoundtripTargetPriceHitIntegrationEvent @event) { try { var trace = await this._traceRepository.GetByInvestmentId(@event.InvestmentId); if (trace == null) { return; } var idealPeriod = trace.IdealCandlePeriod; int minAmounts = 0; foreach (var strategy in trace.TradeStrategies) { if (strategy.GetIdealPeriod().Name == idealPeriod) { if (strategy.Strategy.MinimumAmountOfCandles > minAmounts) { minAmounts = strategy.Strategy.MinimumAmountOfCandles; } } } var period = CandlePeriod.FromName(idealPeriod); DateTime fromWithWarmingPeriod = (DateTime)trace.DateStarted; var oneCandleMinutes = CandlePeriodService.GetOneCandleMinutesByPeriod(period); var currentTime = new RealTimeService().GetCurrentDateTime(); var to = currentTime.AddMinutes(-oneCandleMinutes); fromWithWarmingPeriod = fromWithWarmingPeriod.AddMinutes(-oneCandleMinutes * (minAmounts + 1)); await this._trendAnalysisIntegrationEventService .PublishThroughEventBusAsync(new TargetPriceCandleDataRequestedIntegrationEvent( trace.TraceId, @event.RoundtripId, trace.Market.ExchangeId, trace.Market.BaseCurrency, trace.Market.QuoteCurrency, idealPeriod, @event.HitPrice, fromWithWarmingPeriod, to )); } catch (Exception ex) { Console.WriteLine("Handle Integration Event: RoundtripTargetPriceHitIntegrationEvent."); Console.WriteLine("Result: Failure."); Console.WriteLine("Error Message: " + ex.Message); } }
public void UpdateCandles(string currencyPairId, CandlePeriod candlePeriod, IList <Candle> candles) { lock (DbOperationLocker) { var storedEntities = _candleRepository.GetAll() .Where(entity => entity.CurrencyPair == currencyPairId && entity.Period == candlePeriod) .OrderByDescending(entity => entity.Moment) .Take(candles.Count) .ToList(); var storedCandles = storedEntities .Select(entity => entity.ToModel()) .ToList(); var newCandles = new List <Candle>(); var updatedCandles = new List <Candle>(); foreach (var receivedCandle in candles) { var storedCandle = storedCandles.FirstOrDefault(candle => candle.Moment == receivedCandle.Moment); if (storedCandle == null) { newCandles.Add(receivedCandle); } else { storedCandle.OpenPrice = receivedCandle.OpenPrice; storedCandle.ClosePrice = receivedCandle.ClosePrice; storedCandle.MaxPrice = receivedCandle.MaxPrice; storedCandle.MinPrice = receivedCandle.MinPrice; storedCandle.VolumeInBaseCurrency = receivedCandle.VolumeInBaseCurrency; storedCandle.VolumeInQuoteCurrency = receivedCandle.VolumeInQuoteCurrency; updatedCandles.Add(storedCandle); } } if (newCandles.Any()) { _candleRepository.Insert(newCandles .Select(candle => candle.ToEntity(currencyPairId, candlePeriod)) .ToList()); } if (updatedCandles.Any()) { _candleRepository.Update(updatedCandles .Select(candle => { var storedEntity = storedEntities.Single(entity => entity.Moment == candle.Moment); return(candle.ToEntity(currencyPairId, candlePeriod, storedEntity)); }) .ToList()); } } }
private int GetPeriodDay(CandlePeriod candlePeriod) { var period = candlePeriod.Id; int days = 0; if (period == CandlePeriod.OneDay.Id) { days = 1; } return(days); }
private int GetPeriodWeek(CandlePeriod candlePeriod) { var period = candlePeriod.Id; int weeks = 0; if (period == CandlePeriod.OneWeek.Id) { weeks = 1; } return(weeks); }
private CChartPanel CreateChart(string symbol, CandlePeriod p) { if (!chartsDic[symbol].ContainsKey(p)) { chartsDic[symbol][p] = new CChartPanel(symbolsOn.Single(kv => kv.Key == symbol), (int)p); chartsDic[symbol][p].AfterDisplay -= OnAfterDisplay; chartsDic[symbol][p].AfterDisplay += OnAfterDisplay; chartsDic[symbol][p].EmbededInMultiChart = true; chartsDic[symbol][p].ParentCZoom = toolStripTBZoom; } return(chartsDic[symbol][p]); }
/// <summary> /// Constructor /// </summary> /// <param name="timeframe">ForexConnect timeframe descriptor</param> internal TimeframeItem(O2GTimeframe timeframe) { mTimeframe = timeframe; DateTime start = DateTime.Now.AddDays(-1), end = DateTime.Now; // parse the timeframe ID to get Quotes Manager timeframe descriptor if (!CandlePeriod.parsePeriod(timeframe.ID, ref mTimeframeUnit, ref mTimeframeLength)) { throw new ArgumentException("Invalide timeframe", "timeframe"); } // get a candle in that timeframe to get it length CandlePeriod.getCandle(DateTime.Now, ref start, ref end, mTimeframeUnit, mTimeframeLength, 0, 0); mLength = end.Subtract(start); }
public static IList <IndicatorPanelSettings> GetAdditionalPanelsSettings(CandlePeriod period) { return(new[] { new IndicatorPanelSettings { AssignedIndicators = new[] { new Tuple <IndicatorType, CandlePeriod>(IndicatorType.MACD, period.GetHigherFramePeriod()), } }, new IndicatorPanelSettings { AssignedIndicators = new[] { new Tuple <IndicatorType, CandlePeriod>(IndicatorType.MACD, period), } }, new IndicatorPanelSettings { AssignedIndicators = new[] { new Tuple <IndicatorType, CandlePeriod>(IndicatorType.Stochastic, period), } }, new IndicatorPanelSettings { AssignedIndicators = new[] { new Tuple <IndicatorType, CandlePeriod>(IndicatorType.RelativeStrengthIndex, period), } }, new IndicatorPanelSettings { AssignedIndicators = new[] { new Tuple <IndicatorType, CandlePeriod>(IndicatorType.AccumulationDistribution, period), } }, new IndicatorPanelSettings { AssignedIndicators = new[] { new Tuple <IndicatorType, CandlePeriod>(IndicatorType.WilliamsR, period), } }, }); }
private DateTime CalculateCandleStartDateWithWarmUp(CandlePeriod candlePeriod, int warmUp) { DateTime result = this.DateStarted ?? throw new TrendAnalysisDomainException(nameof(this.DateStarted)); if (candlePeriod.Id == CandlePeriod.OneMinute.Id) { result = result.AddMinutes(-warmUp * 1); } else if (candlePeriod.Id == CandlePeriod.FiveMinutes.Id) { result = result.AddMinutes(-warmUp * 5); } else if (candlePeriod.Id == CandlePeriod.FifteenMinutes.Id) { result = result.AddMinutes(-warmUp * 15); } else if (candlePeriod.Id == CandlePeriod.ThirtyMinutes.Id) { result = result.AddMinutes(-warmUp * 30); } else if (candlePeriod.Id == CandlePeriod.OneHour.Id) { result = result.AddHours(-warmUp * 1); } else if (candlePeriod.Id == CandlePeriod.TwoHours.Id) { result = result.AddHours(-warmUp * 2); } else if (candlePeriod.Id == CandlePeriod.FourHours.Id) { result = result.AddHours(-warmUp * 4); } else if (candlePeriod.Id == CandlePeriod.OneDay.Id) { result = result.AddDays(-warmUp * 1); } else if (candlePeriod.Id == CandlePeriod.OneWeek.Id) { result = result.AddDays(-warmUp * 7); } else { throw new TrendAnalysisDomainException("No matching canlde period when calculating candle start date."); } return(result); }
private async Task ExecutePastCandleCheck(string tradingPair, CandlePeriod candlePeriod, long lastScanId) { var utcNow = DateTimeOffset.UtcNow; var candleInterval = (int)candlePeriod * 60; var endTime = (utcNow.ToUnixTimeSeconds() - utcNow.ToUnixTimeSeconds() % candleInterval) - candleInterval; var startTime = endTime - candleInterval * _strategy.DelayInCandlePeriod; var pastCandles = await _exchangeProvider.GetCandlesAsync(tradingPair, candlePeriod, startTime, endTime); foreach (var pastCandle in pastCandles) { await _strategy.CheckTrendAsync(tradingPair, pastCandle); await _candleRepository.SaveCandleAsync(tradingPair, Mapper.Map <List <CandleDto> >(new List <CandleModel> { pastCandle }), lastScanId); } }
protected override async Task ObserveCandles(string symbol, CandlePeriod p, CancellationTokenSource token) { while (!token.IsCancellationRequested) { try { await this.RefreshCandles(symbol, p, 100); } catch (Exception ex) { this.logService.LogException(this.exchangeSettings.ID, null, ex); } finally { await Task.Delay(60000); } } }
public async Task <IActionResult> UpdateCandlesFromExchange([FromBody] UpdateCandlesFromExchangeCommand command) { /* if (!ModelState.IsValid) * { * return BadRequest(ModelState); * } */ try { DateTime dtDateTime = new DateTime(1970, 1, 1, 0, 0, 0, 0, System.DateTimeKind.Utc); var from = dtDateTime.AddSeconds(command.From); var to = dtDateTime.AddSeconds(command.To); var candles = await this._exchangeAccessService.GetCandlesData( command.ExchangeId, command.BaseCurrency, command.QuoteCurrency, CandlePeriod.FromName(command.CandlePeriod), from, to); var chart = await this._candleChartRepository .GetByCurrencyPairAsync(command.BaseCurrency, command.QuoteCurrency, command.ExchangeId, CandlePeriod.FromName(command.CandlePeriod)); if (chart == null) { throw new KeyNotFoundException(); } foreach (var candle in candles) { chart.UpdateCandle(candle.Timestamp, candle.High, candle.Low, candle.Open, candle.Close, candle.Volume); } await _context.SaveEntitiesAsync(); return(Ok(chart.CandleChartId)); } catch (Exception ex) { return(NotFound(ex.Message)); } }
public static string PeriodToString(CandlePeriod cp) { switch (cp) { case CandlePeriod.m1: return("1-Minute"); case CandlePeriod.m2: return("2-Minute"); case CandlePeriod.m3: return("3-Minute"); case CandlePeriod.m5: return("5-Minute"); case CandlePeriod.m10: return("10-Minute"); case CandlePeriod.m15: return("15-Minute"); case CandlePeriod.m20: return("20-Minute"); case CandlePeriod.m30: return("30-Minute"); case CandlePeriod.m60: return("60-Minute"); case CandlePeriod.D: return("Daily"); case CandlePeriod.W: return("Weekly"); case CandlePeriod.M: return("Monthly"); default: return(string.Empty); } }
private void OnSinglePeriodBtnClick(object sender, EventArgs e) { ToolStripButton btn = (ToolStripButton)sender; CandlePeriod p = ButtonPeriod(btn); foreach (ToolStripButton b in btnPeriods.Values) { b.Checked = (btn == b); periodDic[ButtonPeriod(b)] = (btn == b); } btnPrefered = btnPeriods[p]; if (symbolOnDisplay == null) { return; } RefreshChartPanel(); }
private int GetPeriodHour(CandlePeriod candlePeriod) { var period = candlePeriod.Id; int hours = 0; if (period == CandlePeriod.OneHour.Id) { hours = 1; } else if (period == CandlePeriod.TwoHours.Id) { hours = 2; } else if (period == CandlePeriod.FourHours.Id) { hours = 4; } return(hours); }
private async Task SubscribeOnTradingEvents() { _workingCandlePeriod = _configurationService.GetTradingSettings().Period; var tradingSettings = _configurationService.GetTradingSettings(); var periodsForAnalysis = new[] { tradingSettings.Period.GetLowerFramePeriod(), tradingSettings.Period, tradingSettings.Period.GetHigherFramePeriod() }; await _candleLoadingService.InitSubscription(Position.CurrencyPairId, periodsForAnalysis); _candleLoadingService.CandlesUpdated += OnCandlesUpdated; await _orderBookLoadingService.InitSubscription(Position.CurrencyPair.Id); _orderBookLoadingService.OrderBookUpdated += OnOrderBookUpdated; await _tradingReportsService.InitSubscription(Position.CurrencyPairId); _tradingReportsService.OrdersUpdated += OnOrdersUpdated; }
public async Task Handle(PaperTradeDataCreatedIntegrationEvent @event) { try { var trace = await this._traceRepository.GetByTraceIdAsync(@event.TraceId); if (trace == null) { return; } var candles = new List <Candle>(); foreach (var candle in @event.Candles) { candles.Add(new Candle( candle.Timestamp, candle.High, candle.Low, candle.Open, candle.Close, candle.Volume)); } trace.CandleUpdated(candles, CandlePeriod.FromName(@event.CandlePeriod), new RealTimeService(), new IndicatorService(), @event.StrategyId); _traceRepository.Update(trace); await _traceRepository.UnitOfWork .SaveEntitiesAsync(); } catch (Exception ex) { Console.WriteLine("Handle Integraion Event: PaperTradeDataCreatedIntegrationEvent \n" + "Result: Failure. \n" + "Error Message: " + ex.Message); } }
public static string ToInnerFormat(this CandlePeriod candlePeriod) { switch (candlePeriod) { case CandlePeriod.Minute1: return("M1"); case CandlePeriod.Minute3: return("M3"); case CandlePeriod.Minute5: return("M5"); case CandlePeriod.Minute15: return("M15"); case CandlePeriod.Minute30: return("M30"); case CandlePeriod.Hour1: return("H1"); case CandlePeriod.Hour4: return("H4"); case CandlePeriod.Day1: return("D1"); case CandlePeriod.Day7: return("D7"); case CandlePeriod.Month1: return("1M"); default: throw new ConnectorException("Undefined candle period", null); } }
/// <summary> /// Constructor /// </summary> /// <param name="instrument">The instrument name</param> /// <param name="timeframe">The timeframe id (e.g. m1)</param> /// <param name="alive">The flag indicating whether the collection shall be subscribed for updates</param> /// <param name="controller">The price update controller</param> public PeriodCollection(string instrument, string timeframe, bool alive, IPriceUpdateController controller) { mInstrument = instrument; mTimeframe = timeframe; mAlive = alive; mFilled = false; if (alive) { // if collection is alive - we will need to calculate the date/time of the candle // to which each tick belongs to, so we need to parse the time frame name for // further usage if (!CandlePeriod.parsePeriod(timeframe, ref mTimeframeUnit, ref mTimeframeLength)) { throw new ArgumentException("Invalid timeframe", "timeframe"); } // and we need to subscribe to tick updates mWaitingUpdates = new Queue <IOffer>(); mTradingDayOffset = controller.TradingDayOffset; controller.OnPriceUpdate += OnPriceUpdate; mController = controller; } }
public void StartTracing(ITimeService timeService, CandlePeriod idealCandlePeriod = null) { if (timeService == null) { throw new TrendAnalysisDomainException("Time service is not provided when operating on trace."); } if (idealCandlePeriod == null) { idealCandlePeriod = this.CalculateIdealCandlePeriod(); this.IdealCandlePeriod = idealCandlePeriod.Name; } else { this.IdealCandlePeriod = idealCandlePeriod.Name; } if (this.TraceStatus.Id == TraceStatus.Closed.Id) { throw new TrendAnalysisDomainException("Cannot start tracing after closed."); } if (this.TraceStatus.Id != TraceStatus.Started.Id) { if (!this.TradeStrategies.Any()) { throw new TrendAnalysisDomainException("There must be at least one strategy before starting trace."); } this.DateStarted = timeService.GetCurrentDateTime(); this._traceStatusId = TraceStatus.Started.Id; this.AddDomainEvent(new TraceStartedDomainEvent( this.TraceId, CandlePeriod.FromName(this.IdealCandlePeriod), this.TraceStatus, this.DateStarted ?? throw new TrendAnalysisDomainException("DateStarted missing when changing status."))); } }
private int GetPeriodMinute(CandlePeriod candlePeriod) { var period = candlePeriod.Id; int minutes = 0; if (period == CandlePeriod.OneMinute.Id) { minutes = 1; } else if (period == CandlePeriod.FiveMinutes.Id) { minutes = 5; } else if (period == CandlePeriod.FifteenMinutes.Id) { minutes = 15; } else if (period == CandlePeriod.ThirtyMinutes.Id) { minutes = 30; } return(minutes); }
/// <summary> /// Handling one tick /// </summary> /// <param name="offer"></param> private void HandleOffer(IOffer offer) { lock (mPeriods) { // calculate the start time of the period to which the tick belong to DateTime start = DateTime.MinValue, end = DateTime.MinValue; // calculate candle in EST time because the trading day is always closed by New York time // so to avoid handling different hour depending on daylight saying time - use EST always // for candle calculations // NOTE: for real application this part can be optimized. The candle calculation // is quite complex process, so it is better to avoid it when it is not actually required. // the way to optimize it is to keep end time of the period and check whether the tick belongs to // the period using the following condition start <= tick < end // so the calculation of new candle will be used only when tick is actually >= of the end // of the current candle. CandlePeriod.getCandle(mController.UtcToEst(offer.LastUpdate), ref start, ref end, mTimeframeUnit, mTimeframeLength, mTradingDayOffset, -1); start = mController.EstToUtc(start); // calculate the serial number of minute (for easier comparing) long currMinute = DateToMinute(offer.LastUpdate); if (mPeriods.Count == 0) { // if here is no data in the collection yet - just add a dummy candle mPeriods.Add(new Period(start, offer.Bid, offer.Ask, offer.MinuteVolume)); mLastMinute = currMinute; mLastMinuteVolume = offer.MinuteVolume; } else { // otherwise get the most recent candle Period period = mPeriods[mPeriods.Count - 1]; if (period.Time == start) { // if tick belongs to that period... // update the latest (close) price of bid and ask bars period._Ask.Close = offer.Ask; period._Bid.Close = offer.Bid; // if tick higher than high value of bars - update if (period._Ask.High < offer.Ask) { period._Ask.High = offer.Ask; } if (period._Bid.High < offer.Bid) { period._Bid.High = offer.Bid; } // if tick lower than low value of bars - update if (period._Ask.Low > offer.Ask) { period._Ask.Low = offer.Ask; } if (period._Bid.Low > offer.Bid) { period._Bid.Low = offer.Bid; } // here is a trick. // we don't receive EVERY tick, so we can't simply count them. // It is not a problem for calculating open, high, low and close, because // the tick filter keeps every first, last, and the current extremum ticks // In order to make the volume calculation also correct, the server // broadcasts the accumulated tick volume for the current minute. // so, if the tick belongs to the same minute as the previous tick - // we must substract previous accumulated volume and add a new value. // If the tick is the first tick of a new minute - we must simply // add new accumulated value. if (mLastMinute == currMinute) { period.Volume -= mLastMinuteVolume; period.Volume += offer.MinuteVolume; } else if (currMinute > mLastMinute) { period.Volume += offer.MinuteVolume; } mLastMinute = currMinute; mLastMinuteVolume = offer.MinuteVolume; } else if (period.Time < start) { // this is a first tick of new period, simply create this period // please pay attention that we don't use the first tick as an open // value but use the previous close instead. // This is how the current system works by default. // soon, here should be an option to use the first tick for the open // price instead. mPeriods.Add(period = new Period(start, period.Bid.Close, period.Ask.Close, offer.MinuteVolume)); // update the latest (close) price of bid and ask bars period._Ask.Close = offer.Ask; period._Bid.Close = offer.Bid; // if tick higher than high value of bars - update if (period._Ask.High < offer.Ask) { period._Ask.High = offer.Ask; } if (period._Bid.High < offer.Bid) { period._Bid.High = offer.Bid; } // if tick lower than low value of bars - update if (period._Ask.Low > offer.Ask) { period._Ask.Low = offer.Ask; } if (period._Bid.Low > offer.Bid) { period._Bid.Low = offer.Bid; } mLastMinute = currMinute; mLastMinuteVolume = offer.MinuteVolume; } else { // yep, it is possible that tick is older than the last candle. // it may happen because we start to collect ticks actually BEFORE // we sent the request to the server. So on the border of the minute // it is possible that we "catch" some ticks of the previous // minute // so, simply ignore them ; } } } }