Files
nt8-sdk/TASK_01_WIRE_NT8_EXECUTION.md
2026-02-24 15:00:41 -05:00

179 lines
5.7 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Task 1 — Wire NT8OrderAdapter.ExecuteInNT8()
**Priority:** CRITICAL
**Estimated time:** 34 hours
**Blocks:** All backtest and live trading
**Status:** TODO
---
## Problem
`NT8OrderAdapter.ExecuteInNT8()` in `src/NT8.Adapters/NinjaTrader/NT8OrderAdapter.cs` is a stub.
It only logs to an internal list. The actual NT8 calls (`EnterLong`, `EnterShort`, `SetStopLoss`, `SetProfitTarget`) are in a commented-out block and never execute. This is why backtests show zero trades.
---
## What Needs to Change
### File: `src/NT8.Adapters/NinjaTrader/NT8OrderAdapter.cs`
The adapter currently has no reference to the actual NinjaScript `Strategy` object. It needs a way to call NT8 managed order methods. The pattern used by `NT8StrategyBase` is the right model to follow.
**Option A (Recommended):** Inject a callback delegate so the adapter can call NT8 methods without directly holding a NinjaScript reference.
Add a new `INT8ExecutionBridge` interface:
```csharp
// new file: src/NT8.Adapters/NinjaTrader/INT8ExecutionBridge.cs
namespace NT8.Adapters.NinjaTrader
{
/// <summary>
/// Provides NT8OrderAdapter access to NinjaScript execution methods.
/// Implemented by NT8StrategyBase.
/// </summary>
public interface INT8ExecutionBridge
{
/// <summary>Submit a long entry with stop and target.</summary>
void EnterLongManaged(int quantity, string signalName, int stopTicks, int targetTicks, double tickSize);
/// <summary>Submit a short entry with stop and target.</summary>
void EnterShortManaged(int quantity, string signalName, int stopTicks, int targetTicks, double tickSize);
/// <summary>Exit all long positions.</summary>
void ExitLongManaged(string signalName);
/// <summary>Exit all short positions.</summary>
void ExitShortManaged(string signalName);
/// <summary>Flatten the full position immediately.</summary>
void FlattenAll();
}
}
```
Update `NT8OrderAdapter` constructor to accept `INT8ExecutionBridge`:
```csharp
public NT8OrderAdapter(INT8ExecutionBridge bridge)
{
if (bridge == null)
throw new ArgumentNullException("bridge");
_bridge = bridge;
_executionHistory = new List<NT8OrderExecutionRecord>();
}
```
Implement `ExecuteInNT8()`:
```csharp
private void ExecuteInNT8(StrategyIntent intent, SizingResult sizing)
{
if (intent == null)
throw new ArgumentNullException("intent");
if (sizing == null)
throw new ArgumentNullException("sizing");
var signalName = string.Format("SDK_{0}_{1}", intent.Symbol, intent.Side);
if (intent.Side == Common.Models.OrderSide.Buy)
{
_bridge.EnterLongManaged(
sizing.Contracts,
signalName,
intent.StopTicks,
intent.TargetTicks.HasValue ? intent.TargetTicks.Value : 0,
intent.TickSize);
}
else if (intent.Side == Common.Models.OrderSide.Sell)
{
_bridge.EnterShortManaged(
sizing.Contracts,
signalName,
intent.StopTicks,
intent.TargetTicks.HasValue ? intent.TargetTicks.Value : 0,
intent.TickSize);
}
lock (_lock)
{
_executionHistory.Add(new NT8OrderExecutionRecord(
intent.Symbol,
intent.Side,
intent.EntryType,
sizing.Contracts,
intent.StopTicks,
intent.TargetTicks,
DateTime.UtcNow));
}
}
```
### File: `src/NT8.Adapters/Strategies/NT8StrategyBase.cs`
Implement `INT8ExecutionBridge` on `NT8StrategyBase`:
```csharp
public class NT8StrategyBase : Strategy, INT8ExecutionBridge
{
public void EnterLongManaged(int quantity, string signalName, int stopTicks, int targetTicks, double tickSize)
{
SetStopLoss(signalName, CalculationMode.Ticks, stopTicks, false);
if (targetTicks > 0)
SetProfitTarget(signalName, CalculationMode.Ticks, targetTicks);
EnterLong(quantity, signalName);
}
public void EnterShortManaged(int quantity, string signalName, int stopTicks, int targetTicks, double tickSize)
{
SetStopLoss(signalName, CalculationMode.Ticks, stopTicks, false);
if (targetTicks > 0)
SetProfitTarget(signalName, CalculationMode.Ticks, targetTicks);
EnterShort(quantity, signalName);
}
public void ExitLongManaged(string signalName)
{
ExitLong(signalName);
}
public void ExitShortManaged(string signalName)
{
ExitShort(signalName);
}
// FlattenAll already called in NT8 as: this.Account.Flatten(Instrument)
// or: ExitLong(); ExitShort();
public void FlattenAll()
{
ExitLong("EmergencyFlatten");
ExitShort("EmergencyFlatten");
}
}
```
---
## Acceptance Criteria
- [ ] `NT8OrderAdapter` takes `INT8ExecutionBridge` in its constructor
- [ ] `ExecuteInNT8()` calls the bridge (no more commented-out code)
- [ ] `NT8StrategyBase` implements `INT8ExecutionBridge`
- [ ] `OnOrderUpdate()` callback in `NT8OrderAdapter` updates `BasicOrderManager` state (pass the fill back)
- [ ] `verify-build.bat` passes
- [ ] A backtest run on SimpleORBNT8 produces actual trades (not zero)
---
## Files to Create/Modify
| File | Action |
|---|---|
| `src/NT8.Adapters/NinjaTrader/INT8ExecutionBridge.cs` | CREATE |
| `src/NT8.Adapters/NinjaTrader/NT8OrderAdapter.cs` | MODIFY — implement `ExecuteInNT8()`, update constructor |
| `src/NT8.Adapters/Strategies/NT8StrategyBase.cs` | MODIFY — implement `INT8ExecutionBridge` |
---
## Do NOT Change
- `src/NT8.Core/OMS/BasicOrderManager.cs` — the OMS is correct
- `src/NT8.Strategies/Examples/SimpleORBStrategy.cs` — strategy logic is correct
- Any existing test files