#!/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/)__
# ## Tutorial 23: Dollar Neutral Portfolios
#
# ## 1. Downloading the data:
# In[ ]:
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
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', 'TGT', 'CMCSA', 'CPB', 'MO', 'APA', 'MMC', 'JPM',
'ZION', 'PSA', '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, auto_adjust=False)
data = data.loc[:,('Adj Close', slice(None))]
data.columns = assets
# In[2]:
# Calculating returns
Y = data[assets].pct_change().dropna()
display(Y.head())
# ## 2. Mean Risk Dollar Neutral Portfolios
#
# To calculate dollar neutral portfolios we have to solve the following problem:
#
# $$
# \begin{aligned}
# & \max_{w} & & \mu w \\
# & & & \sum^{N}_{i=1} w_{i} = 0 \\
# & & & \phi(w) \leq \overline{\phi} \\
# & & & \sum^{N}_{i=1} \max(w_{i},0) \leq W^{L} \\
# & & & \sum^{N}_{i=1} -\min(w_{i},0) \leq W^{S} \\
# & & & W^{S} \leq w \leq W^{L}\\
# \end{aligned}
# $$
#
# Where $\mu$ is the mean vector, $w$ are the portfolio weights, $\phi(w)$ is a convex risk function, $\overline{\phi}$ is an upper bound for the risk function, $W^{L}$ is the upper bound of positive weights and $W^{S}$ is the upper bound of negative weights.
#
# ## 3. Dollar Neutral Portfolio with a Constraint on Standard Deviation
#
# ### 3.1 Calculating Dollar Neutral Portfolio
# In[3]:
import riskfolio as rp
# Building the portfolio object
port = rp.Portfolio(returns=Y)
# Calculating optimal 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.
port.assets_stats(method_mu=method_mu, method_cov=method_cov)
# Market neutral constraints:
port.sht = True # Allows short positions
port.uppersht = 1 # Upper bound for sum of negative weights
port.upperlng = 1 # Upper bound for sum of positive weights
port.budget = 0 # Sum of all weights
port.upperdev = 0.20/252**0.5 # Upper bound for daily standard deviation
# Estimate optimal portfolio:
model='Classic' # Could be Classic (historical), BL (Black Litterman), FM (Factor Model)
# or BL_FM (Black Litterman with Factor Model)
rm = 'MV' # Risk measure used, this time will be variance
obj = 'MaxRet' # For Market Neutral the objective must be
hist = True # Use historical scenarios for risk measures that depend on scenarios
rf = 0 # Risk free rate
l = 3 # Risk aversion factor, only useful when obj is 'Utility'
w = port.optimization(model=model, rm=rm, obj=obj, rf=rf, l=l, hist=hist)
print("Sum weights : ", np.round(np.sum(w.to_numpy()),4))
display(w.T)
# ### 3.2 Plotting portfolio composition
# In[4]:
# Plotting the composition of the portfolio
title = "Max Return Dollar Neutral with Variance Constraint"
ax = rp.plot_pie(w=w,
title=title,
others=0.05,
nrow=25,
cmap = "tab20",
height=7,
width=10,
ax=None)
# In[5]:
# Plotting the composition of the portfolio using bar chart
ax = rp.plot_bar(w,
title="Max Return Dollar Neutral with Variance Constraint",
kind="v",
others=0.05,
nrow=25,
height=6,
width=10)
# ### 3.3 Calculating efficient frontier
# In[6]:
points = 50 # Number of points of the frontier
port.upperdev = None # Deleting the upper bound for daily standard deviation
frontier = port.efficient_frontier(model=model, rm=rm, points=points, rf=rf, hist=hist)
display(frontier)
# In[7]:
# Plotting the efficient frontier
label = "Max Return Dollar Neutral with Variance Constraint" # 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 in absolute values
ax = rp.plot_frontier_area(w_frontier=np.abs(frontier), cmap="tab20", height=6, width=10, ax=None)
# ## 4. Dollar Neutral Portfolio with a Constraint on CVaR
#
# ### 4.1 Calculating Dollar Neutral Portfolio
# In[9]:
rm = 'CVaR' # Risk measure
port.upperCVaR = 0.40/252**0.5 # Creating an upper bound for daily CVaR
w = port.optimization(model=model, rm=rm, obj=obj, rf=rf, l=l, hist=hist)
print("Sum weights : ", np.round(np.sum(w.to_numpy()),4))
display(w.T)
# ### 4.2 Plotting portfolio composition
# In[10]:
# Plotting the composition of the portfolio
title = "Max Return Dollar Neutral with CVaR Constraint"
ax = rp.plot_pie(w=w,
title=title,
others=0.05,
nrow=25,
cmap = "tab20",
height=7,
width=10,
ax=None)
# In[11]:
# Plotting the composition of the portfolio using bar chart
ax = rp.plot_bar(w,
title="Max Return Dollar Neutral with CVaR Constraint",
kind="v",
others=0.05,
nrow=25,
height=6,
width=10)
# ### 4.3 Calculate efficient frontier
# In[12]:
points = 50 # Number of points of the frontier
port.upperCVaR = None # Deleting the upper bound for daily CVaR
frontier = port.efficient_frontier(model=model, rm=rm, points=points, rf=rf, hist=hist)
display(frontier.T.head())
# In[13]:
label = "Max Return Dollar Neutral with CVaR Constraint" # Title of point
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[14]:
# Plotting efficient frontier composition in absolute values
ax = rp.plot_frontier_area(w_frontier=np.abs(frontier), cmap="tab20", height=6, width=10, ax=None)