5.7 KiB
Task 1 — Wire NT8OrderAdapter.ExecuteInNT8()
Priority: CRITICAL
Estimated time: 3–4 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:
// 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:
public NT8OrderAdapter(INT8ExecutionBridge bridge)
{
if (bridge == null)
throw new ArgumentNullException("bridge");
_bridge = bridge;
_executionHistory = new List<NT8OrderExecutionRecord>();
}
Implement ExecuteInNT8():
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:
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
NT8OrderAdaptertakesINT8ExecutionBridgein its constructorExecuteInNT8()calls the bridge (no more commented-out code)NT8StrategyBaseimplementsINT8ExecutionBridgeOnOrderUpdate()callback inNT8OrderAdapterupdatesBasicOrderManagerstate (pass the fill back)verify-build.batpasses- 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 correctsrc/NT8.Strategies/Examples/SimpleORBStrategy.cs— strategy logic is correct- Any existing test files