Skip to content

交易 - 组合优化

jh_quant.trading 集成了 Riskfolio-Lib 进行组合优化与再平衡。

启用组合优化

from jh_quant.trading.config import (
SessionServiceConfigBuilder,
RebalanceMode,
RebalancePolicySpec,
)
config = (
SessionServiceConfigBuilder.defaults()
.with_session(session_id="optimized", mode="paper")
.with_selection(...)
.add_strategy(...)
.with_portfolio(
enabled=True,
objective="MinRisk", # MinRisk / MaxRet / MaxSharpe / MaxUtility
risk_measure="MV", # MV / MAD / MSV / CVaR / CDaR 等
model="Classic", # Classic / BL / FM / HRP / HERC / NCO
covariance_method="hist", # hist / ewma1 / ewma2 / ledoit / oas 等
min_weight=0.01,
max_weight=0.20,
lookback=252,
rebalance_policy=RebalancePolicySpec(
mode=RebalanceMode.DRIFT_THRESHOLD,
drift_threshold=0.10,
),
)
.build()
)

再平衡模式

DRIFT_THRESHOLD(漂移触发)

实际持仓偏离目标权重超过阈值时触发。

rebalance_policy=RebalancePolicySpec(
mode=RebalanceMode.DRIFT_THRESHOLD,
drift_threshold=0.10,
min_rebalance_interval_seconds=86400,
)

EVERY_CYCLE(每周期)

每个交易周期都运行优化并再平衡。

INITIAL_ONLY(仅首次建仓)

初始运行一次建仓,之后由策略自主调仓。

SCHEDULE(定时调度)

rebalance_policy=RebalancePolicySpec(
mode=RebalanceMode.SCHEDULE,
schedule_cron="0 16 * * 5", # 每周五 16:00
)

再平衡执行流程

策略选股信号
Riskfolio-Lib 优化 ── 输入:历史收益率矩阵 + 选股信号
│ 输出:原始目标权重
权重后处理 ── 信号引导的权重微调、上下限截断
再平衡计划 ── 对比目标权重 vs 当前持仓
│ T+1 约束、资金约束、取整约束
TradingEngine 执行订单

REST API

优化预览

POST /sessions/{session_id}/portfolio/optimize

触发再平衡

POST /sessions/{session_id}/portfolio/rebalance

查看组合分析

GET /sessions/{session_id}/portfolio/analysis

编程接口

from jh_quant.trading.portfolio import (
RiskfolioPortfolioOptimizer,
optimize_portfolio_preview,
build_rebalance_plan,
)
from jh_quant.trading.config.portfolio import PortfolioSpec
spec = PortfolioSpec(
objective="MinRisk",
risk_measure="MV",
model="Classic",
covariance_method="hist",
min_weight=0.01,
max_weight=0.20,
lookback=252,
)
optimizer = RiskfolioPortfolioOptimizer()
result = optimizer.optimize(
returns=returns_df,
portfolio_spec=spec,
signals=signal_scores,
)
print(result.weights) # 目标权重
print(result.diagnostics) # 优化诊断
# 生成再平衡订单
plan = build_rebalance_plan(
target_weights=result.weights,
positions=current_positions,
latest_prices=prices,
portfolio_spec=spec,
)