2013年11月8日 星期五

隱含波動率 (with EXCEL VBA、C#)

 

延續前兩篇 (選擇權評價-BS MODEL (with Excel) 、歷史波動率 )的內容,這篇要來紀錄隱含波動率了。

 

隱含波動率(implied volatility, iv)是以選擇權市價所倒推回它處在多少的波動率之上, 可以表示市場對於指數波動的看法,這也是重要的選擇權交易策略。而要計算它的方法也有很簡單易懂的,就是去試。

 

假設要計算一個市價100的選擇權商品的iv,如同前篇紀錄的,我們已經有了選擇權評價的公式,先設定一組高低點(如1和0),取高低點的中位(0.5),把0.5代入選擇權評價的公式,假設得到150,比市價100高,表示0.5太高了,將剛剛的高點1改為0.5,再取高低點的中位(0.25),再算價格再和市價比,就這樣一直比到高低點的差距很小,就得到iv了。

 

剛剛這段計算的例子寫成程式,以VBA為例就如下:
Function civ(S, K, T, R, Target)
high = 1
low = 0

Do While (high - low) > 0.00001
If PriceC(S, K, T, R, (high + low) / 2) > Target Then
high = (high + low) / 2
Else
low = (high + low) / 2
End If
Loop

civ = (high + low) / 2
End Function

Function piv(S, K, T, R, Target)
high = 1
low = 0

Do While (high - low) > 0.00001
If PriceP(S, K, T, R, (high + low) / 2) > Target Then
high = (high + low) / 2
Else
low = (high + low) / 2
End If
Loop

piv = (high + low) / 2
End Function

Function d1(S, K, T, R, V)
d1 = (Log(S / K) + (R * T) + (V ^ 2 * T / 2)) / (V * Sqr(T))
End Function

Function d2(S, K, T, R, V)
d2 = d1(S, K, T, R, V) - V * Sqr(T)
End Function

Function PriceC(S, K, T, R, V)
PriceC = S * Application.NormSDist(d1(S, K, T, R, V)) - K * Exp(-(R * T)) * Application.NormSDist(d2(S, K, T, R, V))
End Function

Function PriceP(S, K, T, R, V)
PriceP = K * Exp(-R * T) * Application.NormSDist(-d2(S, K, T, R, V)) - S * Application.NormSDist(-d1(S, K, T, R, V))
End Function

其中civ計算call的iv,piv計算put的iv,用到的Function之前有介紹過。

變數名稱

 

S 現貨價格,我們拿來算台指選的話,就拿台指期市價當作S

K 履約價格

T 距離到期日的時間,要年化

R 年利率

V 年化波動率

Target 標的選擇權的市價

 

同樣的程式用c#寫,也在這篇紀錄一下。
class Option
{

public double CallPrice;
public double PutPrice;

public void Price(double S, double K, double R, double T, double V)
{
double a = Math.Log(S / K);
double b_call = (R + 0.5 * Math.Pow(V, 2)) * T;
double b_put = (R - 0.5 * Math.Pow(V, 2)) * T;
double c = V * Math.Sqrt(T);
double d1 = (a + b_call) / c;
double d2 = (a + b_put) / c;
CallPrice = S * ND(d1) - K * Math.Exp(-R * T) * ND(d2);
PutPrice = K * Math.Exp(-R * T) * ND(-d2) - S * ND(-d1);
}

public double PriceC(double S, double K, double R, double T, double V)
{
double a = Math.Log(S / K);
double b_call = (R + 0.5 * Math.Pow(V, 2)) * T;
double b_put = (R - 0.5 * Math.Pow(V, 2)) * T;
double c = V * Math.Sqrt(T);
double d1 = (a + b_call) / c;
double d2 = (a + b_put) / c;
CallPrice = S * ND(d1) - K * Math.Exp(-R * T) * ND(d2);
return CallPrice;
}

public double PriceP(double S, double K, double R, double T, double V)
{
double a = Math.Log(S / K);
double b_call = (R + 0.5 * Math.Pow(V, 2)) * T;
double b_put = (R - 0.5 * Math.Pow(V, 2)) * T;
double c = V * Math.Sqrt(T);
double d1 = (a + b_call) / c;
double d2 = (a + b_put) / c;
PutPrice = K * Math.Exp(-R * T) * ND(-d2) - S * ND(-d1);
return PutPrice;
}

public double ND(double d)
{
double L = 0.0;
double K = 0.0;
double dD = 0.0;
const double a1 = 0.31938153;
const double a2 = -0.356563782;
const double a3 = 1.781477937;
const double a4 = -1.821255978;
const double a5 = 1.330274429;
L = Math.Abs(d);
K = 1.0 / (1.0 + 0.2316419 * L);

dD = 1.0 - 1.0 / Math.Sqrt(2 * Convert.ToDouble(Math.PI)) * Math.Exp(-L * L / 2.0) * (a1 * K + a2 * K * K + a3 * Math.Pow(K, 3.0) + a4 * Math.Pow(K, 4.0) + a5 * Math.Pow(K, 5.0));

if (d < 0) {return 1.0 - dD;}else{return dD;}
}

public double d1(double S, double K, double R, double T, double V)
{
double a = Math.Log(S / K);
double b_call = (R + 0.5 * Math.Pow(V, 2)) * T;
double c = V * Math.Sqrt(T);
double d1 = (a + b_call) / c;
return d1;
}

public double civ(double S, double K, double R, double T, double Target)
{
double high = 1;
double low = 0;

while ((high - low) > 0.00001)
{
if (PriceC(S, K, R, T, (high + low) / 2) > Target) { high = (high + low) / 2; }
else {low = (high + low) / 2;}
}

double civ = (high + low) / 2;
return civ;
}

public double piv(double S, double K, double R, double T, double Target)
{
double high = 1;
double low = 0;

while ((high - low) > 0.00001)
{
if (PriceP(S, K, R, T, (high + low) / 2) > Target)
{high = (high + low) / 2;} else {low = (high + low) / 2;}
}

double piv = (high + low) / 2;
return piv;
}
}

上面是一個class,直接加入類別就可以使用了,呼叫 Price(...) 後,可以拿屬性 CallPrice 和 PutPrice來用,或是分別呼叫PriceC(...) 或 PriceP(...) ,計算civ和piv一樣,可以直接得到回傳值iv。跟VBA不同的是,C#要多寫一個常態分配的函數ND。

 

有了這些,就可以計算出隱含波動率,運用上就看各人解讀了,之後再繼續紀錄。

(註: 範例程式是 L 參考網路上程式後自己撰寫的,讀者可自由複製使用,但程式碼轉載請註明出處 。)

 

 

6 則留言:

  1. 你好:
    我想請問你(履約價+權利金<指數)為什麼隱波率算不出來?註:權利金還有內含價值.
    假設履約價:8300.
    權利金:50
    指數:8350
    權利金50還可以算出隱波率.權利金49.9算不出隱波率.是什麼原因.
    謝謝

    回覆刪除
  2. HI 以你舉的例子,指數8350時,8300C權利金50點就已經全部是內含價值了。就算到期時間剩下非常短,隱含波動率也小到接近0,這個權利金也至少是50以上,所以若代入比50小的價格回算隱含波動率是算不出來的。

    回覆刪除
  3. 為何會有0.00%的情況
    8800,到期是0.05,選擇權市價334,期貨市價9127

    回覆刪除
  4. HI 不會是0,應該是公式計算有誤,再檢查看看吧,
    8800 CALL 334 & 到期時間及期貨一樣,下我看到VOL值約10.9%

    回覆刪除
  5. 有開發界面的需求,需求非常簡易
    line id:immortal9713

    回覆刪除
  6. HI 阿傑

    不好意思,目前沒在接程式,謝謝

    L

    回覆刪除