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

117 lines
3.6 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 3 — Wire ExecutionCircuitBreaker
**Priority:** HIGH
**Estimated time:** 1.52 hours
**Depends on:** Task 1 (NT8StrategyBase changes)
**Status:** TODO
---
## Problem
`ExecutionCircuitBreaker` in `src/NT8.Core/Execution/ExecutionCircuitBreaker.cs` is a complete, well-tested class.
It is never instantiated or connected to any live order flow. Orders are submitted regardless of latency or rejection conditions.
---
## What Needs to Change
### File: `src/NT8.Adapters/Strategies/NT8StrategyBase.cs`
**Step 1:** Add `ExecutionCircuitBreaker` as a field on `NT8StrategyBase`.
```csharp
private ExecutionCircuitBreaker _circuitBreaker;
```
**Step 2:** Initialize it in `OnStateChange``State.DataLoaded`:
```csharp
// Use Microsoft.Extensions.Logging NullLogger for now (or wire to BasicLogger)
_circuitBreaker = new ExecutionCircuitBreaker(
new NullLogger<ExecutionCircuitBreaker>(),
failureThreshold: 3,
timeout: TimeSpan.FromSeconds(30));
```
**Step 3:** Gate ALL order submissions through the circuit breaker.
In the method that calls `ExecuteIntent()` (or wherever orders flow from strategy intent to the adapter), add:
```csharp
private bool TrySubmitIntent(StrategyIntent intent, StrategyContext context)
{
if (!_circuitBreaker.ShouldAllowOrder())
{
var state = _circuitBreaker.GetState();
Print(string.Format("[NT8-SDK] Circuit breaker OPEN — order blocked. Reason: {0}", state.Reason));
return false;
}
try
{
_orderAdapter.ExecuteIntent(intent, context, _strategyConfig);
_circuitBreaker.OnSuccess();
return true;
}
catch (Exception ex)
{
_circuitBreaker.OnFailure();
_circuitBreaker.RecordOrderRejection(ex.Message);
Print(string.Format("[NT8-SDK] Order execution failed: {0}", ex.Message));
return false;
}
}
```
**Step 4:** Wire `OnOrderUpdate` rejections back to the circuit breaker.
In `NT8StrategyBase.OnOrderUpdate()`:
```csharp
protected override void OnOrderUpdate(Order order, double limitPrice, double stopPrice,
int quantity, int filled, double averageFillPrice,
OrderState orderState, DateTime time, ErrorCode error, string nativeError)
{
if (orderState == OrderState.Rejected)
{
if (_circuitBreaker != null)
{
_circuitBreaker.RecordOrderRejection(
string.Format("NT8 rejected order: {0} {1}", error, nativeError));
}
}
// Pass through to adapter for state tracking
if (_orderAdapter != null)
{
_orderAdapter.OnOrderUpdate(
order != null ? order.Name : "unknown",
limitPrice, stopPrice, quantity, filled,
averageFillPrice,
orderState != null ? orderState.ToString() : "unknown",
time, error.ToString(), nativeError ?? string.Empty);
}
}
```
---
## Acceptance Criteria
- [ ] `ExecutionCircuitBreaker` is instantiated in `NT8StrategyBase`
- [ ] All order submissions go through `_circuitBreaker.ShouldAllowOrder()` — if false, order is blocked and logged
- [ ] NT8 order rejections call `_circuitBreaker.RecordOrderRejection()`
- [ ] 3 consecutive rejections open the circuit breaker (blocks further orders for 30 seconds)
- [ ] After 30 seconds, circuit breaker enters half-open and allows one test order
- [ ] `verify-build.bat` passes
---
## Files to Modify
| File | Action |
|---|---|
| `src/NT8.Adapters/Strategies/NT8StrategyBase.cs` | Add circuit breaker field, initialize, gate submissions, wire rejections |
## Files to NOT Change
- `src/NT8.Core/Execution/ExecutionCircuitBreaker.cs` — complete and correct, do not touch
- Any test files