This commit is contained in:
@@ -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:
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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`
|
||||
|
||||
---
|
||||
|
||||
|
||||
13
README.md
13
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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -182,6 +182,16 @@ namespace NinjaTrader.NinjaScript.Strategies
|
||||
ExitShort("EmergencyFlatten");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
protected virtual bool GetForceSessionReset()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create the SDK strategy instance.
|
||||
/// </summary>
|
||||
@@ -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<string, object>();
|
||||
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],
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
/// <param name="parameters">Parameter map.</param>
|
||||
public void SetParameters(Dictionary<string, object> 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()
|
||||
|
||||
Reference in New Issue
Block a user