public override void Add(Bars bars, double open, double high, double low, double close, DateTime time, long volume, bool isRealtime) { //### First Bar if ((bars.Count == 0) || bars.IsNewSession(time, isRealtime)) { tickSize = bars.Instrument.MasterInstrument.TickSize; trendOffset = bars.Period.Value * bars.Instrument.MasterInstrument.TickSize; reversalOffset = bars.Period.Value2 * bars.Instrument.MasterInstrument.TickSize; //bars.Period.BasePeriodValue = bars.Period.Value; //### Remove to customize OpenOffset openOffset = Math.Ceiling((double)bars.Period.BasePeriodValue * 1) * bars.Instrument.MasterInstrument.TickSize; barOpen = close; barMax = barOpen + (trendOffset * barDirection); barMin = barOpen - (trendOffset * barDirection); AddBar(bars, barOpen, barOpen, barOpen, barOpen, time, volume, isRealtime); } //### Subsequent Bars else { Data.Bar bar = (Bar)bars.Get(bars.Count - 1); maxExceeded = bars.Instrument.MasterInstrument.Compare(close, barMax) > 0 ? true : false; minExceeded = bars.Instrument.MasterInstrument.Compare(close, barMin) < 0 ? true : false; //### Defined Range Exceeded? if (maxExceeded || minExceeded) { double thisClose = maxExceeded ? Math.Min(close, barMax) : minExceeded?Math.Max(close, barMin) : close; barDirection = maxExceeded ? 1 : minExceeded ? -1 : 0; fakeOpen = thisClose - (openOffset * barDirection); //### Fake Open is halfway down the bar //### Close Current Bar UpdateBar(bars, bar.Open, (maxExceeded ? thisClose : bar.High), (minExceeded ? thisClose : bar.Low), thisClose, time, volume, isRealtime); //### Add New Bar barOpen = close; barMax = thisClose + ((barDirection > 0 ? trendOffset : reversalOffset)); barMin = thisClose - ((barDirection > 0 ? reversalOffset : trendOffset)); AddBar(bars, fakeOpen, (maxExceeded ? thisClose : fakeOpen), (minExceeded ? thisClose : fakeOpen), thisClose, time, volume, isRealtime); } //### Current Bar Still Developing else { UpdateBar(bars, bar.Open, (close > bar.High ? close : bar.High), (close < bar.Low ? close : bar.Low), close, time, volume, isRealtime); } } bars.LastPrice = close; }
/// <summary> /// </summary> /// <param name="bars"></param> /// <param name="open"></param> /// <param name="high"></param> /// <param name="low"></param> /// <param name="close"></param> /// <param name="time"></param> /// <param name="volume"></param> /// <param name="isRealtime"></param> public override void Add(Bars bars, double open, double high, double low, double close, DateTime time, long volume, bool isRealtime) { if ((curdat == null) || (time < curdat.dt)) { extdat.Clear(); extdat.TrimExcess(); curdat = null; tickSize = bars.Instrument.MasterInstrument.TickSize; } if (bars.Count == 0) { AddBar(bars, open, high, low, close, time.Date, volume, isRealtime); RWTAddExtDat(time, close, volume); } else { if (curdat == null) { RWTAddExtDat(time, close, 0); } Bar bar = (Bar)bars.Get(bars.Count - 1); double tall = 1 + ((bar.High - bar.Low) / bars.Instrument.MasterInstrument.TickSize); double denom = tall; if (tall < 2) { denom += 99999; } if (tall > 10) { denom -= ((tall - 10) / 2.0); } if (tall > 20) { denom -= ((tall - 20) / 3.0); } if (((double)(bar.Volume + volume)) / denom >= ((double)(bars.Period.Value))) { AddBar(bars, close, close, close, close, time, volume, isRealtime); RWTAddExtDat(time, close, volume); } else { UpdateBar(bars, open, high, low, close, time, volume, isRealtime); curdat.dt = time; RWTUpdateCurdat(close, volume); } } bars.LastPrice = close; prevClose = close; }
/// <summary> /// </summary> /// <param name="bars"></param> /// <param name="open"></param> /// <param name="high"></param> /// <param name="low"></param> /// <param name="close"></param> /// <param name="time"></param> /// <param name="volume"></param> /// <param name="isRealtime"></param> public override void Add(Bars bars, double open, double high, double low, double close, DateTime time, long volume, bool isRealtime) { if ((curdat == null) || (time < curdat.dt)) { extdat.Clear(); extdat.TrimExcess(); curdat = null; tickSize = bars.Instrument.MasterInstrument.TickSize; } if (bars.Count == 0) { AddBar(bars, open, high, low, close, time, volume, isRealtime); RWTAddExtDat(time, close, volume); } else { Data.Bar bar = (Bar)bars.Get(bars.Count - 1); if (curdat == null) { RWTAddExtDat(time, close, 0); } curdat.dt = time; if (upbar && ((curdat.dHigh - curdat.dClose) >= bars.Period.Value)) { AddBar(bars, close, close, close, close, time, volume, isRealtime); RWTAddExtDat(time, close, volume); upbar = false; } else if (!upbar && ((curdat.dClose - curdat.dLow) >= bars.Period.Value)) { AddBar(bars, close, close, close, close, time, volume, isRealtime); RWTAddExtDat(time, close, volume); upbar = true; } else { UpdateBar(bars, open, high, low, close, time, volume, isRealtime); // regular update... RWTUpdateCounts(close); RWTUpdateCurdat(close, volume); } } bars.LastPrice = close; // update the extended data... prevClose = close; }
protected override void OnBarUpdate() { if (Bars == null) { return; } if (!BarsType.GetInstance(Bars.Period.Id).IsIntraday) { return; } if (Bars.Period.Id == PeriodType.Minute && Bars.Period.Value > _minutes / 2) { return; } if (!_isLoaded && !_isInit) { _isInit = true; _intradayBars = Bars.GetBars(Bars.Instrument, new Period(PeriodType.Minute, _minutes, MarketDataType.Last), Bars.From, Bars.To, (Session)Bars.Session.Clone(), Bars.SplitAdjust, Bars.DividendAdjust); _existsHistHourlyData = (_intradayBars.Count <= 1) ? false : true; _isInit = false; _isLoaded = true; } if (!_existsHistHourlyData) { return; } DateTime intradayBarTime = Time[0].AddMinutes(-_minutes); IBar intradayBar = _intradayBars.Get(_intradayBars.GetBar(intradayBarTime)); double high = intradayBar.High; double low = intradayBar.Low; double close = intradayBar.Close; Hpp.Set((high + low + close) / 3); Hs1.Set(2 * Hpp[0] - high); Hr1.Set(2 * Hpp[0] - low); Hs2.Set(Hpp[0] - (high - low)); Hr2.Set(Hpp[0] + (high - low)); }
public override double GetPercentComplete(Bars bars, DateTime now) { switch (Period.BasePeriodType) { case PeriodType.Day: return(now.Date <= bars.TimeLastBar.Date ? 1.0 - (bars.TimeLastBar.AddDays(1).Subtract(now).TotalDays / bars.Period.Value) : 1); case PeriodType.Minute: return(now <= bars.TimeLastBar ? 1.0 - (bars.TimeLastBar.Subtract(now).TotalMinutes / bars.Period.Value) : 1); case PeriodType.Month: if (now.Date <= bars.TimeLastBar.Date) { int month = now.Month; int daysInMonth = (month == 2) ? (DateTime.IsLeapYear(now.Year) ? 29 : 28) : (month == 1 || month == 3 || month == 5 || month == 7 || month == 8 || month == 10 || month == 12 ? 31 : 30); return((daysInMonth - (bars.TimeLastBar.Date.AddDays(1).Subtract(now).TotalDays / bars.Period.Value)) / daysInMonth); // not exact } return(1); case PeriodType.Second: return(now <= bars.TimeLastBar ? 1.0 - (bars.TimeLastBar.Subtract(now).TotalSeconds / bars.Period.Value) : 1); case PeriodType.Tick: return((double)bars.TickCount / bars.Period.Value); case PeriodType.Volume: return((double)bars.Get(bars.CurrentBar).Volume / bars.Period.Value); case PeriodType.Week: return(now.Date <= bars.TimeLastBar.Date ? (7 - (bars.TimeLastBar.AddDays(1).Subtract(now).TotalDays / bars.Period.Value)) / 7 : 1); case PeriodType.Year: if (now.Date <= bars.TimeLastBar.Date) { double daysInYear = DateTime.IsLeapYear(now.Year) ? 366 : 365; return((daysInYear - (bars.TimeLastBar.Date.AddDays(1).Subtract(now).TotalDays / bars.Period.Value)) / daysInYear); } return(1); default: return(now.Date <= bars.TimeLastBar.Date ? 1.0 - (bars.TimeLastBar.AddDays(1).Subtract(now).TotalDays / bars.Period.Value) : 1); } }
/// <summary> /// Called on each incoming tick /// </summary> void OnTick(Bars bars, double open, double high, double low, double close, DateTime time, long volume, bool isRealtime) { // ensure xml config loaded ConfigCheck(); // create initial bar on first tick and handle NT7 session-break issue (note: removing IsNewSession() creates invalid bars; remove if preferred) if ((bars.Count == 0) || bars.IsNewSession(time, isRealtime)) { // set class fields tickSize = bars.Instrument.MasterInstrument.TickSize; // calculate bear/bull min/max RangeInit(); // update class fields AdjustOpenClose(bars, close, close); prevClose = close; // add first bar AddBar(bars, thisOpen, thisOpen, thisOpen, thisOpen, time, volume, isRealtime); // add EmProps AddEmProps(thisOpen, volume, thisCloseDown, thisCloseUp, time); } // continue all subsequent ticks/bars else { // local variables Bar bar = (Bar)bars.Get(bars.Count - 1); int compareCloseUp = bars.Instrument.MasterInstrument.Compare(close, thisCloseUp); int compareCloseDown = bars.Instrument.MasterInstrument.Compare(close, thisCloseDown); // range exceeded; create new bar(s) if (((compareCloseUp > 0 || compareCloseDown < 0) && CloseOption == EmCloses.TickThru) || ((compareCloseUp >= 0 || compareCloseDown <= 0) && CloseOption == EmCloses.OnTouch)) { // local variables bool newBar = true; double thisClose = (compareCloseUp > 0) ? Math.Min(close, thisCloseUp) : (compareCloseDown < 0) ? Math.Max(close, thisCloseDown) : close; // close current bar; volume included for on-touch only // see this post for more info on volume calculation: http://www.ninjatrader.com/support/forum/showthread.php?p=302208#post302208 UpdateBar(bars, bar.Open, ((compareCloseUp > 0) ? thisClose : bar.High), ((compareCloseDown < 0) ? thisClose : bar.Low), thisClose, time, ((CloseOption == EmCloses.OnTouch) ? volume : 0), isRealtime); barProps.Finalize(thisClose, prevClose, ((CloseOption == EmCloses.OnTouch) ? volume : 0), time, ((close > bar.Open) ? 1 : (close < bar.Open) ? -1 : 0)); // add next bar and loop phantom bars, if needed do { // update class fields thisBias = (close > bar.Open) ? 1 : (close < bar.Open) ? -1 : 0; tickRange = EmMath.RangeValidate(Math.Abs(AddTwoDoubles(bars, bar.Open, -thisClose)), (thisBias == -1) ? tickBearRangeMax : tickBullRangeMax, (thisBias == -1) ? tickBearRangeMin : tickBullRangeMin); AdjustOpenClose(bars, thisClose, close); thisClose = (compareCloseUp > 0) ? Math.Min(close, thisCloseUp) : (compareCloseDown < 0) ? Math.Max(close, thisCloseDown) : close; // add new bar; include volume once (except for on-touch), then create phantom bars // see this post for more info on volume calculation: http://www.ninjatrader.com/support/forum/showthread.php?p=302208#post302208 AddBar(bars, thisOpen, ((compareCloseUp > 0) ? thisClose : thisOpen), ((compareCloseDown < 0) ? thisClose : thisOpen), thisClose, time, ((CloseOption == EmCloses.TickThru && newBar) ? volume : 0), isRealtime); // add EmProps AddEmProps(thisOpen, ((compareCloseUp > 0) ? thisClose : thisOpen), ((compareCloseDown < 0) ? thisClose : thisOpen), thisClose, ((CloseOption == EmCloses.TickThru && newBar) ? volume : 0), time, thisBias, thisCloseDown, thisCloseUp); // update class fields newBar = false; compareCloseUp = bars.Instrument.MasterInstrument.Compare(close, thisCloseUp); compareCloseDown = bars.Instrument.MasterInstrument.Compare(close, thisCloseDown); }while (((compareCloseUp > 0 || compareCloseDown < 0) && CloseOption == EmCloses.TickThru) || ((compareCloseUp >= 0 || compareCloseDown <= 0) && CloseOption == EmCloses.OnTouch)); } // range not exceeded; continue current bar else { // update current bar UpdateBar(bars, bar.Open, ((close > bar.High) ? close : bar.High), ((close < bar.Low) ? close : bar.Low), close, time, volume, isRealtime); // update EmProps barProps.Update(close, prevClose, volume, time); } } // update prevClose and last price bars.LastPrice = prevClose = close; }
// Override OnBarUpdate method protected override void OnBarUpdate() { // Protect against too few bars if (Bars == null) { return; } if (!Data.BarsType.GetInstance(Bars.Period.Id).IsIntraday) { return; } if (Bars.Period.Id == PeriodType.Minute && Bars.Period.Value > timeFrame / 2) { return; } if (!full && !apt) { apt = true; periodBars = Data.Bars.GetBars(Bars.Instrument, new Period(PeriodType.Minute, timeFrame, MarketDataType.Last), Bars.From, Bars.To, (Session)Bars.Session.Clone(), Data.Bars.SplitAdjust, Data.Bars.DividendAdjust); apt = false; full = true; } // Remove calculation for first time span after open IBar periodBar; Bars.Session.GetNextBeginEnd(Time[0], out sessionBegin, out sessionEnd); if (Time[0] >= sessionBegin && Time[0] <= sessionBegin.AddMinutes(timeFrame)) { Pivot.Reset(); Resistance1.Reset(); Support1.Reset(); Resistance2.Reset(); Support2.Reset(); Resistance3.Reset(); Support3.Reset(); Resistance4.Reset(); Support4.Reset(); Resistance5.Reset(); Support5.Reset(); } else { // Determine open, high, low, and close DateTime intradayBarTime = Time[0].AddMinutes(-timeFrame); periodBar = periodBars.Get(periodBars.GetBar(intradayBarTime)); double Open = periodBar.Open; double High = periodBar.High; double Low = periodBar.Low; double Close = periodBar.Close; double pivot = periodBar.Close; // Switch central pivot calculation switch (centralPivotCalculation) { // Standard calculation case case CentralPivotCalculation.Standard: { pivot = (High + Low + Close) / 3; break; } // Open included calculation case case CentralPivotCalculation.OpenIncluded: { pivot = (Open + High + Low + Close) / 4; break; } // Close weighted calculation case case CentralPivotCalculation.CloseWeighted: { pivot = (High + Low + Close + Close) / 4; break; } // High weighted calculation case case CentralPivotCalculation.HighWeighted: { pivot = (High + High + Low + Close) / 4; break; } // Low weighted calculation case case CentralPivotCalculation.LowWeighted: { pivot = (High + Low + Low + Close) / 4; break; } } // Switch round to tick option switch (roundToTick) { // Rounding case case RoundToTick.Yes: { // Set all additional pivots, rounded Pivot.Set(Instrument.MasterInstrument.Round2TickSize(pivot)); Resistance1.Set(Instrument.MasterInstrument.Round2TickSize(2 * Pivot[0] - Low)); Support1.Set(Instrument.MasterInstrument.Round2TickSize(2 * Pivot[0] - High)); Resistance2.Set(Instrument.MasterInstrument.Round2TickSize(Pivot[0] + (High - Low))); Support2.Set(Instrument.MasterInstrument.Round2TickSize(Pivot[0] - (High - Low))); Resistance3.Set(Instrument.MasterInstrument.Round2TickSize(High + 2 * (Pivot[0] - Low))); Support3.Set(Instrument.MasterInstrument.Round2TickSize(Low - 2 * (High - Pivot[0]))); Resistance4.Set(Instrument.MasterInstrument.Round2TickSize(Pivot[0] + 2 * (High - Low))); Support4.Set(Instrument.MasterInstrument.Round2TickSize(Pivot[0] - 2 * (High - Low))); Resistance5.Set(Instrument.MasterInstrument.Round2TickSize(2 * (Pivot[0] + High) - 3 * Low)); Support5.Set(Instrument.MasterInstrument.Round2TickSize(2 * (Pivot[0] + Low) - 3 * High)); break; } // No rounding case case RoundToTick.No: { // Set all additional pivots, not rounded Pivot.Set(pivot); Resistance1.Set(2 * Pivot[0] - Low); Support1.Set(2 * Pivot[0] - High); Resistance2.Set(Pivot[0] + (High - Low)); Support2.Set(Pivot[0] - (High - Low)); Resistance3.Set(High + 2 * (Pivot[0] - Low)); Support3.Set(Low - 2 * (High - Pivot[0])); Resistance4.Set(Pivot[0] + 2 * (High - Low)); Support4.Set(Pivot[0] - 2 * (High - Low)); Resistance5.Set(2 * (Pivot[0] + High) - 3 * Low); Support5.Set(2 * (Pivot[0] + Low) - 3 * High); break; } } } }
/// <summary> /// </summary> public override double GetPercentComplete(Bars bars, DateTime now) { return (double) bars.Get(bars.CurrentBar).Volume / bars.Period.Value; }
public override void Add(Bars bars, double open, double high, double low, double close, DateTime time, long volume, bool isRealtime) { // ******************* ADDED FROM RENKO CODE TO SOLVE MEMORY LEAK **************************** // brick size is the trendOffset (Value) + openOffset (BasePeriodValue) offset = (bars.Period.Value + bars.Period.BasePeriodValue) * bars.Instrument.MasterInstrument.TickSize; if (bars.Count < tmpCount && bars.Count > 0) // reset cache when bars are trimmed { barMax = bars.GetClose(bars.Count - 1) + offset; barMin = bars.GetClose(bars.Count - 1) - offset; } // ******************************************************************************************** //### First Bar if ((bars.Count == 0) || bars.IsNewSession(time, isRealtime)) { tickSize = bars.Instrument.MasterInstrument.TickSize; //### Parse Long Param Specification if (bars.Period.Value >= 1000000) { int d; string str = bars.Period.Value.ToString("000000000"); d = 0; Int32.TryParse(str.Substring(0, 3), out d); bars.Period.Value = d; d = 0; Int32.TryParse(str.Substring(3, 3), out d); bars.Period.Value2 = d; d = 0; Int32.TryParse(str.Substring(6, 3), out d); bars.Period.BasePeriodValue = d; } //****** ADDED FROM RENKO ***************************************************************** if (bars.Count != 0) { // close out last bar in session and set open == close Bar lastBar = (Bar)bars.Get(bars.Count - 1); bars.RemoveLastBar(); // Note: bar is now just a local var and not in series! AddBar(bars, lastBar.Close, lastBar.High, lastBar.Low, lastBar.Close, lastBar.Time, lastBar.Volume, isRealtime); } //**************************************************************************************** trendOffset = bars.Period.Value * bars.Instrument.MasterInstrument.TickSize; reversalOffset = bars.Period.Value2 * bars.Instrument.MasterInstrument.TickSize; //bars.Period.BasePeriodValue = bars.Period.Value; //### Remove to customize OpenOffset openOffset = Math.Ceiling((double)bars.Period.BasePeriodValue * 1) * bars.Instrument.MasterInstrument.TickSize; barOpen = close; barMax = barOpen + (trendOffset * barDirection); barMin = barOpen - (trendOffset * barDirection); AddBar(bars, barOpen, barOpen, barOpen, barOpen, time, volume, isRealtime); } //### Subsequent Bars else { Data.Bar bar = (Bar)bars.Get(bars.Count - 1); // *************ADDED FROM RENKO CODE (to deal with '0' values at Market Replay) ************ if (barMax == 0 || barMin == 0) //Not sure why, but happens { // trendOffset was also '0', so need to reinitialize trendOffset = bars.Period.Value * bars.Instrument.MasterInstrument.TickSize; reversalOffset = bars.Period.Value2 * bars.Instrument.MasterInstrument.TickSize; openOffset = Math.Ceiling((double)bars.Period.BasePeriodValue * 1) * bars.Instrument.MasterInstrument.TickSize; if (bars.Count == 1) { barMax = bar.Open + trendOffset; barMin = bar.Open - trendOffset; } else if (bars.GetClose(bars.Count - 2) > bars.GetOpen(bars.Count - 2)) { barMax = bars.GetClose(bars.Count - 2) + trendOffset; barMin = bars.GetClose(bars.Count - 2) - trendOffset * 2; } else { barMax = bars.GetClose(bars.Count - 2) + trendOffset * 2; barMin = bars.GetClose(bars.Count - 2) - trendOffset; } } // ************************************************************************************************ maxExceeded = bars.Instrument.MasterInstrument.Compare(close, barMax) > 0 ? true : false; minExceeded = bars.Instrument.MasterInstrument.Compare(close, barMin) < 0 ? true : false; //### Defined Range Exceeded? if (maxExceeded || minExceeded) { double thisClose = maxExceeded ? Math.Min(close, barMax) : minExceeded?Math.Max(close, barMin) : close; // thisClose is the minimum of BarMax and close (maxExceeded) barDirection = maxExceeded ? 1 : minExceeded ? -1 : 0; fakeOpen = thisClose - (openOffset * barDirection); //### Fake Open is halfway down the bar //### Close Current Bar UpdateBar(bars, bar.Open, (maxExceeded ? thisClose : bar.High), (minExceeded ? thisClose : bar.Low), thisClose, time, volume, isRealtime); //### Add New Bar barOpen = close; barMax = thisClose + ((barDirection > 0 ? trendOffset : reversalOffset)); barMin = thisClose - ((barDirection > 0 ? reversalOffset : trendOffset)); AddBar(bars, fakeOpen, (maxExceeded ? thisClose : fakeOpen), (minExceeded ? thisClose : fakeOpen), thisClose, time, volume, isRealtime); } //### Current Bar Still Developing else { UpdateBar(bars, bar.Open, (close > bar.High ? close : bar.High), (close < bar.Low ? close : bar.Low), close, time, volume, isRealtime); } } bars.LastPrice = close; tmpCount = bars.Count; // ADDED FROM RENKO CODE }
/// <summary> /// </summary> /// <param name="bars"></param> /// <param name="open"></param> /// <param name="high"></param> /// <param name="low"></param> /// <param name="close"></param> /// <param name="time"></param> /// <param name="volume"></param> /// <param name="isRealtime"></param> public override void Add(Bars bars, double open, double high, double low, double close, DateTime time, long volume, bool isRealtime) { #region Building Bars from Base Period if (bars.Count != tmpCount) // reset cache when bars are trimmed if (bars.Count == 0) { tmpTime = Cbi.Globals.MinDate; tmpVolume = 0; tmpDayCount = 0; tmpTickCount = 0; } else { tmpTime = bars.GetTime(bars.Count - 1); tmpVolume = bars.GetVolume(bars.Count - 1); tmpTickCount = bars.TickCount; tmpDayCount = bars.DayCount; bars.LastPrice = bars.GetClose(bars.Count - 1); anchorPrice = bars.LastPrice; } switch (bars.Period.BasePeriodType) { case PeriodType.Day: tmpTime = time.Date; // will be modified for realtime only if (isRealtime && time >= cacheSessionEnd /* on realtime include60 is always false */) { bars.Session.GetSessionDate(time, false, out tmpTime, out cacheSessionEnd); if (tmpTime < time.Date) tmpTime = time.Date; // make sure timestamps are ascending } if (prevTime != tmpTime) tmpDayCount++; if (tmpDayCount < bars.Period.BasePeriodValue || (!isRealtime && bars.Count > 0 && tmpTime == bars.TimeLastBar.Date) || (isRealtime && bars.Count > 0 && tmpTime <= bars.TimeLastBar.Date)) endOfBar = false; else { prevTime = tmpTime; endOfBar = true; } break; case PeriodType.Minute: if (tmpTime == Cbi.Globals.MinDate) prevTime = tmpTime = TimeToBarTimeMinute(bars, time, bars.Session.NextBeginTime, bars.Period.BasePeriodValue, isRealtime); if (!isRealtime && time <= tmpTime || isRealtime && time < tmpTime) endOfBar = false; else { prevTime = tmpTime; tmpTime = TimeToBarTimeMinute(bars, time, bars.Session.NextBeginTime, bars.Period.BasePeriodValue, isRealtime); endOfBar = true; } break; case PeriodType.Volume: if (tmpTime == Cbi.Globals.MinDate) { tmpVolume = volume; endOfBar = tmpVolume >= bars.Period.BasePeriodValue; prevTime = tmpTime = time; if (endOfBar) tmpVolume = 0; break; } tmpVolume += volume; endOfBar = tmpVolume >= bars.Period.BasePeriodValue; if (endOfBar) { prevTime = tmpTime; tmpVolume = 0; } tmpTime = time; break; case PeriodType.Tick: if (tmpTime == Cbi.Globals.MinDate || bars.Period.BasePeriodValue == 1) { prevTime = tmpTime == Cbi.Globals.MinDate ? time : tmpTime; tmpTime = time; tmpTickCount = bars.Period.BasePeriodValue == 1 ? 0 : 1; endOfBar = bars.Period.BasePeriodValue == 1; break; } if (tmpTickCount < bars.Period.BasePeriodValue) { tmpTime = time; endOfBar = false; tmpTickCount++; } else { prevTime = tmpTime; tmpTime = time; endOfBar = true; tmpTickCount = 1; } break; case PeriodType.Month: if (tmpTime == Cbi.Globals.MinDate) prevTime = tmpTime = TimeToBarTimeMonth(time, bars.Period.BasePeriodValue); if (time.Month <= tmpTime.Month && time.Year == tmpTime.Year || time.Year < tmpTime.Year) endOfBar = false; else { prevTime = tmpTime; endOfBar = true; tmpTime = TimeToBarTimeMonth(time, bars.Period.BasePeriodValue); } break; case PeriodType.Second: if (tmpTime == Cbi.Globals.MinDate) { prevTime = tmpTime = TimeToBarTimeSecond(bars, time, new DateTime( bars.Session.NextBeginTime.Year, bars.Session.NextBeginTime.Month, bars.Session.NextBeginTime.Day, bars.Session.NextBeginTime.Hour, bars.Session.NextBeginTime.Minute, 0), bars.Period.BasePeriodValue); } if ((bars.Period.Value > 1 && time < tmpTime) || (bars.Period.Value == 1 && time <= tmpTime)) endOfBar = false; else { prevTime = tmpTime; tmpTime = TimeToBarTimeSecond(bars, time, bars.Session.NextBeginTime, bars.Period.BasePeriodValue); endOfBar = true; } break; case PeriodType.Week: if (tmpTime == Cbi.Globals.MinDate) prevTime = tmpTime = TimeToBarTimeWeek(time.Date, tmpTime.Date, bars.Period.BasePeriodValue); if (time.Date <= tmpTime.Date) endOfBar = false; else { prevTime = tmpTime; endOfBar = true; tmpTime = TimeToBarTimeWeek(time.Date, tmpTime.Date, bars.Period.BasePeriodValue); } break; case PeriodType.Year: if (tmpTime == Cbi.Globals.MinDate) prevTime = tmpTime = TimeToBarTimeYear(time, bars.Period.Value); if (time.Year <= tmpTime.Year) endOfBar = false; else { prevTime = tmpTime; endOfBar = true; tmpTime = TimeToBarTimeYear(time, bars.Period.Value); } break; } #endregion #region Kagi Logic reversalPoint = bars.Period.ReversalType == ReversalType.Tick ? bars.Period.Value * bars.Instrument.MasterInstrument.TickSize : bars.Period.Value * 0.01 * anchorPrice; if (bars.Count == 0 || (IsIntraday && ((bars.Period.BasePeriodType != PeriodType.Second && bars.IsNewSession(time, isRealtime)) || (bars.Period.BasePeriodType == PeriodType.Second && bars.IsNewSession(tmpTime, isRealtime))))) { if (bars.Count > 0) { double lastOpen = bars.GetOpen(bars.Count - 1); double lastHigh = bars.GetHigh(bars.Count - 1); double lastLow = bars.GetLow(bars.Count - 1); double lastClose = bars.GetClose(bars.Count - 1); if (bars.Count == tmpCount) CalculateKagiBar(bars, lastOpen, lastHigh, lastLow, lastClose, prevTime, volume, isRealtime); } AddBar(bars, close, close, close, close, tmpTime, volume, isRealtime); anchorPrice = close; trend = Trend.Undetermined; prevTime = tmpTime; volumeCount = 0; bars.LastPrice = close; tmpCount = bars.Count; return; } Bar bar = (Bar)bars.Get(bars.Count - 1); double c = bar.Close; double o = bar.Open; double h = bar.High; double l = bar.Low; if (endOfBar) CalculateKagiBar(bars, o, h, l, c, prevTime, volume, isRealtime); else volumeCount += volume; bars.LastPrice = close; tmpCount = bars.Count; #endregion }
/// <summary> /// </summary> public override double GetPercentComplete(Bars bars, DateTime now) { return((double)bars.Get(bars.CurrentBar).Volume / bars.Period.Value); }
/// <summary> /// add new tick data to bars /// </summary> public override void Add(Bars bars, double open, double high, double low, double close, DateTime time, long volume, bool isRealtime) { // create initial bar on first tick and handle NT7 session-break issue (note: removing IsNewSession() creates invalid bars; remove if preferred) if ((bars.Count == 0) || bars.IsNewSession(time, isRealtime)) { // update fields tickSize = bars.Instrument.MasterInstrument.TickSize; rangeMax = AddTwoDoubles(bars, (double)Period.Value * tickSize, 0); rangeMin = AddTwoDoubles(bars, (double)Period.BasePeriodValue * tickSize, 0); /// swap min/max if entered incorrectly if (rangeMin > rangeMax) { double tmp = rangeMax; rangeMax = rangeMin; rangeMin = tmp; } // set initial range, factoring dynamic thisRange = isDynamic ? rangeMin : rangeMax; AdjustMaxMin(bars, close, close); // add first bar AddBar(bars, thisOpen, thisOpen, thisOpen, thisOpen, time, volume, isRealtime); } // continue all subsequent ticks/bars else { // local variables Data.Bar thisBar = (Bar)bars.Get(bars.Count - 1); int maxCompare = bars.Instrument.MasterInstrument.Compare(close, thisMax); int minCompare = bars.Instrument.MasterInstrument.Compare(close, thisMin); double thisClose = maxCompare > 0 ? Math.Min(close, thisMax) : minCompare < 0 ? Math.Max(close, thisMin) : close; // range exceeded; create new bar(s) if (maxCompare > 0 || minCompare < 0) { // local variables bool newBar = true; // update bias prevBias = thisBias; thisBias = close > thisBar.Open ? 1 : close < thisBar.Open ? -1 : 0; // close current bar; volume included for on-touch only // see this post for more info on volume calculation: http://www.ninjatrader.com/support/forum/showthread.php?p=302208#post302208 UpdateBar(bars, thisBar.Open, (maxCompare > 0 ? thisClose : thisBar.High), (minCompare < 0 ? thisClose : thisBar.Low), thisClose, time, 0, isRealtime); // add next bar and loop phantom bars, if needed do { // update thisRange for dynamic if (isDynamic) { // increment range for same bias, if range has not exceeded max if ((thisBias == prevBias || prevBias == 0) && thisRange < rangeMax) { thisRange = AddTwoDoubles(bars, thisRange, tickSize); } // increment range after trend change (will only fire once) else if (thisBias != prevBias && prevBias != 0) { thisRange = AddTwoDoubles(bars, rangeMin, tickSize); } // ensure valid range thisRange = Math.Min(thisRange, rangeMax); } // update fields AdjustMaxMin(bars, thisClose, close); thisClose = (maxCompare > 0) ? Math.Min(close, thisMax) : (minCompare < 0) ? Math.Max(close, thisMin) : close; // add new bar; include volume once (except for on-touch), then create phantom bars // see this post for more info on volume calculation: http://www.ninjatrader.com/support/forum/showthread.php?p=302208#post302208 AddBar(bars, thisOpen, (maxCompare > 0 ? thisClose : thisOpen), (minCompare < 0 ? thisClose : thisOpen), thisClose, time, (newBar ? volume : 0), isRealtime); newBar = false; // update fields maxCompare = bars.Instrument.MasterInstrument.Compare(close, thisMax); minCompare = bars.Instrument.MasterInstrument.Compare(close, thisMin); }while (maxCompare > 0 || minCompare < 0); } // range not exceeded; continue current bar else { // update current bar UpdateBar(bars, thisBar.Open, (close > thisBar.High ? close : thisBar.High), (close < thisBar.Low ? close : thisBar.Low), close, time, volume, isRealtime); } } // update last price bars.LastPrice = close; }
/// <summary> /// /// </summary> /// <param name="bars"></param> /// <param name="open"></param> /// <param name="high"></param> /// <param name="low"></param> /// <param name="close"></param> /// <param name="time"></param> /// <param name="volume"></param> /// <param name="isRealtime"></param> public override void Add(Bars bars, double open, double high, double low, double close, DateTime time, long volume, bool isRealtime) { if (bars.Count == 0 && tmpTime != Cbi.Globals.MinDate) // reset caching when live request trimmed existing bars tmpTime = Cbi.Globals.MinDate; bool endOfBar = true; if (tmpTime == Cbi.Globals.MinDate) { tmpTime = time; tmpDayCount = 1; tmpTickCount = 1; } else if (bars.Count < tmpCount && bars.Count == 0) // reset cache when bars are trimmed { tmpTime = Cbi.Globals.MinDate; tmpVolume = 0; tmpDayCount = 0; tmpTickCount = 0; } else if (bars.Count < tmpCount && bars.Count > 0) // reset cache when bars are trimmed { tmpTime = bars.GetTime(bars.Count - 1); tmpVolume = bars.GetVolume(bars.Count - 1); tmpTickCount = bars.TickCount; tmpDayCount = bars.DayCount; } switch (bars.Period.BasePeriodType) { case PeriodType.Day: { if (bars.Count == 0 || (bars.Count > 0 && (bars.TimeLastBar.Month < time.Month || bars.TimeLastBar.Year < time.Year))) { tmpTime = time.Date; bars.LastPrice = close; newSession = true; } else { tmpTime = time.Date; tmpVolume += volume; bars.LastPrice = close; tmpDayCount++; if (tmpDayCount < bars.Period.BasePeriodValue || (bars.Count > 0 && bars.TimeLastBar.Date == time.Date)) endOfBar = false; } break; } case PeriodType.Minute: { if (bars.Count == 0 || bars.IsNewSession(time, isRealtime)) { tmpTime = TimeToBarTimeMinute(bars, time, bars.Session.NextBeginTime, bars.Period.BasePeriodValue, isRealtime); newSession = true; tmpVolume = 0; } else { if (isRealtime && time < bars.TimeLastBar || !isRealtime && time <= bars.TimeLastBar) { tmpTime = bars.TimeLastBar; endOfBar = false; } else tmpTime = TimeToBarTimeMinute(bars, time, bars.Session.NextBeginTime, bars.Period.BasePeriodValue, isRealtime); tmpVolume += volume; } break; } case PeriodType.Month: { if (tmpTime == Cbi.Globals.MinDate) { tmpTime = TimeToBarTimeMonth(time, bars.Period.BasePeriodValue); if (bars.Count == 0) break; endOfBar = false; } else if ((time.Month <= tmpTime.Month && time.Year == tmpTime.Year) || time.Year < tmpTime.Year) { tmpVolume += volume; bars.LastPrice = close; endOfBar = false; } break; } case PeriodType.Second: { if (bars.IsNewSession(time, isRealtime)) { tmpTime = TimeToBarTimeSecond(bars, time, new DateTime(bars.Session.NextBeginTime.Year, bars.Session.NextBeginTime.Month, bars.Session.NextBeginTime.Day, bars.Session.NextBeginTime.Hour, bars.Session.NextBeginTime.Minute, 0), bars.Period.BasePeriodValue); if (bars.Count == 0) break; endOfBar = false; newSession = true; } else if (time <= tmpTime) { tmpVolume += volume; bars.LastPrice = close; endOfBar = false; } else tmpTime = TimeToBarTimeSecond(bars, time, bars.Session.NextBeginTime, bars.Period.BasePeriodValue); break; } case PeriodType.Tick: { if (bars.IsNewSession(time, isRealtime)) { newSession = true; tmpTime = time; tmpTickCount = 1; if (bars.Count == 0) break; endOfBar = false; } else if (bars.Period.BasePeriodValue > 1 && tmpTickCount < bars.Period.BasePeriodValue) { tmpTime = time; tmpVolume += volume; tmpTickCount++; bars.LastPrice = close; endOfBar = false; } else tmpTime = time; // there can't be a situation when new ticks go into old bar, this would mean peeking into future. Fixed in NT7B14 20100416 CH break; } case PeriodType.Volume: { if (bars.IsNewSession(time, isRealtime)) newSession = true; else if (bars.Count == 0 && volume > 0) break; else { tmpVolume += volume; if (tmpVolume < bars.Period.BasePeriodValue) { bars.LastPrice = close; endOfBar = false; } else if (tmpVolume == 0) endOfBar = false; } tmpTime = time; // there can't be a situation when new ticks go into old bar, this would mean peeking into future. Fixed in NT7B14 20100416 CH break; } case PeriodType.Week: { if (tmpTime == Cbi.Globals.MinDate) { tmpTime = TimeToBarTimeWeek(time.Date, tmpTime.Date, bars.Period.BasePeriodValue); if (bars.Count == 0) break; endOfBar = false; } else if (time.Date <= tmpTime.Date) { tmpVolume += volume; bars.LastPrice = close; endOfBar = false; } break; } case PeriodType.Year: { if (tmpTime == Cbi.Globals.MinDate) { tmpTime = TimeToBarTimeYear(time, bars.Period.Value); if (bars.Count == 0) break; endOfBar = false; } else if (time.Year <= tmpTime.Year) { tmpVolume += volume; bars.LastPrice = close; endOfBar = false; } break; } default: break; } if (bars.Count == 0 || (newSession && IsIntraday)) { AddBar(bars, open, close, close, close, tmpTime, volume, isRealtime); upTrend = (open < close); newSessionIdx = bars.Count - 1; newSession = false; firstBarOfSession = true; anchorPrice = close; switchPrice = open; } else if (firstBarOfSession && endOfBar == false) { double prevOpen = bars.GetOpen(bars.Count - 1); bars.RemoveLastBar(isRealtime); AddBar(bars, prevOpen, close, close, close, tmpTime, tmpVolume, isRealtime); upTrend = (prevOpen < close); anchorPrice = close; } else { int breakCount = bars.Period.Value; Bar bar = (Bar)bars.Get(bars.Count - 1); double breakMax = double.MinValue; double breakMin = double.MaxValue; if (firstBarOfSession) { AddBar(bars, anchorPrice, close, close, close, tmpTime, volume, isRealtime); firstBarOfSession = false; tmpVolume = volume; tmpTime = Cbi.Globals.MinDate; return; } if (bars.Count - newSessionIdx - 1 < breakCount) breakCount = bars.Count - (newSessionIdx + 1); for (int k = 1; k <= breakCount; k++) { Bar tmp = (Bar)bars.Get(bars.Count - k - 1); breakMax = Math.Max(breakMax, tmp.Open); breakMax = Math.Max(breakMax, tmp.Close); breakMin = Math.Min(breakMin, tmp.Open); breakMin = Math.Min(breakMin, tmp.Close); } bars.LastPrice = close; if (upTrend) if (endOfBar) { bool adding = false; if (bars.Instrument.MasterInstrument.Compare(bar.Close, anchorPrice) > 0) { anchorPrice = bar.Close; switchPrice = bar.Open; tmpVolume = volume; adding = true; } else if (bars.Instrument.MasterInstrument.Compare(breakMin, bar.Close) > 0) { anchorPrice = bar.Close; switchPrice = bar.Open; tmpVolume = volume; upTrend = false; adding = true; } if (adding) { double tmpOpen = upTrend ? Math.Min(Math.Max(switchPrice, close), anchorPrice) : Math.Max(Math.Min(switchPrice, close), anchorPrice); AddBar(bars, tmpOpen, close, close, close, tmpTime, volume, isRealtime); } else { bars.RemoveLastBar(isRealtime); double tmpOpen = Math.Min(Math.Max(switchPrice, close), anchorPrice); AddBar(bars, tmpOpen, close, close, close, tmpTime, tmpVolume, isRealtime); } } else { bars.RemoveLastBar(isRealtime); double tmpOpen = Math.Min(Math.Max(switchPrice, close), anchorPrice); AddBar(bars, tmpOpen, close, close, close, tmpTime, tmpVolume, isRealtime); } else if (endOfBar) { bool adding = false; if (bars.Instrument.MasterInstrument.Compare(bar.Close, anchorPrice) < 0) { anchorPrice = bar.Close; switchPrice = bar.Open; tmpVolume = volume; adding = true; } else if (bars.Instrument.MasterInstrument.Compare(breakMax, bar.Close) < 0) { anchorPrice = bar.Close; switchPrice = bar.Open; tmpVolume = volume; upTrend = true; adding = true; } if (adding) { double tmpOpen = upTrend ? Math.Min(Math.Max(switchPrice, close), anchorPrice) : Math.Max(Math.Min(switchPrice, close), anchorPrice); AddBar(bars, tmpOpen, close, close, close, tmpTime, volume, isRealtime); } else { bars.RemoveLastBar(isRealtime); double tmpOpen = Math.Max(Math.Min(switchPrice, close), anchorPrice); AddBar(bars, tmpOpen, close, close, close, tmpTime, tmpVolume, isRealtime); } } else { bars.RemoveLastBar(isRealtime); double tmpOpen = Math.Max(Math.Min(switchPrice, close), anchorPrice); AddBar(bars, tmpOpen, close, close, close, tmpTime, tmpVolume, isRealtime); } } if (endOfBar) tmpTime = Cbi.Globals.MinDate; tmpCount = bars.Count; }
/// <summary> /// </summary> /// <param name="bars"></param> /// <param name="open"></param> /// <param name="high"></param> /// <param name="low"></param> /// <param name="close"></param> /// <param name="time"></param> /// <param name="volume"></param> /// <param name="isRealtime"></param> public override void Add(Bars bars, double open, double high, double low, double close, DateTime time, long volume, bool isRealtime) { offset = bars.Period.Value * bars.Instrument.MasterInstrument.TickSize; if (bars.Count < tmpCount && bars.Count > 0) // reset cache when bars are trimmed { renkoHigh = bars.GetClose(bars.Count - 1) + offset; renkoLow = bars.GetClose(bars.Count - 1) - offset; } if ((bars.Count == 0) || (bars.IsNewSession(time, isRealtime))) { if (bars.Count != 0) { // close out last bar in session and set open == close Bar lastBar = (Bar)bars.Get(bars.Count - 1); bars.RemoveLastBar(isRealtime); // Note: bar is now just a local var and not in series! AddBar(bars, lastBar.Close, lastBar.Close, lastBar.Close, lastBar.Close, lastBar.Time, lastBar.Volume, isRealtime); } renkoHigh = close + offset; renkoLow = close - offset; AddBar(bars, close, close, close, close, time, volume, isRealtime); bars.LastPrice = close; return; } Bar bar = (Bar)bars.Get(bars.Count - 1); if (renkoHigh == 0 || renkoLow == 0) //Not sure why, but happens { if (bars.Count == 1) { renkoHigh = bar.Open + offset; renkoLow = bar.Open - offset; } else if (bars.GetClose(bars.Count - 2) > bars.GetOpen(bars.Count - 2)) { renkoHigh = bars.GetClose(bars.Count - 2) + offset; renkoLow = bars.GetClose(bars.Count - 2) - offset * 2; } else { renkoHigh = bars.GetClose(bars.Count - 2) + offset * 2; renkoLow = bars.GetClose(bars.Count - 2) - offset; } } if (bars.Instrument.MasterInstrument.Compare(close, renkoHigh) >= 0) { if (bars.Instrument.MasterInstrument.Compare(bar.Open, renkoHigh - offset) != 0 || bars.Instrument.MasterInstrument.Compare(bar.High, Math.Max(renkoHigh - offset, renkoHigh)) != 0 || bars.Instrument.MasterInstrument.Compare(bar.Low, Math.Min(renkoHigh - offset, renkoHigh)) != 0) { bars.RemoveLastBar(isRealtime); // Note: bar is now just a local var and not in series! AddBar(bars, renkoHigh - offset, Math.Max(renkoHigh - offset, renkoHigh), Math.Min(renkoHigh - offset, renkoHigh), renkoHigh, time, bar.Volume + volume, isRealtime); } else UpdateBar(bars, renkoHigh - offset, Math.Max(renkoHigh - offset, renkoHigh), Math.Min(renkoHigh - offset, renkoHigh), renkoHigh, time, volume, isRealtime); renkoLow = renkoHigh - 2.0 * offset; renkoHigh = renkoHigh + offset; while (bars.Instrument.MasterInstrument.Compare(close, renkoHigh) >= 0) // add empty bars to fill gap { AddBar(bars, renkoHigh - offset, Math.Max(renkoHigh - offset, renkoHigh), Math.Min(renkoHigh - offset, renkoHigh), renkoHigh, time, 1, isRealtime); renkoLow = renkoHigh - 2.0 * offset; renkoHigh = renkoHigh + offset; } // add final partial bar AddBar(bars, renkoHigh - offset, Math.Max(renkoHigh - offset, close), Math.Min(renkoHigh - offset, close), close, time, 1, isRealtime); } else if (bars.Instrument.MasterInstrument.Compare(close, renkoLow) <= 0) { if (bars.Instrument.MasterInstrument.Compare(bar.Open, renkoLow + offset) != 0 || bars.Instrument.MasterInstrument.Compare(bar.High, Math.Max(renkoLow + offset, renkoLow)) != 0 || bars.Instrument.MasterInstrument.Compare(bar.Low, Math.Min(renkoLow + offset, renkoLow)) != 0) { bars.RemoveLastBar(isRealtime); // Note: bar is now just a local var and not in series! AddBar(bars, renkoLow + offset, Math.Max(renkoLow + offset, renkoLow), Math.Min(renkoLow + offset, renkoLow), renkoLow, time, bar.Volume + volume, isRealtime); } else UpdateBar(bars, renkoLow + offset, Math.Max(renkoLow + offset, renkoLow), Math.Min(renkoLow + offset, renkoLow), renkoLow, time, volume, isRealtime); renkoHigh = renkoLow + 2.0 * offset; renkoLow = renkoLow - offset; while (bars.Instrument.MasterInstrument.Compare(close, renkoLow) <= 0) // add empty bars to fill gap { AddBar(bars, renkoLow + offset, Math.Max(renkoLow + offset, renkoLow), Math.Min(renkoLow + offset, renkoLow), renkoLow, time, 1, isRealtime); renkoHigh = renkoLow + 2.0 * offset; renkoLow = renkoLow - offset; } // add final partial bar AddBar(bars, renkoLow + offset, Math.Max(renkoLow + offset, close), Math.Min(renkoLow + offset, close), close, time, 1, isRealtime); } else // Note: open does not really change UpdateBar(bars, close, close, close, close, time, volume, isRealtime); bars.LastPrice = close; tmpCount = bars.Count; }
/// <summary> /// </summary> /// <param name="bars"></param> /// <param name="open"></param> /// <param name="high"></param> /// <param name="low"></param> /// <param name="close"></param> /// <param name="time"></param> /// <param name="volume"></param> /// <param name="isRealtime"></param> public override void Add(Bars bars, double open, double high, double low, double close, DateTime time, long volume, bool isRealtime) { if (bars.Count == 0 || bars.IsNewSession(time, isRealtime)) AddBar(bars, open, high, low, close, time, volume, isRealtime); else { Bar bar = (Bar) bars.Get(bars.Count - 1); double tickSize = bars.Instrument.MasterInstrument.TickSize; double rangeValue = Math.Floor(10000000.0 * bars.Period.Value * tickSize) / 10000000.0; if (bars.Instrument.MasterInstrument.Compare(close, bar.Low + rangeValue) > 0) { bool isFirstNewBar = true; double newClose = bar.Low + rangeValue; // every bar closes either with high or low if (bars.Instrument.MasterInstrument.Compare(bar.Close, newClose) < 0) UpdateBar(bars, bar.Open, newClose, bar.Low, newClose, time, 0, isRealtime); // if still gap, fill with phantom bars double newBarOpen = newClose + tickSize; while (bars.Instrument.MasterInstrument.Compare(close, newClose) > 0) { newClose = Math.Min(close, newBarOpen + rangeValue); AddBar(bars, newBarOpen, newClose, newBarOpen, newClose, time, isFirstNewBar ? volume : 1, isRealtime); newBarOpen = newClose + tickSize; isFirstNewBar = false; } } else if (bars.Instrument.MasterInstrument.Compare(bar.High - rangeValue, close) > 0) { bool isFirstNewBar = true; double newClose = bar.High - rangeValue; // every bar closes either with high or low if (bars.Instrument.MasterInstrument.Compare(bar.Close, newClose) > 0) UpdateBar(bars, bar.Open, bar.High, newClose, newClose, time, 0, isRealtime); // if still gap, fill with phantom bars double newBarOpen = newClose - tickSize; while (bars.Instrument.MasterInstrument.Compare(newClose, close) > 0) { newClose = Math.Max(close, newBarOpen - rangeValue); AddBar(bars, newBarOpen, newBarOpen, newClose, newClose, time, isFirstNewBar ? volume : 1, isRealtime); newBarOpen = newClose - tickSize; isFirstNewBar = false; } } else //UpdateBar(bars, open, high, low, close, time, volume, isRealtime); UpdateBar(bars, open, (close > bar.High ? close : bar.High), (close < bar.Low ? close : bar.Low), close, time, volume, isRealtime); } bars.LastPrice = close; }
protected override void OnBarUpdate() { if (CurrentBars[0] < 121) { return; } if (Bars == null) { return; } if (!Data.BarsType.GetInstance(Bars.Period.Id).IsIntraday) { return; } if (Bars.Period.Id == PeriodType.Minute && Bars.Period.Value > minutes / 2) { return; } if (!isLoaded && !isInit) { isInit = true; hourlyBars = Data.Bars.GetBars(Bars.Instrument, new Period(PeriodType.Minute, minutes, MarketDataType.Last), Bars.From, Bars.To, (Session)Bars.Session.Clone(), Data.Bars.SplitAdjust, Data.Bars.DividendAdjust); existsHistHourlyData = (hourlyBars.Count <= 1) ? false : true; isInit = false; isLoaded = true; } IBar hourlyBar; if (CurrentBar == 0) { return; } if (existsHistHourlyData) { DateTime intradayBarTime = Time[0].AddMinutes(-minutes); hourlyBar = hourlyBars.Get(hourlyBars.GetBar(intradayBarTime)); double high = hourlyBar.High; double low = hourlyBar.Low; double close = hourlyBar.Close; HPP.Set((high + low + close) / 3); if (HPP[0] != HPP[1]) { DrawRay("pp", true, 1, HPP[0], 0, HPP[0], Plots[0].Pen.Color, Plots[0].Pen.DashStyle, (int)Plots[0].Pen.Width); } HS1.Set(2 * HPP[0] - high); if (HS1[0] != HS1[1]) { DrawRay("hs1", true, 1, HS1[0], 0, HS1[0], Plots[1].Pen.Color, Plots[1].Pen.DashStyle, (int)Plots[1].Pen.Width); } HR1.Set(2 * HPP[0] - low); if (HR1[0] != HR1[1]) { DrawRay("hr1", true, 1, HR1[0], 0, HR1[0], Plots[4].Pen.Color, Plots[4].Pen.DashStyle, (int)Plots[4].Pen.Width); } HS2.Set(HPP[0] - (high - low)); if (HS2[0] != HS2[1]) { DrawRay("hs2", true, 1, HS2[0], 0, HS2[0], Plots[2].Pen.Color, Plots[2].Pen.DashStyle, (int)Plots[2].Pen.Width); } HR2.Set(HPP[0] + (high - low)); if (HR2[0] != HR2[1]) { DrawRay("hr2", true, 1, HR2[0], 0, HR2[0], Plots[5].Pen.Color, Plots[5].Pen.DashStyle, (int)Plots[5].Pen.Width); } HS3.Set(HS2[0] - (high - low)); if (HS3[0] != HS3[1]) { DrawRay("hs3", true, 1, HS2[0], 0, HS2[0], Plots[3].Pen.Color, Plots[3].Pen.DashStyle, (int)Plots[3].Pen.Width); } HR3.Set(HR1[0] + (high - low)); if (HR3[0] != HR3[1]) { DrawRay("hr3", true, 1, HR2[0], 0, HR2[0], Plots[6].Pen.Color, Plots[6].Pen.DashStyle, (int)Plots[6].Pen.Width); } } else { return; } }
public override void Add(Bars bars, double open, double high, double low, double close, DateTime time, long volume, bool isRealtime) { #region Reset cache if (bars.Count == 0 && tmpTime != Cbi.Globals.MinDate) // reset caching when live request trimmed existing bars { tmpTime = Cbi.Globals.MinDate; } bool endOfBar = true; if (tmpTime == Cbi.Globals.MinDate) { tmpTime = time; tmpDayCount = 1; tmpTickCount = 1; } else if (bars.Count < tmpCount && bars.Count == 0) // reset cache when bars are trimmed { tmpTime = Cbi.Globals.MinDate; tmpVolume = 0; tmpDayCount = 0; tmpTickCount = 0; } else if (bars.Count < tmpCount && bars.Count > 0) // reset cache when bars are trimmed { tmpTime = bars.GetTime(bars.Count - 1); tmpVolume = bars.GetVolume(bars.Count - 1); tmpTickCount = bars.TickCount; tmpDayCount = bars.DayCount; } #endregion #region Switch Periods switch (bars.Period.BasePeriodType) { #region tick case PeriodType.Tick: { if (bars.IsNewSession(time, isRealtime)) { newSession = true; tmpTime = time; tmpTickCount = 1; if (bars.Count == 0) { break; } endOfBar = false; } else { if (bars.Period.BasePeriodValue > 1 && tmpTickCount < bars.Period.BasePeriodValue) { tmpTime = time; tmpVolume += volume; tmpTickCount++; bars.LastPrice = close; endOfBar = false; } else { tmpTime = time; // there can't be a situation when new ticks go into old bar, this would mean peeking into future. Fixed in NT7B14 20100416 CH } } break; } #endregion #region Volume case PeriodType.Volume: { if (bars.IsNewSession(time, isRealtime)) { newSession = true; } else if (bars.Count == 0 && volume > 0) { break; } else { tmpVolume += volume; if (tmpVolume < bars.Period.BasePeriodValue) { bars.LastPrice = close; endOfBar = false; } else if (tmpVolume == 0) { endOfBar = false; } } tmpTime = time; // there can't be a situation when new ticks go into old bar, this would mean peeking into future. Fixed in NT7B14 20100416 CH break; } #endregion #region Second case PeriodType.Second: { if (bars.IsNewSession(time, isRealtime)) { tmpTime = TimeToBarTimeSecond(bars, time, new DateTime(bars.Session.NextBeginTime.Year, bars.Session.NextBeginTime.Month, bars.Session.NextBeginTime.Day, bars.Session.NextBeginTime.Hour, bars.Session.NextBeginTime.Minute, 0), bars.Period.BasePeriodValue); if (bars.Count == 0) { break; } endOfBar = false; newSession = true; } else { if (time <= tmpTime) { tmpVolume += volume; bars.LastPrice = close; endOfBar = false; } else { tmpTime = TimeToBarTimeSecond(bars, time, bars.Session.NextBeginTime, bars.Period.BasePeriodValue); } } break; } #endregion #region Day case PeriodType.Day: { if (bars.Count == 0 || (bars.Count > 0 && (bars.TimeLastBar.Month < time.Month || bars.TimeLastBar.Year < time.Year))) { tmpTime = time.Date; bars.LastPrice = close; newSession = true; } else { tmpTime = time.Date; tmpVolume += volume; bars.LastPrice = close; tmpDayCount++; if (tmpDayCount < bars.Period.BasePeriodValue || (bars.Count > 0 && bars.TimeLastBar.Date == time.Date)) { endOfBar = false; } } break; } #endregion #region Minute case PeriodType.Minute: { if (bars.Count == 0 || bars.IsNewSession(time, isRealtime)) { tmpTime = TimeToBarTimeMinute(bars, time, bars.Session.NextBeginTime, bars.Period.BasePeriodValue, isRealtime); newSession = true; tmpVolume = 0; } else { if (isRealtime && time < bars.TimeLastBar || !isRealtime && time <= bars.TimeLastBar) { tmpTime = bars.TimeLastBar; endOfBar = false; } else { tmpTime = TimeToBarTimeMinute(bars, time, bars.Session.NextBeginTime, bars.Period.BasePeriodValue, isRealtime); } tmpVolume += volume; } break; } #endregion #region Week case PeriodType.Week: { if (tmpTime == Cbi.Globals.MinDate) { tmpTime = TimeToBarTimeWeek(time.Date, tmpTime.Date, bars.Period.BasePeriodValue); if (bars.Count == 0) { break; } endOfBar = false; } else { if (time.Date <= tmpTime.Date) { tmpVolume += volume; bars.LastPrice = close; endOfBar = false; } } break; } #endregion #region Month case PeriodType.Month: { if (tmpTime == Cbi.Globals.MinDate) { tmpTime = TimeToBarTimeMonth(time, bars.Period.BasePeriodValue); if (bars.Count == 0) { break; } endOfBar = false; } else { if ((time.Month <= tmpTime.Month && time.Year == tmpTime.Year) || time.Year < tmpTime.Year) { tmpVolume += volume; bars.LastPrice = close; endOfBar = false; } } break; } #endregion #region Year case PeriodType.Year: { if (tmpTime == Cbi.Globals.MinDate) { tmpTime = TimeToBarTimeYear(time, bars.Period.Value); if (bars.Count == 0) { break; } endOfBar = false; } else { if (time.Year <= tmpTime.Year) { tmpVolume += volume; bars.LastPrice = close; endOfBar = false; } } break; } #endregion #region Default default: break; #endregion } #endregion #region Add bars if (bars.Count == 0 || (newSession && IsIntraday)) // Very first bar setup. { #region First bar AddBar(bars, open, close, close, close, tmpTime, volume, isRealtime); upTrend = (open < close); newSessionIdx = bars.Count - 1; newSession = false; firstBarOfSession = true; anchorPrice = close; switchPrice = open; tmpHigh = close; tmpLow = close; #endregion } else if (firstBarOfSession && endOfBar == false) { #region Start of subsiquent bars double prevOpen = bars.GetOpen(bars.Count - 1); bars.RemoveLastBar(isRealtime); AddBar(bars, prevOpen, close, close, close, tmpTime, tmpVolume, isRealtime); upTrend = (prevOpen < close); anchorPrice = close; #endregion } else { int breakCount = bars.Period.Value; Bar bar = (Bar)bars.Get(bars.Count - 1); double breakMax = double.MinValue; double breakMin = double.MaxValue; if (firstBarOfSession) { AddBar(bars, anchorPrice, close, close, close, tmpTime, volume, isRealtime); firstBarOfSession = false; tmpVolume = volume; tmpTime = Cbi.Globals.MinDate; return; } if (bars.Count - newSessionIdx - 1 < breakCount) { breakCount = bars.Count - (newSessionIdx + 1); } for (int k = 1; k <= breakCount; k++) { Bar tmp = (Bar)bars.Get(bars.Count - k - 1); breakMax = Math.Max(breakMax, tmp.Open); breakMax = Math.Max(breakMax, tmp.Close); breakMin = Math.Min(breakMin, tmp.Open); breakMin = Math.Min(breakMin, tmp.Close); } bars.LastPrice = close; if (upTrend) { #region Up trend if (endOfBar) { bool adding = false; if (bars.Instrument.MasterInstrument.Compare(bar.Close, anchorPrice) > 0) { anchorPrice = bar.Close; switchPrice = bar.Open; tmpVolume = volume; adding = true; tmpHigh = bar.Close; tmpLow = bar.Close; } else if (bars.Instrument.MasterInstrument.Compare(breakMin, bar.Close) > 0) { anchorPrice = bar.Close; switchPrice = bar.Open; tmpVolume = volume; upTrend = false; adding = true; tmpHigh = bar.Close; tmpLow = bar.Close; } if (adding) { double tmpOpen = upTrend ? Math.Min(Math.Max(switchPrice, close), anchorPrice) : Math.Max(Math.Min(switchPrice, close), anchorPrice); tmpHigh = Math.Max(tmpHigh, close); tmpLow = Math.Min(tmpLow, close); AddBar(bars, tmpOpen, tmpHigh, tmpLow, close, tmpTime, volume, isRealtime); } else { bars.RemoveLastBar(isRealtime); double tmpOpen = Math.Min(Math.Max(switchPrice, close), anchorPrice); tmpHigh = Math.Max(tmpHigh, close); tmpLow = Math.Min(tmpLow, close); AddBar(bars, tmpOpen, tmpHigh, tmpLow, close, tmpTime, tmpVolume, isRealtime); } } else { bars.RemoveLastBar(isRealtime); double tmpOpen = Math.Min(Math.Max(switchPrice, close), anchorPrice); tmpHigh = Math.Max(tmpHigh, close); tmpLow = Math.Min(tmpLow, close); AddBar(bars, tmpOpen, tmpHigh, tmpLow, close, tmpTime, tmpVolume, isRealtime); } #endregion } else { #region Down trend if (endOfBar) { bool adding = false; if (bars.Instrument.MasterInstrument.Compare(bar.Close, anchorPrice) < 0) { anchorPrice = bar.Close; switchPrice = bar.Open; tmpVolume = volume; adding = true; tmpHigh = bar.Close; tmpLow = bar.Close; } else if (bars.Instrument.MasterInstrument.Compare(breakMax, bar.Close) < 0) { anchorPrice = bar.Close; switchPrice = bar.Open; tmpVolume = volume; upTrend = true; adding = true; tmpHigh = bar.Close; tmpLow = bar.Close; } if (adding) { double tmpOpen = upTrend ? Math.Min(Math.Max(switchPrice, close), anchorPrice) : Math.Max(Math.Min(switchPrice, close), anchorPrice); tmpHigh = Math.Max(tmpHigh, close); tmpLow = Math.Min(tmpLow, close); AddBar(bars, tmpOpen, tmpHigh, tmpLow, close, tmpTime, volume, isRealtime); } else { bars.RemoveLastBar(isRealtime); double tmpOpen = Math.Max(Math.Min(switchPrice, close), anchorPrice); tmpHigh = Math.Max(tmpHigh, close); tmpLow = Math.Min(tmpLow, close); AddBar(bars, tmpOpen, tmpHigh, tmpLow, close, tmpTime, tmpVolume, isRealtime); } } else { bars.RemoveLastBar(isRealtime); double tmpOpen = Math.Max(Math.Min(switchPrice, close), anchorPrice); tmpHigh = Math.Max(tmpHigh, close); tmpLow = Math.Min(tmpLow, close); AddBar(bars, tmpOpen, tmpHigh, tmpLow, close, tmpTime, tmpVolume, isRealtime); } #endregion } } #endregion if (endOfBar) { tmpTime = Cbi.Globals.MinDate; } tmpCount = bars.Count; }
/// <summary> /// Called on each bar update event (incoming tick) /// </summary> protected override void OnBarUpdate() { if (Bars == null) { return; } if (!Bars.BarsType.IsIntraday && Bars.Period.Id != PeriodType.Day) { return; } if (Bars.Period.Id == PeriodType.Day && pivotRangeType == PivotRange.Daily) { return; } if (Bars.Period.Id == PeriodType.Day && Bars.Period.Value > 1) { return; } // pivots only work for // - intraday // - 1 day chart with PivotRange Weekly or Monthly if (!isDailyDataLoaded) { if (priorDayHLC == HLCCalculationMode.DailyBars && Bars.BarsType.IsIntraday) { Enabled = false; System.Threading.ThreadPool.QueueUserWorkItem(new System.Threading.WaitCallback(GetBarsNow)); return; } existsHistDailyData = false; isDailyDataLoaded = true; } IBar dailyBar; if (existsHistDailyData) { sessionDateDaily = GetLastBarSessionDate(Time[0], Bars, PivotRange.Daily); dailyBar = dailyBars.Get(dailyBars.GetBar(sessionDateDaily)); if (dailyBar.Time.Date > sessionDateDaily.Date) { for (DateTime i = sessionDateDaily; i >= dailyBars.GetTime(0); i = i.AddDays(-1)) { dailyBar = dailyBars.Get(dailyBars.GetBar(i)); if (dailyBar.Time.Date == i.Date) { break; } } } } else { dailyBar = null; } double high = existsHistDailyData ? dailyBar.High : High[0]; double low = existsHistDailyData ? dailyBar.Low : Low[0]; double close = existsHistDailyData ? dailyBar.Close : Close[0]; DateTime lastBarTimeStamp = GetLastBarSessionDate(Time[0], Bars, pivotRangeType); if ((currentDate != Cbi.Globals.MinDate && pivotRangeType == PivotRange.Daily && lastBarTimeStamp != currentDate) || (currentWeek != Cbi.Globals.MinDate && pivotRangeType == PivotRange.Weekly && lastBarTimeStamp != currentWeek) || (currentMonth != Cbi.Globals.MinDate && pivotRangeType == PivotRange.Monthly && lastBarTimeStamp != currentMonth)) { pp = (currentHigh + currentLow + currentClose) / 3; s1 = 2 * pp - currentHigh; r1 = 2 * pp - currentLow; s2 = pp - (currentHigh - currentLow); r2 = pp + (currentHigh - currentLow); s3 = pp - 2 * (currentHigh - currentLow); r3 = pp + 2 * (currentHigh - currentLow); ppr1 = (pp + r1) / 2; pps1 = (pp + s1) / 2; r1r2 = (r1 + r2) / 2; s1s2 = (s1 + s2) / 2; r2r3 = (r2 + r3) / 2; s2s3 = (s2 + s3) / 2; currentClose = (priorDayHLC == HLCCalculationMode.UserDefinedValues) ? userDefinedClose : close; currentHigh = (priorDayHLC == HLCCalculationMode.UserDefinedValues) ? userDefinedHigh : high; currentLow = (priorDayHLC == HLCCalculationMode.UserDefinedValues) ? userDefinedLow : low; } else { currentClose = (priorDayHLC == HLCCalculationMode.UserDefinedValues) ? userDefinedClose : close; currentHigh = (priorDayHLC == HLCCalculationMode.UserDefinedValues) ? userDefinedHigh : Math.Max(currentHigh, high); currentLow = (priorDayHLC == HLCCalculationMode.UserDefinedValues) ? userDefinedLow : Math.Min(currentLow, low); } if (pivotRangeType == PivotRange.Daily) { currentDate = lastBarTimeStamp; } if (pivotRangeType == PivotRange.Weekly) { currentWeek = lastBarTimeStamp; } if (pivotRangeType == PivotRange.Monthly) { currentMonth = lastBarTimeStamp; } if ((pivotRangeType == PivotRange.Daily && currentDate != Cbi.Globals.MinDate) || (pivotRangeType == PivotRange.Weekly && currentWeek != Cbi.Globals.MinDate) || (pivotRangeType == PivotRange.Monthly && currentMonth != Cbi.Globals.MinDate)) { PP.Set(pp); R1.Set(r1); S1.Set(s1); R2.Set(r2); S2.Set(s2); R3.Set(r3); S3.Set(s3); // PPR1.Set(ppr1); // PPS1.Set(pps1); // R1R2.Set(r1r2); // S1S2.Set(s1s2); // R2R3.Set(r2r3); // S2S3.Set(s2s3); } }
/// <summary> /// </summary> /// <param name="bars"></param> /// <param name="open"></param> /// <param name="high"></param> /// <param name="low"></param> /// <param name="close"></param> /// <param name="time"></param> /// <param name="volume"></param> /// <param name="isRealtime"></param> public override void Add(Bars bars, double open, double high, double low, double close, DateTime time, long volume, bool isRealtime) { #region Building Bars from Base Period if (bars.Count != tmpCount) // reset cache when bars are trimmed if (bars.Count == 0) { tmpTime = Cbi.Globals.MinDate; tmpVolume = 0; tmpDayCount = 0; tmpTickCount = 0; } else { tmpTime = bars.GetTime(bars.Count - 1); tmpVolume = bars.GetVolume(bars.Count - 1); tmpTickCount = bars.TickCount; tmpDayCount = bars.DayCount; bars.LastPrice = anchorPrice = bars.GetClose(bars.Count - 1); } switch (bars.Period.BasePeriodType) { case PeriodType.Day: tmpTime = time.Date; if (isRealtime && time >= cacheSessionEnd) { tmpDayCount++; bars.Session.GetSessionDate(time, false, out tmpTime, out cacheSessionEnd); if (tmpTime < time.Date) tmpTime = time.Date; // make sure timestamps are ascending } if (!isRealtime && prevTimeD != tmpTime) tmpDayCount++; if ((!isRealtime && bars.Count > 0 && tmpTime == bars.TimeLastBar.Date) || (isRealtime && bars.Count > 0 && tmpTime <= bars.TimeLastBar.Date) || tmpDayCount < bars.Period.BasePeriodValue) endOfBar = false; else { prevTime = prevTimeD == Cbi.Globals.MinDate ? tmpTime : prevTimeD; prevTimeD = tmpTime; endOfBar = true; } break; case PeriodType.Minute: if (tmpTime == Cbi.Globals.MinDate) prevTime = tmpTime = TimeToBarTimeMinute(bars, time, bars.Session.NextBeginTime, bars.Period.BasePeriodValue, isRealtime); if (!isRealtime && time <= tmpTime || isRealtime && time < tmpTime) endOfBar = false; else { prevTime = tmpTime; tmpTime = TimeToBarTimeMinute(bars, time, bars.Session.NextBeginTime, bars.Period.BasePeriodValue, isRealtime); endOfBar = true; } break; case PeriodType.Volume: if (tmpTime == Cbi.Globals.MinDate) { tmpVolume = volume; endOfBar = tmpVolume >= bars.Period.BasePeriodValue; prevTime = tmpTime = time; if (endOfBar) tmpVolume = 0; break; } tmpVolume += volume; endOfBar = tmpVolume >= bars.Period.BasePeriodValue; if (endOfBar) { prevTime = tmpTime; tmpVolume = 0; tmpTime = time; } break; case PeriodType.Month: if (tmpTime == Cbi.Globals.MinDate) prevTime = tmpTime = TimeToBarTimeMonth(time, bars.Period.BasePeriodValue); if (time.Month <= tmpTime.Month && time.Year == tmpTime.Year || time.Year < tmpTime.Year) endOfBar = false; else { prevTime = tmpTime; endOfBar = true; tmpTime = TimeToBarTimeMonth(time, bars.Period.BasePeriodValue); } break; case PeriodType.Second: if (tmpTime == Cbi.Globals.MinDate) { prevTime = tmpTime = TimeToBarTimeSecond(bars, time, new DateTime(bars.Session.NextBeginTime.Year, bars.Session.NextBeginTime.Month, bars.Session.NextBeginTime.Day, bars.Session.NextBeginTime.Hour, bars.Session.NextBeginTime.Minute, 0), bars.Period.BasePeriodValue); } if (time <= tmpTime) endOfBar = false; else { prevTime = tmpTime; tmpTime = TimeToBarTimeSecond(bars, time, bars.Session.NextBeginTime, bars.Period.BasePeriodValue); endOfBar = true; } break; case PeriodType.Tick: if (tmpTime == Cbi.Globals.MinDate || bars.Period.BasePeriodValue == 1) { prevTime = tmpTime = time; tmpTickCount = bars.Period.BasePeriodValue == 1 ? 0 : 1; endOfBar = bars.Period.BasePeriodValue == 1; break; } if (tmpTickCount < bars.Period.BasePeriodValue) { tmpTime = time; endOfBar = false; tmpTickCount++; } else { prevTime = tmpTime; tmpTime = time; endOfBar = true; tmpTickCount = 1; } break; case PeriodType.Week: if (tmpTime == Cbi.Globals.MinDate) prevTime = tmpTime = TimeToBarTimeWeek(time.Date, tmpTime.Date, bars.Period.BasePeriodValue); if (time.Date <= tmpTime.Date) endOfBar = false; else { prevTime = tmpTime; endOfBar = true; tmpTime = TimeToBarTimeWeek(time.Date, tmpTime.Date, bars.Period.BasePeriodValue); } break; case PeriodType.Year: if (tmpTime == Cbi.Globals.MinDate) prevTime = tmpTime = TimeToBarTimeYear(time, bars.Period.Value); if (time.Year <= tmpTime.Year) endOfBar = false; else { prevTime = tmpTime; endOfBar = true; tmpTime = TimeToBarTimeYear(time, bars.Period.Value); } break; default: break; } #endregion #region P&F logic double tickSize = bars.Instrument.MasterInstrument.TickSize; boxSize = Math.Floor(10000000.0 * bars.Period.Value * tickSize) / 10000000.0; reversalSize = bars.Period.Value2 * boxSize; if (bars.Count == 0 || (IsIntraday && bars.IsNewSession(time, isRealtime))) { if (bars.Count > 0) { double lastOpen = bars.GetOpen(bars.Count - 1); double lastHigh = bars.GetHigh(bars.Count - 1); double lastLow = bars.GetLow(bars.Count - 1); double lastClose = bars.GetClose(bars.Count - 1); DateTime lastTime = bars.GetTime(bars.Count - 1); bars.LastPrice = anchorPrice = lastClose; if (bars.Count == tmpCount) CalculatePfBar(bars, lastOpen, lastHigh, lastLow, lastClose, prevTime, lastTime, isRealtime); } AddBar(bars, close, close, close, close, tmpTime, volume, isRealtime); anchorPrice = close; trend = Trend.Undetermined; prevTime = tmpTime; volumeCount = 0; bars.LastPrice = close; tmpCount = bars.Count; tmpHigh = high; tmpLow = low; return; } Bar bar = (Bar)bars.Get(bars.Count - 1); double c = bar.Close; double o = bar.Open; double h = bar.High; double l = bar.Low; DateTime t = bar.Time; if (endOfBar) { CalculatePfBar(bars, o, h, l, c, prevTime, t, isRealtime); volumeCount = volume; tmpHigh = high; tmpLow = low; } else { tmpHigh = (high > tmpHigh ? high : tmpHigh); tmpLow = (low < tmpLow ? low : tmpLow); volumeCount += volume; } bars.LastPrice = close; tmpCount = bars.Count; #endregion }