我正在尝试使用Matlab(2012b)中的Black-Scholes公式来计算隐含波动率,但不知何故存在一些执行价格问题。 例如,blsimpv(1558,1440,0.0024,(1/12),116.4)将返回NaN。 我认为它可能是该功能的一些问题,因此在互联网上搜索其他一些matlab脚本并根据我的自定义需求进行定制,但不幸的是我仍然无法返回有效的隐含波动率。
function sigma=impvol(C,S,K,r,T)
%F=S*exp((r).*T);
%G=C.*exp(r.*T);
%alpha=log(F./K)./sqrt(T);
%beta=0.5*sqrt(T);
%a=beta.*(F+K);
%b=sqrt(2*pi)*(0.5*(F-K)-G);
%c=alpha.*(F-K);
%disc=max(0,b.^2-4*a.*c);
%sigma0=(-b+sqrt(disc))./(2*a);
i=-1000;
while i<=5000
sigma0=i/1000;
sigma=NewtonMethod(sigma0);
if sigma<=10 && sigma>=-10
fprintf('This is sigma %f',sigma)
end
i=i+1;
end
end
function s1=NewtonMethod(s0)
s1=s0;
count=0;
f=@(x) call(S,K,r,x,T)-C;
fprime=@(x) call_vega(S,K,r,x,T);
max_count=1e4;
while max(abs(f(s1)))>1e-7 && count<max_count
count=count+1;
s0=s1;
s1=s0-f(s0)./fprime(s0);
end
end
end
function d=d1(S,K,r,sigma,T)
d=(log(S./K)+(r+sigma.^2*0.5).*(T))./(sigma.*sqrt(T));
end
function d=d2(S,K,r,sigma,T)
d=(log(S./K)+(r-sigma.^2*0.5).*(T))./(sigma.*sqrt(T));
end
function p=Phi(x)
p=0.5*(1.+erf(x/sqrt(2)));
end
function p=PhiPrime(x)
p=exp(-0.5*x.^2)/sqrt(2*pi);
end
function c=call(S,K,r,sigma,T)
c=S.*Phi(d1(S,K,r,sigma,T))-K.*exp(-r.*(T)).*Phi(d2(S,K,r,sigma,T));
end
function v=call_vega(S,K,r,sigma,T)
v=S.*PhiPrime(d1(S,K,r,sigma,T)).*sqrt(T);
end
然而,运行impvol(116.4,1558,1440,0.0024,(1/12))将遗憾地返回值'Inf'。不知怎的,Newton-Rhapson方法的问题没有收敛,但我对如何解决这个问题毫无头绪。有谁知道如何解决这个问题或知道如何计算隐含波动率?
提前感谢你的帮助! 亲切的问候,
亨克
答案 0 :(得分:2)
我肯定会建议这段代码:Fast Matrixwise Black-Scholes Implied Volatility 它能够一次性计算整个表面 - 我的经验 - 我发现它比blsimpv()或impvol()更可靠,这是matlab中实现的其他功能。
答案 1 :(得分:1)
Newton-Rhapson方法不适用于隐含波动率。您应该使用二分法(不确定它在Matlab中的使用方式)。它在http://en.wikipedia.org/wiki/Bisection_method中描述。为了完整起见,它以这种方式工作:
1)选择任意高(不可能)的波动率,如高= 200%/年。
2)选择尽可能低的波动率(低= 0%)。
2a)计算0%波动率的期权溢价,如果实际溢价低于该波动率,则表示负波动率(&#34;不可能&#34;)。
3)虽然未找到隐含波动率:
3.1)如果&#34;高&#34;和&#34;低&#34;非常接近(例如,等于小数点后五位),其中一个是你的隐含波动率。如果不是......
3.2)计算&#34; high&#34;之间的平均值。和&#34;低&#34;。平均=(高+低)/ 2
3.3)计算平均波动率的期权溢价。
3.4)如果实际溢价高于p(平均值),则使得min = avg,因为隐含波动率必须介于avg和max之间。
3.4a)如果实际溢价低于p(平均值),则设为max = avg,因为隐含的卷必须介于min和avg之间。
bisect的主要优点是你必须选择一个最大值,因此你的函数不会发现隐含的波动率大于此值。但是,200%/年的东西应该足够高,以便在现实世界中使用。
我使用了另一种更像Newton方法的方法,因此不限于范围,因为vega是一种衍生物,但具有线性化&#34;修复以避免由于小维加斯造成的狩猎和失败:
def implied_volatility(type, premium, S, K, r, s_dummy, t):
if S <= 0.000001 or K <= 0.000001 or t <= 0.000001 or premium <= 0.000001:
return 0.0
s = 0.35
for cycle in range(0, 120):
ext_premium = type(S, K, r, s, t)
if abs(premium - ext_premium) < 0.005:
return s
ext_vega = type.vega(S, K, r, s, t)
# print S, K, r, s, t, premium, ext_premium, ext_vega
if ext_vega < 0.0000001:
# Avoids zero division if stuck
ext_vega = 0.0000001
s_new = s - (ext_premium - premium) / ext_vega
if abs(s_new - s) > 1.00:
# estimated s is too different from previous;
# it is better to go linearly, since
# vega is too small to give a good guess
if s_new > s:
s += 1.0
else:
s -= 1.0
else:
s = s_new
if s < 0.0:
# No volatility < 0%
s = 0.0001
if s > 99.99:
# No point calculating volatilities > 9999%/year
return 100.0
return 0.0
尽管如此,我认为bisect是你最好的选择。
答案 2 :(得分:0)
我创建了一个简单的函数,如果blsimpv的输出是NaN,则会进行一种试验和错误计算。这对我来说显着减慢了计算时间,但它总能给我一个理想的结果。
该功能显示在
下面使用BSIVC(t,i)= blsimpv(S(t,i),K,r,tau(t),HestonCiter(t,i))
if isnan(BSIVC(t,i));
BSIVC(t,i)= secondIVcalc(HestonCiter(t,i),S(t,i),K,r,q,tau(t))
end
该功能本身如下所述:
function IV= secondIVcalc(HestonC,S,K,r,q,T)
lowCdif = 1;
a=0;
while lowCdif>0.0001
a= a+0.00001
lowCdif = HestonC - BSCprice(S,K,r,q,a,T);
end
IV= a;
end
请注意,BSCprice不是matlab中的内置函数。
只是为了让代码更清晰 - BSCprice的格式为BSCprice(标的资产价格,行使价,利率,股息收益率,隐含金额,到期时间)。