2013年12月11日 星期三

選擇權GREEKS實作(C#)

 

在能夠計算 選擇權評價-BS MODEL (with Excel) 及 隱含波動率 (with EXCEL VBA、C#) 之後,再來剩GREEKS了,要計算四個影響價格的變數是Delta、Gamma、 Vega、Theta,完成這部份就可以得出目前選擇權部位組合的各項數值。關於這些希臘字母的定義和作用,都需要深入瞭解後才能對選擇權策略有所掌握,進而設計出選擇權策略。

 

此篇要紀錄的僅是關於系統開發,雖說大部份的交易軟體都會提供GREEKS資料,但總要是自己寫的才能確定正確性,因為券商軟體算的不一定對。當然也有許多人不在意些微差距,或根本沒在觀察GREEKS,但那樣操作選擇權是無法進步的,再說若要自己建立策略模組,這些也只是第一步而已。

 

大部份設計選擇權監視程式的軟體是EXCEL,因為最簡便,直接利用公式和一些函數設計就可以完成,若要即時串接部位的話,大部份是寫VBA程式和券商API串接,而行情的部份可以用DDE或API來接收。

 

但是EXCEL會有效能問題,如果接受行情多,再加上運算邏輯複雜,EXCEL很可能會有延遲的狀況,因此比較好的方式還是自己寫程式,可以先由券商API所提供的範例程式來測試,可能是VB、C#、C++或Delphi等等,選一個好寫的來測試收行情、回報、部位。此篇L要紀錄的是以C#來實作選擇權GREEKS。

 

整段範例程式碼貼在最後面,需要先說明一下前因後果,先有一個DataTable是用來紀錄未平倉的選擇權部位,這個副程式所要處理的是計算目前所有未平倉選擇權部位的GREEKS並寫進DataTable,這個DataTable再與DataGridView串接,就可以顯示在FORM上

 

這個DataTable,取名dtOI,至少有以下的欄位:

 

dtOI.Columns.Add(new DataColumn("SettleM", typeof(string))); //月份

dtOI.Columns.Add(new DataColumn("Strike", typeof(double))); //履約價

dtOI.Columns.Add(new DataColumn("CP", typeof(string))); //Call or Put

dtOI.Columns.Add(new DataColumn("BS", typeof(string))); //Buy or Short

dtOI.Columns.Add(new DataColumn("Qty", typeof(string))); //口數

dtOI.Columns.Add(new DataColumn("Match", typeof(double))); //成交價

dtOI.Columns.Add(new DataColumn("Market", typeof(double))); //市價

dtOI.Columns.Add(new DataColumn("VOL(%)", typeof(double))); //隱含波動率

dtOI.Columns.Add(new DataColumn("DELTA", typeof(double))); //DELTA

dtOI.Columns.Add(new DataColumn("GAMMA", typeof(double)));//GAMMA

dtOI.Columns.Add(new DataColumn("THETA", typeof(double))); //THETA

dtOI.Columns.Add(new DataColumn("VEGA", typeof(double))); //VEGA

 

在執行副程式之前,除了最後五欄之外都是準備好的,然後有一些變數要準備

AssetPrice 期貨價格

Strike 履約價

InterestRate 利率

Expiry 到期因子

Target 選擇權的市價

 

還有之前紀錄隱含波動率的類別,一開始要NEW一下。

Option op = new Option();

 

然後就開始了,看片段來說明一下

 

圖片 1

 

圖片 3

 

圖片 4

 

以下PUT的部份就依此類推。程式碼如後所貼,有一些使用到的參數及關聯FORM的變數沒有仔細說明,不過整個架構已經是可以瞭解的了。以前 L 設計時找不到完整的參考資料,一步步的自己設計,現在若有同樣需求的朋友看到這邊可以自由取用,歡迎參考及指正

 
private void Greeks()
{
int i = 0;
AssetPrice = double.Parse(label16.Text);

while (i < dtOI.Rows.Count)
{
Strike = double.Parse(dtOI.Rows[i]["Strike"].ToString());
Target = double.Parse(dtOI.Rows[i]["Market"].ToString());
Qty = double.Parse(dtOI.Rows[i]["Qty"].ToString());

//期貨
if (dtOI.Rows[i]["CP"].ToString() == "")
{
if (dtOI.Rows[i]["BS"].ToString().Trim() == "B")
{
dtOI.Rows[i].SetField("DELTA", 200 * Qty );
}
if (dtOI.Rows[i]["BS"].ToString().Trim() == "S")
{
dtOI.Rows[i].SetField("DELTA", -200 * Qty );
}
}

//CALL civ(double AssetPrice, double Strike, double InterestRate, double Expiry, double Target)
if ((dtOI.Rows[i]["CP"].ToString().Trim()) == "C")
{
if (dtOI.Rows[i]["PId"].ToString().Trim() == "TXO")
{
if (dtOI.Rows[i]["SettleM"].ToString().Trim() == label10.Text.Substring(0, 6)) //近月
{
AssetPrice = double.Parse(label16.Text);
Expiry = Expirynear;
}

if (dtOI.Rows[i]["SettleM"].ToString().Trim() == label11.Text.Substring(0, 6)) //遠月
{
if (label22.Text != "")
{
AssetPrice = double.Parse(label22.Text);
}
else { AssetPrice = double.Parse(label16.Text); }
Expiry = Expiryfar;
}
}
else //週選
{
if (wnFid != "MX")
{
if (dtOI.Rows[i]["PId"].ToString().Trim().Substring(1, 2) == wnFid.Substring(1, 2)) //近週
{
AssetPrice = double.Parse(label23.Text);
Expiry = Expirywn;
}
}

if (wfFid != "MX")
{
if (dtOI.Rows[i]["PId"].ToString().Trim().Substring(1, 2) == wfFid.Substring(1, 2)) //遠週
{
AssetPrice = double.Parse(label22.Text);
Expiry = Expirywf;
}
}
}

civ = op.civ(AssetPrice, Strike, InterestRate, Expiry, Target);
d1 = op.d1(AssetPrice, Strike, InterestRate, Expiry, civ);
nd1 = Math.Exp(-0.5 * d1 * d1) / Math.Sqrt(2 * Math.PI);
nd2 = op.NormsDist(d1 - civ * Math.Sqrt(Expiry));

//DELTA NormsDist(double x) d1(double AssetPrice, double Strike, double InterestRate, double Expiry, double Volatility)
DELTA = op.NormsDist(d1);
GAMMA = nd1 / (AssetPrice * civ * Math.Sqrt(Expiry));
THETA = (-(AssetPrice * nd1 * civ / (2 * Math.Sqrt(Expiry))) - InterestRate * Strike * Math.Exp(-InterestRate * Expiry) * nd2) / 365;
VEGA = (AssetPrice * (Math.Sqrt(Expiry)) * nd1) / 100;

dtOI.Rows[i].SetField("VOL(%)", Math.Round(civ * 100, 4));

if (dtOI.Rows[i]["BS"].ToString().Trim() == "B")
{
dtOI.Rows[i].SetField("DELTA", Math.Round(DELTA * 50 * Qty , 0));
dtOI.Rows[i].SetField("GAMMA", Math.Round(GAMMA * 50 * Qty * AssetPrice / 100, 0));
dtOI.Rows[i].SetField("THETA", Math.Round(THETA * 50 * Qty, 0));
dtOI.Rows[i].SetField("VEGA", Math.Round(VEGA * 50 * Qty, 0));
}
else if (dtOI.Rows[i]["BS"].ToString().Trim() == "S")
{
dtOI.Rows[i].SetField("DELTA", Math.Round(-DELTA * 50 * Qty , 0));
dtOI.Rows[i].SetField("GAMMA", Math.Round(-GAMMA * 50 * Qty * AssetPrice / 100, 0));
dtOI.Rows[i].SetField("THETA", Math.Round(-THETA * 50 * Qty, 0));
dtOI.Rows[i].SetField("VEGA", Math.Round(-VEGA * 50 * Qty, 0));
}
}

//PUT piv(double AssetPrice, double Strike, double InterestRate, double Expiry, double Target)
if ((dtOI.Rows[i]["CP"].ToString().Trim()) == "P")
{
if (dtOI.Rows[i]["PId"].ToString().Trim() == "TXO")
{
if (dtOI.Rows[i]["SettleM"].ToString().Trim() == label10.Text.Substring(0, 6)) //近月
{
AssetPrice = double.Parse(label16.Text);
Expiry = Expirynear;
}

if (dtOI.Rows[i]["SettleM"].ToString().Trim() == label11.Text.Substring(0, 6)) //遠月
{
if (label22.Text != "")
{
AssetPrice = double.Parse(label22.Text);
}
else { AssetPrice = double.Parse(label16.Text); }
Expiry = Expiryfar;
}
}
else //週選
{

if (wnFid != "MX")
{
if (dtOI.Rows[i]["PId"].ToString().Trim().Substring(1, 2) == wnFid.Substring(1, 2)) //近週
{
AssetPrice = double.Parse(label23.Text);
Expiry = Expirywn;
}
}

if (wfFid != "MX")
{
if (dtOI.Rows[i]["PId"].ToString().Trim().Substring(1, 2) == wfFid.Substring(1, 2)) //遠週
{
AssetPrice = double.Parse(label22.Text);
Expiry = Expirywf;
}
}
}

piv = op.piv(AssetPrice, Strike, InterestRate, Expiry, Target);
d1 = op.d1(AssetPrice, Strike, InterestRate, Expiry, piv);
nd1 = Math.Exp(-0.5 * d1 * d1) / Math.Sqrt(2 * Math.PI);
nd2 = op.NormsDist(d1 - piv * Math.Sqrt(Expiry));

//DELTA NormsDist(double x) d1(double AssetPrice, double Strike, double InterestRate, double Expiry, double Volatility)
DELTA = op.NormsDist(d1) - 1;
GAMMA = nd1 / (AssetPrice * piv * Math.Sqrt(Expiry));
THETA = (-(AssetPrice * nd1 * piv / (2 * Math.Sqrt(Expiry))) + InterestRate * Strike * Math.Exp(-InterestRate * Expiry) * nd2) / 365;
VEGA = (AssetPrice * (Math.Sqrt(Expiry)) * nd1) / 100;

dtOI.Rows[i].SetField("VOL(%)", Math.Round(piv * 100, 4));

if (dtOI.Rows[i]["BS"].ToString().Trim() == "B")
{
dtOI.Rows[i].SetField("DELTA", Math.Round(DELTA * 50 * Qty , 0));
dtOI.Rows[i].SetField("GAMMA", Math.Round(GAMMA * 50 * Qty * AssetPrice / 100, 0));
dtOI.Rows[i].SetField("THETA", Math.Round(THETA * 50 * Qty, 0));
dtOI.Rows[i].SetField("VEGA", Math.Round(VEGA * 50 * Qty, 0));
}
else if (dtOI.Rows[i]["BS"].ToString().Trim() == "S")
{
dtOI.Rows[i].SetField("DELTA", Math.Round(-DELTA * 50 * Qty , 0));
dtOI.Rows[i].SetField("GAMMA", Math.Round(-GAMMA * 50 * Qty * AssetPrice / 100, 0));
dtOI.Rows[i].SetField("THETA", Math.Round(-THETA * 50 * Qty, 0));
dtOI.Rows[i].SetField("VEGA", Math.Round(-VEGA * 50 * Qty, 0));
}
}

//dtOI.Rows[i].SetField("VOL(%)", i);
i = i + 1;
}

}

 

 

 

4 則留言:

  1. 站長大您們好,請問有關C#有什麼推薦的書籍能夠入門嗎?

    雖然我想應該是沒有比較偏向財務應用的書籍,但還是希望大大能夠推薦。

    謝謝'

    回覆刪除
  2. HI steve,

    入門的C#書籍倒是沒有特定的,像是博客來找C#的書我覺得都大同小異,那算是工具書,隨著軟體改版就一本一本出。
    倒是有網站可以推薦,http://cs0.wikidot.com/ ,那是金門大學的教授把教材放到網站上分享,連上課錄影都有,http://cs0.wikidot.com/video,這蠻好的,非常有參考性。
    交大也有開放式課程,可以看看,http://ocw.nctu.edu.tw/course_detail.php?bgid=8&gid=0&nid=343#.UqgRKZuVMe0

    工具書是可有可無,有也不錯,但不論是買書或看線上資料,就是要花時間努力練習一下囉~加油~^^

    回覆刪除
  3. 感謝,接下來準備回去念研究所,所以先來看看需要些什麼技巧...

    回覆刪除