mirror of
https://github.com/c9s/bbgo.git
synced 2024-11-10 09:11:55 +00:00
FEATURE: split self trades when use MAX RESTful API to query trades
This commit is contained in:
parent
f26568e213
commit
f9f6346468
|
@ -5,7 +5,8 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/c9s/bbgo/pkg/exchange/max/maxapi"
|
max "github.com/c9s/bbgo/pkg/exchange/max/maxapi"
|
||||||
|
v3 "github.com/c9s/bbgo/pkg/exchange/max/maxapi/v3"
|
||||||
"github.com/c9s/bbgo/pkg/fixedpoint"
|
"github.com/c9s/bbgo/pkg/fixedpoint"
|
||||||
"github.com/c9s/bbgo/pkg/types"
|
"github.com/c9s/bbgo/pkg/types"
|
||||||
)
|
)
|
||||||
|
@ -193,7 +194,50 @@ func toGlobalOrder(maxOrder max.Order) (*types.Order, error) {
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func toGlobalTrade(t max.Trade) (*types.Trade, error) {
|
func toGlobalTradeV3(t v3.Trade) ([]types.Trade, error) {
|
||||||
|
var trades []types.Trade
|
||||||
|
isMargin := t.WalletType == max.WalletTypeMargin
|
||||||
|
side := toGlobalSideType(t.Side)
|
||||||
|
|
||||||
|
trade := types.Trade{
|
||||||
|
ID: t.ID,
|
||||||
|
OrderID: t.OrderID,
|
||||||
|
Price: t.Price,
|
||||||
|
Symbol: toGlobalSymbol(t.Market),
|
||||||
|
Exchange: types.ExchangeMax,
|
||||||
|
Quantity: t.Volume,
|
||||||
|
Side: side,
|
||||||
|
IsBuyer: t.IsBuyer(),
|
||||||
|
IsMaker: t.IsMaker(),
|
||||||
|
Fee: t.Fee,
|
||||||
|
FeeCurrency: toGlobalCurrency(t.FeeCurrency),
|
||||||
|
QuoteQuantity: t.Funds,
|
||||||
|
Time: types.Time(t.CreatedAt),
|
||||||
|
IsMargin: isMargin,
|
||||||
|
IsIsolated: false,
|
||||||
|
IsFutures: false,
|
||||||
|
}
|
||||||
|
|
||||||
|
if t.Side == "self-trade" {
|
||||||
|
trade.Side = types.SideTypeSell
|
||||||
|
|
||||||
|
// create trade for bid
|
||||||
|
bidTrade := trade
|
||||||
|
bidTrade.Side = types.SideTypeBuy
|
||||||
|
bidTrade.OrderID = t.SelfTradeBidOrderID
|
||||||
|
bidTrade.Fee = t.SelfTradeBidFee
|
||||||
|
bidTrade.FeeCurrency = t.SelfTradeBidFeeCurrency
|
||||||
|
bidTrade.IsBuyer = !trade.IsBuyer
|
||||||
|
bidTrade.IsMaker = !trade.IsMaker
|
||||||
|
trades = append(trades, bidTrade)
|
||||||
|
}
|
||||||
|
|
||||||
|
trades = append(trades, trade)
|
||||||
|
|
||||||
|
return trades, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func toGlobalTradeV2(t max.Trade) (*types.Trade, error) {
|
||||||
isMargin := t.WalletType == max.WalletTypeMargin
|
isMargin := t.WalletType == max.WalletTypeMargin
|
||||||
side := toGlobalSideType(t.Side)
|
side := toGlobalSideType(t.Side)
|
||||||
return &types.Trade{
|
return &types.Trade{
|
||||||
|
|
116
pkg/exchange/max/convert_test.go
Normal file
116
pkg/exchange/max/convert_test.go
Normal file
|
@ -0,0 +1,116 @@
|
||||||
|
package max
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
v3 "github.com/c9s/bbgo/pkg/exchange/max/maxapi/v3"
|
||||||
|
"github.com/c9s/bbgo/pkg/types"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Test_toGlobalTradeV3(t *testing.T) {
|
||||||
|
assert := assert.New(t)
|
||||||
|
|
||||||
|
t.Run("ask trade", func(t *testing.T) {
|
||||||
|
str := `
|
||||||
|
{
|
||||||
|
"id": 68444,
|
||||||
|
"order_id": 87,
|
||||||
|
"wallet_type": "spot",
|
||||||
|
"price": "21499.0",
|
||||||
|
"volume": "0.2658",
|
||||||
|
"funds": "5714.4",
|
||||||
|
"market": "ethtwd",
|
||||||
|
"market_name": "ETH/TWD",
|
||||||
|
"side": "bid",
|
||||||
|
"fee": "0.00001",
|
||||||
|
"fee_currency": "usdt",
|
||||||
|
"self_trade_bid_fee": "0.00001",
|
||||||
|
"self_trade_bid_fee_currency": "eth",
|
||||||
|
"self_trade_bid_order_id": 86,
|
||||||
|
"liquidity": "maker",
|
||||||
|
"created_at": 1521726960357
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
|
var trade v3.Trade
|
||||||
|
assert.NoError(json.Unmarshal([]byte(str), &trade))
|
||||||
|
|
||||||
|
trades, err := toGlobalTradeV3(trade)
|
||||||
|
assert.NoError(err)
|
||||||
|
assert.Len(trades, 1)
|
||||||
|
|
||||||
|
assert.Equal(uint64(87), trades[0].OrderID)
|
||||||
|
assert.Equal(types.SideTypeBuy, trades[0].Side)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("bid trade", func(t *testing.T) {
|
||||||
|
str := `
|
||||||
|
{
|
||||||
|
"id": 68444,
|
||||||
|
"order_id": 87,
|
||||||
|
"wallet_type": "spot",
|
||||||
|
"price": "21499.0",
|
||||||
|
"volume": "0.2658",
|
||||||
|
"funds": "5714.4",
|
||||||
|
"market": "ethtwd",
|
||||||
|
"market_name": "ETH/TWD",
|
||||||
|
"side": "ask",
|
||||||
|
"fee": "0.00001",
|
||||||
|
"fee_currency": "usdt",
|
||||||
|
"self_trade_bid_fee": "0.00001",
|
||||||
|
"self_trade_bid_fee_currency": "eth",
|
||||||
|
"self_trade_bid_order_id": 86,
|
||||||
|
"liquidity": "maker",
|
||||||
|
"created_at": 1521726960357
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
|
var trade v3.Trade
|
||||||
|
assert.NoError(json.Unmarshal([]byte(str), &trade))
|
||||||
|
|
||||||
|
trades, err := toGlobalTradeV3(trade)
|
||||||
|
assert.NoError(err)
|
||||||
|
assert.Len(trades, 1)
|
||||||
|
|
||||||
|
assert.Equal(uint64(87), trades[0].OrderID)
|
||||||
|
assert.Equal(types.SideTypeSell, trades[0].Side)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("self trade", func(t *testing.T) {
|
||||||
|
str := `
|
||||||
|
{
|
||||||
|
"id": 68444,
|
||||||
|
"order_id": 87,
|
||||||
|
"wallet_type": "spot",
|
||||||
|
"price": "21499.0",
|
||||||
|
"volume": "0.2658",
|
||||||
|
"funds": "5714.4",
|
||||||
|
"market": "ethtwd",
|
||||||
|
"market_name": "ETH/TWD",
|
||||||
|
"side": "self-trade",
|
||||||
|
"fee": "0.00001",
|
||||||
|
"fee_currency": "usdt",
|
||||||
|
"self_trade_bid_fee": "0.00001",
|
||||||
|
"self_trade_bid_fee_currency": "eth",
|
||||||
|
"self_trade_bid_order_id": 86,
|
||||||
|
"liquidity": "maker",
|
||||||
|
"created_at": 1521726960357
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
|
var trade v3.Trade
|
||||||
|
assert.NoError(json.Unmarshal([]byte(str), &trade))
|
||||||
|
|
||||||
|
trades, err := toGlobalTradeV3(trade)
|
||||||
|
assert.NoError(err)
|
||||||
|
assert.Len(trades, 2)
|
||||||
|
|
||||||
|
assert.Equal(uint64(86), trades[0].OrderID)
|
||||||
|
assert.Equal(types.SideTypeBuy, trades[0].Side)
|
||||||
|
|
||||||
|
assert.Equal(uint64(87), trades[1].OrderID)
|
||||||
|
assert.Equal(types.SideTypeSell, trades[1].Side)
|
||||||
|
})
|
||||||
|
}
|
|
@ -186,13 +186,13 @@ func (e *Exchange) QueryOrderTrades(ctx context.Context, q types.OrderQuery) ([]
|
||||||
|
|
||||||
var trades []types.Trade
|
var trades []types.Trade
|
||||||
for _, t := range maxTrades {
|
for _, t := range maxTrades {
|
||||||
localTrade, err := toGlobalTrade(t)
|
localTrades, err := toGlobalTradeV3(t)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.WithError(err).Errorf("can not convert trade: %+v", t)
|
log.WithError(err).Errorf("can not convert trade: %+v", t)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
trades = append(trades, *localTrade)
|
trades = append(trades, localTrades...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ensure everything is sorted ascending
|
// ensure everything is sorted ascending
|
||||||
|
@ -806,13 +806,13 @@ func (e *Exchange) QueryTrades(ctx context.Context, symbol string, options *type
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, t := range maxTrades {
|
for _, t := range maxTrades {
|
||||||
localTrade, err := toGlobalTrade(t)
|
localTrades, err := toGlobalTradeV3(t)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.WithError(err).Errorf("can not convert trade: %+v", t)
|
log.WithError(err).Errorf("can not convert trade: %+v", t)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
trades = append(trades, *localTrade)
|
trades = append(trades, localTrades...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ensure everything is sorted ascending
|
// ensure everything is sorted ascending
|
||||||
|
|
|
@ -6,7 +6,6 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/c9s/bbgo/pkg/exchange/max/maxapi"
|
|
||||||
"net/url"
|
"net/url"
|
||||||
"reflect"
|
"reflect"
|
||||||
"regexp"
|
"regexp"
|
||||||
|
@ -136,7 +135,7 @@ func (g *GetOrderTradesRequest) GetSlugsMap() (map[string]string, error) {
|
||||||
return slugs, nil
|
return slugs, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *GetOrderTradesRequest) Do(ctx context.Context) ([]max.Trade, error) {
|
func (g *GetOrderTradesRequest) Do(ctx context.Context) ([]Trade, error) {
|
||||||
|
|
||||||
// empty params for GET operation
|
// empty params for GET operation
|
||||||
var params interface{}
|
var params interface{}
|
||||||
|
@ -157,7 +156,7 @@ func (g *GetOrderTradesRequest) Do(ctx context.Context) ([]max.Trade, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
var apiResponse []max.Trade
|
var apiResponse []Trade
|
||||||
if err := response.DecodeJSON(&apiResponse); err != nil {
|
if err := response.DecodeJSON(&apiResponse); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -198,7 +198,7 @@ func (g *GetWalletTradesRequest) GetSlugsMap() (map[string]string, error) {
|
||||||
return slugs, nil
|
return slugs, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *GetWalletTradesRequest) Do(ctx context.Context) ([]max.Trade, error) {
|
func (g *GetWalletTradesRequest) Do(ctx context.Context) ([]Trade, error) {
|
||||||
|
|
||||||
// empty params for GET operation
|
// empty params for GET operation
|
||||||
var params interface{}
|
var params interface{}
|
||||||
|
@ -225,7 +225,7 @@ func (g *GetWalletTradesRequest) Do(ctx context.Context) ([]max.Trade, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
var apiResponse []max.Trade
|
var apiResponse []Trade
|
||||||
if err := response.DecodeJSON(&apiResponse); err != nil {
|
if err := response.DecodeJSON(&apiResponse); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,7 +15,6 @@ type WalletType = maxapi.WalletType
|
||||||
type OrderType = maxapi.OrderType
|
type OrderType = maxapi.OrderType
|
||||||
|
|
||||||
type Order = maxapi.Order
|
type Order = maxapi.Order
|
||||||
type Trade = maxapi.Trade
|
|
||||||
type Account = maxapi.Account
|
type Account = maxapi.Account
|
||||||
|
|
||||||
// OrderService manages the Order endpoint.
|
// OrderService manages the Order endpoint.
|
||||||
|
|
33
pkg/exchange/max/maxapi/v3/trade.go
Normal file
33
pkg/exchange/max/maxapi/v3/trade.go
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
package v3
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/c9s/bbgo/pkg/fixedpoint"
|
||||||
|
"github.com/c9s/bbgo/pkg/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Trade struct {
|
||||||
|
ID uint64 `json:"id" db:"exchange_id"`
|
||||||
|
WalletType WalletType `json:"wallet_type,omitempty"`
|
||||||
|
Price fixedpoint.Value `json:"price"`
|
||||||
|
Volume fixedpoint.Value `json:"volume"`
|
||||||
|
Funds fixedpoint.Value `json:"funds"`
|
||||||
|
Market string `json:"market"`
|
||||||
|
MarketName string `json:"market_name"`
|
||||||
|
CreatedAt types.MillisecondTimestamp `json:"created_at"`
|
||||||
|
Side string `json:"side"`
|
||||||
|
OrderID uint64 `json:"order_id"`
|
||||||
|
Fee fixedpoint.Value `json:"fee"` // float number as string
|
||||||
|
FeeCurrency string `json:"fee_currency"`
|
||||||
|
Liquidity string `json:"liquidity"`
|
||||||
|
SelfTradeBidFee fixedpoint.Value `json:"self_trade_bid_fee"`
|
||||||
|
SelfTradeBidFeeCurrency string `json:"self_trade_bid_fee_currency"`
|
||||||
|
SelfTradeBidOrderID uint64 `json:"self_trade_bid_order_id"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t Trade) IsBuyer() bool {
|
||||||
|
return t.Side == "bid"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t Trade) IsMaker() bool {
|
||||||
|
return t.Liquidity == "maker"
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user