Skip to content

Instantly share code, notes, and snippets.

@rjsamson
Last active January 23, 2016 16:48
Show Gist options
  • Save rjsamson/f40beea2d1659ef67653 to your computer and use it in GitHub Desktop.
Save rjsamson/f40beea2d1659ef67653 to your computer and use it in GitHub Desktop.
package main
import (
"bytes"
"encoding/json"
"fmt"
"io/ioutil"
"math/rand"
"net/http"
"strconv"
"time"
)
const (
// UrlBase string = "http://localhost:8000"
// Venue string = "MUTEX"
// Symbol string = "BREQ"
// Account string = "SPEEDTEST"
// ApiKey string = "AMSMMDFMSMDMD"
UrlBase string = "http://localhost:4000"
// UrlBase string = "https://api.stockfighter.io/ob/api/venues/TESTEX/stocks/FOOBAR"
Venue string = "OBEX"
Symbol string = "NYC"
Account string = "RJSAMSON"
ApiKey string = "I1kaUrr1SN6HK6i870d54awmLlk76d06"
OrdersPerBatch = 6
MaxOldOrders = 20
)
// This is designed to create a benchmark for evaluating a market server's performance.
// To do so, it creates many "typical" users, who throw orders at the server in question.
// It does not remotely verify correctness.
func main() {
fmt.Printf("Hello, world.\n")
start := time.Now()
totals_chan := make(chan int)
go PlayerNew().Run(2000, totals_chan)
go PlayerNew().Run(2000, totals_chan)
go PlayerNew().Run(2000, totals_chan)
totals := 0
totals += <-totals_chan
totals += <-totals_chan
totals += <-totals_chan
duration := time.Since(start)
fmt.Println(totals)
fmt.Println(duration.Seconds())
fmt.Println(float64(totals) / duration.Seconds())
}
// OrderBot
// Clear Prev 6
// Ticker
// Orderbook
// Place 6
type Player struct {
client *http.Client
active_orders []int
headers map[string]string
count int
totalOrders int
}
type OrderResponse struct {
Id int // `json:"id"`
}
func PlayerNew() *Player {
p := &Player{}
tr := &http.Transport{}
p.client = &http.Client{Transport: tr}
p.headers = make(map[string]string)
p.headers["X-Starfighter-Authorization"] = ApiKey
return p
}
func (p *Player) Run(targetOrders int, totals chan int) {
for p.totalOrders < targetOrders {
p.Cycle()
}
totals <- p.totalOrders
}
func (p *Player) Cycle() {
p.CancelOldOrders()
p.Quote()
p.OrderBook()
for i := 0; i < OrdersPerBatch; i++ {
p.Order()
p.totalOrders += 1
}
}
func (p *Player) Quote() {
url := UrlBase + "/ob/api/venues/" + Venue + "/stocks/" + Symbol + "/quote"
resp, err := p.client.Get(url)
if err != nil {
panic(err)
}
_, err = ioutil.ReadAll(resp.Body) // Make keep alive happy
resp.Body.Close()
}
func (p *Player) OrderBook() {
url := UrlBase + "/ob/api/venues/" + Venue + "/stocks/" + Symbol + ""
resp, err := p.client.Get(url)
if err != nil {
panic(err)
}
_, err = ioutil.ReadAll(resp.Body) // Make keep alive happy
resp.Body.Close()
}
func (p *Player) Order() {
price := 5000 + rand.Intn(100)
qty := 20 + rand.Intn(160)
direction := "buy"
if rand.Intn(1) == 0 {
direction = "sell"
}
buf := bytes.NewBuffer(nil)
buf.WriteString("{\"direction\":\"" + direction + "\", \"price\":" + strconv.Itoa(price) + ", \"qty\":" + strconv.Itoa(qty) + ", ")
buf.WriteString("\"orderType\": \"limit\", ")
buf.WriteString("\"account\":\"" + Account + "\", \"venue\":\"" + Venue + "\", \"stock\":\"" + Symbol + "\"}")
url := UrlBase + "/ob/api/venues/" + Venue + "/stocks/" + Symbol + "/orders"
req, err := http.NewRequest("POST", url, buf)
req.Header.Add("X-Starfighter-Authorization", ApiKey)
req.Header.Set("Content-Type", "application/json")
if err != nil {
panic(err)
}
resp, err := p.client.Do(req)
if err != nil {
panic(err)
}
var order OrderResponse
decoder := json.NewDecoder(resp.Body)
decoder.Decode(&order)
if err != nil {
panic(err)
}
_, err = ioutil.ReadAll(resp.Body) // Make keep alive happy
resp.Body.Close()
p.active_orders = append(p.active_orders, order.Id)
}
func (p *Player) Cancel(id int) {
url := UrlBase + "/ob/api/venues/" + Venue + "/stocks/" + Symbol + "/orders/" + strconv.Itoa(id)
req, err := http.NewRequest("DELETE", url, nil)
if err != nil {
panic(err)
}
req.Header.Add("X-Starfighter-Authorization", ApiKey)
resp, err := p.client.Do(req)
if err != nil {
panic(err)
}
_, err = ioutil.ReadAll(resp.Body) // Make keep alive happy
resp.Body.Close()
}
func (p *Player) CancelOldOrders() {
cancel_count := len(p.active_orders) - (MaxOldOrders - OrdersPerBatch)
if cancel_count <= 0 {
return
}
for i := 0; i < cancel_count; i++ {
p.Cancel(p.active_orders[i])
}
p.active_orders = p.active_orders[cancel_count:]
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment