Risk Models Comparison#
This example script is available in the repository.
- diagonal risk model
- diagonal risk model with risk forecast error
- full covariance
- full covariance with risk forecast error
- ...
We test on a long-only portfolio and use automatic hyper-parameter
optimization to maximize the information ratio, in back-test,
versus the index ETF.
"""
from pprint import pprint
import numpy as np
import pandas as pd
import cvxportfolio as cvx
from .universes import DOW30 as UNIVERSE
# Index
INDEX = 'DIA'
# Times.
START = '2000-01-01'
END = None # today
# Leverage.
LEVERAGE_LIMIT = 1.
# Stock market simulator with default transaction and
# holding cost models.
simulator = cvx.StockMarketSimulator(UNIVERSE + [INDEX])
# Build benchmark.
all_in_index = pd.Series(
0., index = simulator.market_data.returns.columns)
all_in_index[INDEX] = 1.
benchmark = cvx.FixedWeights(all_in_index)
# Define hyper-parameter objects.
# These will be included in the library in a future release.
class GammaTradeCoarse(cvx.RangeHyperParameter):
"""Transaction cost multiplier, coarse value range."""
def __init__(self):
super().__init__(
values_range=np.arange(1, 11),
current_value=1.)
class GammaTradeFine(cvx.RangeHyperParameter):
"""Transaction cost multiplier, fine value range."""
def __init__(self):
super().__init__(
values_range=np.linspace(-1., 1., 51),
current_value=0)
class GammaRiskCoarse(cvx.RangeHyperParameter):
"""Risk term multiplier, coarse value range."""
def __init__(self):
super().__init__(
values_range=np.arange(1, 21),
current_value=1.)
class GammaRiskFine(cvx.RangeHyperParameter):
"""Risk term multiplier, fine value range."""
def __init__(self):
super().__init__(
values_range=np.linspace(-1., 1., 51),
current_value=0)
class Kappa(cvx.RangeHyperParameter):
"""Risk forecast error multiplier, fine value range."""
def __init__(self):
super().__init__(
values_range=np.linspace(0., 0.5),
current_value=0)
# We test these risk models, with symbolic hyper-parameters.
base_risk_models = [cvx.DiagonalCovariance(), cvx.FullCovariance()]
base_risk_models += [
cvx.FactorModelCovariance(num_factors=num_factors)
for num_factors in [1, 2, 5, 10]
]
# with hyper-parameters
RISK_MODELS = [
(GammaRiskCoarse() + GammaRiskFine()) * base_risk_model
for base_risk_model in base_risk_models
]
# with risk forecast error
RISK_MODELS += [
(GammaRiskCoarse() + GammaRiskFine()) * (
base_risk_model + Kappa() * cvx.RiskForecastError())
for base_risk_model in base_risk_models
]
results = {}
for risk_model in RISK_MODELS:
print('Testing risk model:')
print(risk_model)
results[repr(risk_model)] = {}
current_result = results[repr(risk_model)]
# Build policy.
policy = cvx.SinglePeriodOpt(
objective = cvx.ReturnsForecast()
- (GammaTradeCoarse() + GammaTradeFine()
) * cvx.StocksTransactionCost()
- risk_model,
constraints=[cvx.LongOnly(), cvx.LeverageLimit(LEVERAGE_LIMIT)],
benchmark=benchmark,
solver='CLARABEL')
# Optimize HPs.
simulator.optimize_hyperparameters(
policy, start_time=START, end_time=END,
objective='information_ratio')
print('Policy with optimized hyper-parameters:')
print(policy)
current_result['Optimized policy'] = repr(policy)
# Run back-test with optimized HPs.
optimized_result = simulator.backtest(
policy, start_time=START, end_time=END)
print('Back-test result with optimized hyper-parameters:')
print(optimized_result)
current_result['Optimized result'] = optimized_result
pprint(results)