Dois caminhos para o mesmo lugar
Monte duas carteiras. A: compre uma call e coloque no banco (ou num título sem risco) o valor presente do strike K * exp(-rT). B: compre uma put e compre a ação. No vencimento, se a ação termina acima de K, A é o S - K da call mais o K do banco, ou seja S; B é a ação S e uma put sem valor, ou seja S. Se a ação termina abaixo de K, A é só o K do banco, pois a call vence sem valor, e B é o K - S da put mais a ação S, ou seja K. Nos dois casos as duas carteiras valem o mesmo no vencimento, então devem custar o mesmo hoje.
import math
spot, strike, rate, t = 100, 100, 0.05, 1
pv_strike = strike * math.exp(-rate * t) # what must be put in the bank today to own K at expiry
print(round(pv_strike, 4)) # 95.1229
call = 10.4506 # a call price we observe
put = call - spot + pv_strike # the parity relation
print(round(put, 4)) # 5.5735
print(round(put + spot - pv_strike, 4)) # 10.4506 and back to the callQuando a paridade se quebra: arbitragem
Se o mercado cota preços que não satisfazem a relação, existe lucro sem risco. Defina a diferença (C - P) - (S - K e^(-rT)). Uma diferença positiva significa que a call está cara demais para a put: venda a call, compre a put, compre a ação e tome emprestado o valor presente do strike. A carteira não custa nada no início, não paga nada no vencimento faça a ação o que fizer, e embolsa a diferença hoje. Uma diferença negativa inverte cada perna. Mercados reais têm custos e spreads, então pequenas diferenças não são negociáveis: é isso que a tolerância representa.
def parity_gap(call, put, spot, strike, rate, t):
return (call - put) - (spot - strike * math.exp(-rate * t))
print(round(parity_gap(11.0, put, 100, 100, 0.05, 1), 4)) # 0.5494 the call at 11.00 is too expensive: sell it
print(round(parity_gap(call, put, 100, 100, 0.05, 1), 4)) # 0.0 consistent prices: nothing to do
def arbitrage_action(call, put, spot, strike, rate, t, tolerance=0.01):
gap = parity_gap(call, put, spot, strike, rate, t)
if gap > tolerance:
return "sell call, buy put, buy stock"
if gap < -tolerance:
return "buy call, sell put, sell stock"
return "none"
print(arbitrage_action(11.0, put, 100, 100, 0.05, 1)) # sell call, buy put, buy stock# The package of the arbitrage, at today's prices: sell the call at 11, buy the put, buy the stock, borrow the strike's present value
cash_today = 11.0 - put - 100 + 100 * math.exp(-0.05 * 1)
print(round(cash_today, 4)) # 0.5494 you are paid the gap now and owe nothing at expiry# A call minus a put is a synthetic forward: it behaves like the stock bought with borrowed money
print(round(10.4506 - put, 4), round(100 - pv_strike, 4)) # 4.8771 4.8771C + K * exp(-rT) = P + S: uma call mais o título é igual a uma put mais a ação, logoP = C - S + K * exp(-rT).- Diferença
(C - P) - (S - K e^(-rT))positiva: venda a call, compre a put e a ação; negativa: o inverso. - A paridade não depende de modelo, use-a para verificar qualquer modelo de precificação; com dividendos ou exercício antecipado vira desigualdade.
A seguir: a fórmula de Black–Scholes, um preço em forma fechada para a call e a put.
Lab: o que é avaliado
- Obter a put a partir da call com
parity_put_price25 pts - Obter a call a partir da put com
parity_call_price25 pts - Medir o quanto os preços se afastam da paridade com
parity_gap25 pts - Nomear a operação sem risco com
arbitrage_action25 pts