2024-01-11 08:41:42 +00:00
|
|
|
package okex
|
|
|
|
|
|
|
|
import (
|
2024-01-15 09:10:14 +00:00
|
|
|
"encoding/json"
|
2024-01-11 08:41:42 +00:00
|
|
|
"fmt"
|
|
|
|
"testing"
|
|
|
|
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
|
|
|
|
|
|
"github.com/c9s/bbgo/pkg/exchange/okex/okexapi"
|
|
|
|
"github.com/c9s/bbgo/pkg/fixedpoint"
|
|
|
|
"github.com/c9s/bbgo/pkg/types"
|
|
|
|
)
|
|
|
|
|
2024-01-12 07:09:45 +00:00
|
|
|
func Test_orderDetailToGlobal(t *testing.T) {
|
2024-01-11 08:41:42 +00:00
|
|
|
var (
|
|
|
|
assert = assert.New(t)
|
|
|
|
|
|
|
|
orderId = 665576973905014786
|
|
|
|
// {"accFillSz":"0","algoClOrdId":"","algoId":"","attachAlgoClOrdId":"","attachAlgoOrds":[],"avgPx":"","cTime":"1704957916401","cancelSource":"","cancelSourceReason":"","category":"normal","ccy":"","clOrdId":"","fee":"0","feeCcy":"USDT","fillPx":"","fillSz":"0","fillTime":"","instId":"BTC-USDT","instType":"SPOT","lever":"","ordId":"665576973905014786","ordType":"limit","pnl":"0","posSide":"net","px":"48174.5","pxType":"","pxUsd":"","pxVol":"","quickMgnType":"","rebate":"0","rebateCcy":"BTC","reduceOnly":"false","side":"sell","slOrdPx":"","slTriggerPx":"","slTriggerPxType":"","source":"","state":"live","stpId":"","stpMode":"","sz":"0.00001","tag":"","tdMode":"cash","tgtCcy":"","tpOrdPx":"","tpTriggerPx":"","tpTriggerPxType":"","tradeId":"","uTime":"1704957916401"}
|
2024-01-12 07:09:45 +00:00
|
|
|
openOrder = &okexapi.OrderDetail{
|
2024-01-11 08:41:42 +00:00
|
|
|
AccumulatedFillSize: fixedpoint.NewFromFloat(0),
|
|
|
|
AvgPrice: fixedpoint.NewFromFloat(0),
|
|
|
|
CreatedTime: types.NewMillisecondTimestampFromInt(1704957916401),
|
|
|
|
Category: "normal",
|
|
|
|
Currency: "BTC",
|
|
|
|
ClientOrderId: "",
|
|
|
|
Fee: fixedpoint.Zero,
|
|
|
|
FeeCurrency: "USDT",
|
|
|
|
FillTime: types.NewMillisecondTimestampFromInt(0),
|
|
|
|
InstrumentID: "BTC-USDT",
|
|
|
|
InstrumentType: okexapi.InstrumentTypeSpot,
|
|
|
|
OrderId: types.StrInt64(orderId),
|
|
|
|
OrderType: okexapi.OrderTypeLimit,
|
|
|
|
Price: fixedpoint.NewFromFloat(48174.5),
|
|
|
|
Side: okexapi.SideTypeBuy,
|
|
|
|
State: okexapi.OrderStateLive,
|
|
|
|
Size: fixedpoint.NewFromFloat(0.00001),
|
|
|
|
UpdatedTime: types.NewMillisecondTimestampFromInt(1704957916401),
|
|
|
|
}
|
|
|
|
expOrder = &types.Order{
|
|
|
|
SubmitOrder: types.SubmitOrder{
|
|
|
|
ClientOrderID: openOrder.ClientOrderId,
|
|
|
|
Symbol: toGlobalSymbol(openOrder.InstrumentID),
|
|
|
|
Side: types.SideTypeBuy,
|
|
|
|
Type: types.OrderTypeLimit,
|
|
|
|
Quantity: fixedpoint.NewFromFloat(0.00001),
|
|
|
|
Price: fixedpoint.NewFromFloat(48174.5),
|
|
|
|
AveragePrice: fixedpoint.Zero,
|
|
|
|
StopPrice: fixedpoint.Zero,
|
|
|
|
TimeInForce: types.TimeInForceGTC,
|
|
|
|
},
|
|
|
|
Exchange: types.ExchangeOKEx,
|
|
|
|
OrderID: uint64(orderId),
|
|
|
|
UUID: fmt.Sprintf("%d", orderId),
|
|
|
|
Status: types.OrderStatusNew,
|
|
|
|
OriginalStatus: string(okexapi.OrderStateLive),
|
|
|
|
ExecutedQuantity: fixedpoint.Zero,
|
|
|
|
IsWorking: true,
|
|
|
|
CreationTime: types.Time(types.NewMillisecondTimestampFromInt(1704957916401).Time()),
|
|
|
|
UpdateTime: types.Time(types.NewMillisecondTimestampFromInt(1704957916401).Time()),
|
|
|
|
}
|
|
|
|
)
|
|
|
|
|
|
|
|
t.Run("succeeds", func(t *testing.T) {
|
2024-01-12 07:09:45 +00:00
|
|
|
order, err := orderDetailToGlobal(openOrder)
|
2024-01-11 08:41:42 +00:00
|
|
|
assert.NoError(err)
|
|
|
|
assert.Equal(expOrder, order)
|
|
|
|
})
|
|
|
|
|
2024-01-16 07:29:12 +00:00
|
|
|
t.Run("succeeds with market/buy/targetQuoteCurrency", func(t *testing.T) {
|
|
|
|
newOrder := *openOrder
|
|
|
|
newOrder.OrderType = okexapi.OrderTypeMarket
|
|
|
|
newOrder.Side = okexapi.SideTypeBuy
|
|
|
|
newOrder.TargetCurrency = okexapi.TargetCurrencyQuote
|
|
|
|
newOrder.FillPrice = fixedpoint.NewFromFloat(100)
|
|
|
|
newOrder.Size = fixedpoint.NewFromFloat(10000)
|
|
|
|
newOrder.State = okexapi.OrderStatePartiallyFilled
|
|
|
|
|
|
|
|
newExpOrder := *expOrder
|
|
|
|
newExpOrder.Side = types.SideTypeBuy
|
|
|
|
newExpOrder.Type = types.OrderTypeMarket
|
|
|
|
newExpOrder.Quantity = fixedpoint.NewFromFloat(100)
|
|
|
|
newExpOrder.Status = types.OrderStatusPartiallyFilled
|
|
|
|
newExpOrder.OriginalStatus = string(okexapi.OrderStatePartiallyFilled)
|
|
|
|
order, err := orderDetailToGlobal(&newOrder)
|
|
|
|
assert.NoError(err)
|
|
|
|
assert.Equal(&newExpOrder, order)
|
|
|
|
})
|
|
|
|
|
2024-01-11 08:41:42 +00:00
|
|
|
t.Run("unexpected order status", func(t *testing.T) {
|
|
|
|
newOrder := *openOrder
|
|
|
|
newOrder.State = "xxx"
|
2024-01-12 07:09:45 +00:00
|
|
|
_, err := orderDetailToGlobal(&newOrder)
|
2024-01-11 08:41:42 +00:00
|
|
|
assert.ErrorContains(err, "xxx")
|
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("unexpected order type", func(t *testing.T) {
|
|
|
|
newOrder := *openOrder
|
|
|
|
newOrder.OrderType = "xxx"
|
2024-01-12 07:09:45 +00:00
|
|
|
_, err := orderDetailToGlobal(&newOrder)
|
2024-01-11 08:41:42 +00:00
|
|
|
assert.ErrorContains(err, "xxx")
|
|
|
|
})
|
|
|
|
|
|
|
|
}
|
2024-01-15 09:10:14 +00:00
|
|
|
|
|
|
|
func Test_tradeToGlobal(t *testing.T) {
|
|
|
|
var (
|
|
|
|
assert = assert.New(t)
|
|
|
|
raw = `{"side":"sell","fillSz":"1","fillPx":"46446.4","fillPxVol":"","fillFwdPx":"","fee":"-46","fillPnl":"0","ordId":"665951654130348158","feeRate":"-0.001","instType":"SPOT","fillPxUsd":"","instId":"BTC-USDT","clOrdId":"","posSide":"net","billId":"665951654138736652","fillMarkVol":"","tag":"","fillTime":"1705047247128","execType":"T","fillIdxPx":"","tradeId":"724072849","fillMarkPx":"","feeCcy":"USDT","ts":"1705047247130"}`
|
|
|
|
)
|
|
|
|
var res okexapi.Trade
|
|
|
|
err := json.Unmarshal([]byte(raw), &res)
|
|
|
|
assert.NoError(err)
|
|
|
|
|
|
|
|
t.Run("succeeds with sell/taker", func(t *testing.T) {
|
|
|
|
assert.Equal(tradeToGlobal(res), types.Trade{
|
2024-02-07 17:37:35 +00:00
|
|
|
ID: uint64(724072849),
|
2024-01-15 09:10:14 +00:00
|
|
|
OrderID: uint64(665951654130348158),
|
|
|
|
Exchange: types.ExchangeOKEx,
|
|
|
|
Price: fixedpoint.NewFromFloat(46446.4),
|
|
|
|
Quantity: fixedpoint.One,
|
|
|
|
QuoteQuantity: fixedpoint.NewFromFloat(46446.4),
|
|
|
|
Symbol: "BTCUSDT",
|
|
|
|
Side: types.SideTypeSell,
|
|
|
|
IsBuyer: false,
|
|
|
|
IsMaker: false,
|
|
|
|
Time: types.Time(types.NewMillisecondTimestampFromInt(1705047247130).Time()),
|
|
|
|
Fee: fixedpoint.NewFromFloat(46),
|
|
|
|
FeeCurrency: "USDT",
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("succeeds with buy/taker", func(t *testing.T) {
|
|
|
|
newRes := res
|
|
|
|
newRes.Side = okexapi.SideTypeBuy
|
|
|
|
assert.Equal(tradeToGlobal(newRes), types.Trade{
|
2024-02-07 17:37:35 +00:00
|
|
|
ID: uint64(724072849),
|
2024-01-15 09:10:14 +00:00
|
|
|
OrderID: uint64(665951654130348158),
|
|
|
|
Exchange: types.ExchangeOKEx,
|
|
|
|
Price: fixedpoint.NewFromFloat(46446.4),
|
|
|
|
Quantity: fixedpoint.One,
|
|
|
|
QuoteQuantity: fixedpoint.NewFromFloat(46446.4),
|
|
|
|
Symbol: "BTCUSDT",
|
|
|
|
Side: types.SideTypeBuy,
|
|
|
|
IsBuyer: true,
|
|
|
|
IsMaker: false,
|
|
|
|
Time: types.Time(types.NewMillisecondTimestampFromInt(1705047247130).Time()),
|
|
|
|
Fee: fixedpoint.NewFromFloat(46),
|
|
|
|
FeeCurrency: "USDT",
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("succeeds with sell/maker", func(t *testing.T) {
|
|
|
|
newRes := res
|
|
|
|
newRes.ExecutionType = okexapi.LiquidityTypeMaker
|
|
|
|
assert.Equal(tradeToGlobal(newRes), types.Trade{
|
2024-02-07 17:37:35 +00:00
|
|
|
ID: uint64(724072849),
|
2024-01-15 09:10:14 +00:00
|
|
|
OrderID: uint64(665951654130348158),
|
|
|
|
Exchange: types.ExchangeOKEx,
|
|
|
|
Price: fixedpoint.NewFromFloat(46446.4),
|
|
|
|
Quantity: fixedpoint.One,
|
|
|
|
QuoteQuantity: fixedpoint.NewFromFloat(46446.4),
|
|
|
|
Symbol: "BTCUSDT",
|
|
|
|
Side: types.SideTypeSell,
|
|
|
|
IsBuyer: false,
|
|
|
|
IsMaker: true,
|
|
|
|
Time: types.Time(types.NewMillisecondTimestampFromInt(1705047247130).Time()),
|
|
|
|
Fee: fixedpoint.NewFromFloat(46),
|
|
|
|
FeeCurrency: "USDT",
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("succeeds with buy/maker", func(t *testing.T) {
|
|
|
|
newRes := res
|
|
|
|
newRes.Side = okexapi.SideTypeBuy
|
|
|
|
newRes.ExecutionType = okexapi.LiquidityTypeMaker
|
|
|
|
assert.Equal(tradeToGlobal(newRes), types.Trade{
|
2024-02-07 17:37:35 +00:00
|
|
|
ID: uint64(724072849),
|
2024-01-15 09:10:14 +00:00
|
|
|
OrderID: uint64(665951654130348158),
|
|
|
|
Exchange: types.ExchangeOKEx,
|
|
|
|
Price: fixedpoint.NewFromFloat(46446.4),
|
|
|
|
Quantity: fixedpoint.One,
|
|
|
|
QuoteQuantity: fixedpoint.NewFromFloat(46446.4),
|
|
|
|
Symbol: "BTCUSDT",
|
|
|
|
Side: types.SideTypeBuy,
|
|
|
|
IsBuyer: true,
|
|
|
|
IsMaker: true,
|
|
|
|
Time: types.Time(types.NewMillisecondTimestampFromInt(1705047247130).Time()),
|
|
|
|
Fee: fixedpoint.NewFromFloat(46),
|
|
|
|
FeeCurrency: "USDT",
|
|
|
|
})
|
|
|
|
})
|
|
|
|
}
|
2024-01-16 07:29:12 +00:00
|
|
|
|
|
|
|
func Test_processMarketBuyQuantity(t *testing.T) {
|
|
|
|
var (
|
|
|
|
assert = assert.New(t)
|
|
|
|
)
|
|
|
|
|
|
|
|
t.Run("zero", func(t *testing.T) {
|
|
|
|
size, err := processMarketBuySize(&okexapi.OrderDetail{State: okexapi.OrderStateLive})
|
|
|
|
assert.NoError(err)
|
|
|
|
assert.Equal(fixedpoint.Zero, size)
|
|
|
|
|
|
|
|
size, err = processMarketBuySize(&okexapi.OrderDetail{State: okexapi.OrderStateCanceled})
|
|
|
|
assert.NoError(err)
|
|
|
|
assert.Equal(fixedpoint.Zero, size)
|
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("estimated size", func(t *testing.T) {
|
|
|
|
size, err := processMarketBuySize(&okexapi.OrderDetail{
|
|
|
|
FillPrice: fixedpoint.NewFromFloat(2),
|
|
|
|
Size: fixedpoint.NewFromFloat(4),
|
|
|
|
State: okexapi.OrderStatePartiallyFilled,
|
|
|
|
})
|
|
|
|
assert.NoError(err)
|
|
|
|
assert.Equal(fixedpoint.NewFromFloat(2), size)
|
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("unexpected fill price", func(t *testing.T) {
|
|
|
|
_, err := processMarketBuySize(&okexapi.OrderDetail{
|
|
|
|
FillPrice: fixedpoint.Zero,
|
|
|
|
Size: fixedpoint.NewFromFloat(4),
|
|
|
|
State: okexapi.OrderStatePartiallyFilled,
|
|
|
|
})
|
|
|
|
assert.ErrorContains(err, "fillPrice")
|
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("accumulatedFillsize", func(t *testing.T) {
|
|
|
|
size, err := processMarketBuySize(&okexapi.OrderDetail{
|
|
|
|
AccumulatedFillSize: fixedpoint.NewFromFloat(1000),
|
|
|
|
State: okexapi.OrderStateFilled,
|
|
|
|
})
|
|
|
|
assert.NoError(err)
|
|
|
|
assert.Equal(fixedpoint.NewFromFloat(1000), size)
|
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("unexpected status", func(t *testing.T) {
|
|
|
|
_, err := processMarketBuySize(&okexapi.OrderDetail{
|
|
|
|
State: "XXXXXXX",
|
|
|
|
})
|
|
|
|
assert.ErrorContains(err, "unexpected")
|
|
|
|
})
|
|
|
|
}
|