## Purpose A single source of truth to ensure **first-time compile** success for all NinjaTrader 8 strategies, indicators, and add-ons generated by an LLM. --- ## Golden Rules (Pin These) 1. **NT8 only.** No NT7 APIs. If NT7 concepts appear, **silently upgrade** to NT8 (proper `OnStateChange()` and `protected override` signatures). 2. **One file, one public class.** File name = class name. Put at the top: `// File: .cs`. 3. **Namespaces:** - Strategies → `NinjaTrader.NinjaScript.Strategies` - Indicators → `NinjaTrader.NinjaScript.Indicators` 4. **Correct override access:** All NT8 overrides are `protected override` (never `public` or `private`). 5. **Lifecycle:** Use `OnStateChange()` with `State.SetDefaults`, `State.Configure`, `State.DataLoaded` to set defaults, add data series, and instantiate indicators/Series. 6. **Indicator creation:** Instantiate indicators **once** in `State.DataLoaded`. Add to chart (if desired) in `State.Configure` via `AddChartIndicator()`. 7. **Managed orders by default:** Use `SetStopLoss`/`SetProfitTarget` **before** entries on the same bar. Do **not** mix Managed & Unmanaged in the same file. 8. **MTF discipline:** Add secondary series **only** in `State.Configure`. In `OnBarUpdate()`, gate logic with `BarsInProgress` and `CurrentBars[i]`. 9. **No Order Flow+ by default:** Assume unavailable. If VWAP is needed, implement a **local fallback** or feature flag (OFF by default). 10. **Valid enums only:** Use real NT8 members for `OrderState`, `MarketPosition`, etc. 11. **Starter header in every strategy `OnBarUpdate()`:** ```csharp if (BarsInProgress != 0) return; if (CurrentBar < BarsRequiredToTrade) return; Required Using Block (Strategy) Always show details using System; using System.ComponentModel; using System.ComponentModel.DataAnnotations; using System.Windows.Media; using NinjaTrader.Cbi; using NinjaTrader.Data; using NinjaTrader.Gui; using NinjaTrader.Gui.Chart; using NinjaTrader.Gui.Tools; using NinjaTrader.NinjaScript; using NinjaTrader.NinjaScript.Strategies; using NinjaTrader.NinjaScript.Indicators; using NinjaTrader.NinjaScript.DrawingTools; Indicators omit some GUI usings unless needed. Inputs Pattern Use DataAnnotations so properties render properly in the UI: Always show details [NinjaScriptProperty, Range(1, int.MaxValue)] [Display(Name = "Quantity", GroupName = "Parameters", Order = 0)] public int Quantity { get; set; } = 1; [NinjaScriptProperty] [Display(Name = "DebugMode", GroupName = "Parameters", Order = 999)] public bool DebugMode { get; set; } = false; Managed Order Rules Call SetStopLoss and SetProfitTarget before you place an entry order. Re-arm stops/targets when intended direction changes (e.g., flat→long or flat→short). Use unique signal names per direction to bind OCO correctly (e.g., "L1", "S1"). Multi-Timeframe Rules Add secondary series in State.Configure: Always show details AddDataSeries(BarsPeriodType.Minute, 5); Guard in OnBarUpdate(): Always show details if (BarsInProgress == 1) { /* 5-min logic */ } if (CurrentBars[0] < BarsRequiredToTrade || CurrentBars[1] < 20) return; Price Rounding & Tick Math Always round to tick size to avoid rejections: Always show details private double Rt(double p) => Instrument.MasterInstrument.RoundToTickSize(p); double target = Rt(Close[0] + 10 * TickSize); Historical vs. Realtime Always show details private bool IsLive => State == State.Realtime; Avoid timers/threads/file I/O by default. Common Safety Defaults Always show details Calculate = Calculate.OnBarClose; IsOverlay = false; BarsRequiredToTrade = 20; IsSuspendedWhileInactive = true; IsInstantiatedOnEachOptimizationIteration = true; Valid NT8 Signatures (paste as needed) Always show details protected override void OnOrderUpdate( Order order, double limitPrice, double stopPrice, int quantity, int filled, double averageFillPrice, OrderState orderState, DateTime time, ErrorCode error, string nativeError) { } protected override void OnExecutionUpdate( Execution execution, string executionId, double price, int quantity, MarketPosition marketPosition, string orderId, DateTime time) { } protected override void OnMarketData(MarketDataEventArgs e) { } protected override void OnMarketDepth(MarketDepthEventArgs e) { } protected override void OnPositionUpdate(Position position, double averagePrice, int quantity, MarketPosition marketPosition) { } Compile Checklist (Preflight) NT8 only; no OnStartUp() or NT7 methods. Exactly one public class; file name matches class name. Required usings present. Indicators/Series created in State.DataLoaded. Starter header present in OnBarUpdate(). Managed orders only (unless explicitly asked otherwise). Secondary series added only in State.Configure. Enums & members verified against NT8. Price rounding helper present for any custom prices. DebugMode gating for Print() calls. """).format(date=datetime.date.today().isoformat()) files["NT8_Templates.md"] = textwrap.dedent(""" --- # NinjaScript Compiler Constraints ## CRITICAL: Two separate compilers exist in this project This project uses TWO compilers with DIFFERENT rules: 1. **dotnet build** — compiles src/NT8.Core/ and src/NT8.Adapters/ as standard .NET Framework 4.8 assemblies. Errors here show up in the terminal. 2. **NinjaTrader NinjaScript compiler** — compiles the .cs files deployed to `C:\Users\billy\Documents\NinjaTrader 8\bin\Custom\Strategies\`. Errors here only show up inside the NT8 NinjaScript Editor, NOT in dotnet build output. **dotnet build passing does NOT mean NT8 will compile successfully.** Always treat NT8 compilation as a required separate verification step. --- ## NinjaScript-specific API rules ### OnConnectionStatusUpdate — correct signature ```csharp // CORRECT — single ConnectionStatusEventArgs parameter protected override void OnConnectionStatusUpdate( ConnectionStatusEventArgs connectionStatusUpdate) { connectionStatusUpdate.Status // ConnectionStatus enum connectionStatusUpdate.PriceStatus // ConnectionStatus enum } // WRONG — this signature does not exist in NT8 protected override void OnConnectionStatusUpdate( Connection connection, ConnectionStatus status, DateTime time) // CS0115 — no suitable method found to override ``` ### [Optimizable] attribute — does not exist ```csharp // WRONG — OptimizableAttribute does not exist in NinjaScript [Optimizable] public int StopTicks { get; set; } // CS0246 // CORRECT — all [NinjaScriptProperty] params are optimizer-eligible // Use [Range] to set optimizer bounds [NinjaScriptProperty] [Range(1, 50)] public int StopTicks { get; set; } ``` ### Attributes that DO exist in NinjaScript ```csharp [NinjaScriptProperty] // exposes to UI and optimizer [Display(...)] // controls UI label, group, order [Range(min, max)] // sets optimizer/validation bounds [Browsable(false)] // hides from UI [XmlIgnore] // excludes from serialization ``` ### Attributes that do NOT exist in NinjaScript ``` [Optimizable] — use [NinjaScriptProperty] + [Range] instead [JsonProperty] — not available [Required] — not available ``` ### Method overrides — always verify against NT8 documentation Before adding any `protected override` method to NT8StrategyBase.cs or any NinjaScript file, verify the exact signature at: https://developer.ninjatrader.com/docs/desktop Common signatures that differ from intuition: | Method | Correct NT8 Signature | |---|---| | OnConnectionStatusUpdate | `(ConnectionStatusEventArgs e)` | | OnMarketData | `(MarketDataEventArgs e)` | | OnMarketDepth | `(MarketDepthEventArgs e)` | | OnOrderUpdate | `(Order order, double limitPrice, double stopPrice, int quantity, int filled, double avgFillPrice, OrderState orderState, DateTime time, ErrorCode error, string nativeError)` | | OnExecutionUpdate | `(Execution execution, string executionId, double price, int quantity, MarketPosition marketPosition, string orderId, DateTime time)` | --- ## Deployment reminder The full deployment sequence is always: ``` 1. dotnet build NT8-SDK.sln --configuration Release 2. deployment\deploy-to-nt8.bat 3. NT8: Tools → NinjaScript Editor → Compile All 4. Reload any open Strategy Analyzer or chart instances ``` Steps 1-2 passing does NOT mean step 3 will pass. NT8 compilation is the only authoritative check for NinjaScript-specific code. --- ## Files compiled by NT8 (not dotnet build) These files are deployed as source and compiled by NT8's embedded compiler. Any NT8-specific API usage in these files is invisible to dotnet build: - `src/NT8.Adapters/Strategies/NT8StrategyBase.cs` - `src/NT8.Adapters/Strategies/SimpleORBNT8.cs` - `src/NT8.Adapters/Wrappers/BaseNT8StrategyWrapper.cs` - `src/NT8.Adapters/Wrappers/SimpleORBNT8Wrapper.cs` Any new strategy or wrapper file added to these locations inherits the same constraint. When modifying these files, the NT8 compiler is the only valid test.