AssetManager.API/AssetManager.Infrastructure/StrategyEngine/StrategyEngine.cs
niannian zheng b5499ef7fe refactor: 将模型属性改为可为空类型以增强健壮性
- 修改ApiResponse、RiskParityConfig等DTO类的属性为可空类型
- 在策略计算器中添加空值检查逻辑
- 更新服务层代码处理可能的空值情况
- 添加发布配置文件FolderProfile.pubxml
2026-03-06 15:51:59 +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 (strategy.Type == null || !_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
};
}
}
}