将手工观察接入执行时钟并保留来源与账本语义

This commit is contained in:
boris
2026-09-14 11:41:15 +08:00
parent 93de28d369
commit 7f0c6a008a
10 changed files with 435 additions and 95 deletions
+18 -1
View File
@@ -93,6 +93,15 @@ pub fn compute_backtest_metrics(
account_events: &[AccountEvent],
initial_cash: f64,
risk_free_contract: Option<&RiskFreeRateContract>,
) -> Result<BacktestMetrics, String> {
compute_backtest_metrics_with_manual(equity_curve, fills, &[], daily_holdings, account_events, initial_cash, risk_free_contract)
}
pub fn compute_backtest_metrics_with_manual(
equity_curve: &[DailyEquityPoint], fills: &[FillEvent],
manual_executions: &[crate::manual_execution::ManualReplayApplication],
daily_holdings: &[HoldingSummary], account_events: &[AccountEvent], initial_cash: f64,
risk_free_contract: Option<&RiskFreeRateContract>,
) -> Result<BacktestMetrics, String> {
let Some(first_point) = equity_curve.first() else {
return Ok(BacktestMetrics {
@@ -229,12 +238,20 @@ pub fn compute_backtest_metrics(
);
let monthly_volatility = annualized_std(&monthly_portfolio_returns, MONTHS_PER_YEAR);
let turnover_by_date = fills
let mut turnover_by_date = fills
.iter()
.fold(BTreeMap::<NaiveDate, f64>::new(), |mut acc, fill| {
*acc.entry(fill.date).or_default() += fill.gross_amount.abs();
acc
});
for execution in manual_executions {
use rust_decimal::prelude::ToPrimitive;
let gross = execution.ledger_gross_amount.parse::<rust_decimal::Decimal>()
.ok().and_then(|value| value.to_f64()).filter(|value| value.is_finite() && *value >= 0.)
.ok_or("manual turnover requires its validated ledger gross amount")?;
let date = execution.observed_at.with_timezone(&chrono::FixedOffset::east_opt(8 * 3600).unwrap()).date_naive();
*turnover_by_date.entry(date).or_default() += gross;
}
let equity_by_date = equity_curve
.iter()
.map(|point| (point.date, point.total_equity))