private void updateStoredData(IEnumerable <ICandle> candles, string code, string frame) { DateTime dt = candles.First().begin; int index = -1; ICandle candle = _candles[code][frame].FirstOrDefault(c => c.begin >= dt); if (candle != null) { index = _candles[code][frame].IndexOf(candle); } foreach (ICandle item in candles) { if (index == -1) { _candles[code][frame].Add(item); } if (index >= 0 && index >= _candles[code][frame].Count) { _candles[code][frame].Add(item); index++; } if (index >= 0 && index < _candles[code][frame].Count) { _candles[code][frame][index] = item; index++; } } }
//--------------------------------------------------------------------------------------------------------------------------------------- protected override void OnRender(DrawingContext drawingContext) { //drawingContext.DrawRectangle(Brushes.Aquamarine, transparentPen, new Rect(0, 0, RenderSize.Width, RenderSize.Height)); for (int i = 0; i < VisibleCandlesRange.Count; i++) { if (i >= (CandlesSource?.Count ?? 0)) { return; } ICandle cndl = CandlesSource[VisibleCandlesRange.Start_i + i]; Brush cndlBrush = (cndl.C > cndl.O) ? BullishBarFill : BearishBarFill; Pen cndlPen = (cndl.C > cndl.O) ? bullishBarPen : bearishBarPen; double wnd_V = (1.0 - cndl.V / (double)VisibleCandlesExtremums.VolumeHigh) * RenderSize.Height; double cndlLeftX = i * (CandleWidthAndGap.Width + CandleWidthAndGap.Gap); //double cndlCenterX = cndlLeftX + 0.5 * CandleWidthAndGap.Width; if (cndl.V > 0L) { drawingContext.DrawRectangle(cndlBrush, null, new Rect(cndlLeftX, wnd_V, CandleWidthAndGap.Width, RenderSize.Height - wnd_V)); } else { drawingContext.DrawLine(cndlPen, new Point(cndlLeftX, 0.0), new Point(cndlLeftX + CandleWidthAndGap.Width, 0.0)); } } }
public override void AddValueToLine(ICandle candle, Func <ICandle, decimal> func = null) { SeriesCollection[0].Values.Add(new OhlcPoint((double)candle.Open, (double)candle.High, (double)candle.Low, (double)candle.Close)); double average = CalcAverage(), sigma = CalcSigma(average); SeriesCollection[1].Values.Add(new ObservableValue(average + 2 * sigma)); SeriesCollection[2].Values.Add(new ObservableValue(average)); SeriesCollection[3].Values.Add(new ObservableValue(average - 2 * sigma)); while (SeriesCollection[0].Values.Count > MaxPointsCount) { SeriesCollection[0].Values.RemoveAt(0); SeriesCollection[1].Values.RemoveAt(0); SeriesCollection[2].Values.RemoveAt(0); SeriesCollection[3].Values.RemoveAt(0); } for (int i = 19; i > 0; i--) { Candles[i] = Candles[i - 1]; } Candles[0] = (Candle)candle; }
public FilterResult Exec() { FilterResult res = FilterResult.N; ICandle curr = _data["5"].Last(); decimal day_max = Func.Max(_data["60"], 20, 1); decimal day_min = Func.Min(_data["60"], 20, 1); decimal max_offset = curr.close / day_max; decimal min_offset = day_min / curr.close; if (max_offset > 1m) { res = FilterResult.L; } if (min_offset > 1m) { res = FilterResult.S; } return(res); }
//--------------------------------------------------------------------------------------------------------------------------------------- protected override void OnRender(DrawingContext drawingContext) { double range = VisibleCandlesExtremums.PriceHigh - VisibleCandlesExtremums.PriceLow; double correctedCndlWidth = CandleWidthAndGap.Width - 1.0; for (int i = 0; i < VisibleCandlesRange.Count; i++) { if (i >= (CandlesSource?.Count ?? 0)) { return; } ICandle cndl = CandlesSource[VisibleCandlesRange.Start_i + i]; Brush cndlBrush = (cndl.C > cndl.O) ? BullishCandleFill : BearishCandleFill; Pen cndlPen = (cndl.C > cndl.O) ? bullishCandleStrokePen : bearishCandleStrokePen; double wnd_L = (1.0 - (cndl.L - VisibleCandlesExtremums.PriceLow) / range) * RenderSize.Height; double wnd_H = (1.0 - (cndl.H - VisibleCandlesExtremums.PriceLow) / range) * RenderSize.Height; double wnd_O = (1.0 - (cndl.O - VisibleCandlesExtremums.PriceLow) / range) * RenderSize.Height; double wnd_C = (1.0 - (cndl.C - VisibleCandlesExtremums.PriceLow) / range) * RenderSize.Height; double cndlLeftX = i * (CandleWidthAndGap.Width + CandleWidthAndGap.Gap); double cndlCenterX = cndlLeftX + 0.5 * CandleWidthAndGap.Width; drawingContext.DrawLine(cndlPen, new Point(cndlCenterX, wnd_L), new Point(cndlCenterX, wnd_H)); double cndlBodyH = Math.Abs(wnd_O - wnd_C); if (cndlBodyH > 1.0) { drawingContext.DrawRectangle(cndlBrush, cndlPen, new Rect(cndlLeftX + 0.5, Math.Min(wnd_O, wnd_C) + 0.5, correctedCndlWidth, cndlBodyH - 1.0)); } else { drawingContext.DrawLine(cndlPen, new Point(cndlLeftX, wnd_O), new Point(cndlLeftX + CandleWidthAndGap.Width, wnd_O)); } } }
public override dynamic Get(IEnumerable <ICandle> source, IIndicatorOptions options = null) { List <ICandle> result = new List <ICandle>(); ICandle previous = null; foreach (ICandle item in source) { ICandle candle = new Candle(); candle.Id = item.Id; candle.Time = item.Time; candle.Volume = item.Volume; if (previous != null) { candle.Close = (item.High + item.Low + item.Close + item.Open) / 4; candle.Open = (previous.Open + previous.Close) / 2; candle.Low = Math.Min(Math.Min(item.Low, item.Open), item.Close); candle.High = Math.Max(Math.Max(item.High, item.Open), item.Close); } else { candle.Close = (item.High + item.Low + item.Close + item.Open) / 4; candle.Open = (item.Open + item.Close) / 2; candle.Low = Math.Min(Math.Min(item.Low, item.Open), item.Close); candle.High = Math.Max(Math.Max(item.High, item.Open), item.Close); } result.Add(candle); previous = item; } return(result); }
public Task <IEnumerable <ICandle> > GetHistory(string sec, DateTime from, string interval) { TaskCompletionSource <IEnumerable <ICandle> > TCS = new TaskCompletionSource <IEnumerable <ICandle> >(); string url = string.Format("{0}{1}?security={2}&from={3}&interval={4}", this.ServerURL, "api/candle/", sec, from.ToString(System.Globalization.CultureInfo.InvariantCulture), interval); this._apiClient.GetData(url).ContinueWith(t => { IList <ICandle> List = new List <ICandle>(); string data = t.Result; var array = Windows.Data.Json.JsonValue.Parse(data).GetArray(); for (int i = 0; i < array.Count; i++) { var value = array[i]; ICandle candle = this.GetObject(value); List.Add(candle); } TCS.SetResult(List); }); return(TCS.Task); }
public FilterResult Exec() { FilterResult res = FilterResult.N; //скользящая средняя для пятиминуток SimpleMovingAverage ma = new SimpleMovingAverage(_data["5"], 30); ICandle prev = _data["5"][_data["5"].Count - 2]; //свеча вышла за сколящую среднюю вверх bool crossUp = prev.close > ma.Last() * 1.003m; //свеча вышла за сколящую среднюю вниз bool crossDown = prev.close < ma.Last() * 0.997m; if (crossUp) { res = FilterResult.L; } if (crossDown) { res = FilterResult.S; } return(res); }
public Task AddAsync(ICandle candle) { return(_storage.InsertOrModifyAsync( CandleEntity.GetPartitionKey(candle.AssetPairId, candle.CandleTimestamp), CandleEntity.GetRowKey(candle.CandleTimestamp), () => new CandleEntity(candle), c => { if (c.Low > candle.Low) { c.Low = candle.Low; } if (c.High < candle.High) { c.High = candle.High; } if (c.CloseTimestamp < candle.CloseTimestamp) { c.Close = candle.Close; c.CloseTimestamp = candle.CloseTimestamp; } if (c.OpenTimestamp > candle.OpenTimestamp) { c.Open = candle.Open; c.OpenTimestamp = candle.OpenTimestamp; } return true; })); }
private ICandle NormalizeCandlePrices(ICandle candle) { var lastNonZeroPrice = GetLastNonZeroPrice(candle.AssetPairId, candle.PriceType); var open = ConvertToDecimal(candle.Open); var close = ConvertToDecimal(candle.Close); var high = ConvertToDecimal(candle.High); var low = ConvertToDecimal(candle.Low); if (open == 0 || close == 0 || high == 0 || low == 0) { open = open == 0 ? lastNonZeroPrice : open; close = close == 0 ? lastNonZeroPrice : close; high = high == 0 ? lastNonZeroPrice : high; low = low == 0 ? lastNonZeroPrice : low; return(Candle.Create(candle.AssetPairId, candle.PriceType, candle.TimeInterval, candle.Timestamp, (double)open, (double)close, (double)high, (double)low, 0, 0, 0, candle.Timestamp)); } return(candle); }
private static byte[] SerializeCandle(ICandle candle) { // result is: // 0 .. TimestampFormat.Length - 1 bytes: timestamp as yyyyMMddHHmmss in ASCII // TimestampFormat.Length .. end bytes: serialized RedistCachedCandle var timestampString = candle.Timestamp.ToString(TimestampFormat); var timestampBytes = Encoding.ASCII.GetBytes(timestampString); using (var stream = new MemoryStream()) { stream.Write(timestampBytes, 0, timestampBytes.Length); var cachedCandle = new RedisCachedCandle { Open = candle.Open, Close = candle.Close, Low = candle.Low, High = candle.High, TradingVolume = candle.TradingVolume, TradingOppositVolume = candle.TradingOppositeVolume, LastTradePrice = candle.LastTradePrice, LastUpdateTimestamp = candle.LastUpdateTimestamp }; MessagePack.MessagePackSerializer.Serialize(stream, cachedCandle); stream.Flush(); return(stream.ToArray()); } }
private async Task ProcessAskAndBidHistoryAsync( DateTime?askStartDate, DateTime askEndDate, ICandle askEndCandle, DateTime?bidStartDate, DateTime bidEndDate, ICandle bidEndCandle) { try { var processAskCandlesTask = askStartDate.HasValue ? _historyProvider.GetHistoryByChunksAsync(_assetPair, CandlePriceType.Ask, askEndDate, askEndCandle, ProcessHistoryChunkAsync, _cts.Token) : Task.CompletedTask; var processBidkCandlesTask = bidStartDate.HasValue ? _historyProvider.GetHistoryByChunksAsync(_assetPair, CandlePriceType.Bid, bidEndDate, bidEndCandle, ProcessHistoryChunkAsync, _cts.Token) : Task.CompletedTask; await Task.WhenAny(processAskCandlesTask, processBidkCandlesTask); _isAskOrBidMigrationCompleted = true; await Task.WhenAll(processAskCandlesTask, processBidkCandlesTask); } catch { _cts.Cancel(); throw; } }
// The function we will use as predicate in LINQ to find extreme candles private bool IsExtremeCandle(ICandle candleToTest, double limitLow, double limitHigh, double epsilon) { if (candleToTest.Open < epsilon || candleToTest.Close < epsilon || candleToTest.High < epsilon || candleToTest.Low < epsilon) { return(true); } if (candleToTest.Open > limitHigh || candleToTest.Open < limitLow) { return(true); } if (candleToTest.Close > limitHigh || candleToTest.Close < limitLow) { return(true); } if (candleToTest.High > limitHigh || candleToTest.High < limitLow) { return(true); } return(candleToTest.Low > limitHigh || candleToTest.Low < limitLow); }
/// <summary> /// Extends a candle by another one candle. These two candles must be compatible by TimeStamp, TimeInterval and PriceType. /// </summary> public static ICandle ExtendBy(this ICandle self, ICandle newCandle) { if (self.Timestamp != newCandle.Timestamp) { throw new InvalidOperationException("It's impossible to extend a candle by another one with the different time stamp."); } if (self.TimeInterval != newCandle.TimeInterval) { throw new InvalidOperationException($"It's impossible to extend a candle with time interval {self.TimeInterval} by another one with {newCandle.TimeInterval}."); } if (self.PriceType != newCandle.PriceType) { throw new InvalidOperationException($"It's impossible to extend a candle eith price type {self.PriceType} by another one with {newCandle.PriceType}"); } var selfIsOlder = self.LastUpdateTimestamp <= newCandle.LastUpdateTimestamp; return(Candle.Create( self.AssetPairId, self.PriceType, self.TimeInterval, self.Timestamp, selfIsOlder ? self.Open : newCandle.Open, selfIsOlder ? newCandle.Close : self.Close, Math.Max(self.High, newCandle.High), Math.Min(self.Low, newCandle.Low), Convert.ToDouble((decimal)self.TradingVolume + (decimal)newCandle.TradingVolume), // It's a bit messy, but really allows to keep precision in addiction operation. Convert.ToDouble((decimal)self.TradingOppositeVolume + (decimal)newCandle.TradingOppositeVolume), selfIsOlder ? newCandle.LastTradePrice : self.LastTradePrice, selfIsOlder ? newCandle.LastUpdateTimestamp : self.LastUpdateTimestamp )); }
private void UpdateLastNonZeroPrice(ICandle candle) { var key = GetKey(candle.AssetPairId, candle.PriceType); var price = ConvertToDecimal(candle.Close); if (price == 0m) { price = ConvertToDecimal(candle.High); if (price == 0m) { price = ConvertToDecimal(candle.Low); if (price == 0m) { price = ConvertToDecimal(candle.Open); } } } if (price != 0m) { _lastNonZeroPrices[key] = price; } }
public IList <ICandle> Convert(IList <ICandle> candles, int sourceTimeframe, int TargetTimeframe) { List <ICandle> result = new List <ICandle>(); IEnumerable <string> securities = candles.GroupBy(c => c.Code).Select(g => g.Key); foreach (string sec in securities) { var tempdata = candles.Where(c => c.Code == sec).ToList(); DateTime start = tempdata.First().begin; DateTime stop = tempdata.Last().begin; int inc = start.Minute % TargetTimeframe; if (inc > 0) { start = start.AddMinutes(TargetTimeframe - inc); } while (start <= stop) { ICandle candle = CreateCandle(tempdata, start, TargetTimeframe); if (candle != null) { result.Add(candle); } start = start.AddMinutes(TargetTimeframe); } } return(result); }
//--------------------------------------------------------------------------------------------------------------------------------------- protected override void OnRender(DrawingContext drawingContext) { //drawingContext.DrawRectangle(Brushes.Aquamarine, transparentPen, new Rect(0, 0, RenderSize.Width, RenderSize.Height)); double volumeBarWidth = VolumeBarWidthToCandleWidthRatio * CandleWidthAndGap.Width; double volumeBarGap = (1.0 - VolumeBarWidthToCandleWidthRatio) * CandleWidthAndGap.Width + CandleWidthAndGap.Gap; double halfDWidth = 0.5 * (CandleWidthAndGap.Width - volumeBarWidth); for (int i = 0; i < VisibleCandlesRange.Count; i++) { ICandle cndl = CandlesSource[VisibleCandlesRange.Start_i + i]; Brush cndlBrush = (cndl.C > cndl.O) ? BullishBarFill : BearishBarFill; Pen cndlPen = (cndl.C > cndl.O) ? bullishBarPen : bearishBarPen; double wnd_V = (1.0 - cndl.V / (double)VisibleCandlesExtremums.VolumeHigh) * RenderSize.Height; double volumeBarLeftX = halfDWidth + i * (volumeBarWidth + volumeBarGap); if (cndl.V > 0L) { drawingContext.DrawRectangle(cndlBrush, null, new Rect(volumeBarLeftX, wnd_V, volumeBarWidth, RenderSize.Height - wnd_V)); } else { drawingContext.DrawLine(cndlPen, new Point(volumeBarLeftX, 0.0), new Point(volumeBarLeftX + volumeBarWidth, 0.0)); } } }
//--------------------------------------------------------------------------------------------------------------------------------------- protected override void OnMouseMove(MouseEventArgs e) { Point mousePos = e.GetPosition(this); //Vector uv = new Vector(mousePos.X/ RenderSize.Width, mousePos.Y / RenderSize.Height); int cndl_i = VisibleCandlesRange.Start_i + (int)(mousePos.X / (CandleWidthAndGap.Width + CandleWidthAndGap.Gap)); ICandle cndl = CandlesSource[cndl_i]; string tooltipText = $"{cndl.t.ToString("d.MM.yyyy H:mm")}\nO={cndl.O}\nH={cndl.H}\nL={cndl.L}\nC={cndl.C}\nV={cndl.V}"; ((ToolTip)ToolTip).Content = tooltipText; }
public static bool Big(ICandle candle) { decimal avg = (candle.open + candle.close) / 2; decimal v2 = Math.Abs(candle.open - candle.close); decimal p = avg * 0.0015m; return(v2 > p); }
public override void AddValueToLine(ICandle candle, Func <ICandle, decimal> func = null) { var lineValues = SeriesCollection[0].Values; lineValues.Add(new OhlcPoint((double)candle.Open, (double)candle.High, (double)candle.Low, (double)candle.Close)); while (lineValues.Count > MaxPointsCount) { lineValues.RemoveAt(0); } }
/// <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)); }
public override void AddValueToLine(ICandle candle, Func <ICandle, decimal> func) { var curValue = func.Invoke(candle); var lineValues = SeriesCollection[0].Values; double value = LastCandle == null ? 0 : (double)(curValue / func.Invoke(LastCandle) - 1) * 100; lineValues.Add(new ObservableValue(value)); while (lineValues.Count > MaxPointsCount) { lineValues.RemoveAt(0); } LastCandle = candle; }
public static CandleHistoryItem ToItem(this ICandle candle, int tick) { return(new CandleHistoryItem ( open: candle.Open, close: candle.Close, high: candle.High, low: candle.Low, tick: tick, tradingVolume: candle.TradingVolume, tradingOppositeVolume: candle.TradingOppositeVolume, lastUpdateTimestamp: candle.LastUpdateTimestamp )); }
/// <summary> /// Merges candle change with the same asset pair, price type, time interval and timestamp /// </summary> /// <param name="candleState">Candle state</param> public void InplaceMergeWith(ICandle candleState) { if (LastUpdateTimestamp >= candleState.LastUpdateTimestamp) { return; } Close = candleState.Close; High = Math.Max(High, candleState.High); Low = Math.Min(Low, candleState.Low); TradingVolume = candleState.TradingVolume; TradingOppositeVolume = candleState.TradingOppositeVolume; LastUpdateTimestamp = candleState.LastUpdateTimestamp; }
public static CandleHistoryItem ToItem(this ICandle candle, int tick) { return(new CandleHistoryItem ( candle.Open, candle.Close, candle.High, candle.Low, tick, candle.TradingVolume, candle.TradingOppositeVolume, candle.LastTradePrice, candle.LastUpdateTimestamp )); }
//--------------------------------------------------------------------------------------------------------------------------------------- protected override void OnMouseMove(MouseEventArgs e) { string decimalSeparator = Culture.NumberFormat.NumberDecimalSeparator; char[] decimalSeparatorArray = decimalSeparator.ToCharArray(); Point mousePos = e.GetPosition(this); //Vector uv = new Vector(mousePos.X/ RenderSize.Width, mousePos.Y / RenderSize.Height); int cndl_i = VisibleCandlesRange.Start_i + (int)(mousePos.X / (CandleWidthAndGap.Width + CandleWidthAndGap.Gap)); ICandle cndl = CandlesSource[cndl_i]; string strT = cndl.t.ToString((CandlesSource.TimeFrame < 0) ? "G" : "g", Culture); string tooltipText = $"{strT}\nV= {MyNumberFormatting.VolumeToString(cndl.V, Culture, decimalSeparator, decimalSeparatorArray)}"; ((ToolTip)ToolTip).Content = tooltipText; }
/// <summary> /// Creates a new candle with all of the parameter values from self but with new time interval. /// </summary> public static ICandle RebaseToInterval(this ICandle self, CandleTimeInterval newInterval) { return(Candle.Create( self.AssetPairId, self.PriceType, newInterval, self.Timestamp.TruncateTo(newInterval), self.Open, self.Close, self.High, self.Low, self.TradingVolume, self.TradingOppositeVolume, self.LastTradePrice, self.LastUpdateTimestamp )); }
// 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> /// returns the candle with the lowest wick /// </summary> /// <returns>candle with lowest wick.</returns> /// <param name="count">period</param> /// <param name="startBar">Start bar.</param> public ICandle Lowest(int count, int startBar) { ICandle minCandle = null; for (int i = 0; i < count; ++i) { var candle = Candles[i + startBar]; if (minCandle == null) { minCandle = candle; } else if (candle.Low < minCandle.Low) { minCandle = candle; } } return(minCandle); }
/// <summary> /// returns the candle with the highest wick /// </summary> /// <returns>candle with highest wick.</returns> /// <param name="count">period</param> /// <param name="startBar">Start bar.</param> public ICandle Highest(int count, int startBar) { ICandle maxCandle = null; for (int i = 0; i < count; ++i) { var candle = Candles[i + startBar]; if (maxCandle == null) { maxCandle = candle; } else if (candle.High > maxCandle.High) { maxCandle = candle; } } return(maxCandle); }