Dos caminos al mismo sitio
Construye dos carteras. A: compra un call y deposita en el banco (o en un bono sin riesgo) el valor actual del strike K * exp(-rT). B: compra un put y compra la acción. Al vencimiento, si la acción acaba por encima de K, A es el S - K del call más el K del banco, o sea S; B es la acción S y un put sin valor, o sea S. Si la acción acaba por debajo de K, A es solo el K del banco porque el call vence sin valor, y B es el K - S del put más la acción S, o sea K. En ambos casos las dos carteras valen lo mismo al vencimiento, así que deben costar lo mismo hoy.
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 callCuando se rompe la paridad: arbitraje
Si el mercado cotiza precios que no cumplen la relación, existe un beneficio sin riesgo. Define la diferencia (C - P) - (S - K e^(-rT)). Una diferencia positiva significa que el call es demasiado caro para el put: vende el call, compra el put, compra la acción y pide prestado el valor actual del strike. La cartera no cuesta nada al inicio, no paga nada al vencimiento haga lo que haga la acción, y se embolsa la diferencia hoy. Una diferencia negativa invierte cada pata. Los mercados reales tienen costes y horquillas compra-venta, así que las diferencias pequeñas no son operables: eso representa la tolerancia.
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: un call más el bono iguala un put más la acción, así queP = C - S + K * exp(-rT).- Diferencia
(C - P) - (S - K e^(-rT))positiva: vende el call, compra el put y la acción; negativa: lo contrario. - La paridad no depende de ningún modelo: úsala para comprobar cualquier modelo de valoración; con dividendos o ejercicio anticipado se vuelve una desigualdad.
A continuación: la fórmula de Black–Scholes, un precio en forma cerrada para el call y el put.
Lab: qué se califica
- Obtener el put a partir del call con
parity_put_price25 pts - Obtener el call a partir del put con
parity_call_price25 pts - Medir cuánto se alejan los precios de la paridad con
parity_gap25 pts - Nombrar la operación sin riesgo con
arbitrage_action25 pts