614 lines
20 KiB
Markdown
614 lines
20 KiB
Markdown
# 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. |