exchanges: Refactor time handling and other minor improvements (#1948)

* exchanges: Refactor time handling and other minor improvements

- Updated Kraken wrapper to utilise new time handling methods.
- Simplified Kucoin types by removing unnecessary structures and using direct JSON unmarshalling.
- Improved websocket handling in Kucoin to directly parse candlestick data.
- Modified Lbank types to use the new time representation.
- Adjusted Poloniex wrapper and types to utilise the new time handling.
- Updated Yobit types and wrapper to reflect changes in time representation.
- Introduced DateTime type for better handling of specific time formats.
- Added tests for DateTime unmarshalling to ensure correctness.
- Rid UTC().Unix and UTC().UnixMilli as it's not needed
- Correct Huobi timestamp usage for some endpoints.
- Rid RFC3339 time parsing since Go does that automatically.

* exchanges: Refactor JSON unmarshalling for various types and improve test coverage

* linter: Update error message in TestGetKlines

* refactor: Simplify JSON unmarshalling in MovementHistory and improve test assertions in GetKlines

* refactor: Improve JSON unmarshalling for channel name and clarify comment in wsProcessOpenOrders

* refactor: Update time handling in Huobi types to use types.Time for createdAt fields and relax GetLiquidationOrders test

* refactor: Move wsTicker, wsSpread, wsTrades, and wsCandle types to kraken_types.go for better organistion

* refactor: Add validation for underlying parameter in GetExpirationTime and update tests
This commit is contained in:
Adrian Gallagher
2025-07-01 09:11:55 +10:00
committed by GitHub
parent 48a66c9faa
commit 3cc9a2b9e0
92 changed files with 2488 additions and 3276 deletions

View File

@@ -94,32 +94,6 @@ func (a *Alphapoint) GetTrades(ctx context.Context, currencyPair string, startIn
return response, nil
}
// GetTradesByDate gets trades by date
// CurrencyPair - instrument code (ex: “BTCUSD”)
// StartDate - specifies the starting time in epoch time, type is long
// EndDate - specifies the end time in epoch time, type is long
func (a *Alphapoint) GetTradesByDate(ctx context.Context, currencyPair string, startDate, endDate int64) (Trades, error) {
req := make(map[string]any)
req["ins"] = currencyPair
req["startDate"] = startDate
req["endDate"] = endDate
response := Trades{}
err := a.SendHTTPRequest(ctx,
exchange.RestSpot,
http.MethodPost,
alphapointTradesByDate,
req,
&response)
if err != nil {
return response, err
}
if !response.IsAccepted {
return response, errors.New(response.RejectReason)
}
return response, nil
}
// GetOrderbook fetches the current orderbook for a given currency pair
// CurrencyPair - trade pair (ex: “BTCUSD”)
func (a *Alphapoint) GetOrderbook(ctx context.Context, currencyPair string) (Orderbook, error) {

View File

@@ -108,52 +108,6 @@ func TestGetTrades(t *testing.T) {
}
}
func TestGetTradesByDate(t *testing.T) {
t.Parallel()
var trades Trades
var err error
if onlineTest {
trades, err = a.GetTradesByDate(t.Context(),
"BTCUSD", 1414799400, 1414800000)
if err != nil {
t.Errorf("Init error: %s", err)
}
_, err = a.GetTradesByDate(t.Context(),
"wigwham", 1414799400, 1414800000)
if err == nil {
t.Error("GetTradesByDate Expected error")
}
} else {
mockResp := []byte(
string(`{"isAccepted":true,"dateTimeUtc":635504540880633671,"ins":"BTCUSD","startDate":1414799400,"endDate":1414800000,"trades":[{"tid":11505,"px":334.669,"qty":0.1211,"unixtime":1414799403,"utcticks":635503962032459843,"incomingOrderSide":1,"incomingServerOrderId":5185651,"bookServerOrderId":5162440},{"tid":11506,"px":334.669,"qty":0.1211,"unixtime":1414799405,"utcticks":635503962058446171,"incomingOrderSide":1,"incomingServerOrderId":5186245,"bookServerOrderId":5162440},{"tid":11507,"px":336.498,"qty":0.011,"unixtime":1414799407,"utcticks":635503962072967656,"incomingOrderSide":0,"incomingServerOrderId":5186530,"bookServerOrderId":5178944},{"tid":11508,"px":335.948,"qty":0.011,"unixtime":1414799410,"utcticks":635503962108055546,"incomingOrderSide":0,"incomingServerOrderId":5187260,"bookServerOrderId":5186531}]}`),
)
err = json.Unmarshal(mockResp, &trades)
if err != nil {
t.Fatal("GetTradesByDate unmarshalling error: ", err)
}
}
if trades.DateTimeUTC < 0 {
t.Error("Alphapoint trades.Count value is negative")
}
if trades.EndDate < 0 {
t.Error("Alphapoint trades.DateTimeUTC value is negative")
}
if trades.Instrument != "BTCUSD" {
t.Error("Alphapoint trades.Instrument value is incorrect")
}
if !trades.IsAccepted {
t.Error("Alphapoint trades.IsAccepted value is true")
}
if trades.RejectReason != "" {
t.Error("Alphapoint trades.IsAccepted value has been returned")
}
if trades.StartDate < 0 {
t.Error("Alphapoint trades.StartIndex value is negative")
}
}
func TestGetOrderbook(t *testing.T) {
t.Parallel()
var orderBook Orderbook

View File

@@ -2,18 +2,19 @@ package alphapoint
import (
"github.com/thrasher-corp/gocryptotrader/exchanges/order"
"github.com/thrasher-corp/gocryptotrader/types"
)
// Response contains general responses from the exchange
type Response struct {
IsAccepted bool `json:"isAccepted"`
RejectReason string `json:"rejectReason"`
Fee float64 `json:"fee"`
FeeProduct string `json:"feeProduct"`
CancelOrderID int64 `json:"cancelOrderId"`
ServerOrderID int64 `json:"serverOrderId"`
DateTimeUTC float64 `json:"dateTimeUtc"`
ModifyOrderID int64 `json:"modifyOrderId"`
IsAccepted bool `json:"isAccepted"`
RejectReason string `json:"rejectReason"`
Fee float64 `json:"fee"`
FeeProduct string `json:"feeProduct"`
CancelOrderID int64 `json:"cancelOrderId"`
ServerOrderID int64 `json:"serverOrderId"`
DateTimeUTC types.Time `json:"dateTimeUtc"`
ModifyOrderID int64 `json:"modifyOrderId"`
Addresses []DepositAddresses
}
@@ -36,15 +37,15 @@ type Ticker struct {
// Trades holds trade information
type Trades struct {
IsAccepted bool `json:"isAccepted"`
RejectReason string `json:"rejectReason"`
DateTimeUTC int64 `json:"dateTimeUtc"`
Instrument string `json:"ins"`
StartIndex int `json:"startIndex"`
Count int `json:"count"`
StartDate int64 `json:"startDate"`
EndDate int64 `json:"endDate"`
Trades []Trade `json:"trades"`
IsAccepted bool `json:"isAccepted"`
RejectReason string `json:"rejectReason"`
DateTimeUTC types.Time `json:"dateTimeUtc"`
Instrument string `json:"ins"`
StartIndex int `json:"startIndex"`
Count int `json:"count"`
StartDate int64 `json:"startDate"`
EndDate int64 `json:"endDate"`
Trades []Trade `json:"trades"`
}
// Trade is a sub-type which holds the singular trade that occurred in the past
@@ -148,15 +149,15 @@ type AccountInfo struct {
// Order is a generalised order type
type Order struct {
ServerOrderID int `json:"ServerOrderId"`
AccountID int `json:"AccountId"`
Price float64 `json:"Price"`
QtyTotal float64 `json:"QtyTotal"`
QtyRemaining float64 `json:"QtyRemaining"`
ReceiveTime int64 `json:"ReceiveTime"`
Side int64 `json:"Side"`
State int `json:"orderState"`
OrderType int `json:"orderType"`
ServerOrderID int `json:"ServerOrderId"`
AccountID int `json:"AccountId"`
Price float64 `json:"Price"`
QtyTotal float64 `json:"QtyTotal"`
QtyRemaining float64 `json:"QtyRemaining"`
ReceiveTime types.Time `json:"ReceiveTime"`
Side int64 `json:"Side"`
State int `json:"orderState"`
OrderType int `json:"orderType"`
}
// OpenOrders holds the full range of orders by instrument
@@ -169,7 +170,7 @@ type OpenOrders struct {
type OrderInfo struct {
OpenOrders []OpenOrders `json:"openOrdersInfo"`
IsAccepted bool `json:"isAccepted"`
DateTimeUTC int64 `json:"dateTimeUtc"`
DateTimeUTC types.Time `json:"dateTimeUtc"`
RejectReason string `json:"rejectReason"`
}

View File

@@ -357,8 +357,7 @@ func (a *Alphapoint) GetActiveOrders(ctx context.Context, req *order.MultiOrderR
if resp[x].OpenOrders[y].State != 1 {
continue
}
orderDetail := order.Detail{
orders = append(orders, order.Detail{
Amount: resp[x].OpenOrders[y].QtyTotal,
Exchange: a.Name,
ExecutedAmount: resp[x].OpenOrders[y].QtyTotal - resp[x].OpenOrders[y].QtyRemaining,
@@ -366,12 +365,10 @@ func (a *Alphapoint) GetActiveOrders(ctx context.Context, req *order.MultiOrderR
OrderID: strconv.FormatInt(int64(resp[x].OpenOrders[y].ServerOrderID), 10),
Price: resp[x].OpenOrders[y].Price,
RemainingAmount: resp[x].OpenOrders[y].QtyRemaining,
}
orderDetail.Side = orderSideMap[resp[x].OpenOrders[y].Side]
orderDetail.Date = time.Unix(resp[x].OpenOrders[y].ReceiveTime, 0)
orderDetail.Type = orderTypeMap[resp[x].OpenOrders[y].OrderType]
orders = append(orders, orderDetail)
Side: orderSideMap[resp[x].OpenOrders[y].Side],
Date: resp[x].OpenOrders[y].ReceiveTime.Time(),
Type: orderTypeMap[resp[x].OpenOrders[y].OrderType],
})
}
}
return req.Filter(a.Name, orders), nil
@@ -398,7 +395,7 @@ func (a *Alphapoint) GetOrderHistory(ctx context.Context, req *order.MultiOrderR
continue
}
orderDetail := order.Detail{
orders = append(orders, order.Detail{
Amount: resp[x].OpenOrders[y].QtyTotal,
AccountID: strconv.FormatInt(int64(resp[x].OpenOrders[y].AccountID), 10),
Exchange: a.Name,
@@ -406,12 +403,10 @@ func (a *Alphapoint) GetOrderHistory(ctx context.Context, req *order.MultiOrderR
OrderID: strconv.FormatInt(int64(resp[x].OpenOrders[y].ServerOrderID), 10),
Price: resp[x].OpenOrders[y].Price,
RemainingAmount: resp[x].OpenOrders[y].QtyRemaining,
}
orderDetail.Side = orderSideMap[resp[x].OpenOrders[y].Side]
orderDetail.Date = time.Unix(resp[x].OpenOrders[y].ReceiveTime, 0)
orderDetail.Type = orderTypeMap[resp[x].OpenOrders[y].OrderType]
orders = append(orders, orderDetail)
Side: orderSideMap[resp[x].OpenOrders[y].Side],
Date: resp[x].OpenOrders[y].ReceiveTime.Time(),
Type: orderTypeMap[resp[x].OpenOrders[y].OrderType],
})
}
}
return req.Filter(a.Name, orders), nil