diff --git a/.kilocode/rules/coding_patterns.md b/.kilocode/rules/coding_patterns.md index 89f6671..e123b0c 100644 --- a/.kilocode/rules/coding_patterns.md +++ b/.kilocode/rules/coding_patterns.md @@ -1,9 +1,66 @@ # Coding Patterns — NT8 SDK Required Patterns +**Last Updated:** 2026-03-27 All code in the NT8 SDK MUST follow these patterns without exception. --- +## 0. C# 5.0 Hard Constraints (NinjaScript Compiler) + +```csharp +// ❌ PROHIBITED — compiler will fail silently or error +$"Hello {name}" // no string interpolation +obj?.Method() // no null-conditional +public int Prop => _value; // no expression body +nameof(SomeClass) // no nameof +await SomeAsync() // no async/await + +// ✅ REQUIRED +string.Format("Hello {0}", name) +obj != null ? obj.Method() : null +public int Prop { get { return _value; } } +"SomeClass" // string literal +// synchronous only +``` + +--- + +## 0b. NT8-Specific Critical Rules + +```csharp +// SetStopLoss/SetProfitTarget MUST come BEFORE EnterLong/EnterShort +// Calling them after is silently ignored in backtest +SetStopLoss(signalName, CalculationMode.Ticks, stopTicks, false); // FIRST +SetProfitTarget(signalName, CalculationMode.Ticks, targetTicks); // SECOND +EnterShort(qty, signalName); // THIRD + +// OnBarUpdate must guard secondary series +protected override void OnBarUpdate() +{ + if (BarsInProgress != 0) return; // CRITICAL: ignore daily bar series updates + // ... +} + +// State guard in ProcessStrategyIntent +// Allows Historical (backtest), blocks Realtime replay burst: +if (State == State.Realtime && !_realtimeBarSeen) + return; +``` + +--- + +## Sizing Formula + +``` +contracts = floor(RiskPerTrade / (StopTicks × TickValue)) +NQ tick value = $5.00 +$100 / (8 × $5) = 2 contracts +$200 / (8 × $5) = 5 contracts (capped at MaxContracts) +Always verify: RiskPerTrade ≤ MaxTradeRisk +``` + +--- + ## 1. Thread Safety — Lock Everything Shared Every class with shared state must have a lock object: diff --git a/.kilocode/rules/development_workflow.md b/.kilocode/rules/development_workflow.md index 576169f..9d739a5 100644 --- a/.kilocode/rules/development_workflow.md +++ b/.kilocode/rules/development_workflow.md @@ -1,7 +1,108 @@ -# NT8 Institutional SDK - Development Workflow +# NT8-SDK — Kilocode Development Workflow +**Last Updated:** 2026-03-27 -## Overview -This document outlines the development workflow for the NT8 Institutional SDK, following the Archon workflow principles even in the absence of the Archon MCP server. +This is the authoritative workflow for all development work on NT8-SDK using Kilocode. + +--- + +## Division of Labor + +| Role | Responsibility | +|---|---| +| **Claude** | Architecture, diagnosis, Kilocode prompt authoring, sequencing | +| **Kilocode** | ALL code implementation — zero exceptions | +| **Mo** | Strategy direction, backtest execution, log collection, go/no-go | + +--- + +## Per-Task Workflow + +1. **Claude writes Kilocode prompt** — exact Find/Replace, both file paths, build command, validation checklist +2. **Mo runs Kilocode** — pastes prompt, Kilocode executes +3. **Kilocode reports** — build output + files changed +4. **Mo brings results to Claude** — Kilocode report + session log + CSV +5. **Claude diagnoses** — confirms or issues follow-up prompt +6. **Mo commits:** `git add` → `git commit` → `git push` +7. **Update SPRINT_BOARD** — task to Done or Blocked + +--- + +## Kilocode Prompt Template + +``` +TASK: [one-line description] + +CONTEXT: +[1-3 sentences explaining why] + +FILES TO MODIFY: +1. C:\dev\nt8-sdk\src\... [repo path] +2. C:\Users\billy\...\Strategies\... [NT8 path — same change] + +CHANGE 1 — [description]: +File: [path] +Find: +[exact existing code] +Replace with: +[new code] + +BUILD & DEPLOY: +1. dotnet build NT8-SDK.sln --configuration Release +2. deployment\deploy-to-nt8.bat +3. NT8: Tools → Edit NinjaScript → open NT8StrategyBase.cs → save + +VALIDATION: +- Run Strategy Analyzer: NQ JUN26, Jan 1 2026 → Mar 27 2026 +- Look for in session log: [specific confirmation lines] +``` + +--- + +## Guardrails — Kilocode MUST NEVER + +1. Modify files outside the task spec +2. Use C# 6+ syntax +3. Remove existing comments or XML documentation +4. Change interface signatures +5. Deploy without building first +6. Edit NT8 path without also updating repo path +7. Guess NT8 API signatures +8. Introduce async/await + +--- + +## Log Analysis Quick Reference + +**Healthy dual-leg trade in session log:** +``` +SIGNAL Sell | Grade=A | Score=0.820 +SUBMIT Scaler=1 Runner=1 Stop=8 Target=20 +FILL Short 1 @ XXXXX <- scaler fill +PNL_UPDATE Position=Short Qty=1 +FILL Short 1 @ XXXXX <- runner fill +PNL_UPDATE Position=Short Qty=2 <- CRITICAL: Qty=2 = runner entered +``` + +**Warning signs:** +- SUBMIT then only 1 FILL → runner blocked (check EntriesPerDirection + MaxOpenPositions) +- Multiple SIGNALs in milliseconds → replay burst (_realtimeBarSeen not working) +- SIGNAL then nothing → ProcessStrategyIntent guard blocking backtest + +--- + +## Commit Message Format + +``` +feat: description <- new feature +fix: description <- bug fix +refactor: description <- no behavior change +test: description <- tests only +docs: description <- documentation only +``` + +--- + +## Original Archon Workflow (2025, archived below) ## Archon Workflow Principles diff --git a/.kilocode/rules/project_context.md b/.kilocode/rules/project_context.md index e6a7508..d2c1391 100644 --- a/.kilocode/rules/project_context.md +++ b/.kilocode/rules/project_context.md @@ -1,7 +1,74 @@ -# Project Context — NT8 SDK (Production Hardening Phase) +# Project Context — NT8 SDK (Sprint 2: SIM Validation) +**Last Updated:** 2026-03-27 -You are working on the **NT8 SDK** — an institutional-grade algorithmic trading framework for NinjaTrader 8. -This is production trading software. Bugs cause real financial losses. +You are working on the **NT8 SDK** — an institutional-grade algorithmic futures trading system for NinjaTrader 8. +This is **production trading software**. Bugs cause real financial losses. Never take shortcuts. + +--- + +## Critical Rules for Kilocode + +1. **Only modify files listed in the task spec.** Never touch adjacent code. +2. **C# 5.0 only.** No `$""`, no `?.`, no `=>` bodies, no `nameof()`, no async/await. +3. **Never remove XML documentation or comments.** +4. **Never change interface signatures** — IStrategy, IRiskManager, IPositionSizer, INT8ExecutionBridge are frozen. +5. **Always build before deploying:** `dotnet build NT8-SDK.sln --configuration Release` +6. **Always deploy to BOTH paths** after every code change: + - Repo: `C:\dev\nt8-sdk\src\NT8.Adapters\Strategies\` + - NT8: `C:\Users\billy\Documents\NinjaTrader 8\bin\Custom\Strategies\` +7. **Never guess NT8 API signatures.** Verify at `https://developer.ninjatrader.com/docs/desktop`. + +--- + +## Current State (2026-03-27) + +**What works end-to-end:** +- SimpleORBStrategy with 10-factor confluence scoring +- NT8StrategyBase with session management, kill switch, connection recovery +- Dual-leg scaler + runner architecture (EntriesPerDirection=2 restored) +- PortfolioRiskManager singleton (kill switch, daily loss, contract cap) +- File logging (session log + settings export) +- Historical replay guard (_realtimeBarSeen) +- Execution confirmed in SIM on 2026-03-27 + +**Pending validation:** +- Runner leg dual-fill (Qty=2) — run backtest to confirm +- Breakeven + trail in live multi-bar scenario + +--- + +## Architecture + +``` +SimpleORBNT8.cs NT8 entry point + ↓ +NT8StrategyBase.cs Abstract base: bar routing, kill switch, breakeven, runner trail + ↓ +SimpleORBStrategy.cs Signal: ORB detection, 10-factor confluence, _tradeTaken lock + ↓ +NT8OrderAdapter.cs INT8ExecutionBridge: EnterLong/EnterShort/SetStopLoss + ↓ +PortfolioRiskManager.cs Singleton: cross-strategy risk + ↓ +NinjaTrader 8 +``` + +## Key Files + +| File | Path | +|---|---| +| NT8StrategyBase.cs | `src\NT8.Adapters\Strategies\` | +| SimpleORBNT8.cs | `src\NT8.Adapters\Strategies\` | +| SimpleORBStrategy.cs | `src\NT8.Strategies\Examples\` | +| NT8OrderAdapter.cs | `src\NT8.Adapters\NinjaTrader\` | +| PortfolioRiskManager.cs | `src\NT8.Core\Risk\` | +| deploy-to-nt8.bat | `deployment\` | + +## Active Sprint Tasks + +See `SPRINT_BOARD.md` (at `docs\architecture\phase1_sprint_plan.md`) for full task list. + +Immediate next action: Run Strategy Analyzer backtest (NQ JUN26, Jan 1 2026 → Mar 27 2026) and confirm `PNL_UPDATE Position=Short Qty=2` in session log to validate runner leg. --- diff --git a/DESIGNED_VS_IMPLEMENTED_GAP_ANALYSIS.md b/DESIGNED_VS_IMPLEMENTED_GAP_ANALYSIS.md index 50372d1..9ca7f12 100644 --- a/DESIGNED_VS_IMPLEMENTED_GAP_ANALYSIS.md +++ b/DESIGNED_VS_IMPLEMENTED_GAP_ANALYSIS.md @@ -1,4 +1,69 @@ -# Designed vs. Implemented Features - Gap Analysis +# NT8-SDK — Gap Analysis & Roadmap +**Version:** 3.0 | **Date:** 2026-03-27 | Supersedes all previous gap analysis documents. + +--- + +## Open Gaps + +| ID | Description | Priority | Sprint | +|---|---|---|---| +| GAP-001 | Runner leg backtest validation (Qty=2 check). EntriesPerDirection=2 restored but not backtested. | CRITICAL | S2-05 | +| GAP-002 | orbRangeTicks not wired in DailyBarContext (hardcoded 0.0 in SimpleORBNT8.OnBarUpdate) | LOW | Sprint 3 | +| GAP-003 | Risk parameter consistency: RiskPerTrade can exceed MaxTradeRisk silently. No assertion. | HIGH | S2-06 | +| GAP-004 | GetRiskStatus() returns hardcoded limit rather than registered strategy config value | LOW | Sprint 3 | +| GAP-005 | No Gitea CI pipeline. Build and test are manual. | MEDIUM | Sprint 3 | +| GAP-006 | No n8n webhook alerts for fills, risk events, connection loss | MEDIUM | Sprint 3 | +| GAP-007 | No walk-forward / out-of-sample validation. All backtests are in-sample. | HIGH | S2-08 | +| GAP-008 | Short-side profitable only in crash regimes. No regime filter. | MEDIUM | Sprint 3 | +| GAP-009 | No tick replay backtest. OnBarClose simulation compresses trade duration. | LOW | Sprint 3 | + +--- + +## Sprint Roadmap + +### Sprint 2 (ACTIVE) — SIM Validation +Goal: 2+ weeks unattended SIM with dual-leg execution confirmed. +Key pending: GAP-001 (runner validation), GAP-003 (risk consistency), GAP-007 (walk-forward). + +### Sprint 3 — Production Hardening +Goal: 30-day SIM clean. CI and alerts wired. +Key work: GAP-004 through GAP-009, VWAPMeanReversion skeleton. + +### Sprint 4 — Live Capital +Gate: 30-day SIM PF > 2.0, max DD < $500. +Key work: Go live 1 NQ contract, OvernightGap strategies, ops runbook. + +### Sprint 5 — ML Inference +Prerequisite: 60 days live data. +Key work: FastAPI /predict, MLSignalFactorCalculator as 11th factor. + +--- + +## Strategy Backlog + +| ID | Strategy | Priority | Notes | +|---|---|---|---| +| STRAT_079 | Liquidity Sweep Reversal | Medium | Potential short-trade improvement | +| STRAT_154 | Overnight Gap Continuation | High | Leverages existing SessionManager | +| STRAT_214 | Overnight Gap Reversion | High | Counter to STRAT_154 | +| LondonORB | London ORB (3:00 AM ET) | Medium | Separate LondonORBNT8 strategy file | +| VWAP-MR | VWAP Mean Reversion | High | Sprint 3 build target | + +--- + +## Backtest Performance Reference + +| Date | Period | Trades | Win% | PF | Net | Config | +|---|---|---|---|---|---|---| +| 2026-03-27 | Jan–Mar 2026 | 20 | 75% | **7.00** | $1,200 | trail=20 ✅ Production config | +| 2026-03-27 | Jan–Mar 2026 | 40 | 75% | 3.69 | $1,075 | trail=12 | +| 2026-03-27 | Mar 2025–Mar 2026 | 148 | 51% | 3.15 | $71,303 | 9 cts experimental | + +Note: 148-trade run used RiskPerTrade=$500 + EntriesPerDirection=1 (runner blocked). Not a production reference. + +--- + +# ARCHIVED BELOW — Original Gap Analysis (2026-02-17, superseded) **Date:** February 17, 2026 **Status:** Post Phase A-B-C NT8 Integration diff --git a/PROJECT_HANDOVER.md b/PROJECT_HANDOVER.md index bcb13ae..399d428 100644 --- a/PROJECT_HANDOVER.md +++ b/PROJECT_HANDOVER.md @@ -1,9 +1,134 @@ -# NT8 SDK Project - Comprehensive Recap & Handover +# NT8-SDK — Project Context & Current State +**Version:** 3.0 | **Date:** 2026-03-27 | **Status:** Sprint 2 Active — SIM Validation -**Document Version:** 2.0 -**Date:** February 16, 2026 -**Current Phase:** Phase 5 Complete -**Project Completion:** ~85% +> This file supersedes the previous PROJECT_HANDOVER.md and is the live source of truth. +> See also: `SPRINT_BOARD.md`, `GAP_ANALYSIS_AND_ROADMAP.md`, `CODING_PATTERNS.md`, `KILOCODE_WORKFLOW.md` +> Full formatted handover: `NT8_SDK_Handover_Package.docx` + +--- + +## 1. What This Is + +NT8-SDK is an institutional-grade algorithmic futures trading system built on NinjaTrader 8. It is not a research prototype — it is production trading software where bugs equal real financial losses. + +The system trades NQ (Nasdaq 100 E-mini futures) using a 30-minute Opening Range Breakout strategy (SimpleORB) with a 10-factor confluence scoring engine that grades each signal A+ through F before allowing execution. A scaler/runner dual-leg architecture captures quick targets on the scaler while the runner trails for extended moves. + +**Division of labor:** Claude handles architecture, diagnosis, and Kilocode prompt design. Kilocode executes ALL code changes. Mo owns strategy direction and go/no-go decisions. + +--- + +## 2. Technology Stack + +| Layer | Technology | Constraint | +|---|---|---| +| Language | C# 5.0 | Hard — NinjaScript compiler limit | +| Framework | .NET Framework 4.8 | Hard — NT8 requirement | +| Platform | NinjaTrader 8 | Hard — execution environment | +| Local repo | `C:\dev\nt8-sdk` | Windows path | +| NT8 deploy | `C:\Users\billy\Documents\NinjaTrader 8\bin\Custom\Strategies\` | Must match source | +| Deploy script | `deployment\deploy-to-nt8.bat` | Creates timestamped backups | +| VCS | Gitea (self-hosted) | `https://git.thehussains.org/mo/nt8-sdk` | +| AI coding | Kilocode | Executes ALL code changes | +| Automation | n8n (self-hosted) | Deferred to Sprint 4 | +| ML inference | Ollama (local) | Deferred to Sprint 5 | + +**Critical C# constraint:** No `$""`, no `?.`, no `=>`, no async/await. Use `string.Format()`, explicit null checks, full method bodies. + +--- + +## 3. Architecture (Top to Bottom) + +``` +SimpleORBNT8.cs NT8 entry point — sets defaults, adds daily bar series, builds DailyBarContext + ↓ +NT8StrategyBase.cs Abstract base — bar routing, session management, kill switch, breakeven, runner + ↓ +SimpleORBStrategy.cs Core signal — ORB detection, 10-factor confluence, _tradeTaken session lock + ↓ +NT8OrderAdapter.cs INT8ExecutionBridge — calls EnterLong/EnterShort/SetStopLoss + ↓ +PortfolioRiskManager.cs Singleton — cross-strategy daily loss + contract cap + ↓ +NinjaTrader 8 Execution, fills, order management +``` + +--- + +## 4. Current Production Parameters (SIM: SimSimple ORB) + +| Parameter | Value | Notes | +|---|---|---| +| Instrument | NQ JUN26 | Primary instrument | +| Bar type | 13-Range bars | | +| BarsRequiredToTrade | 50 | Warm-up guard | +| DailyLossLimit | $1,000 | | +| MaxTradeRisk | $200 | | +| RiskPerTrade | $100 | 2 contracts at current NQ prices | +| MinContracts | 1 | | +| MaxContracts | 3 | | +| MaxOpenPositions | 2 | Scaler + runner | +| EntriesPerDirection | 2 | Scaler slot 1, runner slot 2 | +| MinTradeGrade | 5 (A) | 4 (B) for broad SIM testing | +| EnableShortTrades | False | Long-only until short backtest done | +| BreakevenTriggerTicks | 20 | Tuned from 12 | +| RunnerTrailTicks | 20 | Tuned from 12 | +| OpeningRangeMinutes | 30 | 9:30–10:00 ET | +| StopTicks | 8 | $40 per contract NQ | +| TargetTicks | 16 (dynamic) | Scales with ORB/ATR ratio | + +--- + +## 5. Two-Path Deployment Rule + +Every code change MUST be applied to both: +1. `C:\dev\nt8-sdk\src\NT8.Adapters\Strategies\` (repo source) +2. `C:\Users\billy\Documents\NinjaTrader 8\bin\Custom\Strategies\` (NT8 runtime) + +After deployment, NT8 must recompile: Tools → Edit NinjaScript → open `NT8StrategyBase.cs` → save. + +--- + +## 6. Key Learnings (Hard-Won) + +1. **`State.Historical` guard** — `if (State == State.Realtime && !_realtimeBarSeen) return;` in `ProcessStrategyIntent` allows backtest (Historical), blocks replay burst in live. + +2. **`_realtimeBarSeen` flag** — reset to `false` in `State.Realtime`, set `true` on first bar. Skips catch-up bar on live load to prevent replay burst. + +3. **`EntriesPerDirection = 2`** — required for scaler + runner. Setting to 1 silently blocks the runner with no error. + +4. **`SetStopLoss`/`SetProfitTarget` before `EnterLong`/`EnterShort`** — calling after entry is silently ignored in backtest. + +5. **`Calculate.OnBarClose` backtest** — trades appear to close in under 1 second in logs. NT8 simulation artifact, not a bug. Live trades hold 2–20 minutes. + +6. **NR7 warm-up** — requires 7 daily bars. Warm-up messages (0/7 bars) are correct behavior. + +7. **NT8 never auto-recompiles** — always force recompile after file changes via NinjaScript Editor. + +8. **Dual-path deployment mandatory** — stale deployed files cause phantom bugs where code looks right but behaves wrong. + +9. **`PortfolioRiskManager` is a singleton** — fully implemented, no changes required. Kill switch, daily loss, contract cap all working. + +10. **Sizing formula** — `floor(RiskPerTrade / (StopTicks × $5.00))`. NQ: `$100 / (8 × $5) = 2 contracts`. Always verify `RiskPerTrade <= MaxTradeRisk`. + +--- + +## 7. Validated Backtest Results + +| Date | Period | Trades | Win% | PF | Net | Config | +|---|---|---|---|---|---|---| +| 2026-03-27 | Jan–Mar 2026 | 20 | 75% | **7.00** | $1,200 | 1 ct, trail=20 ✅ Best | +| 2026-03-27 | Jan–Mar 2026 | 40 | 75% | 3.69 | $1,075 | 1 ct, trail=12 | +| 2026-03-27 | Mar 2025–Mar 2026 | 148 | 51% | 3.15 | $71,303 | 9 cts (experimental) | + +The 9-contract run used `RiskPerTrade=$500` — not a production configuration. Runner leg was also blocked (`EntriesPerDirection=1`) for that run. Re-run required after Sprint 2 fixes. + +--- + +## 8. Immediate Next Actions Before Market Open + +1. Run Strategy Analyzer (NQ JUN26, Jan 1 2026 → Mar 27 2026) and confirm `PNL_UPDATE Position=Short Qty=2` in session log — validates runner leg +2. Verify SIM account settings: `RiskPerTrade=$100`, `BreakevenTriggerTicks=20`, `RunnerTrailTicks=20` +3. Only re-enable BX68915-15 after runner validation passes — long-only, `MaxContracts=2`, `DailyLossLimit=$500` --- diff --git a/README.md b/README.md index 44a180b..86e9f96 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,16 @@ +# NT8-SDK — Institutional Algorithmic Futures Trading System + +**See `NT8_SDK_Handover_Package.docx` for the complete milestone handover document.** + +Quick reference docs in repo root: +- `PROJECT_CONTEXT.md` — current state, parameters, key learnings +- `SPRINT_BOARD.md` — active sprint tasks +- `GAP_ANALYSIS_AND_ROADMAP.md` — open gaps and sprint plan +- `CODING_PATTERNS.md` — C# 5.0 rules, NT8 quirks +- `KILOCODE_WORKFLOW.md` — Kilocode prompt template and guardrails + +--- + # NT8 Institutional Trading SDK **Version:** 0.2.0 diff --git a/deployment/Deploy-To-NT8.ps1 b/deployment/Deploy-To-NT8.ps1 index c13c102..73a5660 100644 --- a/deployment/Deploy-To-NT8.ps1 +++ b/deployment/Deploy-To-NT8.ps1 @@ -173,7 +173,7 @@ else { } if (-not $SkipVerification) { - Write-Step "6/6" "Verifying deployment" + Write-Step "6/7" "Verifying deployment" $ok = $true if (-not (Test-Path "$nt8Custom\NT8.Core.dll")) { @@ -195,13 +195,43 @@ if (-not $SkipVerification) { Write-Success "Deployment verification passed" } else { - Write-Step "6/6" "Skipping verification" + Write-Step "6/7" "Skipping verification" +} + +# Step 7: Delete the compiled NinjaScript assembly so NT8 is forced to do a +# full recompile from source on next startup. Without this, NT8 may load a +# stale cached assembly and silently ignore updated .cs files. +Write-Step "7/7" "Invalidating NinjaScript compiled assembly" +$compiledDll = Join-Path $nt8Custom "NinjaTrader.Custom.dll" +$compiledPdb = Join-Path $nt8Custom "NinjaTrader.Custom.pdb" +$compiledXml = Join-Path $nt8Custom "NinjaTrader.Custom.xml" + +$invalidated = 0 +foreach ($artifact in @($compiledDll, $compiledPdb)) { + if (Test-Path $artifact) { + Remove-Item $artifact -Force + Write-Success ("Deleted {0}" -f (Split-Path $artifact -Leaf)) + $invalidated++ + } +} + +if ($invalidated -gt 0) { + Write-Host " NT8 will perform a full recompile on next startup." -ForegroundColor Green + Write-Host " The .xml file is documentation only and was left in place." -ForegroundColor Gray +} else { + Write-Warn "No compiled assembly found to delete (NT8 may not have been run yet)" } $duration = (Get-Date) - $startTime Write-Header "Deployment Complete" Write-Host ("Duration: {0:F1} seconds" -f $duration.TotalSeconds) -Write-Host "Next: Open NinjaTrader 8 -> NinjaScript Editor -> Compile All" +Write-Host "" +Write-Host "NEXT STEPS:" -ForegroundColor Cyan +Write-Host " 1. Start NinjaTrader 8 (full recompile will happen automatically)" -ForegroundColor White +Write-Host " 2. Wait for compilation to complete in the Output window" -ForegroundColor White +Write-Host " 3. Remove and re-add the strategy to the chart" -ForegroundColor White +Write-Host " 4. Verify defaults: BreakevenTriggerTicks=20 RunnerTrailTicks=20 MaxContracts=3" -ForegroundColor White +Write-Host " 5. Confirm NT8 Output shows: StartBehavior=AdoptAccountPosition EntriesPerDirection=2" -ForegroundColor White exit 0 diff --git a/deployment/deploy-to-nt8.bat b/deployment/deploy-to-nt8.bat index e9880ce..2e992a9 100644 --- a/deployment/deploy-to-nt8.bat +++ b/deployment/deploy-to-nt8.bat @@ -147,10 +147,32 @@ echo. echo Deployment complete. echo Backup location: %BACKUP_DIR% echo Manifest file : %MANIFEST_FILE% + echo. -echo Next steps: -echo 1. Open NinjaTrader 8. -echo 2. Open NinjaScript Editor and press F5 (Compile). -echo 3. Verify strategies appear in the Strategies list. +echo Invalidating NinjaScript compiled assembly... +set "COMPILED_DLL=%NT8_CUSTOM%\NinjaTrader.Custom.dll" +set "COMPILED_PDB=%NT8_CUSTOM%\NinjaTrader.Custom.pdb" + +if exist "%COMPILED_DLL%" ( + del /F /Q "%COMPILED_DLL%" + echo [OK] Deleted NinjaTrader.Custom.dll +) else ( + echo [WARN] NinjaTrader.Custom.dll not found - NT8 may not have been run yet +) + +if exist "%COMPILED_PDB%" ( + del /F /Q "%COMPILED_PDB%" + echo [OK] Deleted NinjaTrader.Custom.pdb +) + +echo. +echo ============================================================ +echo NEXT STEPS: +echo 1. Start NinjaTrader 8 (full recompile happens automatically) +echo 2. Wait for compilation to finish in the Output window +echo 3. Remove and re-add the strategy to the chart +echo 4. Verify defaults: BreakevenTriggerTicks=20 RunnerTrailTicks=20 MaxContracts=3 +echo 5. NT8 Output must show: StartBehavior=AdoptAccountPosition EntriesPerDirection=2 +echo ============================================================ exit /b 0 diff --git a/docs/architecture/phase1_sprint_plan.md b/docs/architecture/phase1_sprint_plan.md index f442599..b61961f 100644 --- a/docs/architecture/phase1_sprint_plan.md +++ b/docs/architecture/phase1_sprint_plan.md @@ -1,7 +1,99 @@ -# NT8 Institutional SDK - Phase 1 Sprint Plan +# NT8-SDK — Sprint Board +**Last Updated:** 2026-03-27 | **Active Sprint:** Sprint 2 -## Overview -This document outlines the sprint plan for Phase 1 development of the NT8 Institutional SDK. Phase 1 builds upon the completed Phase 0 foundation to deliver a more complete trading system with Order Management System (OMS), NinjaTrader 8 integration, enhanced risk controls, and market data handling. +--- + +## Sprint 2 — SIM Validation (ACTIVE) +**Goal:** Strategy runs unattended 2+ weeks in SIM with correct dual-leg execution. +**Gate:** Zero unhandled exceptions, both scaler and runner filling (Qty=2 in log), daily loss limit never accidentally triggered. + +| # | Task | Status | Notes | +|---|---|---|---| +| S2-01 | Restore `EntriesPerDirection=2` | ✅ Done | Deployed 2026-03-27 | +| S2-02 | `MaxOpenPositions=2` in SimpleORBNT8 | ✅ Done | Deployed 2026-03-27 | +| S2-03 | `_realtimeBarSeen` replay guard | ✅ Done | Blocks live replay burst, allows backtest | +| S2-04 | `State.Historical` guard in ProcessStrategyIntent | ✅ Done | Restores backtest execution | +| S2-05 | Validate runner leg — Qty=2 in session log | ⬜ Pending | Run backtest after S2-01 | +| S2-06 | Risk parameter consistency validation | ⬜ Pending | Assert RiskPerTrade ≤ MaxTradeRisk | +| S2-07 | SIM unattended run 2+ weeks | ▶ In progress | Started 2026-03-27 | +| S2-08 | Walk-forward backtest split | ⬜ Pending | Mar–Sep 2025 train / Oct–Mar 2026 test | +| S2-09 | BX68915-15 prop firm re-enable | 🔴 Blocked | Gate: S2-05 + S2-07 pass | + +--- + +## Sprint 3 — Production Hardening +**Goal:** 30-day SIM run clean. CI and alerts live. + +| # | Task | Status | Notes | +|---|---|---|---| +| S3-01 | Gitea CI — build + test on push | ⬜ Pending | `.gitea/workflows/build.yml` | +| S3-02 | n8n webhook — fills + risk events | ⬜ Pending | HTTP POST from NT8StrategyBase | +| S3-03 | Fix `GetRiskStatus()` hardcoded limit | ⬜ Pending | Read from registered strategy config | +| S3-04 | `orbRangeTicks` wiring in DailyBarContext | ⬜ Pending | Low priority | +| S3-05 | Short-side regime filter | ⬜ Pending | 20-day MA or VIX-based gate | +| S3-06 | Tick replay validation | ⬜ Pending | 30-day window | +| S3-07 | VWAPMeanReversion strategy skeleton | ⬜ Pending | New IStrategy implementation | + +--- + +## Sprint 4 — Live Capital +**Gate:** 30-day SIM pass rate > 70%, PF > 2.0, max drawdown < $500 + +| # | Task | Status | +|---|---|---| +| S4-01 | Go live 1 NQ contract | ⬜ Pending gate | +| S4-02 | OvernightGapContinuation strategy | ⬜ Pending | +| S4-03 | OvernightGapReversion strategy | ⬜ Pending | +| S4-04 | Ops runbook and emergency procedures | ⬜ Pending | +| S4-05 | Connection loss recovery testing | ⬜ Pending | +| S4-06 | CME holiday filter | ⬜ Pending | + +--- + +## Sprint 5 — ML Inference +**Prerequisite:** 60 days of live trading data. + +| # | Task | +|---|---| +| S5-01 | FastAPI /predict endpoint on Ollama workstation | +| S5-02 | HTTP client in SimpleORBStrategy | +| S5-03 | MLSignalFactorCalculator as IFactorCalculator | +| S5-04 | Feature engineering from live trade history | +| S5-05 | A/B test: with vs without ML factor | + +--- + +## Completed (Historical) + +| Task | Sprint | Completed | +|---|---|---| +| Execute trades in NT8 SIM (execution bridge wired) | Sprint 1 | 2026-03-27 | +| Historical replay burst fix | Sprint 1 | 2026-03-27 | +| NR7 warm-up guard | Phase 4 | 2026-02 | +| 10-factor confluence scoring engine | Phase 4 | 2026-02 | +| PortfolioRiskManager singleton | Phase 4 | 2026-02 | +| Analytics layer (240+ tests) | Phase 5 | 2026-02-16 | +| Breakeven + runner trail logic | Sprint 1 | 2026-03 | +| Connection loss detection | Sprint 1 | 2026-03 | +| File logging + settings export | Sprint 1 | 2026-03 | + +--- + +## Backtest Results History + +| Date | Period | Trades | Win% | PF | Net | Config | +|---|---|---|---|---|---|---| +| 2026-03-27 | Jan–Mar 2026 | 20 | 75% | 7.00 | $1,200 | trail=20, grade=B ✅ Use this | +| 2026-03-27 | Jan–Mar 2026 | 40 | 75% | 3.69 | $1,075 | trail=12, grade=B | +| 2026-03-27 | Mar 2025–Mar 2026 | 148 | 51% | 3.15 | $71,303 | 9 cts experimental | + +**Note:** The 148-trade run used `RiskPerTrade=$500` producing 9 contracts AND had `EntriesPerDirection=1` blocking the runner. Not a production reference. Re-run required post Sprint 2. + +--- +# ARCHIVED BELOW — Phase 1 Sprint Plan (2025-09-15, superseded) + +## Overview (ARCHIVED) +This document originally outlined Phase 1 sprint planning from September 2025. ## Sprint Goals 1. Implement Order Management System (OMS) with smart order routing diff --git a/src/NT8.Adapters/Strategies/NT8StrategyBase.cs b/src/NT8.Adapters/Strategies/NT8StrategyBase.cs index e45f132..3cb1809 100644 --- a/src/NT8.Adapters/Strategies/NT8StrategyBase.cs +++ b/src/NT8.Adapters/Strategies/NT8StrategyBase.cs @@ -182,6 +182,16 @@ namespace NinjaTrader.NinjaScript.Strategies ExitShort("EmergencyFlatten"); } + /// + /// Returns true if the concrete strategy has ForceSessionReset enabled. + /// Override in subclass to expose the NinjaScript parameter value. + /// Default returns false so base class never forces a reset unless overridden. + /// + protected virtual bool GetForceSessionReset() + { + return false; + } + /// /// Create the SDK strategy instance. /// @@ -207,7 +217,7 @@ namespace NinjaTrader.NinjaScript.Strategies MaximumBarsLookBack = MaximumBarsLookBack.TwoHundredFiftySix; OrderFillResolution = OrderFillResolution.Standard; Slippage = 0; - StartBehavior = StartBehavior.WaitUntilFlat; + StartBehavior = StartBehavior.AdoptAccountPosition; TimeInForce = TimeInForce.Gtc; TraceOrders = false; RealtimeErrorHandling = RealtimeErrorHandling.StopCancelClose; @@ -220,7 +230,7 @@ namespace NinjaTrader.NinjaScript.Strategies MaxOpenPositions = 3; RiskPerTrade = 100.0; MinContracts = 1; - MaxContracts = 10; + MaxContracts = 3; EnableKillSwitch = false; EnableVerboseLogging = false; MinTradeGrade = 4; @@ -229,10 +239,10 @@ namespace NinjaTrader.NinjaScript.Strategies EnableLongTrades = true; EnableShortTrades = true; EnableAutoBreakeven = true; - BreakevenTriggerTicks = 12; + BreakevenTriggerTicks = 20; BreakevenOffsetTicks = 1; EnableRunner = true; - RunnerTrailTicks = 12; + RunnerTrailTicks = 20; _killSwitchTriggered = false; _connectionLost = false; } @@ -242,6 +252,14 @@ namespace NinjaTrader.NinjaScript.Strategies { try { + // DIAGNOSTIC: Print actual runtime property values to confirm + // what NT8 loaded vs what SetDefaults specified. + Print(string.Format("[SDK-DIAG] SetDefaults check: BE={0} Trail={1} MaxC={2} SB={3} EPD={4}", + BreakevenTriggerTicks, + RunnerTrailTicks, + MaxContracts, + StartBehavior, + EntriesPerDirection)); InitFileLog(); InitializeSdkComponents(); _sdkInitialized = true; @@ -260,6 +278,18 @@ namespace NinjaTrader.NinjaScript.Strategies else if (State == State.Realtime) { _realtimeBarSeen = false; + + // If ForceSessionReset is enabled, push a reset signal into the SDK strategy + // so _tradeTaken is cleared before any live bar is processed. + // This recovers from replay-burst scenarios where historical bars set _tradeTaken. + if (_sdkStrategy != null && GetForceSessionReset()) + { + var resetParams = new Dictionary(); + resetParams.Add("force_session_reset", true); + _sdkStrategy.SetParameters(resetParams); + Print(string.Format("[SDK] ForceSessionReset: _tradeTaken cleared on live start at {0}", DateTime.Now.ToString("HH:mm:ss"))); + } + WriteSettingsFile(); } else if (State == State.Terminated) @@ -748,9 +778,24 @@ namespace NinjaTrader.NinjaScript.Strategies private BarData ConvertCurrentBar() { + DateTime barTimeEt; + try + { + var centralZone = TimeZoneInfo.FindSystemTimeZoneById("Central Standard Time"); + var easternZone = TimeZoneInfo.FindSystemTimeZoneById("Eastern Standard Time"); + DateTime utcTime = TimeZoneInfo.ConvertTimeToUtc( + DateTime.SpecifyKind(Time[0], DateTimeKind.Unspecified), + centralZone); + barTimeEt = TimeZoneInfo.ConvertTimeFromUtc(utcTime, easternZone); + } + catch + { + barTimeEt = Time[0]; + } + return NT8DataConverter.ConvertBar( Instrument.MasterInstrument.Name, - Time[0], + barTimeEt, Open[0], High[0], Low[0], diff --git a/src/NT8.Adapters/Strategies/SimpleORBNT8.cs b/src/NT8.Adapters/Strategies/SimpleORBNT8.cs index 0326961..2a9c4c7 100644 --- a/src/NT8.Adapters/Strategies/SimpleORBNT8.cs +++ b/src/NT8.Adapters/Strategies/SimpleORBNT8.cs @@ -40,6 +40,10 @@ namespace NinjaTrader.NinjaScript.Strategies [Range(1, 50)] public int StopTicks { get; set; } + [NinjaScriptProperty] + [Display(Name = "Force Session Reset On Start", GroupName = "ORB Strategy", Order = 10)] + public bool ForceSessionReset { get; set; } + [NinjaScriptProperty] [Display(Name = "Profit Target Ticks", GroupName = "ORB Risk", Order = 2)] [Range(1, 100)] @@ -73,10 +77,12 @@ namespace NinjaTrader.NinjaScript.Strategies // Long-only: short trades permanently disabled pending backtest confirmation EnableShortTrades = false; EnableAutoBreakeven = true; - BreakevenTriggerTicks = 12; + BreakevenTriggerTicks = 20; BreakevenOffsetTicks = 1; EnableRunner = true; - RunnerTrailTicks = 12; + RunnerTrailTicks = 20; + ForceSessionReset = false; + StartBehavior = StartBehavior.AdoptAccountPosition; } else if (State == State.Configure) { @@ -105,6 +111,11 @@ namespace NinjaTrader.NinjaScript.Strategies } } + protected override bool GetForceSessionReset() + { + return ForceSessionReset; + } + protected override IStrategy CreateSdkStrategy() { return new SdkSimpleORB(OpeningRangeMinutes, StdDevMultiplier); diff --git a/src/NT8.Strategies/Examples/SimpleORBStrategy.cs b/src/NT8.Strategies/Examples/SimpleORBStrategy.cs index 5d1469d..b06279b 100644 --- a/src/NT8.Strategies/Examples/SimpleORBStrategy.cs +++ b/src/NT8.Strategies/Examples/SimpleORBStrategy.cs @@ -203,7 +203,15 @@ namespace NT8.Strategies.Examples } if (_tradeTaken) + { + if (_logger != null) + _logger.LogDebug( + "SimpleORBStrategy skip: trade already taken for session {0:yyyy-MM-dd}; bar={1:yyyy-MM-dd HH:mm}; symbol={2}", + _currentSessionDate, + bar.Time, + context.Symbol); return null; + } var openingRange = _openingRangeHigh - _openingRangeLow; var volatilityBuffer = openingRange * (_stdDevMultiplier - 1.0); @@ -286,6 +294,15 @@ namespace NT8.Strategies.Examples _tradeTaken = true; + if (_logger != null) + _logger.LogDebug( + "SimpleORBStrategy flag set: tradeTaken={0} session={1:yyyy-MM-dd}; bar={2:yyyy-MM-dd HH:mm}; side={3}; symbol={4}", + _tradeTaken, + _currentSessionDate, + bar.Time, + candidate.Side, + candidate.Symbol); + if (_logger != null && score.Factors != null) { System.Text.StringBuilder sb = new System.Text.StringBuilder(); @@ -347,7 +364,27 @@ namespace NT8.Strategies.Examples /// Parameter map. public void SetParameters(Dictionary parameters) { - // Constructor-bound parameters intentionally remain immutable for deterministic behavior. + if (parameters == null) + return; + + // force_session_reset: clear _tradeTaken and ORB state so a fresh live session + // can trade even if historical replay set _tradeTaken before going realtime. + if (parameters.ContainsKey("force_session_reset")) + { + var val = parameters["force_session_reset"]; + if (val is bool && (bool)val) + { + lock (_lock) + { + _tradeTaken = false; + _openingRangeReady = false; + _openingRangeHigh = Double.MinValue; + _openingRangeLow = Double.MaxValue; + if (_logger != null) + _logger.LogInformation("ForceSessionReset: _tradeTaken cleared, ORB state reset for live session"); + } + } + } } private void EnsureInitialized()