From 5a169915e760248f058bcde10bd23c67f40bca5b Mon Sep 17 00:00:00 2001 From: Kevin Keogh Date: Fri, 15 Sep 2017 11:32:24 -0400 Subject: [PATCH] Server now returns the results of the Monte Carlo Price --- models.go | 95 +++++++++++-------------------------------------------- serve.go | 39 ++++++++++++++--------- 2 files changed, 42 insertions(+), 92 deletions(-) diff --git a/models.go b/models.go index 6c94aea..f14e440 100644 --- a/models.go +++ b/models.go @@ -1,48 +1,33 @@ package main import ( - "fmt" "math" "math/rand" "time" ) -// RFC8601Time is a time.Time wrapper -type RFC8601Time struct { - time.Time -} - -func (t RFC8601Time) Sub(u RFC8601Time) time.Duration { - return t.Sub(u) -} - -func (t RFC8601Time) MarshalJSON() ([]byte, error) { - fmt.Println("Here!") - stamp := fmt.Sprintf("\"%s\"", t.Format("2006-01-02")) - return []byte(stamp), nil -} - // Option struct that holds all the details of an option // Option details type Option struct { OptType int64 Strike float64 - ExpiryDate RFC8601Time + ExpiryDate time.Time // Market data - ValueDate RFC8601Time + ValueDate time.Time Spot float64 Rfr float64 Vol float64 Sims int64 // Results - FV float64 - Delta float64 - Vega float64 - Rho float64 - Gamma float64 - Theta float64 + FV float64 + Delta float64 + Vega float64 + Rho float64 + Gamma float64 + Theta float64 + Levels []float64 } // Single simulation of Geometric Brownian Motion @@ -54,23 +39,23 @@ func gbmSimulation(spot float64, rfr float64, vol float64, tte float64, randNum return spot * math.Exp(drift+stoch) } -// RunSimulations is the main function that runs Monte Carlo simulations +// runSimulations is the main function that runs Monte Carlo simulations // for an option. Note that it runs normal Geometric Brownian Motion // to calculate the future spot levels -func RunSimulations(opt *Option) { +func runSimulations(opt *Option) { var i int64 var level float64 - levels := make([]float64, opt.Sims) + opt.Levels = make([]float64, opt.Sims) tte := opt.ExpiryDate.Sub(opt.ValueDate).Hours() / (24 * 365) for i = 0; i < opt.Sims; i++ { randNum := rand.NormFloat64() // Base - levels[i] = gbmSimulation(opt.Spot, opt.Rfr, opt.Vol, tte, randNum) - opt.FV += math.Max((levels[i]-opt.Strike)*float64(opt.OptType), 0) + opt.Levels[i] = gbmSimulation(opt.Spot, opt.Rfr, opt.Vol, tte, randNum) + opt.FV += math.Max((opt.Levels[i]-opt.Strike)*float64(opt.OptType), 0) // Delta level = gbmSimulation(opt.Spot+0.0001, opt.Rfr, opt.Vol, tte, randNum) @@ -104,52 +89,8 @@ func RunSimulations(opt *Option) { opt.Rho = (opt.Rho/float64(opt.Sims)*math.Exp(-(opt.Rfr+0.01)*tte) - opt.FV) } -/* -func main() { - value := time.Date(2016, 12, 30, 0, 0, 0, 0, time.UTC) - expiry := time.Date(2017, 12, 30, 0, 0, 0, 0, time.UTC) - opt := Option{optType: 1, strike: 100, expiryDate: expiry, valueDate: value, spot: 100, rfr: 0.03, vol: 0.25, sims: 1000000} - rand.Seed(time.Now().UTC().UnixNano()) - RunSimulations(&opt) - - fmt.Printf( - ` - Valuation date: %s - - - | BS Analytic | BS Monte Carlo | - --------------------------------------------- - |Type: | %10s | %13s | - |Spot: | %10.2f | %13.2f | - |Expiry: | %s | %s | - |Strike: | %10.2f | %13.2f | - |Risk-free: | %10.2f%% | %13.2f%% | - |Implied Vol:| %10.2f%% | %13.2f%% | - --------------------------------------------- - |Fair value: | %8.4f | %11.4f | - |Delta: | %8.4f | %11.4f | - |Gamma: | %8.4f | %11.4f | - |Vega: | %8.4f | %11.4f | - |Theta: | %8.4f | %11.4f | - |Rho: | %8.4f | %11.4f | - |Simulations:| | %11d | - --------------------------------------------- - -`, - value.Format("2006-01-02"), - "Call", "Call", - opt.Spot, opt.Spot, - expiry.Format("2006-01-02"), expiry.Format("2006-01-02"), - opt.Strike, opt.Strike, - opt.Rfr*100, opt.Rfr*100, - opt.Vol*100, opt.Vol*100, - opt.FV, opt.FV, - opt.Delta, opt.Delta, - opt.Gamma, opt.Gamma, - opt.Vega, opt.Vega, - opt.Theta, opt.Theta, - opt.Rho, opt.Rho, - opt.Sims) - +// PriceMonteCarlo is the exported method to run the simulations and value +// a vanilla option using Monte Carlo methods +func (opt *Option) PriceMonteCarlo() { + runSimulations(opt) } -*/ diff --git a/serve.go b/serve.go index 7bc0763..69aa7d6 100644 --- a/serve.go +++ b/serve.go @@ -6,28 +6,37 @@ import ( "net/http" ) +// index is a function that handles all requests to the main page +// Note that there are two separate returns func index(w http.ResponseWriter, r *http.Request) { - formatRequest(r) - fmt.Fprintf(w, "Hello go!\n") -} + if r.Method == "POST" { -func formatRequest(r *http.Request) { + mcOpt := &Option{} + bsOpt := &Option{} - var opt Option - err := json.NewDecoder(r.Body).Decode(&opt) - if err != nil { - fmt.Printf("Error: %s\n", err) + err := json.NewDecoder(r.Body).Decode(&mcOpt) + if err != nil { + fmt.Printf("Error: %s\n", err) + } + + mcOpt.PriceMonteCarlo() + + options := make(map[string]Option) + options["MonteCarlo"] = *mcOpt + options["BlackScholes"] = *bsOpt + + json.NewEncoder(w).Encode(options) + if err != nil { + fmt.Printf("Error: %v\n", err) + } + + } else if r.Method == "GET" { + fmt.Fprintf(w, "Hello go!") // To be updated } - fmt.Println("Option type:", opt.OptType) - fmt.Println("Strike:", opt.Strike) - fmt.Println("Expiry date:", opt.ExpiryDate.Format("2006-01-02")) - - for k, v := range r.Header { - fmt.Printf("%v: %v\n", k, v) - } } + func main() { http.HandleFunc("/", index) http.ListenAndServe(":8080", nil)