Add ORB confluence factors (NR4/NR7, gap alignment, breakout volume, prior close) + session file logger
Some checks failed
Build and Test / build (push) Has been cancelled

This commit is contained in:
2026-03-19 12:16:39 -04:00
parent ee4da1b607
commit 498f298975
11 changed files with 1569 additions and 76 deletions

View File

@@ -12,6 +12,7 @@ using NinjaTrader.NinjaScript;
using NinjaTrader.NinjaScript.Indicators;
using NinjaTrader.NinjaScript.Strategies;
using NT8.Core.Common.Interfaces;
using NT8.Core.Intelligence;
using NT8.Strategies.Examples;
using SdkSimpleORB = NT8.Strategies.Examples.SimpleORBStrategy;
@@ -49,6 +50,8 @@ namespace NinjaTrader.NinjaScript.Strategies
Name = "Simple ORB NT8";
Description = "Opening Range Breakout with NT8 SDK integration";
// Daily bar series is added automatically via AddDataSeries in Configure.
OpeningRangeMinutes = 30;
StdDevMultiplier = 1.0;
StopTicks = 8;
@@ -63,11 +66,28 @@ namespace NinjaTrader.NinjaScript.Strategies
Calculate = Calculate.OnBarClose;
BarsRequiredToTrade = 50;
EnableLongTrades = true;
EnableShortTrades = false;
}
else if (State == State.Configure)
{
AddDataSeries(BarsPeriodType.Day, 1);
}
base.OnStateChange();
}
protected override void OnBarUpdate()
{
if (_strategyConfig != null && BarsArray != null && BarsArray.Length > 1)
{
DailyBarContext dailyContext = BuildDailyBarContext(0, 0.0, (double)Volume[0]);
_strategyConfig.Parameters["daily_bars"] = dailyContext;
}
base.OnBarUpdate();
}
protected override IStrategy CreateSdkStrategy()
{
return new SdkSimpleORB(OpeningRangeMinutes, StdDevMultiplier);
@@ -98,15 +118,82 @@ namespace NinjaTrader.NinjaScript.Strategies
_strategyConfig.Parameters["TargetTicks"] = TargetTicks;
_strategyConfig.Parameters["OpeningRangeMinutes"] = OpeningRangeMinutes;
if (Instrument != null && Instrument.MasterInstrument != null)
{
_strategyConfig.Parameters["TickSize"] = Instrument.MasterInstrument.TickSize;
}
if (_logger != null)
{
_logger.LogInformation(
"Simple ORB configured: OR={0}min, Stop={1}ticks, Target={2}ticks",
"Simple ORB configured: OR={0}min, Stop={1}ticks, Target={2}ticks, Long={3}, Short={4}",
OpeningRangeMinutes,
StopTicks,
TargetTicks);
TargetTicks,
EnableLongTrades,
EnableShortTrades);
}
}
/// <summary>
/// Builds a DailyBarContext from the secondary daily bar series.
/// Returns a context with Count=0 if fewer than 2 daily bars are available.
/// </summary>
/// <param name="tradeDirection">1 for long, -1 for short.</param>
/// <param name="orbRangeTicks">ORB range in ticks for ORB range factor.</param>
/// <param name="breakoutBarVolume">Volume of the current breakout bar.</param>
/// <returns>Populated daily context for confluence scoring.</returns>
private DailyBarContext BuildDailyBarContext(int tradeDirection, double orbRangeTicks, double breakoutBarVolume)
{
DailyBarContext ctx = new DailyBarContext();
ctx.TradeDirection = tradeDirection;
ctx.BreakoutBarVolume = breakoutBarVolume;
ctx.TodayOpen = Open[0];
if (BarsArray == null || BarsArray.Length < 2 || CurrentBars == null || CurrentBars.Length < 2)
{
ctx.Count = 0;
return ctx;
}
int dailyBarsAvailable = CurrentBars[1] + 1;
int lookback = Math.Min(10, dailyBarsAvailable);
if (lookback < 2)
{
ctx.Count = 0;
return ctx;
}
ctx.Highs = new double[lookback];
ctx.Lows = new double[lookback];
ctx.Closes = new double[lookback];
ctx.Opens = new double[lookback];
ctx.Volumes = new long[lookback];
ctx.Count = lookback;
for (int i = 0; i < lookback; i++)
{
int barsAgo = lookback - 1 - i;
ctx.Highs[i] = Highs[1][barsAgo];
ctx.Lows[i] = Lows[1][barsAgo];
ctx.Closes[i] = Closes[1][barsAgo];
ctx.Opens[i] = Opens[1][barsAgo];
ctx.Volumes[i] = (long)Volumes[1][barsAgo];
}
double sumVol = 0.0;
int intradayCount = 0;
int maxBars = Math.Min(78, CurrentBar + 1);
for (int i = 0; i < maxBars; i++)
{
sumVol += Volume[i];
intradayCount++;
}
ctx.AvgIntradayBarVolume = intradayCount > 0 ? sumVol / intradayCount : Volume[0];
return ctx;
}
}
}