#!/usr/bin/env python # coding: utf-8 # # Riskfolio-Lib Tutorial: #
__[Financionerioncios](https://financioneroncios.wordpress.com)__ #
__[Orenji](https://www.linkedin.com/company/orenj-i/)__ #
__[Riskfolio-Lib](https://riskfolio-lib.readthedocs.io/en/latest/)__ #
__[Dany Cajas](https://www.linkedin.com/in/dany-cajas/)__ # Buy Me a Coffee at ko-fi.com # # ## Tutorial 39: Mean Semi Kurtosis Optimization # # ## 1. Downloading the data: # In[1]: import numpy as np import pandas as pd import yfinance as yf import warnings warnings.filterwarnings("ignore") pd.options.display.float_format = '{:.4%}'.format # Date range start = '2016-01-01' end = '2019-12-30' # Tickers of assets assets = ['JCI', 'AMZN', 'CMCSA', 'CPB', 'MO', 'APA', 'MMC', 'JPM', 'ZION', 'AAPL', 'BAX', 'BMY', 'LUV', 'PCAR', 'TXT', 'TMO', 'DE', 'MSFT', 'HPQ', 'SEE', 'VZ', 'CNP', 'NI', 'T', 'BA'] assets.sort() # Downloading data data = yf.download(assets, start = start, end = end) data = data.loc[:,('Adj Close', slice(None))] data.columns = assets # In[2]: # Calculating returns Y = data[assets].iloc[-300:,:].pct_change().dropna() display(Y.head()) # ## 2. Estimating Mean Semi Kurtosis Portfolios # # The Semi Kurtosis portfolio model proposed by __[Cajas (2022)](https://papers.ssrn.com/sol3/papers.cfm?abstract_id=3988927)__ shows how to optimize the fourth lower moment of portfolio returns using an lower semi cokurtosis matrix as an heuristic in a similar way than lower semi covariance matrix. # # It is recommended to use MOSEK to optimize Kurtosis for a large number of assets due the model use semidefinite programming. Also, for a large number of assets is recommended to use the relaxed version of this model based only on second order cone programming. To use the relaxed version we have to use a number of assets higher than the property __n_max_kurt__, so for example if number of assets is 30 and we set __port.n_max_kurt = 25__, riskfolio-lib is going to use the relaxed version. # # Instructions to install MOSEK are in this __[link](https://docs.mosek.com/9.2/install/installation.html)__, is better to install using Anaconda. Also you will need a license, I recommend you that ask for an academic license __[here](https://www.mosek.com/products/academic-licenses/)__. # # ### 2.1 Calculating the portfolio that optimize return/semi kurtosis ratio. # In[3]: import riskfolio as rp import mosek # Building the portfolio object port = rp.Portfolio(returns=Y) # Calculating optimum portfolio # Select method and estimate input parameters: method_mu='hist' # Method to estimate expected returns based on historical data. method_cov='hist' # Method to estimate covariance matrix based on historical data. method_kurt='hist' # Method to estimate cokurtosis square matrix based on historical data. port.assets_stats(method_mu=method_mu, method_cov=method_cov, method_kurt=method_kurt, ) # Estimate optimal portfolio: port.solvers = ['MOSEK'] # It is recommended to use mosek when optimizing GMD port.sol_params = {'MOSEK': {'mosek_params': {'MSK_IPAR_NUM_THREADS': 2}}} model ='Classic' # Could be Classic (historical), BL (Black Litterman) or FM (Factor Model) rm = 'SKT' # Risk measure used, this time will be Tail Gini Range obj = 'Sharpe' # Objective function, could be MinRisk, MaxRet, Utility or Sharpe hist = True # Use historical scenarios for risk measures that depend on scenarios rf = 0 # Risk free rate l = 0 # Risk aversion factor, only useful when obj is 'Utility' w = port.optimization(model=model, rm=rm, obj=obj, rf=rf, l=l, hist=hist) display(w.T) # ### 2.2 Plotting portfolio composition # In[4]: # Plotting the composition of the portfolio ax = rp.plot_pie(w=w, title='Sharpe Mean - Kurtosis', others=0.05, nrow=25, cmap = "tab20", height=6, width=10, ax=None) # ### 2.3 Plotting risk measures # In[5]: ax = rp.plot_hist(returns=Y, w=w, alpha=0.05, bins=50, height=6, width=10, ax=None) # ### 2.4 Calculate efficient frontier # In[6]: points = 50 # Number of points of the frontier frontier = port.efficient_frontier(model=model, rm=rm, points=points, rf=rf, hist=hist) display(frontier.T.head()) # In[7]: # Plotting the efficient frontier label = 'Max Risk Adjusted Return Portfolio' # Title of point mu = port.mu # Expected returns cov = port.cov # Covariance matrix returns = port.returns # Returns of the assets ax = rp.plot_frontier(w_frontier=frontier, mu=mu, cov=cov, returns=returns, rm=rm, rf=rf, alpha=0.05, cmap='viridis', w=w, label=label, marker='*', s=16, c='r', height=6, width=10, ax=None) # In[8]: # Plotting efficient frontier composition ax = rp.plot_frontier_area(w_frontier=frontier, cmap="tab20", height=6, width=10, ax=None) # ## 3. Estimating Risk Parity Portfolios for Square Root Semi Kurtosis # # ### 3.1 Calculating the risk parity portfolio for Square Root Semi Kurtosis. # In[9]: b = None # Risk contribution constraints vector w_rp = port.rp_optimization(model=model, rm=rm, rf=rf, b=b, hist=hist) display(w_rp.T) # ### 3.2 Plotting portfolio composition # In[10]: ax = rp.plot_pie(w=w_rp, title='Risk Parity Square Root Semi Kurtosis', others=0.05, nrow=25, cmap="tab20", height=6, width=10, ax=None) # ### 3.3 Plotting Risk Composition # In[11]: ax = rp.plot_risk_con(w_rp, cov=port.cov, returns=port.returns, rm=rm, rf=0, alpha=0.05, color="tab:blue", height=6, width=10, ax=None) # Due to semi kurtosis use an heuristic based on lower semi cokurtosis matrix to approach portfolio lower semi kurtosis, the solution is only an approximation. # In[12]: # Plotting the efficient frontier ws = pd.concat([w, w_rp],axis=1) ws.columns = ["Max Return/ Semi Kurtosis", "Risk Parity Semi Kurtosis"] mu = port.mu # Expected returns cov = port.cov # Covariance matrix returns = port.returns # Returns of the assets ax = rp.plot_frontier(w_frontier=frontier, mu=mu, cov=cov, returns=returns, rm=rm, rf=rf, alpha=0.05, cmap='viridis', w=ws, marker='*', s=16, c='r', height=6, width=10, ax=None)