golangci-lint/CI: Bump versions and introduce new linters (#798)

* golangci-lint/CI: Bump versions

Fix remaining linter issues

* Specifically set AppVeyor version

* Fix the infamous typos 👀

* Add go env cmd to AppVeyor

* Add go version cmd to AppVeyor

* Specify AppVeyor image, adjust linters

* Update go get to go install due to deprecation

* Bump golangci-lint timeout time for AppVeyor

* Change NW contract to NQ

* Address nitters

* GetRandomPair -> Pair{}

* Address nits

* Address time nitterinos plus additional tweaks

* More time inception upgrades!

* Bending time and space
This commit is contained in:
Adrian Gallagher
2021-10-14 16:38:53 +11:00
committed by GitHub
parent 0a91af0f2e
commit f0d45aa1d2
194 changed files with 1506 additions and 1233 deletions

View File

@@ -26,10 +26,10 @@ func TestWait(t *testing.T) {
wg.Wait()
wg.Add(100)
isLeaky(&wait, nil, t)
isLeaky(t, &wait, nil)
wait.Alert()
wg.Wait()
isLeaky(&wait, nil, t)
isLeaky(t, &wait, nil)
// use kick
ch := make(chan struct{})
@@ -46,11 +46,11 @@ func TestWait(t *testing.T) {
}
wg.Wait()
wg.Add(100)
isLeaky(&wait, ch, t)
isLeaky(t, &wait, ch)
close(ch)
wg.Wait()
ch = make(chan struct{})
isLeaky(&wait, ch, t)
isLeaky(t, &wait, ch)
// late receivers
wg.Add(100)
@@ -70,15 +70,15 @@ func TestWait(t *testing.T) {
}
wg.Wait()
wg.Add(100)
isLeaky(&wait, ch, t)
isLeaky(t, &wait, ch)
wait.Alert()
wg.Wait()
isLeaky(&wait, ch, t)
isLeaky(t, &wait, ch)
}
// isLeaky tests to see if the wait functionality is returning an abnormal
// channel that is operational when it shouldn't be.
func isLeaky(a *Notice, ch chan struct{}, t *testing.T) {
func isLeaky(t *testing.T, a *Notice, ch chan struct{}) {
t.Helper()
check := a.Wait(ch)
time.Sleep(time.Millisecond * 5) // When we call wait a routine for hold is

View File

@@ -62,8 +62,7 @@ func TestIsValid(t *testing.T) {
}
func TestNew(t *testing.T) {
_, err := New("Spota")
if err == nil {
if _, err := New("Spota"); err == nil {
t.Fatal("TestNew returned an unexpected result")
}

View File

@@ -374,51 +374,59 @@ func (b *Binance) GetSpotKline(ctx context.Context, arg *KlinesRequestParams) ([
path := candleStick + "?" + params.Encode()
if err := b.SendHTTPRequest(ctx,
err = b.SendHTTPRequest(ctx,
exchange.RestSpotSupplementary,
path,
spotDefaultRate,
&resp); err != nil {
return klineData, err
&resp)
if err != nil {
return nil, err
}
for _, responseData := range resp.([]interface{}) {
responseData, ok := resp.([]interface{})
if !ok {
return nil, errors.New("unable to type assert responseData")
}
for x := range responseData {
individualData, ok := responseData[x].([]interface{})
if !ok {
return nil, errors.New("unable to type assert individualData")
}
if len(individualData) != 12 {
return nil, errors.New("unexpected kline data length")
}
var candle CandleStick
for i, individualData := range responseData.([]interface{}) {
switch i {
case 0:
tempTime := individualData.(float64)
var err error
candle.OpenTime, err = convert.TimeFromUnixTimestampFloat(tempTime)
if err != nil {
return klineData, err
}
case 1:
candle.Open, _ = strconv.ParseFloat(individualData.(string), 64)
case 2:
candle.High, _ = strconv.ParseFloat(individualData.(string), 64)
case 3:
candle.Low, _ = strconv.ParseFloat(individualData.(string), 64)
case 4:
candle.Close, _ = strconv.ParseFloat(individualData.(string), 64)
case 5:
candle.Volume, _ = strconv.ParseFloat(individualData.(string), 64)
case 6:
tempTime := individualData.(float64)
var err error
candle.CloseTime, err = convert.TimeFromUnixTimestampFloat(tempTime)
if err != nil {
return klineData, err
}
case 7:
candle.QuoteAssetVolume, _ = strconv.ParseFloat(individualData.(string), 64)
case 8:
candle.TradeCount = individualData.(float64)
case 9:
candle.TakerBuyAssetVolume, _ = strconv.ParseFloat(individualData.(string), 64)
case 10:
candle.TakerBuyQuoteAssetVolume, _ = strconv.ParseFloat(individualData.(string), 64)
}
if candle.OpenTime, err = convert.TimeFromUnixTimestampFloat(individualData[0]); err != nil {
return nil, err
}
if candle.Open, err = convert.FloatFromString(individualData[1]); err != nil {
return nil, err
}
if candle.High, err = convert.FloatFromString(individualData[2]); err != nil {
return nil, err
}
if candle.Low, err = convert.FloatFromString(individualData[3]); err != nil {
return nil, err
}
if candle.Close, err = convert.FloatFromString(individualData[4]); err != nil {
return nil, err
}
if candle.Volume, err = convert.FloatFromString(individualData[5]); err != nil {
return nil, err
}
if candle.CloseTime, err = convert.TimeFromUnixTimestampFloat(individualData[6]); err != nil {
return nil, err
}
if candle.QuoteAssetVolume, err = convert.FloatFromString(individualData[7]); err != nil {
return nil, err
}
if candle.TradeCount, ok = individualData[8].(float64); !ok {
return nil, errors.New("unable to type assert trade count")
}
if candle.TakerBuyAssetVolume, err = convert.FloatFromString(individualData[9]); err != nil {
return nil, err
}
if candle.TakerBuyQuoteAssetVolume, err = convert.FloatFromString(individualData[10]); err != nil {
return nil, err
}
klineData = append(klineData, candle)
}
@@ -784,7 +792,7 @@ func (b *Binance) SendAuthHTTPRequest(ctx context.Context, ePath exchange.URL, m
}
if params.Get("recvWindow") == "" {
params.Set("recvWindow", strconv.FormatInt(convert.RecvWindow(defaultRecvWindow), 10))
params.Set("recvWindow", strconv.FormatInt(defaultRecvWindow.Milliseconds(), 10))
}
interim := json.RawMessage{}

View File

@@ -1,4 +1,5 @@
//+build !mock_test_off
//go:build !mock_test_off
// +build !mock_test_off
// This will build if build tag mock_test_off is not parsed and will try to mock
// all tests in _test.go

View File

@@ -1622,6 +1622,7 @@ func TestGetAggregatedTradesBatched(t *testing.T) {
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
if tt.mock != mockTests {
t.Skip()
}
@@ -1677,6 +1678,7 @@ func TestGetAggregatedTradesErrors(t *testing.T) {
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
_, err := b.GetAggregatedTrades(context.Background(), tt.args)
if err == nil {
t.Errorf("Binance.GetAggregatedTrades() error = %v, wantErr true", err)
@@ -2550,8 +2552,8 @@ func TestWsOrderExecutionReport(t *testing.T) {
Side: order.Buy,
Status: order.New,
AssetType: asset.Spot,
Date: time.Unix(0, 1616627567900*int64(time.Millisecond)),
LastUpdated: time.Unix(0, 1616627567900*int64(time.Millisecond)),
Date: time.UnixMilli(1616627567900),
LastUpdated: time.UnixMilli(1616627567900),
Pair: currency.NewPair(currency.BTC, currency.USDT),
}
// empty the channel. otherwise mock_test will fail
@@ -2583,8 +2585,7 @@ func TestWsOrderExecutionReport(t *testing.T) {
func TestWsOutboundAccountPosition(t *testing.T) {
t.Parallel()
payload := []byte(`{"stream":"jTfvpakT2yT0hVIo5gYWVihZhdM2PrBgJUZ5PyfZ4EVpCkx4Uoxk5timcrQc","data":{"e":"outboundAccountPosition","E":1616628815745,"u":1616628815745,"B":[{"a":"BTC","f":"0.00225109","l":"0.00123000"},{"a":"BNB","f":"0.00000000","l":"0.00000000"},{"a":"USDT","f":"54.43390661","l":"0.00000000"}]}}`)
err := b.wsHandleData(payload)
if err != nil {
if err := b.wsHandleData(payload); err != nil {
t.Fatal(err)
}
}

View File

@@ -371,7 +371,7 @@ func (b *Binance) FetchTradablePairs(ctx context.Context, a asset.Item) ([]strin
case asset.CoinMarginedFutures:
cInfo, err := b.FuturesExchangeInfo(ctx)
if err != nil {
return pairs, nil
return pairs, err
}
for z := range cInfo.Symbols {
if cInfo.Symbols[z].ContractStatus == "TRADING" {
@@ -385,7 +385,7 @@ func (b *Binance) FetchTradablePairs(ctx context.Context, a asset.Item) ([]strin
case asset.USDTMarginedFutures:
uInfo, err := b.UExchangeInfo(ctx)
if err != nil {
return pairs, nil
return pairs, err
}
for u := range uInfo.Symbols {
if uInfo.Symbols[u].Status == "TRADING" {
@@ -751,8 +751,7 @@ func (b *Binance) UpdateAccountInfo(ctx context.Context, assetType asset.Item) (
}
acc.AssetType = assetType
info.Accounts = append(info.Accounts, acc)
err := account.Process(&info)
if err != nil {
if err := account.Process(&info); err != nil {
return account.Holdings{}, err
}
return info, nil

View File

@@ -10,6 +10,7 @@ import (
)
func TestRateLimit_Limit(t *testing.T) {
t.Parallel()
symbol := "BTC-USDT"
testTable := map[string]struct {
@@ -56,6 +57,7 @@ func TestRateLimit_Limit(t *testing.T) {
}
func TestRateLimit_LimitStatic(t *testing.T) {
t.Parallel()
testTable := map[string]request.EndpointLimit{
"Default": spotDefaultRate,
"Historical Trades": spotHistoricalTradesRate,

View File

@@ -4,8 +4,6 @@ import (
"encoding/json"
"strconv"
"time"
"github.com/thrasher-corp/gocryptotrader/common/convert"
)
// binanceTime provides an internal conversion helper
@@ -16,7 +14,7 @@ func (t *binanceTime) UnmarshalJSON(data []byte) error {
if err := json.Unmarshal(data, &timestamp); err != nil {
return err
}
*t = binanceTime(time.Unix(0, timestamp*int64(time.Millisecond)))
*t = binanceTime(time.UnixMilli(timestamp))
return nil
}
@@ -27,7 +25,7 @@ func (t binanceTime) Time() time.Time {
// timeString gets the time as Binance timestamp
func timeString(t time.Time) string {
return strconv.FormatInt(convert.UnixMillis(t), 10)
return strconv.FormatInt(t.UnixMilli(), 10)
}
// UnmarshalJSON deserialises the JSON info, including the timestamp
@@ -74,11 +72,8 @@ func (a *NewOrderResponse) UnmarshalJSON(data []byte) error {
if err := json.Unmarshal(data, &aux); err != nil {
return err
}
// there can be an empty response, then `a` is set to nil
if aux != nil {
a.TransactionTime = aux.TransactionTime.Time()
} else {
a = nil
}
return nil
}

View File

@@ -319,16 +319,18 @@ func (b *Bitfinex) GetV2FundingInfo(ctx context.Context, key string) (MarginFund
if len(fundingData) < 4 {
return response, fmt.Errorf("%v GetV2FundingInfo: invalid length of fundingData", b.Name)
}
for x := 0; x < 3; x++ {
_, ok := fundingData[x].(float64)
if !ok {
return response, fmt.Errorf("type conversion failed for x = %d", x)
}
if response.Data.YieldLoan, ok = fundingData[0].(float64); !ok {
return response, errors.New("type conversion failed for YieldLoan")
}
if response.Data.YieldLend, ok = fundingData[1].(float64); !ok {
return response, errors.New("type conversion failed for YieldLend")
}
if response.Data.DurationLoan, ok = fundingData[2].(float64); !ok {
return response, errors.New("type conversion failed for DurationLoan")
}
if response.Data.DurationLend, ok = fundingData[3].(float64); !ok {
return response, errors.New("type conversion failed for DurationLend")
}
response.Data.YieldLoan = fundingData[0].(float64)
response.Data.YieldLend = fundingData[1].(float64)
response.Data.DurationLoan = fundingData[2].(float64)
response.Data.DurationLend = fundingData[3].(float64)
return response, nil
}
@@ -637,7 +639,10 @@ func (b *Bitfinex) GetTrades(ctx context.Context, currencyPair string, limit, ti
var history []Trade
for i := range resp {
amount := resp[i][2].(float64)
amount, ok := resp[i][2].(float64)
if !ok {
return nil, errors.New("unable to type assert amount")
}
side := order.Buy.String()
if amount < 0 {
side = order.Sell.String()
@@ -693,10 +698,21 @@ func (b *Bitfinex) GetOrderbook(ctx context.Context, symbol, precision string, l
var b Book
if len(response[x]) > 3 {
// Funding currency
b.Amount = response[x][3].(float64)
b.Rate = response[x][2].(float64)
b.Period = response[x][1].(float64)
b.OrderID = int64(response[x][0].(float64))
var ok bool
if b.Amount, ok = response[x][3].(float64); !ok {
return Orderbook{}, errors.New("unable to type assert amount")
}
if b.Rate, ok = response[x][2].(float64); !ok {
return Orderbook{}, errors.New("unable to type assert rate")
}
if b.Period, ok = response[x][1].(float64); !ok {
return Orderbook{}, errors.New("unable to type assert period")
}
orderID, ok := response[x][0].(float64)
if !ok {
return Orderbook{}, errors.New("unable to type assert orderID")
}
b.OrderID = int64(orderID)
if b.Amount > 0 {
o.Asks = append(o.Asks, b)
} else {
@@ -705,9 +721,18 @@ func (b *Bitfinex) GetOrderbook(ctx context.Context, symbol, precision string, l
}
} else {
// Trading currency
b.Amount = response[x][2].(float64)
b.Price = response[x][1].(float64)
b.OrderID = int64(response[x][0].(float64))
var ok bool
if b.Amount, ok = response[x][2].(float64); !ok {
return Orderbook{}, errors.New("unable to type assert amount")
}
if b.Price, ok = response[x][1].(float64); !ok {
return Orderbook{}, errors.New("unable to type assert price")
}
orderID, ok := response[x][0].(float64)
if !ok {
return Orderbook{}, errors.New("unable to type assert order ID")
}
b.OrderID = int64(orderID)
if b.Amount > 0 {
o.Bids = append(o.Bids, b)
} else {
@@ -721,10 +746,21 @@ func (b *Bitfinex) GetOrderbook(ctx context.Context, symbol, precision string, l
var b Book
if len(response[x]) > 3 {
// Funding currency
b.Amount = response[x][3].(float64)
b.Count = int64(response[x][2].(float64))
b.Period = response[x][1].(float64)
b.Rate = response[x][0].(float64)
var ok bool
if b.Amount, ok = response[x][3].(float64); !ok {
return Orderbook{}, errors.New("unable to type assert amount")
}
count, ok := response[x][2].(float64)
if !ok {
return Orderbook{}, errors.New("unable to type assert count")
}
b.Count = int64(count)
if b.Period, ok = response[x][1].(float64); !ok {
return Orderbook{}, errors.New("unable to type assert period")
}
if b.Rate, ok = response[x][0].(float64); !ok {
return Orderbook{}, errors.New("unable to type assert rate")
}
if b.Amount > 0 {
o.Asks = append(o.Asks, b)
} else {
@@ -733,9 +769,18 @@ func (b *Bitfinex) GetOrderbook(ctx context.Context, symbol, precision string, l
}
} else {
// Trading currency
b.Amount = response[x][2].(float64)
b.Count = int64(response[x][1].(float64))
b.Price = response[x][0].(float64)
var ok bool
if b.Amount, ok = response[x][2].(float64); !ok {
return Orderbook{}, errors.New("unable to type assert amount")
}
count, ok := response[x][1].(float64)
if !ok {
return Orderbook{}, errors.New("unable to type assert count")
}
b.Count = int64(count)
if b.Price, ok = response[x][0].(float64); !ok {
return Orderbook{}, errors.New("unable to type assert price")
}
if b.Amount > 0 {
o.Bids = append(o.Bids, b)
} else {
@@ -940,12 +985,34 @@ func (b *Bitfinex) GetLeaderboard(ctx context.Context, key, timeframe, symbol st
var result []LeaderboardEntry
for x := range resp {
r := resp[x].([]interface{})
r, ok := resp[x].([]interface{})
if !ok {
return nil, errors.New("unable to type assert leaderboard")
}
if len(r) < 10 {
return nil, errors.New("unexpected leaderboard data length")
}
tm, ok := r[0].(float64)
if !ok {
return nil, errors.New("unable to type assert time")
}
username, ok := r[2].(string)
if !ok {
return nil, errors.New("unable to type assert username")
}
ranking, ok := r[3].(float64)
if !ok {
return nil, errors.New("unable to type assert ranking")
}
value, ok := r[6].(float64)
if !ok {
return nil, errors.New("unable to type assert value")
}
result = append(result, LeaderboardEntry{
Timestamp: time.Unix(0, int64(r[0].(float64))*int64(time.Millisecond)),
Username: r[2].(string),
Ranking: int(r[3].(float64)),
Value: r[6].(float64),
Timestamp: time.UnixMilli(int64(tm)),
Username: username,
Ranking: int(ranking),
Value: value,
TwitterHandle: parseTwitterHandle(r[9]),
})
}

View File

@@ -1067,9 +1067,9 @@ func TestWsAuth(t *testing.T) {
}
func runAuth(t *testing.T) {
t.Helper()
setupWs()
err := b.WsSendAuth()
if err != nil {
if err := b.WsSendAuth(); err != nil {
t.Error(err)
}
timer := time.NewTimer(sharedtestvalues.WebsocketResponseDefaultTimeout)
@@ -1118,8 +1118,7 @@ func TestWsCancelOrder(t *testing.T) {
if !wsAuthExecuted {
runAuth(t)
}
err := b.WsCancelOrder(1234)
if err != nil {
if err := b.WsCancelOrder(1234); err != nil {
t.Error(err)
}
}
@@ -1150,8 +1149,7 @@ func TestWsCancelAllOrders(t *testing.T) {
if !wsAuthExecuted {
runAuth(t)
}
err := b.WsCancelAllOrders()
if err != nil {
if err := b.WsCancelAllOrders(); err != nil {
t.Error(err)
}
}
@@ -1198,8 +1196,7 @@ func TestWsCancelOffer(t *testing.T) {
if !wsAuthExecuted {
runAuth(t)
}
err := b.WsCancelOffer(1234)
if err != nil {
if err := b.WsCancelOffer(1234); err != nil {
t.Error(err)
}
}

View File

@@ -14,6 +14,7 @@ import (
"github.com/gorilla/websocket"
"github.com/thrasher-corp/gocryptotrader/common"
"github.com/thrasher-corp/gocryptotrader/common/convert"
"github.com/thrasher-corp/gocryptotrader/common/crypto"
"github.com/thrasher-corp/gocryptotrader/currency"
exchange "github.com/thrasher-corp/gocryptotrader/exchanges"
@@ -159,7 +160,10 @@ func (b *Bitfinex) wsHandleData(respRaw []byte) error {
)
}
case "auth":
status := d["status"].(string)
status, ok := d["status"].(string)
if !ok {
return errors.New("unable to type assert status")
}
if status == "OK" {
b.Websocket.DataHandler <- d
b.WsAddSubscriptionChannel(0, "account", "N/A")
@@ -266,24 +270,27 @@ func (b *Bitfinex) wsHandleData(respRaw []byte) error {
switch id := obSnapBundle[0].(type) {
case []interface{}:
for i := range obSnapBundle {
data := obSnapBundle[i].([]interface{})
data, ok := obSnapBundle[i].([]interface{})
if !ok {
return errors.New("type assertion failed for orderbok item data")
}
id, okAssert := data[0].(float64)
if !okAssert {
return errors.New("type assertion failed for orderbook item data")
return errors.New("type assertion failed for orderbook id data")
}
pricePeriod, okAssert := data[1].(float64)
if !okAssert {
return errors.New("type assertion failed for orderbook item data")
return errors.New("type assertion failed for orderbook price data")
}
rateAmount, okAssert := data[2].(float64)
if !okAssert {
return errors.New("type assertion failed for orderbook item data")
return errors.New("type assertion failed for orderbook rate data")
}
if len(data) == 4 {
fundingRate = true
amount, okFunding := data[3].(float64)
if !okFunding {
return errors.New("type assertion failed for orderbook item data")
return errors.New("type assertion failed for orderbook funding data")
}
newOrderbook = append(newOrderbook, WebsocketBook{
ID: int64(id),
@@ -297,26 +304,25 @@ func (b *Bitfinex) wsHandleData(respRaw []byte) error {
Amount: rateAmount})
}
}
err := b.WsInsertSnapshot(pair, chanAsset, newOrderbook, fundingRate)
if err != nil {
if err = b.WsInsertSnapshot(pair, chanAsset, newOrderbook, fundingRate); err != nil {
return fmt.Errorf("inserting snapshot error: %s",
err)
}
case float64:
pricePeriod, okSnap := obSnapBundle[1].(float64)
if !okSnap {
return errors.New("type assertion failed for orderbook snapshot data")
return errors.New("type assertion failed for orderbook price snapshot data")
}
amountRate, okSnap := obSnapBundle[2].(float64)
if !okSnap {
return errors.New("type assertion failed for orderbook snapshot data")
return errors.New("type assertion failed for orderbook amount snapshot data")
}
if len(obSnapBundle) == 4 {
fundingRate = true
var amount float64
amount, okSnap = obSnapBundle[3].(float64)
if !okSnap {
return errors.New("type assertion failed for orderbook snapshot data")
return errors.New("type assertion failed for orderbook amount snapshot data")
}
newOrderbook = append(newOrderbook, WebsocketBook{
ID: int64(id),
@@ -330,8 +336,7 @@ func (b *Bitfinex) wsHandleData(respRaw []byte) error {
Amount: amountRate})
}
err := b.WsUpdateOrderbook(pair, chanAsset, newOrderbook, chanID, int64(sequenceNo), fundingRate)
if err != nil {
if err = b.WsUpdateOrderbook(pair, chanAsset, newOrderbook, chanID, int64(sequenceNo), fundingRate); err != nil {
return fmt.Errorf("updating orderbook error: %s",
err)
}
@@ -347,37 +352,73 @@ func (b *Bitfinex) wsHandleData(respRaw []byte) error {
switch candleData := candleBundle[0].(type) {
case []interface{}:
for i := range candleBundle {
element := candleBundle[i].([]interface{})
b.Websocket.DataHandler <- stream.KlineData{
Timestamp: time.Unix(0, int64(element[0].(float64))*int64(time.Millisecond)),
Exchange: b.Name,
AssetType: chanAsset,
Pair: pair,
OpenPrice: element[1].(float64),
ClosePrice: element[2].(float64),
HighPrice: element[3].(float64),
LowPrice: element[4].(float64),
Volume: element[5].(float64),
var element []interface{}
element, ok = candleBundle[i].([]interface{})
if !ok {
return errors.New("type assertion for element data")
}
if len(element) < 6 {
return errors.New("invalid candleBundle length")
}
var klineData stream.KlineData
if klineData.Timestamp, err = convert.TimeFromUnixTimestampFloat(element[0]); err != nil {
return fmt.Errorf("unable to convert timestamp: %w", err)
}
if klineData.OpenPrice, ok = element[1].(float64); !ok {
return errors.New("unable to type assert OpenPrice")
}
if klineData.ClosePrice, ok = element[2].(float64); !ok {
return errors.New("unable to type assert ClosePrice")
}
if klineData.HighPrice, ok = element[3].(float64); !ok {
return errors.New("unable to type assert HighPrice")
}
if klineData.LowPrice, ok = element[4].(float64); !ok {
return errors.New("unable to type assert LowPrice")
}
if klineData.Volume, ok = element[5].(float64); !ok {
return errors.New("unable to type assert volume")
}
klineData.Exchange = b.Name
klineData.AssetType = chanAsset
klineData.Pair = pair
b.Websocket.DataHandler <- klineData
}
case float64:
b.Websocket.DataHandler <- stream.KlineData{
Timestamp: time.Unix(0, int64(candleData)*int64(time.Millisecond)),
Exchange: b.Name,
AssetType: chanAsset,
Pair: pair,
OpenPrice: candleBundle[1].(float64),
ClosePrice: candleBundle[2].(float64),
HighPrice: candleBundle[3].(float64),
LowPrice: candleBundle[4].(float64),
Volume: candleBundle[5].(float64),
if len(candleBundle) < 6 {
return errors.New("invalid candleBundle length")
}
var klineData stream.KlineData
if klineData.Timestamp, err = convert.TimeFromUnixTimestampFloat(candleData); err != nil {
return fmt.Errorf("unable to convert timestamp: %w", err)
}
if klineData.OpenPrice, ok = candleBundle[1].(float64); !ok {
return errors.New("unable to type assert OpenPrice")
}
if klineData.ClosePrice, ok = candleBundle[2].(float64); !ok {
return errors.New("unable to type assert ClosePrice")
}
if klineData.HighPrice, ok = candleBundle[3].(float64); !ok {
return errors.New("unable to type assert HighPrice")
}
if klineData.LowPrice, ok = candleBundle[4].(float64); !ok {
return errors.New("unable to type assert LowPrice")
}
if klineData.Volume, ok = candleBundle[5].(float64); !ok {
return errors.New("unable to type assert volume")
}
klineData.Exchange = b.Name
klineData.AssetType = chanAsset
klineData.Pair = pair
b.Websocket.DataHandler <- klineData
}
}
return nil
case wsTicker:
tickerData := d[1].([]interface{})
tickerData, ok := d[1].([]interface{})
if !ok {
return errors.New("type assertion for tickerData")
}
if len(tickerData) == 10 {
b.Websocket.DataHandler <- &ticker.Price{
ExchangeName: b.Name,
@@ -421,9 +462,15 @@ func (b *Bitfinex) wsHandleData(respRaw []byte) error {
var tradeHolder []WebsocketTrade
switch len(d) {
case 2:
snapshot := d[1].([]interface{})
snapshot, ok := d[1].([]interface{})
if !ok {
return errors.New("unable to type assert snapshot data")
}
for i := range snapshot {
elem := snapshot[i].([]interface{})
elem, ok := snapshot[i].([]interface{})
if !ok {
return errors.New("unable to type assert snapshot element data")
}
if len(elem) == 5 {
tradeHolder = append(tradeHolder, WebsocketTrade{
ID: int64(elem[0].(float64)),
@@ -446,7 +493,10 @@ func (b *Bitfinex) wsHandleData(respRaw []byte) error {
d[1].(string) != wsTradeExecutionUpdate {
return nil
}
data := d[2].([]interface{})
data, ok := d[2].([]interface{})
if !ok {
return errors.New("data type assertion error")
}
if len(data) == 5 {
tradeHolder = append(tradeHolder, WebsocketTrade{
ID: int64(data[0].(float64)),
@@ -479,7 +529,7 @@ func (b *Bitfinex) wsHandleData(respRaw []byte) error {
trades = append(trades, trade.Data{
TID: strconv.FormatInt(tradeHolder[i].ID, 10),
CurrencyPair: pair,
Timestamp: time.Unix(0, tradeHolder[i].Timestamp*int64(time.Millisecond)),
Timestamp: time.UnixMilli(tradeHolder[i].Timestamp),
Price: price,
Amount: newAmount,
Exchange: b.Name,
@@ -496,9 +546,15 @@ func (b *Bitfinex) wsHandleData(respRaw []byte) error {
case wsHeartbeat, pong:
return nil
case wsNotification:
notification := d[2].([]interface{})
notification, ok := d[2].([]interface{})
if !ok {
return errors.New("unable to type assert notification data")
}
if data, ok := notification[4].([]interface{}); ok {
channelName := notification[1].(string)
channelName, ok := notification[1].(string)
if !ok {
return errors.New("unable to type assert channelName")
}
switch {
case strings.Contains(channelName, wsFundingOrderNewRequest),
strings.Contains(channelName, wsFundingOrderUpdateRequest),
@@ -527,18 +583,26 @@ func (b *Bitfinex) wsHandleData(respRaw []byte) error {
respRaw)
}
}
if notification[5] != nil &&
strings.EqualFold(notification[5].(string), wsError) {
return fmt.Errorf("%s - Error %s",
b.Name,
notification[6].(string))
if notification[5] != nil {
if wsErr, ok := notification[5].(string); ok {
if strings.EqualFold(wsErr, wsError) {
if errMsg, ok := notification[6].(string); ok {
return fmt.Errorf("%s - Error %s",
b.Name,
errMsg)
}
return fmt.Errorf("%s - unhandled error message: %v", b.Name,
notification[6])
}
}
}
case wsOrderSnapshot:
if snapBundle, ok := d[2].([]interface{}); ok && len(snapBundle) > 0 {
if _, ok := snapBundle[0].([]interface{}); ok {
for i := range snapBundle {
positionData := snapBundle[i].([]interface{})
b.wsHandleOrder(positionData)
if positionData, ok := snapBundle[i].([]interface{}); ok {
b.wsHandleOrder(positionData)
}
}
}
}
@@ -551,7 +615,10 @@ func (b *Bitfinex) wsHandleData(respRaw []byte) error {
if snapBundle, ok := d[2].([]interface{}); ok && len(snapBundle) > 0 {
if _, ok := snapBundle[0].([]interface{}); ok {
for i := range snapBundle {
positionData := snapBundle[i].([]interface{})
positionData, ok := snapBundle[i].([]interface{})
if !ok {
return errors.New("unable to type assert wsPositionSnapshot positionData")
}
position := WebsocketPosition{
Pair: positionData[0].(string),
Status: positionData[1].(string),
@@ -606,7 +673,10 @@ func (b *Bitfinex) wsHandleData(respRaw []byte) error {
if snapBundle, ok := d[2].([]interface{}); ok && len(snapBundle) > 0 {
if _, ok := snapBundle[0].([]interface{}); ok {
for i := range snapBundle {
data := snapBundle[i].([]interface{})
data, ok := snapBundle[i].([]interface{})
if !ok {
return errors.New("unable to type assert wsFundingOrderSnapshot snapBundle data")
}
offer := WsFundingOffer{
ID: int64(data[0].(float64)),
Symbol: data[1].(string),
@@ -639,7 +709,10 @@ func (b *Bitfinex) wsHandleData(respRaw []byte) error {
if snapBundle, ok := d[2].([]interface{}); ok && len(snapBundle) > 0 {
if _, ok := snapBundle[0].([]interface{}); ok {
for i := range snapBundle {
data := snapBundle[i].([]interface{})
data, ok := snapBundle[i].([]interface{})
if !ok {
return errors.New("unable to type assert wsFundingCreditSnapshot snapBundle data")
}
credit := WsCredit{
ID: int64(data[0].(float64)),
Symbol: data[1].(string),
@@ -695,7 +768,10 @@ func (b *Bitfinex) wsHandleData(respRaw []byte) error {
if snapBundle, ok := d[2].([]interface{}); ok && len(snapBundle) > 0 {
if _, ok := snapBundle[0].([]interface{}); ok {
for i := range snapBundle {
data := snapBundle[i].([]interface{})
data, ok := snapBundle[i].([]interface{})
if !ok {
return errors.New("unable to type assert wsFundingLoanSnapshot snapBundle data")
}
credit := WsCredit{
ID: int64(data[0].(float64)),
Symbol: data[1].(string),
@@ -749,10 +825,13 @@ func (b *Bitfinex) wsHandleData(respRaw []byte) error {
if snapBundle, ok := d[2].([]interface{}); ok && len(snapBundle) > 0 {
if _, ok := snapBundle[0].([]interface{}); ok {
for i := range snapBundle {
data := snapBundle[i].([]interface{})
data, ok := snapBundle[i].([]interface{})
if !ok {
return errors.New("unable to type assert wsWalletSnapshot snapBundle data")
}
var balanceAvailable float64
if _, ok := data[4].(float64); ok {
balanceAvailable = data[4].(float64)
if v, ok := data[4].(float64); ok {
balanceAvailable = v
}
wallet := WsWallet{
Type: data[0].(string),
@@ -769,8 +848,8 @@ func (b *Bitfinex) wsHandleData(respRaw []byte) error {
case wsWalletUpdate:
if data, ok := d[2].([]interface{}); ok && len(data) > 0 {
var balanceAvailable float64
if _, ok := data[4].(float64); ok {
balanceAvailable = data[4].(float64)
if v, ok := data[4].(float64); ok {
balanceAvailable = v
}
b.Websocket.DataHandler <- WsWallet{
Type: data[0].(string),
@@ -791,7 +870,10 @@ func (b *Bitfinex) wsHandleData(respRaw []byte) error {
if data, ok := d[2].([]interface{}); ok && len(data) > 0 {
if data[0].(string) == "base" {
if infoBase, ok := d[2].([]interface{}); ok && len(infoBase) > 0 {
baseData := data[1].([]interface{})
baseData, ok := data[1].([]interface{})
if !ok {
return errors.New("unable to type assert wsMarginInfoUpdate baseData")
}
b.Websocket.DataHandler <- WsMarginInfoBase{
UserProfitLoss: baseData[0].(float64),
UserSwaps: baseData[1].(float64),
@@ -804,7 +886,10 @@ func (b *Bitfinex) wsHandleData(respRaw []byte) error {
case wsFundingInfoUpdate:
if data, ok := d[2].([]interface{}); ok && len(data) > 0 {
if data[0].(string) == "sym" {
symbolData := data[1].([]interface{})
symbolData, ok := data[1].([]interface{})
if !ok {
return errors.New("unable to type assert wsFundingInfoUpdate symbolData")
}
b.Websocket.DataHandler <- WsFundingInfo{
YieldLoan: symbolData[0].(float64),
YieldLend: symbolData[1].(float64),
@@ -839,53 +924,86 @@ func (b *Bitfinex) wsHandleData(respRaw []byte) error {
func (b *Bitfinex) wsHandleFundingOffer(data []interface{}) {
var fo WsFundingOffer
if data[0] != nil {
fo.ID = int64(data[0].(float64))
if id, ok := data[0].(float64); ok {
fo.ID = int64(id)
}
}
if data[1] != nil {
fo.Symbol = data[1].(string)[1:]
if sym, ok := data[1].(string); ok {
fo.Symbol = sym[1:]
}
}
if data[2] != nil {
fo.Created = int64(data[2].(float64))
if created, ok := data[2].(float64); ok {
fo.Created = int64(created)
}
}
if data[3] != nil {
fo.Updated = int64(data[0].(float64))
if updated, ok := data[3].(float64); ok {
fo.Updated = int64(updated)
}
}
if data[15] != nil {
fo.Period = int64(data[15].(float64))
if period, ok := data[15].(float64); ok {
fo.Period = int64(period)
}
}
if data[4] != nil {
fo.Amount = data[4].(float64)
if amount, ok := data[4].(float64); ok {
fo.Amount = amount
}
}
if data[5] != nil {
fo.OriginalAmount = data[5].(float64)
if origAmount, ok := data[5].(float64); ok {
fo.OriginalAmount = origAmount
}
}
if data[6] != nil {
fo.Type = data[6].(string)
if fType, ok := data[6].(string); ok {
fo.Type = fType
}
}
if data[9] != nil {
fo.Flags = data[9].(float64)
if flags, ok := data[9].(float64); ok {
fo.Flags = flags
}
}
if data[9] != nil {
fo.Status = data[10].(string)
if data[9] != nil && data[10] != nil {
if status, ok := data[10].(string); ok {
fo.Status = status
}
}
if data[9] != nil {
fo.Rate = data[14].(float64)
if data[9] != nil && data[14] != nil {
if rate, ok := data[14].(float64); ok {
fo.Rate = rate
}
}
if data[16] != nil {
fo.Notify = data[16].(float64) == 1
if notify, ok := data[16].(float64); ok {
fo.Notify = notify == 1
}
}
if data[17] != nil {
fo.Hidden = data[17].(float64) == 1
if hidden, ok := data[17].(float64); ok {
fo.Hidden = hidden == 1
}
}
if data[18] != nil {
fo.Insure = data[18].(float64) == 1
if insure, ok := data[18].(float64); ok {
fo.Insure = insure == 1
}
}
if data[19] != nil {
fo.Renew = data[19].(float64) == 1
if renew, ok := data[19].(float64); ok {
fo.Renew = renew == 1
}
}
if data[20] != nil {
fo.RateReal = data[20].(float64)
if rateReal, ok := data[20].(float64); ok {
fo.RateReal = rateReal
}
}
b.Websocket.DataHandler <- fo
@@ -896,54 +1014,74 @@ func (b *Bitfinex) wsHandleOrder(data []interface{}) {
var err error
od.Exchange = b.Name
if data[0] != nil {
od.ID = strconv.FormatFloat(data[0].(float64), 'f', -1, 64)
if id, ok := data[0].(float64); ok {
od.ID = strconv.FormatFloat(id, 'f', -1, 64)
}
}
if data[16] != nil {
od.Price = data[16].(float64)
if price, ok := data[16].(float64); ok {
od.Price = price
}
}
if data[7] != nil {
od.Amount = data[7].(float64)
if amount, ok := data[7].(float64); ok {
od.Amount = amount
}
}
if data[6] != nil {
od.RemainingAmount = data[6].(float64)
if remainingAmount, ok := data[6].(float64); ok {
od.RemainingAmount = remainingAmount
}
}
if data[7] != nil && data[6] != nil {
od.ExecutedAmount = data[7].(float64) - data[6].(float64)
if executedAmount, ok := data[7].(float64); ok {
od.ExecutedAmount = executedAmount - od.RemainingAmount
}
}
if data[4] != nil {
od.Date = time.Unix(int64(data[4].(float64))*1000, 0)
if date, ok := data[4].(float64); ok {
od.Date = time.Unix(int64(date)*1000, 0)
}
}
if data[5] != nil {
od.LastUpdated = time.Unix(int64(data[5].(float64))*1000, 0)
if lastUpdated, ok := data[5].(float64); ok {
od.LastUpdated = time.Unix(int64(lastUpdated)*1000, 0)
}
}
if data[2] != nil {
od.Pair, od.AssetType, err = b.GetRequestFormattedPairAndAssetType(data[3].(string)[1:])
if err != nil {
b.Websocket.DataHandler <- err
return
if p, ok := data[3].(string); ok {
od.Pair, od.AssetType, err = b.GetRequestFormattedPairAndAssetType(p[1:])
if err != nil {
b.Websocket.DataHandler <- err
return
}
}
}
if data[8] != nil {
oType, err := order.StringToOrderType(data[8].(string))
if err != nil {
b.Websocket.DataHandler <- order.ClassificationError{
Exchange: b.Name,
OrderID: od.ID,
Err: err,
if ordType, ok := data[8].(string); ok {
oType, err := order.StringToOrderType(ordType)
if err != nil {
b.Websocket.DataHandler <- order.ClassificationError{
Exchange: b.Name,
OrderID: od.ID,
Err: err,
}
}
od.Type = oType
}
od.Type = oType
}
if data[13] != nil {
oStatus, err := order.StringToOrderStatus(data[13].(string))
if err != nil {
b.Websocket.DataHandler <- order.ClassificationError{
Exchange: b.Name,
OrderID: od.ID,
Err: err,
if ordStatus, ok := data[13].(string); ok {
oStatus, err := order.StringToOrderStatus(ordStatus)
if err != nil {
b.Websocket.DataHandler <- order.ClassificationError{
Exchange: b.Name,
OrderID: od.ID,
Err: err,
}
}
od.Status = oStatus
}
od.Status = oStatus
}
b.Websocket.DataHandler <- &od
}
@@ -1242,19 +1380,45 @@ func (b *Bitfinex) WsNewOrder(data *WsNewOrderRequest) (string, error) {
if err != nil {
return "", err
}
responseDataDetail := respData[2].([]interface{})
responseOrderDetail := responseDataDetail[4].([]interface{})
var orderID string
if responseOrderDetail[0] != nil && responseOrderDetail[0].(float64) > 0 {
orderID = strconv.FormatFloat(responseOrderDetail[0].(float64), 'f', -1, 64)
}
errCode := responseDataDetail[6].(string)
errorMessage := responseDataDetail[7].(string)
if len(respData) < 3 {
return "", errors.New("unexpected respData length")
}
responseDataDetail, ok := respData[2].([]interface{})
if !ok {
return "", errors.New("unable to type assert respData")
}
if len(responseDataDetail) < 4 {
return "", errors.New("invalid responseDataDetail length")
}
responseOrderDetail, ok := responseDataDetail[4].([]interface{})
if !ok {
return "", errors.New("unable to type assert responseOrderDetail")
}
var orderID string
if responseOrderDetail[0] != nil {
if ordID, ordOK := responseOrderDetail[0].(float64); ordOK && ordID > 0 {
orderID = strconv.FormatFloat(ordID, 'f', -1, 64)
}
}
var errorMessage, errCode string
if len(responseDataDetail) > 6 {
errCode, ok = responseDataDetail[6].(string)
if !ok {
return "", errors.New("unable to type assert errCode")
}
}
if len(responseDataDetail) > 7 {
errorMessage, ok = responseDataDetail[7].(string)
if !ok {
return "", errors.New("unable to type assert errorMessage")
}
}
if strings.EqualFold(errCode, wsError) {
return orderID, errors.New(b.Name + " - " + errCode + ": " + errorMessage)
}
return orderID, nil
}
@@ -1274,13 +1438,29 @@ func (b *Bitfinex) WsModifyOrder(data *WsUpdateOrderRequest) error {
if err != nil {
return err
}
responseOrderData := responseData[2].([]interface{})
errCode := responseOrderData[6].(string)
errorMessage := responseOrderData[7].(string)
if len(responseData) < 3 {
return errors.New("unexpected responseData length")
}
responseOrderData, ok := responseData[2].([]interface{})
if !ok {
return errors.New("unable to type assert responseOrderData")
}
var errorMessage, errCode string
if len(responseOrderData) > 6 {
errCode, ok = responseOrderData[6].(string)
if !ok {
return errors.New("unable to type assert errCode")
}
}
if len(responseOrderData) > 7 {
errorMessage, ok = responseOrderData[7].(string)
if !ok {
return errors.New("unable to type assert errorMessage")
}
}
if strings.EqualFold(errCode, wsError) {
return errors.New(b.Name + " - " + errCode + ": " + errorMessage)
}
return nil
}
@@ -1311,13 +1491,29 @@ func (b *Bitfinex) WsCancelOrder(orderID int64) error {
if err != nil {
return err
}
responseOrderData := responseData[2].([]interface{})
errCode := responseOrderData[6].(string)
errorMessage := responseOrderData[7].(string)
if len(responseData) < 3 {
return errors.New("unexpected responseData length")
}
responseOrderData, ok := responseData[2].([]interface{})
if !ok {
return errors.New("unable to type assert responseOrderData")
}
var errorMessage, errCode string
if len(responseOrderData) > 6 {
errCode, ok = responseOrderData[6].(string)
if !ok {
return errors.New("unable to type assert errCode")
}
}
if len(responseOrderData) > 7 {
errorMessage, ok = responseOrderData[7].(string)
if !ok {
return errors.New("unable to type assert errorMessage")
}
}
if strings.EqualFold(errCode, wsError) {
return errors.New(b.Name + " - " + errCode + ": " + errorMessage)
}
return nil
}
@@ -1352,11 +1548,25 @@ func (b *Bitfinex) WsCancelOffer(orderID int64) error {
if err != nil {
return err
}
responseOrderData := responseData[2].([]interface{})
errCode := responseOrderData[6].(string)
var errorMessage string
if responseOrderData[7] != nil {
errorMessage = responseOrderData[7].(string)
if len(responseData) < 3 {
return errors.New("unexpected responseData length")
}
responseOrderData, ok := responseData[2].([]interface{})
if !ok {
return errors.New("unable to type assert responseOrderData")
}
var errorMessage, errCode string
if len(responseOrderData) > 6 {
errCode, ok = responseOrderData[6].(string)
if !ok {
return errors.New("unable to type assert errCode")
}
}
if len(responseOrderData) > 7 {
errorMessage, ok = responseOrderData[7].(string)
if !ok {
return errors.New("unable to type assert errorMessage")
}
}
if strings.EqualFold(errCode, wsError) {
return errors.New(b.Name + " - " + errCode + ": " + errorMessage)

View File

@@ -365,8 +365,7 @@ func (b *Bitfinex) UpdateTickers(ctx context.Context, a asset.Item) error {
// UpdateTicker updates and returns the ticker for a currency pair
func (b *Bitfinex) UpdateTicker(ctx context.Context, p currency.Pair, a asset.Item) (*ticker.Price, error) {
err := b.UpdateTickers(ctx, a)
if err != nil {
if err := b.UpdateTickers(ctx, a); err != nil {
return nil, err
}
return ticker.GetTicker(b.Name, p, a)
@@ -567,7 +566,7 @@ allTrades:
return nil, err
}
for i := range tradeData {
tradeTS := time.Unix(0, tradeData[i].Timestamp*int64(time.Millisecond))
tradeTS := time.UnixMilli(tradeData[i].Timestamp)
if tradeTS.Before(timestampStart) && !timestampStart.IsZero() {
break allTrades
}
@@ -579,7 +578,7 @@ allTrades:
AssetType: assetType,
Price: tradeData[i].Price,
Amount: tradeData[i].Amount,
Timestamp: time.Unix(0, tradeData[i].Timestamp*int64(time.Millisecond)),
Timestamp: time.UnixMilli(tradeData[i].Timestamp),
})
if i == len(tradeData)-1 {
if ts.Equal(tradeTS) {

View File

@@ -236,7 +236,11 @@ func (b *Bithumb) GetAccountBalance(ctx context.Context, c string) (FullBalance,
return fullBalance, err
}
} else {
val = datum.(float64)
var ok bool
val, ok = datum.(float64)
if !ok {
return fullBalance, errors.New("unable to type assert datum")
}
}
switch splitTag[0] {
@@ -529,7 +533,7 @@ func (b *Bithumb) SendAuthenticatedHTTPRequest(ctx context.Context, ep exchange.
var intermediary json.RawMessage
err = b.SendPayload(ctx, request.Auth, func() (*request.Item, error) {
// This is time window sensitive
tnMS := time.Now().UnixNano() / int64(time.Millisecond)
tnMS := time.Now().UnixMilli()
n := strconv.FormatInt(tnMS, 10)
params.Set("endpoint", path)

View File

@@ -291,8 +291,7 @@ func (b *Bithumb) UpdateTickers(ctx context.Context, a asset.Item) error {
// UpdateTicker updates and returns the ticker for a currency pair
func (b *Bithumb) UpdateTicker(ctx context.Context, p currency.Pair, a asset.Item) (*ticker.Price, error) {
err := b.UpdateTickers(ctx, a)
if err != nil {
if err := b.UpdateTickers(ctx, a); err != nil {
return nil, err
}
return ticker.GetTicker(b.Name, p, a)
@@ -818,60 +817,33 @@ func (b *Bithumb) GetHistoricCandles(ctx context.Context, pair currency.Pair, a
}
for x := range candle.Data {
if len(candle.Data[x]) < 6 {
return kline.Item{}, errors.New("invalid candle length")
}
var tempCandle kline.Candle
tempTime := candle.Data[x][0].(float64)
timestamp := time.Unix(0, int64(tempTime)*int64(time.Millisecond))
if timestamp.Before(start) {
if tempCandle.Time, err = convert.TimeFromUnixTimestampFloat(candle.Data[x][0]); err != nil {
return kline.Item{}, fmt.Errorf("unable to convert timestamp: %w", err)
}
if tempCandle.Time.Before(start) {
continue
}
if timestamp.After(end) {
if tempCandle.Time.After(end) {
break
}
tempCandle.Time = timestamp
open, ok := candle.Data[x][1].(string)
if !ok {
return kline.Item{}, errors.New("open conversion failed")
if tempCandle.Open, err = convert.FloatFromString(candle.Data[x][1]); err != nil {
return kline.Item{}, fmt.Errorf("kline open conversion failed: %w", err)
}
tempCandle.Open, err = strconv.ParseFloat(open, 64)
if err != nil {
return kline.Item{}, err
if tempCandle.High, err = convert.FloatFromString(candle.Data[x][2]); err != nil {
return kline.Item{}, fmt.Errorf("kline high conversion failed: %w", err)
}
high, ok := candle.Data[x][2].(string)
if !ok {
return kline.Item{}, errors.New("high conversion failed")
if tempCandle.Low, err = convert.FloatFromString(candle.Data[x][3]); err != nil {
return kline.Item{}, fmt.Errorf("kline low conversion failed: %w", err)
}
tempCandle.High, err = strconv.ParseFloat(high, 64)
if err != nil {
return kline.Item{}, err
if tempCandle.Close, err = convert.FloatFromString(candle.Data[x][4]); err != nil {
return kline.Item{}, fmt.Errorf("kline close conversion failed: %w", err)
}
low, ok := candle.Data[x][3].(string)
if !ok {
return kline.Item{}, errors.New("low conversion failed")
}
tempCandle.Low, err = strconv.ParseFloat(low, 64)
if err != nil {
return kline.Item{}, err
}
closeTemp, ok := candle.Data[x][4].(string)
if !ok {
return kline.Item{}, errors.New("close conversion failed")
}
tempCandle.Close, err = strconv.ParseFloat(closeTemp, 64)
if err != nil {
return kline.Item{}, err
}
vol, ok := candle.Data[x][5].(string)
if !ok {
return kline.Item{}, errors.New("vol conversion failed")
}
tempCandle.Volume, err = strconv.ParseFloat(vol, 64)
if err != nil {
return kline.Item{}, err
if tempCandle.Volume, err = convert.FloatFromString(candle.Data[x][5]); err != nil {
return kline.Item{}, fmt.Errorf("kline volume conversion failed: %w", err)
}
ret.Candles = append(ret.Candles, tempCandle)
}

View File

@@ -442,7 +442,7 @@ func (b *Bithumb) SeedLocalCacheWithBook(p currency.Pair, o *Orderbook) error {
newOrderBook.Pair = p
newOrderBook.Asset = asset.Spot
newOrderBook.Exchange = b.Name
newOrderBook.LastUpdated = time.Unix(0, o.Data.Timestamp*int64(time.Millisecond))
newOrderBook.LastUpdated = time.UnixMilli(o.Data.Timestamp)
newOrderBook.VerifyOrderbook = b.CanVerifyOrderbook
return b.Websocket.Orderbook.LoadSnapshot(&newOrderBook)
}

View File

@@ -20,7 +20,7 @@ func TestBithumbTime(t *testing.T) {
tt := newTime.Time()
if tt.UTC().String() != "2021-08-12 03:39:50 +0000 UTC" {
t.Fatalf("expected: %s but receieved: %s",
t.Fatalf("expected: %s but received: %s",
"2021-08-12 03:39:50 +0000 UTC",
tt.UTC().String())
}

View File

@@ -320,8 +320,7 @@ func (b *Bitmex) UpdateTickers(ctx context.Context, a asset.Item) error {
// UpdateTicker updates and returns the ticker for a currency pair
func (b *Bitmex) UpdateTicker(ctx context.Context, p currency.Pair, a asset.Item) (*ticker.Price, error) {
err := b.UpdateTickers(ctx, a)
if err != nil {
if err := b.UpdateTickers(ctx, a); err != nil {
return nil, err
}

View File

@@ -370,7 +370,7 @@ func (b *Bittrex) SendAuthHTTPRequest(ctx context.Context, ep exchange.URL, meth
}
newRequest := func() (*request.Item, error) {
ts := strconv.FormatInt(time.Now().UnixNano()/1000000, 10)
ts := strconv.FormatInt(time.Now().UnixMilli(), 10)
path := common.EncodeURLValues(action, params)
var body io.Reader

View File

@@ -568,6 +568,7 @@ func TestModifyOrder(t *testing.T) {
}
func WithdrawCryptocurrencyFunds(t *testing.T) {
t.Helper()
withdrawCryptoRequest := withdraw.Request{
Amount: -1,
Currency: currency.BTC,

View File

@@ -156,7 +156,7 @@ func (b *Bittrex) WsAuth() error {
if err != nil {
return err
}
timestamp := strconv.FormatInt(time.Now().UnixNano()/1000000, 10)
timestamp := strconv.FormatInt(time.Now().UnixMilli(), 10)
hmac, err := crypto.GetHMAC(
crypto.HashSHA512,
[]byte(timestamp+randomContent.String()),

View File

@@ -950,8 +950,8 @@ func (b *Bittrex) GetHistoricCandles(ctx context.Context, pair currency.Pair, a
year, month, day := start.Date()
curYear, curMonth, curDay := time.Now().Date()
getHistoric := false
getRecent := false
getHistoric := false // nolint:ifshort,nolintlint // false positive and triggers only on Windows
getRecent := false // nolint:ifshort,nolintlint // false positive and triggers only on Windows
switch interval {
case kline.OneMin, kline.FiveMin:

View File

@@ -704,7 +704,7 @@ func (b *BTCMarkets) SendAuthenticatedRequest(ctx context.Context, method, path
newRequest := func() (*request.Item, error) {
now := time.Now()
strTime := strconv.FormatInt(now.UTC().UnixNano()/1000000, 10)
strTime := strconv.FormatInt(now.UTC().UnixMilli(), 10)
var body io.Reader
var payload, hmac []byte

View File

@@ -343,7 +343,7 @@ func (b *BTCMarkets) Subscribe(channelsToSubscribe []stream.ChannelSubscription)
if !common.StringDataCompare(payload.Channels, authChannels[i]) {
continue
}
signTime := strconv.FormatInt(time.Now().UTC().UnixNano()/1000000, 10)
signTime := strconv.FormatInt(time.Now().UTC().UnixMilli(), 10)
strToSign := "/users/self/subscribe" + "\n" + signTime
tempSign, err := crypto.GetHMAC(crypto.HashSHA512,
[]byte(strToSign),

View File

@@ -332,8 +332,7 @@ func (b *BTCMarkets) UpdateTickers(ctx context.Context, a asset.Item) error {
// UpdateTicker updates and returns the ticker for a currency pair
func (b *BTCMarkets) UpdateTicker(ctx context.Context, p currency.Pair, a asset.Item) (*ticker.Price, error) {
err := b.UpdateTickers(ctx, a)
if err != nil {
if err := b.UpdateTickers(ctx, a); err != nil {
return nil, err
}
return ticker.GetTicker(b.Name, p, a)

View File

@@ -477,7 +477,7 @@ func (b *BTSE) SendAuthenticatedHTTPRequest(ctx context.Context, ep exchange.URL
var hmac []byte
var body io.Reader
nonce := strconv.FormatInt(time.Now().UnixNano()/int64(time.Millisecond), 10)
nonce := strconv.FormatInt(time.Now().UnixMilli(), 10)
headers := map[string]string{
"btse-api": b.API.Credentials.Key,
"btse-nonce": nonce,

View File

@@ -543,12 +543,11 @@ func TestGetFee(t *testing.T) {
}
func TestParseOrderTime(t *testing.T) {
expected := int64(1534792846)
actual, err := parseOrderTime("2018-08-20 19:20:46")
if err != nil {
t.Fatal(err)
}
if expected != actual.Unix() {
if expected := int64(1534792846); expected != actual.Unix() {
t.Errorf("TestParseOrderTime expected: %d, got %d", expected, actual.Unix())
}
}
@@ -920,8 +919,7 @@ func TestWsLogin(t *testing.T) {
func TestWsSubscription(t *testing.T) {
t.Parallel()
data := []byte(`{"event":"subscribe","channel":["orderBookL2Api:SFI-ETH_0","tradeHistory:SFI-ETH"]}`)
err := b.wsHandleData(data)
if err != nil {
if err := b.wsHandleData(data); err != nil {
t.Error(err)
}
}

View File

@@ -57,7 +57,7 @@ func (b *BTSE) WsConnect() error {
// WsAuthenticate Send an authentication message to receive auth data
func (b *BTSE) WsAuthenticate() error {
nonce := strconv.FormatInt(time.Now().UnixNano()/int64(time.Millisecond), 10)
nonce := strconv.FormatInt(time.Now().UnixMilli(), 10)
path := "/spotWS" + nonce
hmac, err := crypto.GetHMAC(crypto.HashSHA512_384,
@@ -216,7 +216,7 @@ func (b *BTSE) wsHandleData(respRaw []byte) error {
Side: oSide,
Status: oStatus,
AssetType: a,
Date: time.Unix(0, notification.Data[i].Timestamp*int64(time.Millisecond)),
Date: time.UnixMilli(notification.Data[i].Timestamp),
Pair: p,
}
}
@@ -250,7 +250,7 @@ func (b *BTSE) wsHandleData(respRaw []byte) error {
return err
}
trades = append(trades, trade.Data{
Timestamp: time.Unix(0, tradeHistory.Data[x].TransactionTime*int64(time.Millisecond)),
Timestamp: time.UnixMilli(tradeHistory.Data[x].TransactionTime),
CurrencyPair: p,
AssetType: a,
Exchange: b.Name,

View File

@@ -313,8 +313,7 @@ func (b *BTSE) UpdateTickers(ctx context.Context, a asset.Item) error {
// UpdateTicker updates and returns the ticker for a currency pair
func (b *BTSE) UpdateTicker(ctx context.Context, p currency.Pair, a asset.Item) (*ticker.Price, error) {
err := b.UpdateTickers(ctx, a)
if err != nil {
if err := b.UpdateTickers(ctx, a); err != nil {
return nil, err
}
return ticker.GetTicker(b.Name, p, a)
@@ -589,7 +588,7 @@ func (b *BTSE) CancelAllOrders(ctx context.Context, orderCancellation *order.Can
allOrders, err := b.CancelExistingOrder(ctx, "", fPair.String(), "")
if err != nil {
return resp, nil
return resp, err
}
resp.Status = make(map[string]string)

View File

@@ -432,7 +432,10 @@ func (c *CoinbasePro) UpdateOrderbook(ctx context.Context, p currency.Pair, asse
return book, err
}
obNew := orderbookNew.(OrderbookL1L2)
obNew, ok := orderbookNew.(OrderbookL1L2)
if !ok {
return book, errors.New("unable to type assert orderbook data")
}
for x := range obNew.Bids {
book.Bids = append(book.Bids, orderbook.Item{
Amount: obNew.Bids[x].Amount,

View File

@@ -443,8 +443,7 @@ func (c *Coinbene) getCurrencyFromWsTopic(assetType asset.Item, channelTopic str
// Subscribe sends a websocket message to receive data from the channel
func (c *Coinbene) Subscribe(channelsToSubscribe []stream.ChannelSubscription) error {
maxSubsPerHour := 240
if len(channelsToSubscribe) > maxSubsPerHour {
if maxSubsPerHour := 240; len(channelsToSubscribe) > maxSubsPerHour {
return fmt.Errorf("channel subscriptions length %d exceeds coinbene's limit of %d, try reducing enabled pairs",
len(channelsToSubscribe),
maxSubsPerHour)

View File

@@ -382,8 +382,7 @@ func (c *Coinbene) UpdateTickers(ctx context.Context, a asset.Item) error {
// UpdateTicker updates and returns the ticker for a currency pair
func (c *Coinbene) UpdateTicker(ctx context.Context, p currency.Pair, a asset.Item) (*ticker.Price, error) {
err := c.UpdateTickers(ctx, a)
if err != nil {
if err := c.UpdateTickers(ctx, a); err != nil {
return nil, err
}
return ticker.GetTicker(c.Name, p, a)
@@ -893,11 +892,17 @@ func (c *Coinbene) GetHistoricCandles(ctx context.Context, pair currency.Pair, a
}
for x := range candles.Data {
if len(candles.Data[x]) < 6 {
return kline.Item{}, errors.New("unexpected candle data length")
}
var tempCandle kline.Candle
tempTime := candles.Data[x][0].(string)
tempTime, ok := candles.Data[x][0].(string)
if !ok {
return kline.Item{}, errors.New("timestamp conversion failed")
}
timestamp, err := time.Parse(time.RFC3339, tempTime)
if err != nil {
continue
return kline.Item{}, err
}
tempCandle.Time = timestamp
open, ok := candles.Data[x][1].(string)

View File

@@ -438,8 +438,7 @@ func (i *instrumentMap) Seed(curr string, id int64) {
}
// check to see if the instrument already exists
_, ok := i.Instruments[curr]
if ok {
if _, ok := i.Instruments[curr]; ok {
return
}

View File

@@ -59,6 +59,7 @@ func TestMain(m *testing.M) {
}
func setupWSTestAuth(t *testing.T) {
t.Helper()
if wsSetupRan {
return
}
@@ -430,8 +431,7 @@ func TestGetDepositAddress(t *testing.T) {
// TestWsAuthGetAccountBalance dials websocket, retrieves account balance
func TestWsAuthGetAccountBalance(t *testing.T) {
setupWSTestAuth(t)
_, err := c.wsGetAccountBalance()
if err != nil {
if _, err := c.wsGetAccountBalance(); err != nil {
t.Error(err)
}
}
@@ -449,8 +449,7 @@ func TestWsAuthSubmitOrder(t *testing.T) {
Price: 1,
Side: order.Buy,
}
_, err := c.wsSubmitOrder(&ord)
if err != nil {
if _, err := c.wsSubmitOrder(&ord); err != nil {
t.Error(err)
}
}

View File

@@ -630,18 +630,31 @@ func (c *COINUT) SubmitOrder(ctx context.Context, o *order.Submit) (order.Submit
if err != nil {
return submitOrderResponse, err
}
responseMap := APIResponse.(map[string]interface{})
switch responseMap["reply"].(string) {
responseMap, ok := APIResponse.(map[string]interface{})
if !ok {
return submitOrderResponse, errors.New("unable to type assert responseMap")
}
orderType, ok := responseMap["reply"].(string)
if !ok {
return submitOrderResponse, errors.New("unable to type assert orderType")
}
switch orderType {
case "order_rejected":
return submitOrderResponse, fmt.Errorf("clientOrderID: %v was rejected: %v", o.ClientID, responseMap["reasons"])
case "order_filled":
orderID := responseMap["order_id"].(float64)
orderID, ok := responseMap["order_id"].(float64)
if !ok {
return submitOrderResponse, errors.New("unable to type assert orderID")
}
submitOrderResponse.OrderID = strconv.FormatFloat(orderID, 'f', -1, 64)
submitOrderResponse.IsOrderPlaced = true
submitOrderResponse.FullyMatched = true
return submitOrderResponse, nil
case "order_accepted":
orderID := responseMap["order_id"].(float64)
orderID, ok := responseMap["order_id"].(float64)
if !ok {
return submitOrderResponse, errors.New("unable to type assert orderID")
}
submitOrderResponse.OrderID = strconv.FormatFloat(orderID, 'f', -1, 64)
submitOrderResponse.IsOrderPlaced = true
return submitOrderResponse, nil

View File

@@ -409,7 +409,7 @@ func (b *Base) GetPairFormat(assetType asset.Item, requestFormat bool) (currency
func (b *Base) GetEnabledPairs(a asset.Item) (currency.Pairs, error) {
err := b.CurrencyPairs.IsAssetEnabled(a)
if err != nil {
return nil, nil
return nil, nil // nolint:nilerr // non-fatal error
}
format, err := b.GetPairFormat(a, false)
if err != nil {
@@ -1156,7 +1156,7 @@ func (b *Base) FormatExchangeKlineInterval(in kline.Interval) string {
// ValidateKline confirms that the requested pair, asset & interval are supported and/or enabled by the requested exchange
func (b *Base) ValidateKline(pair currency.Pair, a asset.Item, interval kline.Interval) error {
var errorList []string
var err kline.ErrorKline
var err kline.Error
if b.CurrencyPairs.IsAssetEnabled(a) != nil {
err.Asset = a
errorList = append(errorList, "asset not enabled")
@@ -1242,7 +1242,7 @@ func (e *Endpoints) SetRunning(key, val string) error {
key,
val,
e.Exchange)
return nil
return nil // nolint:nilerr // non-fatal error as we won't update the running URL
}
e.defaults[key] = val
return nil

View File

@@ -752,8 +752,7 @@ func TestGetName(t *testing.T) {
Name: "TESTNAME",
}
name := b.GetName()
if name != "TESTNAME" {
if name := b.GetName(); name != "TESTNAME" {
t.Error("Exchange GetName() returned incorrect name")
}
}
@@ -1167,8 +1166,7 @@ func TestFormatExchangeCurrencies(t *testing.T) {
if err != nil {
t.Errorf("Exchange TestFormatExchangeCurrencies error %s", err)
}
expected := "btc~usd^ltc~btc"
if actual != expected {
if expected := "btc~usd^ltc~btc"; actual != expected {
t.Errorf("Exchange TestFormatExchangeCurrencies %s != %s",
actual, expected)
}
@@ -1801,8 +1799,7 @@ func TestGetBase(t *testing.T) {
func TestGetAssetType(t *testing.T) {
var b Base
p := currency.NewPair(currency.BTC, currency.USD)
_, err := b.GetPairAssetType(p)
if err == nil {
if _, err := b.GetPairAssetType(p); err == nil {
t.Fatal("error cannot be nil")
}
b.CurrencyPairs.Pairs = make(map[asset.Item]*currency.PairStore)
@@ -2410,6 +2407,7 @@ func TestAssetWebsocketFunctionality(t *testing.T) {
}
func TestGetGetURLTypeFromString(t *testing.T) {
t.Parallel()
testCases := []struct {
Endpoint string
Expected URL

View File

@@ -213,7 +213,11 @@ func (e *EXMO) GetCryptoDepositAddress(ctx context.Context) (map[string]string,
case map[string]interface{}:
mapString := make(map[string]string)
for key, value := range r {
mapString[key] = value.(string)
v, ok := value.(string)
if !ok {
return nil, errors.New("unable to type assert value data")
}
mapString[key] = v
}
return mapString, nil

View File

@@ -219,8 +219,7 @@ func (e *EXMO) UpdateTickers(ctx context.Context, a asset.Item) error {
// UpdateTicker updates and returns the ticker for a currency pair
func (e *EXMO) UpdateTicker(ctx context.Context, p currency.Pair, a asset.Item) (*ticker.Price, error) {
err := e.UpdateTickers(ctx, a)
if err != nil {
if err := e.UpdateTickers(ctx, a); err != nil {
return nil, err
}
return ticker.GetTicker(e.Name, p, a)

View File

@@ -1151,7 +1151,7 @@ func (f *FTX) SendAuthHTTPRequest(ctx context.Context, ep exchange.URL, method,
}
newRequest := func() (*request.Item, error) {
ts := strconv.FormatInt(time.Now().UnixNano()/1000000, 10)
ts := strconv.FormatInt(time.Now().UnixMilli(), 10)
var body io.Reader
var hmac, payload []byte

View File

@@ -1364,7 +1364,7 @@ func TestCompatibleOrderVars(t *testing.T) {
t.Errorf("received %v expected %v", orderVars.Status, order.Filled)
}
orderVars, err = f.compatibleOrderVars(context.Background(),
_, err = f.compatibleOrderVars(context.Background(),
"buy",
"closed",
"limit",
@@ -1375,7 +1375,7 @@ func TestCompatibleOrderVars(t *testing.T) {
t.Errorf("received %v expected %v", err, errInvalidOrderAmounts)
}
orderVars, err = f.compatibleOrderVars(context.Background(),
_, err = f.compatibleOrderVars(context.Background(),
"buy",
"fake",
"limit",

View File

@@ -77,7 +77,7 @@ func (f *FTX) WsConnect() error {
// WsAuth sends an authentication message to receive auth data
func (f *FTX) WsAuth() error {
intNonce := time.Now().UnixNano() / 1000000
intNonce := time.Now().UnixMilli()
strNonce := strconv.FormatInt(intNonce, 10)
hmac, err := crypto.GetHMAC(
crypto.HashSHA256,

View File

@@ -251,8 +251,7 @@ func TestParsingOrders(t *testing.T) {
},
"type": "update"
}`)
err := f.wsHandleData(data)
if err != nil {
if err := f.wsHandleData(data); err != nil {
t.Error(err)
}
}
@@ -274,8 +273,7 @@ func TestParsingWSTradesData(t *testing.T) {
}
]
}`)
err := f.wsHandleData(data)
if err != nil {
if err := f.wsHandleData(data); err != nil {
t.Error(err)
}
}
@@ -295,8 +293,7 @@ func TestParsingWSTickerData(t *testing.T) {
"time": 1589505004.4237103
}
}`)
err := f.wsHandleData(data)
if err != nil {
if err := f.wsHandleData(data); err != nil {
t.Error(err)
}
}
@@ -323,8 +320,7 @@ func TestParsingWSOrdersData(t *testing.T) {
},
"type": "update"
}`)
err := f.wsHandleData(data)
if err != nil {
if err := f.wsHandleData(data); err != nil {
t.Error(err)
}
}
@@ -360,8 +356,7 @@ func TestParsingMarketsData(t *testing.T) {
"group": "quarterly"}}},
"action": "partial"
}`)
err := f.wsHandleData(data)
if err != nil {
if err := f.wsHandleData(data); err != nil {
t.Error(err)
}
}

View File

@@ -52,9 +52,6 @@ func (g *Gateio) GetSymbols(ctx context.Context) ([]string, error) {
var result []string
urlPath := fmt.Sprintf("/%s/%s", gateioAPIVersion, gateioSymbol)
err := g.SendHTTPRequest(ctx, exchange.RestSpotSupplementary, urlPath, &result)
if err != nil {
return nil, nil
}
return result, err
}
@@ -76,9 +73,15 @@ func (g *Gateio) GetMarketInfo(ctx context.Context) (MarketInfoResponse, error)
result.Result = res.Result
for _, v := range res.Pairs {
item := v.(map[string]interface{})
item, ok := v.(map[string]interface{})
if !ok {
return result, errors.New("unable to type assert item")
}
for itemk, itemv := range item {
pairv := itemv.(map[string]interface{})
pairv, ok := itemv.(map[string]interface{})
if !ok {
return result, errors.New("unable to type assert pairv")
}
result.Pairs = append(result.Pairs, MarketInfoPairsResponse{
Symbol: itemk,
DecimalPlaces: pairv["decimal_places"].(float64),
@@ -203,28 +206,27 @@ func (g *Gateio) GetSpotKline(ctx context.Context, arg KlinesRequestParams) (kli
arg.GroupSec,
arg.HourSize)
var rawKlines map[string]interface{}
err := g.SendHTTPRequest(ctx, exchange.RestSpotSupplementary, urlPath, &rawKlines)
if err != nil {
resp := struct {
Data [][]string `json:"data"`
Result string `json:"result"`
}{}
if err := g.SendHTTPRequest(ctx, exchange.RestSpotSupplementary, urlPath, &resp); err != nil {
return kline.Item{}, err
}
if resp.Result != "true" || len(resp.Data) == 0 {
return kline.Item{}, errors.New("rawKlines unexpected data returned")
}
result := kline.Item{
Exchange: g.Name,
}
if rawKlines == nil || rawKlines["data"] == nil {
return kline.Item{}, errors.New("rawKlines is nil")
}
rawKlineDatasString, _ := json.Marshal(rawKlines["data"].([]interface{}))
var rawKlineDatas [][]interface{}
if err := json.Unmarshal(rawKlineDatasString, &rawKlineDatas); err != nil {
return kline.Item{}, fmt.Errorf("rawKlines unmarshal failed. Err: %s", err)
}
for _, k := range rawKlineDatas {
otString, err := strconv.ParseFloat(k[0].(string), 64)
for x := range resp.Data {
if len(resp.Data[x]) < 6 {
return kline.Item{}, fmt.Errorf("unexpected kline data length")
}
otString, err := strconv.ParseFloat(resp.Data[x][0], 64)
if err != nil {
return kline.Item{}, err
}
@@ -232,23 +234,23 @@ func (g *Gateio) GetSpotKline(ctx context.Context, arg KlinesRequestParams) (kli
if err != nil {
return kline.Item{}, fmt.Errorf("cannot parse Kline.OpenTime. Err: %s", err)
}
_vol, err := convert.FloatFromString(k[1])
_vol, err := convert.FloatFromString(resp.Data[x][1])
if err != nil {
return kline.Item{}, fmt.Errorf("cannot parse Kline.Volume. Err: %s", err)
}
_close, err := convert.FloatFromString(k[2])
_close, err := convert.FloatFromString(resp.Data[x][2])
if err != nil {
return kline.Item{}, fmt.Errorf("cannot parse Kline.Close. Err: %s", err)
}
_high, err := convert.FloatFromString(k[3])
_high, err := convert.FloatFromString(resp.Data[x][3])
if err != nil {
return kline.Item{}, fmt.Errorf("cannot parse Kline.High. Err: %s", err)
}
_low, err := convert.FloatFromString(k[4])
_low, err := convert.FloatFromString(resp.Data[x][4])
if err != nil {
return kline.Item{}, fmt.Errorf("cannot parse Kline.Low. Err: %s", err)
}
_open, err := convert.FloatFromString(k[5])
_open, err := convert.FloatFromString(resp.Data[x][5])
if err != nil {
return kline.Item{}, fmt.Errorf("cannot parse Kline.Open. Err: %s", err)
}

View File

@@ -544,14 +544,14 @@ func TestWsGetOrderInfo(t *testing.T) {
}
func setupWSTestAuth(t *testing.T) {
t.Helper()
if wsSetupRan {
return
}
if !g.Websocket.IsEnabled() && !g.API.AuthenticatedWebsocketSupport || !areTestAPIKeysSet() {
t.Skip(stream.WebsocketNotEnabled)
}
err := g.Websocket.Connect()
if err != nil {
if err := g.Websocket.Connect(); err != nil {
t.Fatal(err)
}
wsSetupRan = true

View File

@@ -225,11 +225,22 @@ func (g *Gateio) wsHandleData(respRaw []byte) error {
if err != nil {
return err
}
invalidJSON := orderUpdate.Params[1].(map[string]interface{})
if len(orderUpdate.Params) < 2 {
return errors.New("unexpected orderUpdate.Params data length")
}
invalidJSON, ok := orderUpdate.Params[1].(map[string]interface{})
if !ok {
return errors.New("unable to type assert invalidJSON")
}
oStatus := order.UnknownStatus
oType := order.UnknownType
oSide := order.UnknownSide
switch orderUpdate.Params[0].(float64) {
orderStatus, ok := orderUpdate.Params[0].(float64)
if !ok {
return errors.New("unable to type assert orderStatus")
}
switch orderStatus {
case 1:
oStatus = order.New
case 2:
@@ -237,42 +248,57 @@ func (g *Gateio) wsHandleData(respRaw []byte) error {
case 3:
oStatus = order.Filled
}
switch invalidJSON["orderType"].(float64) {
orderType, ok := invalidJSON["orderType"].(float64)
if !ok {
return errors.New("unable to type assert orderType")
}
switch orderType {
case 1:
oType = order.Limit
case 2:
oType = order.Market
}
switch invalidJSON["type"].(float64) {
orderSide, ok := invalidJSON["type"].(float64)
if !ok {
return errors.New("unable to type assert orderSide")
}
switch orderSide {
case 1:
oSide = order.Sell
case 2:
oSide = order.Buy
}
var price, amount, filledTotal, left, fee float64
price, err = strconv.ParseFloat(invalidJSON["price"].(string), 64)
price, err = convert.FloatFromString(invalidJSON["price"])
if err != nil {
return err
}
amount, err = strconv.ParseFloat(invalidJSON["amount"].(string), 64)
amount, err = convert.FloatFromString(invalidJSON["amount"])
if err != nil {
return err
}
filledTotal, err = strconv.ParseFloat(invalidJSON["filledTotal"].(string), 64)
filledTotal, err = convert.FloatFromString(invalidJSON["filledTotal"])
if err != nil {
return err
}
left, err = strconv.ParseFloat(invalidJSON["left"].(string), 64)
left, err = convert.FloatFromString(invalidJSON["left"])
if err != nil {
return err
}
fee, err = strconv.ParseFloat(invalidJSON["dealFee"].(string), 64)
fee, err = convert.FloatFromString(invalidJSON["dealFee"])
if err != nil {
return err
}
var p currency.Pair
p, err = currency.NewPairFromString(invalidJSON["market"].(string))
pairStr, ok := invalidJSON["market"].(string)
if !ok {
return errors.New("unable to type assert market")
}
p, err = currency.NewPairFromString(pairStr)
if err != nil {
return err
}

View File

@@ -270,8 +270,7 @@ func (g *Gateio) UpdateTickers(ctx context.Context, a asset.Item) error {
// UpdateTicker updates and returns the ticker for a currency pair
func (g *Gateio) UpdateTicker(ctx context.Context, p currency.Pair, a asset.Item) (*ticker.Price, error) {
err := g.UpdateTickers(ctx, a)
if err != nil {
if err := g.UpdateTickers(ctx, a); err != nil {
return nil, err
}
return ticker.GetTicker(g.Name, p, a)
@@ -411,8 +410,7 @@ func (g *Gateio) UpdateAccountInfo(ctx context.Context, assetType asset.Item) (a
}
info.Exchange = g.Name
err := account.Process(&info)
if err != nil {
if err := account.Process(&info); err != nil {
return account.Holdings{}, err
}

View File

@@ -1,4 +1,5 @@
//+build !mock_test_off
//go:build !mock_test_off
// +build !mock_test_off
// This will build if build tag mock_test_off is not parsed and will try to mock
// all tests in _test.go

View File

@@ -324,7 +324,7 @@ func (g *Gemini) wsHandleData(respRaw []byte) error {
Side: oSide,
Status: oStatus,
AssetType: asset.Spot,
Date: time.Unix(0, result[i].Timestampms*int64(time.Millisecond)),
Date: time.UnixMilli(result[i].Timestampms),
Pair: pair,
}
}

View File

@@ -455,6 +455,7 @@ func TestGetDepositAddress(t *testing.T) {
}
}
func setupWsAuth(t *testing.T) {
t.Helper()
if wsSetupRan {
return
}
@@ -524,8 +525,7 @@ func TestWsReplaceOrder(t *testing.T) {
// TestWsGetActiveOrders dials websocket, sends get active orders request.
func TestWsGetActiveOrders(t *testing.T) {
setupWsAuth(t)
_, err := h.wsGetActiveOrders()
if err != nil {
if _, err := h.wsGetActiveOrders(); err != nil {
t.Fatal(err)
}
}
@@ -533,8 +533,7 @@ func TestWsGetActiveOrders(t *testing.T) {
// TestWsGetTradingBalance dials websocket, sends get trading balance request.
func TestWsGetTradingBalance(t *testing.T) {
setupWsAuth(t)
_, err := h.wsGetTradingBalance()
if err != nil {
if _, err := h.wsGetTradingBalance(); err != nil {
t.Fatal(err)
}
}

View File

@@ -113,7 +113,10 @@ func (h *HitBTC) wsGetTableName(respRaw []byte) (string, error) {
return "", nil
}
data := resultType[0].(map[string]interface{})
data, ok := resultType[0].(map[string]interface{})
if !ok {
return "", errors.New("unable to type assert data")
}
if _, ok := data["clientOrderId"]; ok {
return "order", nil
} else if _, ok := data["available"]; ok {

View File

@@ -358,8 +358,7 @@ func (h *HitBTC) UpdateTickers(ctx context.Context, a asset.Item) error {
// UpdateTicker updates and returns the ticker for a currency pair
func (h *HitBTC) UpdateTicker(ctx context.Context, p currency.Pair, a asset.Item) (*ticker.Price, error) {
err := h.UpdateTickers(ctx, a)
if err != nil {
if err := h.UpdateTickers(ctx, a); err != nil {
return nil, err
}
return ticker.GetTicker(h.Name, p, a)
@@ -498,8 +497,8 @@ allTrades:
p.String(),
"",
"",
ts.UnixNano()/int64(time.Millisecond),
timestampEnd.UnixNano()/int64(time.Millisecond),
ts.UnixMilli(),
timestampEnd.UnixMilli(),
int64(limit),
0)
if err != nil {

View File

@@ -57,6 +57,7 @@ func TestMain(m *testing.M) {
}
func setupWsTests(t *testing.T) {
t.Helper()
if wsSetupRan {
return
}
@@ -2196,8 +2197,7 @@ func TestQueryWithdrawQuota(t *testing.T) {
// TestWsGetAccountsList connects to WS, logs in, gets account list
func TestWsGetAccountsList(t *testing.T) {
setupWsTests(t)
_, err := h.wsGetAccountsList()
if err != nil {
if _, err := h.wsGetAccountsList(); err != nil {
t.Fatal(err)
}
}

View File

@@ -351,7 +351,7 @@ func (h *HUOBI) wsHandleData(respRaw []byte) error {
return err
}
h.Websocket.DataHandler <- stream.KlineData{
Timestamp: time.Unix(0, kline.Timestamp*int64(time.Millisecond)),
Timestamp: time.UnixMilli(kline.Timestamp),
Exchange: h.Name,
AssetType: a,
Pair: p,
@@ -388,12 +388,11 @@ func (h *HUOBI) wsHandleData(respRaw []byte) error {
Exchange: h.Name,
AssetType: a,
CurrencyPair: p,
Timestamp: time.Unix(0,
t.Tick.Data[i].Timestamp*int64(time.Millisecond)),
Amount: t.Tick.Data[i].Amount,
Price: t.Tick.Data[i].Price,
Side: side,
TID: strconv.FormatFloat(t.Tick.Data[i].TradeID, 'f', -1, 64),
Timestamp: time.UnixMilli(t.Tick.Data[i].Timestamp),
Amount: t.Tick.Data[i].Amount,
Price: t.Tick.Data[i].Price,
Side: side,
TID: strconv.FormatFloat(t.Tick.Data[i].TradeID, 'f', -1, 64),
})
}
return trade.AddTradesToBuffer(h.Name, trades...)
@@ -427,7 +426,7 @@ func (h *HUOBI) wsHandleData(respRaw []byte) error {
QuoteVolume: wsTicker.Tick.Volume,
High: wsTicker.Tick.High,
Low: wsTicker.Tick.Low,
LastUpdated: time.Unix(0, wsTicker.Timestamp*int64(time.Millisecond)),
LastUpdated: time.UnixMilli(wsTicker.Timestamp),
AssetType: a,
Pair: p,
}

View File

@@ -793,8 +793,7 @@ func (h *HUOBI) UpdateAccountInfo(ctx context.Context, assetType asset.Item) (ac
}
acc.AssetType = assetType
info.Accounts = append(info.Accounts, acc)
err := account.Process(&info)
if err != nil {
if err := account.Process(&info); err != nil {
return info, err
}
return info, nil
@@ -844,7 +843,7 @@ func (h *HUOBI) GetRecentTrades(ctx context.Context, p currency.Pair, assetType
Side: side,
Price: tradeData[i].Trades[j].Price,
Amount: tradeData[i].Trades[j].Amount,
Timestamp: time.Unix(0, tradeData[i].Timestamp*int64(time.Millisecond)),
Timestamp: time.UnixMilli(tradeData[i].Timestamp),
})
}
}
@@ -1183,7 +1182,7 @@ func (h *HUOBI) GetOrderInfo(ctx context.Context, orderID string, pair currency.
Pair: p,
Type: orderType,
Side: orderSide,
Date: time.Unix(0, respData.CreatedAt*int64(time.Millisecond)),
Date: time.UnixMilli(respData.CreatedAt),
Status: orderStatus,
Price: respData.Price,
Amount: respData.Amount,
@@ -1349,7 +1348,7 @@ func (h *HUOBI) GetActiveOrders(ctx context.Context, req *order.GetOrdersRequest
Pair: req.Pairs[i],
Type: orderType,
Side: orderSide,
Date: time.Unix(0, resp.Data[j].CreatedAt*int64(time.Millisecond)),
Date: time.UnixMilli(resp.Data[j].CreatedAt),
Status: orderStatus,
Price: resp.Data[j].Price,
Amount: resp.Data[j].OrderAmount,
@@ -1377,7 +1376,7 @@ func (h *HUOBI) GetActiveOrders(ctx context.Context, req *order.GetOrdersRequest
Pair: req.Pairs[i],
Exchange: h.Name,
ExecutedAmount: resp[x].FilledAmount,
Date: time.Unix(0, resp[x].CreatedAt*int64(time.Millisecond)),
Date: time.UnixMilli(resp[x].CreatedAt),
Status: order.Status(resp[x].State),
AccountID: strconv.FormatInt(resp[x].AccountID, 10),
Fee: resp[x].FilledFees,
@@ -1389,7 +1388,7 @@ func (h *HUOBI) GetActiveOrders(ctx context.Context, req *order.GetOrdersRequest
}
case asset.CoinMarginedFutures:
for x := range req.Pairs {
var currentPage int64 = 0
var currentPage int64
for done := false; !done; {
openOrders, err := h.GetSwapOpenOrders(ctx,
req.Pairs[x], currentPage, 50)
@@ -1429,7 +1428,7 @@ func (h *HUOBI) GetActiveOrders(ctx context.Context, req *order.GetOrdersRequest
}
case asset.Futures:
for x := range req.Pairs {
var currentPage int64 = 0
var currentPage int64
for done := false; !done; {
openOrders, err := h.FGetOpenOrders(ctx,
req.Pairs[x].Base, currentPage, 50)
@@ -1508,7 +1507,7 @@ func (h *HUOBI) GetOrderHistory(ctx context.Context, req *order.GetOrdersRequest
Pair: req.Pairs[i],
Exchange: h.Name,
ExecutedAmount: resp[x].FilledAmount,
Date: time.Unix(0, resp[x].CreatedAt*int64(time.Millisecond)),
Date: time.UnixMilli(resp[x].CreatedAt),
Status: order.Status(resp[x].State),
AccountID: strconv.FormatInt(resp[x].AccountID, 10),
Fee: resp[x].FilledFees,
@@ -1519,7 +1518,7 @@ func (h *HUOBI) GetOrderHistory(ctx context.Context, req *order.GetOrdersRequest
}
case asset.CoinMarginedFutures:
for x := range req.Pairs {
var currentPage int64 = 0
var currentPage int64
for done := false; !done; {
orderHistory, err := h.GetSwapOrderHistory(ctx,
req.Pairs[x],
@@ -1570,7 +1569,7 @@ func (h *HUOBI) GetOrderHistory(ctx context.Context, req *order.GetOrdersRequest
}
case asset.Futures:
for x := range req.Pairs {
var currentPage int64 = 0
var currentPage int64
for done := false; !done; {
openOrders, err := h.FGetOrderHistory(ctx,
req.Pairs[x],

View File

@@ -324,7 +324,7 @@ func (i *ItBit) SendAuthenticatedHTTPRequest(ctx context.Context, ep exchange.UR
var intermediary json.RawMessage
err = i.SendPayload(ctx, request.Unset, func() (*request.Item, error) {
n := i.Requester.GetNonce(true).String()
timestamp := strconv.FormatInt(time.Now().UnixNano()/1000000, 10)
timestamp := strconv.FormatInt(time.Now().UnixMilli(), 10)
var message []byte
message, err = json.Marshal([]string{method, urlPath, string(PayloadJSON), n, timestamp})

View File

@@ -19,8 +19,7 @@ func CreateKline(trades []order.TradeHistory, interval Interval, p currency.Pair
return Item{}, fmt.Errorf("invalid time interval: [%s]", interval)
}
err := validateData(trades)
if err != nil {
if err := validateData(trades); err != nil {
return Item{}, err
}

View File

@@ -92,7 +92,7 @@ func TestValidateData(t *testing.T) {
func TestCreateKline(t *testing.T) {
t.Parallel()
c, err := CreateKline(nil,
_, err := CreateKline(nil,
OneMin,
currency.NewPair(currency.BTC, currency.USD),
asset.Spot,
@@ -113,7 +113,7 @@ func TestCreateKline(t *testing.T) {
})
}
c, err = CreateKline(trades,
_, err = CreateKline(trades,
0,
currency.NewPair(currency.BTC, currency.USD),
asset.Spot,
@@ -122,7 +122,7 @@ func TestCreateKline(t *testing.T) {
t.Fatal("error cannot be nil")
}
c, err = CreateKline(trades,
c, err := CreateKline(trades,
OneMin,
currency.NewPair(currency.BTC, currency.USD),
asset.Spot,
@@ -251,6 +251,8 @@ func TestDurationToWord(t *testing.T) {
for x := range testCases {
test := testCases[x]
t.Run(test.name, func(t *testing.T) {
t.Parallel()
t.Helper()
v := durationToWord(test.interval)
if !strings.EqualFold(v, test.name) {
t.Fatalf("%v: received %v expected %v", test.name, v, test.name)
@@ -261,7 +263,7 @@ func TestDurationToWord(t *testing.T) {
func TestKlineErrors(t *testing.T) {
t.Parallel()
v := ErrorKline{
v := Error{
Interval: OneYear,
Pair: currency.NewPair(currency.BTC, currency.AUD),
Err: errors.New("hello world"),
@@ -398,6 +400,7 @@ func TestTotalCandlesPerInterval(t *testing.T) {
for x := range testCases {
test := testCases[x]
t.Run(test.name, func(t *testing.T) {
t.Parallel()
v := TotalCandlesPerInterval(start, end, test.interval)
if v != test.expected {
t.Fatalf("%v: received %v expected %v", test.name, v, test.expected)
@@ -506,6 +509,7 @@ func TestItem_SortCandlesByTimestamp(t *testing.T) {
}
func setupTest(t *testing.T) {
t.Helper()
if verbose {
testhelpers.EnableVerboseTestOutput()
}

View File

@@ -128,8 +128,8 @@ type ExchangeCapabilitiesEnabled struct {
// Interval type for kline Interval usage
type Interval time.Duration
// ErrorKline struct to hold kline interval errors
type ErrorKline struct {
// Error struct to hold kline interval errors
type Error struct {
Asset asset.Item
Pair currency.Pair
Interval Interval
@@ -137,13 +137,13 @@ type ErrorKline struct {
}
// Error returns short interval unsupported message
func (k *ErrorKline) Error() string {
return k.Err.Error()
func (e *Error) Error() string {
return e.Err.Error()
}
// Unwrap returns interval unsupported message
func (k *ErrorKline) Unwrap() error {
return k.Err
func (e *Error) Unwrap() error {
return e.Err
}
// IntervalRangeHolder holds the entire range of intervals

View File

@@ -10,8 +10,10 @@ import (
"strconv"
"strings"
"sync"
"time"
"github.com/thrasher-corp/gocryptotrader/common"
"github.com/thrasher-corp/gocryptotrader/common/convert"
"github.com/thrasher-corp/gocryptotrader/common/crypto"
"github.com/thrasher-corp/gocryptotrader/currency"
exchange "github.com/thrasher-corp/gocryptotrader/exchanges"
@@ -214,46 +216,59 @@ func (k *Kraken) GetOHLC(ctx context.Context, symbol currency.Pair, interval str
Data map[string]interface{} `json:"result"`
}
var OHLC []OpenHighLowClose
var result Response
path := fmt.Sprintf("/%s/public/%s?%s", krakenAPIVersion, krakenOHLC, values.Encode())
err = k.SendHTTPRequest(ctx, exchange.RestSpot, path, &result)
if err != nil {
return OHLC, err
return nil, err
}
if len(result.Error) != 0 {
return OHLC, fmt.Errorf("getOHLC error: %s", result.Error)
return nil, fmt.Errorf("getOHLC error: %s", result.Error)
}
_, ok := result.Data[translatedAsset].([]interface{})
ohlcData, ok := result.Data[translatedAsset].([]interface{})
if !ok {
return nil, errors.New("invalid data returned")
}
for _, y := range result.Data[translatedAsset].([]interface{}) {
o := OpenHighLowClose{}
for i, x := range y.([]interface{}) {
switch i {
case 0:
o.Time = x.(float64)
case 1:
o.Open, _ = strconv.ParseFloat(x.(string), 64)
case 2:
o.High, _ = strconv.ParseFloat(x.(string), 64)
case 3:
o.Low, _ = strconv.ParseFloat(x.(string), 64)
case 4:
o.Close, _ = strconv.ParseFloat(x.(string), 64)
case 5:
o.VolumeWeightedAveragePrice, _ = strconv.ParseFloat(x.(string), 64)
case 6:
o.Volume, _ = strconv.ParseFloat(x.(string), 64)
case 7:
o.Count = x.(float64)
}
var OHLC []OpenHighLowClose
for x := range ohlcData {
subData, ok := ohlcData[x].([]interface{})
if !ok {
return nil, errors.New("unable to type assert subData")
}
if len(subData) < 8 {
return nil, errors.New("unexpected data length returned")
}
var o OpenHighLowClose
if o.Time, ok = subData[0].(float64); !ok {
return nil, errors.New("unable to type assert time")
}
if o.Open, err = convert.FloatFromString(subData[1]); err != nil {
return nil, err
}
if o.High, err = convert.FloatFromString(subData[2]); err != nil {
return nil, err
}
if o.Low, err = convert.FloatFromString(subData[3]); err != nil {
return nil, err
}
if o.Close, err = convert.FloatFromString(subData[4]); err != nil {
return nil, err
}
if o.VolumeWeightedAveragePrice, err = convert.FloatFromString(subData[5]); err != nil {
return nil, err
}
if o.Volume, err = convert.FloatFromString(subData[6]); err != nil {
return nil, err
}
if o.Count, ok = subData[7].(float64); !ok {
return nil, errors.New("unable to type assert count")
}
OHLC = append(OHLC, o)
}
@@ -280,24 +295,40 @@ func (k *Kraken) GetDepth(ctx context.Context, symbol currency.Pair) (Orderbook,
return orderBook, fmt.Errorf("%s GetDepth result is nil", k.Name)
}
data := result.(map[string]interface{})
if data["result"] == nil {
data, ok := result.(map[string]interface{})
if !ok {
return orderBook, errors.New("unable to type assert data")
}
orderbookData, ok := data["result"].(map[string]interface{})
if !ok {
return orderBook, fmt.Errorf("%s GetDepth data[result] is nil", k.Name)
}
orderbookData := data["result"].(map[string]interface{})
var bidsData []interface{}
var asksData []interface{}
for _, y := range orderbookData {
yData := y.(map[string]interface{})
bidsData = yData["bids"].([]interface{})
asksData = yData["asks"].([]interface{})
yData, ok := y.(map[string]interface{})
if !ok {
return orderBook, errors.New("unable to type assert yData")
}
if bidsData, ok = yData["bids"].([]interface{}); !ok {
return orderBook, errors.New("unable to type assert bidsData")
}
if asksData, ok = yData["asks"].([]interface{}); !ok {
return orderBook, errors.New("unable to type assert asksData")
}
}
processOrderbook := func(data []interface{}) ([]OrderbookBase, error) {
var result []OrderbookBase
for x := range data {
entry := data[x].([]interface{})
entry, ok := data[x].([]interface{})
if !ok {
return nil, errors.New("unable to type assert entry")
}
if len(entry) < 2 {
return nil, errors.New("unexpected entry length")
}
price, priceErr := strconv.ParseFloat(entry[0].(string), 64)
if priceErr != nil {
@@ -439,30 +470,48 @@ func (k *Kraken) GetSpread(ctx context.Context, symbol currency.Pair) ([]Spread,
}
values.Set("pair", symbolValue)
var peanutButter []Spread
var response interface{}
resp := struct {
SpreadData map[string]interface{} `json:"result"`
}{}
path := fmt.Sprintf("/%s/public/%s?%s", krakenAPIVersion, krakenSpread, values.Encode())
err = k.SendHTTPRequest(ctx, exchange.RestSpot, path, &response)
err = k.SendHTTPRequest(ctx, exchange.RestSpot, path, &resp)
if err != nil {
return peanutButter, err
return nil, err
}
data := response.(map[string]interface{})
result := data["result"].(map[string]interface{})
data, ok := resp.SpreadData[symbolValue]
if !ok {
return nil, fmt.Errorf("unable to find %s in spread data", symbolValue)
}
for _, x := range result[symbolValue].([]interface{}) {
s := Spread{}
for i, y := range x.([]interface{}) {
switch i {
case 0:
s.Time = y.(float64)
case 1:
s.Bid, _ = strconv.ParseFloat(y.(string), 64)
case 2:
s.Ask, _ = strconv.ParseFloat(y.(string), 64)
}
spreadData, ok := data.([]interface{})
if !ok {
return nil, errors.New("unable to type assert spreadData")
}
var peanutButter []Spread
for x := range spreadData {
subData, ok := spreadData[x].([]interface{})
if !ok {
return nil, errors.New("unable to type assert subData")
}
if len(subData) < 3 {
return nil, errors.New("unexpected data length")
}
var s Spread
timeData, ok := subData[0].(float64)
if !ok {
return nil, errors.New("unable to type assert timeData")
}
s.Time = time.Unix(int64(timeData), 0)
if s.Bid, err = convert.FloatFromString(subData[1]); err != nil {
return nil, err
}
if s.Ask, err = convert.FloatFromString(subData[2]); err != nil {
return nil, err
}
peanutButter = append(peanutButter, s)
}
@@ -1203,8 +1252,7 @@ func (a *assetTranslatorStore) Seed(orig, alt string) {
a.Assets = make(map[string]string)
}
_, ok := a.Assets[orig]
if ok {
if _, ok := a.Assets[orig]; ok {
a.l.Unlock()
return
}

View File

@@ -275,7 +275,7 @@ func (k *Kraken) SendFuturesAuthRequest(ctx context.Context, method, path string
interim := json.RawMessage{}
newRequest := func() (*request.Item, error) {
nonce := strconv.FormatInt(time.Now().UnixNano()/1000000, 10)
nonce := strconv.FormatInt(time.Now().UnixMilli(), 10)
reqData := ""
if len(data) > 0 {
temp, err := json.Marshal(data)

View File

@@ -1128,6 +1128,7 @@ func TestWithdrawCancel(t *testing.T) {
// ---------------------------- Websocket tests -----------------------------------------
func setupWsTests(t *testing.T) {
t.Helper()
if wsSetupRan {
return
}
@@ -1205,16 +1206,14 @@ func TestWsAddOrder(t *testing.T) {
func TestWsCancelOrder(t *testing.T) {
setupWsTests(t)
err := k.wsCancelOrders([]string{"1337"})
if err != nil {
if err := k.wsCancelOrders([]string{"1337"}); err != nil {
t.Error(err)
}
}
func TestWsCancelAllOrders(t *testing.T) {
setupWsTests(t)
_, err := k.wsCancelAllOrders()
if err != nil {
if _, err := k.wsCancelAllOrders(); err != nil {
t.Error(err)
}
}
@@ -1994,6 +1993,7 @@ func Test_FormatExchangeKlineInterval(t *testing.T) {
test := testCases[x]
t.Run(test.name, func(t *testing.T) {
t.Parallel()
ret := k.FormatExchangeKlineInterval(test.interval)
if ret != test.output {

View File

@@ -188,7 +188,7 @@ type Orderbook struct {
// Spread holds the spread between trades
type Spread struct {
Time float64
Time time.Time
Bid float64
Ask float64
}

View File

@@ -717,16 +717,38 @@ func (k *Kraken) wsProcessTickers(channelData *WebsocketChannelData, data map[st
// wsProcessSpread converts spread/orderbook data and sends it to the datahandler
func (k *Kraken) wsProcessSpread(channelData *WebsocketChannelData, data []interface{}) {
bestBid := data[0].(string)
bestAsk := data[1].(string)
if len(data) < 5 {
k.Websocket.DataHandler <- fmt.Errorf("%s unexpected wsProcessSpread data length", k.Name)
return
}
bestBid, ok := data[0].(string)
if !ok {
k.Websocket.DataHandler <- fmt.Errorf("%s wsProcessSpread: unable to type assert bestBid", k.Name)
return
}
bestAsk, ok := data[1].(string)
if !ok {
k.Websocket.DataHandler <- fmt.Errorf("%s wsProcessSpread: unable to type assert bestAsk", k.Name)
return
}
timeData, err := strconv.ParseFloat(data[2].(string), 64)
if err != nil {
k.Websocket.DataHandler <- err
k.Websocket.DataHandler <- fmt.Errorf("%s wsProcessSpread: unable to parse timeData. Error: %s",
k.Name,
err)
return
}
bidVolume, ok := data[3].(string)
if !ok {
k.Websocket.DataHandler <- fmt.Errorf("%s wsProcessSpread: unable to type assert bidVolume", k.Name)
return
}
askVolume, ok := data[4].(string)
if !ok {
k.Websocket.DataHandler <- fmt.Errorf("%s wsProcessSpread: unable to type assert askVolume", k.Name)
return
}
bidVolume := data[3].(string)
askVolume := data[4].(string)
if k.Verbose {
log.Debugf(log.ExchangeSys,
"%v Spread data for '%v' received. Best bid: '%v' Best ask: '%v' Time: '%v', Bid volume '%v', Ask volume '%v'",
@@ -839,7 +861,13 @@ func (k *Kraken) wsProcessOrderBookPartial(channelData *WebsocketChannelData, as
// to respect both within a reasonable degree
var highestLastUpdate time.Time
for i := range askData {
asks := askData[i].([]interface{})
asks, ok := askData[i].([]interface{})
if !ok {
return errors.New("unable to type assert asks")
}
if len(asks) < 3 {
return errors.New("unexpected asks length")
}
price, err := strconv.ParseFloat(asks[0].(string), 64)
if err != nil {
return err
@@ -863,7 +891,13 @@ func (k *Kraken) wsProcessOrderBookPartial(channelData *WebsocketChannelData, as
}
for i := range bidData {
bids := bidData[i].([]interface{})
bids, ok := bidData[i].([]interface{})
if !ok {
return errors.New("unable to type assert bids")
}
if len(bids) < 3 {
return errors.New("unexpected bids length")
}
price, err := strconv.ParseFloat(bids[0].(string), 64)
if err != nil {
return err
@@ -906,7 +940,10 @@ func (k *Kraken) wsProcessOrderBookUpdate(channelData *WebsocketChannelData, ask
var highestLastUpdate time.Time
// Ask data is not always sent
for i := range askData {
asks := askData[i].([]interface{})
asks, ok := askData[i].([]interface{})
if !ok {
return errors.New("asks type assertion failure")
}
priceStr, ok := asks[0].(string)
if !ok {
@@ -966,7 +1003,10 @@ func (k *Kraken) wsProcessOrderBookUpdate(channelData *WebsocketChannelData, ask
// Bid data is not always sent
for i := range bidData {
bids := bidData[i].([]interface{})
bids, ok := bidData[i].([]interface{})
if !ok {
return errors.New("unable to type assert bids")
}
priceStr, ok := bids[0].(string)
if !ok {

View File

@@ -487,8 +487,7 @@ func (k *Kraken) UpdateTickers(ctx context.Context, a asset.Item) error {
// UpdateTicker updates and returns the ticker for a currency pair
func (k *Kraken) UpdateTicker(ctx context.Context, p currency.Pair, a asset.Item) (*ticker.Price, error) {
err := k.UpdateTickers(ctx, a)
if err != nil {
if err := k.UpdateTickers(ctx, a); err != nil {
return nil, err
}
return ticker.GetTicker(k.Name, p, a)
@@ -615,8 +614,7 @@ func (k *Kraken) UpdateAccountInfo(ctx context.Context, assetType asset.Item) (a
})
}
}
err := account.Process(&info)
if err != nil {
if err := account.Process(&info); err != nil {
return account.Holdings{}, err
}
return info, nil
@@ -698,8 +696,7 @@ func (k *Kraken) GetHistoricTrades(_ context.Context, _ currency.Pair, _ asset.I
// SubmitOrder submits a new order
func (k *Kraken) SubmitOrder(ctx context.Context, s *order.Submit) (order.SubmitResponse, error) {
var submitOrderResponse order.SubmitResponse
err := s.Validate()
if err != nil {
if err := s.Validate(); err != nil {
return submitOrderResponse, err
}
switch s.AssetType {
@@ -707,7 +704,7 @@ func (k *Kraken) SubmitOrder(ctx context.Context, s *order.Submit) (order.Submit
if k.Websocket.CanUseAuthenticatedWebsocketForWrapper() {
var resp string
s.Pair.Delimiter = "/" // required pair format: ISO 4217-A3
resp, err = k.wsAddOrder(&WsAddOrderRequest{
resp, err := k.wsAddOrder(&WsAddOrderRequest{
OrderType: s.Type.Lower(),
OrderSide: s.Side.Lower(),
Pair: s.Pair.String(),
@@ -721,7 +718,7 @@ func (k *Kraken) SubmitOrder(ctx context.Context, s *order.Submit) (order.Submit
submitOrderResponse.IsOrderPlaced = true
} else {
var response AddOrderResponse
response, err = k.AddOrder(ctx,
response, err := k.AddOrder(ctx,
s.Pair,
s.Side.String(),
s.Type.String(),

View File

@@ -15,6 +15,7 @@ import (
"net/url"
"strconv"
"strings"
"time"
gctcrypto "github.com/thrasher-corp/gocryptotrader/common/crypto"
exchange "github.com/thrasher-corp/gocryptotrader/exchanges"
@@ -114,70 +115,32 @@ func (l *Lbank) GetTrades(ctx context.Context, symbol string, limit, time int64)
}
// GetKlines returns kline data
func (l *Lbank) GetKlines(ctx context.Context, symbol, size, klineType, time string) ([]KlineResponse, error) {
var klineTemp interface{}
var k []KlineResponse
func (l *Lbank) GetKlines(ctx context.Context, symbol, size, klineType, tm string) ([]KlineResponse, error) {
var klineTemp [][]float64
params := url.Values{}
params.Set("symbol", symbol)
params.Set("size", size)
params.Set("type", klineType)
params.Set("time", time)
params.Set("time", tm)
path := fmt.Sprintf("/v%s/%s?%s", lbankAPIVersion, lbankKlines, params.Encode())
err := l.SendHTTPRequest(ctx, exchange.RestSpot, path, &klineTemp)
if err != nil {
return k, err
return nil, err
}
resp, ok := klineTemp.([]interface{})
if !ok {
return nil, errors.New("response received is invalid")
}
for i := range resp {
resp2, ok := resp[i].([]interface{})
if !ok {
return nil, errors.New("response received is invalid")
var k []KlineResponse
for x := range klineTemp {
if len(klineTemp[x]) < 6 {
return nil, errors.New("unexpected kline data length")
}
var tempResp KlineResponse
for x := range resp2 {
switch x {
case 0:
tempResp.TimeStamp = int64(resp2[x].(float64))
case 1:
if val, ok := resp2[x].(int64); ok {
tempResp.OpenPrice = float64(val)
} else {
tempResp.OpenPrice = resp2[x].(float64)
}
case 2:
if val, ok := resp2[x].(int64); ok {
tempResp.HigestPrice = float64(val)
} else {
tempResp.HigestPrice = resp2[x].(float64)
}
case 3:
if val, ok := resp2[x].(int64); ok {
tempResp.LowestPrice = float64(val)
} else {
tempResp.LowestPrice = resp2[x].(float64)
}
case 4:
if val, ok := resp2[x].(int64); ok {
tempResp.ClosePrice = float64(val)
} else {
tempResp.ClosePrice = resp2[x].(float64)
}
case 5:
if val, ok := resp2[x].(int64); ok {
tempResp.TradingVolume = float64(val)
} else {
tempResp.TradingVolume = resp2[x].(float64)
}
}
}
k = append(k, tempResp)
k = append(k, KlineResponse{
TimeStamp: time.Unix(int64(klineTemp[x][0]), 0).UTC(),
OpenPrice: klineTemp[x][1],
HigestPrice: klineTemp[x][2],
LowestPrice: klineTemp[x][3],
ClosePrice: klineTemp[x][4],
TradingVolume: klineTemp[x][5],
})
}
return k, nil
}

View File

@@ -2,6 +2,7 @@ package lbank
import (
"encoding/json"
"time"
"github.com/thrasher-corp/gocryptotrader/currency"
)
@@ -44,12 +45,12 @@ type TradeResponse struct {
// KlineResponse stores kline info for given currency exchange
type KlineResponse struct {
TimeStamp int64 `json:"timestamp"`
OpenPrice float64 `json:"openprice"`
HigestPrice float64 `json:"highestprice"`
LowestPrice float64 `json:"lowestprice"`
ClosePrice float64 `json:"closeprice"`
TradingVolume float64 `json:"tradingvolume"`
TimeStamp time.Time `json:"timestamp"`
OpenPrice float64 `json:"openprice"`
HigestPrice float64 `json:"highestprice"`
LowestPrice float64 `json:"lowestprice"`
ClosePrice float64 `json:"closeprice"`
TradingVolume float64 `json:"tradingvolume"`
}
// InfoResponse stores info

View File

@@ -224,8 +224,7 @@ func (l *Lbank) UpdateTickers(ctx context.Context, a asset.Item) error {
// UpdateTicker updates and returns the ticker for a currency pair
func (l *Lbank) UpdateTicker(ctx context.Context, p currency.Pair, a asset.Item) (*ticker.Price, error) {
err := l.UpdateTickers(ctx, a)
if err != nil {
if err := l.UpdateTickers(ctx, a); err != nil {
return nil, err
}
return ticker.GetTicker(l.Name, p, a)
@@ -387,12 +386,12 @@ allTrades:
tradeData, err = l.GetTrades(ctx,
p.String(),
int64(limit),
ts.UnixNano()/int64(time.Millisecond))
ts.UnixMilli())
if err != nil {
return nil, err
}
for i := range tradeData {
tradeTime := time.Unix(0, tradeData[i].DateMS*int64(time.Millisecond))
tradeTime := time.UnixMilli(tradeData[i].DateMS)
if tradeTime.Before(timestampStart) || tradeTime.After(timestampEnd) {
break allTrades
}
@@ -499,7 +498,7 @@ func (l *Lbank) CancelAllOrders(ctx context.Context, o *order.Cancel) (order.Can
var resp order.CancelAllResponse
orderIDs, err := l.getAllOpenOrderID(ctx)
if err != nil {
return resp, nil
return resp, err
}
for key := range orderIDs {
@@ -935,7 +934,7 @@ func (l *Lbank) GetHistoricCandles(ctx context.Context, pair currency.Pair, a as
for x := range data {
ret.Candles = append(ret.Candles, kline.Candle{
Time: time.Unix(data[x].TimeStamp, 0),
Time: data[x].TimeStamp,
Open: data[x].OpenPrice,
High: data[x].HigestPrice,
Low: data[x].LowestPrice,
@@ -981,11 +980,11 @@ func (l *Lbank) GetHistoricCandlesExtended(ctx context.Context, pair currency.Pa
return kline.Item{}, err
}
for i := range data {
if data[i].TimeStamp < dates.Ranges[x].Start.Ticks || data[i].TimeStamp > dates.Ranges[x].End.Ticks {
if data[i].TimeStamp.Unix() < dates.Ranges[x].Start.Ticks || data[i].TimeStamp.Unix() > dates.Ranges[x].End.Ticks {
continue
}
ret.Candles = append(ret.Candles, kline.Candle{
Time: time.Unix(data[i].TimeStamp, 0).UTC(),
Time: data[i].TimeStamp,
Open: data[i].OpenPrice,
High: data[i].HigestPrice,
Low: data[i].LowestPrice,

View File

@@ -1,4 +1,5 @@
//+build !mock_test_off
//go:build !mock_test_off
// +build !mock_test_off
// This will build if build tag mock_test_off is not parsed and will try to mock
// all tests in _test.go

View File

@@ -199,8 +199,7 @@ func (l *LocalBitcoins) UpdateTickers(ctx context.Context, a asset.Item) error {
// UpdateTicker updates and returns the ticker for a currency pair
func (l *LocalBitcoins) UpdateTicker(ctx context.Context, p currency.Pair, a asset.Item) (*ticker.Price, error) {
err := l.UpdateTickers(ctx, a)
if err != nil {
if err := l.UpdateTickers(ctx, a); err != nil {
return nil, err
}
return ticker.GetTicker(l.Name, p, a)

View File

@@ -349,7 +349,10 @@ func CheckJSON(data interface{}, excluded *Exclusion) (interface{}, error) {
context[key] = 0.0 // Zero val float
}
case Slice:
slice := val.([]interface{})
slice, ok := val.([]interface{})
if !ok {
return nil, errors.New("unable to type assert slice")
}
if len(slice) < 1 {
// Empty slice found
context[key] = slice

View File

@@ -8,9 +8,7 @@ import (
func TestGet(t *testing.T) {
var nonce Nonce
nonce.Set(112321313)
expected := Value(112321313)
result := nonce.Get()
if expected != result {
if expected, result := Value(112321313), nonce.Get(); expected != result {
t.Errorf("Expected %d got %d", expected, result)
}
}
@@ -18,9 +16,7 @@ func TestGet(t *testing.T) {
func TestGetInc(t *testing.T) {
var nonce Nonce
nonce.Set(1)
expected := Value(2)
result := nonce.GetInc()
if expected != result {
if expected, result := Value(2), nonce.GetInc(); expected != result {
t.Errorf("Expected %d got %d", expected, result)
}
}
@@ -28,9 +24,7 @@ func TestGetInc(t *testing.T) {
func TestSet(t *testing.T) {
var nonce Nonce
nonce.Set(1)
expected := Value(1)
result := nonce.Get()
if expected != result {
if result, expected := nonce.Get(), Value(1); expected != result {
t.Errorf("Expected %d got %d", expected, result)
}
}
@@ -62,9 +56,7 @@ func TestNonceConcurrency(t *testing.T) {
wg.Wait()
result := nonce.Get()
expected := Value(12312 + 1000)
if expected != result {
if expected, result := Value(12312+1000), nonce.Get(); expected != result {
t.Errorf("Expected %d got %d", expected, result)
}
}

View File

@@ -316,8 +316,7 @@ func (o *OKCoin) UpdateTickers(ctx context.Context, a asset.Item) error {
// UpdateTicker updates and returns the ticker for a currency pair
func (o *OKCoin) UpdateTicker(ctx context.Context, p currency.Pair, a asset.Item) (*ticker.Price, error) {
err := o.UpdateTickers(ctx, a)
if err != nil {
if err := o.UpdateTickers(ctx, a); err != nil {
return nil, err
}
return ticker.GetTicker(o.Name, p, a)

View File

@@ -187,6 +187,7 @@ func TestGetPerpSwapMarkets(t *testing.T) {
}
func testStandardErrorHandling(t *testing.T, err error) {
t.Helper()
if !areTestAPIKeysSet() && err == nil {
t.Errorf("Expecting an error when no keys are set")
}

View File

@@ -540,8 +540,7 @@ func (o *OKEX) UpdateTickers(ctx context.Context, a asset.Item) error {
// UpdateTicker updates and returns the ticker for a currency pair
func (o *OKEX) UpdateTicker(ctx context.Context, p currency.Pair, a asset.Item) (*ticker.Price, error) {
err := o.UpdateTickers(ctx, a)
if err != nil {
if err := o.UpdateTickers(ctx, a); err != nil {
return nil, err
}
return ticker.GetTicker(o.Name, p, a)

View File

@@ -546,11 +546,11 @@ func FormatParameters(request interface{}) (parameters string) {
func (o *OKGroup) GetErrorCode(code interface{}) error {
var assertedCode string
switch reflect.TypeOf(code).String() {
case "float64":
assertedCode = strconv.FormatFloat(code.(float64), 'f', -1, 64)
case "string":
assertedCode = code.(string)
switch d := code.(type) {
case float64:
assertedCode = strconv.FormatFloat(d, 'f', -1, 64)
case string:
assertedCode = d
default:
return errors.New("unusual type returned")
}

View File

@@ -276,8 +276,7 @@ func (o *OKGroup) GetFundingHistory(ctx context.Context) (resp []exchange.FundHi
// SubmitOrder submits a new order
func (o *OKGroup) SubmitOrder(ctx context.Context, s *order.Submit) (order.SubmitResponse, error) {
err := s.Validate()
if err != nil {
if err := s.Validate(); err != nil {
return order.SubmitResponse{}, err
}
@@ -625,37 +624,34 @@ func (o *OKGroup) GetHistoricCandles(ctx context.Context, pair currency.Pair, a
}
for x := range candles {
t := candles[x].([]interface{})
tempCandle := kline.Candle{}
t, ok := candles[x].([]interface{})
if !ok {
return kline.Item{}, errors.New("unable to type asset candle data")
}
if len(t) < 6 {
return kline.Item{}, errors.New("incorrect candles data length")
}
v, ok := t[0].(string)
if !ok {
return kline.Item{}, errors.New("unexpected value received")
return kline.Item{}, errors.New("unable to type asset time data")
}
tempCandle.Time, err = time.Parse(time.RFC3339, v)
if err != nil {
var tempCandle kline.Candle
if tempCandle.Time, err = time.Parse(time.RFC3339, v); err != nil {
return kline.Item{}, err
}
tempCandle.Open, err = convert.FloatFromString(t[1])
if err != nil {
if tempCandle.Open, err = convert.FloatFromString(t[1]); err != nil {
return kline.Item{}, err
}
tempCandle.High, err = convert.FloatFromString(t[2])
if err != nil {
if tempCandle.High, err = convert.FloatFromString(t[2]); err != nil {
return kline.Item{}, err
}
tempCandle.Low, err = convert.FloatFromString(t[3])
if err != nil {
if tempCandle.Low, err = convert.FloatFromString(t[3]); err != nil {
return kline.Item{}, err
}
tempCandle.Close, err = convert.FloatFromString(t[4])
if err != nil {
if tempCandle.Close, err = convert.FloatFromString(t[4]); err != nil {
return kline.Item{}, err
}
tempCandle.Volume, err = convert.FloatFromString(t[5])
if err != nil {
if tempCandle.Volume, err = convert.FloatFromString(t[5]); err != nil {
return kline.Item{}, err
}
ret.Candles = append(ret.Candles, tempCandle)
@@ -703,37 +699,37 @@ func (o *OKGroup) GetHistoricCandlesExtended(ctx context.Context, pair currency.
}
for i := range candles {
t := candles[i].([]interface{})
tempCandle := kline.Candle{}
t, ok := candles[i].([]interface{})
if !ok {
return kline.Item{}, errors.New("unable to type assert candles data")
}
if len(t) < 6 {
return kline.Item{}, errors.New("candle data length invalid")
}
v, ok := t[0].(string)
if !ok {
return kline.Item{}, errors.New("unexpected value received")
return kline.Item{}, errors.New("unable to type assert time value")
}
tempCandle.Time, err = time.Parse(time.RFC3339, v)
if err != nil {
var tempCandle kline.Candle
if tempCandle.Time, err = time.Parse(time.RFC3339, v); err != nil {
return kline.Item{}, err
}
tempCandle.Open, err = convert.FloatFromString(t[1])
if err != nil {
if tempCandle.Open, err = convert.FloatFromString(t[1]); err != nil {
return kline.Item{}, err
}
tempCandle.High, err = convert.FloatFromString(t[2])
if err != nil {
if tempCandle.High, err = convert.FloatFromString(t[2]); err != nil {
return kline.Item{}, err
}
tempCandle.Low, err = convert.FloatFromString(t[3])
if err != nil {
if tempCandle.Low, err = convert.FloatFromString(t[3]); err != nil {
return kline.Item{}, err
}
tempCandle.Close, err = convert.FloatFromString(t[4])
if err != nil {
if tempCandle.Close, err = convert.FloatFromString(t[4]); err != nil {
return kline.Item{}, err
}
tempCandle.Volume, err = convert.FloatFromString(t[5])
if err != nil {
if tempCandle.Volume, err = convert.FloatFromString(t[5]); err != nil {
return kline.Item{}, err
}
ret.Candles = append(ret.Candles, tempCandle)

View File

@@ -40,7 +40,7 @@ func (ll *linkedList) display() {
func TestLoad(t *testing.T) {
list := asks{}
Check(list, 0, 0, 0, t)
Check(t, list, 0, 0, 0)
stack := newStack()
list.load(Items{
@@ -56,7 +56,7 @@ func TestLoad(t *testing.T) {
t.Fatalf("incorrect stack count expected: %v received: %v", 0, stack.getCount())
}
Check(list, 6, 36, 6, t)
Check(t, list, 6, 36, 6)
list.load(Items{
{Price: 1, Amount: 1},
@@ -68,7 +68,7 @@ func TestLoad(t *testing.T) {
t.Fatalf("incorrect stack count expected: %v received: %v", 3, stack.getCount())
}
Check(list, 3, 9, 3, t)
Check(t, list, 3, 9, 3)
list.load(Items{
{Price: 1, Amount: 1},
@@ -81,7 +81,7 @@ func TestLoad(t *testing.T) {
t.Fatalf("incorrect stack count expected: %v received: %v", 2, stack.getCount())
}
Check(list, 4, 16, 4, t)
Check(t, list, 4, 16, 4)
// purge entire list
list.load(nil, stack)
@@ -90,7 +90,7 @@ func TestLoad(t *testing.T) {
t.Fatalf("incorrect stack count expected: %v received: %v", 6, stack.getCount())
}
Check(list, 0, 0, 0, t)
Check(t, list, 0, 0, 0)
}
// 22222386 57.3 ns/op 0 B/op 0 allocs/op (old)
@@ -121,7 +121,7 @@ func TestUpdateInsertByPrice(t *testing.T) {
{Price: 1, Amount: 2},
}, stack, 0, getNow())
Check(a, 7, 37, 6, t)
Check(t, a, 7, 37, 6)
if stack.getCount() != 0 {
t.Fatalf("incorrect stack count expected: %v received: %v", 0, stack.getCount())
@@ -132,7 +132,7 @@ func TestUpdateInsertByPrice(t *testing.T) {
{Price: 0.5, Amount: 2},
}, stack, 0, getNow())
Check(a, 9, 38, 7, t)
Check(t, a, 9, 38, 7)
if stack.getCount() != 0 {
t.Fatalf("incorrect stack count expected: %v received: %v", 0, stack.getCount())
@@ -143,7 +143,7 @@ func TestUpdateInsertByPrice(t *testing.T) {
{Price: 12, Amount: 2},
}, stack, 0, getNow())
Check(a, 11, 62, 8, t)
Check(t, a, 11, 62, 8)
if stack.getCount() != 0 {
t.Fatalf("incorrect stack count expected: %v received: %v", 0, stack.getCount())
@@ -156,7 +156,7 @@ func TestUpdateInsertByPrice(t *testing.T) {
{Price: 13, Amount: 2},
}, stack, 10, getNow())
Check(a, 15, 106, 10, t)
Check(t, a, 15, 106, 10)
if stack.getCount() != 1 {
t.Fatalf("incorrect stack count expected: %v received: %v", 1, stack.getCount())
@@ -167,7 +167,7 @@ func TestUpdateInsertByPrice(t *testing.T) {
{Price: 12, Amount: 0},
}, stack, 0, getNow())
Check(a, 13, 82, 9, t)
Check(t, a, 13, 82, 9)
if stack.getCount() != 2 {
t.Fatalf("incorrect stack count expected: %v received: %v", 2, stack.getCount())
@@ -178,7 +178,7 @@ func TestUpdateInsertByPrice(t *testing.T) {
{Price: 7, Amount: 0},
}, stack, 0, getNow())
Check(a, 12, 75, 8, t)
Check(t, a, 12, 75, 8)
if stack.getCount() != 3 {
t.Fatalf("incorrect stack count expected: %v received: %v", 3, stack.getCount())
@@ -189,7 +189,7 @@ func TestUpdateInsertByPrice(t *testing.T) {
{Price: 0.5, Amount: 0},
}, stack, 0, getNow())
Check(a, 10, 74, 7, t)
Check(t, a, 10, 74, 7)
if stack.getCount() != 4 {
t.Fatalf("incorrect stack count expected: %v received: %v", 4, stack.getCount())
@@ -208,7 +208,7 @@ func TestUpdateInsertByPrice(t *testing.T) {
{Price: 11, Amount: 1},
}, stack, 0, getNow())
Check(a, 6, 36, 6, t)
Check(t, a, 6, 36, 6)
if stack.getCount() != 5 {
t.Fatalf("incorrect stack count expected: %v received: %v", 4, stack.getCount())
@@ -230,7 +230,7 @@ func TestUpdateInsertByPrice(t *testing.T) {
{Price: 11, Amount: 2},
}, stack, 0, getNow())
Check(b, 7, 47, 6, t)
Check(t, b, 7, 47, 6)
if stack.getCount() != 0 {
t.Fatalf("incorrect stack count expected: %v received: %v", 0, stack.getCount())
@@ -241,7 +241,7 @@ func TestUpdateInsertByPrice(t *testing.T) {
{Price: 12, Amount: 2},
}, stack, 0, getNow())
Check(b, 9, 71, 7, t)
Check(t, b, 9, 71, 7)
if stack.getCount() != 0 {
t.Fatalf("incorrect stack count expected: %v received: %v", 0, stack.getCount())
@@ -252,7 +252,7 @@ func TestUpdateInsertByPrice(t *testing.T) {
{Price: 0.5, Amount: 2},
}, stack, 0, getNow())
Check(b, 11, 72, 8, t)
Check(t, b, 11, 72, 8)
if stack.getCount() != 0 {
t.Fatalf("incorrect stack count expected: %v received: %v", 0, stack.getCount())
@@ -265,7 +265,7 @@ func TestUpdateInsertByPrice(t *testing.T) {
{Price: 13, Amount: 2},
}, stack, 10, getNow())
Check(b, 15, 141, 10, t)
Check(t, b, 15, 141, 10)
if stack.getCount() != 1 {
t.Fatalf("incorrect stack count expected: %v received: %v", 0, stack.getCount())
@@ -276,7 +276,7 @@ func TestUpdateInsertByPrice(t *testing.T) {
{Price: 1, Amount: 0},
}, stack, 0, getNow())
Check(b, 14, 140, 9, t)
Check(t, b, 14, 140, 9)
if stack.getCount() != 2 {
t.Fatalf("incorrect stack count expected: %v received: %v", 2, stack.getCount())
@@ -287,7 +287,7 @@ func TestUpdateInsertByPrice(t *testing.T) {
{Price: 10.5, Amount: 0},
}, stack, 0, getNow())
Check(b, 12, 119, 8, t)
Check(t, b, 12, 119, 8)
if stack.getCount() != 3 {
t.Fatalf("incorrect stack count expected: %v received: %v", 3, stack.getCount())
@@ -298,7 +298,7 @@ func TestUpdateInsertByPrice(t *testing.T) {
{Price: 13, Amount: 0},
}, stack, 0, getNow())
Check(b, 10, 93, 7, t)
Check(t, b, 10, 93, 7)
if stack.getCount() != 4 {
t.Fatalf("incorrect stack count expected: %v received: %v", 4, stack.getCount())
@@ -317,7 +317,7 @@ func TestUpdateInsertByPrice(t *testing.T) {
{Price: 11, Amount: 1},
}, stack, 0, getNow())
Check(b, 6, 36, 6, t)
Check(t, b, 6, 36, 6)
if stack.getCount() != 5 {
t.Fatalf("incorrect stack count expected: %v received: %v", 4, stack.getCount())
@@ -338,15 +338,15 @@ func TestCleanup(t *testing.T) {
a.load(asksSnapshot, stack)
a.cleanup(6, stack)
Check(a, 6, 36, 6, t)
Check(t, a, 6, 36, 6)
a.cleanup(5, stack)
Check(a, 5, 25, 5, t)
Check(t, a, 5, 25, 5)
a.cleanup(1, stack)
Check(a, 1, 1, 1, t)
Check(t, a, 1, 1, 1)
a.cleanup(10, stack)
Check(a, 1, 1, 1, t)
Check(t, a, 1, 1, 1)
a.cleanup(0, stack) // will purge, underlying checks are done elseware to prevent this
Check(a, 0, 0, 0, t)
Check(t, a, 0, 0, 0)
}
// 46154023 24.0 ns/op 0 B/op 0 allocs/op (old)
@@ -421,7 +421,7 @@ func TestUpdateByID(t *testing.T) {
t.Fatal(err)
}
Check(a, 6, 36, 6, t)
Check(t, a, 6, 36, 6)
err = a.updateByID(Items{
{Price: 11, Amount: 1, ID: 1337},
@@ -496,7 +496,7 @@ func TestDeleteByID(t *testing.T) {
t.Fatal(err)
}
Check(a, 5, 35, 5, t)
Check(t, a, 5, 35, 5)
// Delete at tail
err = a.deleteByID(Items{
@@ -506,7 +506,7 @@ func TestDeleteByID(t *testing.T) {
t.Fatal(err)
}
Check(a, 4, 24, 4, t)
Check(t, a, 4, 24, 4)
// Delete in middle
err = a.deleteByID(Items{
@@ -516,7 +516,7 @@ func TestDeleteByID(t *testing.T) {
t.Fatal(err)
}
Check(a, 3, 19, 3, t)
Check(t, a, 3, 19, 3)
// Intentional error
err = a.deleteByID(Items{
@@ -556,7 +556,7 @@ func TestUpdateInsertByIDAsk(t *testing.T) {
t.Fatal(err)
}
Check(a, 7, 37, 6, t)
Check(t, a, 7, 37, 6)
// Reset
a.load(asksSnapshot, s)
@@ -574,7 +574,7 @@ func TestUpdateInsertByIDAsk(t *testing.T) {
t.Fatal(err)
}
Check(a, 12, 72, 6, t)
Check(t, a, 12, 72, 6)
// Update all instances with matching ID in backwards
err = a.updateInsertByID(Items{
@@ -589,7 +589,7 @@ func TestUpdateInsertByIDAsk(t *testing.T) {
t.Fatal(err)
}
Check(a, 12, 72, 6, t)
Check(t, a, 12, 72, 6)
// Update all instances with matching ID all over the ship
err = a.updateInsertByID(Items{
@@ -604,7 +604,7 @@ func TestUpdateInsertByIDAsk(t *testing.T) {
t.Fatal(err)
}
Check(a, 12, 72, 6, t)
Check(t, a, 12, 72, 6)
// Update all instances move one before ID in middle
err = a.updateInsertByID(Items{
@@ -619,7 +619,7 @@ func TestUpdateInsertByIDAsk(t *testing.T) {
t.Fatal(err)
}
Check(a, 12, 66, 6, t)
Check(t, a, 12, 66, 6)
// Update all instances move one before ID at head
err = a.updateInsertByID(Items{
@@ -634,7 +634,7 @@ func TestUpdateInsertByIDAsk(t *testing.T) {
t.Fatal(err)
}
Check(a, 12, 63, 6, t)
Check(t, a, 12, 63, 6)
// Reset
a.load(asksSnapshot, s)
@@ -652,7 +652,7 @@ func TestUpdateInsertByIDAsk(t *testing.T) {
t.Fatal(err)
}
Check(a, 12, 78, 6, t)
Check(t, a, 12, 78, 6)
// Reset
a.load(asksSnapshot, s)
@@ -670,7 +670,7 @@ func TestUpdateInsertByIDAsk(t *testing.T) {
t.Fatal(err)
}
Check(a, 12, 86, 6, t)
Check(t, a, 12, 86, 6)
// Update all instances then pop new instance
err = a.updateInsertByID(Items{
@@ -686,7 +686,7 @@ func TestUpdateInsertByIDAsk(t *testing.T) {
t.Fatal(err)
}
Check(a, 14, 106, 7, t)
Check(t, a, 14, 106, 7)
// Reset
a.load(asksSnapshot, s)
@@ -705,7 +705,7 @@ func TestUpdateInsertByIDAsk(t *testing.T) {
t.Fatal(err)
}
Check(a, 14, 87, 7, t)
Check(t, a, 14, 87, 7)
// bookmark head and move to mid
err = a.updateInsertByID(Items{
@@ -715,7 +715,7 @@ func TestUpdateInsertByIDAsk(t *testing.T) {
t.Fatal(err)
}
Check(a, 14, 101, 7, t)
Check(t, a, 14, 101, 7)
// bookmark head and move to tail
err = a.updateInsertByID(Items{
@@ -725,7 +725,7 @@ func TestUpdateInsertByIDAsk(t *testing.T) {
t.Fatal(err)
}
Check(a, 14, 124, 7, t)
Check(t, a, 14, 124, 7)
// move tail location to head
err = a.updateInsertByID(Items{
@@ -735,7 +735,7 @@ func TestUpdateInsertByIDAsk(t *testing.T) {
t.Fatal(err)
}
Check(a, 14, 104, 7, t)
Check(t, a, 14, 104, 7)
// move tail location to mid
err = a.updateInsertByID(Items{
@@ -745,7 +745,7 @@ func TestUpdateInsertByIDAsk(t *testing.T) {
t.Fatal(err)
}
Check(a, 14, 96, 7, t)
Check(t, a, 14, 96, 7)
// insert at tail dont match
err = a.updateInsertByID(Items{
@@ -755,7 +755,7 @@ func TestUpdateInsertByIDAsk(t *testing.T) {
t.Fatal(err)
}
Check(a, 16, 156, 8, t)
Check(t, a, 16, 156, 8)
// insert between last and 2nd last
err = a.updateInsertByID(Items{
@@ -765,7 +765,7 @@ func TestUpdateInsertByIDAsk(t *testing.T) {
t.Fatal(err)
}
Check(a, 18, 180, 9, t)
Check(t, a, 18, 180, 9)
// readjust at end
err = a.updateInsertByID(Items{
@@ -775,7 +775,7 @@ func TestUpdateInsertByIDAsk(t *testing.T) {
t.Fatal(err)
}
Check(a, 19, 207, 9, t)
Check(t, a, 19, 207, 9)
// readjust further and decrease price past tail
err = a.updateInsertByID(Items{
@@ -785,7 +785,7 @@ func TestUpdateInsertByIDAsk(t *testing.T) {
t.Fatal(err)
}
Check(a, 19, 213, 9, t)
Check(t, a, 19, 213, 9)
// purge
a.load(nil, s)
@@ -804,7 +804,7 @@ func TestUpdateInsertByIDAsk(t *testing.T) {
t.Fatal(err)
}
Check(a, 14, 87, 7, t)
Check(t, a, 14, 87, 7)
}
func TestUpdateInsertByIDBids(t *testing.T) {
@@ -828,7 +828,7 @@ func TestUpdateInsertByIDBids(t *testing.T) {
t.Fatal(err)
}
Check(b, 7, 37, 6, t)
Check(t, b, 7, 37, 6)
// Reset
b.load(bidsSnapshot, s)
@@ -846,7 +846,7 @@ func TestUpdateInsertByIDBids(t *testing.T) {
t.Fatal(err)
}
Check(b, 12, 72, 6, t)
Check(t, b, 12, 72, 6)
// Update all instances with matching ID in backwards
err = b.updateInsertByID(Items{
@@ -861,7 +861,7 @@ func TestUpdateInsertByIDBids(t *testing.T) {
t.Fatal(err)
}
Check(b, 12, 72, 6, t)
Check(t, b, 12, 72, 6)
// Update all instances with matching ID all over the ship
err = b.updateInsertByID(Items{
@@ -876,7 +876,7 @@ func TestUpdateInsertByIDBids(t *testing.T) {
t.Fatal(err)
}
Check(b, 12, 72, 6, t)
Check(t, b, 12, 72, 6)
// Update all instances move one before ID in middle
err = b.updateInsertByID(Items{
@@ -891,7 +891,7 @@ func TestUpdateInsertByIDBids(t *testing.T) {
t.Fatal(err)
}
Check(b, 12, 66, 6, t)
Check(t, b, 12, 66, 6)
// Update all instances move one before ID at head
err = b.updateInsertByID(Items{
@@ -906,7 +906,7 @@ func TestUpdateInsertByIDBids(t *testing.T) {
t.Fatal(err)
}
Check(b, 12, 63, 6, t)
Check(t, b, 12, 63, 6)
// Reset
b.load(bidsSnapshot, s)
@@ -924,7 +924,7 @@ func TestUpdateInsertByIDBids(t *testing.T) {
t.Fatal(err)
}
Check(b, 12, 78, 6, t)
Check(t, b, 12, 78, 6)
// Reset
b.load(bidsSnapshot, s)
@@ -942,7 +942,7 @@ func TestUpdateInsertByIDBids(t *testing.T) {
t.Fatal(err)
}
Check(b, 12, 86, 6, t)
Check(t, b, 12, 86, 6)
// Update all instances then pop new instance
err = b.updateInsertByID(Items{
@@ -958,7 +958,7 @@ func TestUpdateInsertByIDBids(t *testing.T) {
t.Fatal(err)
}
Check(b, 14, 106, 7, t)
Check(t, b, 14, 106, 7)
// Reset
b.load(bidsSnapshot, s)
@@ -977,7 +977,7 @@ func TestUpdateInsertByIDBids(t *testing.T) {
t.Fatal(err)
}
Check(b, 14, 87, 7, t)
Check(t, b, 14, 87, 7)
// bookmark head and move to mid
err = b.updateInsertByID(Items{
@@ -987,7 +987,7 @@ func TestUpdateInsertByIDBids(t *testing.T) {
t.Fatal(err)
}
Check(b, 14, 82, 7, t)
Check(t, b, 14, 82, 7)
// bookmark head and move to tail
err = b.updateInsertByID(Items{
@@ -997,7 +997,7 @@ func TestUpdateInsertByIDBids(t *testing.T) {
t.Fatal(err)
}
Check(b, 14, 60.5, 7, t)
Check(t, b, 14, 60.5, 7)
// move tail location to head
err = b.updateInsertByID(Items{
@@ -1007,7 +1007,7 @@ func TestUpdateInsertByIDBids(t *testing.T) {
t.Fatal(err)
}
Check(b, 14, 80, 7, t)
Check(t, b, 14, 80, 7)
// move tail location to mid
err = b.updateInsertByID(Items{
@@ -1017,7 +1017,7 @@ func TestUpdateInsertByIDBids(t *testing.T) {
t.Fatal(err)
}
Check(b, 14, 94, 7, t)
Check(t, b, 14, 94, 7)
// insert at head dont match
err = b.updateInsertByID(Items{
@@ -1027,7 +1027,7 @@ func TestUpdateInsertByIDBids(t *testing.T) {
t.Fatal(err)
}
Check(b, 16, 154, 8, t)
Check(t, b, 16, 154, 8)
// insert between last and 2nd last
err = b.updateInsertByID(Items{
@@ -1036,7 +1036,7 @@ func TestUpdateInsertByIDBids(t *testing.T) {
if err != nil {
t.Fatal(err)
}
Check(b, 18, 157, 9, t)
Check(t, b, 18, 157, 9)
// readjust at end
err = b.updateInsertByID(Items{
@@ -1045,7 +1045,7 @@ func TestUpdateInsertByIDBids(t *testing.T) {
if err != nil {
t.Fatal(err)
}
Check(b, 19, 158, 9, t)
Check(t, b, 19, 158, 9)
// readjust further and decrease price past tail
err = b.updateInsertByID(Items{
@@ -1054,7 +1054,7 @@ func TestUpdateInsertByIDBids(t *testing.T) {
if err != nil {
t.Fatal(err)
}
Check(b, 19, 157.7, 9, t)
Check(t, b, 19, 157.7, 9)
// purge
b.load(nil, s)
@@ -1073,7 +1073,7 @@ func TestUpdateInsertByIDBids(t *testing.T) {
t.Fatal(err)
}
Check(b, 14, 87, 7, t)
Check(t, b, 14, 87, 7)
}
func TestInsertUpdatesBid(t *testing.T) {
@@ -1101,7 +1101,7 @@ func TestInsertUpdatesBid(t *testing.T) {
t.Fatalf("expected error %s but received %v", errCollisionDetected, err)
}
Check(b, 6, 36, 6, t)
Check(t, b, 6, 36, 6)
// Insert at head
err = b.insertUpdates(Items{
@@ -1111,7 +1111,7 @@ func TestInsertUpdatesBid(t *testing.T) {
t.Fatal(err)
}
Check(b, 7, 48, 7, t)
Check(t, b, 7, 48, 7)
// Insert at tail
err = b.insertUpdates(Items{
@@ -1121,7 +1121,7 @@ func TestInsertUpdatesBid(t *testing.T) {
t.Fatal(err)
}
Check(b, 8, 48.5, 8, t)
Check(t, b, 8, 48.5, 8)
// Insert at mid
err = b.insertUpdates(Items{
@@ -1131,7 +1131,7 @@ func TestInsertUpdatesBid(t *testing.T) {
t.Fatal(err)
}
Check(b, 9, 54, 9, t)
Check(t, b, 9, 54, 9)
// purge
b.load(nil, s)
@@ -1144,7 +1144,7 @@ func TestInsertUpdatesBid(t *testing.T) {
t.Fatal(err)
}
Check(b, 1, 5.5, 1, t)
Check(t, b, 1, 5.5, 1)
}
func TestInsertUpdatesAsk(t *testing.T) {
@@ -1172,7 +1172,7 @@ func TestInsertUpdatesAsk(t *testing.T) {
t.Fatalf("expected error %s but received %v", errCollisionDetected, err)
}
Check(a, 6, 36, 6, t)
Check(t, a, 6, 36, 6)
// Insert at tail
err = a.insertUpdates(Items{
@@ -1182,7 +1182,7 @@ func TestInsertUpdatesAsk(t *testing.T) {
t.Fatal(err)
}
Check(a, 7, 48, 7, t)
Check(t, a, 7, 48, 7)
// Insert at head
err = a.insertUpdates(Items{
@@ -1192,7 +1192,7 @@ func TestInsertUpdatesAsk(t *testing.T) {
t.Fatal(err)
}
Check(a, 8, 48.5, 8, t)
Check(t, a, 8, 48.5, 8)
// Insert at mid
err = a.insertUpdates(Items{
@@ -1202,7 +1202,7 @@ func TestInsertUpdatesAsk(t *testing.T) {
t.Fatal(err)
}
Check(a, 9, 54, 9, t)
Check(t, a, 9, 54, 9)
// purge
a.load(nil, s)
@@ -1215,11 +1215,11 @@ func TestInsertUpdatesAsk(t *testing.T) {
t.Fatal(err)
}
Check(a, 1, 5.5, 1, t)
Check(t, a, 1, 5.5, 1)
}
// check checks depth values after an update has taken place
func Check(depth interface{}, liquidity, value float64, nodeCount int, t *testing.T) {
func Check(t *testing.T, depth interface{}, liquidity, value float64, nodeCount int) {
t.Helper()
b, isBid := depth.(bids)
a, isAsk := depth.(asks)
@@ -1434,7 +1434,7 @@ func TestShiftBookmark(t *testing.T) {
t.Fatal("nilBookmark not reassigned")
}
head := bookmarkedNode
head := bookmarkedNode // nolint // ifshort false positive
bookmarkedNode.Prev = nil
bookmarkedNode.Next = originalBookmarkNext
tip.Next = nil

View File

@@ -54,7 +54,6 @@ func getNow() now {
func (s *stack) Push(n *Node, tn now) {
if !atomic.CompareAndSwapUint32(&s.sema, neutral, active) {
// Stack is in use, for now we can dereference pointer
n = nil
return
}
// Adds a time when its placed back on to stack.

View File

@@ -321,8 +321,7 @@ func (b *Base) Process() error {
b.LastUpdated = time.Now()
}
err := b.Verify()
if err != nil {
if err := b.Verify(); err != nil {
return err
}
return service.Update(b)

View File

@@ -605,9 +605,7 @@ func TestReverse(t *testing.T) {
var b Base
b.VerifyOrderbook = true
length := 1000
b.Bids = deploySliceOrdered()
if len(b.Bids) != length {
if b.Bids = deploySliceOrdered(); len(b.Bids) != 1000 {
t.Fatal("incorrect length")
}
@@ -637,9 +635,8 @@ func TestReverse(t *testing.T) {
// 705985 1856 ns/op 0 B/op 0 allocs/op
func BenchmarkReverse(b *testing.B) {
length := 1000
s := deploySliceOrdered()
if len(s) != length {
if len(s) != 1000 {
b.Fatal("incorrect length")
}

View File

@@ -246,7 +246,10 @@ func (p *Poloniex) GetBalances(ctx context.Context) (Balance, error) {
return Balance{}, err
}
data := result.(map[string]interface{})
data, ok := result.(map[string]interface{})
if !ok {
return Balance{}, errors.New("unable to type assert balance result")
}
balance := Balance{}
balance.Currency = make(map[string]float64)
@@ -287,7 +290,10 @@ func (p *Poloniex) GetDepositAddresses(ctx context.Context) (DepositAddresses, e
}
for x, y := range data {
addresses.Addresses[x] = y.(string)
addresses.Addresses[x], ok = y.(string)
if !ok {
return addresses, errors.New("unable to type assert address to string")
}
}
return addresses, nil

View File

@@ -1,4 +1,5 @@
//+build !mock_test_off
//go:build !mock_test_off
// +build !mock_test_off
// This will build if build tag mock_test_off is not parsed and will try to mock
// all tests in _test.go

View File

@@ -270,6 +270,7 @@ func TestGetOrderStatus(t *testing.T) {
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
if tt.mock != mockTests {
t.Skip()
}
@@ -325,6 +326,7 @@ func TestGetOrderTrades(t *testing.T) {
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
if tt.mock != mockTests {
t.Skip()
}

View File

@@ -312,8 +312,7 @@ func (p *Poloniex) UpdateTickers(ctx context.Context, a asset.Item) error {
// UpdateTicker updates and returns the ticker for a currency pair
func (p *Poloniex) UpdateTicker(ctx context.Context, currencyPair currency.Pair, a asset.Item) (*ticker.Price, error) {
err := p.UpdateTickers(ctx, a)
if err != nil {
if err := p.UpdateTickers(ctx, a); err != nil {
return nil, err
}
return ticker.GetTicker(p.Name, currencyPair, a)

View File

@@ -8,6 +8,7 @@ import (
)
func TestLinearBackoff(t *testing.T) {
t.Parallel()
type args struct {
Backoff request.Backoff
}

View File

@@ -272,7 +272,7 @@ func (r *Requester) GetNonce(isNano bool) nonce.Value {
func (r *Requester) GetNonceMilli() nonce.Value {
r.timedLock.LockForDuration()
if r.Nonce.Get() == 0 {
r.Nonce.Set(time.Now().UnixNano() / int64(time.Millisecond))
r.Nonce.Set(time.Now().UnixMilli())
return r.Nonce.Get()
}
return r.Nonce.GetInc()

View File

@@ -484,18 +484,14 @@ func TestGetNonce(t *testing.T) {
new(http.Client),
WithLimiter(&globalshell))
n1 := r.GetNonce(false)
n2 := r.GetNonce(false)
if n1 == n2 {
if n1, n2 := r.GetNonce(false), r.GetNonce(false); n1 == n2 {
t.Fatal(unexpected)
}
r2 := New("test",
new(http.Client),
WithLimiter(&globalshell))
n3 := r2.GetNonce(true)
n4 := r2.GetNonce(true)
if n3 == n4 {
if n1, n2 := r2.GetNonce(true), r2.GetNonce(true); n1 == n2 {
t.Fatal(unexpected)
}
}
@@ -505,9 +501,7 @@ func TestGetNonceMillis(t *testing.T) {
r := New("test",
new(http.Client),
WithLimiter(&globalshell))
m1 := r.GetNonceMilli()
m2 := r.GetNonceMilli()
if m1 == m2 {
if m1, m2 := r.GetNonceMilli(), r.GetNonceMilli(); m1 == m2 {
log.Fatal(unexpected)
}
}
@@ -562,7 +556,7 @@ func TestBasicLimiter(t *testing.T) {
defer cancel()
err = r.SendPayload(ctx, Unset, func() (*Item, error) { return &i, nil })
if !errors.Is(err, context.DeadlineExceeded) {
t.Fatalf("receieved: %v but expected: %v", err, context.DeadlineExceeded)
t.Fatalf("received: %v but expected: %v", err, context.DeadlineExceeded)
}
}

View File

@@ -11,6 +11,7 @@ import (
)
func TestDefaultRetryPolicy(t *testing.T) {
t.Parallel()
type args struct {
Error error
Response *http.Response
@@ -70,6 +71,7 @@ func TestDefaultRetryPolicy(t *testing.T) {
}
func TestRetryAfter(t *testing.T) {
t.Parallel()
now := time.Date(2020, time.April, 20, 13, 31, 13, 0, time.UTC)
type args struct {

View File

@@ -48,8 +48,7 @@ func (m *Match) IncomingWithData(signature interface{}, data []byte) bool {
func (m *Match) set(signature interface{}) (matcher, error) {
var ch chan []byte
m.Lock()
_, ok := m.m[signature]
if ok {
if _, ok := m.m[signature]; ok {
m.Unlock()
return matcher{}, errors.New("signature collision")
}

View File

@@ -42,9 +42,8 @@ func TestMatch(t *testing.T) {
fmt.Println("should not have been able to match")
}
data := <-m.C
if data != nil {
t.Fatal("wow")
if data := <-m.C; data != nil {
t.Fatal("data chan should be nil")
}
m.Cleanup()

View File

@@ -475,8 +475,7 @@ func (w *Websocket) FlushChannels() error {
return nil
}
err := w.Shutdown()
if err != nil {
if err := w.Shutdown(); err != nil {
return err
}
return w.Connect()
@@ -867,8 +866,7 @@ func (w *Websocket) SubscribeToChannels(channels []ChannelSubscription) error {
}
}
}
err := w.Subscriber(channels)
if err != nil {
if err := w.Subscriber(channels); err != nil {
return fmt.Errorf("%v %w: %v", w.exchangeName, ErrSubscriptionFailure, err)
}
return nil

View File

@@ -167,8 +167,7 @@ func TestSetup(t *testing.T) {
func TestTrafficMonitorTimeout(t *testing.T) {
t.Parallel()
ws := *New()
err := ws.Setup(defaultSetup)
if err != nil {
if err := ws.Setup(defaultSetup); err != nil {
t.Fatal(err)
}
ws.trafficTimeout = time.Second * 2
@@ -650,6 +649,7 @@ func TestDial(t *testing.T) {
for i := range testCases {
testData := &testCases[i]
t.Run(testData.WC.ExchangeName, func(t *testing.T) {
t.Parallel()
if testData.WC.ProxyURL != "" && !useProxyTests {
t.Skip("Proxy testing not enabled, skipping")
}
@@ -697,6 +697,7 @@ func TestSendMessage(t *testing.T) {
for i := range testCases {
testData := &testCases[i]
t.Run(testData.WC.ExchangeName, func(t *testing.T) {
t.Parallel()
if testData.WC.ProxyURL != "" && !useProxyTests {
t.Skip("Proxy testing not enabled, skipping")
}
@@ -737,7 +738,7 @@ func TestSendMessageWithResponse(t *testing.T) {
t.Fatal(err)
}
go readMessages(wc, t)
go readMessages(t, wc)
request := testRequest{
Event: "subscribe",
@@ -755,7 +756,8 @@ func TestSendMessageWithResponse(t *testing.T) {
}
// readMessages helper func
func readMessages(wc *WebsocketConnection, t *testing.T) {
func readMessages(t *testing.T, wc *WebsocketConnection) {
t.Helper()
timer := time.NewTimer(20 * time.Second)
for {
select {

View File

@@ -222,8 +222,7 @@ func (y *Yobit) UpdateTickers(ctx context.Context, a asset.Item) error {
// UpdateTicker updates and returns the ticker for a currency pair
func (y *Yobit) UpdateTicker(ctx context.Context, p currency.Pair, a asset.Item) (*ticker.Price, error) {
err := y.UpdateTickers(ctx, a)
if err != nil {
if err := y.UpdateTickers(ctx, a); err != nil {
return nil, err
}
return ticker.GetTicker(y.Name, p, a)

View File

@@ -227,39 +227,39 @@ func (z *ZB) GetSpotKline(ctx context.Context, arg KlinesRequestParams) (KLineRe
urlPath := fmt.Sprintf("/%s/%s/%s?%s", zbData, zbAPIVersion, zbKline, vals.Encode())
var res KLineResponse
var rawKlines map[string]interface{}
err := z.SendHTTPRequest(ctx, exchange.RestSpot, urlPath, &rawKlines, klineFunc)
resp := struct {
Data [][]float64 `json:"data"`
MoneyType string `json:"moneyType"`
Symbol string `json:"symbol"`
}{}
err := z.SendHTTPRequest(ctx, exchange.RestSpot, urlPath, &resp, klineFunc)
if err != nil {
return res, err
}
if rawKlines == nil || rawKlines["symbol"] == nil {
return res, errors.New("zb GetSpotKline rawKlines is nil")
if resp.Data == nil || resp.Symbol == "" || resp.MoneyType == "" {
return res, errors.New("GetSpotKline received empty data")
}
res.MoneyType = resp.MoneyType
res.Symbol = resp.Symbol
res.Symbol = rawKlines["symbol"].(string)
res.MoneyType = rawKlines["moneyType"].(string)
for x := range resp.Data {
if len(resp.Data[x]) < 6 {
return res, errors.New("unexpected kline data length")
}
rawKlineDatasString, _ := json.Marshal(rawKlines["data"].([]interface{}))
var rawKlineDatas [][]interface{}
if err := json.Unmarshal(rawKlineDatasString, &rawKlineDatas); err != nil {
return res, errors.New("zb rawKlines unmarshal failed")
}
for _, k := range rawKlineDatas {
ot, err := convert.TimeFromUnixTimestampFloat(k[0])
ot, err := convert.TimeFromUnixTimestampFloat(resp.Data[x][0])
if err != nil {
return res, errors.New("zb cannot parse Kline.OpenTime")
return res, err
}
res.Data = append(res.Data, &KLineResponseData{
ID: k[0].(float64),
KlineTime: ot,
Open: k[1].(float64),
High: k[2].(float64),
Low: k[3].(float64),
Close: k[4].(float64),
Volume: k[5].(float64),
Open: resp.Data[x][1],
High: resp.Data[x][2],
Low: resp.Data[x][3],
Close: resp.Data[x][4],
Volume: resp.Data[x][5],
})
}
return res, nil
}
@@ -325,7 +325,7 @@ func (z *ZB) SendAuthenticatedHTTPRequest(ctx context.Context, ep exchange.URL,
var intermediary json.RawMessage
newRequest := func() (*request.Item, error) {
now := time.Now()
params.Set("reqTime", fmt.Sprintf("%d", convert.UnixMillis(now)))
params.Set("reqTime", strconv.FormatInt(now.UnixMilli(), 10))
params.Set("sign", fmt.Sprintf("%x", hmac))
urlPath := fmt.Sprintf("%s/%s?%s",

View File

@@ -1,4 +1,5 @@
//+build !mock_test_off
//go:build !mock_test_off
// +build !mock_test_off
// This will build if build tag mock_test_off is not parsed and will try to mock
// all tests in _test.go

View File

@@ -12,7 +12,6 @@ import (
"github.com/gorilla/websocket"
"github.com/thrasher-corp/gocryptotrader/common"
"github.com/thrasher-corp/gocryptotrader/common/convert"
"github.com/thrasher-corp/gocryptotrader/core"
"github.com/thrasher-corp/gocryptotrader/currency"
exchange "github.com/thrasher-corp/gocryptotrader/exchanges"
@@ -35,6 +34,7 @@ var z ZB
var wsSetupRan bool
func setupWsAuth(t *testing.T) {
t.Helper()
if wsSetupRan {
return
}
@@ -500,8 +500,7 @@ func TestWsTransferFunds(t *testing.T) {
// TestGetSubUserList ws test
func TestGetSubUserList(t *testing.T) {
setupWsAuth(t)
_, err := z.wsGetSubUserList()
if err != nil {
if _, err := z.wsGetSubUserList(); err != nil {
t.Fatal(err)
}
}
@@ -833,7 +832,7 @@ func TestGetSpotKline(t *testing.T) {
}
if mockTests {
startTime := time.Date(2020, 9, 1, 0, 0, 0, 0, time.UTC)
arg.Since = convert.UnixMillis(startTime)
arg.Since = startTime.UnixMilli()
arg.Type = "1day"
}

View File

@@ -120,7 +120,6 @@ type KlinesRequestParams struct {
// KLineResponseData Kline Data
type KLineResponseData struct {
ID float64 `json:"id"` // K线ID
KlineTime time.Time `json:"klineTime"`
Open float64 `json:"open"` // 开盘价
Close float64 `json:"close"` // 收盘价, 当K线为最晚的一根时, 时最新成交价

View File

@@ -109,7 +109,7 @@ func (z *ZB) wsHandleData(respRaw []byte) error {
Last: wsTicker.Data.Last,
Bid: wsTicker.Data.Buy,
Ask: wsTicker.Data.Sell,
LastUpdated: time.Unix(0, wsTicker.Date*int64(time.Millisecond)),
LastUpdated: time.UnixMilli(wsTicker.Date),
AssetType: asset.Spot,
Pair: p,
}

View File

@@ -11,7 +11,6 @@ import (
"time"
"github.com/thrasher-corp/gocryptotrader/common"
"github.com/thrasher-corp/gocryptotrader/common/convert"
"github.com/thrasher-corp/gocryptotrader/config"
"github.com/thrasher-corp/gocryptotrader/currency"
exchange "github.com/thrasher-corp/gocryptotrader/exchanges"
@@ -283,8 +282,7 @@ func (z *ZB) UpdateTickers(ctx context.Context, a asset.Item) error {
// UpdateTicker updates and returns the ticker for a currency pair
func (z *ZB) UpdateTicker(ctx context.Context, p currency.Pair, a asset.Item) (*ticker.Price, error) {
err := z.UpdateTickers(ctx, a)
if err != nil {
if err := z.UpdateTickers(ctx, a); err != nil {
return nil, err
}
return ticker.GetTicker(z.Name, p, a)
@@ -389,8 +387,7 @@ func (z *ZB) UpdateAccountInfo(ctx context.Context, assetType asset.Item) (accou
Currencies: balances,
})
err := account.Process(&info)
if err != nil {
if err := account.Process(&info); err != nil {
return account.Holdings{}, err
}
@@ -864,7 +861,7 @@ func (z *ZB) GetHistoricCandles(ctx context.Context, p currency.Pair, a asset.It
klineParams := KlinesRequestParams{
Type: z.FormatExchangeKlineInterval(interval),
Symbol: p.String(),
Since: convert.UnixMillis(start),
Since: start.UnixMilli(),
Size: int64(z.Features.Enabled.Kline.ResultLimit),
}
var candles KLineResponse
@@ -909,7 +906,7 @@ allKlines:
klineParams := KlinesRequestParams{
Type: z.FormatExchangeKlineInterval(interval),
Symbol: p.String(),
Since: convert.UnixMillis(startTime),
Since: startTime.UnixMilli(),
Size: int64(z.Features.Enabled.Kline.ResultLimit),
}