fix: 首页组合收益率实时计算

This commit is contained in:
OpenClaw Agent 2026-03-16 08:56:14 +00:00
parent c7712e57bb
commit 71aa7211d6

View File

@ -176,31 +176,61 @@ public class PortfolioService : IPortfolioService
foreach (var p in portfolios)
{
// 获取持仓数量
var positionCount = _db.Queryable<Position>()
// 获取该组合的所有持仓
var positions = _db.Queryable<Position>()
.Where(pos => pos.PortfolioId == p.Id)
.Count();
.ToList();
// 获取今日盈亏(从净值历史)
var todayNav = _db.Queryable<PortfolioNavHistory>()
.Where(n => n.PortfolioId == p.Id && n.NavDate == DateTime.Today)
.First();
int positionCount = positions.Count;
double todayProfit = 0;
if (todayNav != null && p.TotalValue > 0)
// 实时计算当前市值和总成本
decimal totalValue = 0;
decimal totalCost = 0;
decimal todayProfit = 0;
string portfolioCurrency = p.Currency ?? "CNY";
foreach (var pos in positions)
{
// 今日盈亏 = 今日市值 - 昨日市值
var yesterdayNav = _db.Queryable<PortfolioNavHistory>()
.Where(n => n.PortfolioId == p.Id && n.NavDate < DateTime.Today)
.OrderByDescending(n => n.NavDate)
.First();
if (yesterdayNav != null)
if (pos.StockCode == null || pos.Currency == null)
{
todayProfit = (double)(todayNav.TotalValue - yesterdayNav.TotalValue);
continue;
}
// 获取实时价格
decimal currentPrice = pos.AvgPrice;
decimal previousClose = pos.AvgPrice;
try
{
var priceResponse = _marketDataService.GetPriceAsync(pos.StockCode, pos.AssetType ?? "Stock").GetAwaiter().GetResult();
if (priceResponse.Price > 0)
{
currentPrice = priceResponse.Price;
previousClose = priceResponse.PreviousClose > 0 ? priceResponse.PreviousClose : currentPrice;
}
}
catch (Exception ex)
{
_logger.LogWarning(ex, "获取标的 {StockCode} 实时价格失败,使用成本价", pos.StockCode);
}
decimal positionValue = pos.Shares * currentPrice;
decimal positionCost = pos.Shares * pos.AvgPrice;
decimal positionTodayProfit = previousClose > 0 ? pos.Shares * (currentPrice - previousClose) : 0;
// 汇率转换到组合本位币
var valueInTarget = _exchangeRateService.ConvertAmountAsync(positionValue, pos.Currency, portfolioCurrency).GetAwaiter().GetResult();
var costInTarget = _exchangeRateService.ConvertAmountAsync(positionCost, pos.Currency, portfolioCurrency).GetAwaiter().GetResult();
var todayProfitInTarget = _exchangeRateService.ConvertAmountAsync(positionTodayProfit, pos.Currency, portfolioCurrency).GetAwaiter().GetResult();
totalValue += valueInTarget;
totalCost += costInTarget;
todayProfit += todayProfitInTarget;
}
// 计算收益率
double returnRate = totalCost > 0 ? (double)((totalValue - totalCost) / totalCost * 100) : 0;
returnRate = Math.Round(returnRate, 2);
result.Add(new PortfolioListItem
{
Id = p.Id,
@ -211,11 +241,11 @@ public class PortfolioService : IPortfolioService
IconChar = p.Name?.Substring(0, 1).ToUpper() ?? "P",
IconBgClass = "bg-blue-100",
IconTextClass = "text-blue-700",
Value = (double)p.TotalValue,
Value = (double)totalValue,
Currency = p.Currency,
ReturnRate = (double)p.ReturnRate,
ReturnType = p.ReturnRate >= 0 ? "positive" : "negative",
TodayProfit = todayProfit,
ReturnRate = returnRate,
ReturnType = returnRate >= 0 ? "positive" : "negative",
TodayProfit = (double)todayProfit,
TodayProfitCurrency = p.Currency
});
}