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

8.7 KiB

NT8 Strategy Diagnostic Logging Enhancement

For: Kilocode AI Agent
Priority: HIGH
Mode: Code Mode
Estimated Time: 30-40 minutes
Files to Edit: 1 file (NT8StrategyBase.cs)


🎯 Objective

Add comprehensive diagnostic logging to NT8StrategyBase so we can see exactly what's happening during backtesting when zero trades occur. This will help diagnose if the issue is:

  • Strategy not generating intents
  • Risk manager rejecting trades
  • Position sizer issues
  • Data feed issues

🔧 Changes to NT8StrategyBase.cs

Change 1: Enhanced OnBarUpdate logging

Find:

        protected override void OnBarUpdate()
        {
            if (!_sdkInitialized || _sdkStrategy == null)
                return;
            if (CurrentBar < BarsRequiredToTrade)
                return;
            if (Time[0] == _lastBarTime)
                return;

            _lastBarTime = Time[0];

            try
            {
                var barData = ConvertCurrentBar();
                var context = BuildStrategyContext();

                StrategyIntent intent;
                lock (_lock)
                {
                    intent = _sdkStrategy.OnBar(barData, context);
                }

                if (intent != null)
                    ProcessStrategyIntent(intent, context);
            }
            catch (Exception ex)
            {
                if (_logger != null)
                    _logger.LogError("OnBarUpdate failed: {0}", ex.Message);

                Print(string.Format("[SDK ERROR] OnBarUpdate: {0}", ex.Message));
                Log(string.Format("[SDK ERROR] {0}", ex.ToString()), LogLevel.Error);
            }
        }

Replace with:

        protected override void OnBarUpdate()
        {
            if (!_sdkInitialized || _sdkStrategy == null)
            {
                if (CurrentBar == 0)
                    Print(string.Format("[SDK] Not initialized: sdkInit={0}, strategy={1}", 
                        _sdkInitialized, _sdkStrategy != null));
                return;
            }
            
            if (CurrentBar < BarsRequiredToTrade)
            {
                if (CurrentBar == 0)
                    Print(string.Format("[SDK] Waiting for bars: current={0}, required={1}", 
                        CurrentBar, BarsRequiredToTrade));
                return;
            }
            
            if (Time[0] == _lastBarTime)
                return;

            _lastBarTime = Time[0];

            // Log first bar and every 100th bar to show activity
            if (CurrentBar == BarsRequiredToTrade || CurrentBar % 100 == 0)
            {
                Print(string.Format("[SDK] Processing bar {0}: {1} O={2:F2} H={3:F2} L={4:F2} C={5:F2}", 
                    CurrentBar, Time[0].ToString("yyyy-MM-dd HH:mm"), 
                    Open[0], High[0], Low[0], Close[0]));
            }

            try
            {
                var barData = ConvertCurrentBar();
                var context = BuildStrategyContext();

                StrategyIntent intent;
                lock (_lock)
                {
                    intent = _sdkStrategy.OnBar(barData, context);
                }

                if (intent != null)
                {
                    Print(string.Format("[SDK] Intent generated: {0} {1} @ {2}", 
                        intent.Side, intent.Symbol, intent.EntryType));
                    ProcessStrategyIntent(intent, context);
                }
            }
            catch (Exception ex)
            {
                if (_logger != null)
                    _logger.LogError("OnBarUpdate failed: {0}", ex.Message);

                Print(string.Format("[SDK ERROR] OnBarUpdate: {0}", ex.Message));
                Log(string.Format("[SDK ERROR] {0}", ex.ToString()), LogLevel.Error);
            }
        }

Change 2: Enhanced ProcessStrategyIntent logging

Find:

        private void ProcessStrategyIntent(StrategyIntent intent, StrategyContext context)
        {
            var riskDecision = _riskManager.ValidateOrder(intent, context, _riskConfig);
            if (!riskDecision.Allow)
            {
                if (_logger != null)
                    _logger.LogWarning("Intent rejected by risk manager: {0}", riskDecision.RejectReason);
                return;
            }

            var sizingResult = _positionSizer.CalculateSize(intent, context, _sizingConfig);
            if (sizingResult.Contracts < MinContracts)
                return;

            var request = new OmsOrderRequest();
            request.Symbol = intent.Symbol;
            request.Side = MapOrderSide(intent.Side);
            request.Type = MapOrderType(intent.EntryType);
            request.Quantity = sizingResult.Contracts;
            request.LimitPrice = intent.LimitPrice.HasValue ? (decimal?)intent.LimitPrice.Value : null;
            request.StopPrice = null;

            SubmitOrderToNT8(request, intent);
            _ordersSubmittedToday++;
        }

Replace with:

        private void ProcessStrategyIntent(StrategyIntent intent, StrategyContext context)
        {
            Print(string.Format("[SDK] Validating intent: {0} {1}", intent.Side, intent.Symbol));
            
            var riskDecision = _riskManager.ValidateOrder(intent, context, _riskConfig);
            if (!riskDecision.Allow)
            {
                Print(string.Format("[SDK] Risk REJECTED: {0}", riskDecision.RejectReason));
                if (_logger != null)
                    _logger.LogWarning("Intent rejected by risk manager: {0}", riskDecision.RejectReason);
                return;
            }

            Print(string.Format("[SDK] Risk approved"));

            var sizingResult = _positionSizer.CalculateSize(intent, context, _sizingConfig);
            Print(string.Format("[SDK] Position size: {0} contracts (min={1}, max={2})", 
                sizingResult.Contracts, MinContracts, MaxContracts));
            
            if (sizingResult.Contracts < MinContracts)
            {
                Print(string.Format("[SDK] Size too small: {0} < {1}", sizingResult.Contracts, MinContracts));
                return;
            }

            var request = new OmsOrderRequest();
            request.Symbol = intent.Symbol;
            request.Side = MapOrderSide(intent.Side);
            request.Type = MapOrderType(intent.EntryType);
            request.Quantity = sizingResult.Contracts;
            request.LimitPrice = intent.LimitPrice.HasValue ? (decimal?)intent.LimitPrice.Value : null;
            request.StopPrice = null;

            Print(string.Format("[SDK] Submitting order: {0} {1} {2} @ {3}", 
                request.Side, request.Quantity, request.Symbol, request.Type));

            SubmitOrderToNT8(request, intent);
            _ordersSubmittedToday++;
        }

Change 3: Enhanced InitializeSdkComponents logging

Find:

        private void InitializeSdkComponents()
        {
            _logger = new BasicLogger(Name);

            _riskConfig = new RiskConfig(DailyLossLimit, MaxTradeRisk, MaxOpenPositions, true);

Replace with:

        private void InitializeSdkComponents()
        {
            _logger = new BasicLogger(Name);

            Print(string.Format("[SDK] Initializing with: DailyLoss={0:C}, TradeRisk={1:C}, MaxPos={2}", 
                DailyLossLimit, MaxTradeRisk, MaxOpenPositions));

            _riskConfig = new RiskConfig(DailyLossLimit, MaxTradeRisk, MaxOpenPositions, true);

Verification

# Build must succeed
dotnet build src\NT8.Adapters\NT8.Adapters.csproj --configuration Release

# Deploy
.\deployment\Deploy-To-NT8.ps1

Expected in NT8 Output Window after backtest:

[SDK] Initializing with: DailyLoss=$1,000.00, TradeRisk=$200.00, MaxPos=3
[SDK] Simple ORB NT8 initialized successfully
[SDK] Waiting for bars: current=0, required=50
[SDK] Processing bar 50: 2026-02-10 09:30 O=4200.00 H=4210.00 L=4195.00 C=4208.00
[SDK] Processing bar 150: 2026-02-10 12:30 O=4215.00 H=4220.00 L=4210.00 C=4218.00
[SDK] Intent generated: Buy ES @ Market
[SDK] Validating intent: Buy ES
[SDK] Risk approved
[SDK] Position size: 1 contracts (min=1, max=3)
[SDK] Submitting order: Buy 1 ES @ Market

This will show exactly where the strategy is failing.


📋 Git Commit

git add src/NT8.Adapters/Strategies/NT8StrategyBase.cs
git commit -m "feat: Add comprehensive diagnostic logging

- Log initialization parameters
- Log bar processing activity (every 100 bars)
- Log intent generation
- Log risk validation results
- Log position sizing calculations
- Log order submission

Makes it easy to diagnose why strategy isn't trading"

READY FOR KILOCODE - CODE MODE