protected override void OnBarUpdate() { // Reset for every session if (sessionIterator.IsNewSession(Time[0], false)) { sessionIterator.GetNextSession(Time[0], false); } // Sometimes CurrentDayOHL is not initialized yet for new session. IDKW if (CurrentDayOHL().CurrentHigh[0] == 0 || CurrentDayOHL().CurrentLow[0] == 0) { return; } MidPoint[0] = ((CurrentDayOHL().CurrentHigh[0] - CurrentDayOHL().CurrentLow[0]) / 2) + CurrentDayOHL().CurrentLow[0]; // Set brush to Transparent on first tick of new session // to disconnect indicator plot between sesions. Plots are // relative to current bar and last bar. if (Bars.IsFirstBarOfSession && IsFirstTickOfBar) { PlotBrushes[0][0] = Brushes.Transparent; } // Draw line between start of session and first bar since the // plot is set to transparent for the session disconnect effect if (Bars.IsFirstBarOfSession) { RemoveDrawObject(Time[0].Date.ToString() + "mid"); Draw.Line(this, Time[0].Date.ToString() + "mid", true, sessionIterator.ActualSessionBegin, MidPoint[0], Time[0], MidPoint[0], Plots[0].Brush, Plots[0].DashStyleHelper, (int)Plots[0].Pen.Thickness); } }
protected override void OnDataPoint(Bars bars, double open, double high, double low, double close, DateTime time, long volume, bool isBar, double bid, double ask) { if (SessionIterator == null) { SessionIterator = new SessionIterator(bars); } bool isNewSession = SessionIterator.IsNewSession(time, isBar); if (isNewSession) { SessionIterator.GetNextSession(time, isBar); } if (bars.BarsPeriod.Value == 1) { AddBar(bars, open, high, low, close, time, volume, bid, ask); } else if (bars.Count == 0) { AddBar(bars, open, high, low, close, time, volume); } else if (bars.Count > 0 && (!bars.IsResetOnNewTradingDay || !isNewSession) && bars.BarsPeriod.Value > 1 && bars.TickCount < bars.BarsPeriod.Value) { UpdateBar(bars, high, low, close, time, volume); } else { AddBar(bars, open, high, low, close, time, volume); } }
private DateTime GetLastBarSessionDate(DateTime time, PivotRange pivotRange) { // Check the time[0] against the previous session end if (time > cacheSessionEnd) { if (Bars.BarsType.IsIntraday) { // Make use of the stored session iterator to find the next session... storedSession.GetNextSession(time, true); // Store the actual session's end datetime as the session cacheSessionEnd = storedSession.ActualSessionEnd; // We need to convert that time from the session to the users time zone settings sessionDateTmp = TimeZoneInfo.ConvertTime(cacheSessionEnd.AddSeconds(-1), Globals.GeneralOptions.TimeZoneInfo, Bars.TradingHours.TimeZoneInfo).Date; } else { sessionDateTmp = time.Date; } } if (pivotRange == PivotRange.Daily) { if (sessionDateTmp != cacheSessionDate) { if (newSessionBarIdxArr.Count == 0 || newSessionBarIdxArr.Count > 0 && CurrentBar > newSessionBarIdxArr[newSessionBarIdxArr.Count - 1]) { newSessionBarIdxArr.Add(CurrentBar); } cacheSessionDate = sessionDateTmp; } return(sessionDateTmp); } DateTime tmpWeeklyEndDate = RoundUpTimeToPeriodTime(sessionDateTmp, PivotRange.Weekly); if (pivotRange == PivotRange.Weekly) { if (tmpWeeklyEndDate != cacheWeeklyEndDate) { if (newSessionBarIdxArr.Count == 0 || newSessionBarIdxArr.Count > 0 && CurrentBar > newSessionBarIdxArr[newSessionBarIdxArr.Count - 1]) { newSessionBarIdxArr.Add(CurrentBar); } cacheWeeklyEndDate = tmpWeeklyEndDate; } return(tmpWeeklyEndDate); } DateTime tmpMonthlyEndDate = RoundUpTimeToPeriodTime(sessionDateTmp, PivotRange.Monthly); if (tmpMonthlyEndDate != cacheMonthlyEndDate) { if (newSessionBarIdxArr.Count == 0 || newSessionBarIdxArr.Count > 0 && CurrentBar > newSessionBarIdxArr[newSessionBarIdxArr.Count - 1]) { newSessionBarIdxArr.Add(CurrentBar); } cacheMonthlyEndDate = tmpMonthlyEndDate; } return(tmpMonthlyEndDate); }
private DateTime TimeToBarTime(Bars bars, DateTime time, bool isBar) { if (SessionIterator.IsNewSession(time, isBar)) { SessionIterator.GetNextSession(time, isBar); } if (bars.IsResetOnNewTradingDay || !bars.IsResetOnNewTradingDay && bars.Count == 0) { DateTime barTimeStamp = isBar ? SessionIterator.ActualSessionBegin.AddSeconds(Math.Ceiling(Math.Ceiling(Math.Max(0, time.Subtract(SessionIterator.ActualSessionBegin).TotalSeconds)) / bars.BarsPeriod.Value) * bars.BarsPeriod.Value) : SessionIterator.ActualSessionBegin.AddSeconds(bars.BarsPeriod.Value + Math.Floor(Math.Floor(Math.Max(0, time.Subtract(SessionIterator.ActualSessionBegin).TotalSeconds)) / bars.BarsPeriod.Value) * bars.BarsPeriod.Value); if (bars.TradingHours.Sessions.Count > 0 && barTimeStamp > SessionIterator.ActualSessionEnd) // Cut last bar in session down to session end on odd session end time { barTimeStamp = SessionIterator.ActualSessionEnd; } return(barTimeStamp); } else { DateTime lastBarTime = bars.GetTime(bars.Count - 1); DateTime barTimeStamp = isBar ? lastBarTime.AddSeconds(Math.Ceiling(Math.Ceiling(Math.Max(0, time.Subtract(lastBarTime).TotalSeconds)) / bars.BarsPeriod.Value) * bars.BarsPeriod.Value) : lastBarTime.AddSeconds(bars.BarsPeriod.Value + Math.Floor(Math.Floor(Math.Max(0, time.Subtract(lastBarTime).TotalSeconds)) / bars.BarsPeriod.Value) * bars.BarsPeriod.Value); if (bars.TradingHours.Sessions.Count > 0 && barTimeStamp > SessionIterator.ActualSessionEnd) { DateTime saveActualSessionEnd = SessionIterator.ActualSessionEnd; SessionIterator.GetNextSession(SessionIterator.ActualSessionEnd.AddSeconds(1), isBar); barTimeStamp = SessionIterator.ActualSessionBegin.AddSeconds((int)barTimeStamp.Subtract(saveActualSessionEnd).TotalSeconds); } return(barTimeStamp); } }
public void RecalculateSession(DateTime time) { if (sessionIterator == null) { if (BarsArray != null) { sessionIterator = new SessionIterator(BarsArray[1]); } } sessionIterator.GetNextSession(time, false); }
protected override void OnDataPoint(Bars bars, double open, double high, double low, double close, DateTime time, long volume, bool isBar, double bid, double ask) { if (SessionIterator == null) { SessionIterator = new SessionIterator(bars); } bool isNewSession = SessionIterator.IsNewSession(time, isBar); if (isNewSession) { SessionIterator.GetNextSession(time, isBar); } long barsPeriodValue = bars.BarsPeriod.Value; if (bars.Instrument.MasterInstrument.InstrumentType == InstrumentType.CryptoCurrency) { barsPeriodValue = Core.Globals.FromCryptocurrencyVolume(bars.BarsPeriod.Value); } if (bars.Count == 0) { while (volume > barsPeriodValue) { AddBar(bars, open, high, low, close, time, barsPeriodValue); volume -= barsPeriodValue; } if (volume > 0) { AddBar(bars, open, high, low, close, time, volume); } } else { long volumeTmp = 0; if (!bars.IsResetOnNewTradingDay || !isNewSession) { volumeTmp = Math.Min(barsPeriodValue - bars.GetVolume(bars.Count - 1), volume); if (volumeTmp > 0) { UpdateBar(bars, high, low, close, time, volumeTmp); } } volumeTmp = volume - volumeTmp; while (volumeTmp > 0) { AddBar(bars, open, high, low, close, time, Math.Min(volumeTmp, barsPeriodValue)); volumeTmp -= barsPeriodValue; } } }
protected override void OnMarketData(MarketDataEventArgs marketDataUpdate) { // Workaround for market replay backfilling all of replay sessions data(as historical data) // Replay should only backfill history up to replay time, so make sure any historical ticks // are before the current replay time. if ((Connection.PlaybackConnection != null) && (State == State.Historical) && (marketDataUpdate.Time >= Connection.PlaybackConnection.Now)) { if (PrintDebug) { Print("Filter Hit - MarketDataEvent Time :" + marketDataUpdate.Time.ToString() + " Playback Time: " + Connection.PlaybackConnection.Now.ToString() + " Event Type: " + marketDataUpdate.MarketDataType + " State: " + State); } return; } // Reset for every session if (sessionIterator.IsNewSession(marketDataUpdate.Time, false)) { if (PrintDebug) { Print("NewSession: " + marketDataUpdate.Time.ToString()); } totalShares = 0; totalDollars = 0; sessionIterator.GetNextSession(marketDataUpdate.Time, false); } // Check session time if (!sessionIterator.IsInSession(marketDataUpdate.Time, false, true)) { return; } // Is this a trade(not bid or ask) if (marketDataUpdate.MarketDataType == MarketDataType.Last) { totalShares += marketDataUpdate.Volume; totalDollars += marketDataUpdate.Volume * marketDataUpdate.Price; Vwap[0] = totalDollars / totalShares; if (PrintDebug) { Print(marketDataUpdate.Time.ToString() + " Session total shares: " + totalShares.ToString() + " " + State); } } }
private DateTime TimeToBarTimeSecond(Bars bars, DateTime time, bool isBar) { if (SessionIterator.IsNewSession(time, isBar)) { SessionIterator.GetNextSession(time, isBar); } DateTime barTimeStamp = SessionIterator.ActualSessionBegin.AddSeconds(Math.Ceiling(Math.Ceiling(Math.Max(0, time.Subtract(SessionIterator.ActualSessionBegin).TotalSeconds)) / bars.BarsPeriod.BaseBarsPeriodValue) * bars.BarsPeriod.BaseBarsPeriodValue); if (bars.TradingHours.Sessions.Count > 0 && barTimeStamp > SessionIterator.ActualSessionEnd) { barTimeStamp = SessionIterator.ActualSessionEnd <= Core.Globals.MinDate ? barTimeStamp : SessionIterator.ActualSessionEnd; } return(barTimeStamp); }
private DateTime GetLastBarSessionDate(DateTime time) { if (time <= cacheSessionEnd) { return(sessionDateTmp); } if (!Bars.BarsType.IsIntraday) { return(sessionDateTmp); } storedSession.GetNextSession(time, true); cacheSessionEnd = storedSession.ActualSessionEnd; sessionDateTmp = TimeZoneInfo.ConvertTime(cacheSessionEnd.AddSeconds(-1), Globals.GeneralOptions.TimeZoneInfo, Bars.TradingHours.TimeZoneInfo).Date; if (newSessionBarIdx.Count == 0 || newSessionBarIdx.Count > 0 && CurrentBar > newSessionBarIdx[newSessionBarIdx.Count - 1]) { newSessionBarIdx.Add(CurrentBar); } return(sessionDateTmp); }
protected override void OnDataPoint(Bars bars, double open, double high, double low, double close, DateTime time, long volume, bool isBar, double bid, double ask) { if (SessionIterator == null) { SessionIterator = new SessionIterator(bars); } bool isNewSession = SessionIterator.IsNewSession(time, isBar); if (isNewSession) { SessionIterator.GetNextSession(time, isBar); } if (bars.Count == 0 || bars.IsResetOnNewTradingDay && isNewSession) { AddBar(bars, open, high, low, close, time, volume); } else { double barClose = bars.GetClose(bars.Count - 1); double barHigh = bars.GetHigh(bars.Count - 1); double barLow = bars.GetLow(bars.Count - 1); double tickSize = bars.Instrument.MasterInstrument.TickSize; double rangeValue = Math.Floor(10000000.0 * bars.BarsPeriod.Value * tickSize) / 10000000.0; if (close.ApproxCompare(barLow + rangeValue) > 0) { double newClose = barLow + rangeValue; // Every bar closes either with high or low if (newClose.ApproxCompare(barClose) > 0) { UpdateBar(bars, newClose, barLow, newClose, time, 0); } // If there's still a gap, fill with phantom bars double newBarOpen = newClose + tickSize; while (close.ApproxCompare(newClose) > 0) { newClose = Math.Min(close, newBarOpen + rangeValue); AddBar(bars, newBarOpen, newClose, newBarOpen, newClose, time, close.ApproxCompare(newClose) > 0 ? 0 : volume); newBarOpen = newClose + tickSize; } } else if ((barHigh - rangeValue).ApproxCompare(close) > 0) { double newClose = barHigh - rangeValue; // Every bar closes either with high or low if (barClose.ApproxCompare(newClose) > 0) { UpdateBar(bars, barHigh, newClose, newClose, time, 0); } // if there's still a gap, fill with phantom bars double newBarOpen = newClose - tickSize; while (newClose.ApproxCompare(close) > 0) { newClose = Math.Max(close, newBarOpen - rangeValue); AddBar(bars, newBarOpen, newBarOpen, newClose, newClose, time, newClose.ApproxCompare(close) > 0 ? 0 : volume); newBarOpen = newClose - tickSize; } } else { UpdateBar(bars, close > barHigh ? close : barHigh, close < barLow ? close : barLow, close, time, volume); } } bars.LastPrice = close; }
protected override void OnBarUpdate() { if (CurrentBars[0] < BarsRequiredToTrade || CurrentBars[1] < BarsRequiredToTrade) { return; } if (BarsInProgress == 0) { sessionIterator.GetNextSession(Time[0], true); } // if after the exit on close, prevent new orders until the new session if (Times[1][0] >= sessionIterator.ActualSessionEnd.AddSeconds(-ExitOnSessionCloseSeconds) && Times[1][0] <= sessionIterator.ActualSessionEnd) { exitOnCloseWait = true; } // an exit on close occurred in the previous session, reset for a new entry on the first bar of a new session if (exitOnCloseWait && Bars.IsFirstBarOfSession) { entryOrder = null; profitTarget = null; stopLoss = null; exitFlat = null; exitSession = null; exitOnCloseWait = false; } // the entry logic can be done when the primary series is processing if (BarsInProgress == 0) { // Reset the trade profitability counter every day and get the number of trades taken in total. if (Bars.IsFirstBarOfSession && IsFirstTickOfBar) { InitializeTradeAccounting(); } // because this is a demonstration, this code will cause any historical position // to be exited on the last historical bar so the strategy will always start flat in real-time if (State == State.Historical && CurrentBar == BarsArray[0].Count - 2) { if (entryOrder != null) { ExitToStartFlat(); } } // if this is not the last historical bar, and entryOrder is null, then place an entry order //else if (!exitOnCloseWait && entryOrder == null && profitTarget == null && stopLoss == null) else if (!exitOnCloseWait) { suppressOco = false; entryOrder = placeHolderOrder; ReversalTrade(); AfterLunchBollingerTrade(); PullbackTrade(); } } // all code below this point takes places during BarsInProgress 1 when the tick series is processing if (BarsInProgress != 1) { return; } if (ordersCancelled) { message = string.Format("{0} | OBU | stop and/or target cancelled or rejected", Times[1][0]); // if the orders were cancelled due to the exit on close, do not submit an order to flatten if (!exitOnCloseWait && entryOrder != null && entryOrder.OrderState == OrderState.Filled) { ExitForCancel(); } if (entryOrder == null || entryOrder.OrderState != OrderState.Filled) { Print(string.Format("{0} | OBU | entry not filled or is null", Times[1][0])); } ordersCancelled = false; return; } // trailing logic // the profitTarget/stopLoss is first created when the entry order fills. If it exists then move it. // trigger the chase action when the current price is further than the set distance to the profit target if (ChaseProfitTarget && profitTarget != null && (profitTarget.OrderState == OrderState.Accepted || profitTarget.OrderState == OrderState.Working) && Close[0] < currentPtPrice - ProfitTargetDistance * tickSizeSecondary) { // setting chase profit target if (isLongTrade) { currentPtPrice = Close[0] + ProfitTargetDistance * tickSizeSecondary; ExitLongLimit(1, true, entryOrder.Quantity, currentPtPrice, "profit target", entryOrder.Name); } else { currentPtPrice = Close[0] - ProfitTargetDistance * tickSizeSecondary; ExitLongLimit(1, true, entryOrder.Quantity, currentPtPrice, "profit target", entryOrder.Name); } } // trigger the trail action when the current price is further than the set distance to the stop loss if (TrailStopLoss && stopLoss != null && (stopLoss.OrderState == OrderState.Accepted || stopLoss.OrderState == OrderState.Working) && Close[0] > currentSlPrice + StopLossDistance * tickSizeSecondary) { // setting trailing stop loss if (isLongTrade) { currentSlPrice = Close[0] - StopLossDistance * tickSizeSecondary; ExitLongStopMarket(1, true, entryOrder.Quantity, currentSlPrice, "stop loss", entryOrder.Name); } else { currentSlPrice = Close[0] + StopLossDistance * tickSizeSecondary; ExitLongStopMarket(1, true, entryOrder.Quantity, currentSlPrice, "stop loss", entryOrder.Name); } } }
protected override void OnBarUpdate() { if (CurrentBars[0] < BarsRequiredToTrade || CurrentBars[1] < BarsRequiredToTrade) { return; } if (BarsInProgress == 0) { if (CurrentBar == 0 || Bars.IsFirstBarOfSession) { sessionIterator.GetNextSession(Time[0], true); } // if after the exit on close time, prevent new orders until the new session if (Times[1][0] >= sessionIterator.ActualSessionEnd.AddSeconds(-ExitOnSessionCloseSeconds) && Times[1][0] <= sessionIterator.ActualSessionEnd) { exitOnCloseWait = true; } // reset for a new entry on the first bar of a new session else if (exitOnCloseWait && Bars.IsFirstBarOfSession) { exitOnCloseWait = false; } if (State == State.Historical && CurrentBar == BarsArray[0].Count - 2 && Position.MarketPosition == MarketPosition.Long) { ExitLong(1, 1, "exit to start flat", string.Empty); } else if (!exitOnCloseWait && Position.MarketPosition == MarketPosition.Flat) { // Reset the stop loss to the original distance when all positions are closed before placing a new entry currentPtPrice = Close[0] + ProfitTargetDistance * TickSize; currentSlPrice = Close[0] - StopLossDistance * TickSize; if (UseProfitTarget) { SetProfitTarget(CalculationMode.Price, currentPtPrice); } if (UseStopLoss) { SetStopLoss(CalculationMode.Price, currentSlPrice); } Print(string.Format("ProfitChaseStopTrailSetMethodsExample:: tradeCount {0}", tradeCount++)); EnterLong(1, 1, string.Empty); } } if (BarsInProgress == 1 && Position.MarketPosition == MarketPosition.Long) { if (UseProfitTarget && ChaseProfitTarget && Close[0] < currentPtPrice - ProfitTargetDistance * TickSize) { currentPtPrice = Close[0] + ProfitTargetDistance * TickSize; SetProfitTarget(CalculationMode.Price, currentPtPrice); } if (UseStopLoss && TrailStopLoss && Close[0] > currentSlPrice + StopLossDistance * TickSize) { currentSlPrice = Close[0] - StopLossDistance * TickSize; SetStopLoss(CalculationMode.Price, currentSlPrice); } } }
protected override void OnBarUpdate() { //Print(Times[BarsInProgress][0]+" "+BarsInProgress); if (isStartOfNewSessionRTH()) { //Print("RTH "+Times[RTH][0]); //Print(Times[BarsInProgress][0]+" "+BarsInProgress); //Print(Times[ETH][0]+" session: "+ethSessionIterator.ActualSessionBegin+" "+CurrentBars[ETH]); rthSessionIterator.GetNextSession(Times[RTH][0], false); if (tpoProfile != null) { update(tpoProfile); tpoProfiles.Add(tpoProfile); } tpoProfile = new JBTPOProfile(RTH, rthSessionIterator.ActualSessionBegin); } else if (isStartOfNewSessionETH()) { //Print("ETH "+Times[ETH][0]); //Print(Times[BarsInProgress][0]+" "+BarsInProgress); //Print(Times[ETH][0]+" session: "+ethSessionIterator.ActualSessionBegin+" "+CurrentBars[ETH]); ethSessionIterator.GetNextSession(Times[ETH][0], false); if (tpoProfile != null) { update(tpoProfile); tpoProfiles.Add(tpoProfile); } tpoProfile = new JBTPOProfile(ETH, ethSessionIterator.ActualSessionBegin); } if (BarsInProgress == RTH && CurrentBars[RTH] != activeBarRTH) { if (tpoProfile != null) { if (State == State.Realtime) { update(tpoProfile); } tpoId = (Times[RTH][0] - tpoProfile.sessionStart).TotalSeconds; } activeBarRTH = CurrentBars[RTH]; //Print("RTH TPO ID "+Times[RTH][0]+" "+rthTPOId); } else if (BarsInProgress == ETH && CurrentBars[ETH] != activeBarETH) { if (tpoProfile != null) { if (State == State.Realtime) { update(tpoProfile); } tpoId = (Times[ETH][0] - tpoProfile.sessionStart).TotalSeconds; } activeBarETH = CurrentBars[ETH]; //Print("ETH TPO ID "+Times[ETH][0]+" "+rthTPOId); } if (tpoProfile != null) { tpoProfile.add(Closes[BarsInProgress][0], tpoId); } }
protected override void OnDataPoint(Bars bars, double open, double high, double low, double close, DateTime time, long volume, bool isBar, double bid, double ask) { if (SessionIterator == null) { SessionIterator = new SessionIterator(bars); } offset = bars.BarsPeriod.Value * bars.Instrument.MasterInstrument.TickSize; bool isNewSession = SessionIterator.IsNewSession(time, isBar); if (isNewSession) { SessionIterator.GetNextSession(time, isBar); } if (bars.Count == 0 || bars.IsResetOnNewTradingDay && isNewSession) { if (bars.Count > 0) { // Close out last bar in session and set open == close double lastBarClose = bars.GetClose(bars.Count - 1); DateTime lastBarTime = bars.GetTime(bars.Count - 1); long lastBarVolume = bars.GetVolume(bars.Count - 1); RemoveLastBar(bars); AddBar(bars, lastBarClose, lastBarClose, lastBarClose, lastBarClose, lastBarTime, lastBarVolume); } renkoHigh = close + offset; renkoLow = close - offset; isNewSession = SessionIterator.IsNewSession(time, isBar); if (isNewSession) { SessionIterator.GetNextSession(time, isBar); } AddBar(bars, close, close, close, close, time, volume); bars.LastPrice = close; return; } double barOpen = bars.GetOpen(bars.Count - 1); double barHigh = bars.GetHigh(bars.Count - 1); double barLow = bars.GetLow(bars.Count - 1); long barVolume = bars.GetVolume(bars.Count - 1); DateTime barTime = bars.GetTime(bars.Count - 1); if (renkoHigh.ApproxCompare(0.0) == 0 || renkoLow.ApproxCompare(0.0) == 0) { if (bars.Count == 1) { renkoHigh = barOpen + offset; renkoLow = barOpen - 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 (close.ApproxCompare(renkoHigh) >= 0) { if (barOpen.ApproxCompare(renkoHigh - offset) != 0 || barHigh.ApproxCompare(Math.Max(renkoHigh - offset, renkoHigh)) != 0 || barLow.ApproxCompare(Math.Min(renkoHigh - offset, renkoHigh)) != 0) { RemoveLastBar(bars); AddBar(bars, renkoHigh - offset, Math.Max(renkoHigh - offset, renkoHigh), Math.Min(renkoHigh - offset, renkoHigh), renkoHigh, barTime, barVolume); } renkoLow = renkoHigh - 2.0 * offset; renkoHigh = renkoHigh + offset; isNewSession = SessionIterator.IsNewSession(time, isBar); if (isNewSession) { SessionIterator.GetNextSession(time, isBar); } while (close.ApproxCompare(renkoHigh) >= 0) // Add empty bars to fill gap if price jumps { AddBar(bars, renkoHigh - offset, Math.Max(renkoHigh - offset, renkoHigh), Math.Min(renkoHigh - offset, renkoHigh), renkoHigh, time, 0); 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, volume); } else if (close.ApproxCompare(renkoLow) <= 0) { if (barOpen.ApproxCompare(renkoLow + offset) != 0 || barHigh.ApproxCompare(Math.Max(renkoLow + offset, renkoLow)) != 0 || barLow.ApproxCompare(Math.Min(renkoLow + offset, renkoLow)) != 0) { RemoveLastBar(bars); AddBar(bars, renkoLow + offset, Math.Max(renkoLow + offset, renkoLow), Math.Min(renkoLow + offset, renkoLow), renkoLow, barTime, barVolume); } renkoHigh = renkoLow + 2.0 * offset; renkoLow = renkoLow - offset; isNewSession = SessionIterator.IsNewSession(time, isBar); if (isNewSession) { SessionIterator.GetNextSession(time, isBar); } while (close.ApproxCompare(renkoLow) <= 0) // Add empty bars to fill gap if price jumps { AddBar(bars, renkoLow + offset, Math.Max(renkoLow + offset, renkoLow), Math.Min(renkoLow + offset, renkoLow), renkoLow, time, 0); 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, volume); } else { UpdateBar(bars, close, close, close, time, volume); } bars.LastPrice = close; }
protected override void OnDataPoint(Bars bars, double open, double high, double low, double close, DateTime time, long volume, bool isBar, double bid, double ask) { if (SessionIterator == null) { SessionIterator = new SessionIterator(bars); } double haClose = 0.0; double haHigh = 0.0; double haLow = 0.0; double haOpen = 0.0; switch (BarsPeriod.BaseBarsPeriodType) { case BarsPeriodType.Day: { if (bars.Count == 0) { if (isBar || bars.TradingHours.Sessions.Count == 0) { AddBar(bars, open, high, low, close, time.Date, volume); } else { SessionIterator.CalculateTradingDay(time, false); AddBar(bars, open, high, low, close, SessionIterator.ActualTradingDayExchange, volume); } } else { DateTime barTime; if (isBar) { barTime = time.Date; } else { if (bars.TradingHours.Sessions.Count > 0 && SessionIterator.IsNewSession(time, false)) { SessionIterator.CalculateTradingDay(time, false); barTime = SessionIterator.ActualTradingDayExchange; if (barTime < bars.LastBarTime.Date) { barTime = bars.LastBarTime.Date; // Make sure timestamps are ascending } } else { barTime = bars.LastBarTime.Date; // Make sure timestamps are ascending } } if (bars.DayCount < bars.BarsPeriod.BaseBarsPeriodValue || isBar && bars.Count > 0 && barTime == bars.LastBarTime.Date || !isBar && bars.Count > 0 && barTime <= bars.LastBarTime.Date) { haClose = bars.Instrument.MasterInstrument.RoundToTickSize((open + high + low + close) / 4.0); haHigh = bars.Instrument.MasterInstrument.RoundToTickSize(Math.Max(high, bars.GetOpen(bars.Count - 1))); haLow = bars.Instrument.MasterInstrument.RoundToTickSize(Math.Min(low, bars.GetOpen(bars.Count - 1))); UpdateBar(bars, haHigh, haLow, haClose, barTime, volume); } else { haOpen = bars.Instrument.MasterInstrument.RoundToTickSize((bars.GetOpen(bars.Count - 1) + bars.GetClose(bars.Count - 1)) / 2.0); haClose = bars.Instrument.MasterInstrument.RoundToTickSize((open + high + low + close) / 4.0); haHigh = bars.Instrument.MasterInstrument.RoundToTickSize(Math.Max(high, haOpen)); haLow = bars.Instrument.MasterInstrument.RoundToTickSize(Math.Min(low, haOpen)); AddBar(bars, haOpen, haHigh, haLow, haClose, barTime, volume); } } break; } case BarsPeriodType.Minute: { if (bars.Count == 0) { AddBar(bars, open, high, low, close, TimeToBarTimeMinute(bars, time, isBar), volume); } else if (!isBar && time < bars.LastBarTime) { haClose = bars.Instrument.MasterInstrument.RoundToTickSize((open + high + low + close) / 4.0); haHigh = bars.Instrument.MasterInstrument.RoundToTickSize(Math.Max(high, bars.GetOpen(bars.Count - 1))); haLow = bars.Instrument.MasterInstrument.RoundToTickSize(Math.Min(low, bars.GetOpen(bars.Count - 1))); UpdateBar(bars, haHigh, haLow, haClose, bars.LastBarTime, volume); } else if (isBar && time <= bars.LastBarTime) { haClose = bars.Instrument.MasterInstrument.RoundToTickSize((open + high + low + close) / 4.0); haHigh = bars.Instrument.MasterInstrument.RoundToTickSize(Math.Max(high, bars.GetOpen(bars.Count - 1))); haLow = bars.Instrument.MasterInstrument.RoundToTickSize(Math.Min(low, bars.GetOpen(bars.Count - 1))); UpdateBar(bars, haHigh, haLow, haClose, bars.LastBarTime, volume); } else { haOpen = bars.Instrument.MasterInstrument.RoundToTickSize((bars.GetOpen(bars.Count - 1) + bars.GetClose(bars.Count - 1)) / 2.0); haClose = bars.Instrument.MasterInstrument.RoundToTickSize((open + high + low + close) / 4.0); haHigh = bars.Instrument.MasterInstrument.RoundToTickSize(Math.Max(high, haOpen)); haLow = bars.Instrument.MasterInstrument.RoundToTickSize(Math.Min(low, haOpen)); time = TimeToBarTimeMinute(bars, time, isBar); AddBar(bars, haOpen, haHigh, haLow, haClose, time, volume); } break; } case BarsPeriodType.Month: { if (bars.Count == 0) { AddBar(bars, open, high, low, close, TimeToBarTimeMonth(time, bars.BarsPeriod.BaseBarsPeriodValue), volume); } else if (time.Month <= bars.LastBarTime.Month && time.Year == bars.LastBarTime.Year || time.Year < bars.LastBarTime.Year) { if (high.ApproxCompare(bars.GetHigh(bars.Count - 1)) != 0 || low.ApproxCompare(bars.GetLow(bars.Count - 1)) != 0 || close.ApproxCompare(bars.GetClose(bars.Count - 1)) != 0 || volume > 0) { haClose = bars.Instrument.MasterInstrument.RoundToTickSize((open + high + low + close) / 4.0); haHigh = bars.Instrument.MasterInstrument.RoundToTickSize(Math.Max(high, bars.GetOpen(bars.Count - 1))); haLow = bars.Instrument.MasterInstrument.RoundToTickSize(Math.Min(low, bars.GetOpen(bars.Count - 1))); UpdateBar(bars, haHigh, haLow, haClose, bars.LastBarTime, volume); } } else { haOpen = bars.Instrument.MasterInstrument.RoundToTickSize((bars.GetOpen(bars.Count - 1) + bars.GetClose(bars.Count - 1)) / 2.0); haClose = bars.Instrument.MasterInstrument.RoundToTickSize((open + high + low + close) / 4.0); haHigh = bars.Instrument.MasterInstrument.RoundToTickSize(Math.Max(high, haOpen)); haLow = bars.Instrument.MasterInstrument.RoundToTickSize(Math.Min(low, haOpen)); AddBar(bars, haOpen, haHigh, haLow, haClose, TimeToBarTimeMonth(time, bars.BarsPeriod.BaseBarsPeriodValue), volume); } break; } case BarsPeriodType.Second: { if (bars.Count == 0) { DateTime barTime = TimeToBarTimeSecond(bars, time, isBar); AddBar(bars, open, high, low, close, barTime, volume); } else { if (bars.BarsPeriod.BaseBarsPeriodValue > 1 && time < bars.LastBarTime || bars.BarsPeriod.BaseBarsPeriodValue == 1 && time <= bars.LastBarTime) { haClose = bars.Instrument.MasterInstrument.RoundToTickSize((open + high + low + close) / 4.0); haHigh = bars.Instrument.MasterInstrument.RoundToTickSize(Math.Max(high, bars.GetOpen(bars.Count - 1))); haLow = bars.Instrument.MasterInstrument.RoundToTickSize(Math.Min(low, bars.GetOpen(bars.Count - 1))); UpdateBar(bars, haHigh, haLow, haClose, bars.LastBarTime, volume); } else { haOpen = bars.Instrument.MasterInstrument.RoundToTickSize((bars.GetOpen(bars.Count - 1) + bars.GetClose(bars.Count - 1)) / 2.0); haClose = bars.Instrument.MasterInstrument.RoundToTickSize((open + high + low + close) / 4.0); haHigh = bars.Instrument.MasterInstrument.RoundToTickSize(Math.Max(high, haOpen)); haLow = bars.Instrument.MasterInstrument.RoundToTickSize(Math.Min(low, haOpen)); time = TimeToBarTimeSecond(bars, time, isBar); AddBar(bars, haOpen, haHigh, haLow, haClose, time, volume); } } break; } case BarsPeriodType.Tick: { bool isNewSession = SessionIterator.IsNewSession(time, isBar); if (isNewSession) { SessionIterator.GetNextSession(time, isBar); } if (bars.BarsPeriod.BaseBarsPeriodValue == 1) { haOpen = haOpen.ApproxCompare(0.0) == 0 ? open : (haOpen + haClose) / 2.0; haClose = haClose.ApproxCompare(0.0) == 0 ? close : bars.Instrument.MasterInstrument.RoundToTickSize((open + high + low + close) / 4.0); haHigh = bars.Instrument.MasterInstrument.RoundToTickSize(Math.Max(high, haOpen)); haLow = bars.Instrument.MasterInstrument.RoundToTickSize(Math.Min(low, haOpen)); AddBar(bars, haOpen, haHigh, haLow, haClose, time, volume); } else if (bars.Count == 0) { AddBar(bars, open, high, low, close, time, volume); } else if (bars.Count > 0 && (!isNewSession || !bars.IsResetOnNewTradingDay) && bars.BarsPeriod.BaseBarsPeriodValue > 1 && bars.TickCount < bars.BarsPeriod.BaseBarsPeriodValue) { haClose = bars.Instrument.MasterInstrument.RoundToTickSize((open + high + low + close) / 4.0); haHigh = bars.Instrument.MasterInstrument.RoundToTickSize(Math.Max(high, bars.GetOpen(bars.Count - 1))); haLow = bars.Instrument.MasterInstrument.RoundToTickSize(Math.Min(low, bars.GetOpen(bars.Count - 1))); UpdateBar(bars, haHigh, haLow, haClose, time, volume); } else { haOpen = bars.Instrument.MasterInstrument.RoundToTickSize((bars.GetOpen(bars.Count - 1) + bars.GetClose(bars.Count - 1)) / 2.0); haClose = bars.Instrument.MasterInstrument.RoundToTickSize((open + high + low + close) / 4.0); haHigh = bars.Instrument.MasterInstrument.RoundToTickSize(Math.Max(high, haOpen)); haLow = bars.Instrument.MasterInstrument.RoundToTickSize(Math.Min(low, haOpen)); AddBar(bars, haOpen, haHigh, haLow, haClose, time, volume); } break; } case BarsPeriodType.Volume: { if (bars.Count == 0) { while (volume > bars.BarsPeriod.BaseBarsPeriodValue) { haOpen = haOpen.ApproxCompare(0.0) == 0 ? open : (haOpen + haClose) / 2.0; haClose = haClose.ApproxCompare(0) == 0 ? close : bars.Instrument.MasterInstrument.RoundToTickSize((open + high + low + close) / 4.0); haHigh = bars.Instrument.MasterInstrument.RoundToTickSize(Math.Max(high, haOpen)); haLow = bars.Instrument.MasterInstrument.RoundToTickSize(Math.Min(low, haOpen)); AddBar(bars, haOpen, haHigh, haLow, haClose, time, bars.BarsPeriod.BaseBarsPeriodValue); volume -= bars.BarsPeriod.BaseBarsPeriodValue; } if (volume > 0) { haOpen = haOpen.ApproxCompare(0.0) == 0 ? open : bars.Instrument.MasterInstrument.RoundToTickSize((haOpen + haClose) / 2.0); haClose = haClose.ApproxCompare(0.0) == 0 ? close : bars.Instrument.MasterInstrument.RoundToTickSize((open + high + low + close) / 4.0); haHigh = bars.Instrument.MasterInstrument.RoundToTickSize(Math.Max(high, haOpen)); haLow = bars.Instrument.MasterInstrument.RoundToTickSize(Math.Min(low, haOpen)); AddBar(bars, haOpen, haHigh, haLow, haClose, time, volume); } } else { long volumeTmp = 0; bool isNewSession = SessionIterator.IsNewSession(time, isBar); if (!bars.IsResetOnNewTradingDay || !isNewSession) { volumeTmp = Math.Min(bars.BarsPeriod.BaseBarsPeriodValue - bars.GetVolume(bars.Count - 1), volume); if (volumeTmp > 0) { haClose = bars.Instrument.MasterInstrument.RoundToTickSize((open + high + low + close) / 4.0); haHigh = bars.Instrument.MasterInstrument.RoundToTickSize(Math.Max(high, bars.GetOpen(bars.Count - 1))); haLow = bars.Instrument.MasterInstrument.RoundToTickSize(Math.Min(low, bars.GetOpen(bars.Count - 1))); UpdateBar(bars, haHigh, haLow, haClose, time, volumeTmp); } } if (isNewSession) { SessionIterator.GetNextSession(time, isBar); } volumeTmp = volume - volumeTmp; while (volumeTmp > 0) { haOpen = bars.Instrument.MasterInstrument.RoundToTickSize((bars.GetOpen(bars.Count - 1) + bars.GetClose(bars.Count - 1)) / 2.0); haClose = bars.Instrument.MasterInstrument.RoundToTickSize((open + high + low + close) / 4.0); haHigh = bars.Instrument.MasterInstrument.RoundToTickSize(Math.Max(high, haOpen)); haLow = bars.Instrument.MasterInstrument.RoundToTickSize(Math.Min(low, haOpen)); AddBar(bars, haOpen, haHigh, haLow, haClose, time, Math.Min(volumeTmp, bars.BarsPeriod.BaseBarsPeriodValue)); volumeTmp -= bars.BarsPeriod.BaseBarsPeriodValue; } } break; } case BarsPeriodType.Week: { if (bars.Count == 0) { AddBar(bars, open, high, low, close, TimeToBarTimeWeek(time, time.AddDays(6 - ((int)time.DayOfWeek + 1) % 7 + (bars.BarsPeriod.BaseBarsPeriodValue - 1) * 7), bars.BarsPeriod.BaseBarsPeriodValue), volume); } else if (time.Date <= bars.LastBarTime.Date) { haClose = bars.Instrument.MasterInstrument.RoundToTickSize((open + high + low + close) / 4.0); haHigh = bars.Instrument.MasterInstrument.RoundToTickSize(Math.Max(high, bars.GetOpen(bars.Count - 1))); haLow = bars.Instrument.MasterInstrument.RoundToTickSize(Math.Min(low, bars.GetOpen(bars.Count - 1))); UpdateBar(bars, haHigh, haLow, haClose, bars.LastBarTime, volume); } else { haOpen = bars.Instrument.MasterInstrument.RoundToTickSize((bars.GetOpen(bars.Count - 1) + bars.GetClose(bars.Count - 1)) / 2.0); haClose = bars.Instrument.MasterInstrument.RoundToTickSize((open + high + low + close) / 4.0); haHigh = bars.Instrument.MasterInstrument.RoundToTickSize(Math.Max(high, haOpen)); haLow = bars.Instrument.MasterInstrument.RoundToTickSize(Math.Min(low, haOpen)); AddBar(bars, haOpen, haHigh, haLow, haClose, TimeToBarTimeWeek(time.Date, bars.LastBarTime.Date, bars.BarsPeriod.BaseBarsPeriodValue), volume); } break; } case BarsPeriodType.Year: { if (bars.Count == 0) { AddBar(bars, open, high, low, close, TimeToBarTimeYear(time, bars.BarsPeriod.BaseBarsPeriodValue), volume); } else { if (time.Year <= bars.LastBarTime.Year) { haClose = bars.Instrument.MasterInstrument.RoundToTickSize((open + high + low + close) / 4.0); haHigh = bars.Instrument.MasterInstrument.RoundToTickSize(Math.Max(high, bars.GetOpen(bars.Count - 1))); haLow = bars.Instrument.MasterInstrument.RoundToTickSize(Math.Min(low, bars.GetOpen(bars.Count - 1))); UpdateBar(bars, haHigh, haLow, haClose, bars.LastBarTime, volume); } else { haOpen = bars.Instrument.MasterInstrument.RoundToTickSize((bars.GetOpen(bars.Count - 1) + bars.GetClose(bars.Count - 1)) / 2.0); haClose = bars.Instrument.MasterInstrument.RoundToTickSize((open + high + low + close) / 4.0); haHigh = bars.Instrument.MasterInstrument.RoundToTickSize(Math.Max(high, haOpen)); haLow = bars.Instrument.MasterInstrument.RoundToTickSize(Math.Min(low, haOpen)); AddBar(bars, haOpen, haHigh, haLow, haClose, TimeToBarTimeYear(time.Date, bars.BarsPeriod.BaseBarsPeriodValue), volume); } } break; } } bars.LastPrice = haClose; }
protected override void OnDataPoint(Bars bars, double open, double high, double low, double close, DateTime time, long volume, bool isBar, double bid, double ask) { if (SessionIterator == null) { SessionIterator = new SessionIterator(bars); } bool isNewSession = SessionIterator.IsNewSession(time, isBar); if (isNewSession) { SessionIterator.GetNextSession(time, isBar); } #region Building Bars from Base Period if (bars.Count != tmpCount) // Reset cache when bars are trimmed { if (bars.Count == 0) { tmpTime = Core.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 (BarsPeriod.BaseBarsPeriodType) { case BarsPeriodType.Day: tmpTime = time.Date; if (!isBar) { tmpDayCount++; if (tmpTime < time.Date) { tmpTime = time.Date; // Make sure timestamps are ascending } } if (isBar && prevTimeD != tmpTime) { tmpDayCount++; } if (isBar && bars.Count > 0 && tmpTime == bars.LastBarTime.Date || !isBar && bars.Count > 0 && tmpTime <= bars.LastBarTime.Date || tmpDayCount < BarsPeriod.BaseBarsPeriodValue) { endOfBar = false; } else { prevTime = prevTimeD == Core.Globals.MinDate ? tmpTime : prevTimeD; prevTimeD = tmpTime; endOfBar = true; } break; case BarsPeriodType.Minute: if (tmpTime == Core.Globals.MinDate) { prevTime = tmpTime = TimeToBarTimeMinute(bars, time, isBar); } if (isBar && time <= tmpTime || !isBar && time < tmpTime) { endOfBar = false; } else { prevTime = tmpTime; tmpTime = TimeToBarTimeMinute(bars, time, isBar); endOfBar = true; } break; case BarsPeriodType.Volume: if (tmpTime == Core.Globals.MinDate) { tmpVolume = volume; endOfBar = tmpVolume >= BarsPeriod.BaseBarsPeriodValue; prevTime = tmpTime = time; if (endOfBar) { tmpVolume = 0; } break; } tmpVolume += volume; endOfBar = tmpVolume >= BarsPeriod.BaseBarsPeriodValue; if (endOfBar) { prevTime = tmpTime; tmpVolume = 0; tmpTime = time; } break; case BarsPeriodType.Month: if (tmpTime == Core.Globals.MinDate) { prevTime = tmpTime = TimeToBarTimeMonth(time, BarsPeriod.BaseBarsPeriodValue); } if (time.Month <= tmpTime.Month && time.Year == tmpTime.Year || time.Year < tmpTime.Year) { endOfBar = false; } else { prevTime = tmpTime; endOfBar = true; tmpTime = TimeToBarTimeMonth(time, BarsPeriod.BaseBarsPeriodValue); } break; case BarsPeriodType.Second: if (tmpTime == Core.Globals.MinDate) { prevTime = tmpTime = TimeToBarTimeSecond(bars, time, isBar); } if (time <= tmpTime) { endOfBar = false; } else { prevTime = tmpTime; tmpTime = TimeToBarTimeSecond(bars, time, isBar); endOfBar = true; } break; case BarsPeriodType.Tick: if (tmpTime == Core.Globals.MinDate || BarsPeriod.BaseBarsPeriodValue == 1) { prevTime = tmpTime; if (prevTime == Core.Globals.MinDate) { prevTime = time; } tmpTime = time; endOfBar = BarsPeriod.BaseBarsPeriodValue == 1; break; } if (tmpTickCount < BarsPeriod.BaseBarsPeriodValue) { tmpTime = time; endOfBar = false; tmpTickCount++; } else { prevTime = tmpTime; tmpTime = time; endOfBar = true; tmpTickCount = 1; } break; case BarsPeriodType.Week: if (tmpTime == Core.Globals.MinDate) { prevTime = tmpTime = TimeToBarTimeWeek(time.Date, tmpTime.Date, BarsPeriod.BaseBarsPeriodValue); } if (time.Date <= tmpTime.Date) { endOfBar = false; } else { prevTime = tmpTime; endOfBar = true; tmpTime = TimeToBarTimeWeek(time.Date, tmpTime.Date, BarsPeriod.BaseBarsPeriodValue); } break; case BarsPeriodType.Year: if (tmpTime == Core.Globals.MinDate) { prevTime = tmpTime = TimeToBarTimeYear(time, BarsPeriod.BaseBarsPeriodValue); } if (time.Year <= tmpTime.Year) { endOfBar = false; } else { prevTime = tmpTime; endOfBar = true; tmpTime = TimeToBarTimeYear(time, BarsPeriod.BaseBarsPeriodValue); } break; } #endregion #region P&F logic double tickSize = bars.Instrument.MasterInstrument.TickSize; boxSize = Math.Floor(10000000.0 * BarsPeriod.Value * tickSize) / 10000000.0; reversalSize = BarsPeriod.Value2 * boxSize; if (bars.Count == 0 || IsIntraday && bars.IsResetOnNewTradingDay && isNewSession) { if (bars.Count > 0) { 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, lastHigh, lastLow, lastClose, prevTime == Core.Globals.MinDate ? time : prevTime, lastTime); } } AddBar(bars, close, close, close, close, tmpTime, volume); anchorPrice = close; trend = Trend.Undetermined; prevTime = tmpTime; volumeCount = 0; bars.LastPrice = close; tmpCount = bars.Count; tmpHigh = high; tmpLow = low; return; } double c = bars.GetClose(bars.Count - 1); double h = bars.GetHigh(bars.Count - 1); double l = bars.GetLow(bars.Count - 1); DateTime t = bars.GetTime(bars.Count - 1); if (endOfBar) { CalculatePfBar(bars, h, l, c, prevTime, t); 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 }
protected override void OnDataPoint(Bars bars, double open, double high, double low, double close, DateTime time, long volume, bool isBar, double bid, double ask) { double lastBarClose = bars.GetClose(bars.Count - 1); // Trae el último precio de cierre if (SessionIterator == null) { SessionIterator = new SessionIterator(bars); } offset = bars.BarsPeriod.Value * bars.Instrument.MasterInstrument.TickSize; // Periocidad * tick (Tamaño de la caja) bool isNewSession = SessionIterator.IsNewSession(time, isBar); if (isNewSession) { SessionIterator.GetNextSession(time, isBar); } // Si es una gráfica nueva o una sesión nueva y está en un nuevo día if (bars.Count == 0 || bars.IsResetOnNewTradingDay && isNewSession) { // una sesión nueva y está en un nuevo día if (bars.Count > 0) { // Close out last bar in session and set open == close DateTime lastBarTime = bars.GetTime(bars.Count - 1); // Trae la última fecha del precio de cierre long lastBarVolume = bars.GetVolume(bars.Count - 1); // Trae el último volumen de precio de cierre RemoveLastBar(bars); // Elimina la última barra AddBar(bars, lastBarClose, lastBarClose, lastBarClose, lastBarClose, lastBarTime, lastBarVolume); // Crea una nueva barra con la información obtenida } renkoHigh = close + offset; // Suma el valor de cierre y tamaño de la caja renkoLow = close - offset; // Diferencia del valor de cierre y el tamaño de la caja // ¿Hay un nuevo precio negociado? isNewSession = SessionIterator.IsNewSession(time, isBar); if (isNewSession) { SessionIterator.GetNextSession(time, isBar); // Entonces traiga el último precio } // Pinte el último precio negociado AddBar(bars, close, close, close, close, time, volume); bars.LastPrice = close; return; } double barOpen = bars.GetOpen(bars.Count - 1); // Obtiene el valor de apertura de la última barra double barHigh = bars.GetHigh(bars.Count - 1); // Obtiene el valor más alto negociado de la última barra double barLow = bars.GetLow(bars.Count - 1); // Obtiene el valor más bajo negociado de la última barra long barVolume = bars.GetVolume(bars.Count - 1); // Obtiene el volumen de la última barra DateTime barTime = bars.GetTime(bars.Count - 1); // Obtiene la fecha de la última barra // renkoHigh == 0 || renkoLow == 0 // ApproxCompare: Compares two double or float values for equality or being greater than / less than the compared to value. if (renkoHigh.ApproxCompare(0.0) == 0 || renkoLow.ApproxCompare(0.0) == 0) { if (bars.Count == 1) { renkoHigh = barOpen + offset; // suma = valor de apertura de la última barra + el tamaño de la caja renkoLow = barOpen - offset; // diferencia = valor de apertura de la última barra - el tamaño de la caja } // Penultimo valor de cierre es mayor al penultimo valor de apertura? else if (bars.GetClose(bars.Count - 2) > bars.GetOpen(bars.Count - 2)) { renkoHigh = bars.GetClose(bars.Count - 2) + offset; // Suma tamaño de la caja + el penultimo valor de cierre renkoLow = bars.GetClose(bars.Count - 2) - offset * 2; // Resta el doble del tamaño de la caja - el penultimo valor de cierre } else { renkoHigh = bars.GetClose(bars.Count - 2) + offset * 2; // Suma el doble tamaño de la caja + el penultimo valor de cierre renkoLow = bars.GetClose(bars.Count - 2) - offset; // Resta el tamaño de la caja - el penultimo valor de cierre } } bool isRail2Rail = false; // Hay cambio de tendencia hacia bajista? if (close <= (renkoHigh)) { // Elimina la barra de Update RemoveLastBar(bars); // Agrega la nueva barra con los nuevos valores renkoLow = renkoHigh - 2.0 * offset; // RenkoHigh - el doble del tamaño de la caja renkoHigh = renkoHigh + offset; // Renkohigh + el tamaño de la caja // Agrega barra alcista //AddBar(bars, _renkoLow - offset, Math.Max(_renkoLow - offset, _renkoLow), Math.Min(_renkoLow - offset, _renkoLow), _renkoLow, barTime, barVolume); //AddBar(bars, _renkoHigh + offset, Math.Max(_renkoHigh + offset, _renkoHigh), Math.Min(_renkoHigh + offset, _renkoHigh), _renkoHigh, barTime, barVolume); //AddBar(Bars bars, double open, double high, double low, double close, DateTime time, long volume) //Barra de una gráfica bajista AddBar(bars, renkoLow + offset, Math.Max(renkoLow + offset, renkoLow), Math.Min(renkoLow + offset, renkoLow), renkoLow, barTime, barVolume); isRail2Rail = true; } //bool isRail2Rail = false; // Hay cambio de tendencia hacia alcista? if (close >= (renkoLow)) { // Elimina la barra la barra de Update RemoveLastBar(bars); // Agrega la nueva barra con los nuevos valores // Original //AddBar(bars, renkoLow + offset, Math.Max(renkoLow + offset, renkoLow), Math.Min(renkoLow + offset, renkoLow), renkoLow, barTime, barVolume); // Bajista renkoHigh = renkoLow + 2.0 * offset; // RenkoLow - el doble del tamaño de la caja renkoLow = renkoLow - offset; // RenkoLow - el tamaño de la caja //AddBar(bars, _renkoHigh + offset, Math.Max(_renkoHigh + offset, _renkoHigh), Math.Min(_renkoHigh + offset, _renkoHigh), _renkoHigh, barTime, barVolume); //AddBar(bars, _renkoLow - offset, Math.Max(_renkoLow - offset, _renkoLow), Math.Min(_renkoLow - offset, _renkoLow), _renkoLow, barTime, barVolume); //Barra de gráfica alcista AddBar(bars, renkoHigh - offset, Math.Max(renkoHigh - offset, renkoHigh), Math.Min(renkoHigh - offset, renkoHigh), renkoHigh, barTime, barVolume); isRail2Rail = true; } // el precio de cierre es mayor renkohigh? // [DETECTA COMPORTAMIENTO ALCISTA] if (close.ApproxCompare(renkoHigh) >= 0) { /* if (trend != 0 && trend != 1) { * // Elimina la barra de Update * RemoveLastBar(bars); * * // Agrega la nueva barra con los nuevos valores * var _renkoLow = renkoHigh - 1.0 * offset; // RenkoHigh - el doble del tamaño de la caja * var _renkoHigh = renkoHigh + offset; // Renkohigh + el tamaño de la caja * // Agrega barra alcista * AddBar(bars, _renkoLow - offset, Math.Max(_renkoLow - offset, _renkoLow), Math.Min(_renkoLow - offset, _renkoLow), _renkoLow, barTime, barVolume); * * isRail2Rail = true; * } */ // (1) Obtiene el valor mayor entre renkoHigh y, renkoHigh - tamaño de la caja // (2) Si el valor de x es igual a y entonces retorna 0 // Si el valor de x es mayor a y entonces retorna 1 // Si el valor de x es menor a y entonces retorna -1 if (barOpen.ApproxCompare(renkoHigh - offset) != 0 || // valor de apertura de la (última barra - el tamño de la caja) es mayor o menor a barOpen? barHigh.ApproxCompare(Math.Max(renkoHigh - offset, renkoHigh)) != 0 || // Es barHigh mayor o menor a (1)? barLow.ApproxCompare(Math.Min(renkoHigh - offset, renkoHigh)) != 0) // Es barLow mayor o menor a (1)? { // No hubo cambio de tendencia if (!isRail2Rail) { // Elimina la última barra de Update RemoveLastBar(bars); } // Agrega una barra nueva con los nuevos valores // Alcista AddBar(bars, renkoHigh - offset, Math.Max(renkoHigh - offset, renkoHigh), Math.Min(renkoHigh - offset, renkoHigh), renkoHigh, barTime, barVolume); } renkoLow = renkoHigh - 2.0 * offset; // RenkoHigh - el doble del tamaño de la caja renkoHigh = renkoHigh + offset; // Renkohigh + el tamaño de la caja // ¿Hay un nuevo valor negociado? isNewSession = SessionIterator.IsNewSession(time, isBar); if (isNewSession) { SessionIterator.GetNextSession(time, isBar); // Obtiene el último valor negociado } // Agrega barras vacías para llenar el gap si el precio salta while (close.ApproxCompare(renkoHigh) >= 0) { AddBar(bars, renkoHigh - offset, Math.Max(renkoHigh - offset, renkoHigh), Math.Min(renkoHigh - offset, renkoHigh), renkoHigh, time, 0); renkoLow = renkoHigh - 2.0 * offset; renkoHigh = renkoHigh + offset; } // Agrega la barra final parcial AddBar(bars, renkoHigh - offset, Math.Max(renkoHigh - offset, close), Math.Min(renkoHigh - offset, close), close, time, volume); trend = 1; } // el precio de cierre es menor o igual a renkohigh? // El precio de cierre es menor o igual al renkolow // [DETECTA COMPORTAMIENTO BAJISTA] else if (close.ApproxCompare(renkoLow) <= 0) { /* if (trend != 0 && trend != -1) { * // Elimina la barra la barra de Update * RemoveLastBar(bars); * // Agrega la nueva barra con los nuevos valores * // Original * //AddBar(bars, renkoLow + offset, Math.Max(renkoLow + offset, renkoLow), Math.Min(renkoLow + offset, renkoLow), renkoLow, barTime, barVolume); * // Bajista * var _renkoHigh = renkoLow + 1.0 * offset; // RenkoLow - el doble del tamaño de la caja * var _renkoLow = renkoLow - offset; // RenkoLow - el tamaño de la caja * AddBar(bars, _renkoHigh + offset, Math.Max(_renkoHigh + offset, _renkoHigh), Math.Min(_renkoHigh + offset, _renkoHigh), _renkoHigh, barTime, barVolume); * isRail2Rail = true; * } */ // (1) Obtiene el valor mayor entre renkoLow y, renkoLow + tamaño de la caja // (2) Si el valor de x es igual a y entonces retorna 0 // Si el valor de x es mayor a y entonces retorna 1 // Si el valor de x es menor a y entonces retorna -1 if (barOpen.ApproxCompare(renkoLow + offset) != 0 || // Valor de apertura de (renkolow + el tamaño de la caja) es mayor o menor a barOpen? barHigh.ApproxCompare(Math.Max(renkoLow + offset, renkoLow)) != 0 || // Es barHigh mayor o menor a (1)? barLow.ApproxCompare(Math.Min(renkoLow + offset, renkoLow)) != 0) // Es barlow mayor o menor a (1)? { // TODO: Validar si la condición cambia, si si, entonces no elimine la última barra if (!isRail2Rail) { // Elimine la barra de Update RemoveLastBar(bars); } // Agrega la nueva barra con los nuevos valores // AddBar(Bars bars, double open, double high, double low, double close, DateTime time, long volume) //Bajista AddBar(bars, renkoLow + offset, Math.Max(renkoLow + offset, renkoLow), Math.Min(renkoLow + offset, renkoLow), renkoLow, barTime, barVolume); } renkoHigh = renkoLow + 2.0 * offset; // RenkoLow - el doble del tamaño de la caja renkoLow = renkoLow - offset; // RenkoLow - el tamaño de la caja // ¿Hay un nuevo valor negociado? isNewSession = SessionIterator.IsNewSession(time, isBar); if (isNewSession) { SessionIterator.GetNextSession(time, isBar); // Obtiene el último valor negociado } // Agrega barras vacías para llenar el gap si el precio salta while (close.ApproxCompare(renkoLow) <= 0) { AddBar(bars, renkoLow + offset, Math.Max(renkoLow + offset, renkoLow), Math.Min(renkoLow + offset, renkoLow), renkoLow, time, 0); renkoHigh = renkoLow + 2.0 * offset; renkoLow = renkoLow - offset; } // Agrega la barra final parcial AddBar(bars, renkoLow + offset, Math.Max(renkoLow + offset, close), Math.Min(renkoLow + offset, close), close, time, volume); trend = -1; } // El precio de cierre mayor al renkolow else { // Actualiza la barra UpdateBar(bars, close, close, close, time, volume); } // El último precio el valor de cierre bars.LastPrice = close; }
protected override void OnBarUpdate() { if (CurrentBars[0] < BarsRequiredToTrade || CurrentBars[1] < BarsRequiredToTrade) { return; } if (BarsInProgress == 0) { sessionIterator.GetNextSession(Time[0], true); } // if after the exit on close, prevent new orders until the new session if (Times[1][0] >= sessionIterator.ActualSessionEnd.AddSeconds(-ExitOnSessionCloseSeconds) && Times[1][0] <= sessionIterator.ActualSessionEnd) { exitOnCloseWait = true; } // an exit on close occurred in the previous session, reset for a new entry on the first bar of a new session if (exitOnCloseWait && Bars.IsFirstBarOfSession) { entryOrder = null; profitTarget = null; stopLoss = null; exitFlat = null; exitSession = null; exitOnCloseWait = false; suppressCancelExit = false; } // the entry logic can be done when the primary series is processing if (BarsInProgress == 0) { // because this is a demonstration, this code will cause any historical position // to be exited on the last historical bar so the strategy will always start flat in real-time if (State == State.Historical && CurrentBar == BarsArray[0].Count - 2) { if (entryOrder != null) { if (profitTarget != null && (profitTarget.OrderState == OrderState.Accepted || profitTarget.OrderState == OrderState.Working)) { CancelOrder(profitTarget); } else if (stopLoss != null && (stopLoss.OrderState == OrderState.Accepted || stopLoss.OrderState == OrderState.Working)) { CancelOrder(stopLoss); } ordersCancelled = false; suppressCancelExit = true; exitName = "exit to start flat"; exitFlat = placeHolderOrder; SubmitOrderUnmanaged(1, OrderAction.Sell, OrderType.Market, 1, 0, 0, string.Empty, exitName); } } // if this is not the last historical bar, and entryOrder is null, then place an entry order else if (!exitOnCloseWait && entryOrder == null && profitTarget == null && stopLoss == null) { Print(string.Format("ProfitChaseStopTrailUnmanagedExample:: tradeCount {0}", tradeCount++)); entryName = "entry"; entryOrder = placeHolderOrder; SubmitOrderUnmanaged(1, OrderAction.Buy, OrderType.Market, 1, 0, 0, string.Empty, entryName); } } // all code below this point takes places during BarsInProgress 1 when the secondary series is processing if (BarsInProgress != 1) { return; } if (ordersCancelled) { message = string.Format("{0} stop and/or target cancelled or rejected", Times[1][0]); if (entryOrder == null || entryOrder.OrderState != OrderState.Filled && PrintDetails) { Print(string.Format("{0} | OBU | entry not filled or is null", Times[1][0])); } // if the orders were cancelled due to the exit on close, do not submit an order to flatten if (!exitOnCloseWait && !suppressCancelExit && entryOrder != null && entryOrder.OrderState == OrderState.Filled) { message += "; exiting and resetting"; if (PrintDetails) { Print(message); } exitName = "exit for cancel"; exitFlat = placeHolderOrder; SubmitOrderUnmanaged(1, OrderAction.Sell, OrderType.Market, entryOrder.Filled, 0, 0, string.Empty, exitName); } ordersCancelled = false; return; } // the profitTarget/stopLoss is first created when the entry order fills. If it exists then move it. // trigger the chase action when the current price is further than the set distance to the profit target if (ChaseProfitTarget && profitTarget != null && (profitTarget.OrderState == OrderState.Accepted || profitTarget.OrderState == OrderState.Working) && Close[0] < currentPtPrice - ProfitTargetDistance * tickSizeSecondary) { currentPtPrice = Close[0] + ProfitTargetDistance * tickSizeSecondary; ChangeOrder(profitTarget, entryOrder.Filled, currentPtPrice, 0); } // trigger the trail action when the current price is further than the set distance to the stop loss if (TrailStopLoss && stopLoss != null && (stopLoss.OrderState == OrderState.Accepted || stopLoss.OrderState == OrderState.Working) && Close[0] > currentSlPrice + StopLossDistance * tickSizeSecondary) { currentSlPrice = Close[0] - ProfitTargetDistance * tickSizeSecondary; ChangeOrder(stopLoss, entryOrder.Filled, 0, currentSlPrice); } }
protected override void OnDataPoint(Bars bars, double open, double high, double low, double close, DateTime time, long volume, bool isBar, double bid, double ask) { // method variables bool isNewSession = SessionIterator.IsNewSession(time, isBar); double tickSize = bars.Instrument.MasterInstrument.TickSize; if (SessionIterator == null) { SessionIterator = new SessionIterator(bars); } if (isNewSession) { SessionIterator.GetNextSession(time, isBar); } if (bars.Count == 0 || (bars.IsResetOnNewTradingDay && isNewSession)) { // update fields rangeMax = AddTwoDoubles(bars, bars.BarsPeriod.BaseBarsPeriodValue * tickSize, 0); rangeMin = AddTwoDoubles(bars, bars.BarsPeriod.Value * tickSize, 0); // set initial range, factoring dynamic thisRange = isDynamic ? rangeMin : rangeMax; AdjustMaxMin(bars, close, close); // add first bar AddBar(bars, thisOpen, thisOpen, thisOpen, thisOpen, time, volume); } else { // local variables double barOpen = bars.GetOpen(bars.Count - 1); double barHigh = bars.GetHigh(bars.Count - 1); double barLow = bars.GetLow(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 > barOpen ? 1 : close < barOpen ? -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, (maxCompare > 0 ? thisClose : barHigh), (minCompare < 0 ? thisClose : barLow), thisClose, time, 0); // 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)); newBar = false; // update fields maxCompare = bars.Instrument.MasterInstrument.Compare(close, thisMax); minCompare = bars.Instrument.MasterInstrument.Compare(close, thisMin); }while (maxCompare > 0 || minCompare < 0); } else { UpdateBar(bars, (close > barHigh ? close : barHigh), (close < barLow ? close : barLow), close, time, volume); } } bars.LastPrice = close; }
protected override void OnDataPoint(Bars bars, double open, double high, double low, double close, DateTime time, long volume, bool isBar, double bid, double ask) { if (SessionIterator == null) { SessionIterator = new SessionIterator(bars); } if (bars.Count == 0 && tmpTime != Core.Globals.MinDate) // Reset caching when live request trimmed existing bars { tmpTime = Core.Globals.MinDate; } bool endOfBar = true; if (tmpTime == Core.Globals.MinDate) { tmpTime = time; tmpDayCount = 1; tmpTickCount = 1; } else if (bars.Count < tmpCount && bars.Count == 0) // Reset cache when bars are trimmed { tmpTime = Core.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 (BarsPeriod.BaseBarsPeriodType) { case BarsPeriodType.Day: { if (bars.Count == 0 || bars.Count > 0 && (bars.LastBarTime.Month < time.Month || bars.LastBarTime.Year < time.Year)) { tmpTime = time.Date; bars.LastPrice = close; newSession = true; } else { tmpTime = time.Date; tmpVolume += volume; bars.LastPrice = close; tmpDayCount++; if (tmpDayCount < BarsPeriod.BaseBarsPeriodValue || bars.Count > 0 && bars.LastBarTime.Date == time.Date) { endOfBar = false; } } break; } case BarsPeriodType.Minute: { if (bars.Count == 0 || SessionIterator.IsNewSession(time, isBar) && bars.IsResetOnNewTradingDay) { tmpTime = TimeToBarTimeMinute(bars, time, isBar); newSession = true; tmpVolume = 0; } else { if (!isBar && time < bars.LastBarTime || isBar && time <= bars.LastBarTime) { tmpTime = bars.LastBarTime; endOfBar = false; } else { tmpTime = TimeToBarTimeMinute(bars, time, isBar); } tmpVolume += volume; } break; } case BarsPeriodType.Month: { if (tmpTime == Core.Globals.MinDate) { tmpTime = TimeToBarTimeMonth(time, BarsPeriod.BaseBarsPeriodValue); 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 BarsPeriodType.Second: { if (SessionIterator.IsNewSession(time, isBar)) { tmpTime = TimeToBarTimeSecond(bars, time, isBar); 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, isBar); } break; } case BarsPeriodType.Tick: { if (SessionIterator.IsNewSession(time, isBar)) { SessionIterator.GetNextSession(time, isBar); newSession = true; tmpTime = time; tmpTickCount = 1; if (bars.Count == 0) { break; } endOfBar = false; } else if (BarsPeriod.BaseBarsPeriodValue > 1 && tmpTickCount < BarsPeriod.BaseBarsPeriodValue) { tmpTime = time; tmpVolume += volume; tmpTickCount++; bars.LastPrice = close; endOfBar = false; } else { tmpTime = time; } break; } case BarsPeriodType.Volume: { if (SessionIterator.IsNewSession(time, isBar)) { SessionIterator.GetNextSession(time, isBar); newSession = true; } else if (bars.Count == 0 && volume > 0) { break; } else { tmpVolume += volume; if (tmpVolume < BarsPeriod.BaseBarsPeriodValue) { bars.LastPrice = close; endOfBar = false; } else if (tmpVolume == 0) { endOfBar = false; } } tmpTime = time; break; } case BarsPeriodType.Week: { if (tmpTime == Core.Globals.MinDate) { tmpTime = TimeToBarTimeWeek(time.Date, tmpTime.Date, BarsPeriod.BaseBarsPeriodValue); if (bars.Count == 0) { break; } endOfBar = false; } else if (time.Date <= tmpTime.Date) { tmpVolume += volume; bars.LastPrice = close; endOfBar = false; } break; } case BarsPeriodType.Year: { if (tmpTime == Core.Globals.MinDate) { tmpTime = TimeToBarTimeYear(time, BarsPeriod.BaseBarsPeriodValue); if (bars.Count == 0) { break; } endOfBar = false; } else if (time.Year <= tmpTime.Year) { tmpVolume += volume; bars.LastPrice = close; endOfBar = false; } break; } } if (bars.Count > 0 && tmpTime < bars.GetTime(bars.Count - 1) && BarsPeriod.BaseBarsPeriodType == BarsPeriodType.Second) { tmpTime = bars.GetTime(bars.Count - 1); } if (bars.Count == 0 || newSession && IsIntraday) { AddBar(bars, open, close, close, close, tmpTime, volume); 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); RemoveLastBar(bars); if (SessionIterator.IsNewSession(tmpTime, true)) { SessionIterator.GetNextSession(tmpTime, true); } AddBar(bars, prevOpen, close, close, close, tmpTime, tmpVolume); upTrend = prevOpen < close; anchorPrice = close; } else { int breakCount = BarsPeriod.Value; double breakMax = double.MinValue; double breakMin = double.MaxValue; if (firstBarOfSession) { AddBar(bars, anchorPrice, close, close, close, tmpTime, volume); firstBarOfSession = false; tmpVolume = volume; tmpTime = Core.Globals.MinDate; return; } if (bars.Count - newSessionIdx - 1 < breakCount) { breakCount = bars.Count - (newSessionIdx + 1); } for (int k = 1; k <= breakCount; k++) { breakMax = Math.Max(breakMax, bars.GetOpen(bars.Count - k - 1)); breakMax = Math.Max(breakMax, bars.GetClose(bars.Count - k - 1)); breakMin = Math.Min(breakMin, bars.GetOpen(bars.Count - k - 1)); breakMin = Math.Min(breakMin, bars.GetClose(bars.Count - k - 1)); } bars.LastPrice = close; if (upTrend) { if (endOfBar) { bool adding = false; if (bars.Instrument.MasterInstrument.Compare(bars.GetClose(bars.Count - 1), anchorPrice) > 0) { anchorPrice = bars.GetClose(bars.Count - 1); switchPrice = bars.GetOpen(bars.Count - 1); tmpVolume = volume; adding = true; } else if (bars.Instrument.MasterInstrument.Compare(breakMin, bars.GetClose(bars.Count - 1)) > 0) { anchorPrice = bars.GetClose(bars.Count - 1); switchPrice = bars.GetOpen(bars.Count - 1); 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); } else { RemoveLastBar(bars); double tmpOpen = Math.Min(Math.Max(switchPrice, close), anchorPrice); if (SessionIterator.IsNewSession(tmpTime, true)) { SessionIterator.GetNextSession(tmpTime, true); } AddBar(bars, tmpOpen, close, close, close, tmpTime, tmpVolume); } } else { RemoveLastBar(bars); double tmpOpen = Math.Min(Math.Max(switchPrice, close), anchorPrice); if (SessionIterator.IsNewSession(tmpTime, true)) { SessionIterator.GetNextSession(tmpTime, true); } AddBar(bars, tmpOpen, close, close, close, tmpTime, tmpVolume); } } else if (endOfBar) { bool adding = false; if (bars.Instrument.MasterInstrument.Compare(bars.GetClose(bars.Count - 1), anchorPrice) < 0) { anchorPrice = bars.GetClose(bars.Count - 1); switchPrice = bars.GetOpen(bars.Count - 1); tmpVolume = volume; adding = true; } else if (bars.Instrument.MasterInstrument.Compare(breakMax, bars.GetClose(bars.Count - 1)) < 0) { anchorPrice = bars.GetClose(bars.Count - 1); switchPrice = bars.GetOpen(bars.Count - 1); 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); } else { RemoveLastBar(bars); double tmpOpen = Math.Max(Math.Min(switchPrice, close), anchorPrice); if (SessionIterator.IsNewSession(tmpTime, true)) { SessionIterator.GetNextSession(tmpTime, true); } AddBar(bars, tmpOpen, close, close, close, tmpTime, tmpVolume); } } else { RemoveLastBar(bars); double tmpOpen = Math.Max(Math.Min(switchPrice, close), anchorPrice); if (SessionIterator.IsNewSession(tmpTime, true)) { SessionIterator.GetNextSession(tmpTime, true); } AddBar(bars, tmpOpen, close, close, close, tmpTime, tmpVolume); } } if (endOfBar) { tmpTime = Core.Globals.MinDate; } tmpCount = bars.Count; }
protected override void OnMarketData(MarketDataEventArgs e) { if (!initDone) { return; } if (e.MarketDataType == MarketDataType.Settlement && BarsInProgress == 0) { settlement = e.Price; if (CurrentBars[0] > 1) { DrawSettlementRay("SETTLEM " + e.Time.ToString("MMM dd"), Times[0][1], settlement, Times[0][0], SettlementColor); } return; } if (e.MarketDataType == MarketDataType.Last) { if (isStartOfNewSessionRTH()) { // Print(e.Time+" "+BarsInProgress+" "+BarsArray[RTH].IsFirstBarOfSession); if (tpoProfile != null) { update(tpoProfile); tpoProfiles.Add(tpoProfile); } rthSessionIterator.GetNextSession(e.Time, false); tpoProfile = new JBTPOProfile(RTH, rthSessionIterator.ActualSessionBegin, rthSessionIterator.ActualSessionEnd); // Print("SESSION - "+tpoProfile.sessionStart+" - "+tpoProfile.sessionEnd); } if (isStartOfNewSessionETH()) { //Print(e.Time+" "+BarsInProgress+" "+BarsArray[ETH].IsFirstBarOfSession); if (tpoProfile != null) { update(tpoProfile); tpoProfiles.Add(tpoProfile); } ethSessionIterator.GetNextSession(e.Time, false); tpoProfile = new JBTPOProfile(ETH, ethSessionIterator.ActualSessionBegin, ethSessionIterator.ActualSessionEnd); // Print("SESSION - "+tpoProfile.sessionStart+" - "+tpoProfile.sessionEnd); } if (BarsInProgress == RTH && CurrentBars[RTH] != activeBarRTH) { tpoId = (Times[RTH][0] - tpoProfile.sessionStart).TotalSeconds; activeBarRTH = CurrentBars[RTH]; } else if (BarsInProgress == ETH && CurrentBars[ETH] != activeBarETH) { tpoId = (Times[ETH][0] - tpoProfile.sessionStart).TotalSeconds; activeBarETH = CurrentBars[ETH]; } if ((BarsInProgress == RTH || BarsInProgress == ETH) && tpoProfile != null) { //Print(e.Time+" "+e.Price); if (e.Time >= tpoProfile.sessionStart && e.Time < tpoProfile.sessionEnd) { tpoProfile.add(e.Price, tpoId); } } else if (BarsInProgress == 0 && CurrentBars[0] != activeBar) { if (tpoProfile != null) { update(tpoProfile); } activeBar = CurrentBars[0]; } } }
protected override void OnDataPoint(Bars bars, double open, double high, double low, double close, DateTime time, long volume, bool isBar, double bid, double ask) { if (SessionIterator == null) { SessionIterator = new SessionIterator(bars); } #region Building Bars from Base Period if (bars.Count != tmpCount) // Reset cache when bars are trimmed { if (bars.Count == 0) { tmpTime = Core.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; } } bool isNewSession = SessionIterator.IsNewSession(time, isBar); bool isCalculateTradingDayDone = false; switch (bars.BarsPeriod.BaseBarsPeriodType) { case BarsPeriodType.Day: tmpTime = time.Date; // Will be modified for realtime only if (!isBar && time >= cacheSessionEnd /* on realtime includesEndTimeStamp is always false */) { if (isNewSession) { SessionIterator.GetNextSession(time, isBar); isCalculateTradingDayDone = true; } cacheSessionEnd = SessionIterator.ActualSessionEnd; if (tmpTime < time.Date) { tmpTime = time.Date; // Make sure timestamps are ascending } } if (prevTime != tmpTime) { tmpDayCount++; } if (tmpDayCount < bars.BarsPeriod.BaseBarsPeriodValue || isBar && bars.Count > 0 && tmpTime == bars.LastBarTime.Date || !isBar && bars.Count > 0 && tmpTime <= bars.LastBarTime.Date) { endOfBar = false; } else { prevTime = tmpTime; endOfBar = true; } break; case BarsPeriodType.Minute: if (tmpTime == Core.Globals.MinDate) { prevTime = tmpTime = TimeToBarTimeMinute(bars, time, isBar); } if (isBar && time <= tmpTime || !isBar && time < tmpTime) { endOfBar = false; } else { prevTime = tmpTime; tmpTime = TimeToBarTimeMinute(bars, time, isBar); endOfBar = true; } break; case BarsPeriodType.Volume: if (tmpTime == Core.Globals.MinDate) { tmpVolume = volume; endOfBar = tmpVolume >= bars.BarsPeriod.BaseBarsPeriodValue; prevTime = tmpTime = time; if (endOfBar) { tmpVolume = 0; } break; } tmpVolume += volume; endOfBar = tmpVolume >= bars.BarsPeriod.BaseBarsPeriodValue; if (endOfBar) { prevTime = tmpTime; tmpVolume = 0; } tmpTime = time; break; case BarsPeriodType.Tick: if (tmpTime == Core.Globals.MinDate || bars.BarsPeriod.BaseBarsPeriodValue == 1) { prevTime = tmpTime == Core.Globals.MinDate ? time : tmpTime; tmpTime = time; tmpTickCount = bars.BarsPeriod.BaseBarsPeriodValue == 1 ? 0 : 1; endOfBar = bars.BarsPeriod.BaseBarsPeriodValue == 1; break; } if (tmpTickCount < bars.BarsPeriod.BaseBarsPeriodValue) { tmpTime = time; endOfBar = false; tmpTickCount++; } else { prevTime = tmpTime; tmpTime = time; endOfBar = true; tmpTickCount = 1; } break; case BarsPeriodType.Month: if (tmpTime == Core.Globals.MinDate) { prevTime = tmpTime = TimeToBarTimeMonth(time, bars.BarsPeriod.BaseBarsPeriodValue); } if (time.Month <= tmpTime.Month && time.Year == tmpTime.Year || time.Year < tmpTime.Year) { endOfBar = false; } else { prevTime = tmpTime; endOfBar = true; tmpTime = TimeToBarTimeMonth(time, bars.BarsPeriod.BaseBarsPeriodValue); } break; case BarsPeriodType.Second: if (tmpTime == Core.Globals.MinDate) { prevTime = tmpTime = TimeToBarTimeSecond(bars, time, isBar); } if (bars.BarsPeriod.BaseBarsPeriodValue > 1 && time < tmpTime || bars.BarsPeriod.BaseBarsPeriodValue == 1 && time <= tmpTime) { endOfBar = false; } else { prevTime = tmpTime; tmpTime = TimeToBarTimeSecond(bars, time, isBar); endOfBar = true; } break; case BarsPeriodType.Week: if (tmpTime == Core.Globals.MinDate) { prevTime = tmpTime = TimeToBarTimeWeek(time.Date, tmpTime.Date, bars.BarsPeriod.BaseBarsPeriodValue); } if (time.Date <= tmpTime.Date) { endOfBar = false; } else { prevTime = tmpTime; endOfBar = true; tmpTime = TimeToBarTimeWeek(time.Date, tmpTime.Date, bars.BarsPeriod.BaseBarsPeriodValue); } break; case BarsPeriodType.Year: if (tmpTime == Core.Globals.MinDate) { prevTime = tmpTime = TimeToBarTimeYear(time, bars.BarsPeriod.Value); } if (time.Year <= tmpTime.Year) { endOfBar = false; } else { prevTime = tmpTime; endOfBar = true; tmpTime = TimeToBarTimeYear(time, bars.BarsPeriod.Value); } break; } #endregion #region Kagi Logic reversalPoint = bars.BarsPeriod.ReversalType == ReversalType.Tick ? bars.BarsPeriod.Value * bars.Instrument.MasterInstrument.TickSize : bars.BarsPeriod.Value / 100.0 * anchorPrice; if (bars.Count == 0 || IsIntraday && (bars.BarsPeriod.BaseBarsPeriodType != BarsPeriodType.Second && bars.IsResetOnNewTradingDay && isNewSession || bars.BarsPeriod.BaseBarsPeriodType == BarsPeriodType.Second && bars.IsResetOnNewTradingDay && isNewSession)) { if (isNewSession && !isCalculateTradingDayDone) { SessionIterator.GetNextSession(tmpTime, isBar); } 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); } } AddBar(bars, close, close, close, close, tmpTime, volume); anchorPrice = close; trend = Trend.Undetermined; prevTime = tmpTime; volumeCount = 0; bars.LastPrice = close; tmpCount = bars.Count; return; } double c = bars.GetClose(bars.Count - 1); double o = bars.GetOpen(bars.Count - 1); double h = bars.GetHigh(bars.Count - 1); double l = bars.GetLow(bars.Count - 1); if (endOfBar) { CalculateKagiBar(bars, o, h, l, c, prevTime, volume); } else { volumeCount += volume; } bars.LastPrice = close; tmpCount = bars.Count; #endregion }
protected override void OnMarketData(MarketDataEventArgs marketDataUpdate) { // Workaround for market replay sending out all of replay sessions data(as historical data) // Replay should only backfill history up to replay time, so make sure any historical ticks // are before the current replay time. // this code to OnBar and set for on price change notifications for better performance once // this bug is resolved if ((Connection.PlaybackConnection != null) && (State == State.Historical) && (marketDataUpdate.Time >= Connection.PlaybackConnection.Now)) { return; } bool redrawHigh = false; bool redrawLow = false; // Reset for every session if (sessionIterator.IsNewSession(marketDataUpdate.Time, true)) { orHigh = Double.MinValue; orLow = Double.MaxValue; sessionIterator.GetNextSession(marketDataUpdate.Time, true); renderEndTime = sessionIterator.ActualSessionEnd; orCutoffTime = sessionIterator.ActualSessionBegin.AddSeconds(CutoffSeconds); rendered = false; orComplete = false; } if (orComplete) { return; } // Check session time if (!sessionIterator.IsInSession(marketDataUpdate.Time, false, true)) { return; } // keep track of high low if (marketDataUpdate.MarketDataType == MarketDataType.Last) { if (!orComplete && (marketDataUpdate.Time <= orCutoffTime)) { redrawHigh = false; if (marketDataUpdate.Price > orHigh) { orHigh = marketDataUpdate.Price; orHighDateTime = marketDataUpdate.Time; redrawHigh = true; Values[0][0] = orHigh; } redrawLow = false; if (marketDataUpdate.Price < orLow) { orLow = marketDataUpdate.Price; orLowDateTime = marketDataUpdate.Time; redrawLow = true; Values[1][0] = orLow; } if (redrawHigh) { RemoveDrawObject(marketDataUpdate.Time.Date.ToString() + "or_high"); Draw.Line(this, marketDataUpdate.Time.Date.ToString() + "or_high", true, orHighDateTime, orHigh, renderEndTime, orHigh, HighBrush, DashStyleHelper.Dot, HighBrushWidth); } if (redrawLow) { RemoveDrawObject(marketDataUpdate.Time.Date.ToString() + "or_low"); Draw.Line(this, marketDataUpdate.Time.Date.ToString() + "or_low", true, orLowDateTime, orLow, renderEndTime, orLow, LowBrush, DashStyleHelper.Dot, LowBrushWidth); } } // On first tick past cutoff time mark opening range calc complete and // draw the hi and low lines across the entire sesson. if ((marketDataUpdate.Time > orCutoffTime) && !orComplete) { orComplete = true; RemoveDrawObject(marketDataUpdate.Time.Date.ToString() + "or_high"); Draw.Line(this, marketDataUpdate.Time.Date.ToString() + "or_high", true, orHighDateTime, orHigh, renderEndTime, orHigh, HighBrush, DashStyleHelper.Solid, HighBrushWidth); RemoveDrawObject(marketDataUpdate.Time.Date.ToString() + "or_low"); Draw.Line(this, marketDataUpdate.Time.Date.ToString() + "or_low", true, orLowDateTime, orLow, renderEndTime, orLow, LowBrush, DashStyleHelper.Solid, LowBrushWidth); // Go back to first bar and Set all the high and low plot // values for the day so databox works for indicator for (int x = 0; x < Bars.BarsSinceNewTradingDay; x++) { Values[0][x] = orHigh; Values[1][x] = orLow; } } } }