mirror of
https://github.com/d0zingcat/gocryptotrader.git
synced 2026-06-01 15:10:44 +00:00
Package exchanges
This commit is contained in:
391
exchanges/okcoin/okcoin_types.go
Normal file
391
exchanges/okcoin/okcoin_types.go
Normal file
@@ -0,0 +1,391 @@
|
||||
package okcoin
|
||||
|
||||
type OKCoinTicker struct {
|
||||
Buy float64 `json:",string"`
|
||||
High float64 `json:",string"`
|
||||
Last float64 `json:",string"`
|
||||
Low float64 `json:",string"`
|
||||
Sell float64 `json:",string"`
|
||||
Vol float64 `json:",string"`
|
||||
}
|
||||
|
||||
type OKCoinTickerResponse struct {
|
||||
Date string
|
||||
Ticker OKCoinTicker
|
||||
}
|
||||
type OKCoinFuturesTicker struct {
|
||||
Last float64
|
||||
Buy float64
|
||||
Sell float64
|
||||
High float64
|
||||
Low float64
|
||||
Vol float64
|
||||
Contract_ID int64
|
||||
Unit_Amount float64
|
||||
}
|
||||
|
||||
type OKCoinOrderbook struct {
|
||||
Asks [][]float64 `json:"asks"`
|
||||
Bids [][]float64 `json:"bids"`
|
||||
}
|
||||
|
||||
type OKCoinFuturesTickerResponse struct {
|
||||
Date string
|
||||
Ticker OKCoinFuturesTicker
|
||||
}
|
||||
|
||||
type OKCoinBorrowInfo struct {
|
||||
BorrowBTC float64 `json:"borrow_btc"`
|
||||
BorrowLTC float64 `json:"borrow_ltc"`
|
||||
BorrowCNY float64 `json:"borrow_cny"`
|
||||
CanBorrow float64 `json:"can_borrow"`
|
||||
InterestBTC float64 `json:"interest_btc"`
|
||||
InterestLTC float64 `json:"interest_ltc"`
|
||||
Result bool `json:"result"`
|
||||
DailyInterestBTC float64 `json:"today_interest_btc"`
|
||||
DailyInterestLTC float64 `json:"today_interest_ltc"`
|
||||
DailyInterestCNY float64 `json:"today_interest_cny"`
|
||||
}
|
||||
|
||||
type OKCoinBorrowOrder struct {
|
||||
Amount float64 `json:"amount"`
|
||||
BorrowDate int64 `json:"borrow_date"`
|
||||
BorrowID int64 `json:"borrow_id"`
|
||||
Days int64 `json:"days"`
|
||||
TradeAmount float64 `json:"deal_amount"`
|
||||
Rate float64 `json:"rate"`
|
||||
Status int64 `json:"status"`
|
||||
Symbol string `json:"symbol"`
|
||||
}
|
||||
|
||||
type OKCoinRecord struct {
|
||||
Address string `json:"addr"`
|
||||
Account int64 `json:"account,string"`
|
||||
Amount float64 `json:"amount"`
|
||||
Bank string `json:"bank"`
|
||||
BenificiaryAddress string `json:"benificiary_addr"`
|
||||
TransactionValue float64 `json:"transaction_value"`
|
||||
Fee float64 `json:"fee"`
|
||||
Date float64 `json:"date"`
|
||||
}
|
||||
|
||||
type OKCoinAccountRecords struct {
|
||||
Records []OKCoinRecord `json:"records"`
|
||||
Symbol string `json:"symbol"`
|
||||
}
|
||||
|
||||
type OKCoinFuturesOrder struct {
|
||||
Amount float64 `json:"amount"`
|
||||
ContractName string `json:"contract_name"`
|
||||
DateCreated float64 `json:"create_date"`
|
||||
TradeAmount float64 `json:"deal_amount"`
|
||||
Fee float64 `json:"fee"`
|
||||
LeverageRate float64 `json:"lever_rate"`
|
||||
OrderID int64 `json:"order_id"`
|
||||
Price float64 `json:"price"`
|
||||
AvgPrice float64 `json:"avg_price"`
|
||||
Status float64 `json:"status"`
|
||||
Symbol string `json:"symbol"`
|
||||
Type int64 `json:"type"`
|
||||
UnitAmount int64 `json:"unit_amount"`
|
||||
}
|
||||
|
||||
type OKCoinFuturesHoldAmount struct {
|
||||
Amount float64 `json:"amount"`
|
||||
ContractName string `json:"contract_name"`
|
||||
}
|
||||
|
||||
type OKCoinFuturesExplosive struct {
|
||||
Amount float64 `json:"amount,string"`
|
||||
DateCreated string `json:"create_date"`
|
||||
Loss float64 `json:"loss,string"`
|
||||
Type int64 `json:"type"`
|
||||
}
|
||||
|
||||
type OKCoinTrades struct {
|
||||
Amount float64 `json:"amount,string"`
|
||||
Date int64 `json:"date`
|
||||
DateMS int64 `json:"date_ms"`
|
||||
Price float64 `json:"price,string"`
|
||||
TradeID int64 `json:"tid"`
|
||||
Type string `json:"type"`
|
||||
}
|
||||
|
||||
type OKCoinFuturesTrades struct {
|
||||
Amount float64 `json:"amount"`
|
||||
Date int64 `json:"date"`
|
||||
DateMS int64 `json:"date_ms"`
|
||||
Price float64 `json:"price"`
|
||||
TradeID int64 `json:"tid"`
|
||||
Type string `json:"type"`
|
||||
}
|
||||
|
||||
type OKCoinUserInfo struct {
|
||||
Info struct {
|
||||
Funds struct {
|
||||
Asset struct {
|
||||
Net float64 `json:"net,string"`
|
||||
Total float64 `json:"total,string"`
|
||||
} `json:"asset"`
|
||||
Borrow struct {
|
||||
BTC float64 `json:"btc,string"`
|
||||
LTC float64 `json:"ltc,string"`
|
||||
USD float64 `json:"usd,string"`
|
||||
} `json:"borrow"`
|
||||
Free struct {
|
||||
BTC float64 `json:"btc,string"`
|
||||
LTC float64 `json:"ltc,string"`
|
||||
USD float64 `json:"usd,string"`
|
||||
} `json:"free"`
|
||||
Freezed struct {
|
||||
BTC float64 `json:"btc,string"`
|
||||
LTC float64 `json:"ltc,string"`
|
||||
USD float64 `json:"usd,string"`
|
||||
} `json:"freezed"`
|
||||
UnionFund struct {
|
||||
BTC float64 `json:"btc,string"`
|
||||
LTC float64 `json:"ltc,string"`
|
||||
} `json:"union_fund"`
|
||||
} `json:"funds"`
|
||||
} `json:"info"`
|
||||
Result bool `json:"result"`
|
||||
}
|
||||
|
||||
type OKCoinBatchTrade struct {
|
||||
OrderInfo []struct {
|
||||
OrderID int64 `json:"order_id"`
|
||||
ErrorCode int64 `json:"error_code"`
|
||||
} `json:"order_info"`
|
||||
Result bool `json:"result"`
|
||||
}
|
||||
|
||||
type OKCoinCancelOrderResponse struct {
|
||||
Success string
|
||||
Error string
|
||||
}
|
||||
|
||||
type OKCoinOrderInfo struct {
|
||||
Amount float64 `json:"amount"`
|
||||
AvgPrice float64 `json:"avg_price"`
|
||||
Created int64 `json:"create_date"`
|
||||
DealAmount float64 `json:"deal_amount"`
|
||||
OrderID int64 `json:"order_id"`
|
||||
OrdersID int64 `json:"orders_id"`
|
||||
Price float64 `json:"price"`
|
||||
Status int `json:"status"`
|
||||
Symbol string `json:"symbol"`
|
||||
Type string `json:"type"`
|
||||
}
|
||||
|
||||
type OKCoinOrderHistory struct {
|
||||
CurrentPage int `json:"current_page"`
|
||||
Orders []OKCoinOrderInfo `json:"orders"`
|
||||
PageLength int `json:"page_length"`
|
||||
Result bool `json:"result"`
|
||||
Total int `json:"total"`
|
||||
}
|
||||
|
||||
type OKCoinWithdrawalResponse struct {
|
||||
WithdrawID int `json:"withdraw_id"`
|
||||
Result bool `json:"result"`
|
||||
}
|
||||
|
||||
type OKCoinWithdrawInfo struct {
|
||||
Address string `json:"address"`
|
||||
Amount float64 `json:"amount"`
|
||||
Created int64 `json:"created_date"`
|
||||
ChargeFee float64 `json:"chargefee"`
|
||||
Status int `json:"status"`
|
||||
WithdrawID int64 `json:"withdraw_id"`
|
||||
}
|
||||
|
||||
type OKCoinOrderFeeInfo struct {
|
||||
Fee float64 `json:"fee,string"`
|
||||
OrderID int64 `json:"order_id"`
|
||||
Type string `json:"type"`
|
||||
}
|
||||
|
||||
type OKCoinLendDepth struct {
|
||||
Amount float64 `json:"amount"`
|
||||
Days string `json:"days"`
|
||||
Num int64 `json:"num"`
|
||||
Rate float64 `json:"rate,string"`
|
||||
}
|
||||
|
||||
type OKCoinBorrowResponse struct {
|
||||
Result bool `json:"result"`
|
||||
BorrowID int `json:"borrow_id"`
|
||||
}
|
||||
|
||||
type OKCoinWebsocketFutureIndex struct {
|
||||
FutureIndex float64 `json:"futureIndex"`
|
||||
Timestamp int64 `json:"timestamp,string"`
|
||||
}
|
||||
|
||||
type OKCoinWebsocketTicker struct {
|
||||
Timestamp float64
|
||||
Vol string
|
||||
Buy float64
|
||||
High float64
|
||||
Last float64
|
||||
Low float64
|
||||
Sell float64
|
||||
}
|
||||
|
||||
type OKCoinWebsocketFuturesTicker struct {
|
||||
Buy float64 `json:"buy"`
|
||||
ContractID string `json:"contractId"`
|
||||
High float64 `json:"high"`
|
||||
HoldAmount float64 `json:"hold_amount"`
|
||||
Last float64 `json:"last,string"`
|
||||
Low float64 `json:"low"`
|
||||
Sell float64 `json:"sell"`
|
||||
UnitAmount float64 `json:"unitAmount"`
|
||||
Volume float64 `json:"vol,string"`
|
||||
}
|
||||
|
||||
type OKCoinWebsocketOrderbook struct {
|
||||
Asks [][]float64 `json:"asks"`
|
||||
Bids [][]float64 `json:"bids"`
|
||||
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 OKCoinWebsocketFuturesContract struct {
|
||||
Available float64 `json:"available"`
|
||||
Balance float64 `json:"balance"`
|
||||
Bond float64 `json:"bond"`
|
||||
ContractID float64 `json:"contract_id"`
|
||||
ContractType string `json:"contract_type"`
|
||||
Frozen float64 `json:"freeze"`
|
||||
Profit float64 `json:"profit"`
|
||||
Loss float64 `json:"unprofit"`
|
||||
}
|
||||
|
||||
type OKCoinWebsocketFuturesUserInfo struct {
|
||||
Info struct {
|
||||
BTC struct {
|
||||
Balance float64 `json:"balance"`
|
||||
Contracts []OKCoinWebsocketFuturesContract `json:"contracts"`
|
||||
Rights float64 `json:"rights"`
|
||||
} `json:"btc"`
|
||||
LTC struct {
|
||||
Balance float64 `json:"balance"`
|
||||
Contracts []OKCoinWebsocketFuturesContract `json:"contracts"`
|
||||
Rights float64 `json:"rights"`
|
||||
} `json:"ltc"`
|
||||
} `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 OKCoinWebsocketFuturesOrder struct {
|
||||
Amount float64 `json:"amount"`
|
||||
ContractName string `json:"contract_name"`
|
||||
DateCreated float64 `json:"createdDate"`
|
||||
TradeAmount float64 `json:"deal_amount"`
|
||||
Fee float64 `json:"fee"`
|
||||
LeverageAmount int `json:"lever_rate"`
|
||||
OrderID float64 `json:"order_id"`
|
||||
Price float64 `json:"price"`
|
||||
AvgPrice float64 `json:"avg_price"`
|
||||
Status int `json:"status"`
|
||||
Symbol string `json:"symbol"`
|
||||
TradeType int `json:"type"`
|
||||
UnitAmount float64 `json:"unit_amount"`
|
||||
}
|
||||
|
||||
type OKCoinWebsocketRealtrades struct {
|
||||
AveragePrice float64 `json:"averagePrice,string"`
|
||||
CompletedTradeAmount float64 `json:"completedTradeAmount,string"`
|
||||
DateCreated float64 `json:"createdDate"`
|
||||
ID float64 `json:"id"`
|
||||
OrderID float64 `json:"orderId"`
|
||||
SigTradeAmount float64 `json:"sigTradeAmount,string"`
|
||||
SigTradePrice float64 `json:"sigTradePrice,string"`
|
||||
Status int64 `json:"status"`
|
||||
Symbol string `json:"symbol"`
|
||||
TradeAmount float64 `json:"tradeAmount,string"`
|
||||
TradePrice float64 `json:"buy,string"`
|
||||
TradeType string `json:"tradeType"`
|
||||
TradeUnitPrice float64 `json:"tradeUnitPrice,string"`
|
||||
UnTrade float64 `json:"unTrade,string"`
|
||||
}
|
||||
|
||||
type OKCoinWebsocketFuturesRealtrades struct {
|
||||
Amount float64 `json:"amount,string"`
|
||||
ContractID float64 `json:"contract_id,string"`
|
||||
ContractName string `json:"contract_name"`
|
||||
ContractType string `json:"contract_type"`
|
||||
TradeAmount float64 `json:"deal_amount,string"`
|
||||
Fee float64 `json:"fee,string"`
|
||||
OrderID float64 `json:"orderid"`
|
||||
Price float64 `json:"price,string"`
|
||||
AvgPrice float64 `json:"price_avg,string"`
|
||||
Status int `json:"status,string"`
|
||||
TradeType int `json:"type,string"`
|
||||
UnitAmount float64 `json:"unit_amount,string"`
|
||||
LeverageAmount int `json:"lever_rate,string"`
|
||||
}
|
||||
|
||||
type OKCoinWebsocketEvent struct {
|
||||
Event string `json:"event"`
|
||||
Channel string `json:"channel"`
|
||||
}
|
||||
|
||||
type OKCoinWebsocketResponse struct {
|
||||
Channel string `json:"channel"`
|
||||
Data interface{} `json:"data"`
|
||||
}
|
||||
|
||||
type OKCoinWebsocketEventAuth struct {
|
||||
Event string `json:"event"`
|
||||
Channel string `json:"channel"`
|
||||
Parameters map[string]string `json:"parameters"`
|
||||
}
|
||||
|
||||
type OKCoinWebsocketEventAuthRemove struct {
|
||||
Event string `json:"event"`
|
||||
Channel string `json:"channel"`
|
||||
Parameters map[string]string `json:"parameters"`
|
||||
}
|
||||
|
||||
type OKCoinWebsocketTradeOrderResponse struct {
|
||||
OrderID int64 `json:"order_id,string"`
|
||||
Result bool `json:"result,string"`
|
||||
}
|
||||
102
exchanges/okcoin/okcoin_wrapper.go
Normal file
102
exchanges/okcoin/okcoin_wrapper.go
Normal file
@@ -0,0 +1,102 @@
|
||||
package okcoin
|
||||
|
||||
import (
|
||||
"log"
|
||||
"time"
|
||||
|
||||
"github.com/thrasher-/gocryptotrader/common"
|
||||
"github.com/thrasher-/gocryptotrader/exchanges"
|
||||
"github.com/thrasher-/gocryptotrader/exchanges/ticker"
|
||||
)
|
||||
|
||||
func (o *OKCoin) Start() {
|
||||
go o.Run()
|
||||
}
|
||||
|
||||
func (o *OKCoin) Run() {
|
||||
if o.Verbose {
|
||||
log.Printf("%s Websocket: %s. (url: %s).\n", o.GetName(), common.IsEnabled(o.Websocket), o.WebsocketURL)
|
||||
log.Printf("%s polling delay: %ds.\n", o.GetName(), o.RESTPollingDelay)
|
||||
log.Printf("%s %d currencies enabled: %s.\n", o.GetName(), len(o.EnabledPairs), o.EnabledPairs)
|
||||
}
|
||||
|
||||
if o.Websocket {
|
||||
go o.WebsocketClient()
|
||||
}
|
||||
|
||||
for o.Enabled {
|
||||
for _, x := range o.EnabledPairs {
|
||||
currency := common.StringToLower(x[0:3] + "_" + x[3:])
|
||||
if o.APIUrl == OKCOIN_API_URL {
|
||||
for _, y := range o.FuturesValues {
|
||||
futuresValue := y
|
||||
go func() {
|
||||
ticker, err := o.GetFuturesTicker(currency, futuresValue)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
log.Printf("OKCoin Intl Futures %s (%s): Last %f High %f Low %f Volume %f\n", currency, futuresValue, ticker.Last, ticker.High, ticker.Low, ticker.Vol)
|
||||
//AddExchangeInfo(o.GetName(), common.StringToUpper(currency[0:3]), common.StringToUpper(currency[4:]), ticker.Last, ticker.Vol)
|
||||
}()
|
||||
}
|
||||
go func() {
|
||||
ticker, err := o.GetTickerPrice(currency)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
log.Printf("OKCoin Intl Spot %s: Last %f High %f Low %f Volume %f\n", currency, ticker.Last, ticker.High, ticker.Low, ticker.Volume)
|
||||
//AddExchangeInfo(o.GetName(), common.StringToUpper(currency[0:3]), common.StringToUpper(currency[4:]), ticker.Last, ticker.Volume)
|
||||
}()
|
||||
} else {
|
||||
go func() {
|
||||
ticker, err := o.GetTickerPrice(currency)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
//tickerLastUSD, _ := ConvertCurrency(ticker.Last, "CNY", "USD")
|
||||
//tickerHighUSD, _ := ConvertCurrency(ticker.High, "CNY", "USD")
|
||||
//tickerLowUSD, _ := ConvertCurrency(ticker.Low, "CNY", "USD")
|
||||
//log.Printf("OKCoin China %s: Last %f (%f) High %f (%f) Low %f (%f) Volume %f\n", currency, tickerLastUSD, ticker.Last, tickerHighUSD, ticker.High, tickerLowUSD, ticker.Low, ticker.Volume)
|
||||
log.Printf("OKCoin China %s: Last %f High %f Low %f Volume %f\n", currency, ticker.Last, ticker.High, ticker.Low, ticker.Volume)
|
||||
//AddExchangeInfo(o.GetName(), common.StringToUpper(currency[0:3]), common.StringToUpper(currency[4:]), ticker.Last, ticker.Volume)
|
||||
//AddExchangeInfo(o.GetName(), common.StringToUpper(currency[0:3]), "USD", tickerLastUSD, ticker.Volume)
|
||||
}()
|
||||
}
|
||||
}
|
||||
time.Sleep(time.Second * o.RESTPollingDelay)
|
||||
}
|
||||
}
|
||||
|
||||
func (o *OKCoin) GetTickerPrice(currency string) (ticker.TickerPrice, error) {
|
||||
tickerNew, err := ticker.GetTicker(o.GetName(), currency[0:3], currency[3:])
|
||||
if err == nil {
|
||||
return tickerNew, nil
|
||||
}
|
||||
|
||||
var tickerPrice ticker.TickerPrice
|
||||
tick, err := o.GetTicker(currency)
|
||||
if err != nil {
|
||||
return tickerPrice, err
|
||||
}
|
||||
tickerPrice.Ask = tick.Sell
|
||||
tickerPrice.Bid = tick.Buy
|
||||
tickerPrice.FirstCurrency = common.StringToUpper(currency[0:3])
|
||||
tickerPrice.SecondCurrency = common.StringToUpper(currency[4:])
|
||||
tickerPrice.Low = tick.Low
|
||||
tickerPrice.Last = tick.Last
|
||||
tickerPrice.Volume = tick.Vol
|
||||
tickerPrice.High = tick.High
|
||||
ticker.ProcessTicker(o.GetName(), tickerPrice.FirstCurrency, tickerPrice.SecondCurrency, tickerPrice)
|
||||
return tickerPrice, nil
|
||||
}
|
||||
|
||||
//TODO support for retrieving holdings from OKCOIN
|
||||
//GetExchangeAccountInfo : Retrieves balances for all enabled currencies for the OKCoin exchange
|
||||
func (e *OKCoin) GetExchangeAccountInfo() (exchange.ExchangeAccountInfo, error) {
|
||||
var response exchange.ExchangeAccountInfo
|
||||
response.ExchangeName = e.GetName()
|
||||
return response, nil
|
||||
}
|
||||
988
exchanges/okcoin/okcoinhttp.go
Normal file
988
exchanges/okcoin/okcoinhttp.go
Normal file
@@ -0,0 +1,988 @@
|
||||
package okcoin
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"log"
|
||||
"net/url"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/gorilla/websocket"
|
||||
"github.com/thrasher-/gocryptotrader/common"
|
||||
"github.com/thrasher-/gocryptotrader/config"
|
||||
"github.com/thrasher-/gocryptotrader/exchanges"
|
||||
)
|
||||
|
||||
const (
|
||||
OKCOIN_API_URL = "https://www.okcoin.com/api/v1/"
|
||||
OKCOIN_API_URL_CHINA = "https://www.okcoin.cn/api/v1/"
|
||||
OKCOIN_API_VERSION = "1"
|
||||
OKCOIN_WEBSOCKET_URL = "wss://real.okcoin.com:10440/websocket/okcoinapi"
|
||||
OKCOIN_WEBSOCKET_URL_CHINA = "wss://real.okcoin.cn:10440/websocket/okcoinapi"
|
||||
OKCOIN_TICKER = "ticker.do"
|
||||
OKCOIN_DEPTH = "depth.do"
|
||||
OKCOIN_TRADES = "trades.do"
|
||||
OKCOIN_KLINE = "kline.do"
|
||||
OKCOIN_USERINFO = "userinfo.do"
|
||||
OKCOIN_TRADE = "trade.do"
|
||||
OKCOIN_TRADE_HISTORY = "trade_history.do"
|
||||
OKCOIN_TRADE_BATCH = "batch_trade.do"
|
||||
OKCOIN_ORDER_CANCEL = "cancel_order.do"
|
||||
OKCOIN_ORDER_INFO = "order_info.do"
|
||||
OKCOIN_ORDERS_INFO = "orders_info.do"
|
||||
OKCOIN_ORDER_HISTORY = "order_history.do"
|
||||
OKCOIN_WITHDRAW = "withdraw.do"
|
||||
OKCOIN_WITHDRAW_CANCEL = "cancel_withdraw.do"
|
||||
OKCOIN_WITHDRAW_INFO = "withdraw_info.do"
|
||||
OKCOIN_ORDER_FEE = "order_fee.do"
|
||||
OKCOIN_LEND_DEPTH = "lend_depth.do"
|
||||
OKCOIN_BORROWS_INFO = "borrows_info.do"
|
||||
OKCOIN_BORROW_MONEY = "borrow_money.do"
|
||||
OKCOIN_BORROW_CANCEL = "cancel_borrow.do"
|
||||
OKCOIN_BORROW_ORDER_INFO = "borrow_order_info.do"
|
||||
OKCOIN_REPAYMENT = "repayment.do"
|
||||
OKCOIN_UNREPAYMENTS_INFO = "unrepayments_info.do"
|
||||
OKCOIN_ACCOUNT_RECORDS = "account_records.do"
|
||||
OKCOIN_FUTURES_TICKER = "future_ticker.do"
|
||||
OKCOIN_FUTURES_DEPTH = "future_depth.do"
|
||||
OKCOIN_FUTURES_TRADES = "future_trades.do"
|
||||
OKCOIN_FUTURES_INDEX = "future_index.do"
|
||||
OKCOIN_EXCHANGE_RATE = "exchange_rate.do"
|
||||
OKCOIN_FUTURES_ESTIMATED_PRICE = "future_estimated_price.do"
|
||||
OKCOIN_FUTURES_KLINE = "future_kline.do"
|
||||
OKCOIN_FUTURES_HOLD_AMOUNT = "future_hold_amount.do"
|
||||
OKCOIN_FUTURES_USERINFO = "future_userinfo.do"
|
||||
OKCOIN_FUTURES_POSITION = "future_position.do"
|
||||
OKCOIN_FUTURES_TRADE = "future_trade.do"
|
||||
OKCOIN_FUTURES_TRADE_HISTORY = "future_trades_history.do"
|
||||
OKCOIN_FUTURES_TRADE_BATCH = "future_batch_trade.do"
|
||||
OKCOIN_FUTURES_CANCEL = "future_cancel.do"
|
||||
OKCOIN_FUTURES_ORDER_INFO = "future_order_info.do"
|
||||
OKCOIN_FUTURES_ORDERS_INFO = "future_orders_info.do"
|
||||
OKCOIN_FUTURES_USERINFO_4FIX = "future_userinfo_4fix.do"
|
||||
OKCOIN_FUTURES_POSITION_4FIX = "future_position_4fix.do"
|
||||
OKCOIN_FUTURES_EXPLOSIVE = "future_explosive.do"
|
||||
OKCOIN_FUTURES_DEVOLVE = "future_devolve.do"
|
||||
)
|
||||
|
||||
var (
|
||||
okcoinDefaultsSet = false
|
||||
)
|
||||
|
||||
type OKCoin struct {
|
||||
exchange.ExchangeBase
|
||||
RESTErrors map[string]string
|
||||
WebsocketErrors map[string]string
|
||||
FuturesValues []string
|
||||
WebsocketConn *websocket.Conn
|
||||
}
|
||||
|
||||
func (o *OKCoin) SetDefaults() {
|
||||
o.SetErrorDefaults()
|
||||
o.SetWebsocketErrorDefaults()
|
||||
o.Enabled = false
|
||||
o.Verbose = false
|
||||
o.Websocket = false
|
||||
o.RESTPollingDelay = 10
|
||||
o.FuturesValues = []string{"this_week", "next_week", "quarter"}
|
||||
|
||||
if !okcoinDefaultsSet {
|
||||
o.APIUrl = OKCOIN_API_URL
|
||||
o.Name = "OKCOIN International"
|
||||
o.WebsocketURL = OKCOIN_WEBSOCKET_URL
|
||||
okcoinDefaultsSet = true
|
||||
} else {
|
||||
o.APIUrl = OKCOIN_API_URL_CHINA
|
||||
o.Name = "OKCOIN China"
|
||||
o.WebsocketURL = OKCOIN_WEBSOCKET_URL_CHINA
|
||||
}
|
||||
}
|
||||
|
||||
func (o *OKCoin) Setup(exch config.ExchangeConfig) {
|
||||
if !exch.Enabled {
|
||||
o.SetEnabled(false)
|
||||
} else {
|
||||
o.Enabled = true
|
||||
o.AuthenticatedAPISupport = exch.AuthenticatedAPISupport
|
||||
o.SetAPIKeys(exch.APIKey, exch.APISecret, "", false)
|
||||
o.RESTPollingDelay = exch.RESTPollingDelay
|
||||
o.Verbose = exch.Verbose
|
||||
o.Websocket = exch.Websocket
|
||||
o.BaseCurrencies = common.SplitStrings(exch.BaseCurrencies, ",")
|
||||
o.AvailablePairs = common.SplitStrings(exch.AvailablePairs, ",")
|
||||
o.EnabledPairs = common.SplitStrings(exch.EnabledPairs, ",")
|
||||
}
|
||||
}
|
||||
|
||||
func (o *OKCoin) GetFee(maker bool) float64 {
|
||||
if o.APIUrl == OKCOIN_API_URL {
|
||||
if maker {
|
||||
return o.MakerFee
|
||||
} else {
|
||||
return o.TakerFee
|
||||
}
|
||||
}
|
||||
// Chinese exchange does not have any trading fees
|
||||
return 0
|
||||
}
|
||||
|
||||
func (o *OKCoin) GetTicker(symbol string) (OKCoinTicker, error) {
|
||||
resp := OKCoinTickerResponse{}
|
||||
vals := url.Values{}
|
||||
vals.Set("symbol", symbol)
|
||||
path := common.EncodeURLValues(o.APIUrl+OKCOIN_TICKER, vals)
|
||||
err := common.SendHTTPGetRequest(path, true, &resp)
|
||||
if err != nil {
|
||||
return OKCoinTicker{}, err
|
||||
}
|
||||
return resp.Ticker, nil
|
||||
}
|
||||
|
||||
func (o *OKCoin) GetOrderBook(symbol string, size int64, merge bool) (OKCoinOrderbook, error) {
|
||||
resp := OKCoinOrderbook{}
|
||||
vals := url.Values{}
|
||||
vals.Set("symbol", symbol)
|
||||
if size != 0 {
|
||||
vals.Set("size", strconv.FormatInt(size, 10))
|
||||
}
|
||||
if merge {
|
||||
vals.Set("merge", "1")
|
||||
}
|
||||
|
||||
path := common.EncodeURLValues(o.APIUrl+OKCOIN_DEPTH, vals)
|
||||
err := common.SendHTTPGetRequest(path, true, &resp)
|
||||
if err != nil {
|
||||
return resp, err
|
||||
}
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
func (o *OKCoin) GetTrades(symbol string, since int64) ([]OKCoinTrades, error) {
|
||||
result := []OKCoinTrades{}
|
||||
vals := url.Values{}
|
||||
vals.Set("symbol", symbol)
|
||||
if since != 0 {
|
||||
vals.Set("since", strconv.FormatInt(since, 10))
|
||||
}
|
||||
|
||||
path := common.EncodeURLValues(o.APIUrl+OKCOIN_TRADES, vals)
|
||||
err := common.SendHTTPGetRequest(path, true, &result)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (o *OKCoin) GetKline(symbol, klineType string, size, since int64) ([]interface{}, error) {
|
||||
resp := []interface{}{}
|
||||
vals := url.Values{}
|
||||
vals.Set("symbol", symbol)
|
||||
vals.Set("type", klineType)
|
||||
|
||||
if size != 0 {
|
||||
vals.Set("size", strconv.FormatInt(size, 10))
|
||||
}
|
||||
|
||||
if since != 0 {
|
||||
vals.Set("since", strconv.FormatInt(since, 10))
|
||||
}
|
||||
|
||||
path := common.EncodeURLValues(o.APIUrl+OKCOIN_KLINE, vals)
|
||||
err := common.SendHTTPGetRequest(path, true, &resp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
func (o *OKCoin) GetFuturesTicker(symbol, contractType string) (OKCoinFuturesTicker, error) {
|
||||
resp := OKCoinFuturesTickerResponse{}
|
||||
vals := url.Values{}
|
||||
vals.Set("symbol", symbol)
|
||||
vals.Set("contract_type", contractType)
|
||||
path := common.EncodeURLValues(o.APIUrl+OKCOIN_FUTURES_TICKER, vals)
|
||||
err := common.SendHTTPGetRequest(path, true, &resp)
|
||||
if err != nil {
|
||||
return OKCoinFuturesTicker{}, err
|
||||
}
|
||||
return resp.Ticker, nil
|
||||
}
|
||||
|
||||
func (o *OKCoin) GetFuturesDepth(symbol, contractType string, size int64, merge bool) (OKCoinOrderbook, error) {
|
||||
result := OKCoinOrderbook{}
|
||||
vals := url.Values{}
|
||||
vals.Set("symbol", symbol)
|
||||
vals.Set("contract_type", contractType)
|
||||
|
||||
if size != 0 {
|
||||
vals.Set("size", strconv.FormatInt(size, 10))
|
||||
}
|
||||
if merge {
|
||||
vals.Set("merge", "1")
|
||||
}
|
||||
|
||||
path := common.EncodeURLValues(o.APIUrl+OKCOIN_FUTURES_DEPTH, vals)
|
||||
err := common.SendHTTPGetRequest(path, true, &result)
|
||||
if err != nil {
|
||||
return result, err
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (o *OKCoin) GetFuturesTrades(symbol, contractType string) ([]OKCoinFuturesTrades, error) {
|
||||
result := []OKCoinFuturesTrades{}
|
||||
vals := url.Values{}
|
||||
vals.Set("symbol", symbol)
|
||||
vals.Set("contract_type", contractType)
|
||||
|
||||
path := common.EncodeURLValues(o.APIUrl+OKCOIN_FUTURES_TRADES, vals)
|
||||
err := common.SendHTTPGetRequest(path, true, &result)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (o *OKCoin) GetFuturesIndex(symbol string) (float64, error) {
|
||||
type Response struct {
|
||||
Index float64 `json:"future_index"`
|
||||
}
|
||||
|
||||
result := Response{}
|
||||
vals := url.Values{}
|
||||
vals.Set("symbol", symbol)
|
||||
|
||||
path := common.EncodeURLValues(o.APIUrl+OKCOIN_FUTURES_INDEX, vals)
|
||||
err := common.SendHTTPGetRequest(path, true, &result)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return result.Index, nil
|
||||
}
|
||||
|
||||
func (o *OKCoin) GetFuturesExchangeRate() (float64, error) {
|
||||
type Response struct {
|
||||
Rate float64 `json:"rate"`
|
||||
}
|
||||
|
||||
result := Response{}
|
||||
err := common.SendHTTPGetRequest(o.APIUrl+OKCOIN_EXCHANGE_RATE, true, &result)
|
||||
if err != nil {
|
||||
return result.Rate, err
|
||||
}
|
||||
return result.Rate, nil
|
||||
}
|
||||
|
||||
func (o *OKCoin) GetFuturesEstimatedPrice(symbol string) (float64, error) {
|
||||
type Response struct {
|
||||
Price float64 `json:"forecast_price"`
|
||||
}
|
||||
|
||||
result := Response{}
|
||||
vals := url.Values{}
|
||||
vals.Set("symbol", symbol)
|
||||
path := common.EncodeURLValues(o.APIUrl+OKCOIN_FUTURES_ESTIMATED_PRICE, vals)
|
||||
err := common.SendHTTPGetRequest(path, true, &result)
|
||||
if err != nil {
|
||||
return result.Price, err
|
||||
}
|
||||
return result.Price, nil
|
||||
}
|
||||
|
||||
func (o *OKCoin) GetFuturesKline(symbol, klineType, contractType string, size, since int64) ([]interface{}, error) {
|
||||
resp := []interface{}{}
|
||||
vals := url.Values{}
|
||||
vals.Set("symbol", symbol)
|
||||
vals.Set("type", klineType)
|
||||
vals.Set("contract_type", contractType)
|
||||
|
||||
if size != 0 {
|
||||
vals.Set("size", strconv.FormatInt(size, 10))
|
||||
}
|
||||
if since != 0 {
|
||||
vals.Set("since", strconv.FormatInt(since, 10))
|
||||
}
|
||||
|
||||
path := common.EncodeURLValues(o.APIUrl+OKCOIN_FUTURES_KLINE, vals)
|
||||
err := common.SendHTTPGetRequest(path, true, &resp)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
func (o *OKCoin) GetFuturesHoldAmount(symbol, contractType string) ([]OKCoinFuturesHoldAmount, error) {
|
||||
resp := []OKCoinFuturesHoldAmount{}
|
||||
vals := url.Values{}
|
||||
vals.Set("symbol", symbol)
|
||||
vals.Set("contract_type", contractType)
|
||||
|
||||
path := common.EncodeURLValues(o.APIUrl+OKCOIN_FUTURES_HOLD_AMOUNT, vals)
|
||||
err := common.SendHTTPGetRequest(path, true, &resp)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
func (o *OKCoin) GetFuturesExplosive(symbol, contractType string, status, currentPage, pageLength int64) ([]OKCoinFuturesExplosive, error) {
|
||||
type Response struct {
|
||||
Data []OKCoinFuturesExplosive `json:"data"`
|
||||
}
|
||||
resp := Response{}
|
||||
vals := url.Values{}
|
||||
vals.Set("symbol", symbol)
|
||||
vals.Set("contract_type", contractType)
|
||||
vals.Set("status", strconv.FormatInt(status, 10))
|
||||
vals.Set("current_page", strconv.FormatInt(currentPage, 10))
|
||||
vals.Set("page_length", strconv.FormatInt(pageLength, 10))
|
||||
|
||||
path := common.EncodeURLValues(o.APIUrl+OKCOIN_FUTURES_EXPLOSIVE, vals)
|
||||
err := common.SendHTTPGetRequest(path, true, &resp)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return resp.Data, nil
|
||||
}
|
||||
|
||||
func (o *OKCoin) GetUserInfo() (OKCoinUserInfo, error) {
|
||||
result := OKCoinUserInfo{}
|
||||
err := o.SendAuthenticatedHTTPRequest(OKCOIN_USERINFO, url.Values{}, &result)
|
||||
|
||||
if err != nil {
|
||||
return result, err
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (o *OKCoin) Trade(amount, price float64, symbol, orderType string) (int64, error) {
|
||||
type Response struct {
|
||||
Result bool `json:"result"`
|
||||
OrderID int64 `json:"order_id"`
|
||||
}
|
||||
v := url.Values{}
|
||||
v.Set("amount", strconv.FormatFloat(amount, 'f', -1, 64))
|
||||
v.Set("price", strconv.FormatFloat(price, 'f', -1, 64))
|
||||
v.Set("symbol", symbol)
|
||||
v.Set("type", orderType)
|
||||
|
||||
result := Response{}
|
||||
|
||||
err := o.SendAuthenticatedHTTPRequest(OKCOIN_TRADE, v, &result)
|
||||
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
if !result.Result {
|
||||
return 0, errors.New("Unable to place order.")
|
||||
}
|
||||
|
||||
return result.OrderID, nil
|
||||
}
|
||||
|
||||
func (o *OKCoin) GetTradeHistory(symbol string, TradeID int64) ([]OKCoinTrades, error) {
|
||||
result := []OKCoinTrades{}
|
||||
v := url.Values{}
|
||||
v.Set("symbol", symbol)
|
||||
v.Set("since", strconv.FormatInt(TradeID, 10))
|
||||
|
||||
err := o.SendAuthenticatedHTTPRequest(OKCOIN_TRADE_HISTORY, v, &result)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (o *OKCoin) BatchTrade(orderData string, symbol, orderType string) (OKCoinBatchTrade, error) {
|
||||
v := url.Values{}
|
||||
v.Set("orders_data", orderData)
|
||||
v.Set("symbol", symbol)
|
||||
v.Set("type", orderType)
|
||||
result := OKCoinBatchTrade{}
|
||||
|
||||
err := o.SendAuthenticatedHTTPRequest(OKCOIN_TRADE_BATCH, v, &result)
|
||||
|
||||
if err != nil {
|
||||
return result, err
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (o *OKCoin) CancelOrder(orderID []int64, symbol string) (OKCoinCancelOrderResponse, error) {
|
||||
v := url.Values{}
|
||||
orders := []string{}
|
||||
orderStr := ""
|
||||
result := OKCoinCancelOrderResponse{}
|
||||
|
||||
if len(orderID) > 1 {
|
||||
for x := range orderID {
|
||||
orders = append(orders, strconv.FormatInt(orderID[x], 10))
|
||||
}
|
||||
orderStr = common.JoinStrings(orders, ",")
|
||||
} else {
|
||||
orderStr = strconv.FormatInt(orderID[0], 10)
|
||||
}
|
||||
|
||||
v.Set("order_id", orderStr)
|
||||
v.Set("symbol", symbol)
|
||||
|
||||
err := o.SendAuthenticatedHTTPRequest(OKCOIN_ORDER_CANCEL, v, &result)
|
||||
|
||||
if err != nil {
|
||||
return result, err
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (o *OKCoin) GetOrderInfo(orderID int64, symbol string) ([]OKCoinOrderInfo, error) {
|
||||
type Response struct {
|
||||
Result bool `json:"result"`
|
||||
Orders []OKCoinOrderInfo `json:"orders"`
|
||||
}
|
||||
v := url.Values{}
|
||||
v.Set("symbol", symbol)
|
||||
v.Set("order_id", strconv.FormatInt(orderID, 10))
|
||||
result := Response{}
|
||||
|
||||
err := o.SendAuthenticatedHTTPRequest(OKCOIN_ORDER_INFO, v, &result)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if result.Result != true {
|
||||
return nil, errors.New("Unable to retrieve order info.")
|
||||
}
|
||||
|
||||
return result.Orders, nil
|
||||
}
|
||||
|
||||
func (o *OKCoin) GetOrderInfoBatch(orderID []int64, symbol string) ([]OKCoinOrderInfo, error) {
|
||||
type Response struct {
|
||||
Result bool `json:"result"`
|
||||
Orders []OKCoinOrderInfo `json:"orders"`
|
||||
}
|
||||
|
||||
orders := []string{}
|
||||
for x := range orderID {
|
||||
orders = append(orders, strconv.FormatInt(orderID[x], 10))
|
||||
}
|
||||
|
||||
v := url.Values{}
|
||||
v.Set("symbol", symbol)
|
||||
v.Set("order_id", common.JoinStrings(orders, ","))
|
||||
result := Response{}
|
||||
|
||||
err := o.SendAuthenticatedHTTPRequest(OKCOIN_ORDER_INFO, v, &result)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if result.Result != true {
|
||||
return nil, errors.New("Unable to retrieve order info.")
|
||||
}
|
||||
|
||||
return result.Orders, nil
|
||||
}
|
||||
|
||||
func (o *OKCoin) GetOrderHistory(pageLength, currentPage int64, status, symbol string) (OKCoinOrderHistory, error) {
|
||||
v := url.Values{}
|
||||
v.Set("symbol", symbol)
|
||||
v.Set("status", status)
|
||||
v.Set("current_page", strconv.FormatInt(currentPage, 10))
|
||||
v.Set("page_length", strconv.FormatInt(pageLength, 10))
|
||||
result := OKCoinOrderHistory{}
|
||||
|
||||
err := o.SendAuthenticatedHTTPRequest(OKCOIN_ORDER_HISTORY, v, &result)
|
||||
|
||||
if err != nil {
|
||||
return result, err
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (o *OKCoin) Withdrawal(symbol string, fee float64, tradePWD, address string, amount float64) (int, error) {
|
||||
v := url.Values{}
|
||||
v.Set("symbol", symbol)
|
||||
|
||||
if fee != 0 {
|
||||
v.Set("chargefee", strconv.FormatFloat(fee, 'f', -1, 64))
|
||||
}
|
||||
v.Set("trade_pwd", tradePWD)
|
||||
v.Set("withdraw_address", address)
|
||||
v.Set("withdraw_amount", strconv.FormatFloat(amount, 'f', -1, 64))
|
||||
result := OKCoinWithdrawalResponse{}
|
||||
|
||||
err := o.SendAuthenticatedHTTPRequest(OKCOIN_WITHDRAW, v, &result)
|
||||
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
if !result.Result {
|
||||
return 0, errors.New("Unable to process withdrawal request.")
|
||||
}
|
||||
|
||||
return result.WithdrawID, nil
|
||||
}
|
||||
|
||||
func (o *OKCoin) CancelWithdrawal(symbol string, withdrawalID int64) (int, error) {
|
||||
v := url.Values{}
|
||||
v.Set("symbol", symbol)
|
||||
v.Set("withdrawal_id", strconv.FormatInt(withdrawalID, 10))
|
||||
result := OKCoinWithdrawalResponse{}
|
||||
|
||||
err := o.SendAuthenticatedHTTPRequest(OKCOIN_WITHDRAW_CANCEL, v, &result)
|
||||
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
if !result.Result {
|
||||
return 0, errors.New("Unable to process withdrawal cancel request.")
|
||||
}
|
||||
|
||||
return result.WithdrawID, nil
|
||||
}
|
||||
|
||||
func (o *OKCoin) GetWithdrawalInfo(symbol string, withdrawalID int64) ([]OKCoinWithdrawInfo, error) {
|
||||
type Response struct {
|
||||
Result bool
|
||||
Withdraw []OKCoinWithdrawInfo `json:"withdraw"`
|
||||
}
|
||||
v := url.Values{}
|
||||
v.Set("symbol", symbol)
|
||||
v.Set("withdrawal_id", strconv.FormatInt(withdrawalID, 10))
|
||||
result := Response{}
|
||||
|
||||
err := o.SendAuthenticatedHTTPRequest(OKCOIN_WITHDRAW_INFO, v, &result)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if !result.Result {
|
||||
return nil, errors.New("Unable to process withdrawal cancel request.")
|
||||
}
|
||||
|
||||
return result.Withdraw, nil
|
||||
}
|
||||
|
||||
func (o *OKCoin) GetOrderFeeInfo(symbol string, orderID int64) (OKCoinOrderFeeInfo, error) {
|
||||
type Response struct {
|
||||
Data OKCoinOrderFeeInfo `json:"data"`
|
||||
Result bool `json:"result"`
|
||||
}
|
||||
|
||||
v := url.Values{}
|
||||
v.Set("symbol", symbol)
|
||||
v.Set("order_id", strconv.FormatInt(orderID, 10))
|
||||
result := Response{}
|
||||
|
||||
err := o.SendAuthenticatedHTTPRequest(OKCOIN_ORDER_FEE, v, &result)
|
||||
|
||||
if err != nil {
|
||||
return result.Data, err
|
||||
}
|
||||
|
||||
if !result.Result {
|
||||
return result.Data, errors.New("Unable to get order fee info.")
|
||||
}
|
||||
|
||||
return result.Data, nil
|
||||
}
|
||||
|
||||
func (o *OKCoin) GetLendDepth(symbol string) ([]OKCoinLendDepth, error) {
|
||||
type Response struct {
|
||||
LendDepth []OKCoinLendDepth `json:"lend_depth"`
|
||||
}
|
||||
|
||||
v := url.Values{}
|
||||
v.Set("symbol", symbol)
|
||||
result := Response{}
|
||||
|
||||
err := o.SendAuthenticatedHTTPRequest(OKCOIN_LEND_DEPTH, v, &result)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return result.LendDepth, nil
|
||||
}
|
||||
|
||||
func (o *OKCoin) GetBorrowInfo(symbol string) (OKCoinBorrowInfo, error) {
|
||||
v := url.Values{}
|
||||
v.Set("symbol", symbol)
|
||||
result := OKCoinBorrowInfo{}
|
||||
|
||||
err := o.SendAuthenticatedHTTPRequest(OKCOIN_BORROWS_INFO, v, &result)
|
||||
|
||||
if err != nil {
|
||||
return result, nil
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (o *OKCoin) Borrow(symbol, days string, amount, rate float64) (int, error) {
|
||||
v := url.Values{}
|
||||
v.Set("symbol", symbol)
|
||||
v.Set("days", days)
|
||||
v.Set("amount", strconv.FormatFloat(amount, 'f', -1, 64))
|
||||
v.Set("rate", strconv.FormatFloat(rate, 'f', -1, 64))
|
||||
result := OKCoinBorrowResponse{}
|
||||
|
||||
err := o.SendAuthenticatedHTTPRequest(OKCOIN_BORROW_MONEY, v, &result)
|
||||
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
if !result.Result {
|
||||
return 0, errors.New("Unable to borrow.")
|
||||
}
|
||||
|
||||
return result.BorrowID, nil
|
||||
}
|
||||
|
||||
func (o *OKCoin) CancelBorrow(symbol string, borrowID int64) (bool, error) {
|
||||
v := url.Values{}
|
||||
v.Set("symbol", symbol)
|
||||
v.Set("borrow_id", strconv.FormatInt(borrowID, 10))
|
||||
result := OKCoinBorrowResponse{}
|
||||
|
||||
err := o.SendAuthenticatedHTTPRequest(OKCOIN_BORROW_CANCEL, v, &result)
|
||||
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
if !result.Result {
|
||||
return false, errors.New("Unable to cancel borrow.")
|
||||
}
|
||||
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func (o *OKCoin) GetBorrowOrderInfo(borrowID int64) (OKCoinBorrowInfo, error) {
|
||||
type Response struct {
|
||||
Result bool `json:"result"`
|
||||
BorrowOrder OKCoinBorrowInfo `json:"borrow_order"`
|
||||
}
|
||||
|
||||
v := url.Values{}
|
||||
v.Set("borrow_id", strconv.FormatInt(borrowID, 10))
|
||||
result := Response{}
|
||||
err := o.SendAuthenticatedHTTPRequest(OKCOIN_BORROW_ORDER_INFO, v, &result)
|
||||
|
||||
if err != nil {
|
||||
return result.BorrowOrder, err
|
||||
}
|
||||
|
||||
if !result.Result {
|
||||
return result.BorrowOrder, errors.New("Unable to get borrow info.")
|
||||
}
|
||||
|
||||
return result.BorrowOrder, nil
|
||||
}
|
||||
|
||||
func (o *OKCoin) GetRepaymentInfo(borrowID int64) (bool, error) {
|
||||
v := url.Values{}
|
||||
v.Set("borrow_id", strconv.FormatInt(borrowID, 10))
|
||||
result := OKCoinBorrowResponse{}
|
||||
|
||||
err := o.SendAuthenticatedHTTPRequest(OKCOIN_REPAYMENT, v, &result)
|
||||
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
if !result.Result {
|
||||
return false, errors.New("Unable to get repayment info.")
|
||||
}
|
||||
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func (o *OKCoin) GetUnrepaymentsInfo(symbol string, currentPage, pageLength int) ([]OKCoinBorrowOrder, error) {
|
||||
type Response struct {
|
||||
Unrepayments []OKCoinBorrowOrder `json:"unrepayments"`
|
||||
Result bool `json:"result"`
|
||||
}
|
||||
v := url.Values{}
|
||||
v.Set("symbol", symbol)
|
||||
v.Set("current_page", strconv.Itoa(currentPage))
|
||||
v.Set("page_length", strconv.Itoa(pageLength))
|
||||
result := Response{}
|
||||
err := o.SendAuthenticatedHTTPRequest(OKCOIN_UNREPAYMENTS_INFO, v, &result)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if !result.Result {
|
||||
return nil, errors.New("Unable to get unrepayments info.")
|
||||
}
|
||||
|
||||
return result.Unrepayments, nil
|
||||
}
|
||||
|
||||
func (o *OKCoin) GetAccountRecords(symbol string, recType, currentPage, pageLength int) ([]OKCoinAccountRecords, error) {
|
||||
type Response struct {
|
||||
Records []OKCoinAccountRecords `json:"records"`
|
||||
Symbol string `json:"symbol"`
|
||||
}
|
||||
v := url.Values{}
|
||||
v.Set("symbol", symbol)
|
||||
v.Set("type", strconv.Itoa(recType))
|
||||
v.Set("current_page", strconv.Itoa(currentPage))
|
||||
v.Set("page_length", strconv.Itoa(pageLength))
|
||||
result := Response{}
|
||||
|
||||
err := o.SendAuthenticatedHTTPRequest(OKCOIN_ACCOUNT_RECORDS, v, &result)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return result.Records, nil
|
||||
}
|
||||
|
||||
func (o *OKCoin) GetFuturesUserInfo() {
|
||||
err := o.SendAuthenticatedHTTPRequest(OKCOIN_FUTURES_USERINFO, url.Values{}, nil)
|
||||
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
}
|
||||
|
||||
func (o *OKCoin) GetFuturesPosition(symbol, contractType string) {
|
||||
v := url.Values{}
|
||||
v.Set("symbol", symbol)
|
||||
v.Set("contract_type", contractType)
|
||||
err := o.SendAuthenticatedHTTPRequest(OKCOIN_FUTURES_POSITION, v, nil)
|
||||
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
}
|
||||
|
||||
func (o *OKCoin) FuturesTrade(amount, price float64, matchPrice, leverage int64, symbol, contractType, orderType string) {
|
||||
v := url.Values{}
|
||||
v.Set("symbol", symbol)
|
||||
v.Set("contract_type", contractType)
|
||||
v.Set("price", strconv.FormatFloat(price, 'f', -1, 64))
|
||||
v.Set("amount", strconv.FormatFloat(amount, 'f', -1, 64))
|
||||
v.Set("type", orderType)
|
||||
v.Set("match_price", strconv.FormatInt(matchPrice, 10))
|
||||
v.Set("lever_rate", strconv.FormatInt(leverage, 10))
|
||||
|
||||
err := o.SendAuthenticatedHTTPRequest(OKCOIN_FUTURES_TRADE, v, nil)
|
||||
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
}
|
||||
|
||||
func (o *OKCoin) FuturesBatchTrade(orderData, symbol, contractType string, leverage int64, orderType string) {
|
||||
v := url.Values{} //to-do batch trade support for orders_data)
|
||||
v.Set("symbol", symbol)
|
||||
v.Set("contract_type", contractType)
|
||||
v.Set("orders_data", orderData)
|
||||
v.Set("lever_rate", strconv.FormatInt(leverage, 10))
|
||||
|
||||
err := o.SendAuthenticatedHTTPRequest(OKCOIN_FUTURES_TRADE_BATCH, v, nil)
|
||||
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
}
|
||||
|
||||
func (o *OKCoin) CancelFuturesOrder(orderID int64, symbol, contractType string) {
|
||||
v := url.Values{}
|
||||
v.Set("symbol", symbol)
|
||||
v.Set("contract_type", contractType)
|
||||
v.Set("order_id", strconv.FormatInt(orderID, 10))
|
||||
|
||||
err := o.SendAuthenticatedHTTPRequest(OKCOIN_FUTURES_CANCEL, v, nil)
|
||||
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
}
|
||||
|
||||
func (o *OKCoin) GetFuturesOrderInfo(orderID, status, currentPage, pageLength int64, symbol, contractType string) {
|
||||
v := url.Values{}
|
||||
v.Set("symbol", symbol)
|
||||
v.Set("contract_type", contractType)
|
||||
v.Set("status", strconv.FormatInt(status, 10))
|
||||
v.Set("order_id", strconv.FormatInt(orderID, 10))
|
||||
v.Set("current_page", strconv.FormatInt(currentPage, 10))
|
||||
v.Set("page_length", strconv.FormatInt(pageLength, 10))
|
||||
|
||||
err := o.SendAuthenticatedHTTPRequest(OKCOIN_FUTURES_ORDER_INFO, v, nil)
|
||||
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
}
|
||||
|
||||
func (o *OKCoin) GetFutureOrdersInfo(orderID int64, contractType, symbol string) {
|
||||
v := url.Values{}
|
||||
v.Set("order_id", strconv.FormatInt(orderID, 10))
|
||||
v.Set("contract_type", contractType)
|
||||
v.Set("symbol", symbol)
|
||||
|
||||
err := o.SendAuthenticatedHTTPRequest(OKCOIN_FUTURES_ORDERS_INFO, v, nil)
|
||||
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
}
|
||||
|
||||
func (o *OKCoin) GetFuturesUserInfo4Fix() {
|
||||
v := url.Values{}
|
||||
|
||||
err := o.SendAuthenticatedHTTPRequest(OKCOIN_FUTURES_USERINFO_4FIX, v, nil)
|
||||
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
}
|
||||
|
||||
func (o *OKCoin) GetFuturesUserPosition4Fix(symbol, contractType string) {
|
||||
v := url.Values{}
|
||||
v.Set("symbol", symbol)
|
||||
v.Set("contract_type", contractType)
|
||||
v.Set("type", strconv.FormatInt(1, 10))
|
||||
|
||||
err := o.SendAuthenticatedHTTPRequest(OKCOIN_FUTURES_POSITION_4FIX, v, nil)
|
||||
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
}
|
||||
|
||||
func (o *OKCoin) SendAuthenticatedHTTPRequest(method string, v url.Values, result interface{}) (err error) {
|
||||
v.Set("api_key", o.APIKey)
|
||||
hasher := common.GetMD5([]byte(v.Encode() + "&secret_key=" + o.APISecret))
|
||||
v.Set("sign", strings.ToUpper(common.HexEncodeToString(hasher)))
|
||||
|
||||
encoded := v.Encode()
|
||||
path := o.APIUrl + method
|
||||
|
||||
if o.Verbose {
|
||||
log.Printf("Sending POST request to %s with params %s\n", path, encoded)
|
||||
}
|
||||
|
||||
headers := make(map[string]string)
|
||||
headers["Content-Type"] = "application/x-www-form-urlencoded"
|
||||
|
||||
resp, err := common.SendHTTPRequest("POST", path, headers, strings.NewReader(encoded))
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if o.Verbose {
|
||||
log.Printf("Recieved raw: \n%s\n", resp)
|
||||
}
|
||||
|
||||
err = common.JSONDecode([]byte(resp), &result)
|
||||
|
||||
if err != nil {
|
||||
return errors.New("Unable to JSON Unmarshal response.")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *OKCoin) SetErrorDefaults() {
|
||||
o.RESTErrors = map[string]string{
|
||||
"10000": "Required field, can not be null",
|
||||
"10001": "Request frequency too high",
|
||||
"10002": "System error",
|
||||
"10003": "Not in reqest list, please try again later",
|
||||
"10004": "IP not allowed to access the resource",
|
||||
"10005": "'secretKey' does not exist",
|
||||
"10006": "'partner' does not exist",
|
||||
"10007": "Signature does not match",
|
||||
"10008": "Illegal parameter",
|
||||
"10009": "Order does not exist",
|
||||
"10010": "Insufficient funds",
|
||||
"10011": "Amount too low",
|
||||
"10012": "Only btc_usd/btc_cny ltc_usd,ltc_cny supported",
|
||||
"10013": "Only support https request",
|
||||
"10014": "Order price must be between 0 and 1,000,000",
|
||||
"10015": "Order price differs from current market price too much",
|
||||
"10016": "Insufficient coins balance",
|
||||
"10017": "API authorization error",
|
||||
"10018": "Borrow amount less than lower limit [usd/cny:100,btc:0.1,ltc:1]",
|
||||
"10019": "Loan agreement not checked",
|
||||
"10020": `Rate cannot exceed 1%`,
|
||||
"10021": `Rate cannot less than 0.01%`,
|
||||
"10023": "Fail to get latest ticker",
|
||||
"10024": "Balance not sufficient",
|
||||
"10025": "Quota is full, cannot borrow temporarily",
|
||||
"10026": "Loan (including reserved loan) and margin cannot be withdrawn",
|
||||
"10027": "Cannot withdraw within 24 hrs of authentication information modification",
|
||||
"10028": "Withdrawal amount exceeds daily limit",
|
||||
"10029": "Account has unpaid loan, please cancel/pay off the loan before withdraw",
|
||||
"10031": "Deposits can only be withdrawn after 6 confirmations",
|
||||
"10032": "Please enabled phone/google authenticator",
|
||||
"10033": "Fee higher than maximum network transaction fee",
|
||||
"10034": "Fee lower than minimum network transaction fee",
|
||||
"10035": "Insufficient BTC/LTC",
|
||||
"10036": "Withdrawal amount too low",
|
||||
"10037": "Trade password not set",
|
||||
"10040": "Withdrawal cancellation fails",
|
||||
"10041": "Withdrawal address not approved",
|
||||
"10042": "Admin password error",
|
||||
"10043": "Account equity error, withdrawal failure",
|
||||
"10044": "fail to cancel borrowing order",
|
||||
"10047": "This function is disabled for sub-account",
|
||||
"10100": "User account frozen",
|
||||
"10216": "Non-available API",
|
||||
"20001": "User does not exist",
|
||||
"20002": "Account frozen",
|
||||
"20003": "Account frozen due to liquidation",
|
||||
"20004": "Futures account frozen",
|
||||
"20005": "User futures account does not exist",
|
||||
"20006": "Required field missing",
|
||||
"20007": "Illegal parameter",
|
||||
"20008": "Futures account balance is too low",
|
||||
"20009": "Future contract status error",
|
||||
"20010": "Risk rate ratio does not exist",
|
||||
"20011": `Risk rate higher than 90% before opening position`,
|
||||
"20012": `Risk rate higher than 90% after opening position`,
|
||||
"20013": "Temporally no counter party price",
|
||||
"20014": "System error",
|
||||
"20015": "Order does not exist",
|
||||
"20016": "Close amount bigger than your open positions",
|
||||
"20017": "Not authorized/illegal operation",
|
||||
"20018": `Order price differ more than 5% from the price in the last minute`,
|
||||
"20019": "IP restricted from accessing the resource",
|
||||
"20020": "secretKey does not exist",
|
||||
"20021": "Index information does not exist",
|
||||
"20022": "Wrong API interface (Cross margin mode shall call cross margin API, fixed margin mode shall call fixed margin API)",
|
||||
"20023": "Account in fixed-margin mode",
|
||||
"20024": "Signature does not match",
|
||||
"20025": "Leverage rate error",
|
||||
"20026": "API Permission Error",
|
||||
"20027": "No transaction record",
|
||||
"20028": "No such contract",
|
||||
}
|
||||
}
|
||||
558
exchanges/okcoin/okcoinwebsocket.go
Normal file
558
exchanges/okcoin/okcoinwebsocket.go
Normal file
@@ -0,0 +1,558 @@
|
||||
package okcoin
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/gorilla/websocket"
|
||||
"github.com/thrasher-/gocryptotrader/common"
|
||||
)
|
||||
|
||||
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"
|
||||
OKCOIN_WEBSOCKET_FUTURES_TRADE = "ok_futuresusd_trade"
|
||||
OKCOIN_WEBSOCKET_FUTURES_CANCEL_ORDER = "ok_futuresusd_cancel_order"
|
||||
OKCOIN_WEBSOCKET_FUTURES_REALTRADES = "ok_usd_future_realtrades"
|
||||
OKCOIN_WEBSOCKET_FUTURES_USERINFO = "ok_futureusd_userinfo"
|
||||
OKCOIN_WEBSOCKET_FUTURES_ORDER_INFO = "ok_futureusd_order_info"
|
||||
)
|
||||
|
||||
func (o *OKCoin) PingHandler(message string) error {
|
||||
err := o.WebsocketConn.WriteControl(websocket.PingMessage, []byte("{'event':'ping'}"), time.Now().Add(time.Second))
|
||||
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *OKCoin) AddChannel(channel string) {
|
||||
event := OKCoinWebsocketEvent{"addChannel", channel}
|
||||
json, err := common.JSONEncode(event)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
err = o.WebsocketConn.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(channel string) {
|
||||
event := OKCoinWebsocketEvent{"removeChannel", channel}
|
||||
json, err := common.JSONEncode(event)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
err = o.WebsocketConn.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) WebsocketSpotTrade(symbol, orderType string, price, amount float64) {
|
||||
values := make(map[string]string)
|
||||
values["symbol"] = symbol
|
||||
values["type"] = orderType
|
||||
values["price"] = strconv.FormatFloat(price, 'f', -1, 64)
|
||||
values["amount"] = strconv.FormatFloat(amount, 'f', -1, 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) WebsocketFuturesTrade(symbol, contractType string, price, amount float64, orderType, matchPrice, leverage int) {
|
||||
values := make(map[string]string)
|
||||
values["symbol"] = symbol
|
||||
values["contract_type"] = contractType
|
||||
values["price"] = strconv.FormatFloat(price, 'f', -1, 64)
|
||||
values["amount"] = strconv.FormatFloat(amount, 'f', -1, 64)
|
||||
values["type"] = strconv.Itoa(orderType)
|
||||
values["match_price"] = strconv.Itoa(matchPrice)
|
||||
values["lever_rate"] = strconv.Itoa(orderType)
|
||||
o.AddChannelAuthenticated(OKCOIN_WEBSOCKET_FUTURES_TRADE, 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) WebsocketFuturesCancel(symbol, contractType string, orderID int64) {
|
||||
values := make(map[string]string)
|
||||
values["symbol"] = symbol
|
||||
values["order_id"] = strconv.FormatInt(orderID, 10)
|
||||
values["contract_type"] = contractType
|
||||
o.AddChannelAuthenticated(OKCOIN_WEBSOCKET_FUTURES_CANCEL_ORDER, 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) WebsocketFuturesOrderInfo(symbol, contractType string, orderID int64, orderStatus, currentPage, pageLength int) {
|
||||
values := make(map[string]string)
|
||||
values["symbol"] = symbol
|
||||
values["order_id"] = strconv.FormatInt(orderID, 10)
|
||||
values["contract_type"] = contractType
|
||||
values["status"] = strconv.Itoa(orderStatus)
|
||||
values["current_page"] = strconv.Itoa(currentPage)
|
||||
values["page_length"] = strconv.Itoa(pageLength)
|
||||
o.AddChannelAuthenticated(OKCOIN_WEBSOCKET_FUTURES_ORDER_INFO, 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.APIKey
|
||||
urlVals := o.ConvertToURLValues(values)
|
||||
return strings.ToUpper(common.HexEncodeToString(common.GetMD5([]byte(urlVals.Encode() + "&secret_key=" + o.APISecret))))
|
||||
}
|
||||
|
||||
func (o *OKCoin) AddChannelAuthenticated(channel string, values map[string]string) {
|
||||
values["sign"] = o.WebsocketSign(values)
|
||||
event := OKCoinWebsocketEventAuth{"addChannel", channel, values}
|
||||
json, err := common.JSONEncode(event)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
err = o.WebsocketConn.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, values map[string]string) {
|
||||
values["sign"] = o.WebsocketSign(values)
|
||||
event := OKCoinWebsocketEventAuthRemove{"removeChannel", channel, values}
|
||||
json, err := common.JSONEncode(event)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
err = o.WebsocketConn.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() {
|
||||
klineValues := []string{"1min", "3min", "5min", "15min", "30min", "1hour", "2hour", "4hour", "6hour", "12hour", "day", "3day", "week"}
|
||||
currencyChan, userinfoChan := "", ""
|
||||
|
||||
if o.WebsocketURL == OKCOIN_WEBSOCKET_URL_CHINA {
|
||||
currencyChan = OKCOIN_WEBSOCKET_CNY_REALTRADES
|
||||
userinfoChan = OKCOIN_WEBSOCKET_SPOTCNY_USERINFO
|
||||
} else {
|
||||
currencyChan = OKCOIN_WEBSOCKET_USD_REALTRADES
|
||||
userinfoChan = OKCOIN_WEBSOCKET_SPOTUSD_USERINFO
|
||||
}
|
||||
|
||||
for o.Enabled && o.Websocket {
|
||||
var Dialer websocket.Dialer
|
||||
var err error
|
||||
o.WebsocketConn, _, err = Dialer.Dial(o.WebsocketURL, http.Header{})
|
||||
|
||||
if err != nil {
|
||||
log.Printf("%s Unable to connect to Websocket. Error: %s\n", o.GetName(), err)
|
||||
continue
|
||||
}
|
||||
|
||||
if o.Verbose {
|
||||
log.Printf("%s Connected to Websocket.\n", o.GetName())
|
||||
}
|
||||
|
||||
o.WebsocketConn.SetPingHandler(o.PingHandler)
|
||||
|
||||
if o.AuthenticatedAPISupport {
|
||||
if o.WebsocketURL == OKCOIN_WEBSOCKET_URL {
|
||||
o.AddChannelAuthenticated(OKCOIN_WEBSOCKET_FUTURES_REALTRADES, map[string]string{})
|
||||
o.AddChannelAuthenticated(OKCOIN_WEBSOCKET_FUTURES_USERINFO, map[string]string{})
|
||||
}
|
||||
o.AddChannelAuthenticated(currencyChan, map[string]string{})
|
||||
o.AddChannelAuthenticated(userinfoChan, map[string]string{})
|
||||
}
|
||||
|
||||
for _, x := range o.EnabledPairs {
|
||||
currency := common.StringToLower(x)
|
||||
currencyUL := currency[0:3] + "_" + currency[3:]
|
||||
if o.AuthenticatedAPISupport {
|
||||
o.WebsocketSpotOrderInfo(currencyUL, -1)
|
||||
}
|
||||
if o.WebsocketURL == OKCOIN_WEBSOCKET_URL {
|
||||
o.AddChannel(fmt.Sprintf("ok_%s_future_index", currency))
|
||||
for _, y := range o.FuturesValues {
|
||||
if o.AuthenticatedAPISupport {
|
||||
o.WebsocketFuturesOrderInfo(currencyUL, y, -1, 1, 1, 50)
|
||||
}
|
||||
o.AddChannel(fmt.Sprintf("ok_%s_future_ticker_%s", currency, y))
|
||||
o.AddChannel(fmt.Sprintf("ok_%s_future_depth_%s_60", currency, y))
|
||||
o.AddChannel(fmt.Sprintf("ok_%s_future_trade_v1_%s", currency, y))
|
||||
for _, z := range klineValues {
|
||||
o.AddChannel(fmt.Sprintf("ok_future_%s_kline_%s_%s", currency, y, z))
|
||||
}
|
||||
}
|
||||
} else {
|
||||
o.AddChannel(fmt.Sprintf("ok_%s_ticker", currency))
|
||||
o.AddChannel(fmt.Sprintf("ok_%s_depth60", currency))
|
||||
o.AddChannel(fmt.Sprintf("ok_%s_trades_v1", currency))
|
||||
|
||||
for _, y := range klineValues {
|
||||
o.AddChannel(fmt.Sprintf("ok_%s_kline_%s", currency, y))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for o.Enabled && o.Websocket {
|
||||
msgType, resp, err := o.WebsocketConn.ReadMessage()
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
break
|
||||
}
|
||||
switch msgType {
|
||||
case websocket.TextMessage:
|
||||
response := []interface{}{}
|
||||
err = common.JSONDecode(resp, &response)
|
||||
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
continue
|
||||
}
|
||||
|
||||
for _, y := range response {
|
||||
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 success != "true" && success != nil {
|
||||
errorCodeStr, ok := errorcode.(string)
|
||||
if !ok {
|
||||
log.Printf("%s Websocket: Unable to convert errorcode to string.\n", o.GetName())
|
||||
log.Printf("%s Websocket: channel %s error code: %s.\n", o.GetName(), channelStr, errorcode)
|
||||
} else {
|
||||
log.Printf("%s Websocket: channel %s error: %s.\n", o.GetName(), channelStr, o.WebsocketErrors[errorCodeStr])
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
if success == "true" {
|
||||
if data == nil {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
dataJSON, err := common.JSONEncode(data)
|
||||
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
continue
|
||||
}
|
||||
|
||||
switch true {
|
||||
case common.StringContains(channelStr, "ticker") && !common.StringContains(channelStr, "future"):
|
||||
tickerValues := []string{"buy", "high", "last", "low", "sell", "timestamp"}
|
||||
tickerMap := data.(map[string]interface{})
|
||||
ticker := OKCoinWebsocketTicker{}
|
||||
ticker.Vol = tickerMap["vol"].(string)
|
||||
|
||||
for _, z := range tickerValues {
|
||||
result := reflect.TypeOf(tickerMap[z]).String()
|
||||
if result == "string" {
|
||||
value, err := strconv.ParseFloat(tickerMap[z].(string), 64)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
continue
|
||||
}
|
||||
|
||||
switch z {
|
||||
case "buy":
|
||||
ticker.Buy = value
|
||||
case "high":
|
||||
ticker.High = value
|
||||
case "last":
|
||||
ticker.Last = value
|
||||
case "low":
|
||||
ticker.Low = value
|
||||
case "sell":
|
||||
ticker.Sell = value
|
||||
case "timestamp":
|
||||
ticker.Timestamp = value
|
||||
}
|
||||
|
||||
} else if result == "float64" {
|
||||
switch z {
|
||||
case "buy":
|
||||
ticker.Buy = tickerMap[z].(float64)
|
||||
case "high":
|
||||
ticker.High = tickerMap[z].(float64)
|
||||
case "last":
|
||||
ticker.Last = tickerMap[z].(float64)
|
||||
case "low":
|
||||
ticker.Low = tickerMap[z].(float64)
|
||||
case "sell":
|
||||
ticker.Sell = tickerMap[z].(float64)
|
||||
case "timestamp":
|
||||
ticker.Timestamp = tickerMap[z].(float64)
|
||||
}
|
||||
}
|
||||
}
|
||||
case common.StringContains(channelStr, "ticker") && common.StringContains(channelStr, "future"):
|
||||
ticker := OKCoinWebsocketFuturesTicker{}
|
||||
err = common.JSONDecode(dataJSON, &ticker)
|
||||
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
continue
|
||||
}
|
||||
case common.StringContains(channelStr, "depth"):
|
||||
orderbook := OKCoinWebsocketOrderbook{}
|
||||
err = common.JSONDecode(dataJSON, &orderbook)
|
||||
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
continue
|
||||
}
|
||||
case common.StringContains(channelStr, "trades_v1") || common.StringContains(channelStr, "trade_v1"):
|
||||
type TradeResponse struct {
|
||||
Data [][]string
|
||||
}
|
||||
|
||||
trades := TradeResponse{}
|
||||
err = common.JSONDecode(dataJSON, &trades.Data)
|
||||
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
continue
|
||||
}
|
||||
// to-do: convert from string array to trade struct
|
||||
case common.StringContains(channelStr, "kline"):
|
||||
klines := []interface{}{}
|
||||
err := common.JSONDecode(dataJSON, &klines)
|
||||
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
continue
|
||||
}
|
||||
case common.StringContains(channelStr, "spot") && common.StringContains(channelStr, "realtrades"):
|
||||
if string(dataJSON) == "null" {
|
||||
continue
|
||||
}
|
||||
realtrades := OKCoinWebsocketRealtrades{}
|
||||
err := common.JSONDecode(dataJSON, &realtrades)
|
||||
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
continue
|
||||
}
|
||||
case common.StringContains(channelStr, "future") && common.StringContains(channelStr, "realtrades"):
|
||||
if string(dataJSON) == "null" {
|
||||
continue
|
||||
}
|
||||
realtrades := OKCoinWebsocketFuturesRealtrades{}
|
||||
err := common.JSONDecode(dataJSON, &realtrades)
|
||||
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
continue
|
||||
}
|
||||
case common.StringContains(channelStr, "spot") && common.StringContains(channelStr, "trade") || common.StringContains(channelStr, "futures") && common.StringContains(channelStr, "trade"):
|
||||
tradeOrder := OKCoinWebsocketTradeOrderResponse{}
|
||||
err := common.JSONDecode(dataJSON, &tradeOrder)
|
||||
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
continue
|
||||
}
|
||||
case common.StringContains(channelStr, "cancel_order"):
|
||||
cancelOrder := OKCoinWebsocketTradeOrderResponse{}
|
||||
err := common.JSONDecode(dataJSON, &cancelOrder)
|
||||
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
continue
|
||||
}
|
||||
case common.StringContains(channelStr, "spot") && common.StringContains(channelStr, "userinfo"):
|
||||
userinfo := OKCoinWebsocketUserinfo{}
|
||||
err = common.JSONDecode(dataJSON, &userinfo)
|
||||
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
continue
|
||||
}
|
||||
case common.StringContains(channelStr, "futureusd_userinfo"):
|
||||
userinfo := OKCoinWebsocketFuturesUserInfo{}
|
||||
err = common.JSONDecode(dataJSON, &userinfo)
|
||||
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
continue
|
||||
}
|
||||
case common.StringContains(channelStr, "spot") && common.StringContains(channelStr, "order_info"):
|
||||
type OrderInfoResponse struct {
|
||||
Result bool `json:"result"`
|
||||
Orders []OKCoinWebsocketOrder `json:"orders"`
|
||||
}
|
||||
var orders OrderInfoResponse
|
||||
err := common.JSONDecode(dataJSON, &orders)
|
||||
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
continue
|
||||
}
|
||||
case common.StringContains(channelStr, "futureusd_order_info"):
|
||||
type OrderInfoResponse struct {
|
||||
Result bool `json:"result"`
|
||||
Orders []OKCoinWebsocketFuturesOrder `json:"orders"`
|
||||
}
|
||||
var orders OrderInfoResponse
|
||||
err := common.JSONDecode(dataJSON, &orders)
|
||||
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
continue
|
||||
}
|
||||
case common.StringContains(channelStr, "future_index"):
|
||||
index := OKCoinWebsocketFutureIndex{}
|
||||
err = common.JSONDecode(dataJSON, &index)
|
||||
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
o.WebsocketConn.Close()
|
||||
log.Printf("%s Websocket client disconnected.", o.GetName())
|
||||
}
|
||||
}
|
||||
|
||||
func (o *OKCoin) SetWebsocketErrorDefaults() {
|
||||
o.WebsocketErrors = map[string]string{
|
||||
"10001": "Illegal parameters",
|
||||
"10002": "Authentication failure",
|
||||
"10003": "This connection has requested other user data",
|
||||
"10004": "This connection did not request this user data",
|
||||
"10005": "System error",
|
||||
"10009": "Order does not exist",
|
||||
"10010": "Insufficient funds",
|
||||
"10011": "Order quantity too low",
|
||||
"10012": "Only support btc_usd/btc_cny ltc_usd/ltc_cny",
|
||||
"10014": "Order price must be between 0 - 1,000,000",
|
||||
"10015": "Channel subscription temporally not available",
|
||||
"10016": "Insufficient coins",
|
||||
"10017": "WebSocket authorization error",
|
||||
"10100": "User frozen",
|
||||
"10216": "Non-public API",
|
||||
"20001": "User does not exist",
|
||||
"20002": "User frozen",
|
||||
"20003": "Frozen due to force liquidation",
|
||||
"20004": "Future account frozen",
|
||||
"20005": "User future account does not exist",
|
||||
"20006": "Required field can not be null",
|
||||
"20007": "Illegal parameter",
|
||||
"20008": "Future account fund balance is zero",
|
||||
"20009": "Future contract status error",
|
||||
"20010": "Risk rate information does not exist",
|
||||
"20011": `Risk rate bigger than 90% before opening position`,
|
||||
"20012": `Risk rate bigger than 90% after opening position`,
|
||||
"20013": "Temporally no counter party price",
|
||||
"20014": "System error",
|
||||
"20015": "Order does not exist",
|
||||
"20016": "Liquidation quantity bigger than holding",
|
||||
"20017": "Not authorized/illegal order ID",
|
||||
"20018": `Order price higher than 105% or lower than 95% of the price of last minute`,
|
||||
"20019": "IP restrained to access the resource",
|
||||
"20020": "Secret key does not exist",
|
||||
"20021": "Index information does not exist",
|
||||
"20022": "Wrong API interface",
|
||||
"20023": "Fixed margin user",
|
||||
"20024": "Signature does not match",
|
||||
"20025": "Leverage rate error",
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user