Added OKCOIN Websocket authenticated account info/spot related trade functions.

This commit is contained in:
Adrian Gallagher
2015-03-31 17:28:51 +11:00
parent 6d487e1bee
commit e7507732a1

View File

@@ -3,12 +3,29 @@ package main
import (
"log"
"net/http"
"net/url"
"time"
"fmt"
"strings"
"strconv"
"github.com/gorilla/websocket"
)
var OKConnWebsocket *websocket.Conn
const (
OKCOIN_WEBSOCKET_USD_REALTRADES = "ok_usd_realtrades"
OKCOIN_WEBSOCKET_CNY_REALTRADES = "ok_cny_realtrades"
OKCOIN_WEBSOCKET_SPOTUSD_TRADE = "ok_spotusd_trade"
OKCOIN_WEBSOCKET_SPOTCNY_TRADE = "ok_spotcny_trade"
OKCOIN_WEBSOCKET_SPOTUSD_CANCEL_ORDER = "ok_spotusd_cancel_order"
OKCOIN_WEBSOCKET_SPOTCNY_CANCEL_ORDER = "ok_spotcny_cancel_order"
OKCOIN_WEBSOCKET_SPOTUSD_USERINFO = "ok_spotusd_userinfo"
OKCOIN_WEBSOCKET_SPOTCNY_USERINFO = "ok_spotcny_userinfo"
OKCOIN_WEBSOCKET_SPOTUSD_ORDER_INFO = "ok_spotusd_order_info"
OKCOIN_WEBSOCKET_SPOTCNY_ORDER_INFO = "ok_spotcny_order_info"
)
type OKCoinWebsocketTicker struct {
Timestamp int64 `json:"timestamp,string"`
Vol string `json:"vol"`
@@ -25,6 +42,43 @@ type OKCoinWebsocketOrderbook struct {
Timestamp int64 `json:"timestamp,string"`
}
type OKCoinWebsocketUserinfo struct {
Info struct {
Funds struct {
Asset struct {
Net float64 `json:"net,string"`
Total float64 `json:"total,string"`
} `json:"asset"`
Free struct {
BTC float64 `json:"btc,string"`
LTC float64 `json:"ltc,string"`
USD float64 `json:"usd,string"`
CNY float64 `json:"cny,string"`
} `json:"free"`
Frozen struct {
BTC float64 `json:"btc,string"`
LTC float64 `json:"ltc,string"`
USD float64 `json:"usd,string"`
CNY float64 `json:"cny,string"`
} `json:"freezed"`
} `json:"funds"`
} `json:"info"`
Result bool `json:"result"`
}
type OKCoinWebsocketOrder struct {
Amount float64 `json:"amount"`
AvgPrice float64 `json:"avg_price"`
DateCreated float64 `json:"create_date"`
TradeAmount float64 `json:"deal_amount"`
OrderID float64 `json:"order_id"`
OrdersID float64 `json:"orders_id"`
Price float64 `json:"price"`
Status int64 `json:"status"`
Symbol string `json:"symbol"`
OrderType string `json:"type"`
}
type OKCoinWebsocketEvent struct {
Event string `json:"event"`
Channel string `json:"channel"`
@@ -35,31 +89,20 @@ type OKCoinWebsocketResponse struct {
Data interface{} `json:"data"`
}
type OKCoinWebsocketParams struct {
Partner string `json:"partner"`
}
type OKCoinWebsocketAuthParams struct {
Partner string `json:"partner"`
SecretKey string `json:"secretkey"`
}
type OKCoinWebsocketEventAuth struct {
Event string `json:"event"`
Channel string `json:"channel"`
Parameters OKCoinWebsocketAuthParams `json:"parameters"`
Parameters map[string]string `json:"parameters"`
}
type OKCoinWebsocketEventAuthRemove struct {
Event string `json:"event"`
Channel string `json:"channel"`
Parameters OKCoinWebsocketParams `json:"parameters"`
Parameters map[string]string `json:"parameters"`
}
var okConn websocket.Conn
func (o *OKCoin) PingHandler(message string) (error) {
err := okConn.WriteControl(websocket.PingMessage, []byte("{'event':'ping'}"), time.Now().Add(time.Second))
err := OKConnWebsocket.WriteControl(websocket.PingMessage, []byte("{'event':'ping'}"), time.Now().Add(time.Second))
if err != nil {
log.Println(err)
@@ -68,64 +111,143 @@ func (o *OKCoin) PingHandler(message string) (error) {
return nil
}
func (o *OKCoin) AddChannel(conn *websocket.Conn, channel string) {
func (o *OKCoin) AddChannel(channel string) {
event := OKCoinWebsocketEvent{"addChannel", channel}
json, err := JSONEncode(event)
if err != nil {
log.Println(err)
return
}
err = conn.WriteMessage(websocket.TextMessage, json)
err = OKConnWebsocket.WriteMessage(websocket.TextMessage, json)
if err != nil {
log.Println(err)
return
}
if o.Verbose {
log.Printf("%s Adding channel: %s\n", o.GetName(), channel)
}
}
func (o* OKCoin) RemoveChannel(conn *websocket.Conn, channel string) {
func (o* OKCoin) RemoveChannel(channel string) {
event := OKCoinWebsocketEvent{"removeChannel", channel}
json, err := JSONEncode(event)
if err != nil {
log.Println(err)
return
}
err = conn.WriteMessage(websocket.TextMessage, json)
err = OKConnWebsocket.WriteMessage(websocket.TextMessage, json)
if err != nil {
log.Println(err)
return
}
if o.Verbose {
log.Printf("%s Removing channel: %s\n", o.GetName(), channel)
}
}
func (o *OKCoin) AddChannelAuthenticated(conn *websocket.Conn, channel string) {
event := OKCoinWebsocketEventAuth{"addChannel", channel, OKCoinWebsocketAuthParams{o.PartnerID, o.SecretKey}}
func (o *OKCoin) WebsocketSpotTrade(symbol, orderType string, price, amount float64) {
values := make(map[string]string)
values["symbol"] = symbol
values["type"] = orderType
values["price"] = strconv.FormatFloat(price, 'f', 8, 64)
values["amount"] = strconv.FormatFloat(amount, 'f', 8, 64)
channel := ""
if o.WebsocketURL == OKCOIN_WEBSOCKET_URL_CHINA {
channel = OKCOIN_WEBSOCKET_SPOTCNY_TRADE
} else {
channel = OKCOIN_WEBSOCKET_SPOTUSD_TRADE
}
o.AddChannelAuthenticated(channel, values)
}
func (o *OKCoin) WebsocketSpotCancel(symbol string, orderID int64) {
values := make(map[string]string)
values["symbol"] = symbol
values["order_id"] = strconv.FormatInt(orderID, 10)
channel := ""
if o.WebsocketURL == OKCOIN_WEBSOCKET_URL_CHINA {
channel = OKCOIN_WEBSOCKET_SPOTCNY_CANCEL_ORDER
} else {
channel = OKCOIN_WEBSOCKET_SPOTUSD_CANCEL_ORDER
}
o.AddChannelAuthenticated(channel, values)
}
func (o *OKCoin) WebsocketSpotOrderInfo(symbol string, orderID int64) {
values := make(map[string]string)
values["symbol"] = symbol
values["order_id"] = strconv.FormatInt(orderID, 10)
channel := ""
if o.WebsocketURL == OKCOIN_WEBSOCKET_URL_CHINA {
channel = OKCOIN_WEBSOCKET_SPOTCNY_ORDER_INFO
} else {
channel = OKCOIN_WEBSOCKET_SPOTUSD_ORDER_INFO
}
o.AddChannelAuthenticated(channel, values)
}
func (o *OKCoin) ConvertToURLValues(values map[string]string) (url.Values) {
urlVals := url.Values{}
for i, x := range values {
urlVals.Set(i, x)
}
return urlVals
}
func (o *OKCoin) WebsocketSign(values map[string]string) (string) {
values["api_key"] = o.PartnerID
urlVals := o.ConvertToURLValues(values)
return strings.ToUpper(HexEncodeToString(GetMD5([]byte(urlVals.Encode() + "&secret_key=" + o.SecretKey))))
}
func (o *OKCoin) AddChannelAuthenticated(channel string, values map[string]string) {
values["sign"] = o.WebsocketSign(values)
event := OKCoinWebsocketEventAuth{"addChannel", channel, values}
json, err := JSONEncode(event)
if err != nil {
log.Println(err)
return
}
err = conn.WriteMessage(websocket.TextMessage, json)
err = OKConnWebsocket.WriteMessage(websocket.TextMessage, json)
if err != nil {
log.Println(err)
return
}
if o.Verbose {
log.Printf("%s Adding authenticated channel: %s\n", o.GetName(), channel)
}
}
func (o *OKCoin) RemoveChannelAuthenticated(conn *websocket.Conn, channel string) {
event := OKCoinWebsocketEventAuthRemove{"removeChannel", channel, OKCoinWebsocketParams{o.PartnerID}}
func (o *OKCoin) RemoveChannelAuthenticated(conn *websocket.Conn, channel string, values map[string]string) {
values["sign"] = o.WebsocketSign(values)
event := OKCoinWebsocketEventAuthRemove{"removeChannel", channel, values}
json, err := JSONEncode(event)
if err != nil {
log.Println(err)
return
}
err = conn.WriteMessage(websocket.TextMessage, json)
err = OKConnWebsocket.WriteMessage(websocket.TextMessage, json)
if err != nil {
log.Println(err)
return
}
if o.Verbose {
log.Printf("%s Removing authenticated channel: %s\n", o.GetName(), channel)
}
}
func (o *OKCoin) WebsocketClient(currencies []string) {
@@ -135,7 +257,9 @@ func (o *OKCoin) WebsocketClient(currencies []string) {
}
var Dialer websocket.Dialer
okConn, resp, err := Dialer.Dial(o.WebsocketURL, http.Header{})
var err error
var resp *http.Response
OKConnWebsocket, resp, err = Dialer.Dial(o.WebsocketURL, http.Header{})
if err != nil {
log.Println(err)
@@ -147,29 +271,40 @@ func (o *OKCoin) WebsocketClient(currencies []string) {
log.Println(resp)
}
okConn.SetPingHandler(o.PingHandler)
currencyChan := ""
if o.WebsocketURL == OKCOIN_WEBSOCKET_URL_CHINA {
currencyChan = "ok_cny_realtrades"
} else {
currencyChan = "ok_usd_realtrades"
OKConnWebsocket.SetPingHandler(o.PingHandler)
if o.Verbose {
log.Printf("%s Collecting order and userinfo.\n")
}
o.AddChannelAuthenticated(okConn, currencyChan)
currencyChan, userinfoChan := "", ""
if o.WebsocketURL == OKCOIN_WEBSOCKET_URL_CHINA {
currencyChan = OKCOIN_WEBSOCKET_CNY_REALTRADES
userinfoChan = OKCOIN_WEBSOCKET_SPOTCNY_USERINFO
o.WebsocketSpotOrderInfo("btc_cny", -1)
o.WebsocketSpotOrderInfo("ltc_cny", -1)
} else {
currencyChan = OKCOIN_WEBSOCKET_USD_REALTRADES
userinfoChan = OKCOIN_WEBSOCKET_SPOTUSD_USERINFO
o.WebsocketSpotOrderInfo("btc_usd", -1)
o.WebsocketSpotOrderInfo("ltc_usd", -1)
}
o.AddChannelAuthenticated(currencyChan, map[string]string{})
o.AddChannelAuthenticated(userinfoChan, map[string]string{})
klineValues := []string{"1min", "3min", "5min", "15min", "30min", "1hour", "2hour", "4hour", "6hour", "12hour", "day", "3day", "week"}
for _, x := range currencies {
o.AddChannel(okConn, fmt.Sprintf("ok_%s_ticker", x))
o.AddChannel(okConn, fmt.Sprintf("ok_%s_depth60", x))
o.AddChannel(okConn, fmt.Sprintf("ok_%s_trades", x))
o.AddChannel(fmt.Sprintf("ok_%s_ticker", x))
o.AddChannel(fmt.Sprintf("ok_%s_depth60", x))
o.AddChannel(fmt.Sprintf("ok_%s_trades_v1", x))
for _, y := range klineValues {
o.AddChannel(okConn, fmt.Sprintf("ok_%s_kline_%s", x, y))
o.AddChannel(fmt.Sprintf("ok_%s_kline_%s", x, y))
}
}
for {
msgType, resp, err := okConn.ReadMessage()
msgType, resp, err := OKConnWebsocket.ReadMessage()
if err != nil {
log.Println(err)
break
@@ -188,13 +323,19 @@ func (o *OKCoin) WebsocketClient(currencies []string) {
z := y.(map[string]interface{})
channel := z["channel"]
data := z["data"]
success := z["success"]
errorcode := z["errorcode"]
channelStr, ok := channel.(string)
if !ok {
log.Println("Unable to convert channel to string")
continue
}
if o.Verbose {
log.Printf("%s Websocket channel message: %s\n", o.GetName(), channelStr)
}
dataJSON, err := JSONEncode(data)
if err != nil {
@@ -219,7 +360,7 @@ func (o *OKCoin) WebsocketClient(currencies []string) {
log.Println(err)
continue
}
case strings.Contains(channelStr, "trades"):
case strings.Contains(channelStr, "trades_v1"):
type TradeResponse struct {
Data [][]string
}
@@ -234,10 +375,56 @@ func (o *OKCoin) WebsocketClient(currencies []string) {
// to-do: convert from string array to trade struct
case strings.Contains(channelStr, "kline"):
// to-do
case strings.Contains(channelStr, "realtrades"):
// to-do
case strings.Contains(channelStr, "spot") && strings.Contains(channelStr, "trade"):
if success == "false" {
log.Printf("Error placing trade, error code: %s", errorcode)
} else {
type TradeOrderResponse struct {
OrderID int64 `json:"order_id,string"`
Result bool `json:"result"`
}
tradeOrder := TradeOrderResponse{}
err := JSONDecode(dataJSON, &tradeOrder)
if err != nil {
log.Println(err)
continue
}
}
case strings.Contains(channelStr, "userinfo"):
if success == "false" {
log.Printf("Error fetching user info, error code: %s", errorcode)
} else {
userinfo := OKCoinWebsocketUserinfo{}
err = JSONDecode(dataJSON, &userinfo)
if err != nil {
log.Println(err)
continue
}
}
case strings.Contains(channelStr, "order_info"):
if success == "false" {
log.Printf("Error fetching order info, error code: %s", errorcode)
} else {
type OrderInfoResponse struct {
Result bool `json:"result"`
Orders []OKCoinWebsocketOrder `json:"orders"`
}
var orders OrderInfoResponse
err := JSONDecode(dataJSON, &orders)
if err != nil {
log.Println(err)
continue
}
}
}
}
}
}
okConn.Close()
OKConnWebsocket.Close()
log.Printf("%s Websocket client disconnected.", o.GetName())
}