This commit is contained in:
@@ -24,6 +24,7 @@
|
||||
- `data_adapter` — 桥接 qtdb_pro 长表与新模块(rename / long-wide / 复权 / vwap 代理)
|
||||
- `backtest` — weight-based 多日仿真(rebalance_table / compute_nav / compare_to_benchmark)
|
||||
- `portfolio_construction` — 多期因子分数 → Top-K → 等权目标权重表
|
||||
- `research_pipeline` — 因子日 → 下一真实交易日 → 显式执行价 → 执行审计(防前视编排)
|
||||
- `metrics` — 绩效(年化收益 / 波动率 / Sharpe / 最大回撤 / Calmar)
|
||||
- `factor_library` — 通用方法(turnover / winsorize / IC / OLS / jb_test)
|
||||
- `portfolio_decomp` — 组合分解(risk_parity / mean_variance / 因子归因)
|
||||
@@ -61,8 +62,8 @@ from quant_engine.alpha_factors import alpha_001, alpha_005, ALPHA158_REGISTRY
|
||||
from quant_engine.execution import (
|
||||
ExecutionConfig, simulate_multi_day_with_audit, simulate_with_daily_data,
|
||||
)
|
||||
from quant_engine.research_pipeline import run_factor_execution_research
|
||||
from quant_engine.backtest import run_weight_backtest
|
||||
from quant_engine.portfolio_construction import scores_to_weight_table
|
||||
from quant_engine.indicators import macd, bollinger, kdj
|
||||
from quant_engine.data_adapter import (
|
||||
long_to_wide, wide_to_long, rename_tushare_columns,
|
||||
@@ -73,8 +74,9 @@ from quant_engine.data_adapter import (
|
||||
|
||||
# 端到端:qtdb_pro 长表 → 适配 → alpha158 → execution
|
||||
df = load_qtdb_daily(["000001.SZ"], "2024-01-01", with_adj=True)
|
||||
prices, volumes = prepare_execution_inputs(df)
|
||||
result = simulate_with_daily_data(prices, initial_cash=1_000_000.0)
|
||||
close_prices, volumes = prepare_execution_inputs(df)
|
||||
open_prices, _ = prepare_execution_inputs(df, price_col="open")
|
||||
result = simulate_with_daily_data(close_prices, initial_cash=1_000_000.0)
|
||||
|
||||
# 已正确滞后的目标权重 → 现金约束执行 → 唯一来源的成交/拒绝/日末持仓/NAV
|
||||
execution = simulate_multi_day_with_audit(
|
||||
@@ -92,18 +94,25 @@ execution = simulate_multi_day_with_audit(
|
||||
print(execution.nav_series)
|
||||
print(execution.daily_executions)
|
||||
|
||||
# 多期因子分数 → Top-K 等权组合 → 稳定回测结果
|
||||
rebalance_weights = scores_to_weight_table(
|
||||
# 多期因子分数(必须是 point-in-time 数据)→ Top-K → 下一交易日 open 执行
|
||||
factor_execution = run_factor_execution_research(
|
||||
factor_scores,
|
||||
top_k=20,
|
||||
gross_exposure=1.0,
|
||||
execution_prices=open_prices,
|
||||
execution_price_field="open",
|
||||
initial_cash=1_000_000.0,
|
||||
)
|
||||
|
||||
# run_weight_backtest 是低层算子:只接受收益区间开始前已经生效的持仓权重。
|
||||
# 不要把 signal-date 的 factor_scores/decision_weights 直接传给它。
|
||||
backtest = run_weight_backtest(
|
||||
weights=rebalance_weights,
|
||||
weights=effective_holding_weights,
|
||||
stock_returns=daily_returns,
|
||||
initial_capital=1_000_000.0,
|
||||
benchmark_nav=benchmark_nav,
|
||||
)
|
||||
print(factor_execution.schedule.signal_to_execution)
|
||||
print(factor_execution.execution.daily_executions)
|
||||
print(backtest.stats())
|
||||
print(backtest.benchmark_report())
|
||||
```
|
||||
|
||||
@@ -76,8 +76,9 @@ def compute_nav_from_weights(
|
||||
) -> pd.Series:
|
||||
"""从调仓表(日期 × 股票权重)+ 个股日收益 → 净值曲线。
|
||||
|
||||
假设:在调仓日之间权重不变(**前向填充**)。
|
||||
调仓日的权重 = `weights.loc[rebalance_date]`。
|
||||
假设:输入是该收益测量区间开始前已经生效的持仓权重,并在调仓日之间
|
||||
保持不变(**前向填充**)。本函数不会把信号日自动解释为执行日;因子分数
|
||||
应先经交易日历调度和实际执行时点处理,避免把同一时点未知的收益计入。
|
||||
|
||||
Args:
|
||||
weights: 调仓日 × 股票代码 的权重 DataFrame(**0~1**,行和 ≤ 1)
|
||||
|
||||
@@ -91,10 +91,10 @@ def test_scores_to_weight_table_constructs_each_rebalance_independently() -> Non
|
||||
pd.testing.assert_series_equal(result.iloc[0], changed_result.iloc[0])
|
||||
|
||||
|
||||
def test_factor_scores_flow_directly_into_weight_backtest() -> None:
|
||||
def test_effective_holding_weights_flow_into_weight_backtest() -> None:
|
||||
dates = pd.date_range("2026-01-05", periods=3, freq="B")
|
||||
scores = pd.DataFrame(
|
||||
{"A": [2.0, 0.0], "B": [1.0, 3.0]},
|
||||
effective_weights = pd.DataFrame(
|
||||
{"A": [1.0, 0.0], "B": [0.0, 1.0]},
|
||||
index=dates[[0, 2]],
|
||||
)
|
||||
stock_returns = pd.DataFrame(
|
||||
@@ -102,11 +102,10 @@ def test_factor_scores_flow_directly_into_weight_backtest() -> None:
|
||||
index=dates,
|
||||
)
|
||||
|
||||
weights = scores_to_weight_table(scores, top_k=1)
|
||||
result = run_weight_backtest(weights, stock_returns)
|
||||
result = run_weight_backtest(effective_weights, stock_returns)
|
||||
|
||||
pd.testing.assert_series_equal(result.nav, pd.Series([1.1, 1.1, 1.32], index=dates))
|
||||
pd.testing.assert_frame_equal(result.weights, weights)
|
||||
pd.testing.assert_frame_equal(result.weights, effective_weights)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("top_k", [0, -1])
|
||||
|
||||
Reference in New Issue
Block a user