using AssetManager.Data; using AssetManager.Infrastructure.StrategyEngine; using AssetManager.Models; using AssetManager.Models.DTOs; using Microsoft.Extensions.Logging; using SqlSugar; namespace AssetManager.Services; /// /// 投资组合门面实现 - 整合多个服务 /// public class PortfolioFacade : IPortfolioFacade { private readonly ILogger _logger; private readonly IPortfolioService _portfolioService; private readonly IPortfolioNavService _navService; private readonly IStrategyService _strategyService; private readonly IStrategyEngine _strategyEngine; private readonly DatabaseService _databaseService; private readonly ISqlSugarClient _db; public PortfolioFacade( ILogger logger, IPortfolioService portfolioService, IPortfolioNavService navService, IStrategyService strategyService, IStrategyEngine strategyEngine, DatabaseService databaseService, ISqlSugarClient db) { _logger = logger; _portfolioService = portfolioService; _navService = navService; _strategyService = strategyService; _strategyEngine = strategyEngine; _databaseService = databaseService; _db = db; } public async Task CreatePortfolioAsync(CreatePortfolioRequest request, string userId) { _logger.LogInformation("创建投资组合: {Name}", request.Name); return await _portfolioService.CreatePortfolioAsync(request, userId); } public async Task GetPortfolioDetailAsync(string portfolioId, string userId) { _logger.LogInformation("获取组合详情: {PortfolioId}", portfolioId); return await _portfolioService.GetPortfolioDetailAsync(portfolioId, userId); } public async Task> GetPortfolioListAsync(string userId) { _logger.LogInformation("获取组合列表: {UserId}", userId); return await _portfolioService.GetPortfolioListAsync(userId); } public async Task GetNavHistoryAsync(string portfolioId, NavHistoryRequest request, string userId) { _logger.LogInformation("获取净值历史: {PortfolioId}", portfolioId); // 验证权限 var portfolio = _databaseService.GetPortfolioById(portfolioId, userId); if (portfolio == null) { throw new UnauthorizedAccessException("组合不存在或无权访问"); } return await _navService.GetNavHistoryAsync(portfolioId, userId, request); } public async Task CreateTransactionAsync(string portfolioId, CreateTransactionRequest request, string userId) { _logger.LogInformation("创建交易: {PortfolioId}, {Type}", portfolioId, request.Type); // 验证权限 var portfolio = _databaseService.GetPortfolioById(portfolioId, userId); if (portfolio == null) { throw new UnauthorizedAccessException("组合不存在或无权访问"); } var transaction = await _portfolioService.CreateTransactionAsync(portfolioId, request, userId); // 交易完成后,异步触发净值更新 _ = Task.Run(async () => { try { await _navService.CalculateAndSaveDailyNavAsync(portfolioId); } catch (Exception ex) { _logger.LogWarning(ex, "交易后净值更新失败: {PortfolioId}", portfolioId); } }); return transaction; } public async Task> GetTransactionsAsync(string portfolioId, GetTransactionsRequest request, string userId) { _logger.LogInformation("获取交易列表: {PortfolioId}", portfolioId); var response = await _portfolioService.GetTransactionsAsync(portfolioId, userId, request.Limit, request.Offset); return response.Items ?? new List(); } public async Task GetStrategySignalAsync(string portfolioId, string userId) { _logger.LogInformation("获取策略信号: {PortfolioId}", portfolioId); // 获取组合 var portfolio = _databaseService.GetPortfolioById(portfolioId, userId); if (portfolio == null || string.IsNullOrEmpty(portfolio.StrategyId)) { return new StrategySignalResponse { Signal = "hold", Reason = "未绑定策略" }; } // 获取策略(同步调用) var strategy = _strategyService.GetStrategyById(portfolio.StrategyId, userId); if (strategy == null) { return new StrategySignalResponse { Signal = "hold", Reason = "策略不存在" }; } // 计算信号 var positions = _databaseService.GetPositionsByPortfolioId(portfolioId); var signal = await _strategyEngine.CalculateSignalAsync(strategy, positions); return new StrategySignalResponse { Signal = signal.Signal?.ToLower() ?? "hold", Reason = signal.Reason, Actions = signal.PositionSignals?.Select(p => new SignalAction { Symbol = p.Symbol, Action = p.Signal?.ToLower(), Target = (double?)p.TargetWeight }).ToList() }; } public async Task DeletePortfolioAsync(string portfolioId, string userId) { _logger.LogInformation("删除组合: {PortfolioId}", portfolioId); return await _portfolioService.DeletePortfolioAsync(portfolioId, userId); } public async Task UpdatePortfolioAsync(string portfolioId, UpdatePortfolioRequest request, string userId) { _logger.LogInformation("更新组合: {PortfolioId}", portfolioId); return await _portfolioService.UpdatePortfolioAsync(portfolioId, request, userId); } /// /// 创建投资组合(含用户验证和币种校验) /// public async Task CreatePortfolioWithValidationAsync(CreatePortfolioRequest request, string userId) { _logger.LogInformation("创建投资组合(含验证): {Name}", request.Name); // 获取用户默认币种 var user = _db.Queryable().Where(u => u.Id == userId).First(); if (user == null) { throw new Exception("用户不存在"); } // 校验组合币种 if (string.IsNullOrEmpty(request.Currency)) { request.Currency = user.DefaultCurrency; } if (!CurrencyHelper.IsSupported(request.Currency)) { throw new ArgumentException($"不支持的组合币种: {request.Currency}"); } // 校验持仓币种 if (request.Stocks != null) { foreach (var stock in request.Stocks) { if (!string.IsNullOrEmpty(stock.Currency) && !CurrencyHelper.IsSupported(stock.Currency)) { throw new ArgumentException($"不支持的持仓币种: {stock.Currency}"); } } } var response = await _portfolioService.CreatePortfolioAsync(request, userId); // 如果创建了持仓,自动触发净值计算 if (request.Stocks != null && request.Stocks.Any()) { _logger.LogInformation("新组合包含持仓,触发净值计算: {PortfolioId}", response.Id); _ = Task.Run(async () => { try { await _navService.CalculateAndSaveDailyNavAsync(response.Id); } catch (Exception ex) { _logger.LogWarning(ex, "新组合净值计算失败: {PortfolioId}", response.Id); } }); } return response; } /// /// 回填净值历史 /// public async Task BackfillNavHistoryAsync(string portfolioId, string userId, bool force = false) { _logger.LogInformation("回填净值历史: {PortfolioId}, Force={Force}", portfolioId, force); // 验证权限 var portfolio = _databaseService.GetPortfolioById(portfolioId, userId); if (portfolio == null) { throw new UnauthorizedAccessException("组合不存在或无权访问"); } return await _navService.BackfillNavHistoryAsync(portfolioId, userId, force); } /// /// 获取用户总资产 /// public async Task GetTotalAssetsAsync(string userId) { _logger.LogInformation("获取用户总资产: {UserId}", userId); return await _portfolioService.GetTotalAssetsAsync(userId); } }