# TASK-02: Wire ExecutionCircuitBreaker into NT8StrategyBase **File:** `src/NT8.Adapters/Strategies/NT8StrategyBase.cs` **Priority:** CRITICAL **Depends on:** TASK-01 must be done first (file already open/modified) **Estimated time:** 45 min --- ## Background `ExecutionCircuitBreaker` at `src/NT8.Core/Execution/ExecutionCircuitBreaker.cs` is complete and tested. Its public API is: - `bool ShouldAllowOrder()` — returns false when circuit is Open - `void OnSuccess()` — call after a successful order submission - `void OnFailure()` — call after a failed order submission - `void RecordOrderRejection(string reason)` — call when NT8 rejects an order - `void Reset()` — resets to Closed state The `ExecutionCircuitBreaker` constructor: ```csharp public ExecutionCircuitBreaker( ILogger logger, int failureThreshold = 3, TimeSpan? timeout = null, TimeSpan? retryTimeout = null, int latencyWindowSize = 100, int rejectionWindowSize = 10) ``` **Problem:** It is never instantiated. `NT8StrategyBase` submits orders with no circuit breaker gate. --- ## Exact Changes Required ### 1. Add using statement at top of `NT8StrategyBase.cs` ```csharp using NT8.Core.Execution; using Microsoft.Extensions.Logging.Abstractions; ``` ### 2. Add private field alongside the other private fields ```csharp private ExecutionCircuitBreaker _circuitBreaker; ``` ### 3. Initialize in `InitializeSdkComponents()`, after `_positionSizer = new BasicPositionSizer(_logger);` ```csharp _circuitBreaker = new ExecutionCircuitBreaker( NullLogger.Instance, failureThreshold: 3, timeout: TimeSpan.FromSeconds(30)); ``` ### 4. Gate `SubmitOrderToNT8()` — add check at top of the method ```csharp private void SubmitOrderToNT8(OmsOrderRequest request, StrategyIntent intent) { // Circuit breaker gate if (_circuitBreaker != null && !_circuitBreaker.ShouldAllowOrder()) { var state = _circuitBreaker.GetState(); Print(string.Format("[SDK] Circuit breaker OPEN — order blocked: {0}", state.Reason)); if (_logger != null) _logger.LogWarning("Circuit breaker blocked order: {0}", state.Reason); return; } try { // ... EXISTING submit logic unchanged ... var orderName = string.Format("SDK_{0}_{1}", intent.Symbol, DateTime.Now.Ticks); _executionAdapter.SubmitOrder(request, orderName); if (request.Side == OmsOrderSide.Buy) { ... existing EnterLong/EnterLongLimit/etc ... } else if (request.Side == OmsOrderSide.Sell) { ... existing EnterShort/etc ... } if (intent.StopTicks > 0) SetStopLoss(orderName, CalculationMode.Ticks, (int)intent.StopTicks, false); if (intent.TargetTicks.HasValue && intent.TargetTicks.Value > 0) SetProfitTarget(orderName, CalculationMode.Ticks, (int)intent.TargetTicks.Value); // Mark success after submission if (_circuitBreaker != null) _circuitBreaker.OnSuccess(); } catch (Exception ex) { if (_circuitBreaker != null) _circuitBreaker.OnFailure(); Print(string.Format("[SDK] SubmitOrderToNT8 failed: {0}", ex.Message)); if (_logger != null) _logger.LogError("SubmitOrderToNT8 failed: {0}", ex.Message); throw; } } ``` ### 5. Wire rejections in `OnOrderUpdate()` In the existing `OnOrderUpdate()` override, after the null/name checks, add: ```csharp // Record NT8 rejections in circuit breaker if (orderState == NinjaTrader.Cbi.OrderState.Rejected && _circuitBreaker != null) { var reason = string.Format("{0} {1}", errorCode, nativeError ?? string.Empty); _circuitBreaker.RecordOrderRejection(reason); Print(string.Format("[SDK] Order rejected by NT8: {0}", reason)); } ``` --- ## Acceptance Criteria - [ ] `ExecutionCircuitBreaker` is instantiated in `InitializeSdkComponents()` - [ ] `SubmitOrderToNT8()` checks `ShouldAllowOrder()` before submitting — if false, prints message and returns - [ ] `OnOrderUpdate()` calls `RecordOrderRejection()` when `orderState == OrderState.Rejected` - [ ] `OnSuccess()` called after successful order submission - [ ] `OnFailure()` called in catch block - [ ] `verify-build.bat` passes with zero errors - [ ] Existing 240+ tests still pass: `dotnet test NT8-SDK.sln --verbosity minimal` --- ## Do NOT Change - `ExecutionCircuitBreaker.cs` — already correct, just use it - Any Core layer files - Any test files