From 1b0ccac18c1e2e1c5e93384640d00e4fc42c837f Mon Sep 17 00:00:00 2001 From: Adrian Gallagher Date: Thu, 26 Mar 2015 19:10:52 +1100 Subject: [PATCH] Added Websocket support for Coinbase. --- coinbase.go | 5 ++ coinbasewebsocket.go | 170 +++++++++++++++++++++++++++++++++++++++++++ config_example.json | 2 +- 3 files changed, 176 insertions(+), 1 deletion(-) create mode 100644 coinbasewebsocket.go diff --git a/coinbase.go b/coinbase.go index 4052751c450..672c0594c59 100644 --- a/coinbase.go +++ b/coinbase.go @@ -116,9 +116,14 @@ func (c *Coinbase) GetFee(maker bool) (float64) { func (c *Coinbase) Run() { if c.Verbose { + log.Printf("%s Websocket: %s.\n", c.GetName(), IsEnabled(c.Websocket)) log.Printf("%s polling delay: %ds.\n", c.GetName(), c.PollingDelay) } + if c.Websocket { + go c.WebsocketClient() + } + for c.Enabled { go func() { CoinbaseStats := c.GetStats("BTC-USD") diff --git a/coinbasewebsocket.go b/coinbasewebsocket.go new file mode 100644 index 00000000000..f8cedf38389 --- /dev/null +++ b/coinbasewebsocket.go @@ -0,0 +1,170 @@ +package main + +import ( + "log" + "net/http" + "github.com/gorilla/websocket" +) + +const ( + COINBASE_WEBSOCKET_URL = "wss://ws-feed.exchange.coinbase.com" +) + +type CoinbaseWebsocketSubscribe struct { + Type string `json:"type"` + ProductID string `json:"product_id"` +} + +type CoinbaseWebsocketReceived struct { + Type string `json:"type"` + Time string `json:"time"` + Sequence int `json:"sequence"` + OrderID string `json:"order_id"` + Size float64 `json:"size,string"` + Price float64 `json:"price,string"` + Side string `json:"side"` +} + +type CoinbaseWebsocketOpen struct { + Type string `json:"type"` + Time string `json:"time"` + Sequence int `json:"sequence"` + OrderID string `json:"order_id"` + Price float64 `json:"price,string"` + RemainingSize float64 `json:"remaining_size,string"` + Side string `json:"side"` +} + +type CoinbaseWebsocketDone struct { + Type string `json:"type"` + Time string `json:"time"` + Sequence int `json:"sequence"` + Price float64 `json:"price,string"` + OrderID string `json:"order_id"` + Reason string `json:"reason"` + Side string `json:"side"` + RemainingSize float64 `json:"remaining_size,string"` +} + +type CoinbaseWebsocketMatch struct { + Type string `json:"type"` + TradeID int `json:"trade_id"` + Sequence int `json:"sequence"` + MakerOrderID string `json:"maker_order_id"` + TakerOrderID string `json:"taker_order_id"` + Time string `json:"time"` + Size float64 `json:"size,string"` + Price float64 `json:"price,string"` + Side string `json:"side"` +} + +type CoinbaseWebsocketChange struct { + Type string `json:"type"` + Time string `json:"time"` + Sequence int `json:"sequence"` + OrderID string `json:"order_id"` + NewSize float64 `json:"new_size,string"` + OldSize float64 `json:"old_size,string"` + Price float64 `json:"price,string"` + Side string `json:"side"` +} + +func (c *Coinbase) WebsocketClient() { + var Dialer websocket.Dialer + conn, resp, err := Dialer.Dial(COINBASE_WEBSOCKET_URL, http.Header{}) + + if err != nil { + log.Println(err) + return + } + + if c.Verbose { + log.Printf("%s Connected to Websocket.", c.GetName()) + log.Println(resp) + } + + subscribe := CoinbaseWebsocketSubscribe{"subscribe", "BTC-USD"} + json, err := JSONEncode(subscribe) + if err != nil { + log.Println(err) + conn.Close() + return + } + + err = conn.WriteMessage(websocket.TextMessage, json) + + if err != nil { + log.Println(err) + conn.Close() + return + } + + if c.Verbose { + log.Printf("%s Subscribed to product messages.", c.GetName()) + } + + for { + msgType, resp, err := conn.ReadMessage() + if err != nil { + log.Println(err) + break + } + + switch msgType { + case websocket.TextMessage: + type MsgType struct { + Type string `json:"type"` + } + + msgType := MsgType{} + err := JSONDecode(resp, &msgType) + if err != nil { + log.Println(err) + continue + } + + switch msgType.Type { + case "error": + log.Println(string(resp)) + break + case "received": + received := CoinbaseWebsocketReceived{} + err := JSONDecode(resp, &received) + if err != nil { + log.Println(err) + continue + } + case "open": + open := CoinbaseWebsocketOpen{} + err := JSONDecode(resp, &open) + if err != nil { + log.Println(err) + continue + } + case "done": + done := CoinbaseWebsocketDone{} + err := JSONDecode(resp, &done) + if err != nil { + log.Println(err) + continue + } + case "match": + match := CoinbaseWebsocketMatch{} + err := JSONDecode(resp, &match) + if err != nil { + log.Println(err) + continue + } + case "change": + change := CoinbaseWebsocketMatch{} + err := JSONDecode(resp, &change) + if err != nil { + log.Println(err) + continue + } + } + } + } + conn.Close() + log.Printf("%s Websocket client disconnected.", c.GetName()) +} \ No newline at end of file diff --git a/config_example.json b/config_example.json index dc7492593de..cf99e9196ff 100644 --- a/config_example.json +++ b/config_example.json @@ -75,7 +75,7 @@ "BaseCurrencies": "USD", "Enabled": true, "Verbose": false, - "Websocket": false, + "Websocket": true, "PollingDelay": 10 }, {