DOW30 Example#

This example script is available in the repository. See the docstring below for its explanation.

"""Example of long-only portfolio among DOW-30 components.

Monthly rebalance, backtest spans from the start of data of the 
components of the current index (in the 60s) and the other stocks
enter the backtest as times goes on. It ends today.

This uses an explicit loop to create Multi Period Optimization
policies with a grid of values for the risk term multiplier
and the transaction cost term multiplier. (We don't use the
holding cost term because the portfolio is long-only.)

All result objects are collected, and then the one with 
largest Sharpe ratio, and the one with largest growth rate,
are shown. 

Finally, we show the effect of using symbolic hyper-parameters,
:class:`cvxportfolio.Gamma`, as multipliers of the risk and transaction
cost terms. We can optimize on those explicitely, by finding the values
that maximize some back-test metric (in this case, profit).
"""

# Uncomment the logging lines to get online information 
# from the parallel backtest routines

# import logging
# logging.basicConfig(level=logging.INFO)
# log=logging.getLogger('=>')

import os

import cvxportfolio as cvx
import matplotlib.pyplot as plt
import numpy as np


UNIVERSE = ['MMM', 'AXP', 'AMGN', 'AAPL', 'BA', 'CAT', 'CVX', 'CSCO', 'KO', 'DIS',  'DOW', 
            'GS', 'HD', 'HON', 'IBM','INTC', 'JNJ',
            'JPM','MCD', 'MRK', 'MSFT', 'NKE', 'PG', 'CRM', 'TRV', 'VZ', 'V', 'WBA', 'WMT']
    

sim = cvx.StockMarketSimulator(UNIVERSE, trading_frequency='monthly')

def make_policy(gamma_trade, gamma_risk):
    return cvx.MultiPeriodOptimization(cvx.ReturnsForecast() 
        - gamma_risk * cvx.FactorModelCovariance(num_factors=10) 
        - gamma_trade * cvx.StocksTransactionCost(), 
        [cvx.LongOnly(), cvx.LeverageLimit(1)],
        planning_horizon=6, solver='ECOS')

keys = [(gamma_trade, gamma_risk) for gamma_trade in np.array(range(10))/10 for gamma_risk in [.5, 1, 2, 5, 10]]
ress = sim.backtest_many([make_policy(*key) for key in keys])


print('\n\nLARGEST SHARPE RATIO')
idx = np.argmax([el.sharpe_ratio for el in ress])

print('gamma_trade and gamma_risk')
print(keys[idx])

print('result')
print(ress[idx])

ress[idx].plot()
# we use this to save plots for the documentation
if 'CVXPORTFOLIO_SAVE_PLOTS' in os.environ:
    plt.savefig('dow30_largest_sharpe_ratio.png')

print('\n\nLARGEST GROWTH RATE')
idx = np.argmax([el.growth_rates.mean() for el in ress])

print('gamma_trade and gamma_risk')
print(keys[idx])

print('result')
print(ress[idx])

ress[idx].plot()
if 'CVXPORTFOLIO_SAVE_PLOTS' in os.environ:
    plt.savefig('dow30_largest_growth_rate.png')

print('\n\nUNIFORM (1/N) ALLOCATION FOR COMPARISON')
result_uniform = sim.backtest(cvx.Uniform())

print('result_uniform')
print(result_uniform)

result_uniform.plot()
if 'CVXPORTFOLIO_SAVE_PLOTS' in os.environ:
    plt.savefig('dow30_uniform.png')

print('\n\nHYPER-PARAMETER OPTIMIZATION')
policy = cvx.MultiPeriodOptimization(cvx.ReturnsForecast() 
        - cvx.Gamma() * cvx.FactorModelCovariance(num_factors=10) 
        - cvx.Gamma() * cvx.StocksTransactionCost(), 
        [cvx.LongOnly(), cvx.LeverageLimit(1)],
        planning_horizon=6, solver='ECOS')
sim.optimize_hyperparameters(policy, objective='profit')
result_hyperparameter_optimized = sim.backtest(policy)

print('result_hyperparameter_optimized')
print(result_hyperparameter_optimized)

result_hyperparameter_optimized.plot()

if 'CVXPORTFOLIO_SAVE_PLOTS' in os.environ:
    plt.savefig('dow30_hyperparameter_optimized.png')
else:
    plt.show()

This is the output printed to screen when executing this script. You can see many statistics of the back-tests.

Updating data.............................


LARGEST SHARPE RATIO
gamma_trade and gamma_risk
(0.6, 5)
result

###########################################################
Universe size                                            30
Initial timestamp                       1963-02-01 14:30:00
Final timestamp                         2023-11-01 13:30:00
Number of periods                                       730
Initial value (USDOLLAR)                          1.000e+06
Final value (USDOLLAR)                            1.467e+09
Profit (USDOLLAR)                                 1.466e+09
                                                           
Avg. return (annualized)                              12.7%
Volatility (annualized)                               11.5%
Avg. excess return (annualized)                        8.0%
Avg. active return (annualized)                        8.0%
Excess volatility (annualized)                        11.6%
Active volatility (annualized)                        11.6%
                                                           
Avg. growth rate (annualized)                         12.0%
Avg. excess growth rate (annualized)                   7.3%
Avg. active growth rate (annualized)                   7.3%
                                                           
Avg. StocksTransactionCost                              2bp
Max. StocksTransactionCost                            138bp
Avg. StocksHoldingCost                                  0bp
Max. StocksHoldingCost                                  0bp
                                                           
Sharpe ratio                                           0.69
Information ratio                                      0.69
                                                           
Avg. drawdown                                         -5.9%
Min. drawdown                                        -43.7%
Avg. leverage                                         57.9%
Max. leverage                                        100.1%
Avg. turnover                                          1.6%
Max. turnover                                         41.2%
                                                           
Avg. policy time                                     0.044s
Avg. simulator time                                  0.005s
Total time                                          35.144s
###########################################################



LARGEST GROWTH RATE
gamma_trade and gamma_risk
(0.3, 1)
result

###########################################################
Universe size                                            30
Initial timestamp                       1963-02-01 14:30:00
Final timestamp                         2023-11-01 13:30:00
Number of periods                                       730
Initial value (USDOLLAR)                          1.000e+06
Final value (USDOLLAR)                            7.223e+10
Profit (USDOLLAR)                                 7.223e+10
                                                           
Avg. return (annualized)                              23.2%
Volatility (annualized)                               30.1%
Avg. excess return (annualized)                       18.4%
Avg. active return (annualized)                       18.4%
Excess volatility (annualized)                        30.1%
Active volatility (annualized)                        30.1%
                                                           
Avg. growth rate (annualized)                         18.4%
Avg. excess growth rate (annualized)                  13.7%
Avg. active growth rate (annualized)                  13.7%
                                                           
Avg. StocksTransactionCost                              9bp
Max. StocksTransactionCost                            787bp
Avg. StocksHoldingCost                                  0bp
Max. StocksHoldingCost                                  0bp
                                                           
Sharpe ratio                                           0.61
Information ratio                                      0.61
                                                           
Avg. drawdown                                        -27.7%
Min. drawdown                                        -82.5%
Avg. leverage                                         97.8%
Max. leverage                                        106.8%
Avg. turnover                                          2.4%
Max. turnover                                         71.1%
                                                           
Avg. policy time                                     0.045s
Avg. simulator time                                  0.005s
Total time                                          36.697s
###########################################################



UNIFORM (1/N) ALLOCATION FOR COMPARISON
result_uniform

###########################################################
Universe size                                            30
Initial timestamp                       1963-02-01 14:30:00
Final timestamp                         2023-11-01 13:30:00
Number of periods                                       730
Initial value (USDOLLAR)                          1.000e+06
Final value (USDOLLAR)                            6.204e+09
Profit (USDOLLAR)                                 6.203e+09
                                                           
Avg. return (annualized)                              15.9%
Volatility (annualized)                               16.7%
Avg. excess return (annualized)                       11.1%
Excess volatility (annualized)                        16.8%
                                                           
Avg. growth rate (annualized)                         14.4%
Avg. excess growth rate (annualized)                   9.7%
                                                           
Avg. StocksTransactionCost                              4bp
Max. StocksTransactionCost                            234bp
Avg. StocksHoldingCost                                  0bp
Max. StocksHoldingCost                                  0bp
                                                           
Sharpe ratio                                           0.66
                                                           
Avg. drawdown                                         -4.9%
Min. drawdown                                        -49.5%
Avg. leverage                                         99.9%
Max. leverage                                        102.5%
Avg. turnover                                          2.5%
Max. turnover                                         50.0%
                                                           
Avg. policy time                                     0.000s
Avg. simulator time                                  0.003s
Total time                                           1.950s
###########################################################



HYPER-PARAMETER OPTIMIZATION
iteration 0
Current objective:
49262708163.666725
iteration 1
Current objective:
54281879700.21155
iteration 2
Current objective:
58058328523.323006
iteration 3
Current objective:
60955786424.61437
iteration 4
Current objective:
63051214100.27364
iteration 5
Current objective:
64737096341.63388
iteration 6
Current objective:
66039921194.24338
iteration 7
Current objective:
67329996388.34948
iteration 8
Current objective:
68450495985.06613
iteration 9
Current objective:
69296724983.65472
iteration 10
Current objective:
70102723365.48186
iteration 11
Current objective:
71251150787.6262
iteration 12
Current objective:
72192309617.03737
iteration 13
Current objective:
72882238726.47371
iteration 14
Current objective:
73227637485.88083
iteration 15
Current objective:
73299378411.02371
result_hyperparameter_optimized

###########################################################
Universe size                                            30
Initial timestamp                       1963-02-01 14:30:00
Final timestamp                         2023-11-01 13:30:00
Number of periods                                       730
Initial value (USDOLLAR)                          1.000e+06
Final value (USDOLLAR)                            7.330e+10
Profit (USDOLLAR)                                 7.330e+10
                                                           
Avg. return (annualized)                              23.5%
Volatility (annualized)                               31.0%
Avg. excess return (annualized)                       18.8%
Avg. active return (annualized)                       18.8%
Excess volatility (annualized)                        31.0%
Active volatility (annualized)                        31.0%
                                                           
Avg. growth rate (annualized)                         18.4%
Avg. excess growth rate (annualized)                  13.7%
Avg. active growth rate (annualized)                  13.7%
                                                           
Avg. StocksTransactionCost                              9bp
Max. StocksTransactionCost                            855bp
Avg. StocksHoldingCost                                  0bp
Max. StocksHoldingCost                                  0bp
                                                           
Sharpe ratio                                           0.61
Information ratio                                      0.61
                                                           
Avg. drawdown                                        -28.6%
Min. drawdown                                        -83.6%
Avg. leverage                                         98.1%
Max. leverage                                        107.5%
Avg. turnover                                          2.4%
Max. turnover                                         73.8%
                                                           
Avg. policy time                                     0.036s
Avg. simulator time                                  0.003s
Total time                                          28.409s
###########################################################

And these are the figure that are plotted. The result of the cvxportfolio.MultiPeriodOptimization policy that has the largest out-of-sample Sharpe ratio:

dow30_example.py result figure

This figure is made by the plot() method of cvxportfolio.BacktestResult#

The result of the cvxportfolio.MultiPeriodOptimization policy that has the largest out-of-sample growth rate:

dow30_example.py result figure

This figure is made by the plot() method of cvxportfolio.BacktestResult#

The result of the cvxportfolio.Uniform policy, which allocates equal weight to all non-cash assets:

dow30_example.py result figure

This figure is made by the plot() method of cvxportfolio.BacktestResult#

Finally, the result of the cvxportfolio.MultiPeriodOptimization policy obtained by automatic hyper-parameter optimization to have largest profit:

dow30_example.py result figure

This figure is made by the plot() method of cvxportfolio.BacktestResult#