This commit is contained in:
@@ -1,9 +1,66 @@
|
|||||||
# Coding Patterns — NT8 SDK Required Patterns
|
# Coding Patterns — NT8 SDK Required Patterns
|
||||||
|
**Last Updated:** 2026-03-27
|
||||||
|
|
||||||
All code in the NT8 SDK MUST follow these patterns without exception.
|
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
|
## 1. Thread Safety — Lock Everything Shared
|
||||||
|
|
||||||
Every class with shared state must have a lock object:
|
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 is the authoritative workflow for all development work on NT8-SDK using Kilocode.
|
||||||
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.
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 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
|
## 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.
|
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.
|
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
|
**Date:** February 17, 2026
|
||||||
**Status:** Post Phase A-B-C NT8 Integration
|
**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
|
> This file supersedes the previous PROJECT_HANDOVER.md and is the live source of truth.
|
||||||
**Date:** February 16, 2026
|
> See also: `SPRINT_BOARD.md`, `GAP_ANALYSIS_AND_ROADMAP.md`, `CODING_PATTERNS.md`, `KILOCODE_WORKFLOW.md`
|
||||||
**Current Phase:** Phase 5 Complete
|
> Full formatted handover: `NT8_SDK_Handover_Package.docx`
|
||||||
**Project Completion:** ~85%
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 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
|
# NT8 Institutional Trading SDK
|
||||||
|
|
||||||
**Version:** 0.2.0
|
**Version:** 0.2.0
|
||||||
|
|||||||
@@ -173,7 +173,7 @@ else {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (-not $SkipVerification) {
|
if (-not $SkipVerification) {
|
||||||
Write-Step "6/6" "Verifying deployment"
|
Write-Step "6/7" "Verifying deployment"
|
||||||
$ok = $true
|
$ok = $true
|
||||||
|
|
||||||
if (-not (Test-Path "$nt8Custom\NT8.Core.dll")) {
|
if (-not (Test-Path "$nt8Custom\NT8.Core.dll")) {
|
||||||
@@ -195,13 +195,43 @@ if (-not $SkipVerification) {
|
|||||||
Write-Success "Deployment verification passed"
|
Write-Success "Deployment verification passed"
|
||||||
}
|
}
|
||||||
else {
|
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
|
$duration = (Get-Date) - $startTime
|
||||||
Write-Header "Deployment Complete"
|
Write-Header "Deployment Complete"
|
||||||
Write-Host ("Duration: {0:F1} seconds" -f $duration.TotalSeconds)
|
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
|
exit 0
|
||||||
|
|
||||||
|
|||||||
@@ -147,10 +147,32 @@ echo.
|
|||||||
echo Deployment complete.
|
echo Deployment complete.
|
||||||
echo Backup location: %BACKUP_DIR%
|
echo Backup location: %BACKUP_DIR%
|
||||||
echo Manifest file : %MANIFEST_FILE%
|
echo Manifest file : %MANIFEST_FILE%
|
||||||
|
|
||||||
echo.
|
echo.
|
||||||
echo Next steps:
|
echo Invalidating NinjaScript compiled assembly...
|
||||||
echo 1. Open NinjaTrader 8.
|
set "COMPILED_DLL=%NT8_CUSTOM%\NinjaTrader.Custom.dll"
|
||||||
echo 2. Open NinjaScript Editor and press F5 (Compile).
|
set "COMPILED_PDB=%NT8_CUSTOM%\NinjaTrader.Custom.pdb"
|
||||||
echo 3. Verify strategies appear in the Strategies list.
|
|
||||||
|
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
|
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
|
## Sprint Goals
|
||||||
1. Implement Order Management System (OMS) with smart order routing
|
1. Implement Order Management System (OMS) with smart order routing
|
||||||
|
|||||||
@@ -182,6 +182,16 @@ namespace NinjaTrader.NinjaScript.Strategies
|
|||||||
ExitShort("EmergencyFlatten");
|
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>
|
/// <summary>
|
||||||
/// Create the SDK strategy instance.
|
/// Create the SDK strategy instance.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -207,7 +217,7 @@ namespace NinjaTrader.NinjaScript.Strategies
|
|||||||
MaximumBarsLookBack = MaximumBarsLookBack.TwoHundredFiftySix;
|
MaximumBarsLookBack = MaximumBarsLookBack.TwoHundredFiftySix;
|
||||||
OrderFillResolution = OrderFillResolution.Standard;
|
OrderFillResolution = OrderFillResolution.Standard;
|
||||||
Slippage = 0;
|
Slippage = 0;
|
||||||
StartBehavior = StartBehavior.WaitUntilFlat;
|
StartBehavior = StartBehavior.AdoptAccountPosition;
|
||||||
TimeInForce = TimeInForce.Gtc;
|
TimeInForce = TimeInForce.Gtc;
|
||||||
TraceOrders = false;
|
TraceOrders = false;
|
||||||
RealtimeErrorHandling = RealtimeErrorHandling.StopCancelClose;
|
RealtimeErrorHandling = RealtimeErrorHandling.StopCancelClose;
|
||||||
@@ -220,7 +230,7 @@ namespace NinjaTrader.NinjaScript.Strategies
|
|||||||
MaxOpenPositions = 3;
|
MaxOpenPositions = 3;
|
||||||
RiskPerTrade = 100.0;
|
RiskPerTrade = 100.0;
|
||||||
MinContracts = 1;
|
MinContracts = 1;
|
||||||
MaxContracts = 10;
|
MaxContracts = 3;
|
||||||
EnableKillSwitch = false;
|
EnableKillSwitch = false;
|
||||||
EnableVerboseLogging = false;
|
EnableVerboseLogging = false;
|
||||||
MinTradeGrade = 4;
|
MinTradeGrade = 4;
|
||||||
@@ -229,10 +239,10 @@ namespace NinjaTrader.NinjaScript.Strategies
|
|||||||
EnableLongTrades = true;
|
EnableLongTrades = true;
|
||||||
EnableShortTrades = true;
|
EnableShortTrades = true;
|
||||||
EnableAutoBreakeven = true;
|
EnableAutoBreakeven = true;
|
||||||
BreakevenTriggerTicks = 12;
|
BreakevenTriggerTicks = 20;
|
||||||
BreakevenOffsetTicks = 1;
|
BreakevenOffsetTicks = 1;
|
||||||
EnableRunner = true;
|
EnableRunner = true;
|
||||||
RunnerTrailTicks = 12;
|
RunnerTrailTicks = 20;
|
||||||
_killSwitchTriggered = false;
|
_killSwitchTriggered = false;
|
||||||
_connectionLost = false;
|
_connectionLost = false;
|
||||||
}
|
}
|
||||||
@@ -242,6 +252,14 @@ namespace NinjaTrader.NinjaScript.Strategies
|
|||||||
{
|
{
|
||||||
try
|
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();
|
InitFileLog();
|
||||||
InitializeSdkComponents();
|
InitializeSdkComponents();
|
||||||
_sdkInitialized = true;
|
_sdkInitialized = true;
|
||||||
@@ -260,6 +278,18 @@ namespace NinjaTrader.NinjaScript.Strategies
|
|||||||
else if (State == State.Realtime)
|
else if (State == State.Realtime)
|
||||||
{
|
{
|
||||||
_realtimeBarSeen = false;
|
_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();
|
WriteSettingsFile();
|
||||||
}
|
}
|
||||||
else if (State == State.Terminated)
|
else if (State == State.Terminated)
|
||||||
@@ -748,9 +778,24 @@ namespace NinjaTrader.NinjaScript.Strategies
|
|||||||
|
|
||||||
private BarData ConvertCurrentBar()
|
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(
|
return NT8DataConverter.ConvertBar(
|
||||||
Instrument.MasterInstrument.Name,
|
Instrument.MasterInstrument.Name,
|
||||||
Time[0],
|
barTimeEt,
|
||||||
Open[0],
|
Open[0],
|
||||||
High[0],
|
High[0],
|
||||||
Low[0],
|
Low[0],
|
||||||
|
|||||||
@@ -40,6 +40,10 @@ namespace NinjaTrader.NinjaScript.Strategies
|
|||||||
[Range(1, 50)]
|
[Range(1, 50)]
|
||||||
public int StopTicks { get; set; }
|
public int StopTicks { get; set; }
|
||||||
|
|
||||||
|
[NinjaScriptProperty]
|
||||||
|
[Display(Name = "Force Session Reset On Start", GroupName = "ORB Strategy", Order = 10)]
|
||||||
|
public bool ForceSessionReset { get; set; }
|
||||||
|
|
||||||
[NinjaScriptProperty]
|
[NinjaScriptProperty]
|
||||||
[Display(Name = "Profit Target Ticks", GroupName = "ORB Risk", Order = 2)]
|
[Display(Name = "Profit Target Ticks", GroupName = "ORB Risk", Order = 2)]
|
||||||
[Range(1, 100)]
|
[Range(1, 100)]
|
||||||
@@ -73,10 +77,12 @@ namespace NinjaTrader.NinjaScript.Strategies
|
|||||||
// Long-only: short trades permanently disabled pending backtest confirmation
|
// Long-only: short trades permanently disabled pending backtest confirmation
|
||||||
EnableShortTrades = false;
|
EnableShortTrades = false;
|
||||||
EnableAutoBreakeven = true;
|
EnableAutoBreakeven = true;
|
||||||
BreakevenTriggerTicks = 12;
|
BreakevenTriggerTicks = 20;
|
||||||
BreakevenOffsetTicks = 1;
|
BreakevenOffsetTicks = 1;
|
||||||
EnableRunner = true;
|
EnableRunner = true;
|
||||||
RunnerTrailTicks = 12;
|
RunnerTrailTicks = 20;
|
||||||
|
ForceSessionReset = false;
|
||||||
|
StartBehavior = StartBehavior.AdoptAccountPosition;
|
||||||
}
|
}
|
||||||
else if (State == State.Configure)
|
else if (State == State.Configure)
|
||||||
{
|
{
|
||||||
@@ -105,6 +111,11 @@ namespace NinjaTrader.NinjaScript.Strategies
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override bool GetForceSessionReset()
|
||||||
|
{
|
||||||
|
return ForceSessionReset;
|
||||||
|
}
|
||||||
|
|
||||||
protected override IStrategy CreateSdkStrategy()
|
protected override IStrategy CreateSdkStrategy()
|
||||||
{
|
{
|
||||||
return new SdkSimpleORB(OpeningRangeMinutes, StdDevMultiplier);
|
return new SdkSimpleORB(OpeningRangeMinutes, StdDevMultiplier);
|
||||||
|
|||||||
@@ -203,7 +203,15 @@ namespace NT8.Strategies.Examples
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (_tradeTaken)
|
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;
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
var openingRange = _openingRangeHigh - _openingRangeLow;
|
var openingRange = _openingRangeHigh - _openingRangeLow;
|
||||||
var volatilityBuffer = openingRange * (_stdDevMultiplier - 1.0);
|
var volatilityBuffer = openingRange * (_stdDevMultiplier - 1.0);
|
||||||
@@ -286,6 +294,15 @@ namespace NT8.Strategies.Examples
|
|||||||
|
|
||||||
_tradeTaken = true;
|
_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)
|
if (_logger != null && score.Factors != null)
|
||||||
{
|
{
|
||||||
System.Text.StringBuilder sb = new System.Text.StringBuilder();
|
System.Text.StringBuilder sb = new System.Text.StringBuilder();
|
||||||
@@ -347,7 +364,27 @@ namespace NT8.Strategies.Examples
|
|||||||
/// <param name="parameters">Parameter map.</param>
|
/// <param name="parameters">Parameter map.</param>
|
||||||
public void SetParameters(Dictionary<string, object> parameters)
|
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()
|
private void EnsureInitialized()
|
||||||
|
|||||||
Reference in New Issue
Block a user