2023-10-31 03:56:15 +00:00
|
|
|
package bitget
|
|
|
|
|
|
|
|
import (
|
2023-11-05 15:41:57 +00:00
|
|
|
"strconv"
|
2023-10-31 03:56:15 +00:00
|
|
|
"testing"
|
2023-11-13 11:21:58 +00:00
|
|
|
"time"
|
2023-10-31 03:56:15 +00:00
|
|
|
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
|
|
|
2023-11-05 15:41:57 +00:00
|
|
|
v2 "github.com/c9s/bbgo/pkg/exchange/bitget/bitgetapi/v2"
|
2023-10-31 03:56:15 +00:00
|
|
|
"github.com/c9s/bbgo/pkg/fixedpoint"
|
|
|
|
"github.com/c9s/bbgo/pkg/types"
|
|
|
|
)
|
|
|
|
|
2023-11-01 03:46:43 +00:00
|
|
|
func Test_toGlobalBalance(t *testing.T) {
|
|
|
|
// sample:
|
|
|
|
// {
|
|
|
|
// "coinId":"10012",
|
|
|
|
// "coinName":"usdt",
|
|
|
|
// "available":"0",
|
|
|
|
// "frozen":"0",
|
|
|
|
// "lock":"0",
|
|
|
|
// "uTime":"1622697148"
|
|
|
|
// }
|
2024-01-03 03:25:46 +00:00
|
|
|
asset := v2.AccountAsset{
|
|
|
|
Coin: "USDT",
|
|
|
|
Available: fixedpoint.NewFromFloat(1.2),
|
|
|
|
Frozen: fixedpoint.NewFromFloat(0.5),
|
|
|
|
Locked: fixedpoint.NewFromFloat(0.5),
|
|
|
|
LimitAvailable: fixedpoint.Zero,
|
|
|
|
UpdatedTime: types.NewMillisecondTimestampFromInt(1622697148),
|
2023-11-01 03:46:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
assert.Equal(t, types.Balance{
|
|
|
|
Currency: "USDT",
|
|
|
|
Available: fixedpoint.NewFromFloat(1.2),
|
|
|
|
Locked: fixedpoint.NewFromFloat(1), // frozen + lock
|
|
|
|
Borrowed: fixedpoint.Zero,
|
|
|
|
Interest: fixedpoint.Zero,
|
|
|
|
NetAsset: fixedpoint.Zero,
|
|
|
|
MaxWithdrawAmount: fixedpoint.Zero,
|
|
|
|
}, toGlobalBalance(asset))
|
|
|
|
}
|
|
|
|
|
|
|
|
func Test_toGlobalMarket(t *testing.T) {
|
2023-10-31 03:56:15 +00:00
|
|
|
// sample:
|
2024-01-08 09:46:09 +00:00
|
|
|
// {
|
2023-11-14 06:35:16 +00:00
|
|
|
// "symbol":"BTCUSDT",
|
|
|
|
// "baseCoin":"BTC",
|
|
|
|
// "quoteCoin":"USDT",
|
|
|
|
// "minTradeAmount":"0",
|
|
|
|
// "maxTradeAmount":"10000000000",
|
|
|
|
// "takerFeeRate":"0.002",
|
|
|
|
// "makerFeeRate":"0.002",
|
|
|
|
// "pricePrecision":"2",
|
|
|
|
// "quantityPrecision":"4",
|
|
|
|
// "quotePrecision":"6",
|
|
|
|
// "status":"online",
|
|
|
|
// "minTradeUSDT":"5",
|
|
|
|
// "buyLimitPriceRatio":"0.05",
|
|
|
|
// "sellLimitPriceRatio":"0.05"
|
2024-01-08 09:46:09 +00:00
|
|
|
// }
|
2023-11-14 06:35:16 +00:00
|
|
|
inst := v2.Symbol{
|
|
|
|
Symbol: "BTCUSDT",
|
2023-10-31 03:56:15 +00:00
|
|
|
BaseCoin: "BTC",
|
|
|
|
QuoteCoin: "USDT",
|
2023-11-14 06:35:16 +00:00
|
|
|
MinTradeAmount: fixedpoint.NewFromFloat(0),
|
|
|
|
MaxTradeAmount: fixedpoint.NewFromFloat(10000000000),
|
|
|
|
TakerFeeRate: fixedpoint.NewFromFloat(0.002),
|
|
|
|
MakerFeeRate: fixedpoint.NewFromFloat(0.002),
|
|
|
|
PricePrecision: fixedpoint.NewFromFloat(2),
|
|
|
|
QuantityPrecision: fixedpoint.NewFromFloat(4),
|
|
|
|
QuotePrecision: fixedpoint.NewFromFloat(6),
|
2023-10-31 03:56:15 +00:00
|
|
|
MinTradeUSDT: fixedpoint.NewFromFloat(5),
|
2024-01-08 09:46:09 +00:00
|
|
|
Status: v2.SymbolStatusOnline,
|
2023-10-31 03:56:15 +00:00
|
|
|
BuyLimitPriceRatio: fixedpoint.NewFromFloat(0.05),
|
|
|
|
SellLimitPriceRatio: fixedpoint.NewFromFloat(0.05),
|
|
|
|
}
|
|
|
|
|
|
|
|
exp := types.Market{
|
2023-11-14 06:35:16 +00:00
|
|
|
Symbol: inst.Symbol,
|
2023-10-31 03:56:15 +00:00
|
|
|
LocalSymbol: inst.Symbol,
|
2023-11-14 06:35:16 +00:00
|
|
|
PricePrecision: 2,
|
|
|
|
VolumePrecision: 4,
|
2023-10-31 03:56:15 +00:00
|
|
|
QuoteCurrency: inst.QuoteCoin,
|
|
|
|
BaseCurrency: inst.BaseCoin,
|
|
|
|
MinNotional: inst.MinTradeUSDT,
|
|
|
|
MinAmount: inst.MinTradeUSDT,
|
|
|
|
MinQuantity: inst.MinTradeAmount,
|
|
|
|
MaxQuantity: inst.MaxTradeAmount,
|
2023-11-14 06:35:16 +00:00
|
|
|
StepSize: fixedpoint.NewFromFloat(0.0001),
|
2023-10-31 03:56:15 +00:00
|
|
|
MinPrice: fixedpoint.Zero,
|
|
|
|
MaxPrice: fixedpoint.Zero,
|
2023-11-14 06:35:16 +00:00
|
|
|
TickSize: fixedpoint.NewFromFloat(0.01),
|
2023-10-31 03:56:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
assert.Equal(t, toGlobalMarket(inst), exp)
|
|
|
|
}
|
2023-11-01 08:14:21 +00:00
|
|
|
|
|
|
|
func Test_toGlobalTicker(t *testing.T) {
|
|
|
|
// sample:
|
2024-01-08 09:46:09 +00:00
|
|
|
// {
|
2023-11-14 06:57:07 +00:00
|
|
|
// "open":"36465.96",
|
|
|
|
// "symbol":"BTCUSDT",
|
|
|
|
// "high24h":"37040.25",
|
|
|
|
// "low24h":"36202.65",
|
|
|
|
// "lastPr":"36684.42",
|
|
|
|
// "quoteVolume":"311893591.2805",
|
|
|
|
// "baseVolume":"8507.3684",
|
|
|
|
// "usdtVolume":"311893591.280427",
|
|
|
|
// "ts":"1699947106122",
|
|
|
|
// "bidPr":"36684.49",
|
|
|
|
// "askPr":"36684.51",
|
|
|
|
// "bidSz":"0.3812",
|
|
|
|
// "askSz":"0.0133",
|
|
|
|
// "openUtc":"36465.96",
|
|
|
|
// "changeUtc24h":"0.00599",
|
|
|
|
// "change24h":"-0.00426"
|
2024-01-08 09:46:09 +00:00
|
|
|
// }
|
2023-11-14 06:57:07 +00:00
|
|
|
ticker := v2.Ticker{
|
|
|
|
Symbol: "BTCUSDT",
|
|
|
|
High24H: fixedpoint.NewFromFloat(24175.65),
|
|
|
|
Low24H: fixedpoint.NewFromFloat(23677.75),
|
|
|
|
LastPr: fixedpoint.NewFromFloat(24014.11),
|
|
|
|
QuoteVolume: fixedpoint.NewFromFloat(177689342.3025),
|
|
|
|
BaseVolume: fixedpoint.NewFromFloat(7421.5009),
|
|
|
|
UsdtVolume: fixedpoint.NewFromFloat(177689342.302407),
|
|
|
|
Ts: types.NewMillisecondTimestampFromInt(1660704288118),
|
|
|
|
BidPr: fixedpoint.NewFromFloat(24013.94),
|
|
|
|
AskPr: fixedpoint.NewFromFloat(24014.06),
|
|
|
|
BidSz: fixedpoint.NewFromFloat(0.0663),
|
|
|
|
AskSz: fixedpoint.NewFromFloat(0.0119),
|
|
|
|
OpenUtc: fixedpoint.NewFromFloat(23856.72),
|
|
|
|
ChangeUtc24H: fixedpoint.NewFromFloat(0.00301),
|
|
|
|
Change24H: fixedpoint.NewFromFloat(0.00069),
|
|
|
|
Open: fixedpoint.NewFromFloat(23856.72),
|
2023-11-01 08:14:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
assert.Equal(t, types.Ticker{
|
|
|
|
Time: types.NewMillisecondTimestampFromInt(1660704288118).Time(),
|
|
|
|
Volume: fixedpoint.NewFromFloat(7421.5009),
|
|
|
|
Last: fixedpoint.NewFromFloat(24014.11),
|
|
|
|
Open: fixedpoint.NewFromFloat(23856.72),
|
|
|
|
High: fixedpoint.NewFromFloat(24175.65),
|
|
|
|
Low: fixedpoint.NewFromFloat(23677.75),
|
|
|
|
Buy: fixedpoint.NewFromFloat(24013.94),
|
|
|
|
Sell: fixedpoint.NewFromFloat(24014.06),
|
|
|
|
}, toGlobalTicker(ticker))
|
|
|
|
}
|
2023-11-05 15:41:57 +00:00
|
|
|
|
|
|
|
func Test_toGlobalSideType(t *testing.T) {
|
|
|
|
side, err := toGlobalSideType(v2.SideTypeBuy)
|
|
|
|
assert.NoError(t, err)
|
|
|
|
assert.Equal(t, types.SideTypeBuy, side)
|
|
|
|
|
|
|
|
side, err = toGlobalSideType(v2.SideTypeSell)
|
|
|
|
assert.NoError(t, err)
|
|
|
|
assert.Equal(t, types.SideTypeSell, side)
|
|
|
|
|
|
|
|
_, err = toGlobalSideType("xxx")
|
|
|
|
assert.ErrorContains(t, err, "xxx")
|
|
|
|
}
|
|
|
|
|
|
|
|
func Test_toGlobalOrderType(t *testing.T) {
|
|
|
|
orderType, err := toGlobalOrderType(v2.OrderTypeMarket)
|
|
|
|
assert.NoError(t, err)
|
|
|
|
assert.Equal(t, types.OrderTypeMarket, orderType)
|
|
|
|
|
|
|
|
orderType, err = toGlobalOrderType(v2.OrderTypeLimit)
|
|
|
|
assert.NoError(t, err)
|
|
|
|
assert.Equal(t, types.OrderTypeLimit, orderType)
|
|
|
|
|
|
|
|
_, err = toGlobalOrderType("xxx")
|
|
|
|
assert.ErrorContains(t, err, "xxx")
|
|
|
|
}
|
|
|
|
|
|
|
|
func Test_toGlobalOrderStatus(t *testing.T) {
|
|
|
|
status, err := toGlobalOrderStatus(v2.OrderStatusInit)
|
|
|
|
assert.NoError(t, err)
|
|
|
|
assert.Equal(t, types.OrderStatusNew, status)
|
|
|
|
|
|
|
|
status, err = toGlobalOrderStatus(v2.OrderStatusNew)
|
|
|
|
assert.NoError(t, err)
|
|
|
|
assert.Equal(t, types.OrderStatusNew, status)
|
|
|
|
|
|
|
|
status, err = toGlobalOrderStatus(v2.OrderStatusLive)
|
|
|
|
assert.NoError(t, err)
|
|
|
|
assert.Equal(t, types.OrderStatusNew, status)
|
|
|
|
|
|
|
|
status, err = toGlobalOrderStatus(v2.OrderStatusFilled)
|
|
|
|
assert.NoError(t, err)
|
|
|
|
assert.Equal(t, types.OrderStatusFilled, status)
|
|
|
|
|
|
|
|
status, err = toGlobalOrderStatus(v2.OrderStatusPartialFilled)
|
|
|
|
assert.NoError(t, err)
|
|
|
|
assert.Equal(t, types.OrderStatusPartiallyFilled, status)
|
|
|
|
|
|
|
|
status, err = toGlobalOrderStatus(v2.OrderStatusCancelled)
|
|
|
|
assert.NoError(t, err)
|
|
|
|
assert.Equal(t, types.OrderStatusCanceled, status)
|
|
|
|
|
|
|
|
_, err = toGlobalOrderStatus("xxx")
|
|
|
|
assert.ErrorContains(t, err, "xxx")
|
|
|
|
}
|
|
|
|
|
|
|
|
func Test_unfilledOrderToGlobalOrder(t *testing.T) {
|
|
|
|
var (
|
|
|
|
assert = assert.New(t)
|
|
|
|
orderId = 1105087175647989764
|
|
|
|
unfilledOrder = v2.UnfilledOrder{
|
|
|
|
Symbol: "BTCUSDT",
|
|
|
|
OrderId: types.StrInt64(orderId),
|
|
|
|
ClientOrderId: "74b86af3-6098-479c-acac-bfb074c067f3",
|
|
|
|
PriceAvg: fixedpoint.NewFromFloat(1.2),
|
|
|
|
Size: fixedpoint.NewFromFloat(5),
|
|
|
|
OrderType: v2.OrderTypeLimit,
|
|
|
|
Side: v2.SideTypeBuy,
|
|
|
|
Status: v2.OrderStatusLive,
|
|
|
|
BasePrice: fixedpoint.NewFromFloat(0),
|
|
|
|
BaseVolume: fixedpoint.NewFromFloat(0),
|
|
|
|
QuoteVolume: fixedpoint.NewFromFloat(0),
|
|
|
|
EnterPointSource: "API",
|
|
|
|
OrderSource: "normal",
|
2023-11-15 02:46:18 +00:00
|
|
|
CreatedTime: types.NewMillisecondTimestampFromInt(1660704288118),
|
|
|
|
UpdatedTime: types.NewMillisecondTimestampFromInt(1660704288118),
|
2023-11-05 15:41:57 +00:00
|
|
|
}
|
|
|
|
)
|
|
|
|
|
|
|
|
t.Run("succeeds", func(t *testing.T) {
|
|
|
|
order, err := unfilledOrderToGlobalOrder(unfilledOrder)
|
|
|
|
assert.NoError(err)
|
|
|
|
assert.Equal(&types.Order{
|
|
|
|
SubmitOrder: types.SubmitOrder{
|
|
|
|
ClientOrderID: "74b86af3-6098-479c-acac-bfb074c067f3",
|
|
|
|
Symbol: "BTCUSDT",
|
|
|
|
Side: types.SideTypeBuy,
|
|
|
|
Type: types.OrderTypeLimit,
|
|
|
|
Quantity: fixedpoint.NewFromFloat(5),
|
|
|
|
Price: fixedpoint.NewFromFloat(1.2),
|
|
|
|
TimeInForce: types.TimeInForceGTC,
|
|
|
|
},
|
|
|
|
Exchange: types.ExchangeBitget,
|
|
|
|
OrderID: uint64(orderId),
|
|
|
|
UUID: strconv.FormatInt(int64(orderId), 10),
|
|
|
|
Status: types.OrderStatusNew,
|
|
|
|
ExecutedQuantity: fixedpoint.NewFromFloat(0),
|
|
|
|
IsWorking: true,
|
|
|
|
CreationTime: types.Time(types.NewMillisecondTimestampFromInt(1660704288118).Time()),
|
|
|
|
UpdateTime: types.Time(types.NewMillisecondTimestampFromInt(1660704288118).Time()),
|
|
|
|
}, order)
|
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("failed to convert side", func(t *testing.T) {
|
|
|
|
newOrder := unfilledOrder
|
|
|
|
newOrder.Side = "xxx"
|
|
|
|
|
|
|
|
_, err := unfilledOrderToGlobalOrder(newOrder)
|
|
|
|
assert.ErrorContains(err, "xxx")
|
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("failed to convert oder type", func(t *testing.T) {
|
|
|
|
newOrder := unfilledOrder
|
|
|
|
newOrder.OrderType = "xxx"
|
|
|
|
|
|
|
|
_, err := unfilledOrderToGlobalOrder(newOrder)
|
|
|
|
assert.ErrorContains(err, "xxx")
|
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("failed to convert oder status", func(t *testing.T) {
|
|
|
|
newOrder := unfilledOrder
|
|
|
|
newOrder.Status = "xxx"
|
|
|
|
|
|
|
|
_, err := unfilledOrderToGlobalOrder(newOrder)
|
|
|
|
assert.ErrorContains(err, "xxx")
|
|
|
|
})
|
|
|
|
}
|
2023-11-06 03:51:16 +00:00
|
|
|
|
|
|
|
func Test_toGlobalOrder(t *testing.T) {
|
|
|
|
var (
|
|
|
|
assert = assert.New(t)
|
|
|
|
orderId = 1105087175647989764
|
|
|
|
unfilledOrder = v2.OrderDetail{
|
|
|
|
UserId: 123456,
|
|
|
|
Symbol: "BTCUSDT",
|
|
|
|
OrderId: types.StrInt64(orderId),
|
|
|
|
ClientOrderId: "74b86af3-6098-479c-acac-bfb074c067f3",
|
|
|
|
Price: fixedpoint.NewFromFloat(1.2),
|
|
|
|
Size: fixedpoint.NewFromFloat(5),
|
|
|
|
OrderType: v2.OrderTypeLimit,
|
|
|
|
Side: v2.SideTypeBuy,
|
|
|
|
Status: v2.OrderStatusFilled,
|
|
|
|
PriceAvg: fixedpoint.NewFromFloat(1.4),
|
|
|
|
BaseVolume: fixedpoint.NewFromFloat(5),
|
|
|
|
QuoteVolume: fixedpoint.NewFromFloat(7.0005),
|
|
|
|
EnterPointSource: "API",
|
|
|
|
FeeDetailRaw: `{\"newFees\":{\"c\":0,\"d\":0,\"deduction\":false,\"r\":-0.0070005,\"t\":-0.0070005,\"totalDeductionFee\":0},\"USDT\":{\"deduction\":false,\"feeCoinCode\":\"USDT\",\"totalDeductionFee\":0,\"totalFee\":-0.007000500000}}`,
|
|
|
|
OrderSource: "normal",
|
2023-11-15 02:46:18 +00:00
|
|
|
CreatedTime: types.NewMillisecondTimestampFromInt(1660704288118),
|
|
|
|
UpdatedTime: types.NewMillisecondTimestampFromInt(1660704288118),
|
2023-11-06 03:51:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
expOrder = &types.Order{
|
|
|
|
SubmitOrder: types.SubmitOrder{
|
|
|
|
ClientOrderID: "74b86af3-6098-479c-acac-bfb074c067f3",
|
|
|
|
Symbol: "BTCUSDT",
|
|
|
|
Side: types.SideTypeBuy,
|
|
|
|
Type: types.OrderTypeLimit,
|
|
|
|
Quantity: fixedpoint.NewFromFloat(5),
|
|
|
|
Price: fixedpoint.NewFromFloat(1.2),
|
|
|
|
TimeInForce: types.TimeInForceGTC,
|
|
|
|
},
|
|
|
|
Exchange: types.ExchangeBitget,
|
|
|
|
OrderID: uint64(orderId),
|
|
|
|
UUID: strconv.FormatInt(int64(orderId), 10),
|
|
|
|
Status: types.OrderStatusFilled,
|
|
|
|
ExecutedQuantity: fixedpoint.NewFromFloat(5),
|
|
|
|
IsWorking: false,
|
|
|
|
CreationTime: types.Time(types.NewMillisecondTimestampFromInt(1660704288118).Time()),
|
|
|
|
UpdateTime: types.Time(types.NewMillisecondTimestampFromInt(1660704288118).Time()),
|
|
|
|
}
|
|
|
|
)
|
|
|
|
|
|
|
|
t.Run("succeeds with limit buy", func(t *testing.T) {
|
|
|
|
order, err := toGlobalOrder(unfilledOrder)
|
|
|
|
assert.NoError(err)
|
|
|
|
assert.Equal(expOrder, order)
|
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("succeeds with limit sell", func(t *testing.T) {
|
|
|
|
newUnfilledOrder := unfilledOrder
|
|
|
|
newUnfilledOrder.Side = v2.SideTypeSell
|
|
|
|
|
|
|
|
newExpOrder := *expOrder
|
|
|
|
newExpOrder.Side = types.SideTypeSell
|
|
|
|
|
|
|
|
order, err := toGlobalOrder(newUnfilledOrder)
|
|
|
|
assert.NoError(err)
|
|
|
|
assert.Equal(&newExpOrder, order)
|
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("succeeds with market sell", func(t *testing.T) {
|
|
|
|
newUnfilledOrder := unfilledOrder
|
|
|
|
newUnfilledOrder.Side = v2.SideTypeSell
|
|
|
|
newUnfilledOrder.OrderType = v2.OrderTypeMarket
|
|
|
|
|
|
|
|
newExpOrder := *expOrder
|
|
|
|
newExpOrder.Side = types.SideTypeSell
|
|
|
|
newExpOrder.Type = types.OrderTypeMarket
|
|
|
|
newExpOrder.Price = newUnfilledOrder.PriceAvg
|
|
|
|
|
|
|
|
order, err := toGlobalOrder(newUnfilledOrder)
|
|
|
|
assert.NoError(err)
|
|
|
|
assert.Equal(&newExpOrder, order)
|
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("succeeds with market buy", func(t *testing.T) {
|
|
|
|
newUnfilledOrder := unfilledOrder
|
|
|
|
newUnfilledOrder.Side = v2.SideTypeBuy
|
|
|
|
newUnfilledOrder.OrderType = v2.OrderTypeMarket
|
|
|
|
|
|
|
|
newExpOrder := *expOrder
|
|
|
|
newExpOrder.Side = types.SideTypeBuy
|
|
|
|
newExpOrder.Type = types.OrderTypeMarket
|
|
|
|
newExpOrder.Price = newUnfilledOrder.PriceAvg
|
|
|
|
newExpOrder.Quantity = newUnfilledOrder.BaseVolume
|
|
|
|
|
|
|
|
order, err := toGlobalOrder(newUnfilledOrder)
|
|
|
|
assert.NoError(err)
|
|
|
|
assert.Equal(&newExpOrder, order)
|
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("succeeds with limit buy", func(t *testing.T) {
|
|
|
|
order, err := toGlobalOrder(unfilledOrder)
|
|
|
|
assert.NoError(err)
|
|
|
|
assert.Equal(&types.Order{
|
|
|
|
SubmitOrder: types.SubmitOrder{
|
|
|
|
ClientOrderID: "74b86af3-6098-479c-acac-bfb074c067f3",
|
|
|
|
Symbol: "BTCUSDT",
|
|
|
|
Side: types.SideTypeBuy,
|
|
|
|
Type: types.OrderTypeLimit,
|
|
|
|
Quantity: fixedpoint.NewFromFloat(5),
|
|
|
|
Price: fixedpoint.NewFromFloat(1.2),
|
|
|
|
TimeInForce: types.TimeInForceGTC,
|
|
|
|
},
|
|
|
|
Exchange: types.ExchangeBitget,
|
|
|
|
OrderID: uint64(orderId),
|
|
|
|
UUID: strconv.FormatInt(int64(orderId), 10),
|
|
|
|
Status: types.OrderStatusFilled,
|
|
|
|
ExecutedQuantity: fixedpoint.NewFromFloat(5),
|
|
|
|
IsWorking: false,
|
|
|
|
CreationTime: types.Time(types.NewMillisecondTimestampFromInt(1660704288118).Time()),
|
|
|
|
UpdateTime: types.Time(types.NewMillisecondTimestampFromInt(1660704288118).Time()),
|
|
|
|
}, order)
|
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("failed to convert side", func(t *testing.T) {
|
|
|
|
newOrder := unfilledOrder
|
|
|
|
newOrder.Side = "xxx"
|
|
|
|
|
|
|
|
_, err := toGlobalOrder(newOrder)
|
|
|
|
assert.ErrorContains(err, "xxx")
|
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("failed to convert oder type", func(t *testing.T) {
|
|
|
|
newOrder := unfilledOrder
|
|
|
|
newOrder.OrderType = "xxx"
|
|
|
|
|
|
|
|
_, err := toGlobalOrder(newOrder)
|
|
|
|
assert.ErrorContains(err, "xxx")
|
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("failed to convert oder status", func(t *testing.T) {
|
|
|
|
newOrder := unfilledOrder
|
|
|
|
newOrder.Status = "xxx"
|
|
|
|
|
|
|
|
_, err := toGlobalOrder(newOrder)
|
|
|
|
assert.ErrorContains(err, "xxx")
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
func Test_processMarketBuyQuantity(t *testing.T) {
|
|
|
|
var (
|
|
|
|
assert = assert.New(t)
|
|
|
|
filledBaseCoinQty = fixedpoint.NewFromFloat(3.5648)
|
|
|
|
filledPrice = fixedpoint.NewFromFloat(4.99998848)
|
|
|
|
priceAvg = fixedpoint.NewFromFloat(1.4026)
|
|
|
|
buyQty = fixedpoint.NewFromFloat(5)
|
|
|
|
)
|
|
|
|
|
|
|
|
t.Run("zero quantity on Init/New/Live/Cancelled", func(t *testing.T) {
|
|
|
|
qty, err := processMarketBuyQuantity(filledBaseCoinQty, filledPrice, priceAvg, buyQty, v2.OrderStatusInit)
|
|
|
|
assert.NoError(err)
|
|
|
|
assert.Equal(fixedpoint.Zero, qty)
|
|
|
|
|
|
|
|
qty, err = processMarketBuyQuantity(filledBaseCoinQty, filledPrice, priceAvg, buyQty, v2.OrderStatusNew)
|
|
|
|
assert.NoError(err)
|
|
|
|
assert.Equal(fixedpoint.Zero, qty)
|
|
|
|
|
|
|
|
qty, err = processMarketBuyQuantity(filledBaseCoinQty, filledPrice, priceAvg, buyQty, v2.OrderStatusLive)
|
|
|
|
assert.NoError(err)
|
|
|
|
assert.Equal(fixedpoint.Zero, qty)
|
|
|
|
|
|
|
|
qty, err = processMarketBuyQuantity(filledBaseCoinQty, filledPrice, priceAvg, buyQty, v2.OrderStatusCancelled)
|
|
|
|
assert.NoError(err)
|
|
|
|
assert.Equal(fixedpoint.Zero, qty)
|
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("5 on PartialFilled", func(t *testing.T) {
|
|
|
|
priceAvg := fixedpoint.NewFromFloat(2)
|
|
|
|
buyQty := fixedpoint.NewFromFloat(10)
|
|
|
|
filledPrice := fixedpoint.NewFromFloat(4)
|
|
|
|
filledBaseCoinQty := fixedpoint.NewFromFloat(2)
|
|
|
|
|
|
|
|
qty, err := processMarketBuyQuantity(filledBaseCoinQty, filledPrice, priceAvg, buyQty, v2.OrderStatusPartialFilled)
|
|
|
|
assert.NoError(err)
|
|
|
|
assert.Equal(fixedpoint.NewFromFloat(5), qty)
|
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("3.5648 on Filled", func(t *testing.T) {
|
|
|
|
qty, err := processMarketBuyQuantity(filledBaseCoinQty, filledPrice, priceAvg, buyQty, v2.OrderStatusFilled)
|
|
|
|
assert.NoError(err)
|
|
|
|
assert.Equal(fixedpoint.NewFromFloat(3.5648), qty)
|
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("unexpected order status", func(t *testing.T) {
|
|
|
|
_, err := processMarketBuyQuantity(filledBaseCoinQty, filledPrice, priceAvg, buyQty, "xxx")
|
|
|
|
assert.ErrorContains(err, "xxx")
|
|
|
|
})
|
|
|
|
}
|
2023-11-06 03:51:16 +00:00
|
|
|
|
|
|
|
func Test_toLocalOrderType(t *testing.T) {
|
|
|
|
orderType, err := toLocalOrderType(types.OrderTypeLimit)
|
|
|
|
assert.NoError(t, err)
|
|
|
|
assert.Equal(t, v2.OrderTypeLimit, orderType)
|
|
|
|
|
|
|
|
orderType, err = toLocalOrderType(types.OrderTypeMarket)
|
|
|
|
assert.NoError(t, err)
|
|
|
|
assert.Equal(t, v2.OrderTypeMarket, orderType)
|
|
|
|
|
|
|
|
_, err = toLocalOrderType("xxx")
|
|
|
|
assert.ErrorContains(t, err, "xxx")
|
|
|
|
}
|
|
|
|
|
|
|
|
func Test_toLocalSide(t *testing.T) {
|
|
|
|
orderType, err := toLocalSide(types.SideTypeSell)
|
|
|
|
assert.NoError(t, err)
|
|
|
|
assert.Equal(t, v2.SideTypeSell, orderType)
|
|
|
|
|
|
|
|
orderType, err = toLocalSide(types.SideTypeBuy)
|
|
|
|
assert.NoError(t, err)
|
|
|
|
assert.Equal(t, v2.SideTypeBuy, orderType)
|
|
|
|
|
|
|
|
_, err = toLocalOrderType("xxx")
|
|
|
|
assert.ErrorContains(t, err, "xxx")
|
|
|
|
}
|
2023-11-09 02:35:53 +00:00
|
|
|
|
|
|
|
func Test_isMaker(t *testing.T) {
|
|
|
|
isM, err := isMaker(v2.TradeTaker)
|
|
|
|
assert.NoError(t, err)
|
|
|
|
assert.False(t, isM)
|
|
|
|
|
|
|
|
isM, err = isMaker(v2.TradeMaker)
|
|
|
|
assert.NoError(t, err)
|
|
|
|
assert.True(t, isM)
|
|
|
|
|
|
|
|
_, err = isMaker("xxx")
|
|
|
|
assert.ErrorContains(t, err, "xxx")
|
|
|
|
}
|
|
|
|
|
|
|
|
func Test_isFeeDiscount(t *testing.T) {
|
|
|
|
isDiscount, err := isFeeDiscount(v2.DiscountNo)
|
|
|
|
assert.NoError(t, err)
|
|
|
|
assert.False(t, isDiscount)
|
|
|
|
|
|
|
|
isDiscount, err = isFeeDiscount(v2.DiscountYes)
|
|
|
|
assert.NoError(t, err)
|
|
|
|
assert.True(t, isDiscount)
|
|
|
|
|
|
|
|
_, err = isFeeDiscount("xxx")
|
|
|
|
assert.ErrorContains(t, err, "xxx")
|
|
|
|
}
|
|
|
|
|
|
|
|
func Test_toGlobalTrade(t *testing.T) {
|
|
|
|
// {
|
|
|
|
// "userId":"8672173294",
|
|
|
|
// "symbol":"APEUSDT",
|
|
|
|
// "orderId":"1104337778433757184",
|
|
|
|
// "tradeId":"1104337778504044545",
|
|
|
|
// "orderType":"limit",
|
|
|
|
// "side":"sell",
|
|
|
|
// "priceAvg":"1.4001",
|
|
|
|
// "size":"5",
|
|
|
|
// "amount":"7.0005",
|
|
|
|
// "feeDetail":{
|
|
|
|
// "deduction":"no",
|
|
|
|
// "feeCoin":"USDT",
|
|
|
|
// "totalDeductionFee":"",
|
|
|
|
// "totalFee":"-0.0070005"
|
|
|
|
// },
|
|
|
|
// "tradeScope":"taker",
|
|
|
|
// "cTime":"1699020564676",
|
|
|
|
// "uTime":"1699020564687"
|
2024-01-08 09:46:09 +00:00
|
|
|
// }
|
2023-11-09 02:35:53 +00:00
|
|
|
trade := v2.Trade{
|
|
|
|
UserId: types.StrInt64(8672173294),
|
|
|
|
Symbol: "APEUSDT",
|
|
|
|
OrderId: types.StrInt64(1104337778433757184),
|
|
|
|
TradeId: types.StrInt64(1104337778504044545),
|
|
|
|
OrderType: v2.OrderTypeLimit,
|
|
|
|
Side: v2.SideTypeSell,
|
|
|
|
PriceAvg: fixedpoint.NewFromFloat(1.4001),
|
|
|
|
Size: fixedpoint.NewFromFloat(5),
|
|
|
|
Amount: fixedpoint.NewFromFloat(7.0005),
|
|
|
|
FeeDetail: v2.TradeFee{
|
|
|
|
Deduction: "no",
|
|
|
|
FeeCoin: "USDT",
|
|
|
|
TotalDeductionFee: fixedpoint.Zero,
|
|
|
|
TotalFee: fixedpoint.NewFromFloat(-0.0070005),
|
|
|
|
},
|
2023-11-15 02:46:18 +00:00
|
|
|
TradeScope: v2.TradeTaker,
|
|
|
|
CreatedTime: types.NewMillisecondTimestampFromInt(1699020564676),
|
|
|
|
UpdatedTime: types.NewMillisecondTimestampFromInt(1699020564687),
|
2023-11-09 02:35:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
res, err := toGlobalTrade(trade)
|
|
|
|
assert.NoError(t, err)
|
|
|
|
assert.Equal(t, &types.Trade{
|
|
|
|
ID: uint64(1104337778504044545),
|
|
|
|
OrderID: uint64(1104337778433757184),
|
|
|
|
Exchange: types.ExchangeBitget,
|
|
|
|
Price: fixedpoint.NewFromFloat(1.4001),
|
|
|
|
Quantity: fixedpoint.NewFromFloat(5),
|
|
|
|
QuoteQuantity: fixedpoint.NewFromFloat(7.0005),
|
|
|
|
Symbol: "APEUSDT",
|
|
|
|
Side: types.SideTypeSell,
|
|
|
|
IsBuyer: false,
|
|
|
|
IsMaker: false,
|
|
|
|
Time: types.Time(types.NewMillisecondTimestampFromInt(1699020564676)),
|
|
|
|
Fee: fixedpoint.NewFromFloat(0.0070005),
|
|
|
|
FeeCurrency: "USDT",
|
|
|
|
FeeDiscounted: false,
|
|
|
|
}, res)
|
|
|
|
}
|
2023-11-10 14:35:39 +00:00
|
|
|
|
|
|
|
func Test_toGlobalBalanceMap(t *testing.T) {
|
|
|
|
assert.Equal(t, types.BalanceMap{
|
|
|
|
"BTC": {
|
|
|
|
Currency: "BTC",
|
|
|
|
Available: fixedpoint.NewFromFloat(0.5),
|
|
|
|
Locked: fixedpoint.NewFromFloat(0.6 + 0.7),
|
|
|
|
},
|
|
|
|
}, toGlobalBalanceMap([]Balance{
|
|
|
|
{
|
|
|
|
Coin: "BTC",
|
|
|
|
Available: fixedpoint.NewFromFloat(0.5),
|
|
|
|
Frozen: fixedpoint.NewFromFloat(0.6),
|
|
|
|
Locked: fixedpoint.NewFromFloat(0.7),
|
|
|
|
LimitAvailable: fixedpoint.Zero,
|
2023-11-15 02:46:18 +00:00
|
|
|
UpdatedTime: types.NewMillisecondTimestampFromInt(1699020564676),
|
2023-11-10 14:35:39 +00:00
|
|
|
},
|
|
|
|
}))
|
|
|
|
}
|
2023-11-13 11:21:58 +00:00
|
|
|
|
|
|
|
func Test_toGlobalKLines(t *testing.T) {
|
|
|
|
symbol := "BTCUSDT"
|
|
|
|
interval := types.Interval15m
|
|
|
|
|
|
|
|
resp := v2.KLineResponse{
|
|
|
|
/*
|
|
|
|
[
|
|
|
|
{
|
|
|
|
"Ts": "1699816800000",
|
|
|
|
"OpenPrice": 29045.3,
|
|
|
|
"HighPrice": 29228.56,
|
|
|
|
"LowPrice": 29045.3,
|
|
|
|
"ClosePrice": 29228.56,
|
|
|
|
"Volume": 9.265593,
|
|
|
|
"QuoteVolume": 270447.43520753,
|
|
|
|
"UsdtVolume": 270447.43520753
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"Ts": "1699816800000",
|
|
|
|
"OpenPrice": 29167.33,
|
|
|
|
"HighPrice": 29229.08,
|
|
|
|
"LowPrice": 29000,
|
|
|
|
"ClosePrice": 29045.3,
|
|
|
|
"Volume": 9.295508,
|
|
|
|
"QuoteVolume": 270816.87513775,
|
|
|
|
"UsdtVolume": 270816.87513775
|
|
|
|
}
|
|
|
|
]
|
|
|
|
*/
|
|
|
|
{
|
|
|
|
Ts: types.NewMillisecondTimestampFromInt(1691486100000),
|
|
|
|
Open: fixedpoint.NewFromFloat(29045.3),
|
|
|
|
High: fixedpoint.NewFromFloat(29228.56),
|
|
|
|
Low: fixedpoint.NewFromFloat(29045.3),
|
|
|
|
Close: fixedpoint.NewFromFloat(29228.56),
|
|
|
|
Volume: fixedpoint.NewFromFloat(9.265593),
|
|
|
|
QuoteVolume: fixedpoint.NewFromFloat(270447.43520753),
|
|
|
|
UsdtVolume: fixedpoint.NewFromFloat(270447.43520753),
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Ts: types.NewMillisecondTimestampFromInt(1691487000000),
|
|
|
|
Open: fixedpoint.NewFromFloat(29167.33),
|
|
|
|
High: fixedpoint.NewFromFloat(29229.08),
|
|
|
|
Low: fixedpoint.NewFromFloat(29000),
|
|
|
|
Close: fixedpoint.NewFromFloat(29045.3),
|
|
|
|
Volume: fixedpoint.NewFromFloat(9.295508),
|
|
|
|
QuoteVolume: fixedpoint.NewFromFloat(270816.87513775),
|
|
|
|
UsdtVolume: fixedpoint.NewFromFloat(270447.43520753),
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
expKlines := []types.KLine{
|
|
|
|
{
|
|
|
|
Exchange: types.ExchangeBitget,
|
|
|
|
Symbol: symbol,
|
|
|
|
StartTime: types.Time(resp[0].Ts.Time()),
|
|
|
|
EndTime: types.Time(resp[0].Ts.Time().Add(interval.Duration() - time.Millisecond)),
|
|
|
|
Interval: interval,
|
|
|
|
Open: fixedpoint.NewFromFloat(29045.3),
|
|
|
|
Close: fixedpoint.NewFromFloat(29228.56),
|
|
|
|
High: fixedpoint.NewFromFloat(29228.56),
|
|
|
|
Low: fixedpoint.NewFromFloat(29045.3),
|
|
|
|
Volume: fixedpoint.NewFromFloat(9.265593),
|
|
|
|
QuoteVolume: fixedpoint.NewFromFloat(270447.43520753),
|
|
|
|
Closed: false,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Exchange: types.ExchangeBitget,
|
|
|
|
Symbol: symbol,
|
|
|
|
StartTime: types.Time(resp[1].Ts.Time()),
|
|
|
|
EndTime: types.Time(resp[1].Ts.Time().Add(interval.Duration() - time.Millisecond)),
|
|
|
|
Interval: interval,
|
|
|
|
Open: fixedpoint.NewFromFloat(29167.33),
|
|
|
|
Close: fixedpoint.NewFromFloat(29045.3),
|
|
|
|
High: fixedpoint.NewFromFloat(29229.08),
|
|
|
|
Low: fixedpoint.NewFromFloat(29000),
|
|
|
|
Volume: fixedpoint.NewFromFloat(9.295508),
|
|
|
|
QuoteVolume: fixedpoint.NewFromFloat(270816.87513775),
|
|
|
|
Closed: false,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
assert.Equal(t, toGlobalKLines(symbol, interval, resp), expKlines)
|
|
|
|
}
|
2023-11-14 03:23:30 +00:00
|
|
|
|
|
|
|
func Test_toGlobalTimeInForce(t *testing.T) {
|
|
|
|
force, err := toGlobalTimeInForce(v2.OrderForceFOK)
|
|
|
|
assert.NoError(t, err)
|
|
|
|
assert.Equal(t, types.TimeInForceFOK, force)
|
|
|
|
|
|
|
|
force, err = toGlobalTimeInForce(v2.OrderForceGTC)
|
|
|
|
assert.NoError(t, err)
|
|
|
|
assert.Equal(t, types.TimeInForceGTC, force)
|
|
|
|
|
|
|
|
force, err = toGlobalTimeInForce(v2.OrderForcePostOnly)
|
|
|
|
assert.NoError(t, err)
|
|
|
|
assert.Equal(t, types.TimeInForceGTC, force)
|
|
|
|
|
|
|
|
force, err = toGlobalTimeInForce(v2.OrderForceIOC)
|
|
|
|
assert.NoError(t, err)
|
|
|
|
assert.Equal(t, types.TimeInForceIOC, force)
|
|
|
|
|
|
|
|
_, err = toGlobalTimeInForce("xxx")
|
|
|
|
assert.ErrorContains(t, err, "xxx")
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestOrder_processMarketBuyQuantity(t *testing.T) {
|
|
|
|
t.Run("zero qty", func(t *testing.T) {
|
|
|
|
o := Order{}
|
|
|
|
for _, s := range []v2.OrderStatus{v2.OrderStatusLive, v2.OrderStatusNew, v2.OrderStatusInit, v2.OrderStatusCancelled} {
|
|
|
|
o.Status = s
|
|
|
|
qty, err := o.processMarketBuyQuantity()
|
|
|
|
assert.NoError(t, err)
|
|
|
|
assert.Equal(t, fixedpoint.Zero, qty)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("calculate qty", func(t *testing.T) {
|
|
|
|
o := Order{
|
|
|
|
Size: fixedpoint.NewFromFloat(2),
|
|
|
|
Trade: Trade{
|
|
|
|
FillPrice: fixedpoint.NewFromFloat(1),
|
|
|
|
},
|
|
|
|
Status: v2.OrderStatusPartialFilled,
|
|
|
|
}
|
|
|
|
qty, err := o.processMarketBuyQuantity()
|
|
|
|
assert.NoError(t, err)
|
|
|
|
assert.Equal(t, fixedpoint.NewFromFloat(2), qty)
|
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("return accumulated balance", func(t *testing.T) {
|
|
|
|
o := Order{
|
|
|
|
AccBaseVolume: fixedpoint.NewFromFloat(5),
|
|
|
|
Status: v2.OrderStatusFilled,
|
|
|
|
}
|
|
|
|
qty, err := o.processMarketBuyQuantity()
|
|
|
|
assert.NoError(t, err)
|
|
|
|
assert.Equal(t, fixedpoint.NewFromFloat(5), qty)
|
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("unexpected status", func(t *testing.T) {
|
|
|
|
o := Order{
|
|
|
|
Status: "xxx",
|
|
|
|
}
|
|
|
|
_, err := o.processMarketBuyQuantity()
|
|
|
|
assert.ErrorContains(t, err, "xxx")
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestOrder_toGlobalOrder(t *testing.T) {
|
|
|
|
o := Order{
|
|
|
|
Trade: Trade{
|
|
|
|
FillPrice: fixedpoint.NewFromFloat(0.49016),
|
|
|
|
TradeId: types.StrInt64(1107950490073112582),
|
|
|
|
BaseVolume: fixedpoint.NewFromFloat(33.6558),
|
|
|
|
FillTime: types.NewMillisecondTimestampFromInt(1699881902235),
|
|
|
|
FillFee: fixedpoint.NewFromFloat(-0.0336558),
|
|
|
|
FillFeeCoin: "BGB",
|
|
|
|
TradeScope: "T",
|
|
|
|
},
|
|
|
|
InstId: "BGBUSDT",
|
|
|
|
OrderId: types.StrInt64(1107950489998626816),
|
|
|
|
ClientOrderId: "cc73aab9-1e44-4022-8458-60d8c6a08753",
|
|
|
|
Size: fixedpoint.NewFromFloat(39.0),
|
|
|
|
Notional: fixedpoint.NewFromFloat(39.0),
|
|
|
|
OrderType: v2.OrderTypeMarket,
|
|
|
|
Force: v2.OrderForceGTC,
|
|
|
|
Side: v2.SideTypeBuy,
|
|
|
|
AccBaseVolume: fixedpoint.NewFromFloat(33.6558),
|
|
|
|
PriceAvg: fixedpoint.NewFromFloat(0.49016),
|
|
|
|
Status: v2.OrderStatusPartialFilled,
|
2023-11-15 02:46:18 +00:00
|
|
|
CreatedTime: types.NewMillisecondTimestampFromInt(1699881902217),
|
|
|
|
UpdatedTime: types.NewMillisecondTimestampFromInt(1699881902248),
|
2023-11-14 03:23:30 +00:00
|
|
|
FeeDetail: nil,
|
|
|
|
EnterPointSource: "API",
|
|
|
|
}
|
|
|
|
|
|
|
|
// market buy example:
|
|
|
|
// {
|
|
|
|
// "instId":"BGBUSDT",
|
|
|
|
// "orderId":"1107950489998626816",
|
|
|
|
// "clientOid":"cc73aab9-1e44-4022-8458-60d8c6a08753",
|
|
|
|
// "size":"39.0000",
|
|
|
|
// "notional":"39.000000",
|
|
|
|
// "orderType":"market",
|
|
|
|
// "force":"gtc",
|
|
|
|
// "side":"buy",
|
|
|
|
// "fillPrice":"0.49016",
|
|
|
|
// "tradeId":"1107950490073112582",
|
|
|
|
// "baseVolume":"33.6558",
|
|
|
|
// "fillTime":"1699881902235",
|
|
|
|
// "fillFee":"-0.0336558",
|
|
|
|
// "fillFeeCoin":"BGB",
|
|
|
|
// "tradeScope":"T",
|
|
|
|
// "accBaseVolume":"33.6558",
|
|
|
|
// "priceAvg":"0.49016",
|
|
|
|
// "status":"partially_filled",
|
|
|
|
// "cTime":"1699881902217",
|
|
|
|
// "uTime":"1699881902248",
|
|
|
|
// "feeDetail":[
|
|
|
|
// {
|
|
|
|
// "feeCoin":"BGB",
|
|
|
|
// "fee":"-0.0336558"
|
|
|
|
// }
|
|
|
|
// ],
|
|
|
|
// "enterPointSource":"API"
|
|
|
|
// }
|
|
|
|
t.Run("market buy", func(t *testing.T) {
|
|
|
|
newO := o
|
|
|
|
res, err := newO.toGlobalOrder()
|
|
|
|
assert.NoError(t, err)
|
|
|
|
assert.Equal(t, types.Order{
|
|
|
|
SubmitOrder: types.SubmitOrder{
|
|
|
|
ClientOrderID: "cc73aab9-1e44-4022-8458-60d8c6a08753",
|
|
|
|
Symbol: "BGBUSDT",
|
|
|
|
Side: types.SideTypeBuy,
|
|
|
|
Type: types.OrderTypeMarket,
|
|
|
|
Quantity: newO.Size.Div(newO.FillPrice),
|
|
|
|
Price: newO.PriceAvg,
|
|
|
|
TimeInForce: types.TimeInForceGTC,
|
|
|
|
},
|
|
|
|
Exchange: types.ExchangeBitget,
|
|
|
|
OrderID: uint64(newO.OrderId),
|
|
|
|
UUID: strconv.FormatInt(int64(newO.OrderId), 10),
|
|
|
|
Status: types.OrderStatusPartiallyFilled,
|
|
|
|
ExecutedQuantity: newO.AccBaseVolume,
|
|
|
|
IsWorking: newO.Status.IsWorking(),
|
2023-11-15 02:46:18 +00:00
|
|
|
CreationTime: types.Time(newO.CreatedTime),
|
|
|
|
UpdateTime: types.Time(newO.UpdatedTime),
|
2023-11-14 03:23:30 +00:00
|
|
|
}, res)
|
|
|
|
})
|
|
|
|
|
|
|
|
// market sell example:
|
|
|
|
// {
|
|
|
|
// "instId":"BGBUSDT",
|
|
|
|
// "orderId":"1107940456212631553",
|
|
|
|
// "clientOid":"088bb971-858e-48e2-b503-85c3274edd89",
|
|
|
|
// "size":"285.0000",
|
|
|
|
// "orderType":"market",
|
|
|
|
// "force":"gtc",
|
|
|
|
// "side":"sell",
|
|
|
|
// "fillPrice":"0.48706",
|
|
|
|
// "tradeId":"1107940456278728706",
|
|
|
|
// "baseVolume":"22.5840",
|
|
|
|
// "fillTime":"1699879509992",
|
|
|
|
// "fillFee":"-0.01099976304",
|
|
|
|
// "fillFeeCoin":"USDT",
|
|
|
|
// "tradeScope":"T",
|
|
|
|
// "accBaseVolume":"45.1675",
|
|
|
|
// "priceAvg":"0.48706",
|
|
|
|
// "status":"partially_filled",
|
|
|
|
// "cTime":"1699879509976",
|
|
|
|
// "uTime":"1699879510007",
|
|
|
|
// "feeDetail":[
|
|
|
|
// {
|
|
|
|
// "feeCoin":"USDT",
|
|
|
|
// "fee":"-0.02199928255"
|
|
|
|
// }
|
|
|
|
// ],
|
|
|
|
// "enterPointSource":"API"
|
|
|
|
// }
|
|
|
|
t.Run("market sell", func(t *testing.T) {
|
|
|
|
newO := o
|
|
|
|
newO.OrderType = v2.OrderTypeMarket
|
|
|
|
newO.Side = v2.SideTypeSell
|
|
|
|
|
|
|
|
res, err := newO.toGlobalOrder()
|
|
|
|
assert.NoError(t, err)
|
|
|
|
assert.Equal(t, types.Order{
|
|
|
|
SubmitOrder: types.SubmitOrder{
|
|
|
|
ClientOrderID: "cc73aab9-1e44-4022-8458-60d8c6a08753",
|
|
|
|
Symbol: "BGBUSDT",
|
|
|
|
Side: types.SideTypeSell,
|
|
|
|
Type: types.OrderTypeMarket,
|
|
|
|
Quantity: newO.Size,
|
|
|
|
Price: newO.PriceAvg,
|
|
|
|
TimeInForce: types.TimeInForceGTC,
|
|
|
|
},
|
|
|
|
Exchange: types.ExchangeBitget,
|
|
|
|
OrderID: uint64(newO.OrderId),
|
|
|
|
UUID: strconv.FormatInt(int64(newO.OrderId), 10),
|
|
|
|
Status: types.OrderStatusPartiallyFilled,
|
|
|
|
ExecutedQuantity: newO.AccBaseVolume,
|
|
|
|
IsWorking: newO.Status.IsWorking(),
|
2023-11-15 02:46:18 +00:00
|
|
|
CreationTime: types.Time(newO.CreatedTime),
|
|
|
|
UpdateTime: types.Time(newO.UpdatedTime),
|
2023-11-14 03:23:30 +00:00
|
|
|
}, res)
|
|
|
|
})
|
|
|
|
|
|
|
|
// limit buy example:
|
|
|
|
// {
|
|
|
|
// "instId":"BGBUSDT",
|
|
|
|
// "orderId":"1107955329902481408",
|
|
|
|
// "clientOid":"c578164a-bf34-44ba-8bb7-a1538f33b1b8",
|
|
|
|
// "price":"0.49998",
|
|
|
|
// "size":"24.9990",
|
|
|
|
// "notional":"24.999000",
|
|
|
|
// "orderType":"limit",
|
|
|
|
// "force":"gtc",
|
|
|
|
// "side":"buy",
|
|
|
|
// "fillPrice":"0.49998",
|
|
|
|
// "tradeId":"1107955401758285828",
|
|
|
|
// "baseVolume":"15.9404",
|
|
|
|
// "fillTime":"1699883073272",
|
|
|
|
// "fillFee":"-0.0159404",
|
|
|
|
// "fillFeeCoin":"BGB",
|
|
|
|
// "tradeScope":"M",
|
|
|
|
// "accBaseVolume":"15.9404",
|
|
|
|
// "priceAvg":"0.49998",
|
|
|
|
// "status":"partially_filled",
|
|
|
|
// "cTime":"1699883056140",
|
|
|
|
// "uTime":"1699883073285",
|
|
|
|
// "feeDetail":[
|
|
|
|
// {
|
|
|
|
// "feeCoin":"BGB",
|
|
|
|
// "fee":"-0.0159404"
|
|
|
|
// }
|
|
|
|
// ],
|
|
|
|
// "enterPointSource":"API"
|
|
|
|
// }
|
|
|
|
t.Run("limit buy", func(t *testing.T) {
|
|
|
|
newO := o
|
2023-12-12 09:30:51 +00:00
|
|
|
newO.Price = fixedpoint.NewFromFloat(0.49998)
|
2023-11-14 03:23:30 +00:00
|
|
|
newO.OrderType = v2.OrderTypeLimit
|
|
|
|
|
|
|
|
res, err := newO.toGlobalOrder()
|
|
|
|
assert.NoError(t, err)
|
|
|
|
assert.Equal(t, types.Order{
|
|
|
|
SubmitOrder: types.SubmitOrder{
|
|
|
|
ClientOrderID: "cc73aab9-1e44-4022-8458-60d8c6a08753",
|
|
|
|
Symbol: "BGBUSDT",
|
|
|
|
Side: types.SideTypeBuy,
|
|
|
|
Type: types.OrderTypeLimit,
|
|
|
|
Quantity: newO.Size,
|
2023-12-12 09:30:51 +00:00
|
|
|
Price: newO.Price,
|
2023-11-14 03:23:30 +00:00
|
|
|
TimeInForce: types.TimeInForceGTC,
|
|
|
|
},
|
|
|
|
Exchange: types.ExchangeBitget,
|
|
|
|
OrderID: uint64(newO.OrderId),
|
|
|
|
UUID: strconv.FormatInt(int64(newO.OrderId), 10),
|
|
|
|
Status: types.OrderStatusPartiallyFilled,
|
|
|
|
ExecutedQuantity: newO.AccBaseVolume,
|
|
|
|
IsWorking: newO.Status.IsWorking(),
|
2023-11-15 02:46:18 +00:00
|
|
|
CreationTime: types.Time(newO.CreatedTime),
|
|
|
|
UpdateTime: types.Time(newO.UpdatedTime),
|
2023-11-14 03:23:30 +00:00
|
|
|
}, res)
|
|
|
|
})
|
|
|
|
|
|
|
|
// limit sell example:
|
|
|
|
// {
|
|
|
|
// "instId":"BGBUSDT",
|
|
|
|
// "orderId":"1107936497259417600",
|
|
|
|
// "clientOid":"02d4592e-091c-4b5a-aef3-6a7cf57b5e82",
|
|
|
|
// "price":"0.48710",
|
|
|
|
// "size":"280.0000",
|
|
|
|
// "orderType":"limit",
|
|
|
|
// "force":"gtc",
|
|
|
|
// "side":"sell",
|
|
|
|
// "fillPrice":"0.48710",
|
|
|
|
// "tradeId":"1107937053540556809",
|
|
|
|
// "baseVolume":"41.0593",
|
|
|
|
// "fillTime":"1699878698716",
|
|
|
|
// "fillFee":"-0.01999998503",
|
|
|
|
// "fillFeeCoin":"USDT",
|
|
|
|
// "tradeScope":"M",
|
|
|
|
// "accBaseVolume":"146.3209",
|
|
|
|
// "priceAvg":"0.48710",
|
|
|
|
// "status":"partially_filled",
|
|
|
|
// "cTime":"1699878566088",
|
|
|
|
// "uTime":"1699878698746",
|
|
|
|
// "feeDetail":[
|
|
|
|
// {
|
|
|
|
// "feeCoin":"USDT",
|
|
|
|
// "fee":"-0.07127291039"
|
|
|
|
// }
|
|
|
|
// ],
|
|
|
|
// "enterPointSource":"API"
|
|
|
|
// }
|
|
|
|
t.Run("limit sell", func(t *testing.T) {
|
|
|
|
newO := o
|
|
|
|
newO.OrderType = v2.OrderTypeLimit
|
|
|
|
newO.Side = v2.SideTypeSell
|
2023-12-12 09:30:51 +00:00
|
|
|
newO.Price = fixedpoint.NewFromFloat(0.48710)
|
2023-11-14 03:23:30 +00:00
|
|
|
|
|
|
|
res, err := newO.toGlobalOrder()
|
|
|
|
assert.NoError(t, err)
|
|
|
|
assert.Equal(t, types.Order{
|
|
|
|
SubmitOrder: types.SubmitOrder{
|
|
|
|
ClientOrderID: "cc73aab9-1e44-4022-8458-60d8c6a08753",
|
|
|
|
Symbol: "BGBUSDT",
|
|
|
|
Side: types.SideTypeSell,
|
|
|
|
Type: types.OrderTypeLimit,
|
|
|
|
Quantity: newO.Size,
|
2023-12-12 09:30:51 +00:00
|
|
|
Price: newO.Price,
|
2023-11-14 03:23:30 +00:00
|
|
|
TimeInForce: types.TimeInForceGTC,
|
|
|
|
},
|
|
|
|
Exchange: types.ExchangeBitget,
|
|
|
|
OrderID: uint64(newO.OrderId),
|
|
|
|
UUID: strconv.FormatInt(int64(newO.OrderId), 10),
|
|
|
|
Status: types.OrderStatusPartiallyFilled,
|
|
|
|
ExecutedQuantity: newO.AccBaseVolume,
|
|
|
|
IsWorking: newO.Status.IsWorking(),
|
2023-11-15 02:46:18 +00:00
|
|
|
CreationTime: types.Time(newO.CreatedTime),
|
|
|
|
UpdateTime: types.Time(newO.UpdatedTime),
|
2023-11-14 03:23:30 +00:00
|
|
|
}, res)
|
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("unexpected status", func(t *testing.T) {
|
|
|
|
newO := o
|
|
|
|
newO.Status = "xxx"
|
|
|
|
_, err := newO.toGlobalOrder()
|
|
|
|
assert.ErrorContains(t, err, "xxx")
|
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("unexpected time-in-force", func(t *testing.T) {
|
|
|
|
newO := o
|
|
|
|
newO.Force = "xxx"
|
|
|
|
_, err := newO.toGlobalOrder()
|
|
|
|
assert.ErrorContains(t, err, "xxx")
|
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("unexpected order type", func(t *testing.T) {
|
|
|
|
newO := o
|
|
|
|
newO.OrderType = "xxx"
|
|
|
|
_, err := newO.toGlobalOrder()
|
|
|
|
assert.ErrorContains(t, err, "xxx")
|
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("unexpected side", func(t *testing.T) {
|
|
|
|
newO := o
|
|
|
|
newO.Side = "xxx"
|
|
|
|
_, err := newO.toGlobalOrder()
|
|
|
|
assert.ErrorContains(t, err, "xxx")
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestOrder_toGlobalTrade(t *testing.T) {
|
|
|
|
// market buy example:
|
|
|
|
// {
|
|
|
|
// "instId":"BGBUSDT",
|
|
|
|
// "orderId":"1107950489998626816",
|
|
|
|
// "clientOid":"cc73aab9-1e44-4022-8458-60d8c6a08753",
|
|
|
|
// "size":"39.0000",
|
|
|
|
// "notional":"39.000000",
|
|
|
|
// "orderType":"market",
|
|
|
|
// "force":"gtc",
|
|
|
|
// "side":"buy",
|
|
|
|
// "fillPrice":"0.49016",
|
|
|
|
// "tradeId":"1107950490073112582",
|
|
|
|
// "baseVolume":"33.6558",
|
|
|
|
// "fillTime":"1699881902235",
|
|
|
|
// "fillFee":"-0.0336558",
|
|
|
|
// "fillFeeCoin":"BGB",
|
|
|
|
// "tradeScope":"T",
|
|
|
|
// "accBaseVolume":"33.6558",
|
|
|
|
// "priceAvg":"0.49016",
|
|
|
|
// "status":"partially_filled",
|
|
|
|
// "cTime":"1699881902217",
|
|
|
|
// "uTime":"1699881902248",
|
|
|
|
// "feeDetail":[
|
|
|
|
// {
|
|
|
|
// "feeCoin":"BGB",
|
|
|
|
// "fee":"-0.0336558"
|
|
|
|
// }
|
|
|
|
// ],
|
|
|
|
// "enterPointSource":"API"
|
|
|
|
// }
|
|
|
|
o := Order{
|
|
|
|
Trade: Trade{
|
|
|
|
FillPrice: fixedpoint.NewFromFloat(0.49016),
|
|
|
|
TradeId: types.StrInt64(1107950490073112582),
|
|
|
|
BaseVolume: fixedpoint.NewFromFloat(33.6558),
|
|
|
|
FillTime: types.NewMillisecondTimestampFromInt(1699881902235),
|
|
|
|
FillFee: fixedpoint.NewFromFloat(-0.0336558),
|
|
|
|
FillFeeCoin: "BGB",
|
|
|
|
TradeScope: "T",
|
|
|
|
},
|
|
|
|
InstId: "BGBUSDT",
|
|
|
|
OrderId: types.StrInt64(1107950489998626816),
|
|
|
|
ClientOrderId: "cc73aab9-1e44-4022-8458-60d8c6a08753",
|
|
|
|
Size: fixedpoint.NewFromFloat(39.0),
|
|
|
|
Notional: fixedpoint.NewFromFloat(39.0),
|
|
|
|
OrderType: v2.OrderTypeMarket,
|
|
|
|
Force: v2.OrderForceGTC,
|
|
|
|
Side: v2.SideTypeBuy,
|
|
|
|
AccBaseVolume: fixedpoint.NewFromFloat(33.6558),
|
|
|
|
PriceAvg: fixedpoint.NewFromFloat(0.49016),
|
|
|
|
Status: v2.OrderStatusPartialFilled,
|
2023-11-15 02:46:18 +00:00
|
|
|
CreatedTime: types.NewMillisecondTimestampFromInt(1699881902217),
|
|
|
|
UpdatedTime: types.NewMillisecondTimestampFromInt(1699881902248),
|
2023-11-14 03:23:30 +00:00
|
|
|
FeeDetail: nil,
|
|
|
|
EnterPointSource: "API",
|
|
|
|
}
|
|
|
|
|
|
|
|
t.Run("succeeds", func(t *testing.T) {
|
|
|
|
res, err := o.toGlobalTrade()
|
|
|
|
assert.NoError(t, err)
|
|
|
|
assert.Equal(t, types.Trade{
|
|
|
|
ID: uint64(o.TradeId),
|
|
|
|
OrderID: uint64(o.OrderId),
|
|
|
|
Exchange: types.ExchangeBitget,
|
|
|
|
Price: o.FillPrice,
|
|
|
|
Quantity: o.BaseVolume,
|
|
|
|
QuoteQuantity: o.FillPrice.Mul(o.BaseVolume),
|
|
|
|
Symbol: "BGBUSDT",
|
|
|
|
Side: types.SideTypeBuy,
|
|
|
|
IsBuyer: true,
|
|
|
|
IsMaker: false,
|
|
|
|
Time: types.Time(o.FillTime),
|
|
|
|
Fee: o.FillFee.Abs(),
|
|
|
|
FeeCurrency: "BGB",
|
|
|
|
}, res)
|
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("unexpected trade scope", func(t *testing.T) {
|
|
|
|
newO := o
|
|
|
|
newO.TradeScope = "xxx"
|
|
|
|
_, err := newO.toGlobalTrade()
|
|
|
|
assert.ErrorContains(t, err, "xxx")
|
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("unexpected side type", func(t *testing.T) {
|
|
|
|
newO := o
|
|
|
|
newO.Side = "xxx"
|
|
|
|
_, err := newO.toGlobalTrade()
|
|
|
|
assert.ErrorContains(t, err, "xxx")
|
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("unexpected side type", func(t *testing.T) {
|
|
|
|
newO := o
|
|
|
|
newO.Status = "xxx"
|
|
|
|
_, err := newO.toGlobalTrade()
|
|
|
|
assert.ErrorContains(t, err, "xxx")
|
|
|
|
})
|
|
|
|
}
|