AssetManager.API/AssetManager.Infrastructure/StrategyEngine/StrategyEngine.cs
niannian zheng 2d1fbd37d8 feat: 添加策略引擎实现及相关组件
实现策略引擎核心功能,包括三种策略计算器和相关DTO定义:
1. 添加双均线策略(ma_trend)计算器
2. 添加吊灯止损策略(chandelier_exit)计算器
3. 添加风险平价策略(risk_parity)计算器
4. 定义策略类型常量类和策略配置DTO
5. 实现策略引擎服务接口和扩展方法
6. 更新项目引用和README文档
2026-03-02 14:15:34 +08:00

85 lines
2.7 KiB
C#

using AssetManager.Data;
using AssetManager.Models.DTOs;
using Microsoft.Extensions.Logging;
namespace AssetManager.Infrastructure.StrategyEngine;
/// <summary>
/// 策略引擎实现
/// </summary>
public class StrategyEngine : IStrategyEngine
{
private readonly Dictionary<string, IStrategyCalculator> _calculators;
private readonly ILogger<StrategyEngine> _logger;
public StrategyEngine(
IEnumerable<IStrategyCalculator> calculators,
ILogger<StrategyEngine> logger)
{
_calculators = calculators.ToDictionary(c => c.StrategyType, c => c);
_logger = logger;
}
public async Task<StrategySignal> CalculateSignalAsync(
Strategy strategy,
List<Position> positions,
CancellationToken cancellationToken = default)
{
_logger.LogInformation(
"开始计算策略信号, 策略ID: {StrategyId}, 类型: {StrategyType}, 持仓数: {PositionCount}",
strategy.Id, strategy.Type, positions.Count);
if (positions.Count == 0)
{
return new StrategySignal
{
StrategyType = strategy.Type,
Signal = "HOLD",
Reason = "无持仓",
GeneratedAt = DateTime.UtcNow
};
}
if (!_calculators.TryGetValue(strategy.Type, out var calculator))
{
_logger.LogWarning("未找到策略类型 {StrategyType} 的计算器", strategy.Type);
return new StrategySignal
{
StrategyType = strategy.Type,
Signal = "HOLD",
Reason = $"不支持的策略类型: {strategy.Type}",
GeneratedAt = DateTime.UtcNow
};
}
try
{
var signal = await calculator.CalculateAsync(
strategy.Config ?? "{}",
positions,
cancellationToken);
_logger.LogInformation(
"策略信号计算完成, 策略ID: {StrategyId}, 信号: {Signal}",
strategy.Id, signal.Signal);
return signal;
}
catch (OperationCanceledException)
{
_logger.LogInformation("策略信号计算被取消, 策略ID: {StrategyId}", strategy.Id);
throw;
}
catch (Exception ex)
{
_logger.LogError(ex, "策略信号计算失败, 策略ID: {StrategyId}", strategy.Id);
return new StrategySignal
{
StrategyType = strategy.Type,
Signal = "HOLD",
Reason = $"计算失败: {ex.Message}",
GeneratedAt = DateTime.UtcNow
};
}
}
}