将手工观察接入执行时钟并保留来源与账本语义
This commit is contained in:
@@ -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))
|
||||
|
||||
Reference in New Issue
Block a user