Phase 0 completion: NT8 SDK core framework with risk management and position sizing
Some checks failed
Build and Test / build (push) Has been cancelled
Some checks failed
Build and Test / build (push) Has been cancelled
This commit is contained in:
614
ai_workflow_templates.md
Normal file
614
ai_workflow_templates.md
Normal file
@@ -0,0 +1,614 @@
|
||||
# AI Agent Workflow and Code Templates
|
||||
|
||||
## Pre-Implementation Checklist
|
||||
|
||||
### Before Starting ANY NT8 Integration Task:
|
||||
|
||||
1. **Environment Verification**
|
||||
```bash
|
||||
cd C:\dev\nt8-sdk
|
||||
.\verify-build.bat
|
||||
# MUST output: "✅ All checks passed!"
|
||||
```
|
||||
|
||||
2. **Documentation Review**
|
||||
- [ ] Read `AI_DEVELOPMENT_GUIDELINES.md`
|
||||
- [ ] Read `NT8_INTEGRATION_GUIDELINES.md`
|
||||
- [ ] Review task-specific requirements
|
||||
- [ ] Check dependency tasks are complete
|
||||
|
||||
3. **Pattern Study**
|
||||
- [ ] Review existing code in `src/NT8.Core/`
|
||||
- [ ] Study similar implementations in the repository
|
||||
- [ ] Understand data flow and architecture
|
||||
|
||||
## Code Templates
|
||||
|
||||
### Template 1: NT8 Strategy Wrapper
|
||||
```csharp
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using NinjaTrader.Cbi;
|
||||
using NinjaTrader.NinjaScript.Strategies;
|
||||
using NT8.Core.Common.Interfaces;
|
||||
using NT8.Core.Common.Models;
|
||||
using NT8.Core.Risk;
|
||||
using NT8.Core.Sizing;
|
||||
using NT8.Core.Logging;
|
||||
|
||||
namespace NinjaTrader.NinjaScript.Strategies
|
||||
{
|
||||
/// <summary>
|
||||
/// NT8 wrapper for [StrategyName] SDK strategy
|
||||
/// Bridges NinjaTrader 8 with institutional SDK framework
|
||||
/// </summary>
|
||||
public class [StrategyName]NT8Wrapper : Strategy
|
||||
{
|
||||
#region SDK Components
|
||||
private IStrategy _sdkStrategy;
|
||||
private IRiskManager _riskManager;
|
||||
private IPositionSizer _positionSizer;
|
||||
private ILogger _logger;
|
||||
#endregion
|
||||
|
||||
#region NT8 Parameters (Show in UI)
|
||||
[NinjaScriptProperty]
|
||||
[Range(1, 50)]
|
||||
[Display(Name = "Stop Loss Ticks", Description = "Stop loss in ticks", Order = 1, GroupName = "Risk")]
|
||||
public int StopTicks { get; set; } = 8;
|
||||
|
||||
[NinjaScriptProperty]
|
||||
[Range(1, 100)]
|
||||
[Display(Name = "Profit Target Ticks", Description = "Profit target in ticks", Order = 2, GroupName = "Risk")]
|
||||
public int TargetTicks { get; set; } = 16;
|
||||
|
||||
[NinjaScriptProperty]
|
||||
[Range(100, 5000)]
|
||||
[Display(Name = "Daily Loss Limit", Description = "Maximum daily loss in dollars", Order = 3, GroupName = "Risk")]
|
||||
public double DailyLossLimit { get; set; } = 1000;
|
||||
|
||||
[NinjaScriptProperty]
|
||||
[Range(50, 1000)]
|
||||
[Display(Name = "Risk Per Trade", Description = "Dollar risk per trade", Order = 4, GroupName = "Sizing")]
|
||||
public double RiskPerTrade { get; set; } = 200;
|
||||
#endregion
|
||||
|
||||
#region NT8 Lifecycle
|
||||
protected override void OnStateChange()
|
||||
{
|
||||
if (State == State.SetDefaults)
|
||||
{
|
||||
InitializeNT8Properties();
|
||||
InitializeSdkComponents();
|
||||
}
|
||||
else if (State == State.DataLoaded)
|
||||
{
|
||||
ValidateConfiguration();
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnBarUpdate()
|
||||
{
|
||||
if (CurrentBar < 1) return;
|
||||
|
||||
try
|
||||
{
|
||||
// Convert NT8 data to SDK format
|
||||
var barData = ConvertToSdkBar();
|
||||
var context = CreateStrategyContext();
|
||||
|
||||
// Get trading intent from SDK strategy
|
||||
var intent = _sdkStrategy.OnBar(barData, context);
|
||||
if (intent == null) return;
|
||||
|
||||
// Risk validation
|
||||
var riskDecision = ValidateRisk(intent, context);
|
||||
if (!riskDecision.Allow)
|
||||
{
|
||||
_logger.LogWarning("Trade rejected: {0}", riskDecision.RejectReason);
|
||||
return;
|
||||
}
|
||||
|
||||
// Position sizing
|
||||
var sizingResult = CalculatePositionSize(intent, context);
|
||||
if (sizingResult.Contracts <= 0)
|
||||
{
|
||||
_logger.LogWarning("No contracts calculated");
|
||||
return;
|
||||
}
|
||||
|
||||
// Execute in NT8
|
||||
ExecuteTradeInNT8(intent, sizingResult);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError("OnBarUpdate error: {0}", ex.Message);
|
||||
HandleError(ex);
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Initialization
|
||||
private void InitializeNT8Properties()
|
||||
{
|
||||
Description = "[StrategyName] using NT8 SDK";
|
||||
Name = "[StrategyName]NT8";
|
||||
Calculate = Calculate.OnBarClose;
|
||||
EntriesPerDirection = 1;
|
||||
EntryHandling = EntryHandling.AllEntries;
|
||||
IsExitOnSessionCloseStrategy = true;
|
||||
ExitOnSessionCloseSeconds = 30;
|
||||
BarsRequiredToTrade = 20;
|
||||
StartBehavior = StartBehavior.WaitUntilFlat;
|
||||
TimeInForce = TimeInForce.Gtc;
|
||||
}
|
||||
|
||||
private void InitializeSdkComponents()
|
||||
{
|
||||
try
|
||||
{
|
||||
_logger = new BasicLogger(Name);
|
||||
_riskManager = new BasicRiskManager(_logger);
|
||||
_positionSizer = new BasicPositionSizer(_logger);
|
||||
|
||||
// Initialize specific strategy
|
||||
_sdkStrategy = new [ConcreteStrategyClass](_logger);
|
||||
|
||||
var config = CreateSdkConfiguration();
|
||||
_sdkStrategy.Initialize(config, null, _logger);
|
||||
|
||||
_logger.LogInformation("SDK components initialized successfully");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new InvalidOperationException(String.Format("Failed to initialize SDK: {0}", ex.Message), ex);
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Data Conversion
|
||||
private BarData ConvertToSdkBar()
|
||||
{
|
||||
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)
|
||||
);
|
||||
}
|
||||
|
||||
private StrategyContext CreateStrategyContext()
|
||||
{
|
||||
var position = 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
|
||||
);
|
||||
|
||||
var account = new AccountInfo(
|
||||
equity: Account.Get(AccountItem.CashValue, Currency.UsDollar),
|
||||
buyingPower: Account.Get(AccountItem.BuyingPower, Currency.UsDollar),
|
||||
dailyPnL: SystemPerformance.AllTrades.TradesPerformance.Currency.CumProfit,
|
||||
maxDrawdown: SystemPerformance.AllTrades.TradesPerformance.Currency.MaxDrawdown,
|
||||
lastUpdate: DateTime.UtcNow
|
||||
);
|
||||
|
||||
var session = new MarketSession(
|
||||
sessionStart: SessionIterator.GetTradingDay().Date.Add(TimeSpan.FromHours(9.5)),
|
||||
sessionEnd: SessionIterator.GetTradingDay().Date.Add(TimeSpan.FromHours(16)),
|
||||
isRth: true,
|
||||
sessionName: "RTH"
|
||||
);
|
||||
|
||||
return new StrategyContext(
|
||||
symbol: Instrument.MasterInstrument.Name,
|
||||
currentTime: DateTime.UtcNow,
|
||||
currentPosition: position,
|
||||
account: account,
|
||||
session: session,
|
||||
customData: new Dictionary<string, object>()
|
||||
);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region SDK Integration
|
||||
private StrategyConfig CreateSdkConfiguration()
|
||||
{
|
||||
var parameters = new Dictionary<string, object>();
|
||||
parameters.Add("StopTicks", StopTicks);
|
||||
parameters.Add("TargetTicks", TargetTicks);
|
||||
// Add strategy-specific parameters here
|
||||
|
||||
var riskConfig = new RiskConfig(
|
||||
dailyLossLimit: DailyLossLimit,
|
||||
maxTradeRisk: RiskPerTrade,
|
||||
maxOpenPositions: 3,
|
||||
emergencyFlattenEnabled: true
|
||||
);
|
||||
|
||||
var sizingConfig = new SizingConfig(
|
||||
method: SizingMethod.FixedDollarRisk,
|
||||
minContracts: 1,
|
||||
maxContracts: 10,
|
||||
riskPerTrade: RiskPerTrade,
|
||||
methodParameters: new Dictionary<string, object>()
|
||||
);
|
||||
|
||||
return new StrategyConfig(
|
||||
name: Name,
|
||||
symbol: Instrument.MasterInstrument.Name,
|
||||
parameters: parameters,
|
||||
riskSettings: riskConfig,
|
||||
sizingSettings: sizingConfig
|
||||
);
|
||||
}
|
||||
|
||||
private RiskDecision ValidateRisk(StrategyIntent intent, StrategyContext context)
|
||||
{
|
||||
var riskConfig = new RiskConfig(
|
||||
dailyLossLimit: DailyLossLimit,
|
||||
maxTradeRisk: RiskPerTrade,
|
||||
maxOpenPositions: 3,
|
||||
emergencyFlattenEnabled: true
|
||||
);
|
||||
|
||||
return _riskManager.ValidateOrder(intent, context, riskConfig);
|
||||
}
|
||||
|
||||
private SizingResult CalculatePositionSize(StrategyIntent intent, StrategyContext context)
|
||||
{
|
||||
var sizingConfig = new SizingConfig(
|
||||
method: SizingMethod.FixedDollarRisk,
|
||||
minContracts: 1,
|
||||
maxContracts: 10,
|
||||
riskPerTrade: RiskPerTrade,
|
||||
methodParameters: new Dictionary<string, object>()
|
||||
);
|
||||
|
||||
return _positionSizer.CalculateSize(intent, context, sizingConfig);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region NT8 Order Execution
|
||||
private void ExecuteTradeInNT8(StrategyIntent intent, SizingResult sizing)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (intent.Side == OrderSide.Buy)
|
||||
{
|
||||
EnterLong(sizing.Contracts, "SDK_Long");
|
||||
SetStopLoss("SDK_Long", CalculationMode.Ticks, intent.StopTicks);
|
||||
if (intent.TargetTicks.HasValue)
|
||||
SetProfitTarget("SDK_Long", CalculationMode.Ticks, intent.TargetTicks.Value);
|
||||
}
|
||||
else if (intent.Side == OrderSide.Sell)
|
||||
{
|
||||
EnterShort(sizing.Contracts, "SDK_Short");
|
||||
SetStopLoss("SDK_Short", CalculationMode.Ticks, intent.StopTicks);
|
||||
if (intent.TargetTicks.HasValue)
|
||||
SetProfitTarget("SDK_Short", CalculationMode.Ticks, intent.TargetTicks.Value);
|
||||
}
|
||||
|
||||
_logger.LogInformation("Trade executed: {0} {1} contracts, Stop: {2}, Target: {3}",
|
||||
intent.Side, sizing.Contracts, intent.StopTicks, intent.TargetTicks);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError("Trade execution failed: {0}", ex.Message);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Error Handling
|
||||
private void ValidateConfiguration()
|
||||
{
|
||||
if (StopTicks <= 0)
|
||||
throw new ArgumentException("Stop ticks must be greater than 0");
|
||||
|
||||
if (TargetTicks <= 0)
|
||||
throw new ArgumentException("Target ticks must be greater than 0");
|
||||
|
||||
if (DailyLossLimit <= 0)
|
||||
throw new ArgumentException("Daily loss limit must be greater than 0");
|
||||
|
||||
if (RiskPerTrade <= 0)
|
||||
throw new ArgumentException("Risk per trade must be greater than 0");
|
||||
}
|
||||
|
||||
private void HandleError(Exception ex)
|
||||
{
|
||||
// Log error and optionally halt strategy
|
||||
_logger.LogCritical("Critical error in strategy: {0}", ex.Message);
|
||||
|
||||
// Consider emergency flatten if needed
|
||||
// _riskManager.EmergencyFlatten("Critical error occurred");
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Template 2: Data Converter Class
|
||||
```csharp
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using NT8.Core.Common.Models;
|
||||
using NT8.Core.Logging;
|
||||
|
||||
namespace NT8.Adapters.NinjaTrader
|
||||
{
|
||||
/// <summary>
|
||||
/// Converts between NinjaTrader 8 data formats and SDK data models
|
||||
/// Handles all data type conversions with proper error handling
|
||||
/// </summary>
|
||||
public static class NT8DataConverter
|
||||
{
|
||||
/// <summary>
|
||||
/// Convert NT8 bar data to SDK BarData format
|
||||
/// </summary>
|
||||
public static BarData ConvertBar(/* NT8 bar parameters */)
|
||||
{
|
||||
try
|
||||
{
|
||||
return new BarData(
|
||||
symbol: /* NT8 symbol */,
|
||||
time: /* NT8 time */,
|
||||
open: /* NT8 open */,
|
||||
high: /* NT8 high */,
|
||||
low: /* NT8 low */,
|
||||
close: /* NT8 close */,
|
||||
volume: /* NT8 volume */,
|
||||
barSize: /* NT8 bar size */
|
||||
);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
String.Format("Failed to convert NT8 bar data: {0}", ex.Message), ex);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Convert NT8 account info to SDK AccountInfo format
|
||||
/// </summary>
|
||||
public static AccountInfo ConvertAccount(/* NT8 account parameters */)
|
||||
{
|
||||
try
|
||||
{
|
||||
return new AccountInfo(
|
||||
equity: /* NT8 equity */,
|
||||
buyingPower: /* NT8 buying power */,
|
||||
dailyPnL: /* NT8 daily PnL */,
|
||||
maxDrawdown: /* NT8 max drawdown */,
|
||||
lastUpdate: DateTime.UtcNow
|
||||
);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
String.Format("Failed to convert NT8 account data: {0}", ex.Message), ex);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Convert NT8 position to SDK Position format
|
||||
/// </summary>
|
||||
public static Position ConvertPosition(/* NT8 position parameters */)
|
||||
{
|
||||
try
|
||||
{
|
||||
return new Position(
|
||||
symbol: /* NT8 symbol */,
|
||||
quantity: /* NT8 quantity */,
|
||||
averagePrice: /* NT8 average price */,
|
||||
unrealizedPnL: /* NT8 unrealized PnL */,
|
||||
realizedPnL: /* NT8 realized PnL */,
|
||||
lastUpdate: DateTime.UtcNow
|
||||
);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
String.Format("Failed to convert NT8 position data: {0}", ex.Message), ex);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Validate data before conversion
|
||||
/// </summary>
|
||||
private static void ValidateData(object data, string dataType)
|
||||
{
|
||||
if (data == null)
|
||||
throw new ArgumentNullException("data", String.Format("{0} data cannot be null", dataType));
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Template 3: Unit Test Class
|
||||
```csharp
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using NT8.Adapters.NinjaTrader;
|
||||
using NT8.Core.Common.Models;
|
||||
using System;
|
||||
|
||||
namespace NT8.Integration.Tests.Adapters
|
||||
{
|
||||
[TestClass]
|
||||
public class NT8DataConverterTests
|
||||
{
|
||||
[TestMethod]
|
||||
public void ConvertBar_ValidData_ShouldSucceed()
|
||||
{
|
||||
// Arrange
|
||||
// Create test NT8 bar data
|
||||
|
||||
// Act
|
||||
var result = NT8DataConverter.ConvertBar(/* test data */);
|
||||
|
||||
// Assert
|
||||
Assert.IsNotNull(result);
|
||||
Assert.AreEqual("ES", result.Symbol);
|
||||
// Add more specific assertions
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void ConvertBar_NullData_ShouldThrowException()
|
||||
{
|
||||
// Act & Assert
|
||||
Assert.ThrowsException<ArgumentNullException>(() =>
|
||||
NT8DataConverter.ConvertBar(null));
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void ConvertAccount_ValidData_ShouldSucceed()
|
||||
{
|
||||
// Arrange
|
||||
// Create test NT8 account data
|
||||
|
||||
// Act
|
||||
var result = NT8DataConverter.ConvertAccount(/* test data */);
|
||||
|
||||
// Assert
|
||||
Assert.IsNotNull(result);
|
||||
Assert.IsTrue(result.Equity > 0);
|
||||
// Add more specific assertions
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Implementation Workflow
|
||||
|
||||
### Step-by-Step Process for Each Task:
|
||||
|
||||
#### Phase 1: Setup and Planning
|
||||
1. **Read Task Requirements**
|
||||
- Review specific task in task breakdown
|
||||
- Understand deliverables and success criteria
|
||||
- Check dependencies on other tasks
|
||||
|
||||
2. **Study Existing Code**
|
||||
```bash
|
||||
# Look at similar implementations
|
||||
find src/NT8.Core -name "*.cs" | xargs grep -l "pattern"
|
||||
```
|
||||
|
||||
3. **Create File Structure**
|
||||
```bash
|
||||
# Create required directories if needed
|
||||
mkdir -p src/NT8.Adapters/NinjaTrader
|
||||
mkdir -p src/NT8.Adapters/Wrappers
|
||||
```
|
||||
|
||||
#### Phase 2: Implementation
|
||||
1. **Start with Template**
|
||||
- Copy appropriate template from above
|
||||
- Replace placeholders with actual implementation
|
||||
- Follow C# 5.0 syntax requirements
|
||||
|
||||
2. **Implement Core Functionality**
|
||||
- Focus on main requirements first
|
||||
- Add error handling as you go
|
||||
- Use existing SDK patterns
|
||||
|
||||
3. **Test Early and Often**
|
||||
```bash
|
||||
# Test compilation frequently
|
||||
.\verify-build.bat
|
||||
```
|
||||
|
||||
#### Phase 3: Integration Testing
|
||||
1. **Unit Tests**
|
||||
- Create comprehensive unit tests
|
||||
- Test edge cases and error conditions
|
||||
- Ensure >80% code coverage
|
||||
|
||||
2. **NT8 Integration**
|
||||
- Copy files to NT8 directories
|
||||
- Compile in NT8 NinjaScript Editor
|
||||
- Test on simulation account
|
||||
|
||||
#### Phase 4: Finalization
|
||||
1. **Code Review**
|
||||
- Use `CODE_REVIEW_CHECKLIST.md`
|
||||
- Ensure all requirements met
|
||||
- Verify coding standards compliance
|
||||
|
||||
2. **Documentation**
|
||||
- Update relevant documentation
|
||||
- Add code comments
|
||||
- Update deployment instructions
|
||||
|
||||
## Common Patterns and Best Practices
|
||||
|
||||
### Error Handling Pattern
|
||||
```csharp
|
||||
try
|
||||
{
|
||||
// Main logic here
|
||||
}
|
||||
catch (SpecificException ex)
|
||||
{
|
||||
_logger.LogError("Specific error: {0}", ex.Message);
|
||||
// Handle specific case
|
||||
throw; // Re-throw if needed
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError("Unexpected error in {0}: {1}", methodName, ex.Message);
|
||||
throw new InvalidOperationException(
|
||||
String.Format("Operation failed: {0}", ex.Message), ex);
|
||||
}
|
||||
```
|
||||
|
||||
### Parameter Validation Pattern
|
||||
```csharp
|
||||
public ReturnType MethodName(Type parameter)
|
||||
{
|
||||
if (parameter == null)
|
||||
throw new ArgumentNullException("parameter");
|
||||
|
||||
if (!IsValid(parameter))
|
||||
throw new ArgumentException("Invalid parameter value", "parameter");
|
||||
|
||||
// Implementation
|
||||
}
|
||||
```
|
||||
|
||||
### Logging Pattern
|
||||
```csharp
|
||||
_logger.LogDebug("Method {0} called with parameter: {1}", methodName, parameter);
|
||||
_logger.LogInformation("Operation completed successfully: {0}", result);
|
||||
_logger.LogWarning("Potential issue detected: {0}", issue);
|
||||
_logger.LogError("Error occurred: {0}", error.Message);
|
||||
_logger.LogCritical("Critical failure: {0}", criticalError.Message);
|
||||
```
|
||||
|
||||
## Quality Checkpoints
|
||||
|
||||
### Before Submitting Code:
|
||||
- [ ] Compiles without errors (`.\verify-build.bat`)
|
||||
- [ ] Follows C# 5.0 syntax requirements
|
||||
- [ ] Includes comprehensive error handling
|
||||
- [ ] Has unit tests with >80% coverage
|
||||
- [ ] Follows established code patterns
|
||||
- [ ] Includes proper documentation
|
||||
- [ ] Tested with NT8 (for wrapper classes)
|
||||
|
||||
### Code Review Criteria:
|
||||
- [ ] Meets all task requirements
|
||||
- [ ] Proper integration with existing SDK
|
||||
- [ ] No breaking changes to Core
|
||||
- [ ] Performance acceptable
|
||||
- [ ] Maintainable and readable code
|
||||
|
||||
This workflow and templates provide AI agents with clear guidance and proven patterns for implementing NT8 integration while maintaining the quality and compatibility standards of the SDK.
|
||||
Reference in New Issue
Block a user