2

我正在尝试使用 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”。不知何故,牛顿-拉普森方法没有收敛,但我对如何解决这个问题一无所知。有谁知道如何解决这个问题或知道如何计算隐含波动率的其他方法?

预先感谢您的帮助!亲切的问候,

亨克

4

3 回答 3

2

我肯定会建议使用此代码:Fast Matrixwise Black-Scholes Implied Volatility 它能够一次计算整个表面,并且 - 我的经验 - 我发现它比blsimpv()impvol()更可靠,后者是在MATLAB。

于 2014-11-14T18:56:28.657 回答
1

Newton-Rhapson 方法不适用于隐含波动率。您应该使用二分法(不确定它在 Matlab 中是如何使用的)。它在http://en.wikipedia.org/wiki/Bisection_method中有描述。为了完整起见,它是这样工作的:

1) 选择任意高(不可能)波动率,例如高=200%/年。

2) 选择尽可能低的波动性(低=0%)。

2a) 计算0%波动率的期权溢价,如果实际溢价低于这个值,则意味着负波动率(这是“不可能的”)。

3) 虽然没有找到隐含波动率:

3.1) 如果“高”和“低”非常接近(例如等于小数点后第 5 位),则任何一个都是您的隐含波动率。如果不...

3.2)计算“高”和“低”之间的平均值。平均=(高+低)/2

3.3) 计算平均波动率的期权溢价。

3.4) 如果实际溢价高于 p(avg),则令 min=avg,因为隐含波动率必须介于 avg 和 max 之间。

3.4a) 如果实际溢价低于 p(avg),则令 max=avg,因为隐含 vol 必须位于 min 和 avg 之间。

bisect 的主要缺点是你必须选择一个最大值,所以你的函数不会找到比这更大的隐含波动率。但是像 200%/年这样的速度对于实际使用来说应该足够高了。

我使用另一种更像牛顿方法的方法,因此不限于一个范围,因为 vega 是一个衍生物,但有一个“线性化”修复以避免由于小 vegas 而导致的狩猎和失败:

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 是你最好的选择。

于 2014-02-05T19:18:38.863 回答
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(基础资产价格、执行价格、利率、股息收益率、隐含交易量、到期时间)。

于 2017-12-29T13:09:30.043 回答