poloniex: websocket update (#659)

* poloniex: websocket update with debug output and currency tracking system

* linter: fix issues

* nits: Addr

* poloniex: govet fix

* nits: addr

* Bittrex: Fix fee test
This commit is contained in:
Ryan O'Hara-Reid
2021-04-27 12:05:10 +10:00
committed by GitHub
parent d106d091e6
commit ca87ddf825
12 changed files with 4123 additions and 435 deletions

View File

@@ -47,3 +47,12 @@ type Balance struct {
TotalValue float64
Hold float64
}
// Change defines incoming balance change on currency holdings
type Change struct {
Exchange string
Currency currency.Code
Asset asset.Item
Amount float64
Account string
}

View File

@@ -423,7 +423,7 @@ func (b *Bitmex) wsHandleData(respRaw []byte) error {
Err: err,
}
}
b.Websocket.DataHandler <- &order.Cancel{
b.Websocket.DataHandler <- &order.Modify{
Price: response.Data[x].Price,
Amount: response.Data[x].OrderQuantity,
Exchange: b.Name,

View File

@@ -304,8 +304,8 @@ func TestGetFee(t *testing.T) {
// CryptocurrencyWithdrawalFee Basic
feeBuilder = setFeeBuilder()
feeBuilder.FeeType = exchange.CryptocurrencyWithdrawalFee
if resp, err := b.GetFee(feeBuilder); resp != float64(0.00015) || err != nil {
t.Errorf("Expected: %f, Received: %f", float64(0.00015), resp)
if resp, err := b.GetFee(feeBuilder); resp != float64(0.0003) || err != nil {
t.Errorf("Expected: %f, Received: %f", float64(0.0003), resp)
t.Error(err)
}

View File

@@ -238,6 +238,7 @@ const (
Open Status = "OPEN"
AutoDeleverage Status = "ADL"
Closed Status = "CLOSED"
Pending Status = "PENDING"
)
// Type enforces a standard for order types across the code base

View File

@@ -0,0 +1,235 @@
package poloniex
import (
"errors"
"strconv"
"sync"
"github.com/thrasher-corp/gocryptotrader/currency"
)
// CurrencyDetails stores a map of currencies associated with their ID
type CurrencyDetails struct {
pairs map[float64]PairSummaryInfo
codes map[float64]CodeSummaryInfo
// Mutex used for future when we will periodically update this table every
// week or so in production
m sync.RWMutex
}
// PairSummaryInfo defines currency pair information
type PairSummaryInfo struct {
Pair currency.Pair
IsFrozen bool
PostOnly bool
}
// CodeSummaryInfo defines currency information
type CodeSummaryInfo struct {
Currency currency.Code
WithdrawalTXFee float64
MinimumConfirmations int64
DepositAddress string
WithdrawalDepositDisabled bool
Frozen bool
}
var (
errCannotLoadNoData = errors.New("cannot load websocket currency data as data is nil")
errNoDepositAddress = errors.New("no public deposit address for currency")
errPairMapIsNil = errors.New("cannot get currency pair, map is nil")
errCodeMapIsNil = errors.New("cannot get currency code, map is nil")
errCurrencyNotFoundInMap = errors.New("currency not found")
)
// loadPairs loads currency pair associations with unique identifiers from
// ticker data map
func (w *CurrencyDetails) loadPairs(data map[string]Ticker) error {
if data == nil {
return errCannotLoadNoData
}
w.m.Lock()
defer w.m.Unlock()
for k, v := range data {
pair, err := currency.NewPairFromString(k)
if err != nil {
return err
}
if w.pairs == nil {
w.pairs = make(map[float64]PairSummaryInfo)
}
w.pairs[v.ID] = PairSummaryInfo{
Pair: pair,
IsFrozen: v.IsFrozen == 1,
PostOnly: v.PostOnly == 1,
}
}
return nil
}
// loadCodes loads currency codes from currency map
func (w *CurrencyDetails) loadCodes(data map[string]Currencies) error {
if data == nil {
return errCannotLoadNoData
}
w.m.Lock()
defer w.m.Unlock()
for k, v := range data {
if v.Delisted == 1 {
continue
}
if w.codes == nil {
w.codes = make(map[float64]CodeSummaryInfo)
}
w.codes[v.ID] = CodeSummaryInfo{
Currency: currency.NewCode(k),
WithdrawalTXFee: v.TxFee,
MinimumConfirmations: v.MinConfirmations,
DepositAddress: v.DepositAddress,
WithdrawalDepositDisabled: v.WithdrawalDepositDisabled == 1,
Frozen: v.Frozen == 1,
}
}
return nil
}
// GetPair returns a currency pair by its ID
func (w *CurrencyDetails) GetPair(id float64) (currency.Pair, error) {
w.m.RLock()
defer w.m.RUnlock()
if w.pairs == nil {
return currency.Pair{}, errPairMapIsNil
}
p, ok := w.pairs[id]
if ok {
return p.Pair, nil
}
// This is here so we can still log an order with the ID as the currency
// pair which you can then cross reference later with the exchange ID list,
// rather than error out.
op, err := currency.NewPairFromString(strconv.FormatFloat(id, 'f', -1, 64))
if err != nil {
return op, err
}
return op, errIDNotFoundInPairMap
}
// GetCode returns a currency code by its ID
func (w *CurrencyDetails) GetCode(id float64) (currency.Code, error) {
w.m.RLock()
defer w.m.RUnlock()
if w.codes == nil {
return currency.Code{}, errCodeMapIsNil
}
c, ok := w.codes[id]
if ok {
return c.Currency, nil
}
return currency.Code{}, errIDNotFoundInCodeMap
}
// GetWithdrawalTXFee returns withdrawal transaction fee for the currency
func (w *CurrencyDetails) GetWithdrawalTXFee(c currency.Code) (float64, error) {
w.m.RLock()
defer w.m.RUnlock()
if w.codes == nil {
return 0, errCodeMapIsNil
}
for _, v := range w.codes {
if v.Currency == c {
return v.WithdrawalTXFee, nil
}
}
return 0, errCurrencyNotFoundInMap
}
// GetDepositAddress returns the public deposit address details for the currency
func (w *CurrencyDetails) GetDepositAddress(c currency.Code) (string, error) {
w.m.RLock()
defer w.m.RUnlock()
if w.codes == nil {
return "", errCodeMapIsNil
}
for _, v := range w.codes {
if v.Currency == c {
if v.DepositAddress == "" {
return "", errNoDepositAddress
}
return v.DepositAddress, nil
}
}
return "", errCurrencyNotFoundInMap
}
// IsWithdrawAndDepositsEnabled returns if withdrawals or deposits are enabled
func (w *CurrencyDetails) IsWithdrawAndDepositsEnabled(c currency.Code) (bool, error) {
w.m.RLock()
defer w.m.RUnlock()
if w.codes == nil {
return false, errCodeMapIsNil
}
for _, v := range w.codes {
if v.Currency == c {
return !v.WithdrawalDepositDisabled, nil
}
}
return false, errCurrencyNotFoundInMap
}
// IsTradingEnabledForCurrency returns if the currency is allowed to be traded
func (w *CurrencyDetails) IsTradingEnabledForCurrency(c currency.Code) (bool, error) {
w.m.RLock()
defer w.m.RUnlock()
if w.codes == nil {
return false, errCodeMapIsNil
}
for _, v := range w.codes {
if v.Currency == c {
return !v.Frozen, nil
}
}
return false, errCurrencyNotFoundInMap
}
// IsTradingEnabledForPair returns if the currency pair is allowed to be traded
func (w *CurrencyDetails) IsTradingEnabledForPair(pair currency.Pair) (bool, error) {
w.m.RLock()
defer w.m.RUnlock()
if w.codes == nil {
return false, errCodeMapIsNil
}
for _, v := range w.pairs {
if v.Pair.Equal(pair) {
return !v.IsFrozen, nil
}
}
return false, errCurrencyNotFoundInMap
}
// IsPostOnlyForPair returns if an order is allowed to take liquidity from the
// books or reduce positions
func (w *CurrencyDetails) IsPostOnlyForPair(pair currency.Pair) (bool, error) {
w.m.RLock()
defer w.m.RUnlock()
if w.codes == nil {
return false, errCodeMapIsNil
}
for _, v := range w.pairs {
if v.Pair.Equal(pair) {
return v.PostOnly, nil
}
}
return false, errCurrencyNotFoundInMap
}
// isInitial checks state of maps to determine if they have been loaded or not
func (w *CurrencyDetails) isInitial() bool {
w.m.RLock()
defer w.m.RUnlock()
return w.codes == nil || w.pairs == nil
}

View File

@@ -0,0 +1,209 @@
package poloniex
import (
"errors"
"testing"
"github.com/thrasher-corp/gocryptotrader/currency"
)
func TestWsCurrencyMap(t *testing.T) {
var m CurrencyDetails
if !m.isInitial() {
t.Fatal("unexpected value")
}
err := m.loadPairs(nil)
if !errors.Is(err, errCannotLoadNoData) {
t.Fatalf("expected: %v but received: %v", errCannotLoadNoData, err)
}
err = m.loadCodes(nil)
if !errors.Is(err, errCannotLoadNoData) {
t.Fatalf("expected: %v but received: %v", errCannotLoadNoData, err)
}
_, err = m.GetPair(1337)
if !errors.Is(err, errPairMapIsNil) {
t.Fatalf("expected: %v but received: %v", errPairMapIsNil, err)
}
_, err = m.GetCode(1337)
if !errors.Is(err, errCodeMapIsNil) {
t.Fatalf("expected: %v but received: %v", errCodeMapIsNil, err)
}
_, err = m.GetWithdrawalTXFee(currency.Code{})
if !errors.Is(err, errCodeMapIsNil) {
t.Fatalf("expected: %v but received: %v", errCodeMapIsNil, err)
}
_, err = m.GetDepositAddress(currency.Code{})
if !errors.Is(err, errCodeMapIsNil) {
t.Fatalf("expected: %v but received: %v", errCodeMapIsNil, err)
}
_, err = m.IsWithdrawAndDepositsEnabled(currency.Code{})
if !errors.Is(err, errCodeMapIsNil) {
t.Fatalf("expected: %v but received: %v", errCodeMapIsNil, err)
}
_, err = m.IsTradingEnabledForCurrency(currency.Code{})
if !errors.Is(err, errCodeMapIsNil) {
t.Fatalf("expected: %v but received: %v", errCodeMapIsNil, err)
}
_, err = m.IsTradingEnabledForPair(currency.Pair{})
if !errors.Is(err, errCodeMapIsNil) {
t.Fatalf("expected: %v but received: %v", errCodeMapIsNil, err)
}
_, err = m.IsPostOnlyForPair(currency.Pair{})
if !errors.Is(err, errCodeMapIsNil) {
t.Fatalf("expected: %v but received: %v", errCodeMapIsNil, err)
}
c, err := p.GetCurrencies()
if err != nil {
t.Fatal(err)
}
err = m.loadCodes(c)
if err != nil {
t.Fatal(err)
}
tick, err := p.GetTicker()
if err != nil {
t.Fatal(err)
}
err = m.loadPairs(tick)
if err != nil {
t.Fatal(err)
}
pTest, err := m.GetPair(1337)
if !errors.Is(err, errIDNotFoundInPairMap) {
t.Fatalf("expected: %v but received: %v", errIDNotFoundInPairMap, err)
}
if pTest.String() != "1337" {
t.Fatal("unexpected value")
}
_, err = m.GetCode(1337)
if !errors.Is(err, errIDNotFoundInCodeMap) {
t.Fatalf("expected: %v but received: %v", errIDNotFoundInCodeMap, err)
}
btcusdt, err := m.GetPair(121)
if !errors.Is(err, nil) {
t.Fatalf("expected: %v but received: %v", nil, err)
}
if btcusdt.String() != "USDT_BTC" {
t.Fatal("expecting USDT_BTC pair")
}
maid, err := m.GetCode(127)
if !errors.Is(err, nil) {
t.Fatalf("expected: %v but received: %v", nil, err)
}
if maid.String() != "MAID" {
t.Fatal("unexpected value")
}
txFee, err := m.GetWithdrawalTXFee(maid)
if err != nil {
t.Fatal(err)
}
if txFee != 80 {
t.Fatal("unexpected value")
}
_, err = m.GetDepositAddress(maid)
if !errors.Is(err, errNoDepositAddress) {
t.Fatalf("expected: %v but received: %v", errNoDepositAddress, err)
}
dAddr, err := m.GetDepositAddress(currency.NewCode("BCN"))
if !errors.Is(err, nil) {
t.Fatalf("expected: %v but received: %v", nil, err)
}
if dAddr != "25cZNQYVAi3issDCoa6fWA2Aogd4FgPhYdpX3p8KLfhKC6sN8s6Q9WpcW4778TPwcUS5jEM25JrQvjD3XjsvXuNHSWhYUsu" {
t.Fatal("unexpected deposit address")
}
wdEnabled, err := m.IsWithdrawAndDepositsEnabled(maid)
if !errors.Is(err, nil) {
t.Fatalf("expected: %v but received: %v", nil, err)
}
if !wdEnabled {
t.Fatal("unexpected results")
}
tEnabled, err := m.IsTradingEnabledForCurrency(maid)
if !errors.Is(err, nil) {
t.Fatalf("expected: %v but received: %v", nil, err)
}
if !tEnabled {
t.Fatal("unexpected results")
}
cp := currency.NewPair(currency.USDT, currency.BTC)
tEnabled, err = m.IsTradingEnabledForPair(cp)
if !errors.Is(err, nil) {
t.Fatalf("expected: %v but received: %v", nil, err)
}
if !tEnabled {
t.Fatal("unexpected results")
}
postOnly, err := m.IsPostOnlyForPair(cp)
if !errors.Is(err, nil) {
t.Fatalf("expected: %v but received: %v", nil, err)
}
if postOnly {
t.Fatal("unexpected results")
}
_, err = m.GetWithdrawalTXFee(currency.Code{})
if !errors.Is(err, errCurrencyNotFoundInMap) {
t.Fatalf("expected: %v but received: %v", errCurrencyNotFoundInMap, err)
}
_, err = m.GetDepositAddress(currency.Code{})
if !errors.Is(err, errCurrencyNotFoundInMap) {
t.Fatalf("expected: %v but received: %v", errCurrencyNotFoundInMap, err)
}
_, err = m.IsWithdrawAndDepositsEnabled(currency.Code{})
if !errors.Is(err, errCurrencyNotFoundInMap) {
t.Fatalf("expected: %v but received: %v", errCurrencyNotFoundInMap, err)
}
_, err = m.IsTradingEnabledForCurrency(currency.Code{})
if !errors.Is(err, errCurrencyNotFoundInMap) {
t.Fatalf("expected: %v but received: %v", errCurrencyNotFoundInMap, err)
}
_, err = m.IsTradingEnabledForPair(currency.Pair{})
if !errors.Is(err, errCurrencyNotFoundInMap) {
t.Fatalf("expected: %v but received: %v", errCurrencyNotFoundInMap, err)
}
_, err = m.IsPostOnlyForPair(currency.Pair{})
if !errors.Is(err, errCurrencyNotFoundInMap) {
t.Fatalf("expected: %v but received: %v", errCurrencyNotFoundInMap, err)
}
}

View File

@@ -55,6 +55,7 @@ const (
// Poloniex is the overarching type across the poloniex package
type Poloniex struct {
exchange.Base
details CurrencyDetails
}
// GetTicker returns current ticker information
@@ -258,27 +259,15 @@ func (p *Poloniex) GetBalances() (Balance, error) {
// GetCompleteBalances returns complete balances from your account.
func (p *Poloniex) GetCompleteBalances() (CompleteBalances, error) {
var result interface{}
err := p.SendAuthenticatedHTTPRequest(exchange.RestSpot, http.MethodPost, poloniexBalancesComplete, url.Values{}, &result)
if err != nil {
return CompleteBalances{}, err
}
data := result.(map[string]interface{})
balance := CompleteBalances{}
balance.Currency = make(map[string]CompleteBalance)
for x, y := range data {
dataVals := y.(map[string]interface{})
balancesData := CompleteBalance{}
balancesData.Available, _ = strconv.ParseFloat(dataVals["available"].(string), 64)
balancesData.OnOrders, _ = strconv.ParseFloat(dataVals["onOrders"].(string), 64)
balancesData.BTCValue, _ = strconv.ParseFloat(dataVals["btcValue"].(string), 64)
balance.Currency[x] = balancesData
}
return balance, nil
var result CompleteBalances
vals := url.Values{}
vals.Set("account", "all")
err := p.SendAuthenticatedHTTPRequest(exchange.RestSpot,
http.MethodPost,
poloniexBalancesComplete,
vals,
&result)
return result, err
}
// GetDepositAddresses returns deposit addresses for all enabled cryptos.

View File

@@ -1,6 +1,7 @@
package poloniex
import (
"errors"
"net/http"
"strings"
"testing"
@@ -565,7 +566,7 @@ func TestWsSubAck(t *testing.T) {
}
func TestWsTicker(t *testing.T) {
err := p.getCurrencyIDMap()
err := p.loadCurrencyDetails()
if err != nil {
t.Error(err)
}
@@ -577,7 +578,7 @@ func TestWsTicker(t *testing.T) {
}
func TestWsExchangeVolume(t *testing.T) {
err := p.getCurrencyIDMap()
err := p.loadCurrencyDetails()
if err != nil {
t.Error(err)
}
@@ -589,7 +590,8 @@ func TestWsExchangeVolume(t *testing.T) {
}
func TestWsTrades(t *testing.T) {
err := p.getCurrencyIDMap()
p.SetSaveTradeDataStatus(true)
err := p.loadCurrencyDetails()
if err != nil {
t.Error(err)
}
@@ -601,7 +603,7 @@ func TestWsTrades(t *testing.T) {
}
func TestWsPriceAggregateOrderbook(t *testing.T) {
err := p.getCurrencyIDMap()
err := p.loadCurrencyDetails()
if err != nil {
t.Error(err)
}
@@ -617,25 +619,6 @@ func TestWsPriceAggregateOrderbook(t *testing.T) {
t.Error(err)
}
}
func TestWsHandleAccountData(t *testing.T) {
t.Parallel()
err := p.getCurrencyIDMap()
if err != nil {
t.Error(err)
}
jsons := []string{
`[1000,"",[["o",807230187,"0.00000000", "f"],["b",267,"e","0.10000000"]]]`,
`[1000,"",[["n",50,807230187,0,"1000.00000000","0.10000000","2018-11-07 16:42:42"],["b",267,"e","-0.10000000"]]]`,
`[1000,"",[["t", 12345, "0.03000000", "0.50000000", "0.00250000", 0, 6083059, "0.00000375", "2018-09-08 05:54:09", "12345"]]]`,
`[1000,"",[["k", 1337, ""]]]`,
}
for i := range jsons {
err := p.wsHandleData([]byte(jsons[i]))
if err != nil {
t.Error(err)
}
}
}
func TestGetHistoricCandles(t *testing.T) {
currencyPair, err := currency.NewPairFromString("BTC_LTC")
@@ -712,3 +695,330 @@ func TestGetHistoricTrades(t *testing.T) {
t.Error(err)
}
}
func TestProcessAccountMarginPosition(t *testing.T) {
err := p.loadCurrencyDetails()
if err != nil {
t.Error(err)
}
margin := []byte(`[1000,"",[["m", 23432933, 28, "-0.06000000"]]]`)
err = p.wsHandleData(margin)
if !errors.Is(err, errNotEnoughData) {
t.Fatalf("expected: %v but received: %v", errNotEnoughData, err)
}
margin = []byte(`[1000,"",[["m", "23432933", 28, "-0.06000000", null]]]`)
err = p.wsHandleData(margin)
if !errors.Is(err, errTypeAssertionFailure) {
t.Fatalf("expected: %v but received: %v", errTypeAssertionFailure, err)
}
margin = []byte(`[1000,"",[["m", 23432933, "28", "-0.06000000", null]]]`)
err = p.wsHandleData(margin)
if !errors.Is(err, errTypeAssertionFailure) {
t.Fatalf("expected: %v but received: %v", errTypeAssertionFailure, err)
}
margin = []byte(`[1000,"",[["m", 23432933, 28, -0.06000000, null]]]`)
err = p.wsHandleData(margin)
if !errors.Is(err, errTypeAssertionFailure) {
t.Fatalf("expected: %v but received: %v", errTypeAssertionFailure, err)
}
margin = []byte(`[1000,"",[["m", 23432933, 28, "-0.06000000", null]]]`)
err = p.wsHandleData(margin)
if err != nil {
t.Fatal(err)
}
}
func TestProcessAccountPendingOrder(t *testing.T) {
err := p.loadCurrencyDetails()
if err != nil {
t.Error(err)
}
pending := []byte(`[1000,"",[["p",431682155857,127,"1000.00000000","1.00000000","0"]]]`)
err = p.wsHandleData(pending)
if !errors.Is(err, errNotEnoughData) {
t.Fatalf("expected: %v but received: %v", errNotEnoughData, err)
}
pending = []byte(`[1000,"",[["p","431682155857",127,"1000.00000000","1.00000000","0",null]]]`)
err = p.wsHandleData(pending)
if !errors.Is(err, errTypeAssertionFailure) {
t.Fatalf("expected: %v but received: %v", errTypeAssertionFailure, err)
}
pending = []byte(`[1000,"",[["p",431682155857,"127","1000.00000000","1.00000000","0",null]]]`)
err = p.wsHandleData(pending)
if !errors.Is(err, errTypeAssertionFailure) {
t.Fatalf("expected: %v but received: %v", errTypeAssertionFailure, err)
}
pending = []byte(`[1000,"",[["p",431682155857,127,1000.00000000,"1.00000000","0",null]]]`)
err = p.wsHandleData(pending)
if !errors.Is(err, errTypeAssertionFailure) {
t.Fatalf("expected: %v but received: %v", errTypeAssertionFailure, err)
}
pending = []byte(`[1000,"",[["p",431682155857,127,"1000.00000000",1.00000000,"0",null]]]`)
err = p.wsHandleData(pending)
if !errors.Is(err, errTypeAssertionFailure) {
t.Fatalf("expected: %v but received: %v", errTypeAssertionFailure, err)
}
pending = []byte(`[1000,"",[["p",431682155857,127,"1000.00000000","1.00000000",0,null]]]`)
err = p.wsHandleData(pending)
if !errors.Is(err, errTypeAssertionFailure) {
t.Fatalf("expected: %v but received: %v", errTypeAssertionFailure, err)
}
pending = []byte(`[1000,"",[["p",431682155857,127,"1000.00000000","1.00000000","0",null]]]`)
err = p.wsHandleData(pending)
if err != nil {
t.Fatal(err)
}
// Unmatched pair in system
pending = []byte(`[1000,"",[["p",431682155857,666,"1000.00000000","1.00000000","0",null]]]`)
err = p.wsHandleData(pending)
if err != nil {
t.Fatal(err)
}
}
func TestProcessAccountOrderUpdate(t *testing.T) {
orderUpdate := []byte(`[1000,"",[["o",431682155857,"0.00000000","f"]]]`)
err := p.wsHandleData(orderUpdate)
if !errors.Is(err, errNotEnoughData) {
t.Fatalf("expected: %v but received: %v", errNotEnoughData, err)
}
orderUpdate = []byte(`[1000,"",[["o","431682155857","0.00000000","f",null]]]`)
err = p.wsHandleData(orderUpdate)
if !errors.Is(err, errTypeAssertionFailure) {
t.Fatalf("expected: %v but received: %v", errTypeAssertionFailure, err)
}
orderUpdate = []byte(`[1000,"",[["o",431682155857,0.00000000,"f",null]]]`)
err = p.wsHandleData(orderUpdate)
if !errors.Is(err, errTypeAssertionFailure) {
t.Fatalf("expected: %v but received: %v", errTypeAssertionFailure, err)
}
orderUpdate = []byte(`[1000,"",[["o",431682155857,"0.00000000",123,null]]]`)
err = p.wsHandleData(orderUpdate)
if !errors.Is(err, errTypeAssertionFailure) {
t.Fatalf("expected: %v but received: %v", errTypeAssertionFailure, err)
}
orderUpdate = []byte(`[1000,"",[["o",431682155857,"0.00000000","c",null]]]`)
err = p.wsHandleData(orderUpdate)
if !errors.Is(err, errNotEnoughData) {
t.Fatalf("expected: %v but received: %v", errNotEnoughData, err)
}
orderUpdate = []byte(`[1000,"",[["o",431682155857,"0.50000000","c",null,"0.50000000"]]]`)
err = p.wsHandleData(orderUpdate)
if err != nil {
t.Fatal(err)
}
orderUpdate = []byte(`[1000,"",[["o",431682155857,"0.00000000","c",null,"1.00000000"]]]`)
err = p.wsHandleData(orderUpdate)
if err != nil {
t.Fatal(err)
}
orderUpdate = []byte(`[1000,"",[["o",431682155857,"0.50000000","f",null]]]`)
err = p.wsHandleData(orderUpdate)
if err != nil {
t.Fatal(err)
}
orderUpdate = []byte(`[1000,"",[["o",431682155857,"0.00000000","s",null]]]`)
err = p.wsHandleData(orderUpdate)
if err != nil {
t.Fatal(err)
}
}
func TestProcessAccountOrderLimit(t *testing.T) {
err := p.loadCurrencyDetails()
if err != nil {
t.Error(err)
}
accountTrade := []byte(`[1000,"",[["n",127,431682155857,"0","1000.00000000","1.00000000","2021-04-13 07:19:56","1.00000000"]]]`)
err = p.wsHandleData(accountTrade)
if !errors.Is(err, errNotEnoughData) {
t.Fatalf("expected: %v but received: %v", errNotEnoughData, err)
}
accountTrade = []byte(`[1000,"",[["n","127",431682155857,"0","1000.00000000","1.00000000","2021-04-13 07:19:56","1.00000000",null]]]`)
err = p.wsHandleData(accountTrade)
if !errors.Is(err, errTypeAssertionFailure) {
t.Fatalf("expected: %v but received: %v", errTypeAssertionFailure, err)
}
accountTrade = []byte(`[1000,"",[["n",127,"431682155857","0","1000.00000000","1.00000000","2021-04-13 07:19:56","1.00000000",null]]]`)
err = p.wsHandleData(accountTrade)
if !errors.Is(err, errTypeAssertionFailure) {
t.Fatalf("expected: %v but received: %v", errTypeAssertionFailure, err)
}
accountTrade = []byte(`[1000,"",[["n",127,431682155857,0,"1000.00000000","1.00000000","2021-04-13 07:19:56","1.00000000",null]]]`)
err = p.wsHandleData(accountTrade)
if !errors.Is(err, errTypeAssertionFailure) {
t.Fatalf("expected: %v but received: %v", errTypeAssertionFailure, err)
}
accountTrade = []byte(`[1000,"",[["n",127,431682155857,"0",1000.00000000,"1.00000000","2021-04-13 07:19:56","1.00000000",null]]]`)
err = p.wsHandleData(accountTrade)
if !errors.Is(err, errTypeAssertionFailure) {
t.Fatalf("expected: %v but received: %v", errTypeAssertionFailure, err)
}
accountTrade = []byte(`[1000,"",[["n",127,431682155857,"0","1000.00000000",1.00000000,"2021-04-13 07:19:56","1.00000000",null]]]`)
err = p.wsHandleData(accountTrade)
if !errors.Is(err, errTypeAssertionFailure) {
t.Fatalf("expected: %v but received: %v", errTypeAssertionFailure, err)
}
accountTrade = []byte(`[1000,"",[["n",127,431682155857,"0","1000.00000000","1.00000000",1234,"1.00000000",null]]]`)
err = p.wsHandleData(accountTrade)
if !errors.Is(err, errTypeAssertionFailure) {
t.Fatalf("expected: %v but received: %v", errTypeAssertionFailure, err)
}
accountTrade = []byte(`[1000,"",[["n",127,431682155857,"0","1000.00000000","1.00000000","2021-04-13 07:19:56",1.00000000,null]]]`)
err = p.wsHandleData(accountTrade)
if !errors.Is(err, errTypeAssertionFailure) {
t.Fatalf("expected: %v but received: %v", errTypeAssertionFailure, err)
}
accountTrade = []byte(`[1000,"",[["n",127,431682155857,"0","1000.00000000","1.00000000","2021-04-13 07:19:56","1.00000000",null]]]`)
err = p.wsHandleData(accountTrade)
if err != nil {
t.Fatal(err)
}
}
func TestProcessAccountBalanceUpdate(t *testing.T) {
err := p.loadCurrencyDetails()
if err != nil {
t.Error(err)
}
balance := []byte(`[1000,"",[["b",243,"e"]]]`)
err = p.wsHandleData(balance)
if !errors.Is(err, errNotEnoughData) {
t.Fatalf("expected: %v but received: %v", errNotEnoughData, err)
}
balance = []byte(`[1000,"",[["b","243","e","-1.00000000"]]]`)
err = p.wsHandleData(balance)
if !errors.Is(err, errTypeAssertionFailure) {
t.Fatalf("expected: %v but received: %v", errTypeAssertionFailure, err)
}
balance = []byte(`[1000,"",[["b",243,1234,"-1.00000000"]]]`)
err = p.wsHandleData(balance)
if !errors.Is(err, errTypeAssertionFailure) {
t.Fatalf("expected: %v but received: %v", errTypeAssertionFailure, err)
}
balance = []byte(`[1000,"",[["b",243,"e",-1.00000000]]]`)
err = p.wsHandleData(balance)
if !errors.Is(err, errTypeAssertionFailure) {
t.Fatalf("expected: %v but received: %v", errTypeAssertionFailure, err)
}
balance = []byte(`[1000,"",[["b",243,"e","-1.00000000"]]]`)
err = p.wsHandleData(balance)
if err != nil {
t.Fatal(err)
}
}
func TestProcessAccountTrades(t *testing.T) {
accountTrades := []byte(`[1000,"",[["t", 12345, "0.03000000", "0.50000000", "0.00250000", 0, 6083059, "0.00000375", "2018-09-08 05:54:09", "12345"]]]`)
err := p.wsHandleData(accountTrades)
if !errors.Is(err, errNotEnoughData) {
t.Fatalf("expected: %v but received: %v", errNotEnoughData, err)
}
accountTrades = []byte(`[1000,"",[["t", "12345", "0.03000000", "0.50000000", "0.00250000", 0, 6083059, "0.00000375", "2018-09-08 05:54:09", "12345", "0.015"]]]`)
err = p.wsHandleData(accountTrades)
if !errors.Is(err, errTypeAssertionFailure) {
t.Fatalf("expected: %v but received: %v", errTypeAssertionFailure, err)
}
accountTrades = []byte(`[1000,"",[["t", 12345, 0.03000000, "0.50000000", "0.00250000", 0, 6083059, "0.00000375", "2018-09-08 05:54:09", "12345", "0.015"]]]`)
err = p.wsHandleData(accountTrades)
if !errors.Is(err, errTypeAssertionFailure) {
t.Fatalf("expected: %v but received: %v", errTypeAssertionFailure, err)
}
accountTrades = []byte(`[1000,"",[["t", 12345, "0.03000000", 0.50000000, "0.00250000", 0, 6083059, "0.00000375", "2018-09-08 05:54:09", "12345", "0.015"]]]`)
err = p.wsHandleData(accountTrades)
if !errors.Is(err, errTypeAssertionFailure) {
t.Fatalf("expected: %v but received: %v", errTypeAssertionFailure, err)
}
accountTrades = []byte(`[1000,"",[["t", 12345, "0.03000000", "0.50000000", "0.00250000", 0, 6083059, 0.00000375, "2018-09-08 05:54:09", "12345", "0.015"]]]`)
err = p.wsHandleData(accountTrades)
if !errors.Is(err, errTypeAssertionFailure) {
t.Fatalf("expected: %v but received: %v", errTypeAssertionFailure, err)
}
accountTrades = []byte(`[1000,"",[["t", 12345, "0.03000000", "0.50000000", "0.00250000", 0, 6083059, 0.0000037, "2018-09-08 05:54:09", "12345", "0.015"]]]`)
err = p.wsHandleData(accountTrades)
if !errors.Is(err, errTypeAssertionFailure) {
t.Fatalf("expected: %v but received: %v", errTypeAssertionFailure, err)
}
accountTrades = []byte(`[1000,"",[["t", 12345, "0.03000000", "0.50000000", "0.00250000", 0, 6083059, "0.00000375", 12345, "12345", 0.015]]]`)
err = p.wsHandleData(accountTrades)
if !errors.Is(err, errTypeAssertionFailure) {
t.Fatalf("expected: %v but received: %v", errTypeAssertionFailure, err)
}
accountTrades = []byte(`[1000,"",[["t", 12345, "0.03000000", "0.50000000", "0.00250000", 0, 6083059, "0.00000375", "2018-09-08 05:54:09", "12345", "0.015"]]]`)
err = p.wsHandleData(accountTrades)
if err != nil {
t.Fatal(err)
}
}
func TestProcessAccountKilledOrder(t *testing.T) {
kill := []byte(`[1000,"",[["k", 1337]]]`)
err := p.wsHandleData(kill)
if !errors.Is(err, errNotEnoughData) {
t.Fatalf("expected: %v but received: %v", errNotEnoughData, err)
}
kill = []byte(`[1000,"",[["k", "1337", null]]]`)
err = p.wsHandleData(kill)
if !errors.Is(err, errTypeAssertionFailure) {
t.Fatalf("expected: %v but received: %v", errTypeAssertionFailure, err)
}
kill = []byte(`[1000,"",[["k", 1337, null]]]`)
err = p.wsHandleData(kill)
if err != nil {
t.Fatal(err)
}
}
func TestGetCompleteBalances(t *testing.T) {
if !mockTests && !areTestAPIKeysSet() {
t.Skip("API keys not set, mockTests false, skipping test")
}
_, err := p.GetCompleteBalances()
if err != nil {
t.Fatal(err)
}
}

View File

@@ -16,9 +16,10 @@ type Ticker struct {
PercentChange float64 `json:"percentChange,string"`
BaseVolume float64 `json:"baseVolume,string"`
QuoteVolume float64 `json:"quoteVolume,string"`
IsFrozen int64 `json:"isFrozen,string"`
High24Hr float64 `json:"high24hr,string"`
Low24Hr float64 `json:"low24hr,string"`
IsFrozen uint8 `json:"isFrozen,string"`
PostOnly uint8 `json:"postOnly,string"`
}
// OrderbookResponseAll holds the full response type orderbook
@@ -27,9 +28,7 @@ type OrderbookResponseAll struct {
}
// CompleteBalances holds the full balance data
type CompleteBalances struct {
Currency map[string]CompleteBalance
}
type CompleteBalances map[string]CompleteBalance
// OrderbookResponse is a sub-type for orderbooks
type OrderbookResponse struct {
@@ -116,15 +115,14 @@ type ChartData struct {
// Currencies contains currency information
type Currencies struct {
ID float64 `json:"id"`
Name string `json:"name"`
MaxDailyWithdrawal string `json:"maxDailyWithdrawal"`
TxFee float64 `json:"txFee,string"`
MinConfirmations int64 `json:"minConf"`
DepositAddresses interface{} `json:"depositAddress"`
Disabled int64 `json:"disabled"`
Delisted int64 `json:"delisted"`
Frozen int64 `json:"frozen"`
ID float64 `json:"id"`
Name string `json:"name"`
TxFee float64 `json:"txFee,string"`
MinConfirmations int64 `json:"minConf"`
DepositAddress string `json:"depositAddress"`
WithdrawalDepositDisabled uint8 `json:"disabled"`
Delisted uint8 `json:"delisted"`
Frozen uint8 `json:"frozen"`
}
// LoanOrder holds loan order information
@@ -148,9 +146,9 @@ type Balance struct {
// CompleteBalance contains the complete balance with a btcvalue
type CompleteBalance struct {
Available float64
OnOrders float64
BTCValue float64
Available float64 `json:"available,string"`
OnOrders float64 `json:"onOrders,string"`
BTCValue float64 `json:"btcValue,string"`
}
// DepositAddresses holds the full address per crypto-currency
@@ -442,13 +440,6 @@ var WithdrawalFees = map[currency.Code]float64{
currency.ZEC: 0.001,
}
// WsAccountBalanceUpdateResponse Authenticated Ws Account data
type WsAccountBalanceUpdateResponse struct {
currencyID float64
wallet string
amount float64
}
// WsOrderUpdateResponse Authenticated Ws Account data
type WsOrderUpdateResponse struct {
OrderNumber float64

File diff suppressed because it is too large Load Diff