types: Add Time type from Gateio and share across codebase (#1648)

* consolidate type to types package and share across code base

* rm convert type and convert codebase

* rm irrelavant test cases

* Fix tests

* glorious nits

* Update exchanges/gateio/gateio_types.go

Co-authored-by: Adrian Gallagher <adrian.gallagher@thrasher.io>

* thrasher: nits

---------

Co-authored-by: Ryan O'Hara-Reid <ryan.oharareid@thrasher.io>
Co-authored-by: Adrian Gallagher <adrian.gallagher@thrasher.io>
This commit is contained in:
Ryan O'Hara-Reid
2024-10-01 10:46:55 +10:00
committed by GitHub
parent bfd499f0c9
commit d31fa3ff3d
29 changed files with 2633 additions and 2894 deletions

View File

@@ -1,7 +1,6 @@
package convert
import (
"encoding/json"
"fmt"
"math"
"strconv"
@@ -187,56 +186,3 @@ func InterfaceToStringOrZeroValue(r interface{}) string {
}
return ""
}
// ExchangeTime provides timestamp to time conversion method.
type ExchangeTime time.Time
// UnmarshalJSON is custom type json unmarshaller for ExchangeTime
func (k *ExchangeTime) UnmarshalJSON(data []byte) error {
var timestamp interface{}
err := json.Unmarshal(data, &timestamp)
if err != nil {
return err
}
var standard int64
switch value := timestamp.(type) {
case string:
if value == "" {
// Setting the time to zero value because some timestamp fields could return an empty string while there is no error
// So, in such cases, Time returns zero timestamp.
break
}
standard, err = strconv.ParseInt(value, 10, 64)
if err != nil {
return err
}
case int64:
standard = value
case float64:
// Warning: converting float64 to int64 instance may create loss of precision in the timestamp information.
// be aware or consider customizing this section if found necessary.
standard = int64(value)
case nil:
// for some exchange timestamp fields, if the timestamp information is not specified,
// the data is 'nil' instead of zero value string or integer value.
default:
return fmt.Errorf("unsupported timestamp type %T", timestamp)
}
switch {
case standard == 0:
*k = ExchangeTime(time.Time{})
case standard >= 1e13:
*k = ExchangeTime(time.Unix(standard/1e9, standard%1e9))
case standard > 9999999999:
*k = ExchangeTime(time.UnixMilli(standard))
default:
*k = ExchangeTime(time.Unix(standard, 0))
}
return nil
}
// Time returns a time.Time instance from ExchangeTime instance object.
func (k ExchangeTime) Time() time.Time {
return time.Time(k)
}

View File

@@ -1,7 +1,6 @@
package convert
import (
"encoding/json"
"strings"
"testing"
"time"
@@ -316,86 +315,3 @@ func TestInterfaceToStringOrZeroValue(t *testing.T) {
t.Errorf("expected meow, got: %v", x)
}
}
func TestExchangeTimeUnmarshalJSON(t *testing.T) {
t.Parallel()
unmarshaledResult := &struct {
Timestamp ExchangeTime `json:"ts"`
}{}
data1 := `{"ts":""}`
result := time.Time{}
err := json.Unmarshal([]byte(data1), &unmarshaledResult)
if err != nil {
t.Fatal(err)
} else if !unmarshaledResult.Timestamp.Time().Equal(result) {
t.Errorf("found %v, but expected %v", unmarshaledResult.Timestamp.Time(), result)
}
data2 := `{"ts":"1685564775371"}`
result = time.UnixMilli(1685564775371)
err = json.Unmarshal([]byte(data2), &unmarshaledResult)
if err != nil {
t.Fatal(err)
} else if !unmarshaledResult.Timestamp.Time().Equal(result) {
t.Errorf("found %v, but expected %v", unmarshaledResult.Timestamp.Time(), result)
}
data3 := `{"ts":1685564775371}`
err = json.Unmarshal([]byte(data3), &unmarshaledResult)
if err != nil {
t.Fatal(err)
} else if !unmarshaledResult.Timestamp.Time().Equal(result) {
t.Errorf("found %v, but expected %v", unmarshaledResult.Timestamp.Time(), result)
}
data4 := `{"ts":"1685564775"}`
result = time.Unix(1685564775, 0)
err = json.Unmarshal([]byte(data4), &unmarshaledResult)
if err != nil {
t.Fatal(err)
} else if !unmarshaledResult.Timestamp.Time().Equal(result) {
t.Errorf("found %v, but expected %v", unmarshaledResult.Timestamp.Time(), result)
}
data5 := `{"ts":1685564775}`
err = json.Unmarshal([]byte(data5), &unmarshaledResult)
if err != nil {
t.Fatal(err)
} else if !unmarshaledResult.Timestamp.Time().Equal(result) {
t.Errorf("found %v, but expected %v", unmarshaledResult.Timestamp.Time(), result)
}
data6 := `{"ts":"1685564775371320000"}`
result = time.Unix(int64(1685564775371320000)/1e9, int64(1685564775371320000)%1e9)
err = json.Unmarshal([]byte(data6), &unmarshaledResult)
if err != nil {
t.Fatal(err)
} else if !unmarshaledResult.Timestamp.Time().Equal(result) {
t.Errorf("found %v, but expected %v", unmarshaledResult.Timestamp.Time(), result)
}
data7 := `{"ts":"abcdefg"}`
err = json.Unmarshal([]byte(data7), &unmarshaledResult)
if err == nil {
t.Fatal("expecting error but found nil")
}
data8 := `{"ts":0}`
result = time.Time{}
err = json.Unmarshal([]byte(data8), &unmarshaledResult)
if err != nil {
t.Fatal(err)
} else if !unmarshaledResult.Timestamp.Time().Equal(result) {
t.Errorf("found %v, but expected %v", unmarshaledResult.Timestamp.Time(), result)
}
}
// 2239239 516.1 ns/op 424 B/op 9 allocs/op
func BenchmarkExchangeTimeUnmarshaling(b *testing.B) {
unmarshaledResult := &struct {
Timestamp ExchangeTime `json:"ts"`
}{}
data5 := `{"ts":1685564775}`
result := time.Unix(1685564775, 0)
var err error
for i := 0; i < b.N; i++ {
if err = json.Unmarshal([]byte(data5), &unmarshaledResult); err != nil {
b.Fatal(err)
} else if !unmarshaledResult.Timestamp.Time().Equal(result) {
b.Fatalf("found %v, but expected %v", unmarshaledResult.Timestamp.Time(), result)
}
}
}

View File

@@ -2028,11 +2028,11 @@ func TestWsKlineUpdate(t *testing.T) {
t.Parallel()
pressXToJSON := []byte(`{"stream":"btcusdt@kline_1m","data":{
"e": "kline",
"E": 123456789,
"E": 1234567891,
"s": "BTCUSDT",
"k": {
"t": 123400000,
"T": 123460000,
"t": 1234000001,
"T": 1234600001,
"s": "BTCUSDT",
"i": "1m",
"f": 100,
@@ -2061,14 +2061,14 @@ func TestWsTradeUpdate(t *testing.T) {
b.SetSaveTradeDataStatus(true)
pressXToJSON := []byte(`{"stream":"btcusdt@trade","data":{
"e": "trade",
"E": 123456789,
"E": 1234567891,
"s": "BTCUSDT",
"t": 12345,
"p": "0.001",
"q": "100",
"b": 88,
"a": 50,
"T": 123456785,
"T": 1234567851,
"m": true,
"M": true
}}`)
@@ -2114,7 +2114,7 @@ func TestWsDepthUpdate(t *testing.T) {
update1 := []byte(`{"stream":"btcusdt@depth","data":{
"e": "depthUpdate",
"E": 123456788,
"E": 1234567881,
"s": "BTCUSDT",
"U": 157,
"u": 160,
@@ -2132,7 +2132,7 @@ func TestWsDepthUpdate(t *testing.T) {
}
if err := b.wsHandleData(update1); err != nil {
t.Error(err)
t.Fatal(err)
}
b.obm.state[currency.BTC][currency.USDT][asset.Spot].fetchingBook = false
@@ -2154,7 +2154,7 @@ func TestWsDepthUpdate(t *testing.T) {
update2 := []byte(`{"stream":"btcusdt@depth","data":{
"e": "depthUpdate",
"E": 123456789,
"E": 1234567892,
"s": "BTCUSDT",
"U": 161,
"u": 165,

View File

@@ -723,18 +723,18 @@ type WithdrawResponse struct {
// WithdrawStatusResponse defines a withdrawal status response
type WithdrawStatusResponse struct {
Address string `json:"address"`
Amount float64 `json:"amount,string"`
ApplyTime binanceTime `json:"applyTime"`
Coin string `json:"coin"`
ID string `json:"id"`
WithdrawOrderID string `json:"withdrawOrderId"`
Network string `json:"network"`
TransferType uint8 `json:"transferType"`
Status int64 `json:"status"`
TransactionFee float64 `json:"transactionFee,string"`
TransactionID string `json:"txId"`
ConfirmNumber int64 `json:"confirmNo"`
Address string `json:"address"`
Amount float64 `json:"amount,string"`
ApplyTime types.Time `json:"applyTime"`
Coin string `json:"coin"`
ID string `json:"id"`
WithdrawOrderID string `json:"withdrawOrderId"`
Network string `json:"network"`
TransferType uint8 `json:"transferType"`
Status int64 `json:"status"`
TransactionFee float64 `json:"transactionFee,string"`
TransactionID string `json:"txId"`
ConfirmNumber int64 `json:"confirmNo"`
}
// DepositAddress stores the deposit address info
@@ -921,15 +921,15 @@ type UserMarginInterestHistoryResponse struct {
// UserMarginInterestHistory user margin interest history row
type UserMarginInterestHistory struct {
TxID int64 `json:"txId"`
InterestAccruedTime binanceTime `json:"interestAccuredTime"` // typo in docs, cannot verify due to API restrictions
Asset string `json:"asset"`
RawAsset string `json:"rawAsset"`
Principal float64 `json:"principal,string"`
Interest float64 `json:"interest,string"`
InterestRate float64 `json:"interestRate,string"`
Type string `json:"type"`
IsolatedSymbol string `json:"isolatedSymbol"`
TxID int64 `json:"txId"`
InterestAccruedTime types.Time `json:"interestAccuredTime"` // typo in docs, cannot verify due to API restrictions
Asset string `json:"asset"`
RawAsset string `json:"rawAsset"`
Principal float64 `json:"principal,string"`
Interest float64 `json:"interest,string"`
InterestRate float64 `json:"interestRate,string"`
Type string `json:"type"`
IsolatedSymbol string `json:"isolatedSymbol"`
}
// CryptoLoansIncomeHistory stores crypto loan income history data
@@ -959,7 +959,7 @@ type LoanBorrowHistoryItem struct {
LoanTerm int64 `json:"loanTerm,string"`
CollateralCoin currency.Code `json:"collateralCoin"`
InitialCollateralAmount float64 `json:"initialCollateralAmount,string"`
BorrowTime binanceTime `json:"borrowTime"`
BorrowTime types.Time `json:"borrowTime"`
Status string `json:"status"`
}
@@ -978,7 +978,7 @@ type CryptoLoanOngoingOrderItem struct {
CollateralCoin currency.Code `json:"collateralCoin"`
CollateralAmount float64 `json:"collateralAmount,string"`
CurrentLTV float64 `json:"currentLTV,string"`
ExpirationTime binanceTime `json:"expirationTime"`
ExpirationTime types.Time `json:"expirationTime"`
}
// CryptoLoanOngoingOrder stores crypto loan ongoing order data
@@ -1006,7 +1006,7 @@ type CryptoLoanRepayHistoryItem struct {
CollateralUsed float64 `json:"collateralUsed,string"`
CollateralReturn float64 `json:"collateralReturn,string"`
RepayType string `json:"repayType"`
RepayTime binanceTime `json:"repayTime"`
RepayTime types.Time `json:"repayTime"`
OrderID int64 `json:"orderId"`
}
@@ -1033,7 +1033,7 @@ type CryptoLoanLTVAdjustmentItem struct {
Amount float64 `json:"amount,string"`
PreviousLTV float64 `json:"preLTV,string"`
AfterLTV float64 `json:"afterLTV,string"`
AdjustTime binanceTime `json:"adjustTime"`
AdjustTime types.Time `json:"adjustTime"`
OrderID int64 `json:"orderId"`
}
@@ -1097,7 +1097,7 @@ type CustomiseMarginCallItem struct {
CollateralCoin currency.Code `json:"collateralCoin"`
PreMarginCall float64 `json:"preMarginCall,string"`
AfterMarginCall float64 `json:"afterMarginCall,string"`
CustomiseTime binanceTime `json:"customizeTime"`
CustomiseTime types.Time `json:"customizeTime"`
}
// CustomiseMarginCall stores customise margin call data
@@ -1136,7 +1136,7 @@ type FlexibleLoanBorrowHistoryItem struct {
InitialLoanAmount float64 `json:"initialLoanAmount,string"`
CollateralCoin currency.Code `json:"collateralCoin"`
InitialCollateralAmount float64 `json:"initialCollateralAmount,string"`
BorrowTime binanceTime `json:"borrowTime"`
BorrowTime types.Time `json:"borrowTime"`
Status string `json:"status"`
}
@@ -1164,7 +1164,7 @@ type FlexibleLoanRepayHistoryItem struct {
CollateralCoin currency.Code `json:"collateralCoin"`
CollateralReturn float64 `json:"collateralReturn,string"`
RepayStatus string `json:"repayStatus"`
RepayTime binanceTime `json:"repayTime"`
RepayTime types.Time `json:"repayTime"`
}
// FlexibleLoanRepayHistory stores flexible loan repayment history
@@ -1191,7 +1191,7 @@ type FlexibleLoanLTVAdjustmentHistoryItem struct {
CollateralAmount float64 `json:"collateralAmount,string"`
PreviousLTV float64 `json:"preLTV,string"`
AfterLTV float64 `json:"afterLTV,string"`
AdjustTime binanceTime `json:"adjustTime"`
AdjustTime types.Time `json:"adjustTime"`
}
// FlexibleLoanLTVAdjustmentHistory stores flexible loan LTV adjustment history

View File

@@ -5,6 +5,7 @@ import (
"github.com/thrasher-corp/gocryptotrader/currency"
"github.com/thrasher-corp/gocryptotrader/exchanges/order"
"github.com/thrasher-corp/gocryptotrader/types"
)
// Response holds basic binance api response data
@@ -15,32 +16,32 @@ type Response struct {
// FuturesPublicTradesData stores recent public trades for futures
type FuturesPublicTradesData struct {
ID int64 `json:"id"`
Price float64 `json:"price,string"`
Qty float64 `json:"qty,string"`
QuoteQty float64 `json:"quoteQty,string"`
Time binanceTime `json:"time"`
IsBuyerMaker bool `json:"isBuyerMaker"`
ID int64 `json:"id"`
Price float64 `json:"price,string"`
Qty float64 `json:"qty,string"`
QuoteQty float64 `json:"quoteQty,string"`
Time types.Time `json:"time"`
IsBuyerMaker bool `json:"isBuyerMaker"`
}
// CompressedTradesData stores futures trades data in a compressed format
type CompressedTradesData struct {
TradeID int64 `json:"a"`
Price float64 `json:"p"`
Quantity float64 `json:"q"`
FirstTradeID int64 `json:"f"`
LastTradeID int64 `json:"l"`
Timestamp binanceTime `json:"t"`
BuyerMaker bool `json:"b"`
TradeID int64 `json:"a"`
Price float64 `json:"p"`
Quantity float64 `json:"q"`
FirstTradeID int64 `json:"f"`
LastTradeID int64 `json:"l"`
Timestamp types.Time `json:"t"`
BuyerMaker bool `json:"b"`
}
// MarkPriceData stores mark price data for futures
type MarkPriceData struct {
Symbol string `json:"symbol"`
MarkPrice float64 `json:"markPrice"`
LastFundingRate float64 `json:"lastFundingRate"`
NextFundingTime int64 `json:"nextFundingTime"`
Time binanceTime `json:"time"`
Symbol string `json:"symbol"`
MarkPrice float64 `json:"markPrice"`
LastFundingRate float64 `json:"lastFundingRate"`
NextFundingTime int64 `json:"nextFundingTime"`
Time types.Time `json:"time"`
}
// SymbolPriceTicker stores ticker price stats
@@ -445,21 +446,21 @@ type GetPositionMarginChangeHistoryData struct {
// FuturesPositionInformation stores futures position info
type FuturesPositionInformation struct {
Symbol string `json:"symbol"`
PositionAmount float64 `json:"positionAmt,string"`
EntryPrice float64 `json:"entryPrice,string"`
MarkPrice float64 `json:"markPrice,string"`
UnRealizedProfit float64 `json:"unRealizedProfit,string"`
LiquidationPrice float64 `json:"liquidationPrice,string"`
Leverage float64 `json:"leverage,string"`
MaxQty float64 `json:"maxQty,string"`
MarginType string `json:"marginType"`
IsolatedMargin float64 `json:"isolatedMargin,string"`
IsAutoAddMargin bool `json:"isAutoAddMargin,string"`
PositionSide string `json:"positionSide"`
NotionalValue float64 `json:"notionalValue,string"`
IsolatedWallet float64 `json:"isolatedWallet,string"`
UpdateTime binanceTime `json:"updateTime"`
Symbol string `json:"symbol"`
PositionAmount float64 `json:"positionAmt,string"`
EntryPrice float64 `json:"entryPrice,string"`
MarkPrice float64 `json:"markPrice,string"`
UnRealizedProfit float64 `json:"unRealizedProfit,string"`
LiquidationPrice float64 `json:"liquidationPrice,string"`
Leverage float64 `json:"leverage,string"`
MaxQty float64 `json:"maxQty,string"`
MarginType string `json:"marginType"`
IsolatedMargin float64 `json:"isolatedMargin,string"`
IsAutoAddMargin bool `json:"isAutoAddMargin,string"`
PositionSide string `json:"positionSide"`
NotionalValue float64 `json:"notionalValue,string"`
IsolatedWallet float64 `json:"isolatedWallet,string"`
UpdateTime types.Time `json:"updateTime"`
}
// FuturesAccountTradeList stores account trade list data
@@ -581,25 +582,25 @@ type UFuturesExchangeInfo struct {
// UFuturesSymbolInfo contains details of a currency symbol
// for a usdt margined future contract
type UFuturesSymbolInfo struct {
Symbol string `json:"symbol"`
Pair string `json:"pair"`
ContractType string `json:"contractType"`
DeliveryDate binanceTime `json:"deliveryDate"`
OnboardDate binanceTime `json:"onboardDate"`
Status string `json:"status"`
MaintenanceMarginPercent float64 `json:"maintMarginPercent,string"`
RequiredMarginPercent float64 `json:"requiredMarginPercent,string"`
BaseAsset string `json:"baseAsset"`
QuoteAsset string `json:"quoteAsset"`
MarginAsset string `json:"marginAsset"`
PricePrecision int64 `json:"pricePrecision"`
QuantityPrecision int64 `json:"quantityPrecision"`
BaseAssetPrecision int64 `json:"baseAssetPrecision"`
QuotePrecision int64 `json:"quotePrecision"`
UnderlyingType string `json:"underlyingType"`
UnderlyingSubType []string `json:"underlyingSubType"`
SettlePlan float64 `json:"settlePlan"`
TriggerProtect float64 `json:"triggerProtect,string"`
Symbol string `json:"symbol"`
Pair string `json:"pair"`
ContractType string `json:"contractType"`
DeliveryDate types.Time `json:"deliveryDate"`
OnboardDate types.Time `json:"onboardDate"`
Status string `json:"status"`
MaintenanceMarginPercent float64 `json:"maintMarginPercent,string"`
RequiredMarginPercent float64 `json:"requiredMarginPercent,string"`
BaseAsset string `json:"baseAsset"`
QuoteAsset string `json:"quoteAsset"`
MarginAsset string `json:"marginAsset"`
PricePrecision int64 `json:"pricePrecision"`
QuantityPrecision int64 `json:"quantityPrecision"`
BaseAssetPrecision int64 `json:"baseAssetPrecision"`
QuotePrecision int64 `json:"quotePrecision"`
UnderlyingType string `json:"underlyingType"`
UnderlyingSubType []string `json:"underlyingSubType"`
SettlePlan float64 `json:"settlePlan"`
TriggerProtect float64 `json:"triggerProtect,string"`
Filters []struct {
FilterType string `json:"filterType"`
MinPrice float64 `json:"minPrice,string"`
@@ -644,24 +645,24 @@ type CExchangeInfo struct {
MultiplierUp float64 `json:"multiplierUp,string"`
MultiplierDecimal float64 `json:"multiplierDecimal,string"`
} `json:"filters"`
OrderTypes []string `json:"orderType"`
TimeInForce []string `json:"timeInForce"`
Symbol string `json:"symbol"`
Pair string `json:"pair"`
ContractType string `json:"contractType"`
DeliveryDate binanceTime `json:"deliveryDate"`
OnboardDate binanceTime `json:"onboardDate"`
ContractStatus string `json:"contractStatus"`
ContractSize int64 `json:"contractSize"`
QuoteAsset string `json:"quoteAsset"`
BaseAsset string `json:"baseAsset"`
MarginAsset string `json:"marginAsset"`
PricePrecision int64 `json:"pricePrecision"`
QuantityPrecision int64 `json:"quantityPrecision"`
BaseAssetPrecision int64 `json:"baseAssetPrecision"`
QuotePrecision int64 `json:"quotePrecision"`
MaintMarginPercent float64 `json:"maintMarginPercent,string"`
RequiredMarginPercent float64 `json:"requiredMarginPercent,string"`
OrderTypes []string `json:"orderType"`
TimeInForce []string `json:"timeInForce"`
Symbol string `json:"symbol"`
Pair string `json:"pair"`
ContractType string `json:"contractType"`
DeliveryDate types.Time `json:"deliveryDate"`
OnboardDate types.Time `json:"onboardDate"`
ContractStatus string `json:"contractStatus"`
ContractSize int64 `json:"contractSize"`
QuoteAsset string `json:"quoteAsset"`
BaseAsset string `json:"baseAsset"`
MarginAsset string `json:"marginAsset"`
PricePrecision int64 `json:"pricePrecision"`
QuantityPrecision int64 `json:"quantityPrecision"`
BaseAssetPrecision int64 `json:"baseAssetPrecision"`
QuotePrecision int64 `json:"quotePrecision"`
MaintMarginPercent float64 `json:"maintMarginPercent,string"`
RequiredMarginPercent float64 `json:"requiredMarginPercent,string"`
} `json:"symbols"`
Timezone string `json:"timezone"`
}

View File

@@ -2,40 +2,12 @@ package binance
import (
"encoding/json"
"errors"
"strconv"
"time"
"github.com/thrasher-corp/gocryptotrader/types"
)
// binanceTime provides an internal conversion helper
type binanceTime time.Time
func (t *binanceTime) UnmarshalJSON(data []byte) error {
var result interface{}
if err := json.Unmarshal(data, &result); err != nil {
return err
}
switch v := result.(type) {
case string:
timestamp, err := strconv.ParseInt(v, 10, 64)
if err != nil {
return err
}
*t = binanceTime(time.UnixMilli(timestamp))
case float64:
*t = binanceTime(time.UnixMilli(int64(v)))
default:
return errors.New("invalid time format received")
}
return nil
}
// Time returns a time.Time object
func (t binanceTime) Time() time.Time {
return time.Time(t)
}
// timeString gets the time as Binance timestamp
func timeString(t time.Time) string {
return strconv.FormatInt(t.UnixMilli(), 10)
@@ -45,7 +17,7 @@ func timeString(t time.Time) string {
func (a *ExchangeInfo) UnmarshalJSON(data []byte) error {
type Alias ExchangeInfo
aux := &struct {
Servertime binanceTime `json:"serverTime"`
Servertime types.Time `json:"serverTime"`
*Alias
}{
Alias: (*Alias)(a),
@@ -61,7 +33,7 @@ func (a *ExchangeInfo) UnmarshalJSON(data []byte) error {
func (a *AggregatedTrade) UnmarshalJSON(data []byte) error {
type Alias AggregatedTrade
aux := &struct {
TimeStamp binanceTime `json:"T"`
TimeStamp types.Time `json:"T"`
*Alias
}{
Alias: (*Alias)(a),
@@ -77,7 +49,7 @@ func (a *AggregatedTrade) UnmarshalJSON(data []byte) error {
func (a *NewOrderResponse) UnmarshalJSON(data []byte) error {
type Alias NewOrderResponse
aux := &struct {
TransactionTime binanceTime `json:"transactTime"`
TransactionTime types.Time `json:"transactTime"`
*Alias
}{
Alias: (*Alias)(a),
@@ -95,8 +67,8 @@ func (a *NewOrderResponse) UnmarshalJSON(data []byte) error {
func (a *TradeStream) UnmarshalJSON(data []byte) error {
type Alias TradeStream
aux := &struct {
TimeStamp binanceTime `json:"T"`
EventTime binanceTime `json:"E"`
TimeStamp types.Time `json:"T"`
EventTime types.Time `json:"E"`
*Alias
}{
Alias: (*Alias)(a),
@@ -113,10 +85,10 @@ func (a *TradeStream) UnmarshalJSON(data []byte) error {
func (a *KlineStream) UnmarshalJSON(data []byte) error {
type Alias KlineStream
aux := &struct {
EventTime binanceTime `json:"E"`
EventTime types.Time `json:"E"`
Kline struct {
StartTime binanceTime `json:"t"`
CloseTime binanceTime `json:"T"`
StartTime types.Time `json:"t"`
CloseTime types.Time `json:"T"`
*KlineStreamData
} `json:"k"`
*Alias
@@ -137,9 +109,9 @@ func (a *KlineStream) UnmarshalJSON(data []byte) error {
func (a *TickerStream) UnmarshalJSON(data []byte) error {
type Alias TickerStream
aux := &struct {
EventTime binanceTime `json:"E"`
OpenTime binanceTime `json:"O"`
CloseTime binanceTime `json:"C"`
EventTime types.Time `json:"E"`
OpenTime types.Time `json:"O"`
CloseTime types.Time `json:"C"`
*Alias
}{
Alias: (*Alias)(a),
@@ -157,8 +129,8 @@ func (a *TickerStream) UnmarshalJSON(data []byte) error {
func (a *PriceChangeStats) UnmarshalJSON(data []byte) error {
type Alias PriceChangeStats
aux := &struct {
OpenTime binanceTime `json:"openTime"`
CloseTime binanceTime `json:"closeTime"`
OpenTime types.Time `json:"openTime"`
CloseTime types.Time `json:"closeTime"`
*Alias
}{
Alias: (*Alias)(a),
@@ -175,7 +147,7 @@ func (a *PriceChangeStats) UnmarshalJSON(data []byte) error {
func (a *RecentTrade) UnmarshalJSON(data []byte) error {
type Alias RecentTrade
aux := &struct {
Time binanceTime `json:"time"`
Time types.Time `json:"time"`
*Alias
}{
Alias: (*Alias)(a),
@@ -191,7 +163,7 @@ func (a *RecentTrade) UnmarshalJSON(data []byte) error {
func (a *HistoricalTrade) UnmarshalJSON(data []byte) error {
type Alias HistoricalTrade
aux := &struct {
Time binanceTime `json:"time"`
Time types.Time `json:"time"`
*Alias
}{
Alias: (*Alias)(a),
@@ -207,8 +179,8 @@ func (a *HistoricalTrade) UnmarshalJSON(data []byte) error {
func (a *QueryOrderData) UnmarshalJSON(data []byte) error {
type Alias QueryOrderData
aux := &struct {
Time binanceTime `json:"time"`
UpdateTime binanceTime `json:"updateTime"`
Time types.Time `json:"time"`
UpdateTime types.Time `json:"updateTime"`
*Alias
}{
Alias: (*Alias)(a),
@@ -225,8 +197,8 @@ func (a *QueryOrderData) UnmarshalJSON(data []byte) error {
func (a *FuturesOrderData) UnmarshalJSON(data []byte) error {
type Alias FuturesOrderData
aux := &struct {
Time binanceTime `json:"time"`
UpdateTime binanceTime `json:"updateTime"`
Time types.Time `json:"time"`
UpdateTime types.Time `json:"updateTime"`
*Alias
}{
Alias: (*Alias)(a),
@@ -243,8 +215,8 @@ func (a *FuturesOrderData) UnmarshalJSON(data []byte) error {
func (a *UFuturesOrderData) UnmarshalJSON(data []byte) error {
type Alias UFuturesOrderData
aux := &struct {
Time binanceTime `json:"time"`
UpdateTime binanceTime `json:"updateTime"`
Time types.Time `json:"time"`
UpdateTime types.Time `json:"updateTime"`
*Alias
}{
Alias: (*Alias)(a),
@@ -261,8 +233,8 @@ func (a *UFuturesOrderData) UnmarshalJSON(data []byte) error {
func (a *FuturesOrderGetData) UnmarshalJSON(data []byte) error {
type Alias FuturesOrderGetData
aux := &struct {
Time binanceTime `json:"time"`
UpdateTime binanceTime `json:"updateTime"`
Time types.Time `json:"time"`
UpdateTime types.Time `json:"updateTime"`
*Alias
}{
Alias: (*Alias)(a),
@@ -279,8 +251,8 @@ func (a *FuturesOrderGetData) UnmarshalJSON(data []byte) error {
func (a *UOrderData) UnmarshalJSON(data []byte) error {
type Alias UOrderData
aux := &struct {
Time binanceTime `json:"time"`
UpdateTime binanceTime `json:"updateTime"`
Time types.Time `json:"time"`
UpdateTime types.Time `json:"updateTime"`
*Alias
}{
Alias: (*Alias)(a),
@@ -297,7 +269,7 @@ func (a *UOrderData) UnmarshalJSON(data []byte) error {
func (a *Account) UnmarshalJSON(data []byte) error {
type Alias Account
aux := &struct {
UpdateTime binanceTime `json:"updateTime"`
UpdateTime types.Time `json:"updateTime"`
*Alias
}{
Alias: (*Alias)(a),
@@ -313,7 +285,7 @@ func (a *Account) UnmarshalJSON(data []byte) error {
func (a *WebsocketDepthStream) UnmarshalJSON(data []byte) error {
type Alias WebsocketDepthStream
aux := &struct {
Timestamp binanceTime `json:"E"`
Timestamp types.Time `json:"E"`
*Alias
}{
Alias: (*Alias)(a),
@@ -330,8 +302,8 @@ func (a *wsAccountPosition) UnmarshalJSON(data []byte) error {
type Alias wsAccountPosition
aux := &struct {
Data struct {
EventTime binanceTime `json:"E"`
LastUpdated binanceTime `json:"u"`
EventTime types.Time `json:"E"`
LastUpdated types.Time `json:"u"`
*WsAccountPositionData
} `json:"data"`
*Alias
@@ -352,8 +324,8 @@ func (a *wsBalanceUpdate) UnmarshalJSON(data []byte) error {
type Alias wsBalanceUpdate
aux := &struct {
Data struct {
EventTime binanceTime `json:"E"`
ClearTime binanceTime `json:"T"`
EventTime types.Time `json:"E"`
ClearTime types.Time `json:"T"`
*WsBalanceUpdateData
} `json:"data"`
*Alias
@@ -374,10 +346,10 @@ func (a *wsOrderUpdate) UnmarshalJSON(data []byte) error {
type Alias wsOrderUpdate
aux := &struct {
Data struct {
EventTime binanceTime `json:"E"`
OrderCreationTime binanceTime `json:"O"`
TransactionTime binanceTime `json:"T"`
WorkingTime binanceTime `json:"W"`
EventTime types.Time `json:"E"`
OrderCreationTime types.Time `json:"O"`
TransactionTime types.Time `json:"T"`
WorkingTime types.Time `json:"W"`
*WsOrderUpdateData
} `json:"data"`
*Alias
@@ -400,8 +372,8 @@ func (a *wsListStatus) UnmarshalJSON(data []byte) error {
type Alias wsListStatus
aux := &struct {
Data struct {
EventTime binanceTime `json:"E"`
TransactionTime binanceTime `json:"T"`
EventTime types.Time `json:"E"`
TransactionTime types.Time `json:"T"`
*WsListStatusData
} `json:"data"`
*Alias
@@ -422,7 +394,7 @@ func (a *FuturesAccountInformationPosition) UnmarshalJSON(data []byte) error {
type Alias FuturesAccountInformationPosition
aux := &struct {
UpdateTime binanceTime `json:"updateTime"`
UpdateTime types.Time `json:"updateTime"`
*Alias
}{
Alias: (*Alias)(a),
@@ -442,7 +414,7 @@ func (a *FuturesAccountInformation) UnmarshalJSON(data []byte) error {
type Alias FuturesAccountInformation
aux := &struct {
UpdateTime binanceTime `json:"updateTime"`
UpdateTime types.Time `json:"updateTime"`
*Alias
}{
Alias: (*Alias)(a),

View File

@@ -52,12 +52,12 @@ type OrderbookData struct {
// UPublicTradesData stores trade data
type UPublicTradesData struct {
ID int64 `json:"id"`
Price float64 `json:"price,string"`
Qty float64 `json:"qty,string"`
QuoteQty float64 `json:"quoteQty,string"`
Time binanceTime `json:"time"`
IsBuyerMaker bool `json:"isBuyerMaker"`
ID int64 `json:"id"`
Price float64 `json:"price,string"`
Qty float64 `json:"qty,string"`
QuoteQty float64 `json:"quoteQty,string"`
Time types.Time `json:"time"`
IsBuyerMaker bool `json:"isBuyerMaker"`
}
// UCompressedTradeData stores compressed trade data
@@ -300,22 +300,22 @@ type UAsset struct {
// UPosition holds account position information
type UPosition struct {
Symbol string `json:"symbol"`
InitialMargin float64 `json:"initialMargin,string"`
MaintenanceMargin float64 `json:"maintMargin,string"`
UnrealisedProfit float64 `json:"unrealizedProfit,string"`
PositionInitialMargin float64 `json:"positionInitialMargin,string"`
OpenOrderInitialMargin float64 `json:"openOrderInitialMargin,string"`
Leverage float64 `json:"leverage,string"`
Isolated bool `json:"isolated"`
IsolatedWallet float64 `json:"isolatedWallet,string"`
EntryPrice float64 `json:"entryPrice,string"`
MaxNotional float64 `json:"maxNotional,string"`
BidNotional float64 `json:"bidNotional,string"`
AskNotional float64 `json:"askNotional,string"`
PositionSide string `json:"positionSide"`
PositionAmount float64 `json:"positionAmt,string"`
UpdateTime binanceTime `json:"updateTime"`
Symbol string `json:"symbol"`
InitialMargin float64 `json:"initialMargin,string"`
MaintenanceMargin float64 `json:"maintMargin,string"`
UnrealisedProfit float64 `json:"unrealizedProfit,string"`
PositionInitialMargin float64 `json:"positionInitialMargin,string"`
OpenOrderInitialMargin float64 `json:"openOrderInitialMargin,string"`
Leverage float64 `json:"leverage,string"`
Isolated bool `json:"isolated"`
IsolatedWallet float64 `json:"isolatedWallet,string"`
EntryPrice float64 `json:"entryPrice,string"`
MaxNotional float64 `json:"maxNotional,string"`
BidNotional float64 `json:"bidNotional,string"`
AskNotional float64 `json:"askNotional,string"`
PositionSide string `json:"positionSide"`
PositionAmount float64 `json:"positionAmt,string"`
UpdateTime types.Time `json:"updateTime"`
}
// UChangeInitialLeverage stores leverage change data
@@ -343,21 +343,21 @@ type UPositionMarginChangeHistoryData struct {
// UPositionInformationV2 stores positions data
type UPositionInformationV2 struct {
Symbol string `json:"symbol"`
PositionAmount float64 `json:"positionAmt,string"`
EntryPrice float64 `json:"entryPrice,string"`
MarkPrice float64 `json:"markPrice,string"`
UnrealizedProfit float64 `json:"unrealizedProfit,string"`
LiquidationPrice float64 `json:"liquidationPrice,string"`
Leverage float64 `json:"leverage,string"`
MaxNotionalValue float64 `json:"maxNotionalValue,string"`
MarginType string `json:"marginType"`
IsAutoAddMargin bool `json:"isAutoAddMargin,string"`
PositionSide string `json:"positionSide"`
Notional float64 `json:"notional,string"`
IsolatedWallet float64 `json:"isolatedWallet,string"`
IsolatedMargin float64 `json:"isolatedMargin,string"`
UpdateTime binanceTime `json:"updateTime"`
Symbol string `json:"symbol"`
PositionAmount float64 `json:"positionAmt,string"`
EntryPrice float64 `json:"entryPrice,string"`
MarkPrice float64 `json:"markPrice,string"`
UnrealizedProfit float64 `json:"unrealizedProfit,string"`
LiquidationPrice float64 `json:"liquidationPrice,string"`
Leverage float64 `json:"leverage,string"`
MaxNotionalValue float64 `json:"maxNotionalValue,string"`
MarginType string `json:"marginType"`
IsAutoAddMargin bool `json:"isAutoAddMargin,string"`
PositionSide string `json:"positionSide"`
Notional float64 `json:"notional,string"`
IsolatedWallet float64 `json:"isolatedWallet,string"`
IsolatedMargin float64 `json:"isolatedMargin,string"`
UpdateTime types.Time `json:"updateTime"`
}
// UAccountTradeHistory stores trade data for the users account

View File

@@ -1307,7 +1307,7 @@ var ticker24hourChangeStream = `{
"stream":"btcusdt@ticker",
"data" :{
"e": "24hrTicker",
"E": 123456789,
"E": 1234567891,
"s": "BNBBTC",
"p": "0.0015",
"P": "250.00",
@@ -1325,7 +1325,7 @@ var ticker24hourChangeStream = `{
"v": "10000",
"q": "18",
"O": 0,
"C": 86400000,
"C": 8640000011,
"F": 0,
"L": 18150,
"n": 18151
@@ -1346,11 +1346,11 @@ func TestWebsocketKlineUpdate(t *testing.T) {
"stream":"btcusdt@kline_1m",
"data":{
"e": "kline",
"E": 123456789,
"E": 1234567891,
"s": "BNBBTC",
"k": {
"t": 123400000,
"T": 123460000,
"t": 1234000001,
"T": 1234600001,
"s": "BNBBTC",
"i": "1m",
"f": 100,
@@ -1429,7 +1429,7 @@ func TestWebsocketOrderBookDepthDiffStream(t *testing.T) {
}
update1 := []byte(`{"stream":"btcusdt@depth","data":{
"e": "depthUpdate",
"E": 123456788,
"E": 1234567891,
"s": "BTCUSDT",
"U": 157,
"u": 160,
@@ -1446,7 +1446,7 @@ func TestWebsocketOrderBookDepthDiffStream(t *testing.T) {
t.Fatal(err)
}
if err := bi.wsHandleData(update1); err != nil {
t.Error(err)
t.Fatal(err)
}
bi.obm.state[currency.BTC][currency.USDT][asset.Spot].fetchingBook = false
ob, err := bi.Websocket.Orderbook.GetOrderbook(p, asset.Spot)
@@ -1465,7 +1465,7 @@ func TestWebsocketOrderBookDepthDiffStream(t *testing.T) {
update2 := []byte(`{
"stream":"btcusdt@depth","data":{
"e": "depthUpdate",
"E": 123456789,
"E": 1234567892,
"s": "BTCUSDT",
"U": 161,
"u": 165,
@@ -1686,7 +1686,7 @@ func TestExecutionTypeToOrderStatus(t *testing.T) {
var websocketDepthUpdate = []byte(
`{
"e": "depthUpdate",
"E": 123456789,
"E": 12345678911,
"s": "BNBBTC",
"U": 157,
"u": 160,

View File

@@ -3,6 +3,8 @@ package binanceus
import (
"encoding/json"
"time"
"github.com/thrasher-corp/gocryptotrader/types"
)
// UnmarshalJSON deserialises the JSON info, including the timestamp
@@ -139,7 +141,7 @@ func (a *Account) UnmarshalJSON(data []byte) error {
func (a *NewOrderResponse) UnmarshalJSON(data []byte) error {
type Alias NewOrderResponse
aux := &struct {
TransactionTime binanceusTime `json:"transactTime"`
TransactionTime types.Time `json:"transactTime"`
*Alias
}{
Alias: (*Alias)(a),
@@ -306,8 +308,8 @@ func (a *WsListStatus) UnmarshalJSON(data []byte) error {
type Alias WsListStatus
aux := &struct {
Data struct {
EventTime binanceusTime `json:"E"`
TransactionTime binanceusTime `json:"T"`
EventTime types.Time `json:"E"`
TransactionTime types.Time `json:"T"`
*WsListStatusData
} `json:"data"`
*Alias
@@ -327,9 +329,9 @@ func (a *WsListStatus) UnmarshalJSON(data []byte) error {
func (a *TickerStream) UnmarshalJSON(data []byte) error {
type Alias TickerStream
aux := &struct {
EventTime binanceusTime `json:"E"`
OpenTime binanceusTime `json:"O"`
CloseTime binanceusTime `json:"C"`
EventTime types.Time `json:"E"`
OpenTime types.Time `json:"O"`
CloseTime types.Time `json:"C"`
*Alias
}{
Alias: (*Alias)(a),
@@ -347,10 +349,10 @@ func (a *TickerStream) UnmarshalJSON(data []byte) error {
func (a *KlineStream) UnmarshalJSON(data []byte) error {
type Alias KlineStream
aux := &struct {
EventTime binanceusTime `json:"E"`
EventTime types.Time `json:"E"`
Kline struct {
StartTime binanceusTime `json:"t"`
CloseTime binanceusTime `json:"T"`
StartTime types.Time `json:"t"`
CloseTime types.Time `json:"T"`
*KlineStreamData
} `json:"k"`
*Alias
@@ -371,8 +373,8 @@ func (a *KlineStream) UnmarshalJSON(data []byte) error {
func (a *TradeStream) UnmarshalJSON(data []byte) error {
type Alias TradeStream
aux := &struct {
TimeStamp binanceusTime `json:"T"`
EventTime binanceusTime `json:"E"`
TimeStamp types.Time `json:"T"`
EventTime types.Time `json:"E"`
*Alias
}{
Alias: (*Alias)(a),
@@ -390,9 +392,9 @@ func (a *wsOrderUpdate) UnmarshalJSON(data []byte) error {
type Alias wsOrderUpdate
aux := &struct {
Data struct {
EventTime binanceusTime `json:"E"`
OrderCreationTime binanceusTime `json:"O"`
TransactionTime binanceusTime `json:"T"`
EventTime types.Time `json:"E"`
OrderCreationTime types.Time `json:"O"`
TransactionTime types.Time `json:"T"`
*WsOrderUpdateData
} `json:"data"`
*Alias
@@ -414,8 +416,8 @@ func (a *wsBalanceUpdate) UnmarshalJSON(data []byte) error {
type Alias wsBalanceUpdate
aux := &struct {
Data struct {
EventTime binanceusTime `json:"E"`
ClearTime binanceusTime `json:"T"`
EventTime types.Time `json:"E"`
ClearTime types.Time `json:"T"`
*WsBalanceUpdateData
} `json:"data"`
*Alias
@@ -436,8 +438,8 @@ func (a *wsAccountPosition) UnmarshalJSON(data []byte) error {
type Alias wsAccountPosition
aux := &struct {
Data struct {
EventTime binanceusTime `json:"E"`
LastUpdated binanceusTime `json:"u"`
EventTime types.Time `json:"E"`
LastUpdated types.Time `json:"u"`
*WsAccountPositionData
} `json:"data"`
*Alias
@@ -457,7 +459,7 @@ func (a *wsAccountPosition) UnmarshalJSON(data []byte) error {
func (a *WebsocketDepthStream) UnmarshalJSON(data []byte) error {
type Alias WebsocketDepthStream
aux := &struct {
Timestamp binanceusTime `json:"E"`
Timestamp types.Time `json:"E"`
*Alias
}{
Alias: (*Alias)(a),
@@ -491,23 +493,6 @@ func (a *WebsocketAggregateTradeStream) UnmarshalJSON(data []byte) error {
return nil
}
// binanceTime provides an internal conversion helper
type binanceusTime time.Time
func (t *binanceusTime) UnmarshalJSON(data []byte) error {
var timestamp int64
if err := json.Unmarshal(data, &timestamp); err != nil {
return err
}
*t = binanceusTime(time.UnixMilli(timestamp))
return nil
}
// Time returns a time.Time object
func (t binanceusTime) Time() time.Time {
return time.Time(t)
}
// UnmarshalJSON deserialises createTime timestamp to built in time.
func (a *OCBSOrder) UnmarshalJSON(data []byte) error {
type Alias OCBSOrder

View File

@@ -4,6 +4,7 @@ import (
"encoding/json"
"github.com/thrasher-corp/gocryptotrader/currency"
"github.com/thrasher-corp/gocryptotrader/types"
)
// Ticker holds ticker data
@@ -127,17 +128,17 @@ type Orders struct {
// OrderData contains all individual order details
type OrderData struct {
OrderID string `json:"order_id"`
OrderCurrency string `json:"order_currency"`
OrderDate bithumbTime `json:"order_date"`
PaymentCurrency string `json:"payment_currency"`
Type string `json:"type"`
Status string `json:"status"`
Units float64 `json:"units,string"`
UnitsRemaining float64 `json:"units_remaining,string"`
Price float64 `json:"price,string"`
Fee float64 `json:"fee,string"`
Total float64 `json:"total,string"`
OrderID string `json:"order_id"`
OrderCurrency string `json:"order_currency"`
OrderDate types.Time `json:"order_date"`
PaymentCurrency string `json:"payment_currency"`
Type string `json:"type"`
Status string `json:"status"`
Units float64 `json:"units,string"`
UnitsRemaining float64 `json:"units_remaining,string"`
Price float64 `json:"price,string"`
Fee float64 `json:"fee,string"`
Total float64 `json:"total,string"`
}
// UserTransactions holds users full transaction list

View File

@@ -7,6 +7,7 @@ import (
"github.com/thrasher-corp/gocryptotrader/currency"
"github.com/thrasher-corp/gocryptotrader/exchanges/asset"
"github.com/thrasher-corp/gocryptotrader/types"
)
// WsResponse is a generalised response data structure which will defer
@@ -41,7 +42,7 @@ type WsTicker struct {
// WsOrderbooks defines an amalgamated bid ask orderbook tranche list
type WsOrderbooks struct {
List []WsOrderbook `json:"list"`
DateTime bithumbTime `json:"datetime"`
DateTime types.Time `json:"datetime"`
}
// WsOrderbook defines a singular orderbook tranche

View File

@@ -1,31 +0,0 @@
package bithumb
import (
"encoding/json"
"strconv"
"time"
)
// bithumbMSTime provides an internal conversion helper for microsecond parsing
type bithumbTime time.Time
// UnmarshalJSON implements the unmarshal interface
func (t *bithumbTime) UnmarshalJSON(data []byte) error {
var timestamp string
if err := json.Unmarshal(data, &timestamp); err != nil {
return err
}
i, err := strconv.ParseInt(timestamp, 10, 64)
if err != nil {
return err
}
*t = bithumbTime(time.Unix(0, i*int64(time.Microsecond)))
return nil
}
// Time returns a time.Time object
func (t bithumbTime) Time() time.Time {
return time.Time(t)
}

View File

@@ -1,27 +0,0 @@
package bithumb
import (
"encoding/json"
"testing"
)
func TestBithumbTime(t *testing.T) {
var newTime bithumbTime
err := json.Unmarshal([]byte("bad news"), &newTime)
if err == nil {
t.Fatal(err)
}
strData := []byte(`"1628739590000000"`) // Thursday, August 12, 2021 3:39:50 AM UTC
err = json.Unmarshal(strData, &newTime)
if err != nil {
t.Fatal(err)
}
tt := newTime.Time()
if tt.UTC().String() != "2021-08-12 03:39:50 +0000 UTC" {
t.Fatalf("expected: %s but received: %s",
"2021-08-12 03:39:50 +0000 UTC",
tt.UTC().String())
}
}

View File

@@ -5,69 +5,10 @@ import (
"fmt"
"strconv"
"strings"
"time"
"github.com/thrasher-corp/gocryptotrader/common/convert"
"github.com/thrasher-corp/gocryptotrader/exchanges/order"
)
// datetime provides an internal conversion helper
type datetime time.Time
func (d *datetime) UnmarshalJSON(data []byte) error {
var s string
if err := json.Unmarshal(data, &s); err != nil {
return err
}
t, err := convert.UnixTimestampStrToTime(s)
if err != nil {
return err
}
*d = datetime(t)
return nil
}
// Time returns datetime cast directly as time.Time
func (d datetime) Time() time.Time {
return time.Time(d)
}
// microTimestamp provides an internal conversion helper
type microTimestamp time.Time
func (t *microTimestamp) UnmarshalJSON(data []byte) error {
var s string
if err := json.Unmarshal(data, &s); err != nil {
return err
}
if strconv.IntSize == 32 && len(s) >= 10 {
i, err := strconv.ParseInt(s, 10, 64)
if err != nil {
return err
}
*t = microTimestamp(time.UnixMicro(i))
return nil
}
// Has Fast path optimisation when int == 64
i, err := strconv.Atoi(s)
if err != nil {
return err
}
*t = microTimestamp(time.UnixMicro(int64(i)))
return nil
}
// Time returns datetime cast directly as time.Time
func (t microTimestamp) Time() time.Time {
return time.Time(t)
}
// UnmarshalJSON deserializes JSON, and timestamp information.
func (p *TradingPair) UnmarshalJSON(data []byte) error {
type Alias TradingPair

View File

@@ -4,6 +4,7 @@ import (
"errors"
"github.com/thrasher-corp/gocryptotrader/currency"
"github.com/thrasher-corp/gocryptotrader/types"
)
// Transaction types
@@ -283,14 +284,14 @@ type websocketOrderResponse struct {
}
type websocketOrderData struct {
ID int64 `json:"id"`
IDStr string `json:"id_str"`
ClientOrderID string `json:"client_order_id"`
RemainingAmount float64 `json:"amount"`
ExecutedAmount float64 `json:"amount_traded,string"` // Not Cumulative; Partial fill amount
Amount float64 `json:"amount_at_create,string"`
Price float64 `json:"price"`
Side orderSide `json:"order_type"`
Datetime datetime `json:"datetime"`
Microtimestamp microTimestamp `json:"microtimestamp"`
ID int64 `json:"id"`
IDStr string `json:"id_str"`
ClientOrderID string `json:"client_order_id"`
RemainingAmount float64 `json:"amount"`
ExecutedAmount float64 `json:"amount_traded,string"` // Not Cumulative; Partial fill amount
Amount float64 `json:"amount_at_create,string"`
Price float64 `json:"price"`
Side orderSide `json:"order_type"`
Datetime types.Time `json:"datetime"`
Microtimestamp types.Time `json:"microtimestamp"`
}

View File

@@ -3226,7 +3226,7 @@ func TestWsTicker(t *testing.T) {
assert.Equal(t, 6780.866843, v.Volume, "Volume should be correct")
assert.Equal(t, "BTC_USDT", v.Pair.String(), "Pair should be correct")
assert.Equal(t, asset.Spot, v.AssetType, "AssetType should be correct")
assert.Equal(t, int64(233366401000), v.LastUpdated.UnixMilli(), "LastUpdated should be correct")
assert.Equal(t, int64(1715742949283), v.LastUpdated.UnixMilli(), "LastUpdated should be correct")
case 2: // Option
assert.Equal(t, currency.BTC, v.Pair.Base, "Pair base should be correct")
assert.Equal(t, 3565.00, v.Last, "Last should be correct")
@@ -3306,7 +3306,7 @@ func TestWsTicker(t *testing.T) {
assert.Equal(t, 61942.85, v.IndexPrice, "IndexPrice should be correct")
assert.Equal(t, 526.806, v.OpenInterest, "OpenInterest should be correct")
assert.Equal(t, asset.USDCMarginedFutures, v.AssetType, "AssetType should be correct")
assert.Equal(t, int64(171575661221), v.LastUpdated.UnixMilli(), "LastUpdated should be correct")
assert.Equal(t, int64(1715756612210), v.LastUpdated.UnixMilli(), "LastUpdated should be correct")
case 7: // CoinMargined snapshot
assert.Equal(t, currency.BTC, v.Pair.Base, "Pair base should be correct")
assert.Equal(t, currency.USD, v.Pair.Quote, "Pair quote should be correct")

File diff suppressed because it is too large Load Diff

View File

@@ -1,4 +1,4 @@
{"topic":"tickers.BTC-USDT","type":"snapshot","ts":233366401000,"cs":2588407389,"data":{"symbol":"BTCUSDT","lastPrice":"21109.77","highPrice24h":"21426.99","lowPrice24h":"20575","prevPrice24h":"20704.93","volume24h":"6780.866843","turnover24h":"141946527.22907118","price24hPcnt":"0.0196","usdIndexPrice":"21120.2400136"}}
{"topic":"tickers.BTC-USDT","type":"snapshot","ts":1715742949283,"cs":2588407389,"data":{"symbol":"BTCUSDT","lastPrice":"21109.77","highPrice24h":"21426.99","lowPrice24h":"20575","prevPrice24h":"20704.93","volume24h":"6780.866843","turnover24h":"141946527.22907118","price24hPcnt":"0.0196","usdIndexPrice":"21120.2400136"}}
{"topic":"tickers.BTC-28JUN24-60000-P","ts":1715742949283,"type":"snapshot","id":"tickers.BTC-28JUN24-60000-P-6222585724-1715742949283","data":{"symbol":"BTC-28JUN24-60000-P","bidPrice":"3475","bidSize":"10.14","bidIv":"0.5479","askPrice":"3520","askSize":"2.5","askIv":"0.5534","lastPrice":"3565","highPrice24h":"3715","lowPrice24h":"3555","markPrice":"3502.0715721","indexPrice":"61912.8","markPriceIv":"0.5513","underlyingPrice":"62588.50709846","openInterest":"29.35","turnover24h":"101005.6875725","volume24h":"1.62","totalVolume":"45","totalTurnover":"2911557","delta":"-0.37596534","gamma":"0.00003161","vega":"82.65324199","theta":"-51.54651685","predictedDeliveryPrice":"0","change24h":"0.02148998"}}
{"topic":"tickers.BTCUSDT","type":"snapshot","data":{"symbol":"BTCUSDT","tickDirection":"ZeroPlusTick","price24hPcnt":"-0.009772","lastPrice":"61874.00","prevPrice24h":"62484.60","highPrice24h":"62752.90","lowPrice24h":"61000.10","prevPrice1h":"61901.80","markPrice":"61875.25","indexPrice":"61903.73","openInterest":"58117.022","openInterestValue":"3596005265.51","turnover24h":"6073739017.8331","volume24h":"98430.1050","nextFundingTime":"1715760000000","fundingRate":"0.00008055","bid1Price":"61873.90","bid1Size":"3.783","ask1Price":"61874.00","ask1Size":"16.278"},"cs":176530003895,"ts":1715748762463}
{"topic":"tickers.BTCUSDT","type":"delta","data":{"symbol":"BTCUSDT","markPrice":"61875.06","indexPrice":"61903.59","openInterestValue":"3595994223.27","bid1Price":"61873.90","bid1Size":"3.543"},"cs":176530004279,"ts":1715748763063}

File diff suppressed because it is too large Load Diff

View File

@@ -1,72 +0,0 @@
package gateio
import (
"bytes"
"fmt"
"math"
"strconv"
"strings"
"time"
)
var (
zero = []byte(`0`)
emptyStr = []byte(`""`)
zeroStr = []byte(`"0"`)
)
// Time represents a time.Time object that can be unmarshalled from a float64 or string.
type Time time.Time
// UnmarshalJSON deserializes json, and timestamp information.
func (a *Time) UnmarshalJSON(data []byte) error {
if bytes.Equal(data, zero) || bytes.Equal(data, emptyStr) || bytes.Equal(data, zeroStr) {
*a = Time(time.Time{})
return nil
}
s := string(data)
if s[0] == '"' {
s = s[1 : len(s)-1]
}
target := strings.Index(s, ".")
if target != -1 {
s = s[:target] + s[target+1:]
}
standard, err := strconv.ParseInt(s, 10, 64)
if err != nil {
return err
}
switch len(s) {
case 10:
// Seconds
*a = Time(time.Unix(standard, 0))
case 11, 12:
// Milliseconds: 1726104395.5 && 1726104395.56
*a = Time(time.UnixMilli(standard * int64(math.Pow10(13-len(s)))))
case 13:
// Milliseconds
*a = Time(time.UnixMilli(standard))
case 14:
// MicroSeconds: 1726106210903.0
*a = Time(time.UnixMicro(standard * 100))
case 16:
// MicroSeconds
*a = Time(time.UnixMicro(standard))
case 17:
// NanoSeconds: 1606292218213.4578
*a = Time(time.Unix(0, standard*100))
case 19:
// NanoSeconds
*a = Time(time.Unix(0, standard))
default:
return fmt.Errorf("cannot unmarshal %s into Time", string(data))
}
return nil
}
// Time represents a time instance.
func (a Time) Time() time.Time { return time.Time(a) }

View File

@@ -27,6 +27,7 @@ import (
testexch "github.com/thrasher-corp/gocryptotrader/internal/testing/exchange"
testsubs "github.com/thrasher-corp/gocryptotrader/internal/testing/subscriptions"
"github.com/thrasher-corp/gocryptotrader/portfolio/withdraw"
"github.com/thrasher-corp/gocryptotrader/types"
)
// Please supply your own APIKEYS here for due diligence testing
@@ -3192,7 +3193,7 @@ func TestParseGateioMilliSecTimeUnmarshal(t *testing.T) {
float64JSON := `{"number": 1684981731.098}`
time := time.UnixMilli(timeWhenTesting)
var in Time
var in types.Time
err := json.Unmarshal([]byte(timeWhenTestingString), &in)
if err != nil {
t.Fatal(err)
@@ -3201,7 +3202,7 @@ func TestParseGateioMilliSecTimeUnmarshal(t *testing.T) {
t.Fatalf("found %v, but expected %v", in.Time(), time)
}
inInteger := struct {
Number Time `json:"number"`
Number types.Time `json:"number"`
}{}
err = json.Unmarshal([]byte(integerJSON), &inInteger)
if err != nil {
@@ -3212,7 +3213,7 @@ func TestParseGateioMilliSecTimeUnmarshal(t *testing.T) {
}
inFloat64 := struct {
Number Time `json:"number"`
Number types.Time `json:"number"`
}{}
err = json.Unmarshal([]byte(float64JSON), &inFloat64)
if err != nil {
@@ -3232,7 +3233,7 @@ func TestParseTimeUnmarshal(t *testing.T) {
timeWhenTestingStringMicroSecond := `"1691122380942.173000"`
whenTime := time.Unix(timeWhenTesting, 0)
var in Time
var in types.Time
err := json.Unmarshal([]byte(timeWhenTestingString), &in)
if err != nil {
t.Fatal(err)
@@ -3241,7 +3242,7 @@ func TestParseTimeUnmarshal(t *testing.T) {
t.Fatalf("found %v, but expected %v", in.Time(), whenTime)
}
inInteger := struct {
Number Time `json:"number"`
Number types.Time `json:"number"`
}{}
err = json.Unmarshal([]byte(integerJSON), &inInteger)
if err != nil {
@@ -3252,7 +3253,7 @@ func TestParseTimeUnmarshal(t *testing.T) {
}
inFloat64 := struct {
Number Time `json:"number"`
Number types.Time `json:"number"`
}{}
err = json.Unmarshal([]byte(float64JSON), &inFloat64)
if err != nil {
@@ -3263,7 +3264,7 @@ func TestParseTimeUnmarshal(t *testing.T) {
t.Fatalf("found %v, but expected %v", inFloat64.Number.Time(), msTime)
}
var microSeconds Time
var microSeconds types.Time
err = json.Unmarshal([]byte(timeWhenTestingStringMicroSecond), &microSeconds)
if err != nil {
t.Fatal(err)
@@ -3656,57 +3657,3 @@ func TestGenerateWebsocketMessageID(t *testing.T) {
t.Parallel()
require.NotEmpty(t, g.GenerateWebsocketMessageID(false))
}
func TestTime(t *testing.T) {
t.Parallel()
var testTime Time
require.NoError(t, json.Unmarshal([]byte(`0`), &testTime))
assert.Equal(t, time.Time{}, testTime.Time())
require.NoError(t, json.Unmarshal([]byte(`""`), &testTime))
assert.Equal(t, time.Time{}, testTime.Time())
require.NoError(t, json.Unmarshal([]byte(`"0"`), &testTime))
assert.Equal(t, time.Time{}, testTime.Time())
// seconds
require.NoError(t, json.Unmarshal([]byte(`"1628736847"`), &testTime))
assert.Equal(t, time.Unix(1628736847, 0), testTime.Time())
// milliseconds
require.NoError(t, json.Unmarshal([]byte(`"1726104395.5"`), &testTime))
assert.Equal(t, time.UnixMilli(1726104395500), testTime.Time())
require.NoError(t, json.Unmarshal([]byte(`"1726104395.56"`), &testTime))
assert.Equal(t, time.UnixMilli(1726104395560), testTime.Time())
require.NoError(t, json.Unmarshal([]byte(`"1628736847325"`), &testTime))
assert.Equal(t, time.UnixMilli(1628736847325), testTime.Time())
// microseconds
require.NoError(t, json.Unmarshal([]byte(`"1628736847325123"`), &testTime))
assert.Equal(t, time.UnixMicro(1628736847325123), testTime.Time())
require.NoError(t, json.Unmarshal([]byte(`"1726106210903.0"`), &testTime))
assert.Equal(t, time.UnixMicro(1726106210903000), testTime.Time())
// nanoseconds
require.NoError(t, json.Unmarshal([]byte(`"1606292218213.4578"`), &testTime))
assert.Equal(t, time.Unix(0, 1606292218213457800), testTime.Time())
require.NoError(t, json.Unmarshal([]byte(`"1606292218213457800"`), &testTime))
assert.Equal(t, time.Unix(0, 1606292218213457800), testTime.Time())
}
// 5046307 216.0 ns/op 168 B/op 2 allocs/op (current)
// 2716176 441.9 ns/op 352 B/op 6 allocs/op (previous)
func BenchmarkTime(b *testing.B) {
var testTime Time
for i := 0; i < b.N; i++ {
err := json.Unmarshal([]byte(`"1691122380942.173000"`), &testTime)
if err != nil {
b.Fatal(err)
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -16,7 +16,6 @@ import (
"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"
@@ -477,7 +476,7 @@ func (ku *Kucoin) GetSingleIsolatedMarginAccountInfo(ctx context.Context, symbol
// GetCurrentServerTime gets the server time
func (ku *Kucoin) GetCurrentServerTime(ctx context.Context) (time.Time, error) {
resp := struct {
Timestamp convert.ExchangeTime `json:"data"`
Timestamp types.Time `json:"data"`
Error
}{}
err := ku.SendHTTPRequest(ctx, exchange.RestSpot, currentServerTimeEPL, "/v1/timestamp", &resp)

View File

@@ -12,7 +12,6 @@ import (
"time"
"github.com/thrasher-corp/gocryptotrader/common"
"github.com/thrasher-corp/gocryptotrader/common/convert"
"github.com/thrasher-corp/gocryptotrader/currency"
exchange "github.com/thrasher-corp/gocryptotrader/exchanges"
"github.com/thrasher-corp/gocryptotrader/exchanges/asset"
@@ -286,7 +285,7 @@ func (ku *Kucoin) GetPublicFundingRate(ctx context.Context, symbol string, from,
// GetFuturesServerTime get server time
func (ku *Kucoin) GetFuturesServerTime(ctx context.Context) (time.Time, error) {
resp := struct {
Data convert.ExchangeTime `json:"data"`
Data types.Time `json:"data"`
Error
}{}
err := ku.SendHTTPRequest(ctx, exchange.RestFutures, futuresServerTimeEPL, "/v1/timestamp", &resp)

View File

@@ -3,7 +3,6 @@ package kucoin
import (
"time"
"github.com/thrasher-corp/gocryptotrader/common/convert"
"github.com/thrasher-corp/gocryptotrader/exchanges/order"
"github.com/thrasher-corp/gocryptotrader/types"
)
@@ -16,104 +15,104 @@ var (
// Contract store contract details
type Contract struct {
Symbol string `json:"symbol"`
RootSymbol string `json:"rootSymbol"`
ContractType string `json:"type"`
FirstOpenDate convert.ExchangeTime `json:"firstOpenDate"`
ExpireDate convert.ExchangeTime `json:"expireDate"`
SettleDate convert.ExchangeTime `json:"settleDate"`
BaseCurrency string `json:"baseCurrency"`
QuoteCurrency string `json:"quoteCurrency"`
SettleCurrency string `json:"settleCurrency"`
MaxOrderQty float64 `json:"maxOrderQty"`
MaxPrice float64 `json:"maxPrice"`
LotSize float64 `json:"lotSize"`
TickSize float64 `json:"tickSize"`
IndexPriceTickSize float64 `json:"indexPriceTickSize"`
Multiplier float64 `json:"multiplier"`
InitialMargin float64 `json:"initialMargin"`
MaintainMargin float64 `json:"maintainMargin"`
MaxRiskLimit float64 `json:"maxRiskLimit"`
MinRiskLimit float64 `json:"minRiskLimit"`
RiskStep float64 `json:"riskStep"`
MakerFeeRate float64 `json:"makerFeeRate"`
TakerFeeRate float64 `json:"takerFeeRate"`
TakerFixFee float64 `json:"takerFixFee"`
MakerFixFee float64 `json:"makerFixFee"`
SettlementFee float64 `json:"settlementFee"`
IsDeleverage bool `json:"isDeleverage"`
IsQuanto bool `json:"isQuanto"`
IsInverse bool `json:"isInverse"`
MarkMethod string `json:"markMethod"`
FairMethod string `json:"fairMethod"`
FundingBaseSymbol string `json:"fundingBaseSymbol"`
FundingQuoteSymbol string `json:"fundingQuoteSymbol"`
FundingRateSymbol string `json:"fundingRateSymbol"`
IndexSymbol string `json:"indexSymbol"`
SettlementSymbol string `json:"settlementSymbol"`
Status string `json:"status"`
FundingFeeRate float64 `json:"fundingFeeRate"`
PredictedFundingFeeRate float64 `json:"predictedFundingFeeRate"`
OpenInterest types.Number `json:"openInterest"`
TurnoverOf24h float64 `json:"turnoverOf24h"`
VolumeOf24h float64 `json:"volumeOf24h"`
MarkPrice float64 `json:"markPrice"`
IndexPrice float64 `json:"indexPrice"`
LastTradePrice float64 `json:"lastTradePrice"`
NextFundingRateTime int64 `json:"nextFundingRateTime"`
MaxLeverage float64 `json:"maxLeverage"`
SourceExchanges []string `json:"sourceExchanges"`
PremiumsSymbol1M string `json:"premiumsSymbol1M"`
PremiumsSymbol8H string `json:"premiumsSymbol8H"`
FundingBaseSymbol1M string `json:"fundingBaseSymbol1M"`
FundingQuoteSymbol1M string `json:"fundingQuoteSymbol1M"`
LowPrice float64 `json:"lowPrice"`
HighPrice float64 `json:"highPrice"`
PriceChgPct float64 `json:"priceChgPct"`
PriceChg float64 `json:"priceChg"`
Symbol string `json:"symbol"`
RootSymbol string `json:"rootSymbol"`
ContractType string `json:"type"`
FirstOpenDate types.Time `json:"firstOpenDate"`
ExpireDate types.Time `json:"expireDate"`
SettleDate types.Time `json:"settleDate"`
BaseCurrency string `json:"baseCurrency"`
QuoteCurrency string `json:"quoteCurrency"`
SettleCurrency string `json:"settleCurrency"`
MaxOrderQty float64 `json:"maxOrderQty"`
MaxPrice float64 `json:"maxPrice"`
LotSize float64 `json:"lotSize"`
TickSize float64 `json:"tickSize"`
IndexPriceTickSize float64 `json:"indexPriceTickSize"`
Multiplier float64 `json:"multiplier"`
InitialMargin float64 `json:"initialMargin"`
MaintainMargin float64 `json:"maintainMargin"`
MaxRiskLimit float64 `json:"maxRiskLimit"`
MinRiskLimit float64 `json:"minRiskLimit"`
RiskStep float64 `json:"riskStep"`
MakerFeeRate float64 `json:"makerFeeRate"`
TakerFeeRate float64 `json:"takerFeeRate"`
TakerFixFee float64 `json:"takerFixFee"`
MakerFixFee float64 `json:"makerFixFee"`
SettlementFee float64 `json:"settlementFee"`
IsDeleverage bool `json:"isDeleverage"`
IsQuanto bool `json:"isQuanto"`
IsInverse bool `json:"isInverse"`
MarkMethod string `json:"markMethod"`
FairMethod string `json:"fairMethod"`
FundingBaseSymbol string `json:"fundingBaseSymbol"`
FundingQuoteSymbol string `json:"fundingQuoteSymbol"`
FundingRateSymbol string `json:"fundingRateSymbol"`
IndexSymbol string `json:"indexSymbol"`
SettlementSymbol string `json:"settlementSymbol"`
Status string `json:"status"`
FundingFeeRate float64 `json:"fundingFeeRate"`
PredictedFundingFeeRate float64 `json:"predictedFundingFeeRate"`
OpenInterest types.Number `json:"openInterest"`
TurnoverOf24h float64 `json:"turnoverOf24h"`
VolumeOf24h float64 `json:"volumeOf24h"`
MarkPrice float64 `json:"markPrice"`
IndexPrice float64 `json:"indexPrice"`
LastTradePrice float64 `json:"lastTradePrice"`
NextFundingRateTime int64 `json:"nextFundingRateTime"`
MaxLeverage float64 `json:"maxLeverage"`
SourceExchanges []string `json:"sourceExchanges"`
PremiumsSymbol1M string `json:"premiumsSymbol1M"`
PremiumsSymbol8H string `json:"premiumsSymbol8H"`
FundingBaseSymbol1M string `json:"fundingBaseSymbol1M"`
FundingQuoteSymbol1M string `json:"fundingQuoteSymbol1M"`
LowPrice float64 `json:"lowPrice"`
HighPrice float64 `json:"highPrice"`
PriceChgPct float64 `json:"priceChgPct"`
PriceChg float64 `json:"priceChg"`
}
// FuturesTicker stores ticker data
type FuturesTicker struct {
Sequence int64 `json:"sequence"`
Symbol string `json:"symbol"`
Side order.Side `json:"side"`
Size float64 `json:"size"`
Price types.Number `json:"price"`
BestBidSize float64 `json:"bestBidSize"`
BestBidPrice types.Number `json:"bestBidPrice"`
BestAskSize float64 `json:"bestAskSize"`
BestAskPrice types.Number `json:"bestAskPrice"`
TradeID string `json:"tradeId"`
FilledTime convert.ExchangeTime `json:"ts"`
Sequence int64 `json:"sequence"`
Symbol string `json:"symbol"`
Side order.Side `json:"side"`
Size float64 `json:"size"`
Price types.Number `json:"price"`
BestBidSize float64 `json:"bestBidSize"`
BestBidPrice types.Number `json:"bestBidPrice"`
BestAskSize float64 `json:"bestAskSize"`
BestAskPrice types.Number `json:"bestAskPrice"`
TradeID string `json:"tradeId"`
FilledTime types.Time `json:"ts"`
}
type futuresOrderbookResponse struct {
Asks [][2]float64 `json:"asks"`
Bids [][2]float64 `json:"bids"`
Time convert.ExchangeTime `json:"ts"`
Sequence int64 `json:"sequence"`
Symbol string `json:"symbol"`
Asks [][2]float64 `json:"asks"`
Bids [][2]float64 `json:"bids"`
Time types.Time `json:"ts"`
Sequence int64 `json:"sequence"`
Symbol string `json:"symbol"`
}
// FuturesTrade stores trade data
type FuturesTrade struct {
Sequence int64 `json:"sequence"`
TradeID string `json:"tradeId"`
TakerOrderID string `json:"takerOrderId"`
MakerOrderID string `json:"makerOrderId"`
Price float64 `json:"price,string"`
Size float64 `json:"size"`
Side string `json:"side"`
FilledTime convert.ExchangeTime `json:"ts"`
Sequence int64 `json:"sequence"`
TradeID string `json:"tradeId"`
TakerOrderID string `json:"takerOrderId"`
MakerOrderID string `json:"makerOrderId"`
Price float64 `json:"price,string"`
Size float64 `json:"size"`
Side string `json:"side"`
FilledTime types.Time `json:"ts"`
}
// FuturesInterestRate stores interest rate data
type FuturesInterestRate struct {
Symbol string `json:"symbol"`
TimePoint convert.ExchangeTime `json:"timePoint"`
Value float64 `json:"value"`
Granularity int64 `json:"granularity"`
Symbol string `json:"symbol"`
TimePoint types.Time `json:"timePoint"`
Value float64 `json:"value"`
Granularity int64 `json:"granularity"`
}
// Decomposition stores decomposition data
@@ -143,9 +142,9 @@ type FuturesFundingRate struct {
// FundingHistoryItem represents funding history item
type FundingHistoryItem struct {
Symbol string `json:"symbol"`
FundingRate float64 `json:"fundingRate"`
Timepoint convert.ExchangeTime `json:"timepoint"`
Symbol string `json:"symbol"`
FundingRate float64 `json:"fundingRate"`
Timepoint types.Time `json:"timepoint"`
}
// FuturesKline stores kline data
@@ -169,42 +168,42 @@ type FutureOrdersResponse struct {
// FuturesOrder represents futures order information
type FuturesOrder struct {
ID string `json:"id"`
Symbol string `json:"symbol"`
OrderType string `json:"type"`
Side string `json:"side"`
Price float64 `json:"price,string"`
Size float64 `json:"size"`
Value float64 `json:"value,string"`
DealValue float64 `json:"dealValue,string"`
DealSize float64 `json:"dealSize"`
Stp string `json:"stp"`
Stop string `json:"stop"`
StopPriceType string `json:"stopPriceType"`
StopTriggered bool `json:"stopTriggered"`
StopPrice float64 `json:"stopPrice,string"`
TimeInForce string `json:"timeInForce"`
PostOnly bool `json:"postOnly"`
Hidden bool `json:"hidden"`
Iceberg bool `json:"iceberg"`
Leverage float64 `json:"leverage,string"`
ForceHold bool `json:"forceHold"`
CloseOrder bool `json:"closeOrder"`
VisibleSize float64 `json:"visibleSize"`
ClientOid string `json:"clientOid"`
Remark string `json:"remark"`
Tags string `json:"tags"`
IsActive bool `json:"isActive"`
CancelExist bool `json:"cancelExist"`
CreatedAt convert.ExchangeTime `json:"createdAt"`
UpdatedAt convert.ExchangeTime `json:"updatedAt"`
EndAt convert.ExchangeTime `json:"endAt"`
OrderTime convert.ExchangeTime `json:"orderTime"`
SettleCurrency string `json:"settleCurrency"`
Status string `json:"status"`
FilledValue float64 `json:"filledValue,string"`
FilledSize float64 `json:"filledSize"`
ReduceOnly bool `json:"reduceOnly"`
ID string `json:"id"`
Symbol string `json:"symbol"`
OrderType string `json:"type"`
Side string `json:"side"`
Price float64 `json:"price,string"`
Size float64 `json:"size"`
Value float64 `json:"value,string"`
DealValue float64 `json:"dealValue,string"`
DealSize float64 `json:"dealSize"`
Stp string `json:"stp"`
Stop string `json:"stop"`
StopPriceType string `json:"stopPriceType"`
StopTriggered bool `json:"stopTriggered"`
StopPrice float64 `json:"stopPrice,string"`
TimeInForce string `json:"timeInForce"`
PostOnly bool `json:"postOnly"`
Hidden bool `json:"hidden"`
Iceberg bool `json:"iceberg"`
Leverage float64 `json:"leverage,string"`
ForceHold bool `json:"forceHold"`
CloseOrder bool `json:"closeOrder"`
VisibleSize float64 `json:"visibleSize"`
ClientOid string `json:"clientOid"`
Remark string `json:"remark"`
Tags string `json:"tags"`
IsActive bool `json:"isActive"`
CancelExist bool `json:"cancelExist"`
CreatedAt types.Time `json:"createdAt"`
UpdatedAt types.Time `json:"updatedAt"`
EndAt types.Time `json:"endAt"`
OrderTime types.Time `json:"orderTime"`
SettleCurrency string `json:"settleCurrency"`
Status string `json:"status"`
FilledValue float64 `json:"filledValue,string"`
FilledSize float64 `json:"filledSize"`
ReduceOnly bool `json:"reduceOnly"`
}
// FutureFillsResponse represents a future fills list response detail
@@ -218,25 +217,25 @@ type FutureFillsResponse struct {
// FuturesFill represents list of recent fills for futures orders
type FuturesFill struct {
Symbol string `json:"symbol"`
TradeID string `json:"tradeId"`
OrderID string `json:"orderId"`
Side string `json:"side"`
Liquidity string `json:"liquidity"`
ForceTaker bool `json:"forceTaker"`
Price float64 `json:"price,string"`
Size float64 `json:"size,string"`
Value float64 `json:"value,string"`
FeeRate float64 `json:"feeRate,string"`
FixFee float64 `json:"fixFee,string"`
FeeCurrency string `json:"feeCurrency"`
Stop string `json:"stop"`
Fee float64 `json:"fee,string"`
OrderType string `json:"orderType"`
TradeType string `json:"tradeType"`
CreatedAt convert.ExchangeTime `json:"createdAt"`
SettleCurrency string `json:"settleCurrency"`
TradeTime convert.ExchangeTime `json:"tradeTime"`
Symbol string `json:"symbol"`
TradeID string `json:"tradeId"`
OrderID string `json:"orderId"`
Side string `json:"side"`
Liquidity string `json:"liquidity"`
ForceTaker bool `json:"forceTaker"`
Price float64 `json:"price,string"`
Size float64 `json:"size,string"`
Value float64 `json:"value,string"`
FeeRate float64 `json:"feeRate,string"`
FixFee float64 `json:"fixFee,string"`
FeeCurrency string `json:"feeCurrency"`
Stop string `json:"stop"`
Fee float64 `json:"fee,string"`
OrderType string `json:"orderType"`
TradeType string `json:"tradeType"`
CreatedAt types.Time `json:"createdAt"`
SettleCurrency string `json:"settleCurrency"`
TradeTime types.Time `json:"tradeTime"`
}
// FuturesOpenOrderStats represents futures open order summary stats information
@@ -250,44 +249,44 @@ type FuturesOpenOrderStats struct {
// FuturesPosition represents futures position detailed information
type FuturesPosition struct {
ID string `json:"id"`
Symbol string `json:"symbol"`
AutoDeposit bool `json:"autoDeposit"`
MaintMarginReq float64 `json:"maintMarginReq"`
RiskLimit int64 `json:"riskLimit"`
RealLeverage float64 `json:"realLeverage"`
CrossMode bool `json:"crossMode"`
ADLRankingPercentile float64 `json:"delevPercentage"`
OpeningTimestamp convert.ExchangeTime `json:"openingTimestamp"`
CurrentTimestamp convert.ExchangeTime `json:"currentTimestamp"`
CurrentQty float64 `json:"currentQty"`
CurrentCost float64 `json:"currentCost"` // Current position value
CurrentComm float64 `json:"currentComm"` // Current commission
UnrealisedCost float64 `json:"unrealisedCost"`
RealisedGrossCost float64 `json:"realisedGrossCost"`
RealisedCost float64 `json:"realisedCost"`
IsOpen bool `json:"isOpen"`
MarkPrice float64 `json:"markPrice"`
MarkValue float64 `json:"markValue"`
PosCost float64 `json:"posCost"` // Position value
PosCross float64 `json:"posCross"` // Added margin
PosInit float64 `json:"posInit"` // Leverage margin
PosComm float64 `json:"posComm"` // Bankruptcy cost
PosLoss float64 `json:"posLoss"` // Funding fees paid out
PosMargin float64 `json:"posMargin"` // Position margin
PosMaint float64 `json:"posMaint"` // Maintenance margin
MaintMargin float64 `json:"maintMargin"`
RealisedGrossPnl float64 `json:"realisedGrossPnl"`
RealisedPnl float64 `json:"realisedPnl"`
UnrealisedPnl float64 `json:"unrealisedPnl"`
UnrealisedPnlPcnt float64 `json:"unrealisedPnlPcnt"`
UnrealisedRoePcnt float64 `json:"unrealisedRoePcnt"`
AvgEntryPrice float64 `json:"avgEntryPrice"`
LiquidationPrice float64 `json:"liquidationPrice"`
BankruptPrice float64 `json:"bankruptPrice"`
SettleCurrency string `json:"settleCurrency"`
MaintainMargin float64 `json:"maintainMargin"`
RiskLimitLevel int64 `json:"riskLimitLevel"`
ID string `json:"id"`
Symbol string `json:"symbol"`
AutoDeposit bool `json:"autoDeposit"`
MaintMarginReq float64 `json:"maintMarginReq"`
RiskLimit int64 `json:"riskLimit"`
RealLeverage float64 `json:"realLeverage"`
CrossMode bool `json:"crossMode"`
ADLRankingPercentile float64 `json:"delevPercentage"`
OpeningTimestamp types.Time `json:"openingTimestamp"`
CurrentTimestamp types.Time `json:"currentTimestamp"`
CurrentQty float64 `json:"currentQty"`
CurrentCost float64 `json:"currentCost"` // Current position value
CurrentComm float64 `json:"currentComm"` // Current commission
UnrealisedCost float64 `json:"unrealisedCost"`
RealisedGrossCost float64 `json:"realisedGrossCost"`
RealisedCost float64 `json:"realisedCost"`
IsOpen bool `json:"isOpen"`
MarkPrice float64 `json:"markPrice"`
MarkValue float64 `json:"markValue"`
PosCost float64 `json:"posCost"` // Position value
PosCross float64 `json:"posCross"` // Added margin
PosInit float64 `json:"posInit"` // Leverage margin
PosComm float64 `json:"posComm"` // Bankruptcy cost
PosLoss float64 `json:"posLoss"` // Funding fees paid out
PosMargin float64 `json:"posMargin"` // Position margin
PosMaint float64 `json:"posMaint"` // Maintenance margin
MaintMargin float64 `json:"maintMargin"`
RealisedGrossPnl float64 `json:"realisedGrossPnl"`
RealisedPnl float64 `json:"realisedPnl"`
UnrealisedPnl float64 `json:"unrealisedPnl"`
UnrealisedPnlPcnt float64 `json:"unrealisedPnlPcnt"`
UnrealisedRoePcnt float64 `json:"unrealisedRoePcnt"`
AvgEntryPrice float64 `json:"avgEntryPrice"`
LiquidationPrice float64 `json:"liquidationPrice"`
BankruptPrice float64 `json:"bankruptPrice"`
SettleCurrency string `json:"settleCurrency"`
MaintainMargin float64 `json:"maintainMargin"`
RiskLimitLevel int64 `json:"riskLimitLevel"`
}
// WithdrawMarginResponse represents a response data after withdrawing a margin
@@ -315,15 +314,15 @@ type FuturesRiskLimitLevel struct {
// FuturesFundingHistory represents futures funding information
type FuturesFundingHistory struct {
ID string `json:"id"`
Symbol string `json:"symbol"`
Time convert.ExchangeTime `json:"timePoint"`
FundingRate float64 `json:"fundingRate"`
MarkPrice float64 `json:"markPrice"`
PositionQty float64 `json:"positionQty"`
PositionCost float64 `json:"positionCost"`
Funding float64 `json:"funding"`
SettleCurrency string `json:"settleCurrency"`
ID string `json:"id"`
Symbol string `json:"symbol"`
Time types.Time `json:"timePoint"`
FundingRate float64 `json:"fundingRate"`
MarkPrice float64 `json:"markPrice"`
PositionQty float64 `json:"positionQty"`
PositionCost float64 `json:"positionCost"`
Funding float64 `json:"funding"`
SettleCurrency string `json:"settleCurrency"`
}
// FuturesAccount holds futures account detail information
@@ -340,27 +339,27 @@ type FuturesAccount struct {
// FuturesTransactionHistory represents a transaction history
type FuturesTransactionHistory struct {
Time convert.ExchangeTime `json:"time"`
Type string `json:"type"`
Amount float64 `json:"amount"`
Fee float64 `json:"fee"`
AccountEquity float64 `json:"accountEquity"`
Status string `json:"status"`
Remark string `json:"remark"`
Offset int64 `json:"offset"`
Currency string `json:"currency"`
Time types.Time `json:"time"`
Type string `json:"type"`
Amount float64 `json:"amount"`
Fee float64 `json:"fee"`
AccountEquity float64 `json:"accountEquity"`
Status string `json:"status"`
Remark string `json:"remark"`
Offset int64 `json:"offset"`
Currency string `json:"currency"`
}
// APIKeyDetail represents the API key detail
type APIKeyDetail struct {
SubName string `json:"subName"`
Remark string `json:"remark"`
APIKey string `json:"apiKey"`
APISecret string `json:"apiSecret"`
Passphrase string `json:"passphrase"`
Permission string `json:"permission"`
IPWhitelist string `json:"ipWhitelist"`
CreateAt convert.ExchangeTime `json:"createdAt"`
SubName string `json:"subName"`
Remark string `json:"remark"`
APIKey string `json:"apiKey"`
APISecret string `json:"apiSecret"`
Passphrase string `json:"passphrase"`
Permission string `json:"permission"`
IPWhitelist string `json:"ipWhitelist"`
CreateAt types.Time `json:"createdAt"`
}
// FuturesDepositDetailsResponse represents a futures deposits list detail response
@@ -374,14 +373,14 @@ type FuturesDepositDetailsResponse struct {
// FuturesDepositDetail represents futures deposit detail information
type FuturesDepositDetail struct {
Currency string `json:"currency"`
Status string `json:"status"`
Address string `json:"address"`
IsInner bool `json:"isInner"`
Amount float64 `json:"amount"`
Fee float64 `json:"fee"`
WalletTxID string `json:"walletTxId"`
CreatedAt convert.ExchangeTime `json:"createdAt"`
Currency string `json:"currency"`
Status string `json:"status"`
Address string `json:"address"`
IsInner bool `json:"isInner"`
Amount float64 `json:"amount"`
Fee float64 `json:"fee"`
WalletTxID string `json:"walletTxId"`
CreatedAt types.Time `json:"createdAt"`
}
// FuturesWithdrawalLimit represents withdrawal limit information
@@ -410,44 +409,44 @@ type FuturesWithdrawalsListResponse struct {
// FuturesWithdrawalHistory represents a list of Futures withdrawal history
type FuturesWithdrawalHistory struct {
WithdrawalID string `json:"withdrawalId"`
Currency string `json:"currency"`
Status string `json:"status"`
Address string `json:"address"`
Memo string `json:"memo"`
IsInner bool `json:"isInner"`
Amount float64 `json:"amount"`
Fee float64 `json:"fee"`
WalletTxID string `json:"walletTxId"`
CreatedAt convert.ExchangeTime `json:"createdAt"`
Remark string `json:"remark"`
Reason string `json:"reason"`
WithdrawalID string `json:"withdrawalId"`
Currency string `json:"currency"`
Status string `json:"status"`
Address string `json:"address"`
Memo string `json:"memo"`
IsInner bool `json:"isInner"`
Amount float64 `json:"amount"`
Fee float64 `json:"fee"`
WalletTxID string `json:"walletTxId"`
CreatedAt types.Time `json:"createdAt"`
Remark string `json:"remark"`
Reason string `json:"reason"`
}
// TransferBase represents transfer base information
type TransferBase struct {
ApplyID string `json:"applyId"`
Currency string `json:"currency"`
RecRemark string `json:"recRemark"`
RecSystem string `json:"recSystem"`
Status string `json:"status"`
Amount float64 `json:"amount,string"`
Reason string `json:"reason"`
CreatedAt convert.ExchangeTime `json:"createdAt"`
Remark string `json:"remark"`
ApplyID string `json:"applyId"`
Currency string `json:"currency"`
RecRemark string `json:"recRemark"`
RecSystem string `json:"recSystem"`
Status string `json:"status"`
Amount float64 `json:"amount,string"`
Reason string `json:"reason"`
CreatedAt types.Time `json:"createdAt"`
Remark string `json:"remark"`
}
// TransferRes represents a transfer response
type TransferRes struct {
TransferBase
BizNo string `json:"bizNo"`
PayAccountType string `json:"payAccountType"`
PayTag string `json:"payTag"`
RecAccountType string `json:"recAccountType"`
RecTag string `json:"recTag"`
Fee float64 `json:"fee,string"`
Serial int64 `json:"sn"`
UpdatedAt convert.ExchangeTime `json:"updatedAt"`
BizNo string `json:"bizNo"`
PayAccountType string `json:"payAccountType"`
PayTag string `json:"payTag"`
RecAccountType string `json:"recAccountType"`
RecTag string `json:"recTag"`
Fee float64 `json:"fee,string"`
Serial int64 `json:"sn"`
UpdatedAt types.Time `json:"updatedAt"`
}
// TransferListsResponse represents a transfer lists detail

File diff suppressed because it is too large Load Diff

View File

@@ -5,7 +5,6 @@ import (
"strconv"
"time"
"github.com/thrasher-corp/gocryptotrader/common/convert"
"github.com/thrasher-corp/gocryptotrader/currency"
"github.com/thrasher-corp/gocryptotrader/exchanges/asset"
"github.com/thrasher-corp/gocryptotrader/exchanges/kline"
@@ -2169,16 +2168,16 @@ type BlockTicker struct {
// BlockTrade represents a block trade.
type BlockTrade struct {
InstrumentID string `json:"instId"`
TradeID string `json:"tradeId"`
Price types.Number `json:"px"`
Size types.Number `json:"sz"`
Side order.Side `json:"side"`
FillVolatility types.Number `json:"fillVol"`
ForwardPrice types.Number `json:"fwdPx"`
IndexPrice types.Number `json:"idxPx"`
MarkPrice types.Number `json:"markPx"`
Timestamp convert.ExchangeTime `json:"ts"`
InstrumentID string `json:"instId"`
TradeID string `json:"tradeId"`
Price types.Number `json:"px"`
Size types.Number `json:"sz"`
Side order.Side `json:"side"`
FillVolatility types.Number `json:"fillVol"`
ForwardPrice types.Number `json:"fwdPx"`
IndexPrice types.Number `json:"idxPx"`
MarkPrice types.Number `json:"markPx"`
Timestamp types.Time `json:"ts"`
}
// UnitConvertResponse unit convert response.

79
types/time.go Normal file
View File

@@ -0,0 +1,79 @@
package types
import (
"fmt"
"math"
"strconv"
"strings"
"time"
)
// Time represents a time.Time object that can be unmarshalled from a float64 or string.
// MarshalJSON serializes the time to JSON using RFC 3339 format.
// Note: Not all exchanges may support RFC 3339 for outbound requests, so ensure compatibility with each exchange's time
// format requirements.
type Time time.Time
// UnmarshalJSON deserializes json, and timestamp information.
func (t *Time) UnmarshalJSON(data []byte) error {
s := string(data)
switch s {
case "null", "0", `""`, `"0"`:
*t = Time(time.Time{})
return nil
}
if s[0] == '"' {
s = s[1 : len(s)-1]
}
if target := strings.Index(s, "."); target != -1 {
s = s[:target] + s[target+1:]
}
standard, err := strconv.ParseInt(s, 10, 64)
if err != nil {
return err
}
switch len(s) {
case 10:
// Seconds
*t = Time(time.Unix(standard, 0))
case 11, 12:
// Milliseconds: 1726104395.5 && 1726104395.56
*t = Time(time.UnixMilli(standard * int64(math.Pow10(13-len(s)))))
case 13:
// Milliseconds
*t = Time(time.UnixMilli(standard))
case 14:
// MicroSeconds: 1726106210903.0
*t = Time(time.UnixMicro(standard * 100))
case 16:
// MicroSeconds
*t = Time(time.UnixMicro(standard))
case 17:
// NanoSeconds: 1606292218213.4578
*t = Time(time.Unix(0, standard*100))
case 19:
// NanoSeconds
*t = Time(time.Unix(0, standard))
default:
return fmt.Errorf("cannot unmarshal %s into Time", string(data))
}
return nil
}
// Time represents a time instance.
func (t Time) Time() time.Time { return time.Time(t) }
// String returns a string representation of the time.
func (t Time) String() string {
return t.Time().String()
}
// MarshalJSON serializes the time to json.
func (t Time) MarshalJSON() ([]byte, error) {
return t.Time().MarshalJSON()
}

86
types/time_test.go Normal file
View File

@@ -0,0 +1,86 @@
package types
import (
"encoding/json"
"strconv"
"testing"
"time"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestUnmarshalJSON(t *testing.T) {
t.Parallel()
var testTime Time
require.NoError(t, json.Unmarshal([]byte(`null`), &testTime))
assert.Equal(t, time.Time{}, testTime.Time())
require.NoError(t, json.Unmarshal([]byte(`0`), &testTime))
assert.Equal(t, time.Time{}, testTime.Time())
require.NoError(t, json.Unmarshal([]byte(`""`), &testTime))
assert.Equal(t, time.Time{}, testTime.Time())
require.NoError(t, json.Unmarshal([]byte(`"0"`), &testTime))
assert.Equal(t, time.Time{}, testTime.Time())
// seconds
require.NoError(t, json.Unmarshal([]byte(`"1628736847"`), &testTime))
assert.Equal(t, time.Unix(1628736847, 0), testTime.Time())
// milliseconds
require.NoError(t, json.Unmarshal([]byte(`"1726104395.5"`), &testTime))
assert.Equal(t, time.UnixMilli(1726104395500), testTime.Time())
require.NoError(t, json.Unmarshal([]byte(`"1726104395.56"`), &testTime))
assert.Equal(t, time.UnixMilli(1726104395560), testTime.Time())
require.NoError(t, json.Unmarshal([]byte(`"1628736847325"`), &testTime))
assert.Equal(t, time.UnixMilli(1628736847325), testTime.Time())
// microseconds
require.NoError(t, json.Unmarshal([]byte(`"1628736847325123"`), &testTime))
assert.Equal(t, time.UnixMicro(1628736847325123), testTime.Time())
require.NoError(t, json.Unmarshal([]byte(`"1726106210903.0"`), &testTime))
assert.Equal(t, time.UnixMicro(1726106210903000), testTime.Time())
// nanoseconds
require.NoError(t, json.Unmarshal([]byte(`"1606292218213.4578"`), &testTime))
assert.Equal(t, time.Unix(0, 1606292218213457800), testTime.Time())
require.NoError(t, json.Unmarshal([]byte(`"1606292218213457800"`), &testTime))
assert.Equal(t, time.Unix(0, 1606292218213457800), testTime.Time())
require.ErrorIs(t, json.Unmarshal([]byte(`"blurp"`), &testTime), strconv.ErrSyntax)
require.Error(t, json.Unmarshal([]byte(`"123456"`), &testTime))
}
// 5046307 216.0 ns/op 168 B/op 2 allocs/op (current)
// 2716176 441.9 ns/op 352 B/op 6 allocs/op (previous)
func BenchmarkUnmarshalJSON(b *testing.B) {
var testTime Time
for i := 0; i < b.N; i++ {
err := json.Unmarshal([]byte(`"1691122380942.173000"`), &testTime)
if err != nil {
b.Fatal(err)
}
}
}
func TestTime(t *testing.T) {
t.Parallel()
testTime := Time(time.Time{})
assert.Equal(t, time.Time{}, testTime.Time())
assert.Equal(t, "0001-01-01 00:00:00 +0000 UTC", testTime.String())
}
func TestTime_MarshalJSON(t *testing.T) {
t.Parallel()
testTime := Time(time.Time{})
data, err := testTime.MarshalJSON()
require.NoError(t, err)
assert.Equal(t, `"0001-01-01T00:00:00Z"`, string(data))
}