mirror of
https://github.com/d0zingcat/gocryptotrader.git
synced 2026-05-13 23:16:45 +00:00
Add Exchange: HitBTC
This commit is contained in:
@@ -10,4 +10,5 @@ Manuel Kreutz - 140am
|
||||
libsora.so - if1live
|
||||
Tong - tongxiaofeng
|
||||
Jamie Cheng - starit
|
||||
Jake - snipesjr
|
||||
Jake - snipesjr
|
||||
Bret Palsson - bretep
|
||||
@@ -30,6 +30,7 @@ Join our slack to discuss all things related to GoCryptoTrader! [GoCryptoTrader
|
||||
| COINUT | Yes | No | NA |
|
||||
| GDAX(Coinbase) | Yes | Yes | No|
|
||||
| Gemini | Yes | NA | NA |
|
||||
| HitBTC | Yes | Yes | NA |
|
||||
| Huobi.Pro | Yes | No |No |
|
||||
| ItBit | Yes | NA | NA |
|
||||
| Kraken | Yes | NA | NA |
|
||||
|
||||
@@ -89,7 +89,7 @@ func TestGetEnabledExchanges(t *testing.T) {
|
||||
}
|
||||
|
||||
exchanges := cfg.GetEnabledExchanges()
|
||||
if len(exchanges) != 23 {
|
||||
if len(exchanges) != 24 {
|
||||
t.Error(
|
||||
"Test failed. TestGetEnabledExchanges. Enabled exchanges value mismatch",
|
||||
)
|
||||
@@ -141,7 +141,7 @@ func TestGetDisabledExchanges(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestCountEnabledExchanges(t *testing.T) {
|
||||
defaultEnabledExchanges := 23
|
||||
defaultEnabledExchanges := 24
|
||||
GetConfigEnabledExchanges := GetConfig()
|
||||
err := GetConfigEnabledExchanges.LoadConfig(ConfigTestFile)
|
||||
if err != nil {
|
||||
|
||||
@@ -298,6 +298,27 @@
|
||||
"Uppercase": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"Name": "HitBTC",
|
||||
"Enabled": true,
|
||||
"Verbose": false,
|
||||
"Websocket": false,
|
||||
"UseSandbox": false,
|
||||
"RESTPollingDelay": 10,
|
||||
"AuthenticatedAPISupport": false,
|
||||
"APIKey": "Key",
|
||||
"APISecret": "Secret",
|
||||
"AvailablePairs": "BTCUSD,ETHBTC,ETHUSD",
|
||||
"EnabledPairs": "BTCUSD",
|
||||
"BaseCurrencies": "USD",
|
||||
"AssetTypes": "SPOT",
|
||||
"ConfigCurrencyPairFormat": {
|
||||
"Uppercase": true
|
||||
},
|
||||
"RequestCurrencyPairFormat": {
|
||||
"Uppercase": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"Name": "Huobi",
|
||||
"Enabled": true,
|
||||
|
||||
@@ -17,6 +17,7 @@ import (
|
||||
"github.com/thrasher-/gocryptotrader/exchanges/coinut"
|
||||
"github.com/thrasher-/gocryptotrader/exchanges/gdax"
|
||||
"github.com/thrasher-/gocryptotrader/exchanges/gemini"
|
||||
"github.com/thrasher-/gocryptotrader/exchanges/hitbtc"
|
||||
"github.com/thrasher-/gocryptotrader/exchanges/huobi"
|
||||
"github.com/thrasher-/gocryptotrader/exchanges/itbit"
|
||||
"github.com/thrasher-/gocryptotrader/exchanges/kraken"
|
||||
@@ -150,6 +151,8 @@ func LoadExchange(name string) error {
|
||||
exch = new(gdax.GDAX)
|
||||
case "gemini":
|
||||
exch = new(gemini.Gemini)
|
||||
case "hitbtc":
|
||||
exch = new(hitbtc.HitBTC)
|
||||
case "huobi":
|
||||
exch = new(huobi.HUOBI)
|
||||
case "itbit":
|
||||
|
||||
507
exchanges/hitbtc/hitbtc.go
Normal file
507
exchanges/hitbtc/hitbtc.go
Normal file
@@ -0,0 +1,507 @@
|
||||
package hitbtc
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"log"
|
||||
"net/url"
|
||||
"strconv"
|
||||
|
||||
"github.com/thrasher-/gocryptotrader/common"
|
||||
"github.com/thrasher-/gocryptotrader/config"
|
||||
"github.com/thrasher-/gocryptotrader/exchanges"
|
||||
"github.com/thrasher-/gocryptotrader/exchanges/ticker"
|
||||
)
|
||||
|
||||
const (
|
||||
// API
|
||||
APIURL = "https://api.hitbtc.com"
|
||||
|
||||
// Public
|
||||
APIv2Trades = "api/2/public/trades"
|
||||
APIv2Currency = "api/2/public/currency"
|
||||
APIv2Symbol = "api/2/public/symbol"
|
||||
APIv2Ticker = "api/2/public/ticker"
|
||||
APIv2OrderBook = "api/2/public/orderbook"
|
||||
APIv2Candles = "api/2/public/candles"
|
||||
|
||||
// Authenticated
|
||||
APIv2Balance = "api/2/trading/balance"
|
||||
APIv2CryptoAddress = "api/2/account/crypto/address"
|
||||
APIv2CryptoWithdraw = "api/2/account/crypto/withdraw"
|
||||
APIv2TradeHistory = "api/2/history/trades"
|
||||
APIv2FeeInfo = "api/2/trading/fee"
|
||||
Orders = "order"
|
||||
OrderBuy = "buy"
|
||||
OrderSell = "sell"
|
||||
OrderCancel = "cancelOrder"
|
||||
OrderMove = "moveOrder"
|
||||
TradableBalances = "returnTradableBalances"
|
||||
TransferBalance = "transferBalance"
|
||||
)
|
||||
|
||||
// HitBTC is the overarching type across the hitbtc package
|
||||
type HitBTC struct {
|
||||
exchange.Base
|
||||
}
|
||||
|
||||
// SetDefaults sets default settings for hitbtc
|
||||
func (p *HitBTC) SetDefaults() {
|
||||
p.Name = "HitBTC"
|
||||
p.Enabled = false
|
||||
p.Fee = 0
|
||||
p.Verbose = false
|
||||
p.Websocket = false
|
||||
p.RESTPollingDelay = 10
|
||||
p.RequestCurrencyPairFormat.Delimiter = ""
|
||||
p.RequestCurrencyPairFormat.Uppercase = true
|
||||
p.ConfigCurrencyPairFormat.Delimiter = ""
|
||||
p.ConfigCurrencyPairFormat.Uppercase = true
|
||||
p.AssetTypes = []string{ticker.Spot}
|
||||
}
|
||||
|
||||
// Setup sets user exchange configuration settings
|
||||
func (p *HitBTC) Setup(exch config.ExchangeConfig) {
|
||||
if !exch.Enabled {
|
||||
p.SetEnabled(false)
|
||||
} else {
|
||||
p.Enabled = true
|
||||
p.AuthenticatedAPISupport = exch.AuthenticatedAPISupport
|
||||
p.SetAPIKeys(exch.APIKey, exch.APISecret, "", false)
|
||||
p.RESTPollingDelay = exch.RESTPollingDelay // Max 60000ms
|
||||
p.Verbose = exch.Verbose
|
||||
p.Websocket = exch.Websocket
|
||||
p.BaseCurrencies = common.SplitStrings(exch.BaseCurrencies, ",")
|
||||
availiableSymbols, err := p.GetSymbols("")
|
||||
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
p.AvailablePairs = common.SplitStrings(exch.AvailablePairs, ",")
|
||||
} else {
|
||||
p.AvailablePairs = availiableSymbols
|
||||
}
|
||||
p.EnabledPairs = common.SplitStrings(exch.EnabledPairs, ",")
|
||||
err = p.SetCurrencyPairFormat()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
err = p.SetAssetTypes()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// GetFee returns the fee for hitbtc
|
||||
func (p *HitBTC) GetFee() float64 {
|
||||
return p.Fee
|
||||
}
|
||||
|
||||
// Public Market Data
|
||||
// https://api.hitbtc.com/?python#market-data
|
||||
|
||||
// GetCurrencies
|
||||
// Return the actual list of available currencies, tokens, ICO etc.
|
||||
func (p *HitBTC) GetCurrencies(currency string) (map[string]Currencies, error) {
|
||||
type Response struct {
|
||||
Data []Currencies
|
||||
}
|
||||
resp := Response{}
|
||||
path := fmt.Sprintf("%s/%s/%s", APIURL, APIv2Currency, currency)
|
||||
err := common.SendHTTPGetRequest(path, true, p.Verbose, &resp.Data)
|
||||
ret := make(map[string]Currencies)
|
||||
for _, id := range resp.Data {
|
||||
ret[id.Id] = id
|
||||
}
|
||||
|
||||
return ret, err
|
||||
}
|
||||
|
||||
// GetSymbols
|
||||
// Return the actual list of currency symbols (currency pairs) traded on HitBTC exchange.
|
||||
// The first listed currency of a symbol is called the base currency, and the second currency
|
||||
// is called the quote currency. The currency pair indicates how much of the quote currency
|
||||
// is needed to purchase one unit of the base currency.
|
||||
func (p *HitBTC) GetSymbols(symbol string) ([]string, error) {
|
||||
|
||||
resp := []Symbol{}
|
||||
path := fmt.Sprintf("%s/%s/%s", APIURL, APIv2Symbol, symbol)
|
||||
err := common.SendHTTPGetRequest(path, true, p.Verbose, &resp)
|
||||
ret := make([]string, 0, len(resp))
|
||||
for _, x := range resp {
|
||||
ret = append(ret, x.Id)
|
||||
}
|
||||
|
||||
return ret, err
|
||||
}
|
||||
|
||||
// GetTicker
|
||||
// Return ticker information
|
||||
func (p *HitBTC) GetTicker(symbol string) map[string]Ticker {
|
||||
|
||||
resp1 := []Ticker{}
|
||||
resp2 := Ticker{}
|
||||
ret := make(map[string]Ticker)
|
||||
path := fmt.Sprintf("%s/%s/%s", APIURL, APIv2Ticker, symbol)
|
||||
|
||||
if symbol == "" {
|
||||
common.SendHTTPGetRequest(path, true, p.Verbose, &resp1)
|
||||
|
||||
for _, item := range resp1 {
|
||||
if item.Symbol != "" {
|
||||
ret[item.Symbol] = item
|
||||
}
|
||||
}
|
||||
} else {
|
||||
common.SendHTTPGetRequest(path, true, p.Verbose, &resp2)
|
||||
ret[resp2.Symbol] = resp2
|
||||
}
|
||||
|
||||
return ret
|
||||
}
|
||||
|
||||
// GetTrades returns trades from hitbtc
|
||||
func (p *HitBTC) GetTrades(currencyPair, from, till, limit, offset, by, sort string) ([]TradeHistory, error) {
|
||||
// start Number or Datetime
|
||||
// end Number or Datetime
|
||||
// limit Number
|
||||
// offset Number
|
||||
// by Filtration definition. Accepted values: id, timestamp. Default timestamp
|
||||
// sort Default DESC
|
||||
vals := url.Values{}
|
||||
|
||||
if from != "" {
|
||||
vals.Set("from", from)
|
||||
}
|
||||
|
||||
if till != "" {
|
||||
vals.Set("till", till)
|
||||
}
|
||||
|
||||
if limit != "" {
|
||||
vals.Set("limit", limit)
|
||||
}
|
||||
|
||||
if offset != "" {
|
||||
vals.Set("offset", offset)
|
||||
}
|
||||
|
||||
if by != "" {
|
||||
vals.Set("by", by)
|
||||
}
|
||||
|
||||
if sort != "" {
|
||||
vals.Set("sort", sort)
|
||||
}
|
||||
|
||||
resp := []TradeHistory{}
|
||||
path := fmt.Sprintf("%s/%s/%s?%s", APIURL, APIv2Trades, currencyPair, vals.Encode())
|
||||
|
||||
return resp, common.SendHTTPGetRequest(path, true, p.Verbose, &resp)
|
||||
}
|
||||
|
||||
// GetOrderbook
|
||||
// An order book is an electronic list of buy and sell orders for a specific
|
||||
// symbol, organized by price level.
|
||||
func (p *HitBTC) GetOrderbook(currencyPair string, limit int) (Orderbook, error) {
|
||||
// limit Limit of orderbook levels, default 100. Set 0 to view full orderbook levels
|
||||
vals := url.Values{}
|
||||
|
||||
if limit != 0 {
|
||||
vals.Set("limit", strconv.Itoa(limit))
|
||||
}
|
||||
|
||||
resp := OrderbookResponse{}
|
||||
path := fmt.Sprintf("%s/%s/%s?%s", APIURL, APIv2OrderBook, currencyPair, vals.Encode())
|
||||
|
||||
err := common.SendHTTPGetRequest(path, true, p.Verbose, &resp)
|
||||
if err != nil {
|
||||
return Orderbook{}, err
|
||||
}
|
||||
|
||||
ob := Orderbook{}
|
||||
for _, x := range resp.Asks {
|
||||
ob.Asks = append(ob.Asks, x)
|
||||
}
|
||||
|
||||
for _, x := range resp.Bids {
|
||||
ob.Bids = append(ob.Bids, x)
|
||||
}
|
||||
return ob, nil
|
||||
}
|
||||
|
||||
// GetCandles
|
||||
// A candles used for OHLC a specific symbol.
|
||||
// Note: Result contain candles only with non zero volume.
|
||||
func (p *HitBTC) GetCandles(currencyPair, limit, period string) ([]ChartData, error) {
|
||||
// limit Limit of candles, default 100.
|
||||
// period One of: M1 (one minute), M3, M5, M15, M30, H1, H4, D1, D7, 1M (one month). Default is M30 (30 minutes).
|
||||
vals := url.Values{}
|
||||
|
||||
if limit != "" {
|
||||
vals.Set("limit", limit)
|
||||
}
|
||||
|
||||
if period != "" {
|
||||
vals.Set("period", period)
|
||||
}
|
||||
|
||||
resp := []ChartData{}
|
||||
path := fmt.Sprintf("%s/%s/%s?%s", APIURL, APIv2Candles, currencyPair, vals.Encode())
|
||||
|
||||
err := common.SendHTTPGetRequest(path, true, p.Verbose, &resp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
// Authenticated Market Data
|
||||
// https://api.hitbtc.com/?python#market-data
|
||||
|
||||
// GetBalances
|
||||
func (p *HitBTC) GetBalances() (map[string]Balance, error) {
|
||||
|
||||
result := []Balance{}
|
||||
err := p.SendAuthenticatedHTTPRequest("GET", APIv2Balance, url.Values{}, &result)
|
||||
ret := make(map[string]Balance)
|
||||
|
||||
if err != nil {
|
||||
return ret, err
|
||||
}
|
||||
|
||||
for _, item := range result {
|
||||
ret[item.Currency] = item
|
||||
}
|
||||
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func (p *HitBTC) GetDepositAddresses(currency string) (DepositCryptoAddresses, error) {
|
||||
resp := DepositCryptoAddresses{}
|
||||
err := p.SendAuthenticatedHTTPRequest("GET", APIv2CryptoAddress+"/"+currency, url.Values{}, &resp)
|
||||
|
||||
return resp, err
|
||||
}
|
||||
|
||||
func (p *HitBTC) GenerateNewAddress(currency string) (DepositCryptoAddresses, error) {
|
||||
|
||||
resp := DepositCryptoAddresses{}
|
||||
err := p.SendAuthenticatedHTTPRequest("POST", APIv2CryptoAddress+"/"+currency, url.Values{}, &resp)
|
||||
|
||||
return resp, err
|
||||
}
|
||||
|
||||
// Get Active orders
|
||||
func (p *HitBTC) GetActiveOrders(currency string) ([]Order, error) {
|
||||
|
||||
resp := []Order{}
|
||||
err := p.SendAuthenticatedHTTPRequest("GET", Orders+"?symbol="+currency, url.Values{}, &resp)
|
||||
|
||||
return resp, err
|
||||
}
|
||||
|
||||
func (p *HitBTC) GetAuthenticatedTradeHistory(currency, start, end string) (interface{}, error) {
|
||||
values := url.Values{}
|
||||
|
||||
if start != "" {
|
||||
values.Set("start", start)
|
||||
}
|
||||
|
||||
if end != "" {
|
||||
values.Set("end", end)
|
||||
}
|
||||
|
||||
if currency != "" && currency != "all" {
|
||||
values.Set("currencyPair", currency)
|
||||
result := AuthenticatedTradeHistoryResponse{}
|
||||
err := p.SendAuthenticatedHTTPRequest("POST", APIv2TradeHistory, values, &result.Data)
|
||||
|
||||
if err != nil {
|
||||
return result, err
|
||||
}
|
||||
|
||||
return result, nil
|
||||
} else {
|
||||
values.Set("currencyPair", "all")
|
||||
result := AuthenticatedTradeHistoryAll{}
|
||||
err := p.SendAuthenticatedHTTPRequest("POST", APIv2TradeHistory, values, &result.Data)
|
||||
|
||||
if err != nil {
|
||||
return result, err
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
}
|
||||
|
||||
func (p *HitBTC) PlaceOrder(currency string, rate, amount float64, immediate, fillOrKill, buy bool) (OrderResponse, error) {
|
||||
result := OrderResponse{}
|
||||
values := url.Values{}
|
||||
|
||||
var orderType string
|
||||
if buy {
|
||||
orderType = OrderBuy
|
||||
} else {
|
||||
orderType = OrderSell
|
||||
}
|
||||
|
||||
values.Set("currencyPair", currency)
|
||||
values.Set("rate", strconv.FormatFloat(rate, 'f', -1, 64))
|
||||
values.Set("amount", strconv.FormatFloat(amount, 'f', -1, 64))
|
||||
|
||||
if immediate {
|
||||
values.Set("immediateOrCancel", "1")
|
||||
}
|
||||
|
||||
if fillOrKill {
|
||||
values.Set("fillOrKill", "1")
|
||||
}
|
||||
|
||||
err := p.SendAuthenticatedHTTPRequest("POST", orderType, values, &result)
|
||||
|
||||
if err != nil {
|
||||
return result, err
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (p *HitBTC) CancelOrder(orderID int64) (bool, error) {
|
||||
result := GenericResponse{}
|
||||
values := url.Values{}
|
||||
values.Set("orderNumber", strconv.FormatInt(orderID, 10))
|
||||
|
||||
err := p.SendAuthenticatedHTTPRequest("POST", OrderCancel, values, &result)
|
||||
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
if result.Success != 1 {
|
||||
return false, errors.New(result.Error)
|
||||
}
|
||||
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func (p *HitBTC) MoveOrder(orderID int64, rate, amount float64) (MoveOrderResponse, error) {
|
||||
result := MoveOrderResponse{}
|
||||
values := url.Values{}
|
||||
values.Set("orderNumber", strconv.FormatInt(orderID, 10))
|
||||
values.Set("rate", strconv.FormatFloat(rate, 'f', -1, 64))
|
||||
|
||||
if amount != 0 {
|
||||
values.Set("amount", strconv.FormatFloat(amount, 'f', -1, 64))
|
||||
}
|
||||
|
||||
err := p.SendAuthenticatedHTTPRequest("POST", OrderMove, values, &result)
|
||||
|
||||
if err != nil {
|
||||
return result, err
|
||||
}
|
||||
|
||||
if result.Success != 1 {
|
||||
return result, errors.New(result.Error)
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (p *HitBTC) Withdraw(currency, address string, amount float64) (bool, error) {
|
||||
result := Withdraw{}
|
||||
values := url.Values{}
|
||||
|
||||
values.Set("currency", currency)
|
||||
values.Set("amount", strconv.FormatFloat(amount, 'f', -1, 64))
|
||||
values.Set("address", address)
|
||||
|
||||
err := p.SendAuthenticatedHTTPRequest("POST", APIv2CryptoWithdraw, values, &result)
|
||||
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
if result.Error != "" {
|
||||
return false, errors.New(result.Error)
|
||||
}
|
||||
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func (p *HitBTC) GetFeeInfo(currencyPair string) (Fee, error) {
|
||||
result := Fee{}
|
||||
err := p.SendAuthenticatedHTTPRequest("GET", APIv2FeeInfo+"/"+currencyPair, url.Values{}, &result)
|
||||
|
||||
return result, err
|
||||
}
|
||||
|
||||
func (p *HitBTC) GetTradableBalances() (map[string]map[string]float64, error) {
|
||||
type Response struct {
|
||||
Data map[string]map[string]interface{}
|
||||
}
|
||||
result := Response{}
|
||||
|
||||
err := p.SendAuthenticatedHTTPRequest("POST", TradableBalances, url.Values{}, &result.Data)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
balances := make(map[string]map[string]float64)
|
||||
|
||||
for x, y := range result.Data {
|
||||
balances[x] = make(map[string]float64)
|
||||
for z, w := range y {
|
||||
balances[x][z], _ = strconv.ParseFloat(w.(string), 64)
|
||||
}
|
||||
}
|
||||
|
||||
return balances, nil
|
||||
}
|
||||
|
||||
func (p *HitBTC) TransferBalance(currency, from, to string, amount float64) (bool, error) {
|
||||
values := url.Values{}
|
||||
result := GenericResponse{}
|
||||
|
||||
values.Set("currency", currency)
|
||||
values.Set("amount", strconv.FormatFloat(amount, 'f', -1, 64))
|
||||
values.Set("fromAccount", from)
|
||||
values.Set("toAccount", to)
|
||||
|
||||
err := p.SendAuthenticatedHTTPRequest("POST", TransferBalance, values, &result)
|
||||
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
if result.Error != "" && result.Success != 1 {
|
||||
return false, errors.New(result.Error)
|
||||
}
|
||||
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func (p *HitBTC) SendAuthenticatedHTTPRequest(method, endpoint string, values url.Values, result interface{}) error {
|
||||
if !p.AuthenticatedAPISupport {
|
||||
return fmt.Errorf(exchange.WarningAuthenticatedRequestWithoutCredentialsSet, p.Name)
|
||||
}
|
||||
headers := make(map[string]string)
|
||||
headers["Authorization"] = "Basic " + common.Base64Encode([]byte(p.APIKey+":"+p.APISecret))
|
||||
|
||||
path := fmt.Sprintf("%s/%s", APIURL, endpoint)
|
||||
resp, err := common.SendHTTPRequest(method, path, headers, bytes.NewBufferString(values.Encode()))
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = common.JSONDecode([]byte(resp), &result)
|
||||
|
||||
if err != nil {
|
||||
return errors.New("Unable to JSON Unmarshal response.")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
69
exchanges/hitbtc/hitbtc_test.go
Normal file
69
exchanges/hitbtc/hitbtc_test.go
Normal file
@@ -0,0 +1,69 @@
|
||||
package hitbtc
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/thrasher-/gocryptotrader/config"
|
||||
)
|
||||
|
||||
var p HitBTC
|
||||
|
||||
// Please supply your own APIKEYS here for due diligence testing
|
||||
|
||||
const (
|
||||
apiKey = ""
|
||||
apiSecret = ""
|
||||
)
|
||||
|
||||
func TestSetDefaults(t *testing.T) {
|
||||
p.SetDefaults()
|
||||
}
|
||||
|
||||
func TestSetup(t *testing.T) {
|
||||
cfg := config.GetConfig()
|
||||
cfg.LoadConfig("../../testdata/configtest.json")
|
||||
hitbtcConfig, err := cfg.GetExchangeConfig("HitBTC")
|
||||
if err != nil {
|
||||
t.Error("Test Failed - HitBTC Setup() init error")
|
||||
}
|
||||
|
||||
hitbtcConfig.AuthenticatedAPISupport = true
|
||||
hitbtcConfig.APIKey = apiKey
|
||||
hitbtcConfig.APISecret = apiSecret
|
||||
|
||||
p.Setup(hitbtcConfig)
|
||||
}
|
||||
|
||||
func TestGetFee(t *testing.T) {
|
||||
if p.GetFee() != 0 {
|
||||
t.Error("Test faild - HitBTC GetFee() error")
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetOrderbook(t *testing.T) {
|
||||
_, err := p.GetOrderbook("BTCUSD", 50)
|
||||
if err != nil {
|
||||
t.Error("Test faild - HitBTC GetOrderbook() error", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetTrades(t *testing.T) {
|
||||
_, err := p.GetTrades("BTCUSD", "", "", "", "", "", "")
|
||||
if err != nil {
|
||||
t.Error("Test faild - HitBTC GetTradeHistory() error", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetChartCandles(t *testing.T) {
|
||||
_, err := p.GetCandles("BTCUSD", "", "")
|
||||
if err != nil {
|
||||
t.Error("Test faild - HitBTC GetChartData() error", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetCurrencies(t *testing.T) {
|
||||
_, err := p.GetCurrencies("")
|
||||
if err != nil {
|
||||
t.Error("Test faild - HitBTC GetCurrencies() error", err)
|
||||
}
|
||||
}
|
||||
233
exchanges/hitbtc/hitbtc_types.go
Normal file
233
exchanges/hitbtc/hitbtc_types.go
Normal file
@@ -0,0 +1,233 @@
|
||||
package hitbtc
|
||||
|
||||
import "time"
|
||||
|
||||
type Ticker struct {
|
||||
Last float64 `json:"last,string"` // Last trade price
|
||||
Ask float64 `json:"ask,string"` // Best ask price
|
||||
Bid float64 `json:"bid,string"` // Best bid price
|
||||
Timestamp time.Time `json:"timestamp,string"` // Last update or refresh ticker timestamp
|
||||
Volume float64 `json:"volume,string"` // Total trading amount within 24 hours in base currency
|
||||
VolumeQuote float64 `json:"volumeQuote,string"` // Total trading amount within 24 hours in quote currency
|
||||
Symbol string `json:"symbol"`
|
||||
High float64 `json:"high,string"` // Highest trade price within 24 hours
|
||||
Low float64 `json:"low,string"` // Lowest trade price within 24 hours
|
||||
Open float64 `json:"open,string"` // Last trade price 24 hours ago
|
||||
}
|
||||
|
||||
type Symbol struct {
|
||||
Id string `json:"id"` // Symbol identifier. In the future, the description will simply use the symbol
|
||||
BaseCurrency string `json:"baseCurrency"`
|
||||
QuoteCurrency string `json:"quoteCurrency"`
|
||||
QuantityIncrement float64 `json:"quantityIncrement,string"`
|
||||
TickSize float64 `json:"tickSize,string"`
|
||||
TakeLiquidityRate float64 `json:"takeLiquidityRate,string"` // Default fee rate
|
||||
ProvideLiquidityRate float64 `json:"provideLiquidityRate,string"` // Default fee rate for market making trades
|
||||
FeeCurrency string `json:"feeCurrency"` // Default fee rate for market making trades
|
||||
}
|
||||
|
||||
type OrderbookResponse struct {
|
||||
Asks []OrderbookItem `json:"ask"` // Ask side array of levels
|
||||
Bids []OrderbookItem `json:"bid"` // Bid side array of levels
|
||||
}
|
||||
|
||||
type OrderbookItem struct {
|
||||
Price float64 `json:"price,string"` // Price level
|
||||
Amount float64 `json:"size,string"` // Total volume of orders with the specified price
|
||||
}
|
||||
|
||||
type Orderbook struct {
|
||||
Asks []OrderbookItem `json:"asks"`
|
||||
Bids []OrderbookItem `json:"bids"`
|
||||
}
|
||||
|
||||
type TradeHistory struct {
|
||||
Id int64 `json:"id"` // Trade id
|
||||
Timestamp string `json:"timestamp"` // Trade timestamp
|
||||
Side string `json:"side"` // Trade side sell or buy
|
||||
Price float64 `json:"price,string"` // Trade price
|
||||
Quantity float64 `json:"quantity,string"` // Trade quantity
|
||||
}
|
||||
|
||||
type ChartData struct {
|
||||
Timestamp time.Time `json:"timestamp,string"`
|
||||
Max float64 `json:"max,string"` // Max price
|
||||
Min float64 `json:"min,string"` // Min price
|
||||
Open float64 `json:"open,string"` // Open price
|
||||
Close float64 `json:"close,string"` // Close price
|
||||
Volume float64 `json:"volume,string"` // Volume in base currency
|
||||
VolumeQuote float64 `json:"volumeQuote,string"` // Volume in quote currency
|
||||
}
|
||||
|
||||
type Currencies struct {
|
||||
Id string `json:"id"` // Currency identifier.
|
||||
FullName string `json:"fullName"` // Currency full name
|
||||
Crypto bool `json:"crypto,boolean"` // Is currency belongs to blockchain (false for ICO and fiat, like EUR)
|
||||
PayinEnabled bool `json:"payinEnabled"` // Is allowed for deposit (false for ICO)
|
||||
PayinPaymentId bool `json:"payinPaymentId"` // Is required to provide additional information other than the address for deposit
|
||||
PayinConfirmations int64 `json:"payinConfirmations"` // Blocks confirmations count for deposit
|
||||
PayoutEnabled bool `json:"payoutEnabled"` // Is allowed for withdraw (false for ICO)
|
||||
PayoutIsPaymentId bool `json:"payoutIsPaymentId"` // Is allowed to provide additional information for withdraw
|
||||
TransferEnabled bool `json:"transferEnabled"` // Is allowed to transfer between trading and account (may be disabled on maintain)
|
||||
}
|
||||
|
||||
type LoanOrder struct {
|
||||
Rate float64 `json:"rate,string"`
|
||||
Amount float64 `json:"amount,string"`
|
||||
RangeMin int `json:"rangeMin"`
|
||||
RangeMax int `json:"rangeMax"`
|
||||
}
|
||||
|
||||
type LoanOrders struct {
|
||||
Offers []LoanOrder `json:"offers"`
|
||||
Demands []LoanOrder `json:"demands"`
|
||||
}
|
||||
|
||||
type Balance struct {
|
||||
Currency string `json:"currency"`
|
||||
Available float64 `json:"available,string"` // Amount available for trading or transfer to main account
|
||||
Reserved float64 `json:"reserved,string"` // Amount reserved for active orders or incomplete transfers to main account
|
||||
|
||||
}
|
||||
|
||||
type DepositCryptoAddresses struct {
|
||||
Address string `json:"address"` // Address for deposit
|
||||
PaymentId string `json:"paymentId"` // Optional additional parameter. Required for deposit if persist
|
||||
}
|
||||
|
||||
type Order struct {
|
||||
Id int64 `json:"id,string"` // Unique identifier for Order as assigned by exchange
|
||||
ClientOrderId string `json:"clientOrderId"` // Unique identifier for Order as assigned by trader. Uniqueness must be
|
||||
// guaranteed within a single trading day, including all active orders.
|
||||
Symbol string `json:"symbol"` // Trading symbol
|
||||
Side string `json:"side"` // sell buy
|
||||
Status string `json:"status"` // new, suspended, partiallyFilled, filled, canceled, expired
|
||||
Type string `json:"type"` // Enum: limit, market, stopLimit, stopMarket
|
||||
TimeInForce string `json:"timeInForce"` // Time in force is a special instruction used when placing a trade to
|
||||
// indicate how long an order will remain active before it is executed or expires
|
||||
// GTC - Good till cancel. GTC order won't close until it is filled.
|
||||
// IOC - An immediate or cancel order is an order to buy or sell that must be executed immediately, and any portion
|
||||
// of the order that cannot be immediately filled is cancelled.
|
||||
// FOK - Fill or kill is a type of time-in-force designation used in securities trading that instructs a brokerage
|
||||
// to execute a transaction immediately and completely or not at all.
|
||||
// Day - keeps the order active until the end of the trading day in UTC.
|
||||
// GTD - Good till date specified in expireTime.
|
||||
Quantity float64 `json:"quantity,string"` // Order quantity
|
||||
Price float64 `json:"price,string"` // Order price
|
||||
CumQuantity float64 `json:"cumQuantity,string"` // Cumulative executed quantity
|
||||
CreatedAt time.Time `json:"createdAt,string"`
|
||||
UpdatedAt time.Time `json:"updatedAt,string"`
|
||||
StopPrice float64 `json:"stopPrice,string"`
|
||||
ExpireTime time.Time `json:"expireTime,string"`
|
||||
}
|
||||
|
||||
type OpenOrdersResponseAll struct {
|
||||
Data map[string][]Order
|
||||
}
|
||||
|
||||
type OpenOrdersResponse struct {
|
||||
Data []Order
|
||||
}
|
||||
|
||||
type AuthentictedTradeHistory struct {
|
||||
GlobalTradeID int64 `json:"globalTradeID"`
|
||||
TradeID int64 `json:"tradeID,string"`
|
||||
Date string `json:"date"`
|
||||
Rate float64 `json:"rate,string"`
|
||||
Amount float64 `json:"amount,string"`
|
||||
Total float64 `json:"total,string"`
|
||||
Fee float64 `json:"fee,string"`
|
||||
OrderNumber int64 `json:"orderNumber,string"`
|
||||
Type string `json:"type"`
|
||||
Category string `json:"category"`
|
||||
}
|
||||
|
||||
type AuthenticatedTradeHistoryAll struct {
|
||||
Data map[string][]AuthentictedTradeHistory
|
||||
}
|
||||
|
||||
type AuthenticatedTradeHistoryResponse struct {
|
||||
Data []AuthentictedTradeHistory
|
||||
}
|
||||
|
||||
type ResultingTrades struct {
|
||||
Amount float64 `json:"amount,string"`
|
||||
Date string `json:"date"`
|
||||
Rate float64 `json:"rate,string"`
|
||||
Total float64 `json:"total,string"`
|
||||
TradeID int64 `json:"tradeID,string"`
|
||||
Type string `json:"type"`
|
||||
}
|
||||
|
||||
type OrderResponse struct {
|
||||
OrderNumber int64 `json:"orderNumber,string"`
|
||||
Trades []ResultingTrades `json:"resultingTrades"`
|
||||
}
|
||||
|
||||
type GenericResponse struct {
|
||||
Success int `json:"success"`
|
||||
Error string `json:"error"`
|
||||
}
|
||||
|
||||
type MoveOrderResponse struct {
|
||||
Success int `json:"success"`
|
||||
Error string `json:"error"`
|
||||
OrderNumber int64 `json:"orderNumber,string"`
|
||||
Trades map[string][]ResultingTrades `json:"resultingTrades"`
|
||||
}
|
||||
|
||||
type Withdraw struct {
|
||||
Response string `json:"response"`
|
||||
Error string `json:"error"`
|
||||
}
|
||||
|
||||
type Fee struct {
|
||||
TakeLiquidityRate float64 `json:"takeLiquidityRate,string"` // Taker
|
||||
ProvideLiquidityRate float64 `json:"provideLiquidityRate,string"` // Maker
|
||||
}
|
||||
|
||||
type Margin struct {
|
||||
TotalValue float64 `json:"totalValue,string"`
|
||||
ProfitLoss float64 `json:"pl,string"`
|
||||
LendingFees float64 `json:"lendingFees,string"`
|
||||
NetValue float64 `json:"netValue,string"`
|
||||
BorrowedValue float64 `json:"totalBorrowedValue,string"`
|
||||
CurrentMargin float64 `json:"currentMargin,string"`
|
||||
}
|
||||
|
||||
type MarginPosition struct {
|
||||
Amount float64 `json:"amount,string"`
|
||||
Total float64 `json:"total,string"`
|
||||
BasePrice float64 `json:"basePrice,string"`
|
||||
LiquidiationPrice float64 `json:"liquidiationPrice"`
|
||||
ProfitLoss float64 `json:"pl,string"`
|
||||
LendingFees float64 `json:"lendingFees,string"`
|
||||
Type string `json:"type"`
|
||||
}
|
||||
|
||||
type LoanOffer struct {
|
||||
ID int64 `json:"id"`
|
||||
Rate float64 `json:"rate,string"`
|
||||
Amount float64 `json:"amount,string"`
|
||||
Duration int `json:"duration"`
|
||||
AutoRenew bool `json:"autoRenew,int"`
|
||||
Date string `json:"date"`
|
||||
}
|
||||
|
||||
type ActiveLoans struct {
|
||||
Provided []LoanOffer `json:"provided"`
|
||||
Used []LoanOffer `json:"used"`
|
||||
}
|
||||
|
||||
type LendingHistory struct {
|
||||
ID int64 `json:"id"`
|
||||
Currency string `json:"currency"`
|
||||
Rate float64 `json:"rate,string"`
|
||||
Amount float64 `json:"amount,string"`
|
||||
Duration float64 `json:"duration,string"`
|
||||
Interest float64 `json:"interest,string"`
|
||||
Fee float64 `json:"fee,string"`
|
||||
Earned float64 `json:"earned,string"`
|
||||
Open string `json:"open"`
|
||||
Close string `json:"close"`
|
||||
}
|
||||
182
exchanges/hitbtc/hitbtc_websocket.go
Normal file
182
exchanges/hitbtc/hitbtc_websocket.go
Normal file
@@ -0,0 +1,182 @@
|
||||
package hitbtc
|
||||
|
||||
import (
|
||||
"log"
|
||||
"strconv"
|
||||
|
||||
"github.com/beatgammit/turnpike"
|
||||
)
|
||||
|
||||
const (
|
||||
HITBTC_WEBSOCKET_ADDRESS = "wss://api.hitbtc.com"
|
||||
HITBTC_WEBSOCKET_REALM = "realm1"
|
||||
HITBTC_WEBSOCKET_TICKER = "ticker"
|
||||
HITBTC_WEBSOCKET_TROLLBOX = "trollbox"
|
||||
)
|
||||
|
||||
type HitBTCWebsocketTicker struct {
|
||||
CurrencyPair string
|
||||
Last float64
|
||||
LowestAsk float64
|
||||
HighestBid float64
|
||||
PercentChange float64
|
||||
BaseVolume float64
|
||||
QuoteVolume float64
|
||||
IsFrozen bool
|
||||
High float64
|
||||
Low float64
|
||||
}
|
||||
|
||||
func HitBTCOnTicker(args []interface{}, kwargs map[string]interface{}) {
|
||||
ticker := HitBTCWebsocketTicker{}
|
||||
ticker.CurrencyPair = args[0].(string)
|
||||
ticker.Last, _ = strconv.ParseFloat(args[1].(string), 64)
|
||||
ticker.LowestAsk, _ = strconv.ParseFloat(args[2].(string), 64)
|
||||
ticker.HighestBid, _ = strconv.ParseFloat(args[3].(string), 64)
|
||||
ticker.PercentChange, _ = strconv.ParseFloat(args[4].(string), 64)
|
||||
ticker.BaseVolume, _ = strconv.ParseFloat(args[5].(string), 64)
|
||||
ticker.QuoteVolume, _ = strconv.ParseFloat(args[6].(string), 64)
|
||||
|
||||
if args[7].(float64) != 0 {
|
||||
ticker.IsFrozen = true
|
||||
} else {
|
||||
ticker.IsFrozen = false
|
||||
}
|
||||
|
||||
ticker.High, _ = strconv.ParseFloat(args[8].(string), 64)
|
||||
ticker.Low, _ = strconv.ParseFloat(args[9].(string), 64)
|
||||
}
|
||||
|
||||
type HitBTCWebsocketTrollboxMessage struct {
|
||||
MessageNumber float64
|
||||
Username string
|
||||
Message string
|
||||
Reputation float64
|
||||
}
|
||||
|
||||
func HitBTCOnTrollbox(args []interface{}, kwargs map[string]interface{}) {
|
||||
message := HitBTCWebsocketTrollboxMessage{}
|
||||
message.MessageNumber, _ = args[1].(float64)
|
||||
message.Username = args[2].(string)
|
||||
message.Message = args[3].(string)
|
||||
if len(args) == 5 {
|
||||
message.Reputation = args[4].(float64)
|
||||
}
|
||||
}
|
||||
|
||||
func HitBTCOnDepthOrTrade(args []interface{}, kwargs map[string]interface{}) {
|
||||
for x := range args {
|
||||
data := args[x].(map[string]interface{})
|
||||
msgData := data["data"].(map[string]interface{})
|
||||
msgType := data["type"].(string)
|
||||
|
||||
switch msgType {
|
||||
case "orderBookModify":
|
||||
{
|
||||
type HitBTCWebsocketOrderbookModify struct {
|
||||
Type string
|
||||
Rate float64
|
||||
Amount float64
|
||||
}
|
||||
|
||||
orderModify := HitBTCWebsocketOrderbookModify{}
|
||||
orderModify.Type = msgData["type"].(string)
|
||||
|
||||
rateStr := msgData["rate"].(string)
|
||||
orderModify.Rate, _ = strconv.ParseFloat(rateStr, 64)
|
||||
|
||||
amountStr := msgData["amount"].(string)
|
||||
orderModify.Amount, _ = strconv.ParseFloat(amountStr, 64)
|
||||
}
|
||||
case "orderBookRemove":
|
||||
{
|
||||
type HitBTCWebsocketOrderbookRemove struct {
|
||||
Type string
|
||||
Rate float64
|
||||
}
|
||||
|
||||
orderRemoval := HitBTCWebsocketOrderbookRemove{}
|
||||
orderRemoval.Type = msgData["type"].(string)
|
||||
|
||||
rateStr := msgData["rate"].(string)
|
||||
orderRemoval.Rate, _ = strconv.ParseFloat(rateStr, 64)
|
||||
}
|
||||
case "newTrade":
|
||||
{
|
||||
type HitBTCWebsocketNewTrade struct {
|
||||
Type string
|
||||
TradeID int64
|
||||
Rate float64
|
||||
Amount float64
|
||||
Date string
|
||||
Total float64
|
||||
}
|
||||
|
||||
trade := HitBTCWebsocketNewTrade{}
|
||||
trade.Type = msgData["type"].(string)
|
||||
|
||||
tradeIDstr := msgData["tradeID"].(string)
|
||||
trade.TradeID, _ = strconv.ParseInt(tradeIDstr, 10, 64)
|
||||
|
||||
rateStr := msgData["rate"].(string)
|
||||
trade.Rate, _ = strconv.ParseFloat(rateStr, 64)
|
||||
|
||||
amountStr := msgData["amount"].(string)
|
||||
trade.Amount, _ = strconv.ParseFloat(amountStr, 64)
|
||||
|
||||
totalStr := msgData["total"].(string)
|
||||
trade.Rate, _ = strconv.ParseFloat(totalStr, 64)
|
||||
|
||||
trade.Date = msgData["date"].(string)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (p *HitBTC) WebsocketClient() {
|
||||
for p.Enabled && p.Websocket {
|
||||
c, err := turnpike.NewWebsocketClient(turnpike.JSON, HITBTC_WEBSOCKET_ADDRESS, nil)
|
||||
if err != nil {
|
||||
log.Printf("%s Unable to connect to Websocket. Error: %s\n", p.GetName(), err)
|
||||
continue
|
||||
}
|
||||
|
||||
if p.Verbose {
|
||||
log.Printf("%s Connected to Websocket.\n", p.GetName())
|
||||
}
|
||||
|
||||
_, err = c.JoinRealm(HITBTC_WEBSOCKET_REALM, nil)
|
||||
if err != nil {
|
||||
log.Printf("%s Unable to join realm. Error: %s\n", p.GetName(), err)
|
||||
continue
|
||||
}
|
||||
|
||||
if p.Verbose {
|
||||
log.Printf("%s Joined Websocket realm.\n", p.GetName())
|
||||
}
|
||||
|
||||
c.ReceiveDone = make(chan bool)
|
||||
|
||||
if err := c.Subscribe(HITBTC_WEBSOCKET_TICKER, HitBTCOnTicker); err != nil {
|
||||
log.Printf("%s Error subscribing to ticker channel: %s\n", p.GetName(), err)
|
||||
}
|
||||
|
||||
if err := c.Subscribe(HITBTC_WEBSOCKET_TROLLBOX, HitBTCOnTrollbox); err != nil {
|
||||
log.Printf("%s Error subscribing to trollbox channel: %s\n", p.GetName(), err)
|
||||
}
|
||||
|
||||
for x := range p.EnabledPairs {
|
||||
currency := p.EnabledPairs[x]
|
||||
if err := c.Subscribe(currency, HitBTCOnDepthOrTrade); err != nil {
|
||||
log.Printf("%s Error subscribing to %s channel: %s\n", p.GetName(), currency, err)
|
||||
}
|
||||
}
|
||||
|
||||
if p.Verbose {
|
||||
log.Printf("%s Subscribed to websocket channels.\n", p.GetName())
|
||||
}
|
||||
|
||||
<-c.ReceiveDone
|
||||
log.Printf("%s Websocket client disconnected.\n", p.GetName())
|
||||
}
|
||||
}
|
||||
108
exchanges/hitbtc/hitbtc_wrapper.go
Normal file
108
exchanges/hitbtc/hitbtc_wrapper.go
Normal file
@@ -0,0 +1,108 @@
|
||||
package hitbtc
|
||||
|
||||
import (
|
||||
"log"
|
||||
|
||||
"github.com/thrasher-/gocryptotrader/common"
|
||||
"github.com/thrasher-/gocryptotrader/currency/pair"
|
||||
"github.com/thrasher-/gocryptotrader/exchanges"
|
||||
"github.com/thrasher-/gocryptotrader/exchanges/orderbook"
|
||||
"github.com/thrasher-/gocryptotrader/exchanges/ticker"
|
||||
)
|
||||
|
||||
// Start starts the HitBTC go routine
|
||||
func (p *HitBTC) Start() {
|
||||
go p.Run()
|
||||
}
|
||||
|
||||
// Run implements the HitBTC wrapper
|
||||
func (p *HitBTC) Run() {
|
||||
if p.Verbose {
|
||||
log.Printf("%s Websocket: %s (url: %s).\n", p.GetName(), common.IsEnabled(p.Websocket), HITBTC_WEBSOCKET_ADDRESS)
|
||||
log.Printf("%s polling delay: %ds.\n", p.GetName(), p.RESTPollingDelay)
|
||||
log.Printf("%s %d currencies enabled: %s.\n", p.GetName(), len(p.EnabledPairs), p.EnabledPairs)
|
||||
}
|
||||
|
||||
if p.Websocket {
|
||||
go p.WebsocketClient()
|
||||
}
|
||||
}
|
||||
|
||||
// UpdateTicker updates and returns the ticker for a currency pair
|
||||
func (p *HitBTC) UpdateTicker(currencyPair pair.CurrencyPair, assetType string) (ticker.Price, error) {
|
||||
tick := p.GetTicker("")
|
||||
|
||||
for _, x := range p.GetEnabledCurrencies() {
|
||||
var tp ticker.Price
|
||||
curr := exchange.FormatExchangeCurrency(p.GetName(), x).String()
|
||||
tp.Pair = x
|
||||
tp.Ask = tick[curr].Ask
|
||||
tp.Bid = tick[curr].Bid
|
||||
tp.High = tick[curr].High
|
||||
tp.Last = tick[curr].Last
|
||||
tp.Low = tick[curr].Low
|
||||
tp.Volume = tick[curr].Volume
|
||||
ticker.ProcessTicker(p.GetName(), x, tp, assetType)
|
||||
}
|
||||
return ticker.GetTicker(p.Name, currencyPair, assetType)
|
||||
}
|
||||
|
||||
// GetTickerPrice returns the ticker for a currency pair
|
||||
func (p *HitBTC) GetTickerPrice(currencyPair pair.CurrencyPair, assetType string) (ticker.Price, error) {
|
||||
tickerNew, err := ticker.GetTicker(p.GetName(), currencyPair, assetType)
|
||||
if err != nil {
|
||||
return p.UpdateTicker(currencyPair, assetType)
|
||||
}
|
||||
return tickerNew, nil
|
||||
}
|
||||
|
||||
// GetOrderbookEx returns orderbook base on the currency pair
|
||||
func (p *HitBTC) GetOrderbookEx(currencyPair pair.CurrencyPair, assetType string) (orderbook.Base, error) {
|
||||
ob, err := orderbook.GetOrderbook(p.GetName(), currencyPair, assetType)
|
||||
if err == nil {
|
||||
return p.UpdateOrderbook(currencyPair, assetType)
|
||||
}
|
||||
return ob, nil
|
||||
}
|
||||
|
||||
// UpdateOrderbook updates and returns the orderbook for a currency pair
|
||||
func (p *HitBTC) UpdateOrderbook(currencyPair pair.CurrencyPair, assetType string) (orderbook.Base, error) {
|
||||
var orderBook orderbook.Base
|
||||
orderbookNew, err := p.GetOrderbook(exchange.FormatExchangeCurrency(p.GetName(), currencyPair).String(), 1000)
|
||||
if err != nil {
|
||||
return orderBook, err
|
||||
}
|
||||
|
||||
for x := range orderbookNew.Bids {
|
||||
data := orderbookNew.Bids[x]
|
||||
orderBook.Bids = append(orderBook.Bids, orderbook.Item{Amount: data.Amount, Price: data.Price})
|
||||
}
|
||||
|
||||
for x := range orderbookNew.Asks {
|
||||
data := orderbookNew.Asks[x]
|
||||
orderBook.Asks = append(orderBook.Asks, orderbook.Item{Amount: data.Amount, Price: data.Price})
|
||||
}
|
||||
|
||||
orderbook.ProcessOrderbook(p.GetName(), currencyPair, orderBook, assetType)
|
||||
return orderbook.GetOrderbook(p.Name, currencyPair, assetType)
|
||||
}
|
||||
|
||||
// GetExchangeAccountInfo retrieves balances for all enabled currencies for the
|
||||
// HitBTC exchange
|
||||
func (p *HitBTC) GetExchangeAccountInfo() (exchange.AccountInfo, error) {
|
||||
var response exchange.AccountInfo
|
||||
response.ExchangeName = p.GetName()
|
||||
accountBalance, err := p.GetBalances()
|
||||
if err != nil {
|
||||
return response, err
|
||||
}
|
||||
|
||||
for _, item := range accountBalance {
|
||||
var exchangeCurrency exchange.AccountCurrencyInfo
|
||||
exchangeCurrency.CurrencyName = item.Currency
|
||||
exchangeCurrency.TotalValue = item.Available
|
||||
exchangeCurrency.Hold = item.Reserved
|
||||
response.Currencies = append(response.Currencies, exchangeCurrency)
|
||||
}
|
||||
return response, nil
|
||||
}
|
||||
21
testdata/configtest.json
vendored
21
testdata/configtest.json
vendored
@@ -321,6 +321,27 @@
|
||||
"Uppercase": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"Name": "HitBTC",
|
||||
"Enabled": true,
|
||||
"Verbose": false,
|
||||
"Websocket": false,
|
||||
"UseSandbox": false,
|
||||
"RESTPollingDelay": 10,
|
||||
"AuthenticatedAPISupport": false,
|
||||
"APIKey": "Key",
|
||||
"APISecret": "Secret",
|
||||
"AvailablePairs": "BTCUSD,ETHBTC,ETHUSD",
|
||||
"EnabledPairs": "BTCUSD",
|
||||
"BaseCurrencies": "USD",
|
||||
"AssetTypes": "SPOT",
|
||||
"ConfigCurrencyPairFormat": {
|
||||
"Uppercase": true
|
||||
},
|
||||
"RequestCurrencyPairFormat": {
|
||||
"Uppercase": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"Name": "Huobi",
|
||||
"Enabled": true,
|
||||
|
||||
Reference in New Issue
Block a user