From 60f3b487ffd671c94799f3d57ae23e787fdd323f Mon Sep 17 00:00:00 2001 From: OpenClaw Agent Date: Sun, 15 Mar 2026 13:31:49 +0000 Subject: [PATCH] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=20PortfolioService=20?= =?UTF-8?q?=E5=92=8C=20PortfolioNavService=20=E5=8F=98=E9=87=8F=E5=91=BD?= =?UTF-8?q?=E5=90=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 统一局部变量使用 camelCase(C# 规范) - 修复 DTO 属性名引用 - NavItem -> NavHistoryItem - 修复 for 循环变量名 --- AssetManager.Services/PortfolioFacade.cs | 14 ++++- AssetManager.Services/PortfolioNavService.cs | 62 ++++++++++---------- AssetManager.Services/PortfolioService.cs | 18 +++--- 3 files changed, 53 insertions(+), 41 deletions(-) diff --git a/AssetManager.Services/PortfolioFacade.cs b/AssetManager.Services/PortfolioFacade.cs index 2d5208d..c107d11 100644 --- a/AssetManager.Services/PortfolioFacade.cs +++ b/AssetManager.Services/PortfolioFacade.cs @@ -110,7 +110,19 @@ public class PortfolioFacade : IPortfolioFacade // 计算信号 var positions = _databaseService.GetPositionsByPortfolioId(portfolioId); - return await _strategyEngine.GenerateSignalAsync(strategy, positions); + 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) diff --git a/AssetManager.Services/PortfolioNavService.cs b/AssetManager.Services/PortfolioNavService.cs index 7da08b2..6da1ebc 100644 --- a/AssetManager.Services/PortfolioNavService.cs +++ b/AssetManager.Services/PortfolioNavService.cs @@ -41,8 +41,8 @@ public class PortfolioNavService : IPortfolioNavService } // 设置默认日期范围(最近30天) - var EndDate = request.EndDate ?? DateTime.Today; - var StartDate = request.StartDate ?? endDate.AddDays(-30); + var endDate = request.EndDate ?? DateTime.Today; + var startDate = request.StartDate ?? endDate.AddDays(-30); // 检查是否有历史数据,没有则自动回填 var existingCount = await _db.Queryable() @@ -56,7 +56,7 @@ public class PortfolioNavService : IPortfolioNavService } // 查询净值历史 - var NavHistory = await _db.Queryable() + var navHistory = await _db.Queryable() .Where(n => n.PortfolioId == portfolioId) .Where(n => n.NavDate >= startDate && n.NavDate <= endDate) .OrderBy(n => n.NavDate) @@ -69,20 +69,20 @@ public class PortfolioNavService : IPortfolioNavService { PortfolioId = portfolioId, Currency = portfolio.Currency, - NavHistory = new List(), + NavHistory = new List(), Statistics = new NavStatistics() }; } // 计算统计指标 var returns = navHistory.Select(n => (double)n.DailyReturn).Where(r => r != 0).ToList(); - var Statistics = CalculateStatistics(returns, navHistory); + var statistics = CalculateStatistics(returns, navHistory); return new NavHistoryResponse { PortfolioId = portfolioId, Currency = portfolio.Currency, - NavHistory = navHistory.Select(n => new NavItem + NavHistory = navHistory.Select(n => new NavHistoryItem { Date = n.NavDate.ToString("yyyy-MM-dd"), Nav = (double)n.Nav, @@ -128,7 +128,7 @@ public class PortfolioNavService : IPortfolioNavService } string targetCurrency = portfolio.Currency ?? "CNY"; - decimal TotalValue = 0; + decimal totalValue = 0; // 计算总市值 foreach (var pos in positions) @@ -166,7 +166,7 @@ public class PortfolioNavService : IPortfolioNavService .Where(t => t.PortfolioId == portfolioId && t.TransactionTime.Date <= today) .ToListAsync(); - decimal TotalCost = 0; + decimal totalCost = 0; foreach (var tx in transactions) { if (tx.Type == "buy") @@ -186,13 +186,13 @@ public class PortfolioNavService : IPortfolioNavService } // 计算净值 - decimal Nav = totalCost > 0 ? totalValue / totalCost : 1.0m; - decimal DailyReturn = 0; - decimal CumulativeReturn = totalCost > 0 ? (totalValue - totalCost) / totalCost * 100 : 0; + decimal nav = totalCost > 0 ? totalValue / totalCost : 1.0m; + decimal dailyReturn = 0; + decimal cumulativeReturn = totalCost > 0 ? (totalValue - totalCost) / totalCost * 100 : 0; if (yesterdayNav != null && yesterdayNav.TotalValue > 0) { - DailyReturn = (totalValue - yesterdayNav.TotalValue) / yesterdayNav.TotalValue * 100; + dailyReturn = (totalValue - yesterdayNav.TotalValue) / yesterdayNav.TotalValue * 100; } // 保存净值记录 @@ -280,8 +280,8 @@ public class PortfolioNavService : IPortfolioNavService } // 确定起始日期(最早交易日期) - var StartDate = transactions.Min(t => t.TransactionTime).Date; - var EndDate = DateTime.Today; + var startDate = transactions.Min(t => t.TransactionTime).Date; + var endDate = DateTime.Today; string targetCurrency = portfolio.Currency ?? "CNY"; _logger.LogInformation("开始回填净值历史: {PortfolioId}, 日期范围: {StartDate} ~ {EndDate}", @@ -302,10 +302,10 @@ public class PortfolioNavService : IPortfolioNavService decimal cumulativeCost = 0; // 记录创建数量 - int RecordsCreated = 0; + int recordsCreated = 0; // 遍历每个交易日 - for (var Date = startDate; date <= endDate; Date = date.AddDays(1)) + for (var date = startDate; date <= endDate; date = date.AddDays(1)) { // 检查是否已存在该日期的净值记录(非强制模式) if (!force) @@ -372,7 +372,7 @@ public class PortfolioNavService : IPortfolioNavService if (!holdings.Any()) continue; // 计算当日市值 - decimal TotalValue = 0; + decimal totalValue = 0; bool hasValidPrice = true; List failedSymbols = new List(); @@ -402,8 +402,8 @@ public class PortfolioNavService : IPortfolioNavService } // 计算净值 - decimal Nav = cumulativeCost > 0 ? totalValue / cumulativeCost : 1.0m; - decimal CumulativeReturn = cumulativeCost > 0 ? (totalValue - cumulativeCost) / cumulativeCost * 100 : 0; + decimal nav = cumulativeCost > 0 ? totalValue / cumulativeCost : 1.0m; + decimal cumulativeReturn = cumulativeCost > 0 ? (totalValue - cumulativeCost) / cumulativeCost * 100 : 0; // 获取昨日净值以计算日收益率 var yesterdayNav = await _db.Queryable() @@ -411,10 +411,10 @@ public class PortfolioNavService : IPortfolioNavService .OrderByDescending(n => n.NavDate) .FirstAsync(); - decimal DailyReturn = 0; + decimal dailyReturn = 0; if (yesterdayNav != null && yesterdayNav.TotalValue > 0) { - DailyReturn = (totalValue - yesterdayNav.TotalValue) / yesterdayNav.TotalValue * 100; + dailyReturn = (totalValue - yesterdayNav.TotalValue) / yesterdayNav.TotalValue * 100; } // 保存净值记录 @@ -536,33 +536,33 @@ public class PortfolioNavService : IPortfolioNavService { if (!history.Any()) return new NavStatistics(); - var MaxReturn = returns.Any() ? returns.Max() : 0; - var MinReturn = returns.Any() ? returns.Min() : 0; + var maxReturn = returns.Any() ? returns.Max() : 0; + var minReturn = returns.Any() ? returns.Min() : 0; // 计算最大回撤 - double MaxDrawdown = 0; + double maxDrawdown = 0; double peak = 1.0; foreach (var item in history.OrderBy(h => h.NavDate)) { - var Nav = (double)item.Nav; + var nav = (double)item.Nav; if (nav > peak) peak = nav; var drawdown = (peak - nav) / peak * 100; - if (drawdown > maxDrawdown) MaxDrawdown = drawdown; + if (drawdown > maxDrawdown) maxDrawdown = drawdown; } // 计算夏普比率(简化版,假设无风险利率=3%年化) - double SharpeRatio = 0; - double Volatility = 0; + double sharpeRatio = 0; + double volatility = 0; if (returns.Any()) { var avgReturn = returns.Average(); var stdDev = Math.Sqrt(returns.Sum(r => Math.Pow(r - avgReturn, 2)) / returns.Count); - Volatility = stdDev * Math.Sqrt(252); // 年化波动率 - SharpeRatio = stdDev > 0 ? (avgReturn * 252 - 3) / (stdDev * Math.Sqrt(252)) : 0; + volatility = stdDev * Math.Sqrt(252); // 年化波动率 + sharpeRatio = stdDev > 0 ? (avgReturn * 252 - 3) / (stdDev * Math.Sqrt(252)) : 0; } // 总收益率 - var TotalReturn = history.Any() + var totalReturn = history.Any() ? (double)(history.Last().CumulativeReturn) : 0; diff --git a/AssetManager.Services/PortfolioService.cs b/AssetManager.Services/PortfolioService.cs index 840293f..74e7488 100755 --- a/AssetManager.Services/PortfolioService.cs +++ b/AssetManager.Services/PortfolioService.cs @@ -159,7 +159,7 @@ public class PortfolioService : IPortfolioService return new CreatePortfolioResponse { Id = portfolio.Id, - totalValue = (double)portfolio.TotalValue, + TotalValue = (double)portfolio.TotalValue, ReturnRate = 0, Currency = portfolio.Currency, CreatedAt = portfolio.CreatedAt.ToString("yyyy-MM-dd HH:mm:ss") @@ -266,11 +266,11 @@ public class PortfolioService : IPortfolioService return new TotalAssetsResponse { - totalValue = (double)totalValueInTargetCurrency, + TotalValue = (double)totalValueInTargetCurrency, Currency = targetCurrency, TodayProfit = (double)totalTodayProfitInTargetCurrency, TodayProfitCurrency = targetCurrency, - totalReturnRate = Math.Round(totalReturnRate, 2) + TotalReturnRate = Math.Round(totalReturnRate, 2) }; } @@ -350,7 +350,7 @@ public class PortfolioService : IPortfolioService Amount = (int)pos.Shares, AveragePrice = (double)pos.AvgPrice, CurrentPrice = (double)currentPrice, - totalValue = (double)positionValueInTarget, + TotalValue = (double)positionValueInTarget, Profit = (double)(positionValueInTarget - costInTarget), ProfitRate = profitRate, ChangeAmount = (double)todayProfitInTarget, @@ -379,7 +379,7 @@ public class PortfolioService : IPortfolioService { Id = portfolio.StrategyId, Name = "策略名称", - description = "策略描述" + Description = "策略描述" }, PortfolioValue = (double)totalPortfolioValue, TotalReturn = (double)totalReturn, @@ -427,7 +427,7 @@ public class PortfolioService : IPortfolioService return new GetTransactionsResponse { - items = transactions.Select(t => new TransactionItem + Items = transactions.Select(t => new TransactionItem { Id = t.Id, PortfolioId = t.PortfolioId, @@ -441,9 +441,9 @@ public class PortfolioService : IPortfolioService Status = t.Status, Remark = t.Remark }).ToList(), - total = total, - page = offset / limit + 1, - pageSize = limit + Total = total, + Page = offset / limit + 1, + PageSize = limit }; }