Align jq microcap execution with intraday snapshots

This commit is contained in:
boris
2026-04-20 12:13:59 +08:00
parent 0e2c25e4c4
commit 0fe681ff5f
10 changed files with 761 additions and 94 deletions

View File

@@ -163,10 +163,12 @@ pub fn compute_backtest_metrics(
);
let monthly_volatility = annualized_std(&monthly_portfolio_returns, MONTHS_PER_YEAR);
let turnover_by_date = fills.iter().fold(BTreeMap::<NaiveDate, f64>::new(), |mut acc, fill| {
*acc.entry(fill.date).or_default() += fill.gross_amount.abs();
acc
});
let turnover_by_date = fills
.iter()
.fold(BTreeMap::<NaiveDate, f64>::new(), |mut acc, fill| {
*acc.entry(fill.date).or_default() += fill.gross_amount.abs();
acc
});
let equity_by_date = equity_curve
.iter()
.map(|point| (point.date, point.total_equity))
@@ -177,7 +179,10 @@ pub fn compute_backtest_metrics(
equity_curve
.iter()
.map(|point| {
let traded = turnover_by_date.get(&point.date).copied().unwrap_or_default();
let traded = turnover_by_date
.get(&point.date)
.copied()
.unwrap_or_default();
safe_div(traded, point.total_equity.max(initial_cash * 0.5), 0.0)
})
.sum::<f64>()
@@ -270,7 +275,10 @@ fn annualized_sharpe(returns: &[f64], daily_rf: f64, periods_per_year: f64) -> f
if returns.len() < 2 {
return 0.0;
}
let adjusted = returns.iter().map(|value| value - daily_rf).collect::<Vec<_>>();
let adjusted = returns
.iter()
.map(|value| value - daily_rf)
.collect::<Vec<_>>();
let mean_ret = mean(&adjusted);
let std = std_dev(&adjusted);
if std <= f64::EPSILON {
@@ -284,7 +292,10 @@ fn annualized_sortino(returns: &[f64], daily_rf: f64, periods_per_year: f64) ->
if returns.is_empty() {
return 0.0;
}
let adjusted = returns.iter().map(|value| value - daily_rf).collect::<Vec<_>>();
let adjusted = returns
.iter()
.map(|value| value - daily_rf)
.collect::<Vec<_>>();
let downside = adjusted
.iter()
.filter(|value| **value < 0.0)
@@ -309,7 +320,10 @@ fn alpha_beta(returns: &[f64], benchmark_returns: &[f64], daily_rf: f64) -> (f64
if returns.len() < 2 || returns.len() != benchmark_returns.len() {
return (0.0, 0.0);
}
let strategy_excess = returns.iter().map(|value| value - daily_rf).collect::<Vec<_>>();
let strategy_excess = returns
.iter()
.map(|value| value - daily_rf)
.collect::<Vec<_>>();
let benchmark_excess = benchmark_returns
.iter()
.map(|value| value - daily_rf)