Current state: Strategy builds and loads correctly, passes 240+ tests, backtest (Strategy Analyzer) works but zero trades execute on live/SIM. Root cause identified: NT8OrderAdapter.ExecuteInNT8() is a stub - it logs to an internal list but never calls EnterLong/EnterShort/SetStopLoss/ SetProfitTarget. Fix is ready in TASK_01_WIRE_NT8_EXECUTION.md. Task files added (ready for Kilocode): - TASK_01_WIRE_NT8_EXECUTION.md (CRITICAL - INT8ExecutionBridge + wiring) - TASK_02_EMERGENCY_KILL_SWITCH.md (CRITICAL - kill switch + verbose logging) - TASK_03_WIRE_CIRCUIT_BREAKER.md (HIGH - wire ExecutionCircuitBreaker) Build Status: All 240+ tests passing, zero errors Next: Run Kilocode against TASK_01, TASK_02, TASK_03 in order
230 lines
6.9 KiB
C#
230 lines
6.9 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using NT8.Core.Common.Interfaces;
|
|
using NT8.Core.Common.Models;
|
|
using NT8.Core.Logging;
|
|
using NT8.Core.Risk;
|
|
using NT8.Core.Sizing;
|
|
using NT8.Adapters.NinjaTrader;
|
|
|
|
namespace NT8.Adapters.Wrappers
|
|
{
|
|
/// <summary>
|
|
/// Base wrapper class for NT8 strategies that integrate with the SDK
|
|
/// This is a template that would be extended in actual NT8 strategy files
|
|
/// </summary>
|
|
public abstract class BaseNT8StrategyWrapper
|
|
{
|
|
private readonly object _lock = new object();
|
|
|
|
#region SDK Components
|
|
|
|
protected IStrategy _sdkStrategy;
|
|
protected IRiskManager _riskManager;
|
|
protected IPositionSizer _positionSizer;
|
|
protected NT8Adapter _nt8Adapter;
|
|
protected StrategyConfig _strategyConfig;
|
|
protected ILogger _logger;
|
|
|
|
#endregion
|
|
|
|
#region Properties
|
|
|
|
/// <summary>
|
|
/// Stop loss in ticks
|
|
/// </summary>
|
|
public int StopTicks { get; set; }
|
|
|
|
/// <summary>
|
|
/// Profit target in ticks (optional)
|
|
/// </summary>
|
|
public int TargetTicks { get; set; }
|
|
|
|
/// <summary>
|
|
/// Risk amount per trade in dollars
|
|
/// </summary>
|
|
public double RiskAmount { get; set; }
|
|
|
|
#endregion
|
|
|
|
#region Constructor
|
|
|
|
/// <summary>
|
|
/// Constructor for BaseNT8StrategyWrapper
|
|
/// </summary>
|
|
public BaseNT8StrategyWrapper()
|
|
{
|
|
// Set default values
|
|
StopTicks = 10;
|
|
TargetTicks = 20;
|
|
RiskAmount = 100.0;
|
|
|
|
// Initialize SDK components with default implementations.
|
|
// Derived wrappers can replace these through InitializeSdkComponents.
|
|
_logger = new BasicLogger("BaseNT8StrategyWrapper");
|
|
_riskManager = new BasicRiskManager(_logger);
|
|
_positionSizer = new BasicPositionSizer(_logger);
|
|
|
|
InitializeSdkComponents(_riskManager, _positionSizer, _logger);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Abstract Methods
|
|
|
|
/// <summary>
|
|
/// Create the SDK strategy implementation
|
|
/// </summary>
|
|
protected abstract IStrategy CreateSdkStrategy();
|
|
|
|
#endregion
|
|
|
|
#region Public Methods
|
|
|
|
/// <summary>
|
|
/// Process a bar update (would be called from NT8's OnBarUpdate)
|
|
/// </summary>
|
|
public void ProcessBarUpdate(BarData barData, StrategyContext context)
|
|
{
|
|
if (barData == null)
|
|
throw new ArgumentNullException("barData");
|
|
if (context == null)
|
|
throw new ArgumentNullException("context");
|
|
|
|
try
|
|
{
|
|
StrategyIntent intent;
|
|
|
|
lock (_lock)
|
|
{
|
|
if (_sdkStrategy == null)
|
|
{
|
|
throw new InvalidOperationException("SDK strategy has not been initialized.");
|
|
}
|
|
|
|
intent = _sdkStrategy.OnBar(barData, context);
|
|
}
|
|
|
|
if (intent != null)
|
|
{
|
|
ExecuteIntent(intent, context);
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
if (_logger != null)
|
|
{
|
|
_logger.LogError("Failed processing bar update for {0}: {1}", context.Symbol, ex.Message);
|
|
}
|
|
|
|
throw;
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Private Methods
|
|
|
|
/// <summary>
|
|
/// Initialize SDK components
|
|
/// </summary>
|
|
protected virtual void InitializeSdkComponents(IRiskManager riskManager, IPositionSizer positionSizer, ILogger logger)
|
|
{
|
|
if (riskManager == null)
|
|
throw new ArgumentNullException("riskManager");
|
|
if (positionSizer == null)
|
|
throw new ArgumentNullException("positionSizer");
|
|
if (logger == null)
|
|
throw new ArgumentNullException("logger");
|
|
|
|
_riskManager = riskManager;
|
|
_positionSizer = positionSizer;
|
|
_logger = logger;
|
|
|
|
_nt8Adapter = new NT8Adapter();
|
|
_nt8Adapter.Initialize(_riskManager, _positionSizer);
|
|
|
|
CreateSdkConfiguration();
|
|
|
|
_sdkStrategy = CreateSdkStrategy();
|
|
if (_sdkStrategy == null)
|
|
throw new InvalidOperationException("CreateSdkStrategy returned null.");
|
|
|
|
_sdkStrategy.Initialize(_strategyConfig, null, _logger);
|
|
|
|
_logger.LogInformation("Base NT8 strategy wrapper initialized for symbol {0}", _strategyConfig.Symbol);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Create SDK configuration from parameters
|
|
/// </summary>
|
|
private void CreateSdkConfiguration()
|
|
{
|
|
// Create risk configuration
|
|
var riskConfig = new RiskConfig(
|
|
dailyLossLimit: 500.0,
|
|
maxTradeRisk: RiskAmount,
|
|
maxOpenPositions: 5,
|
|
emergencyFlattenEnabled: true
|
|
);
|
|
|
|
// Create sizing configuration
|
|
var sizingConfig = new SizingConfig(
|
|
method: SizingMethod.FixedDollarRisk,
|
|
minContracts: 1,
|
|
maxContracts: 100,
|
|
riskPerTrade: RiskAmount,
|
|
methodParameters: new Dictionary<string, object>()
|
|
);
|
|
|
|
// Create strategy configuration
|
|
_strategyConfig = new StrategyConfig(
|
|
name: "NT8Strategy",
|
|
symbol: "Unknown",
|
|
parameters: new Dictionary<string, object>(),
|
|
riskSettings: riskConfig,
|
|
sizingSettings: sizingConfig
|
|
);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Execute strategy intent through NT8
|
|
/// </summary>
|
|
private void ExecuteIntent(StrategyIntent intent, StrategyContext context)
|
|
{
|
|
if (intent == null)
|
|
throw new ArgumentNullException("intent");
|
|
if (context == null)
|
|
throw new ArgumentNullException("context");
|
|
|
|
try
|
|
{
|
|
SizingResult sizingResult;
|
|
|
|
lock (_lock)
|
|
{
|
|
if (_positionSizer == null)
|
|
{
|
|
throw new InvalidOperationException("Position sizer has not been initialized.");
|
|
}
|
|
|
|
sizingResult = _positionSizer.CalculateSize(intent, context, _strategyConfig.SizingSettings);
|
|
}
|
|
|
|
_nt8Adapter.ExecuteIntent(intent, sizingResult);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
if (_logger != null)
|
|
{
|
|
_logger.LogError("Failed executing intent for {0}: {1}", intent.Symbol, ex.Message);
|
|
}
|
|
|
|
throw;
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
}
|
|
}
|