mirror of
https://github.com/d0zingcat/gocryptotrader.git
synced 2026-06-05 15:10:59 +00:00
Initial overhaul of websocket connection and feeds (#189)
* Initial overhaul of websocket connection and feeds * Added proxy support * Piped to routines.go * Added new websocket file in exchanges Refactored orderbook handling into exchange_websocket.go Added better error responses for binance_websocket.go General clean for binance_websocket.go * General fixes - bitfinex_websocket.go Refactored orderbook cache code - bitfinex_websocket.go Removed fatal error with unhandled type - routines.go * Added general improvements to bitmex_websocket.go Refactored orderbook handling to exchange_websocket.go Added variable in Item struct in orderbook.go for looking up orders by ID * Fix issue when routines are blocked due to Data Handler not started Updated traffic handler General fixes for bitstamp_websocket.go * General fixes for coinbasepro_websocket.go * General fixes for coinut_websocket.go Fixed error return in exchange_websocket.go * Removed comments in coinut_wrapper.go Refactor orderbook logic from hitbtc_websocket.go to exchange_websocket.go * General fixes * Removed comments General fixes * Updated routines.go * After rebase fix * Fixed update config pairs in okcoin.go * fixed config currency issue in okcoin.go for okcoin China * exchange_websocket.go *Removed unused const dec *Removed state change routine *Improved trafficMonitor routine *Increased verbosity for error returns *Removed uneeded mutex locks exchange_websocket_test.go *Added new tests for websocket and orderbook updating routines.go *Removed string cased * Fixed race conditions on sync.waitgroup in exchanges_websocket.go * Changes variable name in config.go * Removes unnecessary comment * Removes indefinite lock on error return * Removes unnecessary comment * Adds support for BTCC websocket Drops support for BTCC REST * Rewords comment in exchange_websocket.go Moves types to poloniex_types.go * Moves types to coinut_types.go * Removes uneeded range for accessing array variables for coinbase_websocket.go Removes comments in coinut_types.go * Adds verbosity flag to GCT Suppresses verbose output from routines.go * Fixes setting proxy for REST and Websocket per exchange Upgrades error handling Drops unused *url.Url variable in exchange type * Adds test for setting proxy * Fixes bug that closes connection due to incorrect timeout time through a proxy connection * Clarify verbose flag message
This commit is contained in:
committed by
Adrian Gallagher
parent
7315e6604c
commit
d3c2800fe0
@@ -1,14 +1,10 @@
|
||||
package btcc
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"log"
|
||||
"net/url"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/gorilla/websocket"
|
||||
"github.com/thrasher-/gocryptotrader/common"
|
||||
"github.com/thrasher-/gocryptotrader/config"
|
||||
"github.com/thrasher-/gocryptotrader/exchanges"
|
||||
@@ -17,39 +13,16 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
btccAPIUrl = "https://spotusd-data.btcc.com"
|
||||
btccAPIAuthenticatedMethod = "api_trade_v1.php"
|
||||
btccAPIVersion = "2.0.1.3"
|
||||
btccOrderBuy = "buyOrder2"
|
||||
btccOrderSell = "sellOrder2"
|
||||
btccOrderCancel = "cancelOrder"
|
||||
btccIcebergBuy = "buyIcebergOrder"
|
||||
btccIcebergSell = "sellIcebergOrder"
|
||||
btccIcebergOrder = "getIcebergOrder"
|
||||
btccIcebergOrders = "getIcebergOrders"
|
||||
btccIcebergCancel = "cancelIcebergOrder"
|
||||
btccAccountInfo = "getAccountInfo"
|
||||
btccDeposits = "getDeposits"
|
||||
btccMarketdepth = "getMarketDepth2"
|
||||
btccOrder = "getOrder"
|
||||
btccOrders = "getOrders"
|
||||
btccTransactions = "getTransactions"
|
||||
btccWithdrawal = "getWithdrawal"
|
||||
btccWithdrawals = "getWithdrawals"
|
||||
btccWithdrawalRequest = "requestWithdrawal"
|
||||
btccStoporderBuy = "buyStopOrder"
|
||||
btccStoporderSell = "sellStopOrder"
|
||||
btccStoporderCancel = "cancelStopOrder"
|
||||
btccStoporder = "getStopOrder"
|
||||
btccStoporders = "getStopOrders"
|
||||
|
||||
btccAuthRate = 0
|
||||
btccUnauthRate = 0
|
||||
)
|
||||
|
||||
// BTCC is the main overaching type across the BTCC package
|
||||
// NOTE this package is websocket connection dependant, the REST endpoints have
|
||||
// been dropped
|
||||
type BTCC struct {
|
||||
exchange.Base
|
||||
Conn *websocket.Conn
|
||||
}
|
||||
|
||||
// SetDefaults sets default values for the exchange
|
||||
@@ -58,10 +31,9 @@ func (b *BTCC) SetDefaults() {
|
||||
b.Enabled = false
|
||||
b.Fee = 0
|
||||
b.Verbose = false
|
||||
b.Websocket = false
|
||||
b.RESTPollingDelay = 10
|
||||
b.RequestCurrencyPairFormat.Delimiter = ""
|
||||
b.RequestCurrencyPairFormat.Uppercase = false
|
||||
b.RequestCurrencyPairFormat.Uppercase = true
|
||||
b.ConfigCurrencyPairFormat.Delimiter = ""
|
||||
b.ConfigCurrencyPairFormat.Uppercase = true
|
||||
b.AssetTypes = []string{ticker.Spot}
|
||||
@@ -71,8 +43,7 @@ func (b *BTCC) SetDefaults() {
|
||||
request.NewRateLimit(time.Second, btccAuthRate),
|
||||
request.NewRateLimit(time.Second, btccUnauthRate),
|
||||
common.NewHTTPClientWithTimeout(exchange.DefaultHTTPTimeout))
|
||||
b.APIUrlDefault = btccAPIUrl
|
||||
b.APIUrl = b.APIUrlDefault
|
||||
b.WebsocketInit()
|
||||
}
|
||||
|
||||
// Setup is run on startup to setup exchange with config values
|
||||
@@ -87,7 +58,7 @@ func (b *BTCC) Setup(exch config.ExchangeConfig) {
|
||||
b.SetHTTPClientUserAgent(exch.HTTPUserAgent)
|
||||
b.RESTPollingDelay = exch.RESTPollingDelay
|
||||
b.Verbose = exch.Verbose
|
||||
b.Websocket = exch.Websocket
|
||||
b.Websocket.SetEnabled(exch.Websocket)
|
||||
b.BaseCurrencies = common.SplitStrings(exch.BaseCurrencies, ",")
|
||||
b.AvailablePairs = common.SplitStrings(exch.AvailablePairs, ",")
|
||||
b.EnabledPairs = common.SplitStrings(exch.EnabledPairs, ",")
|
||||
@@ -107,6 +78,18 @@ func (b *BTCC) Setup(exch config.ExchangeConfig) {
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
err = b.SetClientProxyAddress(exch.ProxyAddress)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
err = b.WebsocketSetup(b.WsConnect,
|
||||
exch.Name,
|
||||
exch.Websocket,
|
||||
btccSocketioAddress,
|
||||
exch.WebsocketURL)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -114,528 +97,3 @@ func (b *BTCC) Setup(exch config.ExchangeConfig) {
|
||||
func (b *BTCC) GetFee() float64 {
|
||||
return b.Fee
|
||||
}
|
||||
|
||||
// GetTicker returns ticker information
|
||||
// currencyPair - Example "btccny", "ltccny" or "ltcbtc"
|
||||
func (b *BTCC) GetTicker(currencyPair string) (Ticker, error) {
|
||||
resp := Response{}
|
||||
path := fmt.Sprintf("%s/data/pro/ticker?symbol=%s", b.APIUrl, currencyPair)
|
||||
return resp.Ticker, b.SendHTTPRequest(path, &resp)
|
||||
}
|
||||
|
||||
// GetTradeHistory returns trade history data
|
||||
// currencyPair - Example "btccny", "ltccny" or "ltcbtc"
|
||||
// limit - limits the returned trades example "10"
|
||||
// sinceTid - returns trade records starting from id supplied example "5000"
|
||||
// time - returns trade records starting from unix time 1406794449
|
||||
func (b *BTCC) GetTradeHistory(currencyPair string, limit, sinceTid int64, time time.Time) ([]Trade, error) {
|
||||
trades := []Trade{}
|
||||
path := fmt.Sprintf("%s/data/pro/historydata?symbol=%s", b.APIUrl, currencyPair)
|
||||
v := url.Values{}
|
||||
|
||||
if limit > 0 {
|
||||
v.Set("limit", strconv.FormatInt(limit, 10))
|
||||
}
|
||||
if sinceTid > 0 {
|
||||
v.Set("since", strconv.FormatInt(sinceTid, 10))
|
||||
}
|
||||
if !time.IsZero() {
|
||||
v.Set("sincetype", strconv.FormatInt(time.Unix(), 10))
|
||||
}
|
||||
|
||||
path = common.EncodeURLValues(path, v)
|
||||
return trades, b.SendHTTPRequest(path, &trades)
|
||||
}
|
||||
|
||||
// GetOrderBook returns current symbol order book
|
||||
// currencyPair - Example "btccny", "ltccny" or "ltcbtc"
|
||||
// limit - limits the returned trades example "10" if 0 will return full
|
||||
// orderbook
|
||||
func (b *BTCC) GetOrderBook(currencyPair string, limit int) (Orderbook, error) {
|
||||
result := Orderbook{}
|
||||
path := fmt.Sprintf("%s/data/pro/orderbook?symbol=%s&limit=%d", b.APIUrl, currencyPair, limit)
|
||||
if limit == 0 {
|
||||
path = fmt.Sprintf("%s/data/pro/orderbook?symbol=%s", b.APIUrl, currencyPair)
|
||||
}
|
||||
|
||||
return result, b.SendHTTPRequest(path, &result)
|
||||
}
|
||||
|
||||
// GetAccountInfo returns account information
|
||||
func (b *BTCC) GetAccountInfo(infoType string) error {
|
||||
params := make([]interface{}, 0)
|
||||
|
||||
if len(infoType) > 0 {
|
||||
params = append(params, infoType)
|
||||
}
|
||||
|
||||
return b.SendAuthenticatedHTTPRequest(btccAccountInfo, params)
|
||||
}
|
||||
|
||||
// PlaceOrder places a new order
|
||||
func (b *BTCC) PlaceOrder(buyOrder bool, price, amount float64, symbol string) {
|
||||
params := make([]interface{}, 0)
|
||||
params = append(params, strconv.FormatFloat(price, 'f', -1, 64))
|
||||
params = append(params, strconv.FormatFloat(amount, 'f', -1, 64))
|
||||
|
||||
if len(symbol) > 0 {
|
||||
params = append(params, symbol)
|
||||
}
|
||||
|
||||
req := btccOrderBuy
|
||||
if !buyOrder {
|
||||
req = btccOrderSell
|
||||
}
|
||||
|
||||
err := b.SendAuthenticatedHTTPRequest(req, params)
|
||||
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
}
|
||||
|
||||
// CancelOrder cancels an order
|
||||
func (b *BTCC) CancelOrder(orderID int64, symbol string) {
|
||||
params := make([]interface{}, 0)
|
||||
params = append(params, orderID)
|
||||
|
||||
if len(symbol) > 0 {
|
||||
params = append(params, symbol)
|
||||
}
|
||||
|
||||
err := b.SendAuthenticatedHTTPRequest(btccOrderCancel, params)
|
||||
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
}
|
||||
|
||||
// GetDeposits returns deposit information
|
||||
func (b *BTCC) GetDeposits(currency string, pending bool) {
|
||||
params := make([]interface{}, 0)
|
||||
params = append(params, currency)
|
||||
|
||||
if pending {
|
||||
params = append(params, pending)
|
||||
}
|
||||
|
||||
err := b.SendAuthenticatedHTTPRequest(btccDeposits, params)
|
||||
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
}
|
||||
|
||||
// GetMarketDepth returns market depth at limit
|
||||
func (b *BTCC) GetMarketDepth(symbol string, limit int64) {
|
||||
params := make([]interface{}, 0)
|
||||
|
||||
if limit > 0 {
|
||||
params = append(params, limit)
|
||||
}
|
||||
|
||||
if len(symbol) > 0 {
|
||||
params = append(params, symbol)
|
||||
}
|
||||
|
||||
err := b.SendAuthenticatedHTTPRequest(btccMarketdepth, params)
|
||||
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
}
|
||||
|
||||
// GetOrder returns information about a specific order
|
||||
func (b *BTCC) GetOrder(orderID int64, symbol string, detailed bool) {
|
||||
params := make([]interface{}, 0)
|
||||
params = append(params, orderID)
|
||||
|
||||
if len(symbol) > 0 {
|
||||
params = append(params, symbol)
|
||||
}
|
||||
|
||||
if detailed {
|
||||
params = append(params, detailed)
|
||||
}
|
||||
|
||||
err := b.SendAuthenticatedHTTPRequest(btccOrder, params)
|
||||
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
}
|
||||
|
||||
// GetOrders returns information of a range of orders
|
||||
func (b *BTCC) GetOrders(openonly bool, symbol string, limit, offset, since int64, detailed bool) {
|
||||
params := make([]interface{}, 0)
|
||||
|
||||
if openonly {
|
||||
params = append(params, openonly)
|
||||
}
|
||||
|
||||
if len(symbol) > 0 {
|
||||
params = append(params, symbol)
|
||||
}
|
||||
|
||||
if limit > 0 {
|
||||
params = append(params, limit)
|
||||
}
|
||||
|
||||
if offset > 0 {
|
||||
params = append(params, offset)
|
||||
}
|
||||
|
||||
if since > 0 {
|
||||
params = append(params, since)
|
||||
}
|
||||
|
||||
if detailed {
|
||||
params = append(params, detailed)
|
||||
}
|
||||
|
||||
err := b.SendAuthenticatedHTTPRequest(btccOrders, params)
|
||||
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
}
|
||||
|
||||
// GetTransactions returns transaction lists
|
||||
func (b *BTCC) GetTransactions(transType string, limit, offset, since int64, sinceType string) {
|
||||
params := make([]interface{}, 0)
|
||||
|
||||
if len(transType) > 0 {
|
||||
params = append(params, transType)
|
||||
}
|
||||
|
||||
if limit > 0 {
|
||||
params = append(params, limit)
|
||||
}
|
||||
|
||||
if offset > 0 {
|
||||
params = append(params, offset)
|
||||
}
|
||||
|
||||
if since > 0 {
|
||||
params = append(params, since)
|
||||
}
|
||||
|
||||
if len(sinceType) > 0 {
|
||||
params = append(params, sinceType)
|
||||
}
|
||||
|
||||
err := b.SendAuthenticatedHTTPRequest(btccTransactions, params)
|
||||
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
}
|
||||
|
||||
// GetWithdrawal returns information about a withdrawal process
|
||||
func (b *BTCC) GetWithdrawal(withdrawalID int64, currency string) {
|
||||
params := make([]interface{}, 0)
|
||||
params = append(params, withdrawalID)
|
||||
|
||||
if len(currency) > 0 {
|
||||
params = append(params, currency)
|
||||
}
|
||||
|
||||
err := b.SendAuthenticatedHTTPRequest(btccWithdrawal, params)
|
||||
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
}
|
||||
|
||||
// GetWithdrawals gets information about all withdrawals
|
||||
func (b *BTCC) GetWithdrawals(currency string, pending bool) {
|
||||
params := make([]interface{}, 0)
|
||||
params = append(params, currency)
|
||||
|
||||
if pending {
|
||||
params = append(params, pending)
|
||||
}
|
||||
|
||||
err := b.SendAuthenticatedHTTPRequest(btccWithdrawals, params)
|
||||
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
}
|
||||
|
||||
// RequestWithdrawal requests a new withdrawal
|
||||
func (b *BTCC) RequestWithdrawal(currency string, amount float64) {
|
||||
params := make([]interface{}, 0)
|
||||
params = append(params, currency)
|
||||
params = append(params, amount)
|
||||
|
||||
err := b.SendAuthenticatedHTTPRequest(btccWithdrawalRequest, params)
|
||||
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
}
|
||||
|
||||
// IcebergOrder intiates a large order but at intervals to preserve orderbook
|
||||
// integrity
|
||||
func (b *BTCC) IcebergOrder(buyOrder bool, price, amount, discAmount, variance float64, symbol string) {
|
||||
params := make([]interface{}, 0)
|
||||
params = append(params, strconv.FormatFloat(price, 'f', -1, 64))
|
||||
params = append(params, strconv.FormatFloat(amount, 'f', -1, 64))
|
||||
params = append(params, strconv.FormatFloat(discAmount, 'f', -1, 64))
|
||||
params = append(params, strconv.FormatFloat(variance, 'f', -1, 64))
|
||||
|
||||
if len(symbol) > 0 {
|
||||
params = append(params, symbol)
|
||||
}
|
||||
|
||||
req := btccIcebergBuy
|
||||
if !buyOrder {
|
||||
req = btccIcebergSell
|
||||
}
|
||||
|
||||
err := b.SendAuthenticatedHTTPRequest(req, params)
|
||||
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
}
|
||||
|
||||
// GetIcebergOrder returns information on your iceberg order
|
||||
func (b *BTCC) GetIcebergOrder(orderID int64, symbol string) {
|
||||
params := make([]interface{}, 0)
|
||||
params = append(params, orderID)
|
||||
|
||||
if len(symbol) > 0 {
|
||||
params = append(params, symbol)
|
||||
}
|
||||
|
||||
err := b.SendAuthenticatedHTTPRequest(btccIcebergOrder, params)
|
||||
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
}
|
||||
|
||||
// GetIcebergOrders returns information on all iceberg orders
|
||||
func (b *BTCC) GetIcebergOrders(limit, offset int64, symbol string) {
|
||||
params := make([]interface{}, 0)
|
||||
|
||||
if limit > 0 {
|
||||
params = append(params, limit)
|
||||
}
|
||||
|
||||
if offset > 0 {
|
||||
params = append(params, offset)
|
||||
}
|
||||
|
||||
if len(symbol) > 0 {
|
||||
params = append(params, symbol)
|
||||
}
|
||||
|
||||
err := b.SendAuthenticatedHTTPRequest(btccIcebergOrders, params)
|
||||
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
}
|
||||
|
||||
// CancelIcebergOrder cancels iceberg order
|
||||
func (b *BTCC) CancelIcebergOrder(orderID int64, symbol string) {
|
||||
params := make([]interface{}, 0)
|
||||
params = append(params, orderID)
|
||||
|
||||
if len(symbol) > 0 {
|
||||
params = append(params, symbol)
|
||||
}
|
||||
|
||||
err := b.SendAuthenticatedHTTPRequest(btccIcebergCancel, params)
|
||||
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
}
|
||||
|
||||
// PlaceStopOrder inserts a stop loss order
|
||||
func (b *BTCC) PlaceStopOrder(buyOder bool, stopPrice, price, amount, trailingAmt, trailingPct float64, symbol string) {
|
||||
params := make([]interface{}, 0)
|
||||
|
||||
if stopPrice > 0 {
|
||||
params = append(params, stopPrice)
|
||||
}
|
||||
|
||||
params = append(params, strconv.FormatFloat(price, 'f', -1, 64))
|
||||
params = append(params, strconv.FormatFloat(amount, 'f', -1, 64))
|
||||
|
||||
if trailingAmt > 0 {
|
||||
params = append(params, strconv.FormatFloat(trailingAmt, 'f', -1, 64))
|
||||
}
|
||||
|
||||
if trailingPct > 0 {
|
||||
params = append(params, strconv.FormatFloat(trailingPct, 'f', -1, 64))
|
||||
}
|
||||
|
||||
if len(symbol) > 0 {
|
||||
params = append(params, symbol)
|
||||
}
|
||||
|
||||
req := btccStoporderBuy
|
||||
if !buyOder {
|
||||
req = btccStoporderSell
|
||||
}
|
||||
|
||||
err := b.SendAuthenticatedHTTPRequest(req, params)
|
||||
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
}
|
||||
|
||||
// GetStopOrder returns a stop order
|
||||
func (b *BTCC) GetStopOrder(orderID int64, symbol string) {
|
||||
params := make([]interface{}, 0)
|
||||
params = append(params, orderID)
|
||||
|
||||
if len(symbol) > 0 {
|
||||
params = append(params, symbol)
|
||||
}
|
||||
|
||||
err := b.SendAuthenticatedHTTPRequest(btccStoporder, params)
|
||||
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
}
|
||||
|
||||
// GetStopOrders returns all stop orders
|
||||
func (b *BTCC) GetStopOrders(status, orderType string, stopPrice float64, limit, offset int64, symbol string) {
|
||||
params := make([]interface{}, 0)
|
||||
|
||||
if len(status) > 0 {
|
||||
params = append(params, status)
|
||||
}
|
||||
|
||||
if len(orderType) > 0 {
|
||||
params = append(params, orderType)
|
||||
}
|
||||
|
||||
if stopPrice > 0 {
|
||||
params = append(params, stopPrice)
|
||||
}
|
||||
|
||||
if limit > 0 {
|
||||
params = append(params, limit)
|
||||
}
|
||||
|
||||
if offset > 0 {
|
||||
params = append(params, limit)
|
||||
}
|
||||
|
||||
if len(symbol) > 0 {
|
||||
params = append(params, symbol)
|
||||
}
|
||||
|
||||
err := b.SendAuthenticatedHTTPRequest(btccStoporders, params)
|
||||
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
}
|
||||
|
||||
// CancelStopOrder cancels a stop order
|
||||
func (b *BTCC) CancelStopOrder(orderID int64, symbol string) {
|
||||
params := make([]interface{}, 0)
|
||||
params = append(params, orderID)
|
||||
|
||||
if len(symbol) > 0 {
|
||||
params = append(params, symbol)
|
||||
}
|
||||
|
||||
err := b.SendAuthenticatedHTTPRequest(btccStoporderCancel, params)
|
||||
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
}
|
||||
|
||||
// SendHTTPRequest sends an unauthenticated HTTP request
|
||||
func (b *BTCC) SendHTTPRequest(path string, result interface{}) error {
|
||||
return b.SendPayload("GET", path, nil, nil, result, false, b.Verbose)
|
||||
}
|
||||
|
||||
// SendAuthenticatedHTTPRequest sends a valid authenticated HTTP request
|
||||
func (b *BTCC) SendAuthenticatedHTTPRequest(method string, params []interface{}) (err error) {
|
||||
if !b.AuthenticatedAPISupport {
|
||||
return fmt.Errorf(exchange.WarningAuthenticatedRequestWithoutCredentialsSet, b.Name)
|
||||
}
|
||||
|
||||
if b.Nonce.Get() == 0 {
|
||||
b.Nonce.Set(time.Now().UnixNano())
|
||||
} else {
|
||||
b.Nonce.Inc()
|
||||
}
|
||||
encoded := fmt.Sprintf("tonce=%s&accesskey=%s&requestmethod=post&id=%d&method=%s¶ms=", b.Nonce.String()[0:16], b.APIKey, 1, method)
|
||||
|
||||
if len(params) == 0 {
|
||||
params = make([]interface{}, 0)
|
||||
} else {
|
||||
items := make([]string, 0)
|
||||
for _, x := range params {
|
||||
xType := fmt.Sprintf("%T", x)
|
||||
switch xType {
|
||||
case "int64", "int":
|
||||
{
|
||||
items = append(items, fmt.Sprintf("%d", x))
|
||||
}
|
||||
case "string":
|
||||
{
|
||||
items = append(items, fmt.Sprintf("%s", x))
|
||||
}
|
||||
case "float64":
|
||||
{
|
||||
items = append(items, fmt.Sprintf("%f", x))
|
||||
}
|
||||
case "bool":
|
||||
{
|
||||
if x == true {
|
||||
items = append(items, "1")
|
||||
} else {
|
||||
items = append(items, "")
|
||||
}
|
||||
}
|
||||
default:
|
||||
{
|
||||
items = append(items, fmt.Sprintf("%v", x))
|
||||
}
|
||||
}
|
||||
}
|
||||
encoded += common.JoinStrings(items, ",")
|
||||
}
|
||||
if b.Verbose {
|
||||
log.Println(encoded)
|
||||
}
|
||||
|
||||
hmac := common.GetHMAC(common.HashSHA1, []byte(encoded), []byte(b.APISecret))
|
||||
postData := make(map[string]interface{})
|
||||
postData["method"] = method
|
||||
postData["params"] = params
|
||||
postData["id"] = 1
|
||||
|
||||
apiURL := fmt.Sprintf("%s/%s", b.APIUrl, btccAPIAuthenticatedMethod)
|
||||
|
||||
data, err := common.JSONEncode(postData)
|
||||
if err != nil {
|
||||
return errors.New("Unable to JSON Marshal POST data")
|
||||
}
|
||||
|
||||
if b.Verbose {
|
||||
log.Printf("Sending POST request to %s calling method %s with params %s\n", apiURL, method, data)
|
||||
}
|
||||
|
||||
headers := make(map[string]string)
|
||||
headers["Content-type"] = "application/json-rpc"
|
||||
headers["Authorization"] = "Basic " + common.Base64Encode([]byte(b.APIKey+":"+common.HexEncodeToString(hmac)))
|
||||
headers["Json-Rpc-Tonce"] = b.Nonce.String()
|
||||
|
||||
return b.SendPayload("POST", apiURL, headers, strings.NewReader(string(data)), nil, true, b.Verbose)
|
||||
}
|
||||
|
||||
@@ -28,8 +28,9 @@ func TestSetup(t *testing.T) {
|
||||
}
|
||||
b.Setup(bConfig)
|
||||
|
||||
if !b.IsEnabled() || b.AuthenticatedAPISupport || b.RESTPollingDelay != time.Duration(10) ||
|
||||
b.Verbose || b.Websocket || len(b.BaseCurrencies) < 1 ||
|
||||
if !b.IsEnabled() || b.AuthenticatedAPISupport ||
|
||||
b.RESTPollingDelay != time.Duration(10) || b.Verbose ||
|
||||
b.Websocket.IsEnabled() || len(b.BaseCurrencies) < 1 ||
|
||||
len(b.AvailablePairs) < 1 || len(b.EnabledPairs) < 1 {
|
||||
t.Error("Test Failed - BTCC Setup values not set correctly")
|
||||
}
|
||||
@@ -41,38 +42,38 @@ func TestGetFee(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetTicker(t *testing.T) {
|
||||
t.Skip()
|
||||
_, err := b.GetTicker("BTCUSD")
|
||||
if err != nil {
|
||||
t.Error("Test failed - GetTicker() error", err)
|
||||
}
|
||||
}
|
||||
// func TestGetTicker(t *testing.T) {
|
||||
// t.Skip()
|
||||
// _, err := b.GetTicker("BTCUSD")
|
||||
// if err != nil {
|
||||
// t.Error("Test failed - GetTicker() error", err)
|
||||
// }
|
||||
// }
|
||||
|
||||
func TestGetTradeHistory(t *testing.T) {
|
||||
t.Skip()
|
||||
_, err := b.GetTradeHistory("BTCUSD", 0, 0, time.Time{})
|
||||
if err != nil {
|
||||
t.Error("Test failed - GetTradeHistory() error", err)
|
||||
}
|
||||
}
|
||||
// func TestGetTradeHistory(t *testing.T) {
|
||||
// t.Skip()
|
||||
// _, err := b.GetTradeHistory("BTCUSD", 0, 0, time.Time{})
|
||||
// if err != nil {
|
||||
// t.Error("Test failed - GetTradeHistory() error", err)
|
||||
// }
|
||||
// }
|
||||
|
||||
func TestGetOrderBook(t *testing.T) {
|
||||
t.Skip()
|
||||
_, err := b.GetOrderBook("BTCUSD", 100)
|
||||
if err != nil {
|
||||
t.Error("Test failed - GetOrderBook() error", err)
|
||||
}
|
||||
_, err = b.GetOrderBook("BTCUSD", 0)
|
||||
if err != nil {
|
||||
t.Error("Test failed - GetOrderBook() error", err)
|
||||
}
|
||||
}
|
||||
// func TestGetOrderBook(t *testing.T) {
|
||||
// t.Skip()
|
||||
// _, err := b.GetOrderBook("BTCUSD", 100)
|
||||
// if err != nil {
|
||||
// t.Error("Test failed - GetOrderBook() error", err)
|
||||
// }
|
||||
// _, err = b.GetOrderBook("BTCUSD", 0)
|
||||
// if err != nil {
|
||||
// t.Error("Test failed - GetOrderBook() error", err)
|
||||
// }
|
||||
// }
|
||||
|
||||
func TestGetAccountInfo(t *testing.T) {
|
||||
t.Skip()
|
||||
err := b.GetAccountInfo("")
|
||||
if err == nil {
|
||||
t.Error("Test failed - GetAccountInfo() error", err)
|
||||
}
|
||||
}
|
||||
// func TestGetAccountInfo(t *testing.T) {
|
||||
// t.Skip()
|
||||
// err := b.GetAccountInfo("")
|
||||
// if err == nil {
|
||||
// t.Error("Test failed - GetAccountInfo() error", err)
|
||||
// }
|
||||
// }
|
||||
|
||||
@@ -1,12 +1,70 @@
|
||||
package btcc
|
||||
|
||||
// Response is the generalized response type
|
||||
type Response struct {
|
||||
Ticker Ticker `json:"ticker"`
|
||||
import "encoding/json"
|
||||
|
||||
// WsAllTickerData defines multiple ticker data
|
||||
type WsAllTickerData []WsTicker
|
||||
|
||||
// WsOutgoing defines outgoing JSON
|
||||
type WsOutgoing struct {
|
||||
Action string `json:"action"`
|
||||
Symbol string `json:"symbol,omitempty"`
|
||||
Count int `json:"count,omitempty"`
|
||||
Len int `json:"len,omitempty"`
|
||||
}
|
||||
|
||||
// Ticker holds basic ticker information
|
||||
type Ticker struct {
|
||||
// WsResponseMain defines the main websocket response
|
||||
type WsResponseMain struct {
|
||||
MsgType string `json:"MsgType"`
|
||||
CRID string `json:"CRID"`
|
||||
RC interface{} `json:"RC"`
|
||||
Reason string `json:"Reason"`
|
||||
Data json.RawMessage `json:"data"`
|
||||
}
|
||||
|
||||
// WsOrderbookSnapshot defines an orderbook from the websocket
|
||||
type WsOrderbookSnapshot struct {
|
||||
Timestamp int64 `json:"Timestamp"`
|
||||
Symbol string `json:"Symbol"`
|
||||
Version int64 `json:"Version"`
|
||||
Type string `json:"Type"`
|
||||
Content string `json:"Content"`
|
||||
List []struct {
|
||||
Side string `json:"Side"`
|
||||
Size interface{} `json:"Size"`
|
||||
Price float64 `json:"Price"`
|
||||
} `json:"List"`
|
||||
MsgType string `json:"MsgType"`
|
||||
}
|
||||
|
||||
// WsOrderbookSnapshotOld defines an old orderbook from the websocket connection
|
||||
type WsOrderbookSnapshotOld struct {
|
||||
MsgType string `json:"MsgType"`
|
||||
Symbol string `json:"Symbol"`
|
||||
Data map[string][]interface{} `json:"Data"`
|
||||
Timestamp int64 `json:"Timestamp"`
|
||||
}
|
||||
|
||||
// WsTrades defines trading data from the websocket
|
||||
type WsTrades struct {
|
||||
Trades []struct {
|
||||
TID int64 `json:"TID"`
|
||||
Timestamp int64 `json:"Timestamp"`
|
||||
Symbol string `json:"Symbol"`
|
||||
Side string `json:"Side"`
|
||||
Size float64 `json:"Size"`
|
||||
Price float64 `json:"Price"`
|
||||
MsgType string `json:"MsgType"`
|
||||
} `json:"Trades"`
|
||||
RC int64 `json:"RC"`
|
||||
CRID string `json:"CRID"`
|
||||
Reason string `json:"Reason"`
|
||||
MsgType string `json:"MsgType"`
|
||||
}
|
||||
|
||||
// WsTicker defines ticker data from the websocket
|
||||
type WsTicker struct {
|
||||
Symbol string `json:"Symbol"`
|
||||
BidPrice float64 `json:"BidPrice"`
|
||||
AskPrice float64 `json:"AskPrice"`
|
||||
Open float64 `json:"Open"`
|
||||
@@ -20,177 +78,5 @@ type Ticker struct {
|
||||
Timestamp int64 `json:"Timestamp"`
|
||||
ExecutionLimitDown float64 `json:"ExecutionLimitDown"`
|
||||
ExecutionLimitUp float64 `json:"ExecutionLimitUp"`
|
||||
}
|
||||
|
||||
// Trade holds executed trade data
|
||||
type Trade struct {
|
||||
ID int64 `json:"Id"`
|
||||
Timestamp int64 `json:"Timestamp"`
|
||||
Price float64 `json:"Price"`
|
||||
Quantity float64 `json:"Quantity"`
|
||||
Side string `json:"Side"`
|
||||
}
|
||||
|
||||
// Orderbook holds orderbook data
|
||||
type Orderbook struct {
|
||||
Bids [][]float64 `json:"bids"`
|
||||
Asks [][]float64 `json:"asks"`
|
||||
Date int64 `json:"date"`
|
||||
}
|
||||
|
||||
// Profile holds profile information
|
||||
type Profile struct {
|
||||
Username string
|
||||
TradePasswordEnabled bool `json:"trade_password_enabled,bool"`
|
||||
OTPEnabled bool `json:"otp_enabled,bool"`
|
||||
TradeFee float64 `json:"trade_fee"`
|
||||
TradeFeeCNYLTC float64 `json:"trade_fee_cnyltc"`
|
||||
TradeFeeBTCLTC float64 `json:"trade_fee_btcltc"`
|
||||
DailyBTCLimit float64 `json:"daily_btc_limit"`
|
||||
DailyLTCLimit float64 `json:"daily_ltc_limit"`
|
||||
BTCDespoitAddress string `json:"btc_despoit_address"`
|
||||
BTCWithdrawalAddress string `json:"btc_withdrawal_address"`
|
||||
LTCDepositAddress string `json:"ltc_deposit_address"`
|
||||
LTCWithdrawalAddress string `json:"ltc_withdrawal_request"`
|
||||
APIKeyPermission int64 `json:"api_key_permission"`
|
||||
}
|
||||
|
||||
// CurrencyGeneric holds currency information
|
||||
type CurrencyGeneric struct {
|
||||
Currency string
|
||||
Symbol string
|
||||
Amount string
|
||||
AmountInt int64 `json:"amount_integer"`
|
||||
AmountDecimal float64 `json:"amount_decimal"`
|
||||
}
|
||||
|
||||
// Order holds order information
|
||||
type Order struct {
|
||||
ID int64
|
||||
Type string
|
||||
Price float64
|
||||
Currency string
|
||||
Amount float64
|
||||
AmountOrig float64 `json:"amount_original"`
|
||||
Date int64
|
||||
Status string
|
||||
Detail OrderDetail
|
||||
}
|
||||
|
||||
// OrderDetail holds order detail information
|
||||
type OrderDetail struct {
|
||||
Dateline int64
|
||||
Price float64
|
||||
Amount float64
|
||||
}
|
||||
|
||||
// Withdrawal holds withdrawal transaction information
|
||||
type Withdrawal struct {
|
||||
ID int64
|
||||
Address string
|
||||
Currency string
|
||||
Amount float64
|
||||
Date int64
|
||||
Transaction string
|
||||
Status string
|
||||
}
|
||||
|
||||
// Deposit holds deposit address information
|
||||
type Deposit struct {
|
||||
ID int64
|
||||
Address string
|
||||
Currency string
|
||||
Amount float64
|
||||
Date int64
|
||||
Status string
|
||||
}
|
||||
|
||||
// BidAsk holds bid and ask information
|
||||
type BidAsk struct {
|
||||
Price float64
|
||||
Amount float64
|
||||
}
|
||||
|
||||
// Depth holds order book depth
|
||||
type Depth struct {
|
||||
Bid []BidAsk
|
||||
Ask []BidAsk
|
||||
}
|
||||
|
||||
// Transaction holds transaction information
|
||||
type Transaction struct {
|
||||
ID int64
|
||||
Type string
|
||||
BTCAmount float64 `json:"btc_amount"`
|
||||
LTCAmount float64 `json:"ltc_amount"`
|
||||
CNYAmount float64 `json:"cny_amount"`
|
||||
Date int64
|
||||
}
|
||||
|
||||
// IcebergOrder holds iceberg lettuce
|
||||
type IcebergOrder struct {
|
||||
ID int64
|
||||
Type string
|
||||
Price float64
|
||||
Market string
|
||||
Amount float64
|
||||
AmountOrig float64 `json:"amount_original"`
|
||||
DisclosedAmount float64 `json:"disclosed_amount"`
|
||||
Variance float64
|
||||
Date int64
|
||||
Status string
|
||||
}
|
||||
|
||||
// StopOrder holds stop order information
|
||||
type StopOrder struct {
|
||||
ID int64
|
||||
Type string
|
||||
StopPrice float64 `json:"stop_price"`
|
||||
TrailingAmt float64 `json:"trailing_amount"`
|
||||
TrailingPct float64 `json:"trailing_percentage"`
|
||||
Price float64
|
||||
Market string
|
||||
Amount float64
|
||||
Date int64
|
||||
Status string
|
||||
OrderID int64 `json:"order_id"`
|
||||
}
|
||||
|
||||
// WebsocketOrder holds websocket order information
|
||||
type WebsocketOrder struct {
|
||||
Price float64 `json:"price"`
|
||||
TotalAmount float64 `json:"totalamount"`
|
||||
Type string `json:"type"`
|
||||
}
|
||||
|
||||
// WebsocketGroupOrder holds websocket group order book information
|
||||
type WebsocketGroupOrder struct {
|
||||
Asks []WebsocketOrder `json:"ask"`
|
||||
Bids []WebsocketOrder `json:"bid"`
|
||||
Market string `json:"market"`
|
||||
}
|
||||
|
||||
// WebsocketTrade holds websocket trade information
|
||||
type WebsocketTrade struct {
|
||||
Amount float64 `json:"amount"`
|
||||
Date float64 `json:"date"`
|
||||
Market string `json:"market"`
|
||||
Price float64 `json:"price"`
|
||||
TradeID float64 `json:"trade_id"`
|
||||
Type string `json:"type"`
|
||||
}
|
||||
|
||||
// WebsocketTicker holds websocket ticker information
|
||||
type WebsocketTicker struct {
|
||||
Buy float64 `json:"buy"`
|
||||
Date float64 `json:"date"`
|
||||
High float64 `json:"high"`
|
||||
Last float64 `json:"last"`
|
||||
Low float64 `json:"low"`
|
||||
Market string `json:"market"`
|
||||
Open float64 `json:"open"`
|
||||
PrevClose float64 `json:"prev_close"`
|
||||
Sell float64 `json:"sell"`
|
||||
Volume float64 `json:"vol"`
|
||||
Vwap float64 `json:"vwap"`
|
||||
MsgType string `json:"MsgType"`
|
||||
}
|
||||
|
||||
@@ -1,125 +1,569 @@
|
||||
package btcc
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strconv"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/gorilla/websocket"
|
||||
"github.com/thrasher-/gocryptotrader/common"
|
||||
"github.com/thrasher-/socketio"
|
||||
"github.com/thrasher-/gocryptotrader/currency/pair"
|
||||
exchange "github.com/thrasher-/gocryptotrader/exchanges"
|
||||
"github.com/thrasher-/gocryptotrader/exchanges/orderbook"
|
||||
)
|
||||
|
||||
const (
|
||||
btccSocketioAddress = "https://websocket.btcc.com"
|
||||
btccSocketioAddress = "wss://ws.btcc.com"
|
||||
|
||||
msgTypeHeartBeat = "Heartbeat"
|
||||
msgTypeGetActiveContracts = "GetActiveContractsResponse"
|
||||
msgTypeQuote = "QuoteResponse"
|
||||
msgTypeLogin = "LoginResponse"
|
||||
msgTypeAccountInfo = "AccountInfo"
|
||||
msgTypeExecReport = "ExecReport"
|
||||
msgTypePlaceOrder = "PlaceOrderResponse"
|
||||
msgTypeCancelAllOrders = "CancelAllOrdersResponse"
|
||||
msgTypeCancelOrder = "CancelOrderResponse"
|
||||
msgTypeCancelReplaceOrder = "CancelReplaceOrderResponse"
|
||||
msgTypeGetAccountInfo = "GetAccountInfoResponse"
|
||||
msgTypeRetrieveOrder = "RetrieveOrderResponse"
|
||||
msgTypeGetTrades = "GetTradesResponse"
|
||||
|
||||
msgTypeAllTickers = "AllTickersResponse"
|
||||
)
|
||||
|
||||
// BTCCSocket is a pointer to a IO socket
|
||||
var BTCCSocket *socketio.SocketIO
|
||||
var (
|
||||
mtx sync.Mutex
|
||||
)
|
||||
|
||||
// OnConnect gets information from the server when its connected
|
||||
func (b *BTCC) OnConnect(output chan socketio.Message) {
|
||||
if b.Verbose {
|
||||
log.Printf("%s Connected to Websocket.", b.GetName())
|
||||
// WsConnect initiates a websocket client connection
|
||||
func (b *BTCC) WsConnect() error {
|
||||
if !b.Websocket.IsEnabled() || !b.IsEnabled() {
|
||||
return errors.New(exchange.WebsocketNotEnabled)
|
||||
}
|
||||
|
||||
currencies := []string{}
|
||||
for _, x := range b.EnabledPairs {
|
||||
currency := common.StringToLower(x[3:] + x[0:3])
|
||||
currencies = append(currencies, currency)
|
||||
}
|
||||
endpoints := []string{"marketdata", "grouporder"}
|
||||
var dialer websocket.Dialer
|
||||
var err error
|
||||
|
||||
for _, x := range endpoints {
|
||||
for _, y := range currencies {
|
||||
channel := fmt.Sprintf(`"%s_%s"`, x, y)
|
||||
if b.Verbose {
|
||||
log.Printf("%s Websocket subscribing to channel: %s.", b.GetName(), channel)
|
||||
if b.Websocket.GetProxyAddress() != "" {
|
||||
prxy, err := url.Parse(b.Websocket.GetProxyAddress())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
dialer.Proxy = http.ProxyURL(prxy)
|
||||
}
|
||||
|
||||
b.Conn, _, err = dialer.Dial(b.Websocket.GetWebsocketURL(), http.Header{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = b.WsUpdateCurrencyPairs()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
go b.WsReadData()
|
||||
go b.WsHandleData()
|
||||
|
||||
err = b.WsSubscribeToOrderbook()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = b.WsSubcribeToTicker()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return b.WsSubcribeToTrades()
|
||||
}
|
||||
|
||||
// WsReadData reads data from the websocket connection
|
||||
func (b *BTCC) WsReadData() {
|
||||
b.Websocket.Wg.Add(1)
|
||||
defer b.Websocket.Wg.Done()
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-b.Websocket.ShutdownC:
|
||||
return
|
||||
|
||||
default:
|
||||
mtx.Lock()
|
||||
_, resp, err := b.Conn.ReadMessage()
|
||||
mtx.Unlock()
|
||||
if err != nil {
|
||||
b.Websocket.DataHandler <- err
|
||||
}
|
||||
|
||||
b.Websocket.TrafficAlert <- struct{}{}
|
||||
|
||||
b.Websocket.Intercomm <- exchange.WebsocketResponse{
|
||||
Raw: resp,
|
||||
}
|
||||
output <- socketio.CreateMessageEvent("subscribe", channel, b.OnMessage, BTCCSocket.Version)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// OnDisconnect alerts when disconnection occurs
|
||||
func (b *BTCC) OnDisconnect(output chan socketio.Message) {
|
||||
log.Printf("%s Disconnected from websocket server.. Reconnecting.\n", b.GetName())
|
||||
b.WebsocketClient()
|
||||
}
|
||||
// WsHandleData handles read data
|
||||
func (b *BTCC) WsHandleData() {
|
||||
b.Websocket.Wg.Add(1)
|
||||
defer b.Websocket.Wg.Done()
|
||||
|
||||
// OnError alerts when error occurs
|
||||
func (b *BTCC) OnError() {
|
||||
log.Printf("%s Error with Websocket connection.. Reconnecting.\n", b.GetName())
|
||||
b.WebsocketClient()
|
||||
}
|
||||
for {
|
||||
select {
|
||||
case <-b.Websocket.ShutdownC:
|
||||
return
|
||||
|
||||
// OnMessage if message received and verbose it is printed out
|
||||
func (b *BTCC) OnMessage(message []byte, output chan socketio.Message) {
|
||||
if b.Verbose {
|
||||
log.Printf("%s Websocket message received which isn't handled by default.\n", b.GetName())
|
||||
log.Println(string(message))
|
||||
case resp := <-b.Websocket.Intercomm:
|
||||
var Result WsResponseMain
|
||||
err := common.JSONDecode(resp.Raw, &Result)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
switch Result.MsgType {
|
||||
case msgTypeHeartBeat:
|
||||
|
||||
case msgTypeGetActiveContracts:
|
||||
log.Println("Active Contracts")
|
||||
log.Fatal(string(resp.Raw))
|
||||
|
||||
case msgTypeQuote:
|
||||
log.Println("Quotes")
|
||||
log.Fatal(string(resp.Raw))
|
||||
|
||||
case msgTypeLogin:
|
||||
log.Println("Login")
|
||||
log.Fatal(string(resp.Raw))
|
||||
|
||||
case msgTypeAccountInfo:
|
||||
log.Println("Account info")
|
||||
log.Fatal(string(resp.Raw))
|
||||
|
||||
case msgTypeExecReport:
|
||||
log.Println("Exec Report")
|
||||
log.Fatal(string(resp.Raw))
|
||||
|
||||
case msgTypePlaceOrder:
|
||||
log.Println("Place order")
|
||||
log.Fatal(string(resp.Raw))
|
||||
|
||||
case msgTypeCancelAllOrders:
|
||||
log.Println("Cancel All orders")
|
||||
log.Fatal(string(resp.Raw))
|
||||
|
||||
case msgTypeCancelOrder:
|
||||
log.Println("Cancel order")
|
||||
log.Fatal(string(resp.Raw))
|
||||
|
||||
case msgTypeCancelReplaceOrder:
|
||||
log.Println("Replace order")
|
||||
log.Fatal(string(resp.Raw))
|
||||
|
||||
case msgTypeGetAccountInfo:
|
||||
log.Println("Account info")
|
||||
log.Fatal(string(resp.Raw))
|
||||
|
||||
case msgTypeRetrieveOrder:
|
||||
log.Println("Retrieve order")
|
||||
log.Fatal(string(resp.Raw))
|
||||
|
||||
case msgTypeGetTrades:
|
||||
var trades WsTrades
|
||||
|
||||
err := common.JSONDecode(resp.Raw, &trades)
|
||||
if err != nil {
|
||||
b.Websocket.DataHandler <- err
|
||||
continue
|
||||
}
|
||||
|
||||
case "OrderBook":
|
||||
// NOTE: This seems to be a websocket update not reflected in
|
||||
// current API docs, this comes in conjunction with the other
|
||||
// orderbook feeds
|
||||
var orderbook WsOrderbookSnapshot
|
||||
|
||||
err := common.JSONDecode(resp.Raw, &orderbook)
|
||||
if err != nil {
|
||||
b.Websocket.DataHandler <- err
|
||||
continue
|
||||
}
|
||||
|
||||
switch orderbook.Type {
|
||||
case "F":
|
||||
err = b.WsProcessOrderbookSnapshot(orderbook)
|
||||
if err != nil {
|
||||
b.Websocket.DataHandler <- err
|
||||
}
|
||||
|
||||
case "I":
|
||||
err = b.WsProcessOrderbookUpdate(orderbook)
|
||||
if err != nil {
|
||||
b.Websocket.DataHandler <- err
|
||||
}
|
||||
}
|
||||
|
||||
case "SubOrderBookResponse":
|
||||
|
||||
case "Ticker":
|
||||
var ticker WsTicker
|
||||
|
||||
err = common.JSONDecode(resp.Raw, &ticker)
|
||||
if err != nil {
|
||||
b.Websocket.DataHandler <- err
|
||||
continue
|
||||
}
|
||||
|
||||
tick := exchange.TickerData{}
|
||||
tick.AssetType = "SPOT"
|
||||
tick.ClosePrice = ticker.PrevCls
|
||||
tick.Exchange = b.GetName()
|
||||
tick.HighPrice = ticker.High
|
||||
tick.LowPrice = ticker.Low
|
||||
tick.OpenPrice = ticker.Open
|
||||
tick.Pair = pair.NewCurrencyPairFromString(ticker.Symbol)
|
||||
tick.Quantity = ticker.Volume
|
||||
timestamp := time.Unix(ticker.Timestamp, 0)
|
||||
tick.Timestamp = timestamp
|
||||
|
||||
b.Websocket.DataHandler <- tick
|
||||
|
||||
default:
|
||||
|
||||
if common.StringContains(Result.MsgType, "OrderBook") {
|
||||
var oldOrderbookType WsOrderbookSnapshotOld
|
||||
err = common.JSONDecode(resp.Raw, &oldOrderbookType)
|
||||
if err != nil {
|
||||
b.Websocket.DataHandler <- err
|
||||
continue
|
||||
}
|
||||
|
||||
symbol := common.SplitStrings(Result.MsgType, ".")
|
||||
err = b.WsProcessOldOrderbookSnapshot(oldOrderbookType, symbol[1])
|
||||
if err != nil {
|
||||
b.Websocket.DataHandler <- err
|
||||
continue
|
||||
}
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// OnTicker handles ticker information
|
||||
func (b *BTCC) OnTicker(message []byte, output chan socketio.Message) {
|
||||
type Response struct {
|
||||
Ticker WebsocketTicker `json:"ticker"`
|
||||
}
|
||||
var resp Response
|
||||
err := common.JSONDecode(message, &resp)
|
||||
// WsSubscribeAllTickers subscribes to a ticker channel
|
||||
func (b *BTCC) WsSubscribeAllTickers() error {
|
||||
mtx.Lock()
|
||||
defer mtx.Unlock()
|
||||
|
||||
return b.Conn.WriteJSON(WsOutgoing{
|
||||
Action: "SubscribeAllTickers",
|
||||
})
|
||||
}
|
||||
|
||||
// WsUnSubscribeAllTickers unsubscribes from a ticker channel
|
||||
func (b *BTCC) WsUnSubscribeAllTickers() error {
|
||||
mtx.Lock()
|
||||
defer mtx.Unlock()
|
||||
|
||||
return b.Conn.WriteJSON(WsOutgoing{
|
||||
Action: "UnSubscribeAllTickers",
|
||||
})
|
||||
}
|
||||
|
||||
// WsUpdateCurrencyPairs updates currency pairs from the websocket connection
|
||||
func (b *BTCC) WsUpdateCurrencyPairs() error {
|
||||
err := b.WsSubscribeAllTickers()
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// OnGroupOrder handles group order information
|
||||
func (b *BTCC) OnGroupOrder(message []byte, output chan socketio.Message) {
|
||||
type Response struct {
|
||||
GroupOrder WebsocketGroupOrder `json:"grouporder"`
|
||||
}
|
||||
var resp Response
|
||||
err := common.JSONDecode(message, &resp)
|
||||
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// OnTrade handles group trade information
|
||||
func (b *BTCC) OnTrade(message []byte, output chan socketio.Message) {
|
||||
trade := WebsocketTrade{}
|
||||
err := common.JSONDecode(message, &trade)
|
||||
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// WebsocketClient initiates a websocket client
|
||||
func (b *BTCC) WebsocketClient() {
|
||||
events := make(map[string]func(message []byte, output chan socketio.Message))
|
||||
events["grouporder"] = b.OnGroupOrder
|
||||
events["ticker"] = b.OnTicker
|
||||
events["trade"] = b.OnTrade
|
||||
|
||||
BTCCSocket = &socketio.SocketIO{
|
||||
Version: 1,
|
||||
OnConnect: b.OnConnect,
|
||||
OnEvent: events,
|
||||
OnError: b.OnError,
|
||||
OnMessage: b.OnMessage,
|
||||
OnDisconnect: b.OnDisconnect,
|
||||
return err
|
||||
}
|
||||
|
||||
for b.Enabled && b.Websocket {
|
||||
err := socketio.ConnectToSocket(btccSocketioAddress, BTCCSocket)
|
||||
var currencyResponse WsResponseMain
|
||||
for {
|
||||
_, resp, err := b.Conn.ReadMessage()
|
||||
if err != nil {
|
||||
log.Printf("%s Unable to connect to Websocket. Err: %s\n", b.GetName(), err)
|
||||
return err
|
||||
}
|
||||
|
||||
b.Websocket.TrafficAlert <- struct{}{}
|
||||
|
||||
err = common.JSONDecode(resp, ¤cyResponse)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
switch currencyResponse.MsgType {
|
||||
case msgTypeAllTickers:
|
||||
var tickers WsAllTickerData
|
||||
err := common.JSONDecode(currencyResponse.Data, &tickers)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var availableTickers []string
|
||||
for _, tickerData := range tickers {
|
||||
availableTickers = append(availableTickers, tickerData.Symbol)
|
||||
}
|
||||
|
||||
err = b.UpdateCurrencies(availableTickers, false, true)
|
||||
if err != nil {
|
||||
return fmt.Errorf("%s failed to update available currencies. %s",
|
||||
b.Name,
|
||||
err)
|
||||
}
|
||||
|
||||
return b.WsUnSubscribeAllTickers()
|
||||
|
||||
case "Heartbeat":
|
||||
|
||||
default:
|
||||
return fmt.Errorf("btcc_websocket.go error - Updating currency pairs resp incorrect: %s",
|
||||
string(resp))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// WsSubscribeToOrderbook subscribes to an orderbook channel
|
||||
func (b *BTCC) WsSubscribeToOrderbook() error {
|
||||
mtx.Lock()
|
||||
defer mtx.Unlock()
|
||||
|
||||
for _, pair := range b.GetEnabledCurrencies() {
|
||||
formattedPair := exchange.FormatExchangeCurrency(b.GetName(), pair)
|
||||
err := b.Conn.WriteJSON(WsOutgoing{
|
||||
Action: "SubOrderBook",
|
||||
Symbol: formattedPair.String(),
|
||||
Len: 100})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// WsSubcribeToTicker subscribes to a ticker channel
|
||||
func (b *BTCC) WsSubcribeToTicker() error {
|
||||
mtx.Lock()
|
||||
defer mtx.Unlock()
|
||||
|
||||
for _, pair := range b.GetEnabledCurrencies() {
|
||||
formattedPair := exchange.FormatExchangeCurrency(b.GetName(), pair)
|
||||
err := b.Conn.WriteJSON(WsOutgoing{
|
||||
Action: "Subscribe",
|
||||
Symbol: formattedPair.String(),
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// WsSubcribeToTrades subscribes to a trade channel
|
||||
func (b *BTCC) WsSubcribeToTrades() error {
|
||||
mtx.Lock()
|
||||
defer mtx.Unlock()
|
||||
|
||||
for _, pair := range b.GetEnabledCurrencies() {
|
||||
formattedPair := exchange.FormatExchangeCurrency(b.GetName(), pair)
|
||||
err := b.Conn.WriteJSON(WsOutgoing{
|
||||
Action: "GetTrades",
|
||||
Symbol: formattedPair.String(),
|
||||
Count: 100,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// WsProcessOrderbookSnapshot processes a new orderbook snapshot
|
||||
func (b *BTCC) WsProcessOrderbookSnapshot(ob WsOrderbookSnapshot) error {
|
||||
var asks, bids []orderbook.Item
|
||||
for _, data := range ob.List {
|
||||
var newSize float64
|
||||
switch data.Size.(type) {
|
||||
case float64:
|
||||
newSize = data.Size.(float64)
|
||||
case string:
|
||||
var err error
|
||||
newSize, err = strconv.ParseFloat(data.Size.(string), 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if data.Side == "1" {
|
||||
asks = append(asks, orderbook.Item{Price: data.Price, Amount: newSize})
|
||||
continue
|
||||
}
|
||||
log.Printf("%s Disconnected from Websocket.\n", b.GetName())
|
||||
|
||||
bids = append(bids, orderbook.Item{Price: data.Price, Amount: newSize})
|
||||
}
|
||||
|
||||
var newOrderbook orderbook.Base
|
||||
|
||||
newOrderbook.Asks = asks
|
||||
newOrderbook.AssetType = "SPOT"
|
||||
newOrderbook.Bids = bids
|
||||
newOrderbook.CurrencyPair = ob.Symbol
|
||||
newOrderbook.LastUpdated = time.Now()
|
||||
newOrderbook.Pair = pair.NewCurrencyPairFromString(ob.Symbol)
|
||||
|
||||
err := b.Websocket.Orderbook.LoadSnapshot(newOrderbook, b.GetName())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
b.Websocket.DataHandler <- exchange.WebsocketOrderbookUpdate{
|
||||
Exchange: b.GetName(),
|
||||
Asset: "SPOT",
|
||||
Pair: pair.NewCurrencyPairFromString(ob.Symbol),
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// WsProcessOrderbookUpdate processes an orderbook update
|
||||
func (b *BTCC) WsProcessOrderbookUpdate(ob WsOrderbookSnapshot) error {
|
||||
var asks, bids []orderbook.Item
|
||||
for _, data := range ob.List {
|
||||
var newSize float64
|
||||
switch data.Size.(type) {
|
||||
case float64:
|
||||
newSize = data.Size.(float64)
|
||||
case string:
|
||||
var err error
|
||||
newSize, err = strconv.ParseFloat(data.Size.(string), 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if data.Side == "1" {
|
||||
if newSize < 0 {
|
||||
asks = append(asks, orderbook.Item{Price: data.Price, Amount: 0})
|
||||
continue
|
||||
}
|
||||
asks = append(asks, orderbook.Item{Price: data.Price, Amount: newSize})
|
||||
continue
|
||||
}
|
||||
|
||||
if newSize < 0 {
|
||||
bids = append(bids, orderbook.Item{Price: data.Price, Amount: 0})
|
||||
continue
|
||||
}
|
||||
|
||||
bids = append(bids, orderbook.Item{Price: data.Price, Amount: newSize})
|
||||
}
|
||||
|
||||
p := pair.NewCurrencyPairFromString(ob.Symbol)
|
||||
|
||||
err := b.Websocket.Orderbook.Update(bids, asks, p, time.Now(), b.GetName(), "SPOT")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
b.Websocket.DataHandler <- exchange.WebsocketOrderbookUpdate{
|
||||
Exchange: b.GetName(),
|
||||
Asset: "SPOT",
|
||||
Pair: pair.NewCurrencyPairFromString(ob.Symbol),
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// WsProcessOldOrderbookSnapshot processes an old orderbook snapshot
|
||||
func (b *BTCC) WsProcessOldOrderbookSnapshot(ob WsOrderbookSnapshotOld, symbol string) error {
|
||||
var asks, bids []orderbook.Item
|
||||
|
||||
askData, _ := ob.Data["Asks"]
|
||||
bidData, _ := ob.Data["Bids"]
|
||||
|
||||
for _, ask := range askData {
|
||||
data := ask.([]interface{})
|
||||
var price, amount float64
|
||||
|
||||
switch data[0].(type) {
|
||||
case string:
|
||||
var err error
|
||||
price, err = strconv.ParseFloat(data[0].(string), 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
case float64:
|
||||
price = data[0].(float64)
|
||||
}
|
||||
|
||||
switch data[0].(type) {
|
||||
case string:
|
||||
var err error
|
||||
amount, err = strconv.ParseFloat(data[0].(string), 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
case float64:
|
||||
amount = data[0].(float64)
|
||||
}
|
||||
|
||||
asks = append(asks, orderbook.Item{
|
||||
Price: price,
|
||||
Amount: amount,
|
||||
})
|
||||
}
|
||||
|
||||
for _, bid := range bidData {
|
||||
data := bid.([]interface{})
|
||||
var price, amount float64
|
||||
|
||||
switch data[1].(type) {
|
||||
case string:
|
||||
var err error
|
||||
price, err = strconv.ParseFloat(data[1].(string), 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
case float64:
|
||||
price = data[1].(float64)
|
||||
}
|
||||
|
||||
switch data[1].(type) {
|
||||
case string:
|
||||
var err error
|
||||
amount, err = strconv.ParseFloat(data[1].(string), 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
case float64:
|
||||
amount = data[1].(float64)
|
||||
}
|
||||
|
||||
bids = append(bids, orderbook.Item{
|
||||
Price: price,
|
||||
Amount: amount,
|
||||
})
|
||||
}
|
||||
|
||||
p := pair.NewCurrencyPairFromString(symbol)
|
||||
|
||||
err := b.Websocket.Orderbook.Update(bids, asks, p, time.Now(), b.GetName(), "SPOT")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
b.Websocket.DataHandler <- exchange.WebsocketOrderbookUpdate{
|
||||
Exchange: b.GetName(),
|
||||
Pair: p,
|
||||
Asset: "SPOT",
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -25,15 +25,11 @@ func (b *BTCC) Start(wg *sync.WaitGroup) {
|
||||
// Run implements the BTCC wrapper
|
||||
func (b *BTCC) Run() {
|
||||
if b.Verbose {
|
||||
log.Printf("%s Websocket: %s.", b.GetName(), common.IsEnabled(b.Websocket))
|
||||
log.Printf("%s Websocket: %s.", b.GetName(), common.IsEnabled(b.Websocket.IsEnabled()))
|
||||
log.Printf("%s polling delay: %ds.\n", b.GetName(), b.RESTPollingDelay)
|
||||
log.Printf("%s %d currencies enabled: %s.\n", b.GetName(), len(b.EnabledPairs), b.EnabledPairs)
|
||||
}
|
||||
|
||||
if b.Websocket {
|
||||
go b.WebsocketClient()
|
||||
}
|
||||
|
||||
if common.StringDataContains(b.EnabledPairs, "CNY") || common.StringDataContains(b.AvailablePairs, "CNY") || common.StringDataContains(b.BaseCurrencies, "CNY") {
|
||||
log.Println("WARNING: BTCC only supports BTCUSD now, upgrading available, enabled and base currencies to BTCUSD/USD")
|
||||
pairs := []string{"BTCUSD"}
|
||||
@@ -69,82 +65,89 @@ func (b *BTCC) Run() {
|
||||
|
||||
// UpdateTicker updates and returns the ticker for a currency pair
|
||||
func (b *BTCC) UpdateTicker(p pair.CurrencyPair, assetType string) (ticker.Price, error) {
|
||||
var tickerPrice ticker.Price
|
||||
tick, err := b.GetTicker(exchange.FormatExchangeCurrency(b.GetName(), p).String())
|
||||
if err != nil {
|
||||
return tickerPrice, err
|
||||
}
|
||||
tickerPrice.Pair = p
|
||||
tickerPrice.Ask = tick.AskPrice
|
||||
tickerPrice.Bid = tick.BidPrice
|
||||
tickerPrice.Low = tick.Low
|
||||
tickerPrice.Last = tick.Last
|
||||
tickerPrice.Volume = tick.Volume24H
|
||||
tickerPrice.High = tick.High
|
||||
ticker.ProcessTicker(b.GetName(), p, tickerPrice, assetType)
|
||||
return ticker.GetTicker(b.Name, p, assetType)
|
||||
// var tickerPrice ticker.Price
|
||||
// tick, err := b.GetTicker(exchange.FormatExchangeCurrency(b.GetName(), p).String())
|
||||
// if err != nil {
|
||||
// return tickerPrice, err
|
||||
// }
|
||||
// tickerPrice.Pair = p
|
||||
// tickerPrice.Ask = tick.AskPrice
|
||||
// tickerPrice.Bid = tick.BidPrice
|
||||
// tickerPrice.Low = tick.Low
|
||||
// tickerPrice.Last = tick.Last
|
||||
// tickerPrice.Volume = tick.Volume24H
|
||||
// tickerPrice.High = tick.High
|
||||
// ticker.ProcessTicker(b.GetName(), p, tickerPrice, assetType)
|
||||
// return ticker.GetTicker(b.Name, p, assetType)
|
||||
return ticker.Price{}, errors.New("REST NOT SUPPORTED")
|
||||
}
|
||||
|
||||
// GetTickerPrice returns the ticker for a currency pair
|
||||
func (b *BTCC) GetTickerPrice(p pair.CurrencyPair, assetType string) (ticker.Price, error) {
|
||||
tickerNew, err := ticker.GetTicker(b.GetName(), p, assetType)
|
||||
if err != nil {
|
||||
return b.UpdateTicker(p, assetType)
|
||||
}
|
||||
return tickerNew, nil
|
||||
// tickerNew, err := ticker.GetTicker(b.GetName(), p, assetType)
|
||||
// if err != nil {
|
||||
// return b.UpdateTicker(p, assetType)
|
||||
// }
|
||||
// return tickerNew, nil
|
||||
return ticker.Price{}, errors.New("REST NOT SUPPORTED")
|
||||
}
|
||||
|
||||
// GetOrderbookEx returns the orderbook for a currency pair
|
||||
func (b *BTCC) GetOrderbookEx(p pair.CurrencyPair, assetType string) (orderbook.Base, error) {
|
||||
ob, err := orderbook.GetOrderbook(b.GetName(), p, assetType)
|
||||
if err != nil {
|
||||
return b.UpdateOrderbook(p, assetType)
|
||||
}
|
||||
return ob, nil
|
||||
// ob, err := orderbook.GetOrderbook(b.GetName(), p, assetType)
|
||||
// if err != nil {
|
||||
// return b.UpdateOrderbook(p, assetType)
|
||||
// }
|
||||
// return ob, nil
|
||||
return orderbook.Base{}, errors.New("REST NOT SUPPORTED")
|
||||
}
|
||||
|
||||
// UpdateOrderbook updates and returns the orderbook for a currency pair
|
||||
func (b *BTCC) UpdateOrderbook(p pair.CurrencyPair, assetType string) (orderbook.Base, error) {
|
||||
var orderBook orderbook.Base
|
||||
orderbookNew, err := b.GetOrderBook(exchange.FormatExchangeCurrency(b.GetName(), p).String(), 100)
|
||||
if err != nil {
|
||||
return orderBook, err
|
||||
}
|
||||
// var orderBook orderbook.Base
|
||||
// orderbookNew, err := b.GetOrderBook(exchange.FormatExchangeCurrency(b.GetName(), p).String(), 100)
|
||||
// if err != nil {
|
||||
// return orderBook, err
|
||||
// }
|
||||
|
||||
for x := range orderbookNew.Bids {
|
||||
data := orderbookNew.Bids[x]
|
||||
orderBook.Bids = append(orderBook.Bids, orderbook.Item{Price: data[0], Amount: data[1]})
|
||||
}
|
||||
// for x := range orderbookNew.Bids {
|
||||
// data := orderbookNew.Bids[x]
|
||||
// orderBook.Bids = append(orderBook.Bids, orderbook.Item{Price: data[0], Amount: data[1]})
|
||||
// }
|
||||
|
||||
for x := range orderbookNew.Asks {
|
||||
data := orderbookNew.Asks[x]
|
||||
orderBook.Asks = append(orderBook.Asks, orderbook.Item{Price: data[0], Amount: data[1]})
|
||||
}
|
||||
// for x := range orderbookNew.Asks {
|
||||
// data := orderbookNew.Asks[x]
|
||||
// orderBook.Asks = append(orderBook.Asks, orderbook.Item{Price: data[0], Amount: data[1]})
|
||||
// }
|
||||
|
||||
orderbook.ProcessOrderbook(b.GetName(), p, orderBook, assetType)
|
||||
return orderbook.GetOrderbook(b.Name, p, assetType)
|
||||
// orderbook.ProcessOrderbook(b.GetName(), p, orderBook, assetType)
|
||||
// return orderbook.GetOrderbook(b.Name, p, assetType)
|
||||
return orderbook.Base{}, errors.New("REST NOT SUPPORTED")
|
||||
}
|
||||
|
||||
// GetExchangeAccountInfo : Retrieves balances for all enabled currencies for
|
||||
// the Kraken exchange - TODO
|
||||
func (b *BTCC) GetExchangeAccountInfo() (exchange.AccountInfo, error) {
|
||||
var response exchange.AccountInfo
|
||||
response.ExchangeName = b.GetName()
|
||||
return response, nil
|
||||
// var response exchange.AccountInfo
|
||||
// response.ExchangeName = b.GetName()
|
||||
// return response, nil
|
||||
return exchange.AccountInfo{}, errors.New("REST NOT SUPPORTED")
|
||||
}
|
||||
|
||||
// GetExchangeFundTransferHistory returns funding history, deposits and
|
||||
// withdrawals
|
||||
func (b *BTCC) GetExchangeFundTransferHistory() ([]exchange.FundHistory, error) {
|
||||
var fundHistory []exchange.FundHistory
|
||||
return fundHistory, errors.New("not supported on exchange")
|
||||
// var fundHistory []exchange.FundHistory
|
||||
// return fundHistory, errors.New("not supported on exchange")
|
||||
return nil, errors.New("REST NOT SUPPORTED")
|
||||
}
|
||||
|
||||
// GetExchangeHistory returns historic trade data since exchange opening.
|
||||
func (b *BTCC) GetExchangeHistory(p pair.CurrencyPair, assetType string) ([]exchange.TradeHistory, error) {
|
||||
var resp []exchange.TradeHistory
|
||||
// var resp []exchange.TradeHistory
|
||||
|
||||
return resp, errors.New("trade history not yet implemented")
|
||||
// return resp, errors.New("trade history not yet implemented")
|
||||
return nil, errors.New("REST NOT SUPPORTED")
|
||||
}
|
||||
|
||||
// SubmitExchangeOrder submits a new order
|
||||
@@ -196,3 +199,8 @@ func (b *BTCC) WithdrawFiatExchangeFunds(currency pair.CurrencyItem, amount floa
|
||||
func (b *BTCC) WithdrawFiatExchangeFundsToInternationalBank(currency pair.CurrencyItem, amount float64) (string, error) {
|
||||
return "", errors.New("not yet implemented")
|
||||
}
|
||||
|
||||
// GetWebsocket returns a pointer to the exchange websocket
|
||||
func (b *BTCC) GetWebsocket() (*exchange.Websocket, error) {
|
||||
return b.Websocket, nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user