skfolio:基于scikit-learn构建的投资组合优化工具

·
·
·
自从马科维茨在1952年开发了现代投资组合理论以来,均值方差优化(MVO)一直备受关注。然而,MVO存在许多问题,比如对输入参数(预期收益和协方差)非常敏感、容易导致投资权重过于集中、频繁调整投资组合、在实际应用中表现不佳。相比之下,我们普遍认为简单的分配方法,比如等权分配或者逆卷分配,在实际应用中的表现往往优于MVO。为了解决这些问题,人们提出了许多方法,例如收缩方法、附加约束、正则化、不确定性集、考虑更高阶矩的方法、贝叶斯方法、连贯风险度量、优化左尾风险、分布鲁棒优化、因子模型、风险平价、层次聚类、集成方法、预选等。由于方法的数量众多,并且它们可以组合使用,所以我们需要一个统一的框架,结合机器学习方法,来进行模型选择、验证和参数调整,同时降低数据泄漏和过拟合的风险。

图片

skfolio是一个基于 scikit-learn 构建的用于投资组合优化的 Python 库。它提供了与 scikit-learn 兼容的统一界面和工具,用于构建、微调和交叉验证投资组合模型。skfolio提供以下的模型供使用:

  1. 可用的投资组合优化模型包括朴素方法(等权重分配、逆波动率分配、随机分配)、凸优化方法(均值-风险优化、风险分配、最大多样化、分布鲁棒CVaR)、聚类方法(层次风险平价、层次等风险贡献、嵌套聚类优化)和集成方法(堆叠优化)。
  2. 提供多种预期收益估计方法,如经验估计、指数加权估计、均衡估计和收缩估计。
  3. 协方差估计方法包括经验估计、格伯估计、去噪估计、去调估计、指数加权估计、Ledoit-Wolf估计、近似收缩估计、缩减协方差估计和图拉索协方差估计。
  4. 支持多种距离估计方法,如皮尔逊距离、肯德尔距离、斯皮尔曼距离、协方差距离、距离相关性和信息变异度。
  5. 提供多种先验估计方法,如经验估计、Black & Litterman估计和因子模型估计。
  6. 支持不确定性集估计方法,包括对预期收益的经验估计和循环自助法,以及对协方差的经验估计和循环自助法。
  7. 提供预选转换功能,如非支配选择、选择K个极端值和剔除高度相关资产。
  8. 支持交叉验证和模型选择,包括KFold和滚动向前验证等方法。
  9. 提供超参数调整功能,如GridSearchCV和RandomizedSearchCV。
  10. 支持多种风险度量方法,如方差、半方差、平均绝对偏差、CVaR、EVaR、最大回撤、平均回撤、溃疡指数、基尼平均差异、风险价值等。
  11. 提供优化功能,包括最小化风险、最大化收益、最大化效用、最大化比率、交易成本、管理费用、L1和L2正则化、权重约束、组约束、预算约束、跟踪误差约束以及周转率约束等。

安装skfolio

pip install -U skfolio

使用skfolio

# 导入
from sklearn import set_config
from sklearn.model_selection import (
    GridSearchCV,
    KFold,
    RandomizedSearchCV,
    train_test_split,
)
from sklearn.pipeline import Pipeline
from scipy.stats import loguniform

from skfolio import RatioMeasure, RiskMeasure
from skfolio.datasets import load_factors_dataset, load_sp500_dataset
from skfolio.model_selection import (
    CombinatorialPurgedCV,
    WalkForward,
    cross_val_predict,
)
from skfolio.moments import (
    DenoiseCovariance,
    DetoneCovariance,
    EWMu,
    GerberCovariance,
    ShrunkMu,
)
from skfolio.optimization import (
    MeanRisk,
    NestedClustersOptimization,
    ObjectiveFunction,
    RiskBudgeting,
)
from skfolio.pre_selection import SelectKExtremes
from skfolio.preprocessing import prices_to_returns
from skfolio.prior import BlackLitterman, EmpiricalPrior, FactorModel
from skfolio.uncertainty_set import BootstrapMuUncertaintySet


# 加载数据集
prices = load_sp500_dataset()


# 训练/测试数据划分
X = prices_to_returns(prices)
X_train, X_test = train_test_split(X, test_size=0.33, shuffle=False)


# 训练最小风险模型
model = MeanRisk()
model.fit(X_train)
print(model.weights_)


# 对测试集进行预测
portfolio = model.predict(X_test)
print(portfolio.annualized_sharpe_ratio)
print(portfolio.summary())


# 最大索提诺比率
model = MeanRisk(
    objective_function=ObjectiveFunction.MAXIMIZE_RATIO,
    risk_measure=RiskMeasure.SEMI_VARIANCE,
)

# 去噪协方差和缩小的预期回报
model = MeanRisk(
    objective_function=ObjectiveFunction.MAXIMIZE_RATIO,
    prior_estimator=EmpiricalPrior(
        mu_estimator=ShrunkMu(), covariance_estimator=DenoiseCovariance()
    ),
)

# 预期回报的不确定性
model = MeanRisk(
    objective_function=ObjectiveFunction.MAXIMIZE_RATIO,
    mu_uncertainty_set_estimator=BootstrapMuUncertaintySet(),
)

# 权重限制和交易成本
model = MeanRisk(
    min_weights={"AAPL"0.10"JPM"0.05},
    max_weights=0.8,
    transaction_costs={"AAPL"0.0001"RRC"0.0002},
    groups=[
        ["Equity"] * 3 + ["Fund"] * 5 + ["Bond"] * 12,
        ["US"] * 2 + ["Europe"] * 8 + ["Japan"] * 10,
    ],
    linear_constraints=[
        "Equity <= 0.5 * Bond",
        "US >= 0.1",
        "Europe >= 0.5 * Fund",
        "Japan <= 1",
    ],
)
model.fit(X_train)


# 参数网格搜索
model = MeanRisk(
    objective_function=ObjectiveFunction.MAXIMIZE_RATIO,
    risk_measure=RiskMeasure.VARIANCE,
    prior_estimator=EmpiricalPrior(mu_estimator=EWMu(alpha=0.2)),
)

print(model.get_params(deep=True))

gs = GridSearchCV(
    estimator=model,
    cv=KFold(n_splits=5, shuffle=False),
    n_jobs=-1,
    param_grid={
        "risk_measure": [
            RiskMeasure.VARIANCE,
            RiskMeasure.CVAR,
            RiskMeasure.VARIANCE.CDAR,
        ],
        "prior_estimator__mu_estimator__alpha": [0.050.10.20.5],
    },
)
gs.fit(X)

best_model = gs.best_estimator_

print(best_model.weights_)


# K 折交叉验证
model = MeanRisk()
mmp = cross_val_predict(model, X_test, cv=KFold(n_splits=5))
# mmp is the predicted MultiPeriodPortfolio object composed of 5 Portfolios (1 per testing fold)

mmp.plot_cumulative_returns()
print(mmp.summary()
组合清除交叉验证

发布者:股市刺客,转载请注明出处:https://www.95sca.cn/archives/111047
站内所有文章皆来自网络转载或读者投稿,请勿用于商业用途。如有侵权、不妥之处,请联系站长并出示版权证明以便删除。敬请谅解!

(0)
股市刺客的头像股市刺客
上一篇 2小时前
下一篇 2小时前

相关推荐

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注