# NT8 SDK - Architecture Overview **Version:** 0.2.0 **Last Updated:** February 15, 2026 --- ## Table of Contents - [System Architecture](#system-architecture) - [Component Design](#component-design) - [Data Flow](#data-flow) - [Threading Model](#threading-model) - [State Management](#state-management) - [Error Handling](#error-handling) - [Performance Considerations](#performance-considerations) --- ## System Architecture ### High-Level Overview ``` ┌─────────────────────────────────────────────────────────────┐ │ Strategy Layer │ │ ┌──────────────────────────────────────────────────────┐ │ │ │ IStrategy: Signal Generation │ │ │ │ • OnBar() / OnTick() │ │ │ │ • Strategy-specific logic only │ │ │ └──────────────────────────────────────────────────────┘ │ └────────────────────────┬────────────────────────────────────┘ │ StrategyIntent ↓ ┌─────────────────────────────────────────────────────────────┐ │ Risk Layer │ │ ┌──────────────────────────────────────────────────────┐ │ │ │ IRiskManager: Multi-Tier Validation │ │ │ │ • Tier 1: Daily limits, position limits │ │ │ │ • Tier 2: Weekly limits, trailing drawdown │ │ │ │ • Tier 3: Exposure, correlation, time windows │ │ │ └──────────────────────────────────────────────────────┘ │ └────────────────────────┬────────────────────────────────────┘ │ RiskDecision ↓ ┌─────────────────────────────────────────────────────────────┐ │ Sizing Layer │ │ ┌──────────────────────────────────────────────────────┐ │ │ │ IPositionSizer: Contract Quantity Calculation │ │ │ │ • Fixed contracts / Fixed dollar risk │ │ │ │ • Optimal-f (Ralph Vince) │ │ │ │ • Volatility-adjusted (ATR/StdDev) │ │ │ └──────────────────────────────────────────────────────┘ │ └────────────────────────┬────────────────────────────────────┘ │ SizingResult ↓ ┌─────────────────────────────────────────────────────────────┐ │ OMS Layer │ │ ┌──────────────────────────────────────────────────────┐ │ │ │ IOrderManager: Order Lifecycle Management │ │ │ │ • State Machine: Pending → Working → Filled │ │ │ │ • Partial fills, modifications, cancellations │ │ │ │ • Position reconciliation │ │ │ └──────────────────────────────────────────────────────┘ │ └────────────────────────┬────────────────────────────────────┘ │ OrderRequest ↓ ┌─────────────────────────────────────────────────────────────┐ │ NT8 Adapter Layer │ │ ┌──────────────────────────────────────────────────────┐ │ │ │ INT8OrderAdapter: Platform Integration │ │ │ │ • Data conversion (NT8 ↔ SDK) │ │ │ │ • Order submission to NT8 │ │ │ │ • Fill/update callbacks │ │ │ └──────────────────────────────────────────────────────┘ │ └────────────────────────┬────────────────────────────────────┘ │ ↓ ┌───────────────┐ │ NinjaTrader 8 │ └───────────────┘ ``` --- ## Component Design ### Strategy Component **Purpose:** Generate trading signals based on market data **Design Principles:** - Strategies are **pure signal generators** - No direct access to order management or risk - Stateful but isolated - Deterministic for backtesting **Interface:** ```csharp public interface IStrategy { StrategyIntent? OnBar(BarData bar, StrategyContext context); } ``` **Key Characteristics:** - Receives market data and context - Returns trading intent (or null) - No side effects outside internal state - All infrastructure handled by SDK **Example Implementation:** ```csharp public class SimpleORBStrategy : IStrategy { private double _orbHigh, _orbLow; private bool _orbComplete; public StrategyIntent? OnBar(BarData bar, StrategyContext context) { // Update ORB during formation if (!_orbComplete && IsORBPeriod(bar.Time)) { UpdateORB(bar); return null; } // Generate signal after ORB complete if (_orbComplete && bar.Close > _orbHigh) { return new StrategyIntent(/* long signal */); } return null; } } ``` --- ### Risk Management Component **Purpose:** Validate all trading decisions against risk parameters **Architecture:** ``` BasicRiskManager (Tier 1) ├─ Daily loss limits ├─ Per-trade risk caps ├─ Position count limits └─ Emergency flatten ↓ wraps AdvancedRiskManager (Tiers 2-3) ├─ Weekly rolling limits (Tier 2) ├─ Trailing drawdown (Tier 2) ├─ Cross-strategy exposure (Tier 3) ├─ Correlation limits (Tier 3) └─ Time-based windows (Tier 3) ``` **Tier Classification:** | Tier | Purpose | Scope | |------|---------|-------| | **Tier 1** | Core capital protection | Single account, single day | | **Tier 2** | Extended protection | Multi-day, drawdown | | **Tier 3** | Portfolio management | Cross-strategy, correlation | **Validation Flow:** ```csharp public RiskDecision ValidateOrder(StrategyIntent intent, StrategyContext context, RiskConfig config) { // 1. Check Tier 1 (via BasicRiskManager) var tier1 = _basicRiskManager.ValidateOrder(intent, context, config); if (!tier1.Allow) return tier1; // 2. Check Tier 2 if (IsWeeklyLimitBreached()) return Reject("Weekly limit"); if (IsDrawdownExceeded()) return Reject("Drawdown limit"); // 3. Check Tier 3 if (IsExposureLimitBreached()) return Reject("Exposure limit"); if (IsCorrelationTooHigh()) return Reject("Correlation limit"); return Allow(); } ``` **State Management:** - Thread-safe with locks - Weekly window: 7-day rolling P&L tracking - Peak equity: Updated on every P&L update - Exposure tracking: Per-symbol aggregation - Correlation matrix: Dynamic updates --- ### Position Sizing Component **Purpose:** Calculate optimal contract quantities **Architecture:** ``` BasicPositionSizer ├─ Fixed Contracts └─ Fixed Dollar Risk ↓ extended by AdvancedPositionSizer ├─ OptimalFCalculator │ ├─ Historical trade analysis │ ├─ Risk of ruin calculation │ └─ Optimal leverage ├─ VolatilityAdjustedSizer │ ├─ ATR-based sizing │ ├─ StdDev-based sizing │ └─ Regime detection └─ Dollar-Risk Override ├─ Rounding modes └─ Contract constraints ``` **Sizing Methods:** #### Fixed Contracts Simplest method - always trade the same quantity. ```csharp Contracts = ConfiguredContracts ``` #### Fixed Dollar Risk Target specific dollar risk per trade. ```csharp Contracts = TargetRisk / (StopTicks × TickValue) ``` #### Optimal-f (Ralph Vince) Maximize geometric growth rate. ```csharp f* = (Win% × AvgWin - Loss% × AvgLoss) / AvgWin Contracts = (Capital × f*) / RiskPerContract ``` **Considerations:** - Requires historical trade data - Includes risk of ruin check - Conservative approach recommended #### Volatility-Adjusted Scale position size based on market volatility. ```csharp BaseSize = TargetRisk / (ATR × TickValue) AdjustedSize = BaseSize × (NormalATR / CurrentATR) ``` **Volatility Regimes:** - **Low:** CurrentATR < 0.8 × NormalATR → Increase size - **Normal:** 0.8 ≤ ratio ≤ 1.2 → Standard size - **High:** CurrentATR > 1.2 × NormalATR → Reduce size --- ### Order Management Component **Purpose:** Manage complete order lifecycle **State Machine:** ``` SubmitOrder() ↓ ┌─────────┐ │ Pending │ └────┬────┘ │ NT8 Accepts ↓ ┌─────────┐ │ Working │────────→ CancelOrder() → Cancelled └────┬────┘ │ Partial Fill ↓ ┌──────────────────┐ │ PartiallyFilled │──→ More Fills └────┬─────────────┘ ↓ │ Complete Back to PartiallyFilled ↓ or ┌─────────┐ ↓ │ Filled │ ┌─────────┐ └─────────┘ │ Filled │ └─────────┘ ┌──────────┐ │ Rejected │ ← NT8 Rejects at any point └──────────┘ ``` **State Transitions:** | From | To | Trigger | Validation | |------|----|---------|-----------| | `Pending` | `Working` | NT8 accepts | Auto | | `Pending` | `Rejected` | NT8 rejects | Auto | | `Working` | `PartiallyFilled` | First partial fill | FilledQty < TotalQty | | `Working` | `Filled` | Complete fill | FilledQty == TotalQty | | `Working` | `Cancelled` | Cancel request | Must be working | | `PartiallyFilled` | `Filled` | Final fill | FilledQty == TotalQty | | `PartiallyFilled` | `Cancelled` | Cancel remainder | Allowed | **Thread Safety:** ```csharp private readonly Dictionary _orders; private readonly object _lock = new object(); public OrderStatus? GetOrderStatus(string orderId) { lock (_lock) { return _orders.TryGetValue(orderId, out var status) ? status : null; } } ``` **Event Notifications:** ```csharp private readonly List> _callbacks; public void SubscribeToOrderUpdates(Action callback) { lock (_lock) { _callbacks.Add(callback); } } private void NotifyOrderUpdate(OrderStatus status) { List> callbacks; lock (_lock) { callbacks = new List>(_callbacks); } // Raise events outside lock foreach (var callback in callbacks) { try { callback(status); } catch { /* Log and continue */ } } } ``` --- ### NT8 Adapter Component **Purpose:** Bridge SDK and NinjaTrader 8 platform **Responsibilities:** 1. **Data Conversion** - NT8 ↔ SDK format conversion 2. **Order Submission** - SDK requests → NT8 orders 3. **Event Handling** - NT8 callbacks → SDK notifications 4. **Error Translation** - NT8 errors → SDK exceptions **Data Conversion Example:** ```csharp public class NT8DataConverter { public static BarData ConvertBar(/* NT8 bar parameters */) { return new BarData( symbol: Instrument.MasterInstrument.Name, time: Time[0], open: Open[0], high: High[0], low: Low[0], close: Close[0], volume: Volume[0], barSize: TimeSpan.FromMinutes(BarsPeriod.Value) ); } public static Position ConvertPosition(/* NT8 position */) { return new Position( symbol: Instrument.MasterInstrument.Name, quantity: Position.Quantity, averagePrice: Position.AveragePrice, unrealizedPnL: Position.GetUnrealizedProfitLoss(PerformanceUnit.Currency), realizedPnL: SystemPerformance.AllTrades.TradesPerformance.Currency.CumProfit, lastUpdate: DateTime.UtcNow ); } } ``` **Order Submission Flow:** ``` SDK OrderRequest ↓ convert NT8 Order Parameters ↓ submit NT8 EnterLong() / EnterShort() ↓ callback NT8 OnOrderUpdate() ↓ convert SDK OrderStatus ↓ notify Strategy Callbacks ``` --- ## Data Flow ### Complete Trading Flow ``` 1. Market Data Arrives │ ├─ NT8: OnBarUpdate() │ ↓ ├─ Adapter: Convert to BarData │ ↓ ├─ Strategy: OnBar(BarData, StrategyContext) │ ↓ ├─ Returns: StrategyIntent? │ 2. Intent Validation (if intent != null) │ ├─ Risk: ValidateOrder(intent, context, config) │ ├─ Tier 1 checks │ ├─ Tier 2 checks │ └─ Tier 3 checks │ ↓ ├─ Returns: RiskDecision │ ├─ If rejected: Log and return │ └─ If approved: Continue │ 3. Position Sizing │ ├─ Sizer: CalculateSize(intent, context, config) │ ├─ Method-specific calculation │ ├─ Apply constraints │ └─ Round contracts │ ↓ ├─ Returns: SizingResult │ 4. Order Submission │ ├─ OMS: SubmitOrderAsync(OrderRequest) │ ├─ Create order record │ ├─ State = Pending │ └─ Delegate to adapter │ ↓ ├─ Adapter: SubmitToNT8(request) │ ├─ Convert to NT8 format │ ├─ EnterLong() / EnterShort() │ └─ Set stops/targets │ ↓ ├─ Returns: OrderId │ 5. Order Updates (async) │ ├─ NT8: OnOrderUpdate() │ ↓ ├─ Adapter: Convert to OrderStatus │ ↓ ├─ OMS: OnOrderUpdate(status) │ ├─ Update state machine │ ├─ Update position tracker │ └─ Notify subscribers │ ↓ ├─ Risk: OnFill(fill) [if filled] │ └─ Update P&L tracking │ 6. Position Monitoring │ ├─ NT8: OnPositionUpdate() │ ↓ ├─ Adapter: Convert to Position │ ↓ ├─ Risk: OnPnLUpdate(netPnL, dayPnL) │ ├─ Check daily limits │ ├─ Check weekly limits │ ├─ Update drawdown │ └─ Trigger alerts if needed ``` --- ## Threading Model ### Thread Safety Strategy **Principle:** All shared state protected by locks **Shared State Identification:** - Dictionaries (orders, positions, P&L tracking) - Lists (callbacks, history) - Mutable fields (counters, accumulators) **Lock Pattern:** ```csharp private readonly object _lock = new object(); // Read operation public TValue GetValue(TKey key) { lock (_lock) { return _dictionary.TryGetValue(key, out var value) ? value : default; } } // Write operation public void SetValue(TKey key, TValue value) { lock (_lock) { _dictionary[key] = value; } } // Complex operation public void ComplexOperation() { lock (_lock) { // Multiple operations under single lock var value = _dictionary[key]; value = Transform(value); _dictionary[key] = value; _counter++; } } ``` **Event Notification Pattern:** ```csharp public void NotifySubscribers(TEventData data) { List> callbacks; // Copy callbacks under lock lock (_lock) { callbacks = new List>(_callbacks); } // Raise events outside lock to prevent deadlocks foreach (var callback in callbacks) { try { callback(data); } catch (Exception ex) { _logger.LogError("Callback error: {0}", ex.Message); // Continue with other callbacks } } } ``` ### Threading Scenarios **Scenario 1: Concurrent Strategy Execution** - Multiple strategies call risk/sizing simultaneously - Each component has own lock - No shared state between strategies - Result: Safe concurrent execution **Scenario 2: Order Updates During Validation** - Strategy validates order (holds risk lock) - NT8 callback updates P&L (needs risk lock) - Result: Callback waits for validation to complete - Performance: <1ms typical lock contention **Scenario 3: Emergency Flatten During Trading** - Multiple strategies active - EmergencyFlatten() called - Result: All new orders rejected, existing orders cancelled - Thread-safe state transition --- ## State Management ### Risk Manager State ```csharp private class RiskState { // Tier 1 public double DailyPnL { get; set; } public bool TradingHalted { get; set; } // Tier 2 public Queue WeeklyWindow { get; set; } // 7 days public double PeakEquity { get; set; } public double CurrentEquity { get; set; } // Tier 3 public Dictionary SymbolExposure { get; set; } public CorrelationMatrix Correlations { get; set; } // All protected by _lock } ``` **State Updates:** - **Daily Reset:** Midnight UTC, clear daily P&L - **Weekly Rollover:** Monday, drop oldest day - **Peak Update:** On every positive P&L update - **Exposure Update:** On every fill ### Order Manager State ```csharp private class OrderManagerState { public Dictionary Orders { get; set; } public Dictionary> Fills { get; set; } public Dictionary Positions { get; set; } // State history for auditability public List TransitionHistory { get; set; } // All protected by _lock } ``` **State Persistence:** - In-memory only (current implementation) - Future: Optional database persistence - Replay: State reconstructable from event log --- ## Error Handling ### Error Categories **Level 1: Validation Errors** - Expected during normal operation - Example: Risk limit exceeded - Handling: Return error result, log at Info/Warning **Level 2: Operational Errors** - Recoverable issues - Example: Network timeout, order rejection - Handling: Log error, retry if appropriate, notify user **Level 3: System Errors** - Unexpected critical issues - Example: Null reference, state corruption - Handling: Log critical, emergency flatten, halt trading ### Error Handling Pattern ```csharp public ReturnType PublicMethod(Type parameter) { // 1. Parameter validation if (parameter == null) throw new ArgumentNullException(nameof(parameter)); if (!IsValid(parameter)) throw new ArgumentException("Invalid parameter", nameof(parameter)); try { // 2. Main logic return Implementation(parameter); } catch (ExpectedException ex) { // 3. Expected errors _logger.LogWarning("Expected error: {0}", ex.Message); return DefaultValue; } catch (Exception ex) { // 4. Unexpected errors _logger.LogError("Unexpected error in {0}: {1}", nameof(PublicMethod), ex.Message); throw; // Re-throw for caller to handle } } ``` ### Circuit Breaker Pattern ```csharp private int _consecutiveErrors = 0; private const int MaxConsecutiveErrors = 5; public RiskDecision ValidateOrder(StrategyIntent intent, StrategyContext context, RiskConfig config) { try { var result = ValidateOrderInternal(intent, context, config); _consecutiveErrors = 0; // Reset on success return result; } catch (Exception ex) { _consecutiveErrors++; if (_consecutiveErrors >= MaxConsecutiveErrors) { _logger.LogCritical("Circuit breaker triggered: {0} consecutive errors", _consecutiveErrors); _ = EmergencyFlatten("Circuit breaker"); } throw; } } ``` --- ## Performance Considerations ### Latency Targets | Component | Target | Achieved | Criticality | |-----------|--------|----------|-------------| | Risk Validation | <5ms | <3ms | High | | Position Sizing | <3ms | <2ms | Medium | | Order Submission | <10ms | <8ms | High | | State Update | <1ms | <0.5ms | Medium | | **Total Tick-to-Trade** | **<200ms** | **<150ms** | **Critical** | ### Optimization Techniques **1. Lock Granularity** ```csharp // Bad: Single lock for everything private readonly object _globalLock = new object(); // Good: Separate locks for independent state private readonly object _ordersLock = new object(); private readonly object _positionsLock = new object(); private readonly object _pnlLock = new object(); ``` **2. Copy-on-Read for Collections** ```csharp // Minimize lock duration public List GetActiveOrders() { lock (_lock) { return _orders.Values .Where(o => IsActive(o.State)) .ToList(); // Copy under lock } // Processing happens outside lock } ``` **3. Lazy Initialization** ```csharp private OptimalFCalculator _calculator; private readonly object _calculatorLock = new object(); private OptimalFCalculator GetCalculator() { if (_calculator == null) { lock (_calculatorLock) { if (_calculator == null) // Double-check { _calculator = new OptimalFCalculator(_logger); } } } return _calculator; } ``` **4. String Formatting** ```csharp // C# 5.0 compliant, minimal allocations _logger.LogDebug("Order {0}: {1} {2} @ {3:F2}", orderId, side, quantity, price); ``` **5. Avoid LINQ in Hot Paths** ```csharp // Bad: LINQ in critical path var activeOrders = _orders.Values.Where(o => o.State == OrderState.Working).Count(); // Good: Direct iteration int activeCount = 0; foreach (var order in _orders.Values) { if (order.State == OrderState.Working) activeCount++; } ``` ### Memory Management **Avoid Allocations in Hot Paths:** ```csharp // Reuse dictionaries for metadata private readonly Dictionary _reuseableMetadata = new Dictionary(); public RiskDecision ValidateOrder(...) { lock (_lock) { _reuseableMetadata.Clear(); _reuseableMetadata["daily_pnl"] = _dailyPnL; _reuseableMetadata["limit"] = config.DailyLossLimit; return new RiskDecision(allow, reason, null, level, _reuseableMetadata); } } ``` **Object Pooling for Events:** ```csharp // Future optimization: Pool frequently-created objects private readonly ObjectPool _statusPool; public OrderStatus CreateOrderStatus(...) { var status = _statusPool.Get(); status.OrderId = orderId; // ... populate return status; } ``` --- ## Design Patterns Used ### Strategy Pattern - Multiple risk managers (Basic, Advanced) - Multiple position sizers (Basic, Advanced) - Pluggable strategies ### State Machine Pattern - Order lifecycle management - Risk mode transitions - Defined states and transitions ### Observer Pattern - Order update subscriptions - Event notifications - Callback registration ### Facade Pattern - Simple SDK interface hiding complexity - Unified entry point for trading operations ### Template Method Pattern - BaseRiskManager with extension points - BasePositionSizer with method overrides ### Factory Pattern - Strategy creation - Component initialization --- ## Future Architecture Considerations ### Phase 3: Market Microstructure - Add liquidity monitoring component - Execution quality tracker - Smart order routing ### Phase 4: Intelligence & Grading - Confluence scoring engine - Regime detection system - ML model integration ### Phase 5: Analytics - Performance attribution engine - Trade analytics pipeline - Portfolio optimization ### Phase 6: Production Hardening - High availability setup - Disaster recovery - Enhanced monitoring --- **For implementation details, see [API Reference](API_REFERENCE.md)** **For usage examples, see [README](README.md)**