import dos módulos básicos
In [530]:
# always yielding a real result, even dividing two integers
from __future__ import division
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
import scipy.stats as st
import datetime as dt
from dateutil.relativedelta import relativedelta
from functools import reduce
import operator
# plot inline
%matplotlib inline
Carregando dados de feriados: cdi e bmf. Fonte: anbima
In [531]:
feriado_arq = 'feriados.xlsx'
feriado_cdi = pd.read_excel(feriado_arq,'cdi')
feriado_bmf = pd.read_excel(feriado_arq,'bmf')
Carregando dados de mercado
In [532]:
mkt_series_arq = 'BBergValues.xlsx'
usdbrl=pd.read_excel(mkt_series_arq,'Sheet1',skiprows=1,index_col=0,parse_cols="A:E")
ptax=pd.read_excel(mkt_series_arq,'Sheet1',skiprows=1,index_col=0,parse_cols="G:H")
ibov=pd.read_excel(mkt_series_arq,'Sheet1',skiprows=1,index_col=0,parse_cols="J:M")
di1f21=pd.read_excel(mkt_series_arq,'Sheet1',skiprows=1,index_col=0,parse_cols="O:S")
cdi=pd.read_excel(mkt_series_arq,'Sheet1',skiprows=1,index_col=0,parse_cols="U:V")
cds5y=pd.read_excel(mkt_series_arq,'Sheet1',skiprows=1,index_col=0,parse_cols="X:AB")
vol1m_off=pd.read_excel(mkt_series_arq,'Sheet1',skiprows=1,index_col=0,parse_cols="AD:AH")
vol3m_off=pd.read_excel(mkt_series_arq,'Sheet1',skiprows=1,index_col=0,parse_cols="AJ:AN")
vol12m_off=pd.read_excel(mkt_series_arq,'Sheet1',skiprows=1,index_col=0,parse_cols="AP:AT")
swpprecdi1m=pd.read_excel(mkt_series_arq,'Sheet1',skiprows=1,index_col=0,parse_cols="AV:AZ")
swpprecdi3m=pd.read_excel(mkt_series_arq,'Sheet1',skiprows=1,index_col=0,parse_cols="BB:BF")
swpprecdi12m=pd.read_excel(mkt_series_arq,'Sheet1',skiprows=1,index_col=0,parse_cols="BH:BL")
fwd1m_on=pd.read_excel(mkt_series_arq,'Sheet1',skiprows=1,index_col=0,parse_cols="BN:BR")
fwd3m_on=pd.read_excel(mkt_series_arq,'Sheet1',skiprows=1,index_col=0,parse_cols="BT:BX")
fwd12m_on=pd.read_excel(mkt_series_arq,'Sheet1',skiprows=1,index_col=0,parse_cols="BZ:CD")
In [681]:
vol=pd.DataFrame(vol1m_off['PX_LAST'].values,columns=[1],index=vol1m_off.index)
vol[3]=vol3m_off['PX_LAST'].values
vol[12]=vol12m_off['PX_LAST'].values
fwd=pd.DataFrame(usdbrl['PX_LAST'].values,columns=[0],index=usdbrl.index)
fwd[1]=fwd1m_on['PX_LAST'].values
fwd[3]=fwd3m_on['PX_LAST'].values
fwd[12]=fwd12m_on['PX_LAST'].values
pre=pd.DataFrame(cdi['PX_LAST'].values,columns=[0],index=cdi.index)
pre[1]=swpprecdi1m['PX_LAST'].values
pre[3]=swpprecdi3m['PX_LAST'].values
pre[12]=swpprecdi12m['PX_LAST'].values
In [658]:
cdi.plot()
Out[658]:
In [5]:
ibov.plot()
Out[5]:
Como estimar o risco dos portfolios do fundo a partir das séries de preços? Aponte as diferenças entre como estimar o risco entre os diferentes tipos de séries. Assuma que esse cálculo está sendo feito em 31-Mar-2016.
In [ ]:
Um trader olhou o gráfico abaixo e pensou em uma estratégia.
a) Qual a estratégia que você acha que ele pensou?
In [ ]:
b) Faz sentido? Qual a proporção dos ativos? Ela é fixa?
c) Se ele tivesse entrado no trade em 13-Abr-2016, qual teria sido o máximo drawdown (perda) dele no período entre 13-Abr-2016 e 22-Jun-2016? Assuma notional de BRL 1MM.
d) A estimativa de risco que você teria feito teria estimado corretamente esse resultado?
e) Acrescente Ibovespa como uma estratégia (não esqueça do funding!); você faria algum novo trade?
Em 30-Jun-2015 vários traders compraram opções de compra de USD (venda de BRL) ATMF para diferentes prazos. Use os dados anexos, interpolação linear para spot e forwards, e a interpolação adequada para vols ATMF (vol forward constante, variância efetiva é a soma das variâncias efetivas) para estimar os resultados finais e perdas máximas de cada um dos traders.
Definindo a função BS para ser utilizada na precificação das opções
In [587]:
def bsv(phi,F,K,discount,vol,t):
if(t>0):
# calculate d1 and d2
sigma_rt = vol*np.sqrt(t)
d1=(np.log(F/K)+(vol**2/2)*t)/(sigma_rt)
d2=d1-sigma_rt
# calculate N(d1) and N(d2)
Nd1=st.norm.cdf(phi*d1)
Nd2=st.norm.cdf(phi*d2)
delta=phi*Nd1*discount
premium=phi*(F*Nd1-K*Nd2)*discount
else:
delta=0
premium=max(phi*(F-K),0)
return [premium,delta]
Definindo função para fazer a interpolação da vol:
In [589]:
def interpolaVol(dt0,v0,dt1,v1,dt):
vv0=v0**2
vv1=v1**2
d0=dt0.toordinal()
d1=dt1.toordinal()
d=dt.toordinal()
vv=((1/(d1-d0))*(vv1*d1*(d-d0)+vv0*d0*(d1-d)))/d
return np.sqrt(vv)
Definindo a função para inicializar o DataFrame com as séries de acordo com o prazo (tenor)
In [769]:
def portf_initdf(start,months,usdbrl,cdi,fwd_tenor,vol_tenor,swpprecdi_tenor):
term=relativedelta(months=months)
end=start+term
s=pd.Series(usdbrl['PX_LAST'][start:end])
df=pd.DataFrame(s.index)
df['t']=[(end.toordinal()-i.toordinal())/365 for i in df['Date']]
df['tenor']=[i+term for i in s.index]
df['usdbrl']=usdbrl['PX_LAST'][start:end].values
df['cdi']=cdi['PX_LAST'][start:end].values/100
df['cdi']=cdi['PX_LAST'][start:end].values/100
cdiprod=[reduce(operator.mul,(1+df['cdi'][0:i])**(1/252),1) for i in range(1,len(df))]
cdiprod.insert(0,1)
df['cdiprod']=cdiprod
df['fwd_tenor']=fwd_tenor[months][start:end].values
df['vol_tenor']=vol_tenor[months][start:end].values/100
df['pre_tenor']=swpprecdi_tenor[months][start:end].values/100
df['strike']=df['fwd_tenor'][0]
#interpolações
if(months==1):
tenor_short=df['Date']
fwd_short=df['usdbrl']
vol_short=df['vol_tenor']
pre_short=df['cdi']
if(months==3):
tenor_short=[i+relativedelta(months=1) for i in s.index]
fwd_short=fwd[1][start:end]
vol_short=vol[1][start:end]/100
pre_short=pre[1][start:end]/100
if(months==12):
tenor_short=[i+relativedelta(months=3) for i in s.index]
fwd_short=fwd[3][start:end]
vol_short=vol[3][start:end]/100
pre_short=pre[3][start:end]/100
df['fwd']=[fwd_short[i]+(df['fwd_tenor'][i]-fwd_short[i])*((end-tenor_short[i])/(df['tenor'][i]-tenor_short[i])) for i in df['Date'].index]
df['vol']=[interpolaVol(tenor_short[i],vol_short[i],df['tenor'][i],df['vol_tenor'][i],end) for i in df['Date'].index]
df['discount']=[pre_short[i]+(df['pre_tenor'][i]-pre_short[i])*((end-tenor_short[i])/(df['tenor'][i]-tenor_short[i])) for i in df['Date'].index]
df['discount']=(1+df['discount'])**[-(end.toordinal()-i.toordinal())/365 for i in df['Date']]
df=df.join(pd.DataFrame([bsv(call,df['fwd'][i],df['strike'][i],df['discount'][i],df['vol'][i],df['t'][i]) for i in df['Date'].index],columns=['premium','delta']))
return df
In [770]:
portf_initdf(start,3,usdbrl,cdi,fwd,vol,pre)
Out[770]:
Definindo a função para cálculo do portfolio sem fazer o hedging:
In [675]:
def calc_portf_semhedge(start,months,usdbrl,cdi,fwd_tenor,vol_tenor,swpprecdi_tenor):
#init data
df=portf_initdf(start,months,usdbrl,cdi,fwd_tenor,vol_tenor,swpprecdi_tenor)
#caixa do prêmio
df['cfwprem']=-df['premium'][0]*df['cdiprod']
#portfolio
df['portf']=df['premium']+df['cfwprem']
return df
a) O primeiro comprou uma opção de 1m e carregou sem hedge até o final.
In [689]:
#traderA=calc_portf_semhedge(start,1,usdbrl,cdi,fwd1m_on,vol1m_off,swpprecdi1m)
traderA=calc_portf_semhedge(start,1,usdbrl,cdi,fwd,vol,pre)
traderA
Out[689]:
b) O segundo comprou uma opção de 1m e fez o delta hedge até o final.
c) O terceiro comprou uma opção de 3m e carregou sem hedge até o final.
In [772]:
traderC=calc_portf_semhedge(start,3,usdbrl,cdi,fwd,vol,pre)
traderC
Out[772]:
d) O quarto comprou uma opção de 3m e fez o delta hedge até o final.
e) O quinto comprou uma opção de 12m e carregou sem hedge até o final.
In [776]:
traderE=calc_portf_semhedge(start,12,usdbrl,cdi,fwd,vol,pre)
traderE
Out[776]:
a) Monte Carlo
b) PDE
implementação sugerida
In [ ]:
def grid(N,T,Nj,S,dx,vol,r,q,K,output='V'):
dt = T / N
if dx < vol * np.sqrt(3 * dt):
print('Convergence error')
mu = -(0.5)*(r-q)*vol**2
emdx = np.exp(-dx)
ppu = 0.5 * dt * ((vol / dx) ** 2 + mu / dx)
ppm = 1.0-dt * (vol / dx) ** 2-r * dt
ppd = 0.5 * dt * ((vol / dx) ** 2-mu / dx)
St = np.full(2 * Nj + 1,0.)
St[0] = S * np.exp(Nj * dx)
for j in np.arange(1,2 * Nj + 1):
St[j] = St[j-1]*emdx
Ct = np.full((2 * Nj + 1,N + 1),np.nan)
for j in np.arange(0,2 * Nj + 1):
Ct[j,N] = np.max([St[j]-K,0])
for i in np.arange(N-1,-1,-1):
for k in np.arange(N-i,2 * Nj + 1-(N-i)):
Ct[k,i] = ppu * Ct[k-1,i + 1]+ ppm * Ct[k,i + 1] + ppd * Ct[k + 1,i + 1]
#Boundary
#Boundary
if output == 'G':
return Ct
else:
return Ct[Nj,0]
In [ ]: