feat: 用户访问时自动触发当日净值计算

修改 GetNavHistoryAsync:
- 检查是否存在今日净值记录
- 如果不存在,自动调用 CalculateAndSaveDailyNavAsync
- 捕获异常避免影响历史数据查询

收益:
- 用户每次访问收益曲线都能获取最新数据
- 无需手动触发或定时任务
This commit is contained in:
OpenClaw Agent 2026-03-24 06:22:28 +00:00
parent 1c3add27ef
commit c0accdc903

View File

@ -54,6 +54,27 @@ public class PortfolioNavService : IPortfolioNavService
_logger.LogInformation("组合 {PortfolioId} 无净值历史数据,自动开始回填", portfolioId);
await BackfillNavHistoryInternalAsync(portfolioId, portfolio);
}
else
{
// 有历史数据,检查是否需要计算今日净值
var today = DateTime.Today;
var todayNavExists = await _db.Queryable<PortfolioNavHistory>()
.Where(n => n.PortfolioId == portfolioId && n.NavDate == today)
.AnyAsync();
if (!todayNavExists)
{
_logger.LogInformation("组合 {PortfolioId} 今日净值不存在,自动计算", portfolioId);
try
{
await CalculateAndSaveDailyNavAsync(portfolioId);
}
catch (Exception ex)
{
_logger.LogWarning(ex, "组合 {PortfolioId} 今日净值计算失败,将使用历史数据", portfolioId);
}
}
}
// 查询净值历史
var navHistory = await _db.Queryable<PortfolioNavHistory>()
@ -77,45 +98,6 @@ public class PortfolioNavService : IPortfolioNavService
// 计算统计指标
var returns = navHistory.Select(n => (double)n.DailyReturn).Where(r => r != 0).ToList();
var statistics = CalculateStatistics(returns, navHistory);
// 如果净值历史的最后一条不是今天,实时计算当前累计收益率
var lastNavDate = navHistory.Last().NavDate;
if (lastNavDate < DateTime.Today)
{
// 获取当前持仓数据
var positions = await _db.Queryable<PortfolioPosition>()
.Where(p => p.PortfolioId == portfolioId)
.ToListAsync();
if (positions.Any())
{
// 计算当前总市值和总成本
decimal totalValue = 0;
decimal totalCost = 0;
foreach (var pos in positions)
{
var currentValue = pos.Shares * pos.CurrentPrice;
var cost = pos.Shares * pos.AverageCost;
// 汇率转换
var currentInTarget = await _exchangeRateService.ConvertAmountAsync(currentValue, pos.Currency, portfolio.Currency);
var costInTarget = await _exchangeRateService.ConvertAmountAsync(cost, pos.Currency, portfolio.Currency);
totalValue += currentInTarget;
totalCost += costInTarget;
}
// 计算实时累计收益率
if (totalCost > 0)
{
var realTimeReturn = (double)((totalValue - totalCost) / totalCost * 100);
statistics.TotalReturn = Math.Round(realTimeReturn, 2);
_logger.LogDebug("实时计算累计收益率: {RealTimeReturn}%, 总市值: {TotalValue}, 总成本: {TotalCost}",
realTimeReturn, totalValue, totalCost);
}
}
}
return new NavHistoryResponse
{