feat: 量化引擎加固 — 新增测试 + 数据/因子/回测层优化
- 新增 finance/tests/ 6 个测试套件(agents/backtest/dao_upsert/factors/features/fundamental_lookahead) - 数据层: data_manager / dao 优化,新增 upsert 逻辑 - 因子层: 基本面因子抽象定位 _mapping、ROE/PE/PB 重构 - 回测层: vectorbt/engine 大改动(251 行),report 增强 - ML 层: features/backtest_integration 特征工程与回测优化 - CLI: agent_cli 重构 - config/settings 扩充配置项
This commit is contained in:
+23
-13
@@ -129,9 +129,13 @@ class OptunaEngine:
|
||||
|
||||
n_total = len(price_df)
|
||||
windows = []
|
||||
test_equities = []
|
||||
param_history = []
|
||||
|
||||
# 跨窗口结转资本:consolidated 是连续可投资的净值曲线,
|
||||
# 每个测试窗口的收益按期初已积累资本放大,而非各自从 100k 独立重算。
|
||||
running_capital = float(self.bt_engine.initial_capital)
|
||||
equity_parts: list[pd.Series] = []
|
||||
|
||||
start = 0
|
||||
while start + train_window + test_window <= n_total:
|
||||
train_slice = slice(start, start + train_window)
|
||||
@@ -162,8 +166,14 @@ class OptunaEngine:
|
||||
|
||||
test_report = self.bt_engine.run(test_strategy, test_price, test_factor)
|
||||
|
||||
if len(test_report.equity_curve) > 0:
|
||||
test_equities.append(test_report.equity_curve)
|
||||
# 该窗口的相对收益 → 用累计资本放大 → 连续资本曲线
|
||||
eq = test_report.equity_curve
|
||||
if eq is not None and len(eq) > 0:
|
||||
window_ret = eq.pct_change().fillna(0.0)
|
||||
# 用上一窗口末累计资本作基准放大本窗口收益
|
||||
window_capital = running_capital * (1 + window_ret).cumprod()
|
||||
equity_parts.append(window_capital)
|
||||
running_capital = float(window_capital.iloc[-1])
|
||||
|
||||
train_idx = train_price.index
|
||||
test_idx = test_price.index
|
||||
@@ -182,8 +192,8 @@ class OptunaEngine:
|
||||
|
||||
start += test_window
|
||||
|
||||
# 合并测试期权益曲线
|
||||
consolidated = _merge_test_periods(test_equities, self.bt_engine.initial_capital)
|
||||
# 合并测试期权益曲线(跨窗口结转后的连续净值)
|
||||
consolidated = _merge_test_periods(equity_parts)
|
||||
|
||||
# 参数稳定性
|
||||
param_df = pd.DataFrame(param_history) if param_history else pd.DataFrame()
|
||||
@@ -198,20 +208,20 @@ class OptunaEngine:
|
||||
|
||||
|
||||
def _merge_test_periods(
|
||||
equity_list: list[pd.Series],
|
||||
initial_capital: float = 100_000,
|
||||
equity_parts: list[pd.Series],
|
||||
) -> BacktestReport | None:
|
||||
"""拼接各窗口测试期权益曲线为一个连续序列。"""
|
||||
if not equity_list:
|
||||
"""拼接已跨窗口结转资本的测试期净值片段为连续序列。"""
|
||||
if not equity_parts:
|
||||
return None
|
||||
|
||||
merged = pd.concat(equity_list)
|
||||
merged = merged.sort_index()
|
||||
merged = merged[~merged.index.duplicated()]
|
||||
merged = pd.concat(equity_parts)
|
||||
merged = merged[~merged.index.duplicated(keep="last")].sort_index()
|
||||
|
||||
# 确保 DatetimeIndex
|
||||
if not isinstance(merged.index, pd.DatetimeIndex):
|
||||
merged.index = pd.to_datetime(merged.index, format="%Y%m%d")
|
||||
parsed = pd.to_datetime(merged.index, format="%Y%m%d", errors="coerce")
|
||||
if parsed.notna().all():
|
||||
merged.index = parsed
|
||||
|
||||
dd = merged / merged.cummax() - 1
|
||||
daily_ret = merged.pct_change().dropna()
|
||||
|
||||
Reference in New Issue
Block a user