feat: add portfolio risk computation contracts
CI / lite (pull_request) Successful in 10s

This commit is contained in:
ao gong
2026-09-01 13:57:03 +08:00
parent d4ee6f005f
commit 8c5af40dad
6 changed files with 3026 additions and 13 deletions
+106
View File
@@ -28,6 +28,7 @@
- `research_pipeline` — 因子日 → 下一真实交易日 → 显式执行价 → 日末估值 → 成本后绩效(防前视编排)
- `governed_pipeline` — 数据快照 → 因子版本 → 策略版本 → 回测运行 → 目标组合 → 风险决策 → Paper 订单意图;同时拥有输入/配置/重放血缘决定的 `BacktestRunRef`
- `artifact` — 版本化、确定性、存储中立的完整 research run 事实表,以及只映射现有表的 `BacktestEvidenceManifest`
- `portfolio_risk_contracts` — S3 证据闭合的 `PortfolioDecision` / `RiskAssessment` v1;独立复核 freshness、约束与 computation receipt,并复用既有标签安全风险分解
- `attribution` — 基于实际成交后持仓的隔夜 / 日内 / 交易成本逐日收益归因与闭合审计
- `metrics` — 绝对绩效 + 严格日期对齐的 TE / IR / alpha / beta 基准相对绩效
- `factor_library` — 通用方法(turnover / winsorize / IC / OLS / jb_test)
@@ -259,6 +260,111 @@ digest 等价,也不会把旧 run 静默升级为新合同。
`LEGACY_EXPLORATORY`;不能隐式提升为 `CONTRACT_QUALIFIED`。所有资格均只描述离线证据闭合,
不表示投资有效、组合获批、Paper、生产或实盘就绪。
## 组合决策与风险评估合同 v1
`quant_engine.portfolio_risk_contracts` 是现有计算 owner 外围的薄合同层。创建
`PortfolioDecision` 必须同时提供完整 `BacktestRunRef`、嵌入同一 RunRef 的
`CONTRACT_QUALIFIED` 非 legacy `BacktestEvidenceManifest`、现有 `PortfolioTarget`、
`FreshnessPolicy`、`ConstraintSetV1` 与 `ComputationReceipt`。适配器会从权威输入独立重算
receipt 的 input/constraint/output digest、敞口、持仓数和 L1 turnover 残差;receipt 自报
成功、fallback 或放宽 tolerance 均不能替代复核。
```python
from quant_engine.portfolio_risk_contracts import (
ComputationReceipt,
ConstraintSetV1,
FreshnessPolicy,
assess_portfolio_risk,
build_portfolio_decision,
compute_portfolio_receipt_digests,
)
freshness = FreshnessPolicy(
max_manifest_age_seconds=3600,
max_covariance_age_days=5,
)
constraints = ConstraintSetV1(
gross_exposure_max=1.0,
single_asset_max=0.10,
position_count_max=20,
turnover_max=0.30,
)
# 生产者先形成公开 canonical digest;decision 构建时仍会独立重算。
expected = compute_portfolio_receipt_digests(
backtest_run_ref=run_ref,
manifest=evidence_manifest,
target=portfolio_target,
objective_name="long_only_allocation",
objective_version="1.0.0",
objective_digest=objective_digest,
model_name="factor_weighting",
model_version="1.0.0",
model_digest=model_digest,
expected_return_digest=expected_return_digest,
covariance_digest=covariance_digest,
scenario_digest=scenario_digest,
constraints=constraints,
freshness_policy=freshness,
prior_weights=prior_weights,
)
receipt = ComputationReceipt(
algorithm="factor_weighting",
algorithm_version="1.0.0",
implementation_digest=implementation_digest,
parameter_digest=parameter_digest,
input_digest=expected["input_digest"],
constraint_digest=expected["constraint_digest"],
output_digest=expected["output_digest"],
status="completed",
solver_required=False,
solver_name=None,
solver_version=None,
solver_config_digest=None,
iterations=None,
objective_value=None,
max_constraint_residual=expected["max_constraint_residual"],
tolerance=1e-12,
computed_at=computed_at,
)
decision = build_portfolio_decision(
backtest_run_ref=run_ref,
manifest=evidence_manifest,
target=portfolio_target,
objective_name="long_only_allocation",
objective_version="1.0.0",
objective_digest=objective_digest,
model_name="factor_weighting",
model_version="1.0.0",
model_digest=model_digest,
expected_return_digest=expected_return_digest,
covariance_digest=covariance_digest,
scenario_digest=scenario_digest,
constraints=constraints,
freshness_policy=freshness,
receipt=receipt,
computed_at=computed_at,
prior_weights=prior_weights,
)
assessment = assess_portfolio_risk(
portfolio_decision=decision,
backtest_run_ref=run_ref,
manifest=evidence_manifest,
covariance=covariance_snapshot,
risk_model_name="euler_volatility",
risk_model_version="1.0.0",
risk_model_digest=risk_model_digest,
)
```
`source_universe_digest` 保留 S3 研究 universe 身份,`portfolio_asset_set_digest` 只描述实际
目标资产标签;二者不会互相冒充成员证明。风险评估在任何数值计算前要求 covariance、target、
RunRef 的 dataset identity 三方一致,并且只调用一次现有 `labeled_component_risk()`。合同中的
`qualified` 仅表示 S4.1 计算证据闭合,不授予 maker-checker、发布、订单、Paper、生产或实盘权限。
## 治理垂直切片
`governed_pipeline` 不复制因子、回测、组合或执行算法,只编排现有能力并补充版本与风险契约。