fix(backtest): NaN/Inf浮点→None消毒(vnpy统计+empyrical指标+时序)修JSON序列化500
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
"""CTA strategy backtesting engine wrapper using vnpy_ctastrategy.backtesting."""
|
||||
import sys
|
||||
import os
|
||||
import math
|
||||
import traceback
|
||||
import uuid
|
||||
from datetime import datetime
|
||||
@@ -120,9 +121,11 @@ def run_cta_backtest(strategy_class, symbol: str, params: dict, start: str, end:
|
||||
# calculate_statistics(df) returns the stats dict (sharpe/drawdown/etc.)
|
||||
daily_df = engine.calculate_result()
|
||||
raw_stats = engine.calculate_statistics(daily_df, output=False) or {}
|
||||
# Ensure JSON-serializable (vnpy may include Timestamp / non-numeric values)
|
||||
# Ensure JSON-serializable (vnpy may include Timestamp / non-numeric / NaN values)
|
||||
statistics = {
|
||||
k: (v if isinstance(v, (int, float, str, bool)) or v is None else str(v))
|
||||
k: (None if (isinstance(v, float) and not math.isfinite(v))
|
||||
else v if isinstance(v, (int, float, str, bool)) or v is None
|
||||
else str(v))
|
||||
for k, v in raw_stats.items()
|
||||
}
|
||||
|
||||
@@ -173,7 +176,8 @@ def run_cta_backtest(strategy_class, symbol: str, params: dict, start: str, end:
|
||||
if isinstance(series, pd.Series):
|
||||
series_data[key] = {
|
||||
"dates": series.index.astype(str).tolist(),
|
||||
"values": series.tolist()
|
||||
"values": [None if (isinstance(x, float) and not math.isfinite(x)) else x
|
||||
for x in series.tolist()]
|
||||
}
|
||||
|
||||
# Write metrics series to JSON file
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
"""回测相对/绝对指标计算(empyrical,聚宽同源口径)。纯函数。"""
|
||||
from dataclasses import dataclass, field
|
||||
from typing import Dict, Literal
|
||||
import math
|
||||
import numpy as np
|
||||
import pandas as pd
|
||||
import empyrical
|
||||
@@ -44,6 +45,8 @@ def compute_metrics(
|
||||
"benchmark_return": float(empyrical.cum_returns_final(b)),
|
||||
"benchmark_volatility": float(empyrical.annual_volatility(b, period='daily')),
|
||||
}
|
||||
# Sanitize non-finite floats (NaN/Inf from degenerate inputs) → None for JSON safety
|
||||
scalars = {k: (None if isinstance(v, float) and not math.isfinite(v) else v) for k, v in scalars.items()}
|
||||
|
||||
equity = empyrical.cum_returns(s)
|
||||
bench_curve = empyrical.cum_returns(b)
|
||||
|
||||
Reference in New Issue
Block a user