Hoy vemos cómo calcular el precio de una Call o una Put y representarlo en la pantalla de Amibroker. El modelo se ajusta variando la volatilidad implícita para que el precio teórico coincida con el precio de mercado.
El siguiente vídeo explica cómo se usa el código:
CÓDIGO AMIBROKER
//*******************************************
//
// IMPLEMENTACIÓN DE LA FORMULA BLACK 76
// DE OPCIONES SOBRE FUTUROS
// OSCAR G. CAGIGAS - 19 MARZO 2021
//
//*******************************************
//INCLUDE CON LOS MULTIPLICADORES Y EL INTERVALO DE STRIKES (STKINT)
SetOption("warninglevel",1);
decim = 1.2;
stkint = 5; //intervalo entre strikes
//PARÁMETROS
r = 0.00; //interés
tipo = ParamList("Tipo","Call|Put");
expiration = ParamDate("Expiration Date ","1/6/2021");
//redondea los strikes a números enteros
function Redondea( precio )
{
TickInv = 1 / stkint;
return ( round( precio * TickInv ) / TickInv );
}
function RedondeaVolat( volat )
{
TickInv = 1 / 0.005;
return ( round( volat * TickInv ) / TickInv );
}
//valores mínimos y máximos del strike
stk = redondea(LastValue(C));
smin = redondea(LastValue(C)*0.5);
smax = redondea(LastValue(C)*2);
s = Param("Strike",stk,smin,smax,stkint);
//PRECIO DEL SUBYACENTE
SetChartOptions(0,chartShowArrows|chartShowDates);
_N(Title = StrFormat("{{NAME}} - {{INTERVAL}} {{DATE}} Open %g, Hi %g, Lo %g, Close %g (%.1f%%) {{VALUES}}", O, H, L, C, SelectedValue( ROC( C, 1 ) ) ));
Plot( C, "Close", colorblack, styleNoTitle | styleThick| styleBar );
//*********** FUNCIÓN BLACK76 ***************
// comprobado con el libro McMillan pág 636
function Black76call(f,k,DTE,r,vol)
{
t = DTE/365;
d1 = ( ln(f/k) + (r + 0.5*vol^2)*t ) / ( vol*sqrt(t) );
d2 = d1 - vol*sqrt(t);
price = exp(-r*t)*( f*NormDist(d1,0,1,True) - k*NormDist(d2,0,1,True) );
return price;
}
function Black76put(f,k,DTE,r,vol)
{
t = DTE/365;
d1 = ( ln(f/k) + (r + 0.5*vol^2)*t ) / ( vol*sqrt(t) );
d2 = d1 - vol*sqrt(t);
price = exp(-r*t)*( k*NormDist(-d2,0,1,True) - f*NormDist(-d1,0,1,True) );
return price;
}
function CalculaDelta(f,k,DTE,r,vol)
{
t = DTE/365;
d1 = ( ln(f/k) + (r + 0.5*vol^2)*t ) / ( vol*sqrt(t) );
return NormDist(d1,0,1,True);
}
function CalculaGamma(f,k,DTE,r,vol)
{
t = DTE/365;
d1 = ( ln(f/k) + (r + 0.5*vol^2)*t ) / ( vol*sqrt(t) );
Npd1 = ( 1/sqrt(2*3.141592654) ) * exp( -d1^2/2 ); //Derivada Dist Normal de d1
return Npd1 / ( vol*f*sqrt(t) );
}
function CalculaVega(f,k,DTE,r,vol)
{
t = DTE/365;
d1 = ( ln(f/k) + (r + 0.5*vol^2)*t ) / ( vol*sqrt(t) );
Npd1 = ( 1/sqrt(2*3.141592654) ) * exp( -d1^2/2 ); //Derivada Dist Normal de d1
return f*Npd1*sqrt(t);
}
function CalculaThetaCall(f,k,DTE,r,vol)
{
t = DTE/365;
d1 = ( ln(f/k) + (r + 0.5*vol^2)*t ) / ( vol*sqrt(t) );
d2 = d1 - vol*sqrt(t);
Npd1 = ( 1/sqrt(2*3.141592654) ) * exp( -d1^2/2 ); //Derivada Dist Normal de d2
temp = r*k*exp(-r*t)*NormDist(d2,0,1,True) + f*Vol*Npd1/( 2*sqrt(t) );
return -temp/365;
}
function CalculaThetaPut(f,k,DTE,r,vol)
{
t = DTE/365;
d1 = ( ln(f/k) + (r + 0.5*vol^2)*t ) / ( vol*sqrt(t) );
d2 = d1 - vol*sqrt(t);
Npd1 = ( 1/sqrt(2*3.141592654) ) * exp( -d1^2/2 ); //Derivada Dist Normal de d1
temp = r*k*exp(-r*t)*NormDist(-d2,0,1,True) - f*Vol*Npd1/( 2*sqrt(t) );
return temp/365;
}
function CalculaProb(f,k,DTE,r,vol)
{
t = DTE/365;
temp = ln(k/f) / ( vol*sqrt(t) );
return NormDist(temp,0,1,True);
}
function DayNum(dt)
{
yr= int(Dt/10000);
mo= int((dt-(yr*10000))/100);
dy= int(dt-(yr*10000)-(mo*100));
adj = (mo>1) +(mo>3) + (mo>5) + (mo>7) + (mo>8) + (mo>10) + (mo>12)- ((mo>2)*2);
return ( yr*365) +( (mo-1)*30) +dy +adj;
}
//DAYS TO EXPIRATION
DTE = daynum(expiration)-daynum(DateNum());
//VOLATILIDAD
HV = sqrt(252)*StDev(ln(C/Ref(C,-1)),21);
vol = LastValue(HV) + Param("Ajuste Volat",0,-0.5,1,0.001); //IV comienza en HV
//CALL O PUT
call = Black76call(C,s,DTE,r,vol);
Put = Black76put(C,s,DTE,r,vol);
opcion = IIf(tipo == "Call", call, put);
color = IIf(tipo == "Call", colorGreen,colorRed);
Plot(opcion,tipo,color,styleLeftAxisScale|styleThick,Null,Null,Null,0,3);
//LETRAS GRIEGAS Y PROB
delta = IIf(tipo == "Call", CalculaDelta(C,s,DTE,r,vol), CalculaDelta(C,s,DTE,r,vol)-1 );
gamma = CalculaGamma(C,s,DTE,r,vol);
vega = CalculaVega(C,s,DTE,r,vol)/100; //igual para call y put
theta = IIf(tipo == "Call", CalculaThetaCall(C,s,DTE,r,vol), CalculaThetaPut(C,s,DTE,r,vol) );
prob = IIf(tipo == "Call", CalculaProb(C,s + call,DTE,r,vol), 1 - CalculaProb(C,s - put,DTE,r,vol) );
//PINTA EL STRIKE
Plot(s,"Strike",colorBlue,styleLine);
//AÑADIMOS LETREROS CON STRIKE, DTE, ETC
Title = Title + "\n" + "STRIKE = " + s + "; DTE = " + DTE + "; IV = " + vol + "\n" + LastValue(HV)
+ "\n" + "blackPUT=" + Black76put(100,90,91,0.06,0.384) + "; blackCALL=" + Black76call(100,90,91,0.06,0.384);
//LETRERO EN GRANDE
sep = 48; start = 300; //separación y comienzo eje Y
GfxSetBkColor( colorLightYellow); GfxSelectFont( "Tahoma", 12 );
GfxSetBkMode( 2 );
GfxTextOut(" " + tipo, 40, start ); //call o put
GfxTextOut(" STRIKE = " + WriteVal(s,decim), 40, start+sep );
GfxTextOut(" DTE = " + WriteVal(DTE,1), 40, start+2*sep );
GfxTextOut(" HV = " + WriteVal(HV*100,1.2) + "%; "
+ " IV = " + WriteVal(vol*100,1.2) + "%", 40, start+3*sep );
GfxTextOut(" Delta = " + WriteVal(delta,1.2), 40, start+4*sep );
GfxTextOut(" Gamma = " + WriteVal(gamma,.6), 40, start+5*sep );
GfxTextOut(" Vega = " + WriteVal(vega,.6), 40, start+6*sep );
GfxTextOut(" Theta = " + WriteVal(Theta,.7), 40, start+7*sep );
GfxTextOut(" Prob = " + WriteVal(Prob*100,1.2) + "%", 40, start+8*sep );
GfxTextOut(" Premium = $" + WriteVal(opcion*PointValue,1), 40, start+9*sep );
//comprobación McMIllan libro gordo pág 636
//+ "\n" + "blackPUT=" + Black76put(100,90,91,0.06,0.384) + "; blackCALL=" + Black76call(100,90,91,0.06,0.384);
//
// IMPLEMENTACIÓN DE LA FORMULA BLACK 76
// DE OPCIONES SOBRE FUTUROS
// OSCAR G. CAGIGAS - 19 MARZO 2021
//
//*******************************************
//INCLUDE CON LOS MULTIPLICADORES Y EL INTERVALO DE STRIKES (STKINT)
SetOption("warninglevel",1);
decim = 1.2;
stkint = 5; //intervalo entre strikes
//PARÁMETROS
r = 0.00; //interés
tipo = ParamList("Tipo","Call|Put");
expiration = ParamDate("Expiration Date ","1/6/2021");
//redondea los strikes a números enteros
function Redondea( precio )
{
TickInv = 1 / stkint;
return ( round( precio * TickInv ) / TickInv );
}
function RedondeaVolat( volat )
{
TickInv = 1 / 0.005;
return ( round( volat * TickInv ) / TickInv );
}
//valores mínimos y máximos del strike
stk = redondea(LastValue(C));
smin = redondea(LastValue(C)*0.5);
smax = redondea(LastValue(C)*2);
s = Param("Strike",stk,smin,smax,stkint);
//PRECIO DEL SUBYACENTE
SetChartOptions(0,chartShowArrows|chartShowDates);
_N(Title = StrFormat("{{NAME}} - {{INTERVAL}} {{DATE}} Open %g, Hi %g, Lo %g, Close %g (%.1f%%) {{VALUES}}", O, H, L, C, SelectedValue( ROC( C, 1 ) ) ));
Plot( C, "Close", colorblack, styleNoTitle | styleThick| styleBar );
//*********** FUNCIÓN BLACK76 ***************
// comprobado con el libro McMillan pág 636
function Black76call(f,k,DTE,r,vol)
{
t = DTE/365;
d1 = ( ln(f/k) + (r + 0.5*vol^2)*t ) / ( vol*sqrt(t) );
d2 = d1 - vol*sqrt(t);
price = exp(-r*t)*( f*NormDist(d1,0,1,True) - k*NormDist(d2,0,1,True) );
return price;
}
function Black76put(f,k,DTE,r,vol)
{
t = DTE/365;
d1 = ( ln(f/k) + (r + 0.5*vol^2)*t ) / ( vol*sqrt(t) );
d2 = d1 - vol*sqrt(t);
price = exp(-r*t)*( k*NormDist(-d2,0,1,True) - f*NormDist(-d1,0,1,True) );
return price;
}
function CalculaDelta(f,k,DTE,r,vol)
{
t = DTE/365;
d1 = ( ln(f/k) + (r + 0.5*vol^2)*t ) / ( vol*sqrt(t) );
return NormDist(d1,0,1,True);
}
function CalculaGamma(f,k,DTE,r,vol)
{
t = DTE/365;
d1 = ( ln(f/k) + (r + 0.5*vol^2)*t ) / ( vol*sqrt(t) );
Npd1 = ( 1/sqrt(2*3.141592654) ) * exp( -d1^2/2 ); //Derivada Dist Normal de d1
return Npd1 / ( vol*f*sqrt(t) );
}
function CalculaVega(f,k,DTE,r,vol)
{
t = DTE/365;
d1 = ( ln(f/k) + (r + 0.5*vol^2)*t ) / ( vol*sqrt(t) );
Npd1 = ( 1/sqrt(2*3.141592654) ) * exp( -d1^2/2 ); //Derivada Dist Normal de d1
return f*Npd1*sqrt(t);
}
function CalculaThetaCall(f,k,DTE,r,vol)
{
t = DTE/365;
d1 = ( ln(f/k) + (r + 0.5*vol^2)*t ) / ( vol*sqrt(t) );
d2 = d1 - vol*sqrt(t);
Npd1 = ( 1/sqrt(2*3.141592654) ) * exp( -d1^2/2 ); //Derivada Dist Normal de d2
temp = r*k*exp(-r*t)*NormDist(d2,0,1,True) + f*Vol*Npd1/( 2*sqrt(t) );
return -temp/365;
}
function CalculaThetaPut(f,k,DTE,r,vol)
{
t = DTE/365;
d1 = ( ln(f/k) + (r + 0.5*vol^2)*t ) / ( vol*sqrt(t) );
d2 = d1 - vol*sqrt(t);
Npd1 = ( 1/sqrt(2*3.141592654) ) * exp( -d1^2/2 ); //Derivada Dist Normal de d1
temp = r*k*exp(-r*t)*NormDist(-d2,0,1,True) - f*Vol*Npd1/( 2*sqrt(t) );
return temp/365;
}
function CalculaProb(f,k,DTE,r,vol)
{
t = DTE/365;
temp = ln(k/f) / ( vol*sqrt(t) );
return NormDist(temp,0,1,True);
}
function DayNum(dt)
{
yr= int(Dt/10000);
mo= int((dt-(yr*10000))/100);
dy= int(dt-(yr*10000)-(mo*100));
adj = (mo>1) +(mo>3) + (mo>5) + (mo>7) + (mo>8) + (mo>10) + (mo>12)- ((mo>2)*2);
return ( yr*365) +( (mo-1)*30) +dy +adj;
}
//DAYS TO EXPIRATION
DTE = daynum(expiration)-daynum(DateNum());
//VOLATILIDAD
HV = sqrt(252)*StDev(ln(C/Ref(C,-1)),21);
vol = LastValue(HV) + Param("Ajuste Volat",0,-0.5,1,0.001); //IV comienza en HV
//CALL O PUT
call = Black76call(C,s,DTE,r,vol);
Put = Black76put(C,s,DTE,r,vol);
opcion = IIf(tipo == "Call", call, put);
color = IIf(tipo == "Call", colorGreen,colorRed);
Plot(opcion,tipo,color,styleLeftAxisScale|styleThick,Null,Null,Null,0,3);
//LETRAS GRIEGAS Y PROB
delta = IIf(tipo == "Call", CalculaDelta(C,s,DTE,r,vol), CalculaDelta(C,s,DTE,r,vol)-1 );
gamma = CalculaGamma(C,s,DTE,r,vol);
vega = CalculaVega(C,s,DTE,r,vol)/100; //igual para call y put
theta = IIf(tipo == "Call", CalculaThetaCall(C,s,DTE,r,vol), CalculaThetaPut(C,s,DTE,r,vol) );
prob = IIf(tipo == "Call", CalculaProb(C,s + call,DTE,r,vol), 1 - CalculaProb(C,s - put,DTE,r,vol) );
//PINTA EL STRIKE
Plot(s,"Strike",colorBlue,styleLine);
//AÑADIMOS LETREROS CON STRIKE, DTE, ETC
Title = Title + "\n" + "STRIKE = " + s + "; DTE = " + DTE + "; IV = " + vol + "\n" + LastValue(HV)
+ "\n" + "blackPUT=" + Black76put(100,90,91,0.06,0.384) + "; blackCALL=" + Black76call(100,90,91,0.06,0.384);
//LETRERO EN GRANDE
sep = 48; start = 300; //separación y comienzo eje Y
GfxSetBkColor( colorLightYellow); GfxSelectFont( "Tahoma", 12 );
GfxSetBkMode( 2 );
GfxTextOut(" " + tipo, 40, start ); //call o put
GfxTextOut(" STRIKE = " + WriteVal(s,decim), 40, start+sep );
GfxTextOut(" DTE = " + WriteVal(DTE,1), 40, start+2*sep );
GfxTextOut(" HV = " + WriteVal(HV*100,1.2) + "%; "
+ " IV = " + WriteVal(vol*100,1.2) + "%", 40, start+3*sep );
GfxTextOut(" Delta = " + WriteVal(delta,1.2), 40, start+4*sep );
GfxTextOut(" Gamma = " + WriteVal(gamma,.6), 40, start+5*sep );
GfxTextOut(" Vega = " + WriteVal(vega,.6), 40, start+6*sep );
GfxTextOut(" Theta = " + WriteVal(Theta,.7), 40, start+7*sep );
GfxTextOut(" Prob = " + WriteVal(Prob*100,1.2) + "%", 40, start+8*sep );
GfxTextOut(" Premium = $" + WriteVal(opcion*PointValue,1), 40, start+9*sep );
//comprobación McMIllan libro gordo pág 636
//+ "\n" + "blackPUT=" + Black76put(100,90,91,0.06,0.384) + "; blackCALL=" + Black76call(100,90,91,0.06,0.384);
Muy bueno Oscar, Gracias por compartirlo
ResponderEliminar