Initial commit
This commit is contained in:
14
.gitignore
vendored
Normal file
14
.gitignore
vendored
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
# Binaries for programs and plugins
|
||||||
|
*.exe
|
||||||
|
*.dll
|
||||||
|
*.so
|
||||||
|
*.dylib
|
||||||
|
|
||||||
|
# Test binary, build with `go test -c`
|
||||||
|
*.test
|
||||||
|
|
||||||
|
# Output of the go coverage tool, specifically when used with LiteIDE
|
||||||
|
*.out
|
||||||
|
|
||||||
|
# Project-local glide cache, RE: https://github.com/Masterminds/glide/issues/736
|
||||||
|
.glide/
|
||||||
20
LICENSE
Normal file
20
LICENSE
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
Copyright (c) 2017 Kevin Keogh - kevin.d.keogh@gmail.com
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
a copy of this software and associated documentation files (the
|
||||||
|
"Software"), to deal in the Software without restriction, including
|
||||||
|
without limitation the rights to use, copy, modify, merge, publish,
|
||||||
|
distribute, sublicense, and/or sell copies of the Software, and to
|
||||||
|
permit persons to whom the Software is furnished to do so, subject to
|
||||||
|
the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be
|
||||||
|
included in all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
|
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||||
|
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||||
|
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
|
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
155
models.go
Normal file
155
models.go
Normal file
@@ -0,0 +1,155 @@
|
|||||||
|
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
|
||||||
|
|
||||||
|
// Market data
|
||||||
|
valueDate RFC8601Time
|
||||||
|
spot float64
|
||||||
|
rfr float64
|
||||||
|
vol float64
|
||||||
|
sims int64
|
||||||
|
|
||||||
|
// Results
|
||||||
|
fv float64
|
||||||
|
delta float64
|
||||||
|
vega float64
|
||||||
|
rho float64
|
||||||
|
gamma float64
|
||||||
|
theta float64
|
||||||
|
}
|
||||||
|
|
||||||
|
// Single simulation of Geometric Brownian Motion
|
||||||
|
func gbmSimulation(spot float64, rfr float64, vol float64, tte float64, randNum float64) float64 {
|
||||||
|
var drift, stoch float64
|
||||||
|
|
||||||
|
drift = (rfr - math.Pow(vol, 2)/2) * tte
|
||||||
|
stoch = vol * math.Pow(tte, 0.5) * randNum
|
||||||
|
return spot * math.Exp(drift+stoch)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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) {
|
||||||
|
|
||||||
|
var i int64
|
||||||
|
var level float64
|
||||||
|
|
||||||
|
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)
|
||||||
|
|
||||||
|
// Delta
|
||||||
|
level = gbmSimulation(opt.spot+0.0001, opt.rfr, opt.vol, tte, randNum)
|
||||||
|
opt.delta += math.Max((level-opt.strike)*float64(opt.optType), 0)
|
||||||
|
|
||||||
|
// Gamma -- TODO: Doesn't look right
|
||||||
|
level = gbmSimulation(opt.spot+0.0001, opt.rfr, opt.vol, tte, randNum)
|
||||||
|
level += gbmSimulation(opt.spot-0.0001, opt.rfr, opt.vol, tte, randNum)
|
||||||
|
level -= 2 * gbmSimulation(opt.spot, opt.rfr, opt.vol, tte, randNum)
|
||||||
|
opt.gamma += math.Max((level-opt.strike)*float64(opt.optType), 0)
|
||||||
|
|
||||||
|
// Vega
|
||||||
|
level = gbmSimulation(opt.spot, opt.rfr, opt.vol+0.0001, tte, randNum)
|
||||||
|
opt.vega += math.Max((level-opt.strike)*float64(opt.optType), 0)
|
||||||
|
|
||||||
|
// Theta
|
||||||
|
level = gbmSimulation(opt.spot, opt.rfr, opt.vol, tte-1./365, randNum)
|
||||||
|
opt.theta += math.Max((level-opt.strike)*float64(opt.optType), 0)
|
||||||
|
|
||||||
|
// Rho -- TODO: Doesn't look right
|
||||||
|
level = gbmSimulation(opt.spot, opt.rfr+0.0001, opt.vol, tte, randNum)
|
||||||
|
opt.rho += math.Max((level-opt.strike)*float64(opt.optType), 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
df := math.Exp(-opt.rfr * tte)
|
||||||
|
opt.fv = opt.fv / float64(opt.sims) * df
|
||||||
|
opt.delta = (opt.delta/float64(opt.sims)*df - opt.fv) / 0.0001
|
||||||
|
opt.gamma = (opt.gamma/float64(opt.sims)*df - opt.fv) / 10000
|
||||||
|
opt.vega = (opt.vega/float64(opt.sims)*df - opt.fv) / 0.01
|
||||||
|
opt.theta = (opt.theta/float64(opt.sims)*math.Exp(-opt.rfr*(tte-1./365)) - opt.fv) / -(1. / 365)
|
||||||
|
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)
|
||||||
|
|
||||||
|
}
|
||||||
|
*/
|
||||||
34
serve.go
Normal file
34
serve.go
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
func index(w http.ResponseWriter, r *http.Request) {
|
||||||
|
formatRequest(r)
|
||||||
|
fmt.Fprintf(w, "Hello go!\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
func formatRequest(r *http.Request) {
|
||||||
|
|
||||||
|
var opt Option
|
||||||
|
err := json.NewDecoder(r.Body).Decode(&opt)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("Error: %s\n", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user