Files
nt8-sdk/docs/architecture/interface_stability_contract.md
mo fb4f5d3bde
Some checks failed
Build and Test / build (push) Has been cancelled
chore: Add project configuration and documentation
- Kilocode AI agent rules and guidelines
- Setup and implementation guides
- Architecture documentation
- Build and verification references
2026-02-15 14:59:36 -05:00

19 KiB
Raw Blame History

Interface Stability Contract - SDK ↔ Adapter Boundary

Version: 1.0
Date: February 14, 2026
Status: DRAFT - Needs Review & Approval


Purpose

This document defines the stable API contract between:

  • NT8.Core.dll (SDK - platform-agnostic)
  • NT8.Adapters.dll (Adapters - platform-specific)

Goal: Ensure SDK updates don't break adapters, and vice versa.


Design Principles

1. Stable Interfaces, Evolving Implementations

  • Interfaces are contracts (change rarely)
  • Implementations can evolve freely (change often)
  • Adapters depend on interfaces, NOT implementations

2. Semantic Versioning

  • MAJOR: Breaking changes to interfaces
  • MINOR: New features (backward compatible)
  • PATCH: Bug fixes (no API changes)

3. Explicit Deprecation Cycle

  • Deprecated methods stay for 2+ minor versions
  • Mark with [Obsolete] attribute
  • Provide migration path in docs

Current Interface Contract (v1.0)

Core SDK Interfaces (STABLE)

These interfaces define the boundary. Changes require MAJOR version bump.

1. Strategy Interface

// src/NT8.Core/Common/Interfaces/IStrategy.cs
// VERSION: 1.0.0
// STABILITY: STABLE

public interface IStrategy
{
    // Properties
    StrategyMetadata Metadata { get; }
    
    // Methods
    void Initialize(StrategyConfig config, IMarketDataProvider dataProvider, ILogger logger);
    StrategyIntent OnBar(BarData bar, StrategyContext context);
    StrategyIntent OnTick(TickData tick, StrategyContext context);
    Dictionary<string, object> GetParameters();
    void SetParameters(Dictionary<string, object> parameters);
}

Stability Guarantee:

  • Method signatures won't change
  • Method names won't change
  • Return types won't change (may add properties to returned objects)
  • Parameter types won't change (may add optional parameters)

Allowed Changes:

  • Add new optional methods with default implementations
  • Add properties to StrategyMetadata
  • Add properties to StrategyConfig
  • Cannot remove existing methods
  • Cannot change existing method signatures

2. Data Models (STABLE)

// src/NT8.Core/Common/Models/BarData.cs
// VERSION: 1.0.0
// STABILITY: STABLE

public class BarData
{
    // Core properties (IMMUTABLE)
    public string Symbol { get; set; }
    public DateTime Time { get; set; }
    public double Open { get; set; }
    public double High { get; set; }
    public double Low { get; set; }
    public double Close { get; set; }
    public long Volume { get; set; }
    public TimeSpan BarSize { get; set; }
    
    // Constructor (IMMUTABLE signature)
    public BarData(
        string symbol,
        DateTime time,
        double open,
        double high,
        double low,
        double close,
        long volume,
        TimeSpan barSize)
    { ... }
}

Stability Guarantee:

  • Existing properties keep same names
  • Existing properties keep same types
  • Constructor signature won't change (may add overloads)
  • Property getters/setters won't change behavior

Allowed Changes:

  • Add new properties (with sensible defaults)
  • Add new constructor overloads
  • Add helper methods
  • Cannot rename existing properties
  • Cannot change property types
  • Cannot remove properties

3. Strategy Intent (STABLE)

// src/NT8.Core/Common/Models/StrategyIntent.cs
// VERSION: 1.0.0
// STABILITY: STABLE

public class StrategyIntent
{
    // Core properties (IMMUTABLE)
    public string IntentId { get; private set; }
    public DateTime Timestamp { get; private set; }
    public string Symbol { get; set; }
    public OrderSide Side { get; set; }
    public OrderType EntryType { get; set; }
    public double? LimitPrice { get; set; }
    public int StopTicks { get; set; }
    public int? TargetTicks { get; set; }
    public double Confidence { get; set; }
    public string Reason { get; set; }
    public Dictionary<string, object> Metadata { get; set; }
    
    // Constructor (IMMUTABLE signature)
    public StrategyIntent(
        string symbol,
        OrderSide side,
        OrderType entryType,
        double? limitPrice,
        int stopTicks,
        int? targetTicks,
        double confidence,
        string reason,
        Dictionary<string, object> metadata)
    { ... }
    
    // Validation (IMMUTABLE signature)
    public bool IsValid() { ... }
}

Stability Guarantee:

  • All property names fixed
  • All property types fixed
  • IsValid() signature fixed
  • Enums can add new values (but not remove)

Allowed Changes:

  • Add new optional properties
  • Add new validation methods
  • Add enum values to OrderSide, OrderType
  • Cannot remove properties
  • Cannot change property types
  • Cannot remove enum values

4. Strategy Context (STABLE)

// src/NT8.Core/Common/Models/StrategyContext.cs
// VERSION: 1.0.0
// STABILITY: STABLE

public class StrategyContext
{
    // Core properties (IMMUTABLE)
    public string Symbol { get; set; }
    public DateTime CurrentTime { get; set; }
    public Position CurrentPosition { get; set; }
    public AccountInfo Account { get; set; }
    public MarketSession Session { get; set; }
    public Dictionary<string, object> CustomData { get; set; }
    
    // Constructor (IMMUTABLE signature)
    public StrategyContext(
        string symbol,
        DateTime currentTime,
        Position currentPosition,
        AccountInfo account,
        MarketSession session,
        Dictionary<string, object> customData)
    { ... }
}

Stability Guarantee:

  • Context structure is stable
  • Nested objects (Position, AccountInfo, MarketSession) can add properties
  • CustomData dictionary for extensibility

Allowed Changes:

  • Add properties to Position, AccountInfo, MarketSession
  • Add new top-level properties to StrategyContext
  • Cannot remove existing properties
  • Cannot change property types

Adapter Interface (SEMI-STABLE)

This is platform-specific. Can evolve more freely.

// src/NT8.Adapters/NinjaTrader/INT8Adapter.cs
// VERSION: 1.0.0
// STABILITY: SEMI-STABLE (can evolve between minor versions)

public interface INT8Adapter
{
    // Initialization
    void Initialize(IRiskManager riskManager, IPositionSizer positionSizer);
    
    // Data conversion (SDK models as return types = STABLE)
    BarData ConvertToSdkBar(string symbol, DateTime time, double open, double high, double low, double close, long volume, int barSize);
    AccountInfo ConvertToSdkAccount(double equity, double buyingPower, double dailyPnL, double maxDrawdown, DateTime lastUpdate);
    Position ConvertToSdkPosition(string symbol, int quantity, double averagePrice, double unrealizedPnL, double realizedPnL, DateTime lastUpdate);
    
    // Intent execution (SDK models as parameters = STABLE)
    void ExecuteIntent(StrategyIntent intent, SizingResult sizing);
    
    // NT8 callbacks (NT8-specific parameters = CAN CHANGE)
    void OnOrderUpdate(string orderId, double limitPrice, double stopPrice, int quantity, int filled, double averageFillPrice, string orderState, DateTime time, string errorCode, string nativeError);
    void OnExecutionUpdate(string executionId, string orderId, double price, int quantity, string marketPosition, DateTime time);
}

Stability Guarantee:

  • Methods that return SDK models are stable
  • Methods that accept SDK models are stable
  • 🟡 NT8-specific signatures can evolve (minor versions)

Allowed Changes:

  • Add new conversion methods
  • Add optional parameters to NT8-specific methods
  • Add new callback methods
  • Cannot change SDK model signatures
  • 🟡 Can change NT8-specific signatures (with deprecation)

Versioning Strategy

SDK Core (NT8.Core.dll)

Version Format: MAJOR.MINOR.PATCH

1.0.0 → Initial release (Phase 1)
1.1.0 → Add new optional features (Phase 2)
1.2.0 → More new features (Phase 3)
2.0.0 → Breaking interface changes (major refactor)

Breaking Changes (MAJOR bump):

  • Remove methods from IStrategy
  • Change method signatures in core interfaces
  • Remove properties from data models
  • Change property types in data models

Compatible Changes (MINOR bump):

  • Add new optional interface methods (with defaults)
  • Add new properties to data models
  • Add new data models
  • Add new interfaces

Bug Fixes (PATCH bump):

  • Fix bugs in implementations
  • Performance improvements
  • Internal refactoring
  • Documentation updates

Adapters (NT8.Adapters.dll)

Version Format: Matches SDK version for compatibility

NT8.Core 1.0.0 → NT8.Adapters 1.0.x (compatible)
NT8.Core 1.1.0 → NT8.Adapters 1.1.x (compatible)
NT8.Core 2.0.0 → NT8.Adapters 2.0.x (requires rewrite)

Adapter versions MUST match SDK MAJOR.MINOR


Interface Evolution Examples

Example 1: Adding Optional Feature (MINOR version)

Scenario: Add support for multiple targets

// v1.0.0 - Original
public class StrategyIntent
{
    public int? TargetTicks { get; set; }
    // ...
}

// v1.1.0 - Enhanced (BACKWARD COMPATIBLE)
public class StrategyIntent
{
    public int? TargetTicks { get; set; }      // Keep for compatibility
    
    // NEW: Optional multiple targets
    public List<int> TargetTicksList { get; set; }  // Defaults to null
    
    // Helper to maintain compatibility
    public int? GetPrimaryTarget()
    {
        if (TargetTicksList != null && TargetTicksList.Count > 0)
            return TargetTicksList[0];
        return TargetTicks;
    }
}

Adapter Impact: None - old code still works
Strategy Impact: None - can optionally use new feature


Example 2: Deprecating Old Method (MINOR version with warning)

Scenario: Rename method for clarity

// v1.0.0 - Original
public interface IStrategy
{
    StrategyIntent OnBar(BarData bar, StrategyContext context);
}

// v1.1.0 - Add new, deprecate old
public interface IStrategy
{
    [Obsolete("Use OnBarClose instead. Will be removed in v2.0.0")]
    StrategyIntent OnBar(BarData bar, StrategyContext context);
    
    // NEW preferred method
    StrategyIntent OnBarClose(BarData bar, StrategyContext context);
}

// v1.2.0 - Still support both
// ... same as v1.1.0 ...

// v2.0.0 - Remove old (BREAKING CHANGE)
public interface IStrategy
{
    StrategyIntent OnBarClose(BarData bar, StrategyContext context);
}

Migration Timeline:

  • v1.1.0: Add new method, deprecate old (warning)
  • v1.2.0: Keep both (warning)
  • v2.0.0: Remove old (breaking change, requires adapter update)

Example 3: Breaking Change (MAJOR version)

Scenario: Change position model to support multi-symbol

// v1.x.x - Original
public class StrategyContext
{
    public Position CurrentPosition { get; set; }  // Single position
}

// v2.0.0 - Breaking change
public class StrategyContext
{
    public Dictionary<string, Position> Positions { get; set; }  // Multi-symbol
    
    // Helper for single-symbol strategies
    public Position GetPosition(string symbol) 
    {
        return Positions.ContainsKey(symbol) ? Positions[symbol] : null;
    }
}

Adapter Impact: Must update - breaking change
Migration Required: Yes, all adapters need rewrite
Version Bump: 1.x.x → 2.0.0


Compatibility Matrix

SDK ↔ Adapter Compatibility

SDK Version Adapter Version Compatible? Notes
1.0.0 1.0.x Yes Perfect match
1.1.0 1.0.x Yes Forward compatible
1.1.0 1.1.x Yes Perfect match
1.2.0 1.1.x Yes Forward compatible
2.0.0 1.x.x No Breaking change
2.0.0 2.0.x Yes Perfect match

Rule: Adapter MINOR can be less than SDK MINOR (forward compatible)
Rule: Adapter MAJOR must equal SDK MAJOR


Contract Testing

Automated Contract Tests

Create tests that verify interface stability:

// tests/NT8.Core.Tests/Contracts/InterfaceStabilityTests.cs

[Fact]
public void IStrategy_Interface_Should_Be_Stable()
{
    var type = typeof(IStrategy);
    
    // Verify method count hasn't decreased
    var methods = type.GetMethods();
    Assert.True(methods.Length >= 5, "IStrategy methods removed!");
    
    // Verify specific methods exist
    Assert.NotNull(type.GetMethod("OnBar"));
    Assert.NotNull(type.GetMethod("OnTick"));
    Assert.NotNull(type.GetMethod("Initialize"));
    
    // Verify method signatures
    var onBarMethod = type.GetMethod("OnBar");
    Assert.Equal(typeof(StrategyIntent), onBarMethod.ReturnType);
    
    var parameters = onBarMethod.GetParameters();
    Assert.Equal(2, parameters.Length);
    Assert.Equal(typeof(BarData), parameters[0].ParameterType);
    Assert.Equal(typeof(StrategyContext), parameters[1].ParameterType);
}

[Fact]
public void BarData_Properties_Should_Be_Stable()
{
    var type = typeof(BarData);
    
    // Verify required properties exist
    Assert.NotNull(type.GetProperty("Symbol"));
    Assert.NotNull(type.GetProperty("Time"));
    Assert.NotNull(type.GetProperty("Open"));
    Assert.NotNull(type.GetProperty("High"));
    Assert.NotNull(type.GetProperty("Low"));
    Assert.NotNull(type.GetProperty("Close"));
    Assert.NotNull(type.GetProperty("Volume"));
    
    // Verify property types haven't changed
    Assert.Equal(typeof(string), type.GetProperty("Symbol").PropertyType);
    Assert.Equal(typeof(DateTime), type.GetProperty("Time").PropertyType);
    Assert.Equal(typeof(double), type.GetProperty("Open").PropertyType);
}

[Fact]
public void StrategyIntent_Constructor_Should_Be_Stable()
{
    var type = typeof(StrategyIntent);
    
    // Verify constructor exists with expected parameters
    var constructor = type.GetConstructor(new[]
    {
        typeof(string),              // symbol
        typeof(OrderSide),           // side
        typeof(OrderType),           // entryType
        typeof(double?),             // limitPrice
        typeof(int),                 // stopTicks
        typeof(int?),                // targetTicks
        typeof(double),              // confidence
        typeof(string),              // reason
        typeof(Dictionary<string, object>)  // metadata
    });
    
    Assert.NotNull(constructor);
}

Run these tests in CI/CD to catch accidental breaking changes!


Adapter-Safe Practices

For SDK Developers

DO:

  • Add optional parameters with defaults
  • Add new properties with sensible defaults
  • Add new interfaces for new features
  • Add helper methods to existing classes
  • Mark deprecated methods with [Obsolete]
  • Run contract tests before release

DON'T:

  • Remove existing methods
  • Change method signatures
  • Rename properties
  • Change property types
  • Remove enum values
  • Break existing constructors

For Adapter Developers

DO:

  • Depend only on interfaces, not implementations
  • Use factory patterns for object creation
  • Handle new optional properties gracefully
  • Catch and log unknown enum values
  • Version-check SDK at runtime if needed

DON'T:

  • Depend on internal implementation details
  • Assume fixed property counts
  • Hard-code enum values
  • Access private members via reflection

Naming Conventions (IMMUTABLE)

These naming patterns are contracts and won't change:

Interface Names

Pattern: I{Concept}
Examples: IStrategy, IRiskManager, IPositionSizer, ILogger

Model Classes

Pattern: {Concept}{Type}
Examples: BarData, TickData, StrategyIntent, StrategyContext

Enums

Pattern: {Concept}{Optional Suffix}
Examples: OrderSide, OrderType, TickType, RiskLevel

Methods

Pattern: {Verb}{Noun}
Examples: OnBar, OnTick, Initialize, ValidateOrder, CalculateSize

Properties

Pattern: {Noun} or {Adjective}{Noun}
Examples: Symbol, Timestamp, CurrentPosition, DailyPnL

These patterns are STABLE and won't change.


Extension Points (For Future Growth)

1. Metadata Dictionaries

public Dictionary<string, object> Metadata { get; set; }

Use for: Adding data without breaking compatibility

2. Optional Parameters

public void Initialize(
    StrategyConfig config, 
    IMarketDataProvider dataProvider, 
    ILogger logger,
    Dictionary<string, object> options = null)  // Extension point

3. Interface Composition

// Instead of changing IStrategy, create new interface
public interface IAdvancedStrategy : IStrategy
{
    void OnMarketDepth(MarketDepthData depth);
}

4. Feature Flags

public class StrategyMetadata
{
    public Dictionary<string, bool> SupportedFeatures { get; set; }
}

Adapters can check: if (metadata.SupportedFeatures["MultiTarget"]) { ... }


Documentation Requirements

For Every Interface Change

Must Document:

  1. What changed (method/property added/removed/changed)
  2. Why it changed (business reason)
  3. Version it changed in
  4. Migration path for adapters
  5. Deprecation timeline (if applicable)

Example:

## v1.1.0 - January 2026

### Added
- `StrategyIntent.TargetTicksList` - Support for multiple profit targets
  - **Migration**: Not required. Old code using `TargetTicks` still works.
  - **New feature**: Strategies can now specify multiple targets.
  
### Deprecated
- `IStrategy.OnBar()` - Deprecated in favor of `OnBarClose()`
  - **Reason**: Clearer naming for bar-close strategies
  - **Timeline**: Will be removed in v2.0.0 (12+ months)
  - **Migration**: Replace `OnBar` with `OnBarClose` (same signature)

Approval Process

Before Releasing Interface Changes

Required Reviews:

  1. Technical review (breaking vs. non-breaking)
  2. Contract tests pass
  3. Documentation updated
  4. Migration guide written (if needed)
  5. Version number updated correctly

For Breaking Changes:

  1. All of the above, plus:
  2. Deprecation period completed (2+ minor versions)
  3. Adapter developers notified 30+ days in advance
  4. Migration tooling provided (if possible)

Summary

The Contract

SDK Core provides:

  • Stable interfaces (IStrategy, IRiskManager, IPositionSizer)
  • Stable data models (BarData, StrategyIntent, StrategyContext)
  • Versioned API (semantic versioning)
  • Backward compatibility within MAJOR versions

Adapters rely on:

  • Interface contracts (not implementations)
  • Data model structures
  • Method signatures
  • Enum values

The promise:

  • SDK can evolve WITHOUT breaking adapters (within MAJOR version)
  • Adapters can evolve WITHOUT rewriting SDK
  • Clear versioning communicates compatibility
  • Deprecation gives time to migrate

Action Items

Immediate (Before Phase 1 Release)

  • Review all public interfaces for stability
  • Add contract tests to CI/CD
  • Document current interface versions
  • Establish version numbering (start at 1.0.0)
  • Get team approval on this contract

Ongoing

  • Run contract tests on every build
  • Review all PR's for interface stability
  • Document changes in CHANGELOG.md
  • Notify adapter developers of deprecations
  • Maintain compatibility matrix

Version History:

  • v1.0 (2026-02-14): Initial draft
  • [Future versions will be listed here]