2013-10-01 31 views
0

我試圖在f#中實現一些我已經在c#中使用的方法,以查看語法是多麼簡潔。我使用期權定價公式(黑色76)作爲測試,因爲這對我來說似乎是一個功能性問題。一切似乎都很好,但我無法計算隱含卷,因爲我需要從內部調用同一個類的方法。這是我到目前爲止:調用f中同一類中的方法的問題#

module Module1 
open System 

type Black76 (CallPutFlag, Fwd, Strike, time, rf, vol, ?BlackPrice:float) = 
    let d1 = (Math.Log(Fwd/Strike) + (vol * vol * 0.5) * time)/(vol * Math.Sqrt(time)) 
    let d2 = d1 - vol * Math.Sqrt(time) 
    let n = new MathNet.Numerics.Distributions.Normal() 
    member x.valuation = 
     match CallPutFlag with 
     | "c" | "C" | "Call" | "call" -> Math.Exp(-rf * time) * (Fwd * n.InverseCumulativeDistribution(d1) - Strike * n.InverseCumulativeDistribution(d2)) 
     | "p" | "P" | "Put" | "put" -> Math.Exp(-rf * time) * (Strike * n.InverseCumulativeDistribution(-d2)- Fwd * n.InverseCumulativeDistribution(-d1)) 
     | _ -> failwith "Unrecognized option type" 

member x.delta = 
    match CallPutFlag with 
    | "c" | "C" | "Call" | "call" -> Math.Exp(-rf * time) * n.InverseCumulativeDistribution(d1) 
    | "p" | "P" | "Put" | "put" -> Math.Exp(-rf * time) * n.InverseCumulativeDistribution(-d1) 
    | _ -> failwith "Unrecognized option type" 
member x.gamma = 
    Math.Exp(-rf * time) * (n.Density(d1)/(Fwd * vol * Math.Sqrt(time))) 

member x.vega = 
    Math.Exp(-rf * time) * n.Density(d1) * Fwd * Math.Sqrt(time) 

member x.rho = 
    match CallPutFlag with 
    | "c" | "C" | "Call" | "call" -> time * Strike * Math.Sqrt(-rf * time) * n.InverseCumulativeDistribution(d2) 
    | "p" | "P" | "Put" | "put" -> -time * Strike * Math.Sqrt(-rf * time) * n.InverseCumulativeDistribution(-d2) 
    | _ -> failwith "Unrecognized option type" 

member x.theta = 
    match CallPutFlag with 
    | "c" | "C" | "Call" | "call" -> -(Fwd * vol * n.Density(d1))/(2.0 * Math.Sqrt(time)) - rf * Strike * Math.Sqrt(-rf * time) * n.InverseCumulativeDistribution(d2) 
    | "p" | "P" | "Put" | "put" -> -(Fwd * vol * n.Density(d1))/(2.0 * Math.Sqrt(time)) + rf * Strike * Math.Sqrt(-rf * time) * n.InverseCumulativeDistribution(-d2) 
    | _ -> failwith "Unrecognized option type" 

member x.impliedvol = 
    let vst = Math.Sqrt(2.0*Math.Abs((Math.Log(Fwd/Strike)+rf*time)/time)) 
    let tol = 0.0001 
    let mutable v = vst 
    let mutable sigmadiff = 1.0 
    let mutable k = 1 
    let kmax = 100 
    while (sigmadiff >= tol && k < kmax) do 
     let option = Black76.valuation(CallPutFlag, Fwd, Strike, time, rf, v) 
     let cvega = Black76.vega(CallPutFlag, Fwd, Strike, time, rf, v) 
     let increment = (option - BlackPrice)/cvega 
     v <- v - increment 
     k < - k + 1 
     sigmadiff = Math.Abs(increment) 
    v 

這一切工作除了隱含的卷功能。此外,它似乎沒有比c#版本更簡潔。你能不能讓我知道我可以從內部調用這個方法來表示隱含的vol函數? 。另外,有人知道如何擺脫讓可變的(畢竟,你不應該在fsharp使用這個(我認爲) 感謝

+0

什麼是某事? __ –

回答

5

如果你想讓代碼更簡潔和更實用,那麼我可能會嘗試重構它多一點。我認爲以下這些方面的內容應該適用。

首先,你肯定不想重複對字符串匹配,所以我會定義一個可識別聯合捕捉各種計算的(那麼你可以解析字符串只有一次):

type CallPutFlag = Call | Put 

接下來,我們可以定義紀錄保持公式的結果(我補充剛纔你用的東西,但你可能會想增加更多的在這裏):

type Black76Results = { Vega : float; Valuation : float } 

現在,我認爲這將這個函數與隱含的函數分開是非常有意義的波動。該black76功能可以運行在給定的輸入計算和結果Black76Results記錄的值返回:

let black76 flag fwd strike time rf vol = 
    let d1 = (Math.Log(fwd/strike) + (vol * vol * 0.5) * time)/(vol * Math.Sqrt(time)) 
    let d2 = d1 - vol * Math.Sqrt(time) 
    let n = new MathNet.Numerics.Distributions.Normal() 
    match flag with 
    | Call -> 
     let valuation = Math.Exp(-rf * time) * (fwd * n.InverseCumulativeDistribution(d1) - strike * n.InverseCumulativeDistribution(d2)) 
     let delta = Math.Exp(-rf * time) * n.InverseCumulativeDistribution(d1) 
     let gamma = Math.Exp(-rf * time) * (n.Density(d1)/(fwd * vol * Math.Sqrt(time))) 
     let vega = Math.Exp(-rf * time) * n.Density(d1) * fwd * Math.Sqrt(time) 
     let rho = time * strike * Math.Sqrt(-rf * time) * n.InverseCumulativeDistribution(d2) 
     let theta = -(fwd * vol * n.Density(d1))/(2.0 * Math.Sqrt(time)) - rf * strike * Math.Sqrt(-rf * time) * n.InverseCumulativeDistribution(d2) 
     { Vega = vega; Valuation = valuation }  
    | Put -> 
     failwith "TODO: Similar for Put" 

雖然在CallPut一些共享的代碼,我認爲它看起來很多更具可讀性,當你分開將兩者分成不同的分支(您仍然可以將常見的代碼片段提取到單獨的函數中)。現在

impliedVol是簡單的重複調用black76功能:

let impliedVol flag fwd strike time rf blackPrice = 
    let vst = Math.Sqrt(2.0*Math.Abs((Math.Log(fwd/strike)+rf*time)/time)) 
    let tol = 0.0001 
    let mutable v = vst 
    let mutable sigmadiff = 1.0 
    let mutable k = 1 
    let kmax = 100 
    while (sigmadiff >= tol && k < kmax) do 
     let b = black76 flag fwd strike time rf v 
     let option = b.Valuation 
     let cvega = b.Vega 
     let increment = (option - blackPrice)/cvega 
     v <- v - increment 
     k <- k + 1 
     sigmadiff <- Math.Abs(increment) 
    v 
+0

感謝Tomas!我不需要指定類Black76Results中的參數嗎? – nik

+0

'Black76Results'是一個F#記錄 - 你可以把它看作是C#中的一個匿名類型,除了它被命名爲:-)。它不需要知道輸入參數,因爲它僅用於存儲結果(以便您可以從函數中返回'vega'和'valuation')。如果你出於某種原因需要這些,你可以保留結果中的參數 - 但我認爲你不需要這樣做。 (另一方面,你可以定義另一個記錄來保留所有的輸入,以便你的函數有更少的參數) –

+0

看看這篇文章:http://fsharpforfunandprofit.com/posts/records/ –

1

所以你的問題是線路:

let option = Black76.valuation(CallPutFlag, Fwd, Strike, time, rf, v) 
let cvega = Black76.vega(CallPutFlag, Fwd, Strike, time, rf, v) 

你試圖調用他們的類型Black76,當他們類型Black76的對象的實例成員。您應該使用x.valuation(...)代替,(x因爲這是你叫什麼你this變量)。

F#不有一個固定的關鍵字在C#中被稱爲this 。相反,當你聲明一個成員時,你在點之前給出你想要的任何名字。

member this.method_name = 
member x.another_method = 
+1

另外,他可能需要'member val',因此每個屬性只計算一次。原樣,它們將在每次訪問時計算。 – Daniel

+0

這不會真的有幫助,因爲OP需要使用'v'的不同值來運行計算 - 所以它不僅僅調用當前實例的方法。 –

+1

完全託馬斯,我需要調用該方法並覆蓋其中一個參數,我應該更明確 – nik

相關問題