# Coding Patterns — NT8 SDK Required Patterns All code in the NT8 SDK MUST follow these patterns without exception. --- ## 1. Thread Safety — Lock Everything Shared Every class with shared state must have a lock object: ```csharp private readonly object _lock = new object(); ``` Every access to shared `Dictionary`, `List`, `Queue`, or any field touched by multiple threads: ```csharp // ❌ NEVER _activeOrders[orderId] = status; // ✅ ALWAYS lock (_lock) { _activeOrders[orderId] = status; } ``` ### Read-then-write must be atomic ```csharp // ❌ WRONG — race condition between check and write if (!_orders.ContainsKey(id)) _orders[id] = newOrder; // ✅ CORRECT lock (_lock) { if (!_orders.ContainsKey(id)) _orders[id] = newOrder; } ``` --- ## 2. Error Handling — Try-Catch on All Public Methods ```csharp public ReturnType MethodName(Type parameter) { // 1. Validate parameters first if (parameter == null) throw new ArgumentNullException("parameter"); // 2. Wrap the main logic try { // Implementation return result; } catch (SpecificException ex) { _logger.LogError("Specific failure in MethodName: {0}", ex.Message); throw; } catch (Exception ex) { _logger.LogError("Unexpected failure in MethodName: {0}", ex.Message); throw; } } ``` --- ## 3. Logging — Always string.Format, Never $"" ```csharp // ❌ NEVER — C# 6 syntax, breaks NT8 compile _logger.LogInformation($"Order {orderId} filled"); // ✅ ALWAYS _logger.LogInformation("Order {0} filled", orderId); _logger.LogWarning("Risk check failed for {0}: {1}", symbol, reason); _logger.LogError("Exception in {0}: {1}", "MethodName", ex.Message); _logger.LogCritical("Emergency flatten triggered: {0}", reason); ``` ### Log level guide | Level | When to use | |---|---| | `LogTrace` | Entering/exiting methods, fine-grained flow | | `LogDebug` | State reads, normal data flow | | `LogInformation` | Important events: order submitted, filled, cancelled | | `LogWarning` | Recoverable issues: validation failed, limit approaching | | `LogError` | Failures: exceptions, unexpected states | | `LogCritical` | System integrity issues: emergency flatten, data corruption | --- ## 4. Events — Never Raise Inside Locks Raising events inside a lock causes deadlocks when event handlers acquire other locks. ```csharp // ❌ DEADLOCK RISK lock (_lock) { _state = newState; OrderStateChanged?.Invoke(this, args); // handler may try to acquire _lock } // ✅ CORRECT OrderState newState; lock (_lock) { newState = CalculateNewState(); _state = newState; } // Raise AFTER releasing lock RaiseOrderStateChanged(orderId, previousState, newState); ``` --- ## 5. Constructor — Validate All Dependencies ```csharp public MyClass(ILogger logger, ISomeDependency dep) { if (logger == null) throw new ArgumentNullException("logger"); if (dep == null) throw new ArgumentNullException("dep"); _logger = logger; _dep = dep; // Initialize collections _activeOrders = new Dictionary(); _logger.LogInformation("MyClass initialized"); } ``` --- ## 6. XML Documentation — Required on All Public Members ```csharp /// /// Brief one-line description of what this does. /// /// The trading intent to validate. /// Current strategy context with account state. /// Risk decision indicating allow or reject. /// Thrown when intent or context is null. public RiskDecision ValidateOrder(StrategyIntent intent, StrategyContext context) { ... } ``` --- ## 7. NT8-Specific Patterns (NinjaScript) When writing code that runs inside NinjaTrader (in `NT8.Adapters/`): ```csharp // Always guard OnBarUpdate protected override void OnBarUpdate() { if (BarsInProgress != 0) return; if (CurrentBar < BarsRequiredToTrade) return; // ... } // Managed order pattern — set stops BEFORE entry SetStopLoss("SignalName", CalculationMode.Ticks, stopTicks, false); SetProfitTarget("SignalName", CalculationMode.Ticks, targetTicks); EnterLong(contracts, "SignalName"); // Use string.Format for Print() too Print(string.Format("Order submitted: {0} contracts at {1}", qty, price)); ``` --- ## 8. Checklist Before Marking Any Method Complete - [ ] Parameter null checks at the top - [ ] `try-catch` wrapping the body - [ ] All `Dictionary`/collection access inside `lock (_lock)` - [ ] All logging uses `string.Format()` (no `$""`) - [ ] XML `/// ` on every public method, property, class - [ ] No C# 6+ syntax - [ ] Events raised outside lock blocks - [ ] `verify-build.bat` passes