10 Commits

Author SHA1 Message Date
mo
de6e150655 Harden AI agent rules and compile learning workflow 2026-04-05 17:59:34 -04:00
mo
4453ff552a Merge branch 'cleanup/archive-stale-docs' into cleanup/rules 2026-04-05 17:43:07 -04:00
mo
1cd8df759f nnce branch merge
:q!
nnnn branch 'cleanup/docs-governance' into cleanup/rules

:q!
:q!
;q!

nnce	;q!
:q!
2026-04-05 17:41:14 -04:00
mo
2be9c843e5 Archive stale docs and mark historical references 2026-04-05 17:38:35 -04:00
mo
a6ececaf73 Merge branch 'cleanup/docs-governance' into cleanup/archive-stale-docs 2026-04-05 17:30:16 -04:00
mo
ce74f68e54 Establish governance docs as canonical repo context 2026-04-05 17:24:48 -04:00
mo
3ccd3a8bfd Create canonical governance documentation files 2026-04-05 16:54:22 -04:00
mo
e2ea45b58f Normalize line endings (CRLF/LF) 2026-04-05 16:52:09 -04:00
mo
9a28a49292 Pre-cleanup baseline snapshot
Some checks failed
Build and Test / build (push) Has been cancelled
2026-04-05 16:50:18 -04:00
mo
d856f3949d fix: restore EntriesPerDirection=2 and align risk defaults
Some checks failed
Build and Test / build (push) Has been cancelled
- Restore EntriesPerDirection=2 so runner leg can enter alongside scaler.
  Replay burst protection is now handled by the State.Realtime guard in
  ProcessStrategyIntent rather than by limiting entries per direction.

- Set MaxOpenPositions=2 in SimpleORBNT8 to match scaler+runner structure.
  Previous value of 1 caused PortfolioRiskManager to block the runner.

- Confirm RiskPerTrade=100 and MaxContracts=3 as live defaults.
  The /9-contract configuration was a one-off backtest experiment and
  must not be the deployed default.

- _realtimeBarSeen field and OnBarUpdate guard confirmed present and correct.
  ProcessStrategyIntent guard: if (State == State.Realtime && !_realtimeBarSeen)
  allows backtest (State.Historical) to execute normally while blocking
  replay bars in live/SIM mode.

Backtest validation: Jan 2026 - Mar 2026, NQ, trail=20ticks
  PF=7.00, win=75%, avg winner=, avg loser=-, max DD=-
2026-03-29 19:18:29 -04:00
29 changed files with 1105 additions and 797 deletions

BIN
.gitattributes vendored Normal file

Binary file not shown.

View File

@@ -1,204 +1,35 @@
ALWAYS verify with the live Ninjascript reference available on the web at https://developer.ninjatrader.com/docs/desktop before making final edits. # Compile Error Guidance - Reusable Protocol
**Last Updated:** 2026-04-05
This third file confirms a recurrence of CS0246 compiler errors in VWAP_Pro.cs, specifically related to undefined types like ModeType and AnchorModeType.
Apply this protocol for all compile issues.
🔍 CS0246 - "The type or namespace name 'X' could not be found"
Line Column Missing Type ## 1) Verify First
371 28 ModeType - [ ] Verify exact NinjaScript/API signature against official NT8 docs before editing: `https://developer.ninjatrader.com/docs/desktop`.
371 43 AnchorModeType - [ ] Confirm file is in scope before making any change.
391 39 ModeType
391 54 AnchorModeType ## 2) Classify the Error
376 51 ModeType - [ ] Missing type/namespace (e.g., `CS0246`).
✅ How to Fix It - [ ] Invalid override/signature/access modifier (e.g., `CS0115`, `CS0507`).
🔧 1. Define Missing Enums (Recommended Fix) - [ ] Argument mismatch or wrong overload (e.g., `CS1503`).
- [ ] C# language version incompatibility (C# 6+ syntax in C# 5 project).
It seems that ModeType and AnchorModeType are custom enums that were expected to exist in the code but were never declared.
## 3) Apply Smallest Safe Fix
Create a separate file or include this in the same VWAP_Pro.cs file near the top: - [ ] Prefer minimal edits in scoped files only.
- [ ] Fix root cause, not symptom chaining.
public enum ModeType - [ ] Preserve existing architecture/contracts unless task explicitly requires change.
{
Standard, ## 4) Re-Run Verification
Aggressive, - [ ] Run `.\verify-build.bat`.
Conservative - [ ] Run required tests for changed area.
} - [ ] If NinjaScript touched, run NT8 compile check in NinjaScript Editor.
public enum AnchorModeType ## 5) Capture Durable Learning
{ For non-trivial compile failures, add concise entries to:
SessionStart, - [ ] `docs/00-governance/common_failures.md` (error fingerprint + fix).
FixedTime, - [ ] `docs/00-governance/compile_guardrails.md` (prevention rule).
Custom - [ ] `docs/00-governance/patterns_and_antipatterns.md` (good vs bad pattern).
}
## Do Not
- [ ] Do not guess signatures, overloads, enums, or attributes.
Youll need to customize the enum values (Standard, Aggressive, etc.) to match your strategy logic. These names are placeholders based on typical VWAP settings. - [ ] Do not invent placeholder enums/types unless confirmed by domain/task requirements.
- [ ] Do not keep one-off incident dumps in this rule file; store incidents in `common_failures.md`.
🔧 2. OR Add Missing using Directives
If these types exist in another NinjaTrader script or add-on you've imported before, ensure you include the right namespace:
using NinjaTrader.NinjaScript.AddOns.MyVWAPEnums; // Example
But since these errors suggest the types are completely undefined, it's much more likely they are simply not declared anywhere.
🔧 3. Verify File Inclusion in NinjaTrader
If these enums are defined in another file (e.g., VWAPTypes.cs), make sure:
It's saved in the same directory as VWAP_Pro.cs
It's added to the NinjaScript Editor, not just sitting in the file system
You can add it using:
Tools > NinjaScript Editor > Right-click > Add > Existing Item...
🧼 Suggested Organization
If these enums are used across multiple indicators/strategies, you should centralize them:
VWAP_Enums.cs
namespace NinjaTrader.NinjaScript.VWAP
{
public enum ModeType
{
Standard,
Aggressive,
Conservative
}
public enum AnchorModeType
{
SessionStart,
FixedTime,
Custom
}
}
Then use:
using NinjaTrader.NinjaScript.VWAP;
These are occurring in VWAP_Pro.cs, mainly on lines 132134:
Line Error Message (Truncated)
132 Argument 2: cannot convert from 'int' to 'NinjaTrader.Gui.Tools.SimpleFont'
132 Argument 3: cannot convert from 'NinjaTrader.Gui.Tools.SimpleFont' to 'System.Windows.Media.Brush'
133 Same as above
134 Same as above
🔧 Interpretation:
It looks like a method (likely a drawing method like Draw.Text() or Draw.TextFixed()) is being called with the wrong argument types — specifically:
An int is being passed where a SimpleFont is expected.
A SimpleFont is being passed where a Brush is expected.
This suggests that arguments are out of order or misassigned.
✅ Proper Fix
Lets consider the proper usage of Draw.Text() in NinjaTrader 8:
Draw.Text(NinjaScriptBase owner, string tag, bool isAutoScale, string text, int barsAgo, double y, Brush textBrush, SimpleFont font, TextAlignment alignment, Brush outlineBrush, int outlineWidth);
Or for simpler usage:
Draw.Text(this, "tag1", "Hello", 0, Close[0], Brushes.White);
Your issue likely looks like this:
Draw.Text(this, "tag1", true, "Label", 0, 100, 12, someFont, ...);
Where 12 (int) is mistakenly passed as a font or brush, causing the error.
🔧 Corrected Example:
Assuming you want to draw text with a specific font and color:
SimpleFont font = new SimpleFont("Arial", 12);
Draw.Text(this, "tag1", true, "VWAP Label", 0, Close[0], Brushes.White, font, TextAlignment.Center, Brushes.Black, 1);
Brushes.White → text color
font → SimpleFont object
TextAlignment.Center → alignment
Brushes.Black → outline brush
1 → outline width
✅ Steps to Fix:
Replace the integer (e.g., 12) with a SimpleFont:
new SimpleFont("Arial", 12)
Ensure arguments are in the correct order:
Double-check the method signature from the NinjaTrader 8 Help Guide
.
Use Brushes for colors, not fonts.
Summary of Errors:
Line Column Missing Type
403 39 ModeType
403 54 AnchorModeType
408 63 ModeType
408 78 AnchorModeType
367 28 ModeType
✅ Fixes:
These types — ModeType and AnchorModeType — are not recognized. Here are the likely causes and solutions:
🔍 1. Missing using Directive
These types might be defined in a different namespace. If they are from a custom or NinjaTrader add-on:
Fix: Add the appropriate using statement at the top of your file.
Example:
using NinjaTrader.NinjaScript.AddOns.VWAP;
Adjust according to where ModeType and AnchorModeType are defined.
🔍 2. Missing Class Definitions
If they are not in any existing libraries, they might be custom enum types that should be defined in your project but are missing.
Fix: Add enum declarations like these (if applicable):
public enum ModeType
{
Standard,
Aggressive,
Conservative
}
public enum AnchorModeType
{
SessionStart,
FixedTime,
Custom
}
Only do this if you know what the enum values should be. These names are placeholders — you should match them with how your indicator/strategy is designed.

View File

@@ -1,195 +1,33 @@
# Coding Patterns NT8 SDK Required Patterns # Coding Patterns - NT8 SDK Required Patterns
**Last Updated:** 2026-04-05
All code in the NT8 SDK MUST follow these patterns without exception. All production code must use these implementation patterns.
--- ## Scope Discipline and Minimum Diff
- [ ] Edit only files in task scope.
- [ ] Make the smallest safe change that resolves the issue.
- [ ] Do not change interfaces/contracts unless explicitly required.
- [ ] Do not mix functional changes with style-only cleanup.
## 1. Thread Safety — Lock Everything Shared ## C# 5.0 and .NET 4.8 Compatibility
- [ ] Use C# 5.0 syntax only.
- [ ] Avoid C# 6+ features (`$""`, `?.`, `nameof`, expression-bodied members, `out var`, etc.).
- [ ] Keep compatibility with .NET Framework 4.8.
- [ ] Use `string.Format` style logging/messages.
Every class with shared state must have a lock object: ## Core Implementation Patterns
```csharp - [ ] Validate inputs at method entry.
private readonly object _lock = new object(); - [ ] Wrap public method logic in `try/catch` with meaningful logging.
``` - [ ] Protect shared mutable collections/state with `lock (_lock)`.
- [ ] Do not raise events while holding locks.
- [ ] Keep public members documented with XML comments where required by project standards.
Every access to shared `Dictionary`, `List`, `Queue`, or any field touched by multiple threads: ## NinjaScript Coding Patterns (When Applicable)
```csharp - [ ] Keep `OnStateChange` responsibilities separated by state.
// ❌ NEVER - [ ] Guard `OnBarUpdate` by `BarsInProgress` and bar readiness.
_activeOrders[orderId] = status; - [ ] In managed order flow, set stop/target before entry on the same bar.
// ✅ ALWAYS ## Authoritative Rule References (Do Not Duplicate)
lock (_lock) - Syntax constraints: `.kilocode/rules/csharp_50_syntax.md`
{ - NT8 compile and API constraints: `.kilocode/rules/nt8compilespec.md`
_activeOrders[orderId] = status; - Verification commands and gates: `.kilocode/rules/verification_requirements.md`
}
```
### Read-then-write must be atomic
```csharp
// ❌ WRONG — race condition between check and write
if (!_orders.ContainsKey(id))
_orders[id] = newOrder;
// ✅ CORRECT
lock (_lock)
{
if (!_orders.ContainsKey(id))
_orders[id] = newOrder;
}
```
---
## 2. Error Handling — Try-Catch on All Public Methods
```csharp
public ReturnType MethodName(Type parameter)
{
// 1. Validate parameters first
if (parameter == null)
throw new ArgumentNullException("parameter");
// 2. Wrap the main logic
try
{
// Implementation
return result;
}
catch (SpecificException ex)
{
_logger.LogError("Specific failure in MethodName: {0}", ex.Message);
throw;
}
catch (Exception ex)
{
_logger.LogError("Unexpected failure in MethodName: {0}", ex.Message);
throw;
}
}
```
---
## 3. Logging — Always string.Format, Never $""
```csharp
// ❌ NEVER — C# 6 syntax, breaks NT8 compile
_logger.LogInformation($"Order {orderId} filled");
// ✅ ALWAYS
_logger.LogInformation("Order {0} filled", orderId);
_logger.LogWarning("Risk check failed for {0}: {1}", symbol, reason);
_logger.LogError("Exception in {0}: {1}", "MethodName", ex.Message);
_logger.LogCritical("Emergency flatten triggered: {0}", reason);
```
### Log level guide
| Level | When to use |
|---|---|
| `LogTrace` | Entering/exiting methods, fine-grained flow |
| `LogDebug` | State reads, normal data flow |
| `LogInformation` | Important events: order submitted, filled, cancelled |
| `LogWarning` | Recoverable issues: validation failed, limit approaching |
| `LogError` | Failures: exceptions, unexpected states |
| `LogCritical` | System integrity issues: emergency flatten, data corruption |
---
## 4. Events — Never Raise Inside Locks
Raising events inside a lock causes deadlocks when event handlers acquire other locks.
```csharp
// ❌ DEADLOCK RISK
lock (_lock)
{
_state = newState;
OrderStateChanged?.Invoke(this, args); // handler may try to acquire _lock
}
// ✅ CORRECT
OrderState newState;
lock (_lock)
{
newState = CalculateNewState();
_state = newState;
}
// Raise AFTER releasing lock
RaiseOrderStateChanged(orderId, previousState, newState);
```
---
## 5. Constructor — Validate All Dependencies
```csharp
public MyClass(ILogger<MyClass> logger, ISomeDependency dep)
{
if (logger == null)
throw new ArgumentNullException("logger");
if (dep == null)
throw new ArgumentNullException("dep");
_logger = logger;
_dep = dep;
// Initialize collections
_activeOrders = new Dictionary<string, OrderStatus>();
_logger.LogInformation("MyClass initialized");
}
```
---
## 6. XML Documentation — Required on All Public Members
```csharp
/// <summary>
/// Brief one-line description of what this does.
/// </summary>
/// <param name="intent">The trading intent to validate.</param>
/// <param name="context">Current strategy context with account state.</param>
/// <returns>Risk decision indicating allow or reject.</returns>
/// <exception cref="ArgumentNullException">Thrown when intent or context is null.</exception>
public RiskDecision ValidateOrder(StrategyIntent intent, StrategyContext context)
{
...
}
```
---
## 7. NT8-Specific Patterns (NinjaScript)
When writing code that runs inside NinjaTrader (in `NT8.Adapters/`):
```csharp
// Always guard OnBarUpdate
protected override void OnBarUpdate()
{
if (BarsInProgress != 0) return;
if (CurrentBar < BarsRequiredToTrade) return;
// ...
}
// Managed order pattern — set stops BEFORE entry
SetStopLoss("SignalName", CalculationMode.Ticks, stopTicks, false);
SetProfitTarget("SignalName", CalculationMode.Ticks, targetTicks);
EnterLong(contracts, "SignalName");
// Use string.Format for Print() too
Print(string.Format("Order submitted: {0} contracts at {1}", qty, price));
```
---
## 8. Checklist Before Marking Any Method Complete
- [ ] Parameter null checks at the top
- [ ] `try-catch` wrapping the body
- [ ] All `Dictionary`/collection access inside `lock (_lock)`
- [ ] All logging uses `string.Format()` (no `$""`)
- [ ] XML `/// <summary>` on every public method, property, class
- [ ] No C# 6+ syntax
- [ ] Events raised outside lock blocks
- [ ] `verify-build.bat` passes

View File

@@ -1,243 +1,46 @@
# NT8 Institutional SDK - Development Workflow # NT8-SDK Development Workflow
**Last Updated:** 2026-04-05
## Overview Operational workflow for Kilo/Codex-assisted development.
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.
## Archon Workflow Principles ## Per-Task Workflow (Required)
1. **Confirm scope**
- [ ] Confirm exact files allowed by task spec.
- [ ] Cross-check `.kilocode/rules/file_boundaries.md`.
2. **Set task state**
- [ ] Move task status from `todo` -> `doing` before edits.
3. **Implement**
- [ ] Make minimum-diff changes only in scoped files.
4. **Verify**
- [ ] Run `.\verify-build.bat` per `.kilocode/rules/verification_requirements.md`.
- [ ] Run focused tests required by changed area.
5. **NT8 compile/deploy checks** (when NinjaScript files are touched)
- [ ] Validate signatures against official NT8 docs.
- [ ] Run repo build/deploy sequence required for NT8.
- [ ] Compile in NinjaScript Editor (authoritative NT8 check).
6. **Documentation updates**
- [ ] Update `docs/00-governance/active_work.md` when task status or blockers changed.
- [ ] Update `docs/00-governance/roadmap.md` when sequencing/scope changed.
- [ ] Update `docs/00-governance/decisions.md` when durable architecture decisions were made.
- [ ] Update `CLEANUP_LOG.md` when cleanup debt status changed.
7. **Compile-learning capture** (if any compile issue occurred)
- [ ] Add prevention rule to `docs/00-governance/compile_guardrails.md`.
- [ ] Add error fingerprint + fix to `docs/00-governance/common_failures.md`.
- [ ] Add pattern/anti-pattern to `docs/00-governance/patterns_and_antipatterns.md`.
8. **Set task state and report**
- [ ] Move task status from `doing` -> `review`.
- [ ] Report changed files and verification evidence.
The development process follows these core principles adapted from the Archon workflow: ## Definition of Done (Required)
- [ ] Only scoped files changed.
- [ ] Verification gates passed.
- [ ] NT8 compile checks completed when relevant.
- [ ] Relevant governance docs updated.
- [ ] Compile learnings captured when applicable.
- [ ] Task moved to `review` with evidence.
### 1. Check Current Task ## Out-of-Scope Safety
Before beginning any work, clearly define what needs to be accomplished: - [ ] Do not modify files outside task scope.
- Review requirements and specifications - [ ] Do not apply opportunistic refactors.
- Understand success criteria - [ ] Do not modify historical/contextual docs unless explicitly requested.
- Identify dependencies and blockers - [ ] If a real fix needs out-of-scope changes, stop and report a scope blocker.
### 2. Research for Task
Conduct thorough research before implementation:
- Review existing code and documentation
- Understand best practices and patterns
- Identify potential challenges and solutions
### 3. Implement the Task
Execute the implementation with focus and precision:
- Follow established patterns and conventions
- Write clean, maintainable code
- Include comprehensive error handling
- Add structured logging for observability
### 4. Update Task Status
Track progress and document completion:
- Mark tasks as completed in the todo list
- Document any issues or deviations
- Note lessons learned for future reference
### 5. Get Next Task
Move systematically through the implementation:
- Prioritize tasks based on dependencies
- Focus on one task at a time
- Ensure quality before moving forward
## Development Process
### Phase 1: Planning and Design
1. Review specifications and requirements
2. Create architecture diagrams and documentation
3. Identify core components and their interactions
4. Plan implementation approach and timeline
### Phase 2: Environment Setup
1. Create project structure and configuration files
2. Set up build and test infrastructure
3. Configure CI/CD pipeline
4. Verify development environment
### Phase 3: Core Implementation
1. Implement core interfaces and models
2. Develop risk management components
3. Create position sizing algorithms
4. Build supporting utilities and helpers
### Phase 4: Testing and Validation
1. Create comprehensive unit tests
2. Implement integration tests
3. Run validation scripts
4. Verify all success criteria
### Phase 5: Documentation and Delivery
1. Create developer documentation
2. Write user guides and examples
3. Prepare release notes
4. Conduct final validation
## Code Quality Standards
### 1. Code Structure
- Follow established naming conventions
- Use consistent formatting and style
- Organize code into logical modules
- Maintain clear separation of concerns
### 2. Error Handling
- Validate all inputs and parameters
- Provide meaningful error messages
- Handle exceptions gracefully
- Log errors for debugging
### 3. Testing
- Write unit tests for all public methods
- Include edge case testing
- Validate error conditions
- Maintain >90% code coverage
### 4. Documentation
- Include XML documentation for all public APIs
- Add inline comments for complex logic
- Document configuration options
- Provide usage examples
## Git Workflow
### Branching Strategy
- Use feature branches for all development
- Create branches from main for new features
- Keep feature branches short-lived
- Merge to main after review and testing
### Commit Guidelines
- Write clear, descriptive commit messages
- Make small, focused commits
- Reference issues or tasks in commit messages
- Squash related commits before merging
### Pull Request Process
- Create PRs for all feature work
- Include description of changes and testing
- Request review from team members
- Address feedback before merging
## Development Environment
### Required Tools
- .NET 6.0 SDK
- Visual Studio Code or Visual Studio
- Git for version control
- Docker Desktop (recommended)
### Recommended Extensions
- C# for Visual Studio Code
- EditorConfig for VS Code
- GitLens for enhanced Git experience
- Docker extension for container management
## Build and Test Process
### Local Development
1. Restore NuGet packages: `dotnet restore`
2. Build solution: `dotnet build`
3. Run tests: `dotnet test`
4. Run specific test categories if needed
### Continuous Integration
- Automated builds on every commit
- Run full test suite on each build
- Generate code coverage reports
- Deploy to test environments
## Debugging and Troubleshooting
### Common Issues
1. **Build Failures**
- Check for missing NuGet packages
- Verify .NET SDK version
- Ensure all projects reference correct frameworks
2. **Test Failures**
- Review test output for specific errors
- Check test data and setup
- Verify mock configurations
3. **Runtime Errors**
- Check logs for error details
- Validate configuration settings
- Review dependency injection setup
### Debugging Tools
- Visual Studio debugger
- Console logging
- Structured logging with correlation IDs
- Performance profiling tools
## Release Process
### Versioning
- Follow semantic versioning (MAJOR.MINOR.PATCH)
- Increment version in Directory.Build.props
- Update release notes with changes
- Tag releases in Git
### Deployment
- Create NuGet packages for SDK components
- Publish to internal package repository
- Update documentation with release notes
- Notify stakeholders of new releases
## Best Practices
### 1. Code Reviews
- Review all code before merging
- Focus on correctness, maintainability, and performance
- Provide constructive feedback
- Ensure adherence to coding standards
### 2. Performance Considerations
- Minimize allocations in hot paths
- Use efficient data structures
- Cache expensive operations
- Profile performance regularly
### 3. Security
- Validate all inputs
- Sanitize user data
- Protect sensitive configuration
- Follow secure coding practices
### 4. Maintainability
- Write self-documenting code
- Use meaningful variable and method names
- Keep methods small and focused
- Refactor regularly to improve design
## Task Management Without Archon
Since we're not using the Archon MCP server, we'll manage tasks using:
1. **Todo Lists**: Track progress using markdown checklists
2. **Documentation**: Maintain detailed records of implementation decisions
3. **Git**: Use commits and branches to track work progress
4. **Issue Tracking**: Use GitHub Issues or similar for task management
### Task Status Tracking
- **Todo**: Task identified but not started
- **In Progress**: Actively working on task
- **Review**: Task completed, awaiting validation
- **Done**: Task validated and completed
## Communication and Collaboration
### Team Coordination
- Hold regular standups to discuss progress
- Use collaborative tools for communication
- Document architectural decisions
- Share knowledge and best practices
### Knowledge Sharing
- Conduct code walkthroughs for complex features
- Create technical documentation
- Share lessons learned from issues
- Mentor new team members
## Conclusion
This development workflow ensures consistent, high-quality implementation of the NT8 Institutional SDK. By following these principles and practices, we can deliver a robust, maintainable, and scalable trading platform that meets institutional requirements for risk management and performance.
The workflow emphasizes systematic progress, quality assurance, and continuous improvement. Each task should be approached with thorough research, careful implementation, and comprehensive validation to ensure the highest quality outcome.

View File

@@ -0,0 +1,31 @@
# Governance Docs Maintenance Policy
**Last Updated:** 2026-04-05
## Canonical Source Rule
- [ ] `docs/00-governance/*` is the canonical planning and execution source.
- [ ] Prefer updating canonical governance docs over duplicating guidance elsewhere.
## Historical/Contextual Docs (Read-Only by Default)
Treat these as non-canonical unless explicitly requested by task scope:
- `README.md`
- `docs/README.md`
- `PROJECT_HANDOVER.md`
- `DESIGNED_VS_IMPLEMENTED_GAP_ANALYSIS.md`
- `docs/INDEX.md`
## Update Triggers
- [ ] Update `docs/00-governance/active_work.md` when priorities, status, blockers, or ownership change.
- [ ] Update `docs/00-governance/roadmap.md` when milestone sequence, scope, or timing changes.
- [ ] Update `docs/00-governance/decisions.md` when durable architecture tradeoffs/decisions are made.
- [ ] Update `CLEANUP_LOG.md` when cleanup debt is created, resolved, or deferred.
## Compile Knowledge Capture (Concise and Durable)
When a compile issue occurs, record:
- [ ] Prevention rule in `docs/00-governance/compile_guardrails.md`.
- [ ] Error fingerprint + fix in `docs/00-governance/common_failures.md`.
- [ ] Reusable pattern and anti-pattern in `docs/00-governance/patterns_and_antipatterns.md`.
## Documentation Hygiene
- [ ] Keep entries concise, actionable, and dated.
- [ ] Link to authoritative rules instead of duplicating long guidance.
- [ ] Do not update unrelated docs in the same task.

View File

@@ -0,0 +1,35 @@
# NinjaScript Guardrails - Operational Checklist
**Last Updated:** 2026-04-05
Use this checklist whenever touching NinjaScript-facing files.
## Pre-Edit Checks (Required)
- [ ] Confirm file is in task scope and allowed by `.kilocode/rules/file_boundaries.md`.
- [ ] Verify exact API signatures against official NT8 docs: `https://developer.ninjatrader.com/docs/desktop`.
- [ ] Confirm C# 5.0 compatibility using `.kilocode/rules/csharp_50_syntax.md`.
## Lifecycle and Safety Rules (Required)
- [ ] Use `OnStateChange` correctly: `State.SetDefaults`, `State.Configure`, `State.DataLoaded`.
- [ ] Keep runtime logic out of `SetDefaults` and `Configure`.
- [ ] Guard `OnBarUpdate` for series and readiness (`BarsInProgress`, `CurrentBar`/`CurrentBars`).
- [ ] In managed order flow, set stop/target before entry on the same bar.
- [ ] Do not mix managed and unmanaged order models unless explicitly required.
## API Integrity Rules (Required)
- [ ] Do not guess method signatures, enum members, attributes, or overloads.
- [ ] Do not use unsupported attributes (example: `[Optimizable]`).
- [ ] Do not invent placeholder types/enums unless explicitly confirmed by task/domain requirements.
## Compile Validation Sequence
- [ ] Run `.\verify-build.bat`.
- [ ] Run required deploy step when NinjaScript source must be synced to NT8.
- [ ] Compile in NT8 NinjaScript Editor (authoritative NinjaScript compile gate).
## Compile Failure Learning Loop
If any compile issue occurs:
- [ ] Capture error fingerprint (`code`, file, line, root cause).
- [ ] Apply the smallest safe fix and re-run validation sequence.
- [ ] Record durable learning in:
- `docs/00-governance/common_failures.md` (symptom + fix)
- `docs/00-governance/compile_guardrails.md` (preventive rule)
- `docs/00-governance/patterns_and_antipatterns.md` (good vs bad pattern)

View File

@@ -1,96 +1,45 @@
# Project Context NT8 SDK (Production Hardening Phase) # Project Context - NT8 SDK
**Last Updated:** 2026-04-05
You are working on the **NT8 SDK** — an institutional-grade algorithmic trading framework for NinjaTrader 8. Mission: ship safe, compile-stable NT8 trading software with strict scope control and durable governance documentation.
This is production trading software. Bugs cause real financial losses.
--- ## Session Start (Mandatory)
- [ ] Read these files first, in order:
1. `docs/00-governance/executive_summary.md`
2. `docs/00-governance/current_status.md`
3. `docs/00-governance/active_work.md`
4. `docs/00-governance/architecture.md`
5. `docs/00-governance/roadmap.md`
- [ ] Treat `docs/00-governance/*` as canonical for current direction.
## What Is Already Built (Do Not Touch) ## Historical/Contextual Sources (Non-Canonical)
Use only for background unless explicitly requested in task scope:
- `README.md`
- `docs/README.md`
- `PROJECT_HANDOVER.md`
- `DESIGNED_VS_IMPLEMENTED_GAP_ANALYSIS.md`
- `docs/INDEX.md`
All core trading logic is complete and has 240+ passing tests: ## File Touch Scope (Hard Rules)
- [ ] Modify only files explicitly listed in the task spec.
- [ ] Do not edit adjacent files for cleanup or style-only changes.
- [ ] If a required fix is outside scope, stop and record a scope blocker.
- [ ] Respect `.kilocode/rules/file_boundaries.md` at all times.
| Layer | Status | Key Files | ## Conversation Separation (Hard Rules)
|---|---|---| - [ ] Strategy conversations: entry/exit logic and behavior.
| Risk (Tier 1-3) | ✅ Complete | `src/NT8.Core/Risk/` | - [ ] Architecture conversations: cross-component design and interfaces.
| Position Sizing | ✅ Complete | `src/NT8.Core/Sizing/` | - [ ] Coding conversations: implementation details and diffs.
| OMS / Order Lifecycle | ✅ Complete | `src/NT8.Core/OMS/` | - [ ] Do not mix decisions across tracks; record architecture decisions in `docs/00-governance/decisions.md`.
| Intelligence | ✅ Complete | `src/NT8.Core/Intelligence/` |
| Analytics | ✅ Complete | `src/NT8.Core/Analytics/` |
| Execution Utilities | ✅ Complete | `src/NT8.Core/Execution/` |
| Market Data | ✅ Complete | `src/NT8.Core/MarketData/` |
**NT8 Order Execution is ALREADY WIRED.** ## Documentation Sync Triggers
`NT8StrategyBase.SubmitOrderToNT8()` calls `EnterLong`, `EnterShort`, `SetStopLoss`, and Update governance docs as part of normal task completion:
`SetProfitTarget` directly. The execution path works end-to-end. Do not re-implement it. - [ ] Update `docs/00-governance/active_work.md` when current priorities, status, blockers, or ownership change.
- [ ] Update `docs/00-governance/roadmap.md` when milestone sequence, scope, or timing changes.
- [ ] Update `docs/00-governance/decisions.md` when a durable tradeoff or architecture decision is made.
- [ ] Update `CLEANUP_LOG.md` when cleanup debt is created, resolved, or deferred.
--- ## Compatibility and Safety Baselines
- [ ] C# 5.0 only (`.kilocode/rules/csharp_50_syntax.md`).
## What You Are Fixing (The Active Task List) - [ ] NT8 compile safety (`.kilocode/rules/ninjascript_guardrails.md`, `.kilocode/rules/nt8compilespec.md`).
- [ ] Verification gates (`.kilocode/rules/verification_requirements.md`).
### CRITICAL — `NT8StrategyBase.cs`
**Gap 1 — No kill switch**
`NT8StrategyBase` has no `EnableKillSwitch` NinjaScript parameter and no early-exit in `OnBarUpdate()`.
A runaway strategy cannot be stopped without killing NinjaTrader.
**Fix:** Add `EnableKillSwitch` (bool NinjaScript property) and `EnableVerboseLogging` property.
Add kill switch check as the FIRST thing in `OnBarUpdate()`.
→ See `TASK-01-kill-switch.md`
**Gap 2 — `ExecutionCircuitBreaker` not wired**
`src/NT8.Core/Execution/ExecutionCircuitBreaker.cs` is complete and tested.
It is never instantiated. Orders submit regardless of latency or rejection conditions.
**Fix:** Instantiate in `InitializeSdkComponents()`, gate orders in `SubmitOrderToNT8()`, wire rejections in `OnOrderUpdate()`.
→ See `TASK-02-circuit-breaker.md`
### HIGH — `TrailingStopManager.cs`
**Gap 3 — Placeholder stop math returns zero**
`CalculateNewStopPrice()` FixedTrailing branch: `marketPrice - (x - x)` = always zero movement.
ATRTrailing and Chandelier also have meaningless placeholder formulas.
**Fix:** Replace with real calculations using `TrailingStopConfig.TrailingAmountTicks` and `AtrMultiplier`.
→ See `TASK-03-trailing-stop.md`
### HIGH — `BasicLogger.cs`
**Gap 4 — No log-level filter**
Every log statement writes to console unconditionally. Cannot suppress debug noise in production.
**Fix:** Add `MinimumLevel` property (defaults to `Information`). Suppress messages below threshold.
→ See `TASK-04-log-level.md`
### MEDIUM — `SessionManager.cs`
**Gap 5 — No holiday awareness**
`IsRegularTradingHours()` checks session times only. Will attempt to trade on Christmas, Thanksgiving, etc.
**Fix:** Add static CME holiday set for 2025/2026. Return `false` on those dates.
→ See `TASK-05-session-holidays.md`
---
## Architecture (Read Before Touching Anything)
```
SimpleORBStrategy.OnBar()
↓ returns StrategyIntent
NT8StrategyBase.OnBarUpdate()
↓ [TASK-01: kill switch check here, first]
↓ calls ProcessStrategyIntent()
↓ calls _riskManager.ValidateOrder()
↓ calls _positionSizer.CalculateSize()
↓ calls SubmitOrderToNT8()
↓ [TASK-02: circuit breaker gate here]
↓ calls EnterLong/EnterShort/SetStopLoss/SetProfitTarget (already works)
NT8 callbacks → OnOrderUpdate / OnExecutionUpdate
↓ [TASK-02: record rejections in circuit breaker here]
```
---
## Technology Constraints
- **C# 5.0 only** — no `$""`, no `?.`, no `=>` on methods/properties, no `nameof()`, no `out var`
- **.NET Framework 4.8** — not .NET Core/5+/6+
- **NinjaScript managed orders** — `EnterLong`, `EnterShort`, `SetStopLoss`, `SetProfitTarget`
- `string.Format()` everywhere, never string interpolation
- All `Dictionary`, `HashSet` access inside `lock (_lock)` blocks
- XML doc comments on all public members
- `try/catch` on all public methods with `LogError` in the catch

View File

@@ -1,4 +1,75 @@
# Designed vs. Implemented Features - Gap Analysis > ⚠️ HISTORICAL — see docs/00-governance/ for current state
This file may contain outdated or mixed historical information.
Canonical current-state documentation lives in docs/00-governance/.
This file is retained for history/reference only.
# 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 | JanMar 2026 | 20 | 75% | **7.00** | $1,200 | trail=20 ✅ Production config |
| 2026-03-27 | JanMar 2026 | 40 | 75% | 3.69 | $1,075 | trail=12 |
| 2026-03-27 | Mar 2025Mar 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

View File

@@ -1,9 +1,140 @@
# NT8 SDK Project - Comprehensive Recap & Handover > ⚠️ HISTORICAL — see docs/00-governance/ for current state
**Document Version:** 2.0 This file may contain outdated or mixed historical information.
**Date:** February 16, 2026 Canonical current-state documentation lives in docs/00-governance/.
**Current Phase:** Phase 5 Complete This file is retained for history/reference only.
**Project Completion:** ~85%
# NT8-SDK — Project Context & Current State
**Version:** 3.0 | **Date:** 2026-03-27 | **Status:** Sprint 2 Active — SIM Validation
> 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:3010: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 220 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 | JanMar 2026 | 20 | 75% | **7.00** | $1,200 | 1 ct, trail=20 ✅ Best |
| 2026-03-27 | JanMar 2026 | 40 | 75% | 3.69 | $1,075 | 1 ct, trail=12 |
| 2026-03-27 | Mar 2025Mar 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`
--- ---

View File

@@ -1,3 +1,18 @@
> 📋 NOTE — This README is under revision. See docs/00-governance/ for current architecture and status.
# 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

View File

@@ -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

View File

@@ -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

View File

@@ -0,0 +1,22 @@
# Governance Cleanup Log
## 2026-04-05
- Established `docs/00-governance/` as canonical governance entry point.
- Added concise governance baseline documents:
- `executive_summary.md`
- `architecture.md`
- `current_status.md`
- `roadmap.md`
- `active_work.md`
- Updated onboarding guidance in `.kilocode/rules/project_context.md` to point new sessions to governance docs first.
- Reclassified `PROJECT_HANDOVER.md` and `DESIGNED_VS_IMPLEMENTED_GAP_ANALYSIS.md` as historical/contextual references, not primary truth.
- No code files modified and no file moves performed.
- Moved `docs/PHASE2_COMPLETION_REPORT.md` to `docs/archive/phase-history/PHASE2_COMPLETION_REPORT.md`.
- Added historical header + archival note block to:
- `docs/README.md`
- `PROJECT_HANDOVER.md`
- `DESIGNED_VS_IMPLEMENTED_GAP_ANALYSIS.md`
- `docs/INDEX.md`
- `docs/archive/phase-history/PHASE2_COMPLETION_REPORT.md`
- Added a softer revision note to `README.md` instead of a historical warning.
- Marked `docs/INDEX.md` historical in place because it currently misdirects navigation.

View File

@@ -0,0 +1,17 @@
# Active Work
## Current Execution Focus
- Validate runner-leg dual-fill behavior in Strategy Analyzer/session logs.
- Close remaining Sprint 2 hardening items already identified in task specs.
- Preserve strict compile and deployment verification sequence for every change.
## In-Scope Hardening Themes
- Strategy safety controls and execution circuit-breaker wiring.
- Trailing stop calculation correctness.
- Logging verbosity controls for production noise reduction.
- Session/holiday awareness to avoid invalid trading windows.
## Working Rules
- Apply changes only to explicitly scoped files per task.
- Keep NT8 API signatures and managed-order sequencing exact.
- Maintain C# 5.0 compatibility and existing interface boundaries.

View File

@@ -0,0 +1,28 @@
# Architecture Governance
## Runtime Flow (Authoritative)
```
SimpleORBNT8.cs
-> NT8StrategyBase.cs
-> SimpleORBStrategy.cs
-> NT8OrderAdapter.cs
-> PortfolioRiskManager.cs
-> NinjaTrader 8
```
## Responsibilities
- `SimpleORBNT8.cs`: NT8 entry point and platform lifecycle bridge.
- `NT8StrategyBase.cs`: orchestration, risk gate sequencing, execution handoff, platform callbacks.
- `SimpleORBStrategy.cs`: signal generation and confluence grading only.
- `NT8OrderAdapter.cs`: execution bridge to NT8 managed order APIs.
- `PortfolioRiskManager.cs`: cross-strategy risk controls and account-level enforcement.
## Architectural Constraints
- Risk-first flow is mandatory; no strategy-level bypass of risk validation.
- Managed-order sequence remains required (`SetStopLoss` / `SetProfitTarget` before entry).
- C# 5.0 syntax only, .NET Framework 4.8 only.
- NT8 signatures must be verified against official NinjaTrader docs before API-touching edits.
## Governance Notes
- Core Risk/Sizing/OMS/Intelligence/Analytics layers are treated as complete and stable unless explicitly re-opened by approved work.
- Hardening changes are concentrated in targeted adapter/utility components per active-work scope.

View File

@@ -0,0 +1,33 @@
# Common Compile Failures
**Last Updated:** 2026-04-05
Record concise error fingerprints and verified fixes.
## Entry Template
- **Date:** YYYY-MM-DD
- **Error:** `CSXXXX`
- **Fingerprint:** file + line + short symptom
- **Root cause:** one sentence
- **Fix:** one to three concrete steps
- **Prevention link:** guardrail/pattern doc entry added
## Starter Examples
1. **`CS0115` no suitable method found to override**
- Root cause: incorrect NT8 override signature.
- Fix: replace with exact official signature; recompile.
2. **`CS0507` cannot change access modifiers when overriding**
- Root cause: used `public override`/`private override` instead of `protected override`.
- Fix: change to `protected override`; recompile.
3. **`CS0246` type or namespace not found**
- Root cause: missing using/namespace or undefined domain type.
- Fix: add correct namespace reference or confirmed type definition.
4. **`CS1503` argument type mismatch**
- Root cause: wrong overload or argument ordering.
- Fix: align call with exact method signature and parameter types.
5. **C# 6+ syntax in C# 5 project**
- Root cause: use of `$""`, `?.`, `nameof`, expression-bodied members, etc.
- Fix: rewrite using C# 5 compatible constructs.

View File

@@ -0,0 +1,20 @@
# Compile Guardrails
**Last Updated:** 2026-04-05
Preventive rules to reduce repeat compile failures.
## Core Prevention Rules
- [ ] Verify NT8 signatures in official docs before adding/changing any `protected override`.
- [ ] Keep NinjaScript edits within task scope and allowed file boundaries.
- [ ] Enforce C# 5.0 syntax only; reject C# 6+ constructs.
- [ ] Keep managed order sequence correct (stop/target before entry on same bar).
- [ ] Guard `OnBarUpdate` by `BarsInProgress` and bar readiness.
- [ ] Do not use unsupported attributes/types/enums without confirmation.
## Verification Gates
- [ ] Run `.\verify-build.bat` after changes.
- [ ] Run focused tests for changed area.
- [ ] If NinjaScript touched, compile in NT8 NinjaScript Editor.
## Update Rule
- [ ] Add a new guardrail entry whenever a compile issue reveals a missing prevention rule.

View File

@@ -0,0 +1,20 @@
# Current Status
## Snapshot (2026-04-05)
- Program phase: Sprint 2 SIM validation with production-hardening follow-through.
- Core implementation: complete across major layers with 240+ passing tests.
- Live focus: execution safety, validation depth, and operational reliability.
## Confirmed Working Areas
- End-to-end strategy pipeline from signal -> risk -> sizing -> NT8 managed execution.
- Session handling, portfolio risk controls, and base strategy orchestration.
- Existing analytics/risk/sizing/OMS foundations remain stable.
## Open Findings Driving Work
- Runner leg behavior requires explicit validation evidence (`Qty=2` path confirmation).
- Risk/config consistency checks need tightening in runtime safeguards.
- Operational controls (CI automation, alerting, and out-of-sample validation) remain pending.
## Operational Reality
- `dotnet build` success is necessary but not sufficient; NT8 NinjaScript compile remains a separate required validation step.
- Deployment integrity requires keeping repo and NT8 runtime strategy copies synchronized.

View File

View File

@@ -0,0 +1,20 @@
# Executive Summary
## Scope
- This folder (`docs/00-governance/`) is the canonical governance source for project state, priorities, architecture intent, and active execution guidance.
- Governance is aligned to Sprint 2 (SIM validation) with production hardening gaps tracked and prioritized.
## Current Position (2026-04-05)
- Core engine is implemented with 240+ passing tests across core components.
- NT8 execution path is wired and validated in SIM for baseline operation.
- Remaining work is focused on closing operational hardening gaps and validating runner behavior under production-like conditions.
## Approved Direction
- Keep execution in managed-order NT8 patterns and C# 5.0 / .NET Framework 4.8 constraints.
- Complete critical and high-priority hardening tasks before expanding strategy scope.
- Treat historical handover artifacts as context only; governance decisions flow from this folder.
## Immediate Priorities
- Confirm runner-leg dual-fill behavior in analyzer/session logs.
- Close safety and observability items already identified in Sprint 2/3 gap tracking.
- Maintain strict file-boundary and compile-guardrail discipline for all changes.

View File

@@ -0,0 +1,36 @@
# Patterns and Anti-Patterns
**Last Updated:** 2026-04-05
Capture recurring implementation patterns that impact compile stability.
## Pattern Entry Template
- **Context:** where this applies
- **Good pattern:** concise example/description
- **Anti-pattern:** concise example/description
- **Why it matters:** one sentence
## Starter Patterns
1. **NT8 override signatures**
- Good pattern: copy exact signature from official NT8 docs before coding.
- Anti-pattern: infer or copy from outdated examples.
- Why it matters: prevents `CS0115` and runtime integration drift.
2. **Access modifier on overrides**
- Good pattern: use `protected override` for NT8 lifecycle/event methods.
- Anti-pattern: `public override` or `private override`.
- Why it matters: prevents `CS0507`.
3. **C# 5 compatibility discipline**
- Good pattern: `string.Format`, explicit null checks, block-bodied members.
- Anti-pattern: string interpolation, null-conditional, expression-bodied members.
- Why it matters: prevents avoidable language-version compile failures.
4. **Managed order sequencing**
- Good pattern: set stop/target before entry on the same bar.
- Anti-pattern: entry first, then stop/target.
- Why it matters: avoids silent behavior defects and rejected assumptions.
5. **Scope-first fixes**
- Good pattern: smallest safe change in scoped files only.
- Anti-pattern: broad cleanup or adjacent-file edits during bugfix.
- Why it matters: reduces regression risk and review churn.

View File

@@ -0,0 +1,21 @@
# Roadmap
## Sprint 2 (Active): SIM Validation
- Validate dual-leg execution behavior with log evidence.
- Complete remaining safety/consistency fixes tied to active gap list.
- Exit criteria: stable SIM behavior with no unresolved critical gaps.
## Sprint 3: Production Hardening
- Implement CI build/test automation and operational alerting.
- Complete lower-priority runtime consistency and observability improvements.
- Add walk-forward and broader validation coverage beyond in-sample checks.
## Sprint 4: Live Capital Readiness
- Gate on sustained SIM metrics and drawdown controls.
- Introduce go-live runbook and operational controls for controlled capital exposure.
## Sprint 5: ML Extension (Deferred)
- Add inference integration only after sufficient live/sim data and stable production operations.
## Sequencing Rule
- No feature expansion ahead of unresolved safety and validation gates.

View File

@@ -1,3 +1,10 @@
> ⚠️ HISTORICAL — see docs/00-governance/ for current state
This file may contain outdated or mixed historical information.
Canonical current-state documentation lives in docs/00-governance/.
This file is retained for history/reference only.
Navigation links in this file may be stale or broken.
# NT8 SDK - Documentation Index # NT8 SDK - Documentation Index
**Complete documentation for the NT8 Institutional Trading SDK** **Complete documentation for the NT8 Institutional Trading SDK**

View File

@@ -1,3 +1,9 @@
> ⚠️ HISTORICAL — see docs/00-governance/ for current state
This file may contain outdated or mixed historical information.
Canonical current-state documentation lives in docs/00-governance/.
This file is retained for history/reference only.
# NT8 Institutional Trading SDK # NT8 Institutional Trading SDK
**Version:** 0.2.0 **Version:** 0.2.0

View File

@@ -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 | MarSep 2025 train / OctMar 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 | JanMar 2026 | 20 | 75% | 7.00 | $1,200 | trail=20, grade=B ✅ Use this |
| 2026-03-27 | JanMar 2026 | 40 | 75% | 3.69 | $1,075 | trail=12, grade=B |
| 2026-03-27 | Mar 2025Mar 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

View File

@@ -1,3 +1,9 @@
> ⚠️ HISTORICAL — see docs/00-governance/ for current state
This file may contain outdated or mixed historical information.
Canonical current-state documentation lives in docs/00-governance/.
This file is retained for history/reference only.
# Phase 2 Completion Report # Phase 2 Completion Report
**Project:** NT8 Institutional Trading SDK **Project:** NT8 Institutional Trading SDK

View File

@@ -54,6 +54,11 @@ namespace NinjaTrader.NinjaScript.Strategies
private DateTime _lastBarTime; private DateTime _lastBarTime;
private bool _killSwitchTriggered; private bool _killSwitchTriggered;
private bool _connectionLost; private bool _connectionLost;
private bool _realtimeBarSeen;
private bool _breakevenMoved;
private string _scalerSignalName;
private string _runnerSignalName;
private bool _runnerActive;
private ExecutionCircuitBreaker _circuitBreaker; private ExecutionCircuitBreaker _circuitBreaker;
private System.IO.StreamWriter _fileLog; private System.IO.StreamWriter _fileLog;
private readonly object _fileLock = new object(); private readonly object _fileLock = new object();
@@ -117,6 +122,29 @@ namespace NinjaTrader.NinjaScript.Strategies
[Display(Name = "Enable Short Trades", GroupName = "Trade Direction", Order = 2)] [Display(Name = "Enable Short Trades", GroupName = "Trade Direction", Order = 2)]
public bool EnableShortTrades { get; set; } public bool EnableShortTrades { get; set; }
[NinjaScriptProperty]
[Display(Name = "Enable Auto Breakeven", GroupName = "Exit Management", Order = 1)]
public bool EnableAutoBreakeven { get; set; }
[NinjaScriptProperty]
[Display(Name = "Breakeven Trigger Ticks", GroupName = "Exit Management", Order = 2)]
[Range(1, 100)]
public int BreakevenTriggerTicks { get; set; }
[NinjaScriptProperty]
[Display(Name = "Breakeven Offset Ticks", GroupName = "Exit Management", Order = 3)]
[Range(0, 20)]
public int BreakevenOffsetTicks { get; set; }
[NinjaScriptProperty]
[Display(Name = "Enable Runner", GroupName = "Exit Management", Order = 4)]
public bool EnableRunner { get; set; }
[NinjaScriptProperty]
[Display(Name = "Runner Trail Ticks", GroupName = "Exit Management", Order = 5)]
[Range(4, 100)]
public int RunnerTrailTicks { get; set; }
#endregion #endregion
// INT8ExecutionBridge implementation // INT8ExecutionBridge implementation
@@ -154,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>
@@ -171,7 +209,7 @@ namespace NinjaTrader.NinjaScript.Strategies
Description = "SDK-integrated strategy base"; Description = "SDK-integrated strategy base";
// Name intentionally not set - this is an abstract base class // Name intentionally not set - this is an abstract base class
Calculate = Calculate.OnBarClose; Calculate = Calculate.OnBarClose;
EntriesPerDirection = 1; EntriesPerDirection = 2;
EntryHandling = EntryHandling.AllEntries; EntryHandling = EntryHandling.AllEntries;
IsExitOnSessionCloseStrategy = true; IsExitOnSessionCloseStrategy = true;
ExitOnSessionCloseSeconds = 30; ExitOnSessionCloseSeconds = 30;
@@ -179,12 +217,12 @@ 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;
StopTargetHandling = StopTargetHandling.PerEntryExecution; StopTargetHandling = StopTargetHandling.PerEntryExecution;
BarsRequiredToTrade = 50; BarsRequiredToTrade = 1;
EnableSDK = true; EnableSDK = true;
DailyLossLimit = 1000.0; DailyLossLimit = 1000.0;
@@ -192,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;
@@ -200,6 +238,11 @@ namespace NinjaTrader.NinjaScript.Strategies
LogDirectory = string.Empty; LogDirectory = string.Empty;
EnableLongTrades = true; EnableLongTrades = true;
EnableShortTrades = true; EnableShortTrades = true;
EnableAutoBreakeven = true;
BreakevenTriggerTicks = 20;
BreakevenOffsetTicks = 1;
EnableRunner = true;
RunnerTrailTicks = 20;
_killSwitchTriggered = false; _killSwitchTriggered = false;
_connectionLost = false; _connectionLost = false;
} }
@@ -209,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;
@@ -226,6 +277,19 @@ namespace NinjaTrader.NinjaScript.Strategies
} }
else if (State == State.Realtime) 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(); WriteSettingsFile();
} }
else if (State == State.Terminated) else if (State == State.Terminated)
@@ -243,6 +307,22 @@ namespace NinjaTrader.NinjaScript.Strategies
if (BarsInProgress != 0) if (BarsInProgress != 0)
return; return;
// Require 7 completed daily bars before allowing any signal.
// NarrowRangeFactorCalculator needs 7 daily bars for NR7 scoring.
// Without this guard, NR7 silently returns its floor score (0.3)
// which may suppress trades via the MinTradeGrade confluence gate.
if (BarsArray != null && BarsArray.Length > 1
&& CurrentBars != null && CurrentBars.Length > 1
&& CurrentBars[1] < 7)
{
// Always print warm-up status — visible in Strategy Analyzer output
// to confirm how many daily bars are available on a given backtest range.
if (CurrentBar % 20 == 0)
Print(String.Format("[SDK] Daily warm-up: {0}/7 bars — waiting for NR7 history. Extend backtest start date or add pre-load days.",
CurrentBars[1] + 1));
return;
}
if (!_sdkInitialized || _sdkStrategy == null) if (!_sdkInitialized || _sdkStrategy == null)
{ {
return; return;
@@ -256,8 +336,25 @@ namespace NinjaTrader.NinjaScript.Strategies
if (Time[0] == _lastBarTime) if (Time[0] == _lastBarTime)
return; return;
if (Time[0].Date != _lastBarTime.Date && _lastBarTime != DateTime.MinValue)
{
_runnerActive = false;
_breakevenMoved = false;
_scalerSignalName = null;
_runnerSignalName = null;
}
_lastBarTime = Time[0]; _lastBarTime = Time[0];
// Mark first bar seen after going realtime. Until this fires, we're
// processing catch-up replay bars and must not submit orders.
if (State == State.Realtime && !_realtimeBarSeen)
{
_realtimeBarSeen = true;
Print(string.Format("[SDK] First realtime bar seen: {0}", Time[0]));
return;
}
// Sync actual open position to portfolio manager on every bar // Sync actual open position to portfolio manager on every bar
PortfolioRiskManager.Instance.UpdateOpenContracts(Name, Math.Abs(Position.Quantity)); PortfolioRiskManager.Instance.UpdateOpenContracts(Name, Math.Abs(Position.Quantity));
@@ -329,6 +426,50 @@ namespace NinjaTrader.NinjaScript.Strategies
Close[0])); Close[0]));
} }
// --- Breakeven and runner trailing monitor ---
if (_runnerActive && !string.IsNullOrEmpty(_runnerSignalName) && Position.Quantity != 0)
{
double entryPrice = Position.AveragePrice;
double currentClose = Close[0];
bool isLong = Position.MarketPosition == MarketPosition.Long;
double profitTicks = isLong
? (currentClose - entryPrice) / TickSize
: (entryPrice - currentClose) / TickSize;
// Move runner stop to breakeven + offset once trigger is reached
if (EnableAutoBreakeven && !_breakevenMoved && profitTicks >= BreakevenTriggerTicks)
{
double bePrice = isLong
? entryPrice + (BreakevenOffsetTicks * TickSize)
: entryPrice - (BreakevenOffsetTicks * TickSize);
SetStopLoss(_runnerSignalName, CalculationMode.Price, bePrice, false);
_breakevenMoved = true;
Print(String.Format("[SDK] Runner breakeven set at {0:F2} (profit={1:F0} ticks)",
bePrice, profitTicks));
if (EnableFileLogging)
FileLog(String.Format("BREAKEVEN runner stop -> {0:F2} profit={1:F0}ticks",
bePrice, profitTicks));
}
// Activate trailing stop on runner once breakeven is secured
if (_breakevenMoved && RunnerTrailTicks > 0)
{
SetTrailStop(_runnerSignalName, CalculationMode.Ticks, RunnerTrailTicks, false);
}
}
// Clear runner state when flat
if (Position.Quantity == 0 && _runnerActive)
{
_runnerActive = false;
_breakevenMoved = false;
if (EnableFileLogging && !string.IsNullOrEmpty(_runnerSignalName))
FileLog("RUNNER closed — position flat");
}
try try
{ {
var barData = ConvertCurrentBar(); var barData = ConvertCurrentBar();
@@ -427,7 +568,7 @@ namespace NinjaTrader.NinjaScript.Strategies
} }
protected override void OnPositionUpdate( protected override void OnPositionUpdate(
Position position, NinjaTrader.Cbi.Position position,
double averagePrice, double averagePrice,
int quantity, int quantity,
MarketPosition marketPosition) MarketPosition marketPosition)
@@ -442,7 +583,7 @@ namespace NinjaTrader.NinjaScript.Strategies
{ {
try try
{ {
dayPnL = Account.Get(AccountItem.GainLoss, Currency.UsDollar); dayPnL = Account.Get(AccountItem.RealizedProfitLoss, Currency.UsDollar);
} }
catch catch
{ {
@@ -637,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],
@@ -761,6 +917,11 @@ namespace NinjaTrader.NinjaScript.Strategies
private void ProcessStrategyIntent(StrategyIntent intent, StrategyContext context) private void ProcessStrategyIntent(StrategyIntent intent, StrategyContext context)
{ {
// In live/SIM: block if we haven't seen a genuine realtime bar yet (replay guard).
// In Strategy Analyzer (State.Historical): always allow — backtest must execute normally.
if (State == State.Realtime && !_realtimeBarSeen)
return;
// Portfolio-level risk check — runs before per-strategy risk validation // Portfolio-level risk check — runs before per-strategy risk validation
var portfolioDecision = PortfolioRiskManager.Instance.ValidatePortfolioRisk(Name, intent); var portfolioDecision = PortfolioRiskManager.Instance.ValidatePortfolioRisk(Name, intent);
if (!portfolioDecision.Allow) if (!portfolioDecision.Allow)
@@ -840,30 +1001,36 @@ namespace NinjaTrader.NinjaScript.Strategies
private void SubmitOrderToNT8(OmsOrderRequest request, StrategyIntent intent) private void SubmitOrderToNT8(OmsOrderRequest request, StrategyIntent intent)
{ {
// Circuit breaker gate if (State != State.Historical)
if (State == State.Historical)
{ {
// Skip circuit breaker during backtest — wall-clock timeout is meaningless on historical data. if (_circuitBreaker != null && !_circuitBreaker.ShouldAllowOrder())
}
else if (_circuitBreaker != null && !_circuitBreaker.ShouldAllowOrder())
{ {
var state = _circuitBreaker.GetState(); var cbState = _circuitBreaker.GetState();
Print(string.Format("[SDK] Circuit breaker OPEN — order blocked: {0}", state.Reason)); Print(String.Format("[SDK] Circuit breaker OPEN — order blocked: {0}", cbState.Reason));
if (_logger != null) if (_logger != null)
_logger.LogWarning("Circuit breaker blocked order: {0}", state.Reason); _logger.LogWarning("Circuit breaker blocked order: {0}", cbState.Reason);
return; return;
} }
}
try try
{ {
var orderName = string.Format("SDK_{0}_{1}", intent.Symbol, Guid.NewGuid().ToString("N").Substring(0, 12)); bool useRunner = EnableRunner && request.Quantity >= 2;
int scalerQty = useRunner ? request.Quantity - 1 : request.Quantity;
int runnerQty = useRunner ? 1 : 0;
string baseId = Guid.NewGuid().ToString("N").Substring(0, 12);
_scalerSignalName = String.Format("SDK_{0}_S_{1}", intent.Symbol, baseId);
_runnerSignalName = useRunner ? String.Format("SDK_{0}_R_{1}", intent.Symbol, baseId) : null;
_breakevenMoved = false;
_runnerActive = useRunner;
if (EnableFileLogging) if (EnableFileLogging)
{ {
string grade = "N/A"; string grade = "N/A";
string score = "N/A"; string score = "N/A";
string factors = string.Empty; string factors = string.Empty;
if (intent.Metadata != null && intent.Metadata.ContainsKey("confluence_score")) if (intent.Metadata != null && intent.Metadata.ContainsKey("confluence_score"))
{ {
var cs = intent.Metadata["confluence_score"] as NT8.Core.Intelligence.ConfluenceScore; var cs = intent.Metadata["confluence_score"] as NT8.Core.Intelligence.ConfluenceScore;
@@ -871,55 +1038,46 @@ namespace NinjaTrader.NinjaScript.Strategies
{ {
grade = cs.Grade.ToString(); grade = cs.Grade.ToString();
score = cs.WeightedScore.ToString("F3"); score = cs.WeightedScore.ToString("F3");
var sb = new System.Text.StringBuilder(); var sb = new System.Text.StringBuilder();
foreach (var f in cs.Factors) foreach (var f in cs.Factors)
sb.Append(string.Format("{0}={1:F2} ", f.Type, f.Score)); sb.Append(String.Format("{0}={1:F2} ", f.Type, f.Score));
factors = sb.ToString().TrimEnd(); factors = sb.ToString().TrimEnd();
} }
} }
FileLog(String.Format("SIGNAL {0} | Grade={1} | Score={2}", intent.Side, grade, score));
FileLog(string.Format("SIGNAL {0} | Grade={1} | Score={2}", intent.Side, grade, score));
if (!string.IsNullOrEmpty(factors)) if (!string.IsNullOrEmpty(factors))
FileLog(string.Format(" Factors: {0}", factors)); FileLog(String.Format(" Factors: {0}", factors));
FileLog(string.Format("SUBMIT {0} {1} @ Market | Stop={2} Target={3}{4}", FileLog(String.Format("SUBMIT Scaler={0} Runner={1} Stop={2} Target={3}",
intent.Side, scalerQty, runnerQty, intent.StopTicks,
request.Quantity, intent.TargetTicks.HasValue ? intent.TargetTicks.Value.ToString() : "none"));
intent.StopTicks,
intent.TargetTicks,
intent.Metadata != null && intent.Metadata.ContainsKey("dynamic_target_ticks") ? " [dynamic]" : ""));
} }
_executionAdapter.SubmitOrder(request, orderName); // --- Submit scaler leg ---
// Register stop and target BEFORE submitting the entry order.
// NT8 requires stop/target to be pre-registered to the signal name
// so they are applied correctly in both backtest and live/SIM modes.
if (intent.StopTicks > 0) if (intent.StopTicks > 0)
SetStopLoss(orderName, CalculationMode.Ticks, (int)intent.StopTicks, false); SetStopLoss(_scalerSignalName, CalculationMode.Ticks, (int)intent.StopTicks, false);
if (intent.TargetTicks.HasValue && intent.TargetTicks.Value > 0) if (intent.TargetTicks.HasValue && intent.TargetTicks.Value > 0)
SetProfitTarget(orderName, CalculationMode.Ticks, (int)intent.TargetTicks.Value); SetProfitTarget(_scalerSignalName, CalculationMode.Ticks, (int)intent.TargetTicks.Value);
if (request.Side == OmsOrderSide.Buy) if (request.Side == OmsOrderSide.Buy)
EnterLong(scalerQty, _scalerSignalName);
else
EnterShort(scalerQty, _scalerSignalName);
// --- Submit runner leg (no fixed target — exits via trailing stop) ---
if (useRunner)
{ {
if (request.Type == OmsOrderType.Market) if (intent.StopTicks > 0)
EnterLong(request.Quantity, orderName); SetStopLoss(_runnerSignalName, CalculationMode.Ticks, (int)intent.StopTicks, false);
else if (request.Type == OmsOrderType.Limit && request.LimitPrice.HasValue) // No SetProfitTarget on runner — trail stop will manage exit
EnterLongLimit(request.Quantity, (double)request.LimitPrice.Value, orderName);
else if (request.Type == OmsOrderType.StopMarket && request.StopPrice.HasValue) if (request.Side == OmsOrderSide.Buy)
EnterLongStopMarket(request.Quantity, (double)request.StopPrice.Value, orderName); EnterLong(runnerQty, _runnerSignalName);
} else
else if (request.Side == OmsOrderSide.Sell) EnterShort(runnerQty, _runnerSignalName);
{
if (request.Type == OmsOrderType.Market)
EnterShort(request.Quantity, orderName);
else if (request.Type == OmsOrderType.Limit && request.LimitPrice.HasValue)
EnterShortLimit(request.Quantity, (double)request.LimitPrice.Value, orderName);
else if (request.Type == OmsOrderType.StopMarket && request.StopPrice.HasValue)
EnterShortStopMarket(request.Quantity, (double)request.StopPrice.Value, orderName);
} }
_executionAdapter.SubmitOrder(request, _scalerSignalName);
if (_circuitBreaker != null) if (_circuitBreaker != null)
_circuitBreaker.OnSuccess(); _circuitBreaker.OnSuccess();
} }
@@ -927,8 +1085,7 @@ namespace NinjaTrader.NinjaScript.Strategies
{ {
if (_circuitBreaker != null) if (_circuitBreaker != null)
_circuitBreaker.OnFailure(); _circuitBreaker.OnFailure();
Print(String.Format("[SDK] SubmitOrderToNT8 failed: {0}", ex.Message));
Print(string.Format("[SDK] SubmitOrderToNT8 failed: {0}", ex.Message));
if (_logger != null) if (_logger != null)
_logger.LogError("SubmitOrderToNT8 failed: {0}", ex.Message); _logger.LogError("SubmitOrderToNT8 failed: {0}", ex.Message);
throw; throw;

View File

@@ -23,6 +23,8 @@ namespace NinjaTrader.NinjaScript.Strategies
/// </summary> /// </summary>
public class SimpleORBNT8 : NT8StrategyBase public class SimpleORBNT8 : NT8StrategyBase
{ {
private int _lastSignalDirection;
[NinjaScriptProperty] [NinjaScriptProperty]
[Display(Name = "Opening Range Minutes", GroupName = "ORB Strategy", Order = 1)] [Display(Name = "Opening Range Minutes", GroupName = "ORB Strategy", Order = 1)]
[Range(5, 120)] [Range(5, 120)]
@@ -38,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)]
@@ -59,16 +65,24 @@ namespace NinjaTrader.NinjaScript.Strategies
DailyLossLimit = 1000.0; DailyLossLimit = 1000.0;
MaxTradeRisk = 200.0; MaxTradeRisk = 200.0;
MaxOpenPositions = 1; MaxOpenPositions = 2;
RiskPerTrade = 100.0; RiskPerTrade = 100.0;
MinContracts = 1; MinContracts = 1;
MaxContracts = 3; MaxContracts = 3;
Calculate = Calculate.OnBarClose; Calculate = Calculate.OnBarClose;
BarsRequiredToTrade = 50; BarsRequiredToTrade = 50;
MinTradeGrade = 5;
EnableLongTrades = true; EnableLongTrades = true;
// Long-only: short trades permanently disabled pending backtest confirmation // Long-only: short trades permanently disabled pending backtest confirmation
EnableShortTrades = false; EnableShortTrades = false;
EnableAutoBreakeven = true;
BreakevenTriggerTicks = 20;
BreakevenOffsetTicks = 1;
EnableRunner = true;
RunnerTrailTicks = 20;
ForceSessionReset = false;
StartBehavior = StartBehavior.AdoptAccountPosition;
} }
else if (State == State.Configure) else if (State == State.Configure)
{ {
@@ -82,11 +96,24 @@ namespace NinjaTrader.NinjaScript.Strategies
{ {
if (_strategyConfig != null && BarsArray != null && BarsArray.Length > 1) if (_strategyConfig != null && BarsArray != null && BarsArray.Length > 1)
{ {
DailyBarContext dailyContext = BuildDailyBarContext(0, 0.0, (double)Volume[0]); DailyBarContext dailyContext = BuildDailyBarContext(_lastSignalDirection, 0.0, (double)Volume[0]);
_strategyConfig.Parameters["daily_bars"] = dailyContext; _strategyConfig.Parameters["daily_bars"] = dailyContext;
} }
base.OnBarUpdate(); base.OnBarUpdate();
if (Position != null)
{
if (Position.MarketPosition == MarketPosition.Long)
_lastSignalDirection = 1;
else if (Position.MarketPosition == MarketPosition.Short)
_lastSignalDirection = -1;
}
}
protected override bool GetForceSessionReset()
{
return ForceSessionReset;
} }
protected override IStrategy CreateSdkStrategy() protected override IStrategy CreateSdkStrategy()
@@ -160,6 +187,10 @@ namespace NinjaTrader.NinjaScript.Strategies
lines.Insert(endIdx + 6, string.Format("StopDollars : {0:C}", StopTicks * tickDollarValue)); lines.Insert(endIdx + 6, string.Format("StopDollars : {0:C}", StopTicks * tickDollarValue));
lines.Insert(endIdx + 7, string.Format("TargetDollars : {0:C}", TargetTicks * tickDollarValue)); lines.Insert(endIdx + 7, string.Format("TargetDollars : {0:C}", TargetTicks * tickDollarValue));
lines.Insert(endIdx + 8, string.Format("RR_Ratio : {0:F2}:1", (double)TargetTicks / StopTicks)); lines.Insert(endIdx + 8, string.Format("RR_Ratio : {0:F2}:1", (double)TargetTicks / StopTicks));
lines.Insert(endIdx + 9, String.Format("AutoBreakeven : {0} @ {1}ticks + {2}tick offset",
EnableAutoBreakeven, BreakevenTriggerTicks, BreakevenOffsetTicks));
lines.Insert(endIdx + 10, String.Format("Runner : {0} | Trail={1}ticks",
EnableRunner, RunnerTrailTicks));
return lines; return lines;
} }
@@ -225,4 +256,3 @@ namespace NinjaTrader.NinjaScript.Strategies
} }
} }
} }

View File

@@ -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()