mirror of
https://github.com/d0zingcat/gocryptotrader.git
synced 2026-05-18 23:16:49 +00:00
gateio: fix spot/futures order issues (#1524)
* gateio: fix spot deployment issue * fix status bug add test * to actual return type * fix linter * ch type * glorious: nits * rm space * glorious: nits --------- Co-authored-by: Ryan O'Hara-Reid <ryan.oharareid@thrasher.io>
This commit is contained in:
@@ -156,7 +156,6 @@ var (
|
||||
errTooManyOrderRequest = errors.New("too many order creation request")
|
||||
errInvalidTimeout = errors.New("invalid timeout, should be in seconds At least 5 seconds, 0 means cancel the countdown")
|
||||
errNoTickerData = errors.New("no ticker data available")
|
||||
errOnlyLimitOrderType = errors.New("only order type 'limit' is allowed")
|
||||
errNilArgument = errors.New("null argument")
|
||||
errInvalidTimezone = errors.New("invalid timezone")
|
||||
errMultipleOrders = errors.New("multiple orders passed")
|
||||
@@ -632,9 +631,6 @@ func (g *Gateio) PlaceSpotOrder(ctx context.Context, arg *CreateOrderRequestData
|
||||
if arg.CurrencyPair.IsInvalid() {
|
||||
return nil, currency.ErrCurrencyPairEmpty
|
||||
}
|
||||
if arg.Type != "limit" {
|
||||
return nil, errOnlyLimitOrderType
|
||||
}
|
||||
arg.Side = strings.ToLower(arg.Side)
|
||||
if arg.Side != "buy" && arg.Side != "sell" {
|
||||
return nil, errInvalidOrderSide
|
||||
@@ -647,7 +643,7 @@ func (g *Gateio) PlaceSpotOrder(ctx context.Context, arg *CreateOrderRequestData
|
||||
if arg.Amount <= 0 {
|
||||
return nil, errInvalidAmount
|
||||
}
|
||||
if arg.Price <= 0 {
|
||||
if arg.Price < 0 {
|
||||
return nil, errInvalidPrice
|
||||
}
|
||||
var response *SpotOrder
|
||||
|
||||
@@ -3550,3 +3550,34 @@ func TestGetTimeInForce(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, "fok", ret)
|
||||
}
|
||||
|
||||
func TestProcessFuturesOrdersPushData(t *testing.T) {
|
||||
t.Parallel()
|
||||
testCases := []struct {
|
||||
incoming string
|
||||
status order.Status
|
||||
}{
|
||||
{`{"channel":"futures.orders","event":"update","time":1541505434,"time_ms":1541505434123,"result":[{"contract":"BTC_USD","create_time":1628736847,"create_time_ms":1628736847325,"fill_price":40000.4,"finish_as":"","finish_time":1628736848,"finish_time_ms":1628736848321,"iceberg":0,"id":4872460,"is_close":false,"is_liq":false,"is_reduce_only":false,"left":0,"mkfr":-0.00025,"price":40000.4,"refr":0,"refu":0,"size":1,"status":"open","text":"-","tif":"gtc","tkfr":0.0005,"user":"110xxxxx"}]}`, order.Open},
|
||||
{`{"channel":"futures.orders","event":"update","time":1541505434,"time_ms":1541505434123,"result":[{"contract":"BTC_USD","create_time":1628736847,"create_time_ms":1628736847325,"fill_price":40000.4,"finish_as":"filled","finish_time":1628736848,"finish_time_ms":1628736848321,"iceberg":0,"id":4872460,"is_close":false,"is_liq":false,"is_reduce_only":false,"left":0,"mkfr":-0.00025,"price":40000.4,"refr":0,"refu":0,"size":1,"status":"finished","text":"-","tif":"gtc","tkfr":0.0005,"user":"110xxxxx"}]}`, order.Filled},
|
||||
{`{"channel":"futures.orders","event":"update","time":1541505434,"time_ms":1541505434123,"result":[{"contract":"BTC_USD","create_time":1628736847,"create_time_ms":1628736847325,"fill_price":40000.4,"finish_as":"cancelled","finish_time":1628736848,"finish_time_ms":1628736848321,"iceberg":0,"id":4872460,"is_close":false,"is_liq":false,"is_reduce_only":false,"left":0,"mkfr":-0.00025,"price":40000.4,"refr":0,"refu":0,"size":1,"status":"finished","text":"-","tif":"gtc","tkfr":0.0005,"user":"110xxxxx"}]}`, order.Cancelled},
|
||||
{`{"channel":"futures.orders","event":"update","time":1541505434,"time_ms":1541505434123,"result":[{"contract":"BTC_USD","create_time":1628736847,"create_time_ms":1628736847325,"fill_price":40000.4,"finish_as":"liquidated","finish_time":1628736848,"finish_time_ms":1628736848321,"iceberg":0,"id":4872460,"is_close":false,"is_liq":false,"is_reduce_only":false,"left":0,"mkfr":-0.00025,"price":40000.4,"refr":0,"refu":0,"size":1,"status":"finished","text":"-","tif":"gtc","tkfr":0.0005,"user":"110xxxxx"}]}`, order.Liquidated},
|
||||
{`{"channel":"futures.orders","event":"update","time":1541505434,"time_ms":1541505434123,"result":[{"contract":"BTC_USD","create_time":1628736847,"create_time_ms":1628736847325,"fill_price":40000.4,"finish_as":"ioc","finish_time":1628736848,"finish_time_ms":1628736848321,"iceberg":0,"id":4872460,"is_close":false,"is_liq":false,"is_reduce_only":false,"left":0,"mkfr":-0.00025,"price":40000.4,"refr":0,"refu":0,"size":1,"status":"finished","text":"-","tif":"gtc","tkfr":0.0005,"user":"110xxxxx"}]}`, order.Cancelled},
|
||||
{`{"channel":"futures.orders","event":"update","time":1541505434,"time_ms":1541505434123,"result":[{"contract":"BTC_USD","create_time":1628736847,"create_time_ms":1628736847325,"fill_price":40000.4,"finish_as":"auto_deleveraged","finish_time":1628736848,"finish_time_ms":1628736848321,"iceberg":0,"id":4872460,"is_close":false,"is_liq":false,"is_reduce_only":false,"left":0,"mkfr":-0.00025,"price":40000.4,"refr":0,"refu":0,"size":1,"status":"finished","text":"-","tif":"gtc","tkfr":0.0005,"user":"110xxxxx"}]}`, order.AutoDeleverage},
|
||||
{`{"channel":"futures.orders","event":"update","time":1541505434,"time_ms":1541505434123,"result":[{"contract":"BTC_USD","create_time":1628736847,"create_time_ms":1628736847325,"fill_price":40000.4,"finish_as":"reduce_only","finish_time":1628736848,"finish_time_ms":1628736848321,"iceberg":0,"id":4872460,"is_close":false,"is_liq":false,"is_reduce_only":false,"left":0,"mkfr":-0.00025,"price":40000.4,"refr":0,"refu":0,"size":1,"status":"finished","text":"-","tif":"gtc","tkfr":0.0005,"user":"110xxxxx"}]}`, order.Cancelled},
|
||||
{`{"channel":"futures.orders","event":"update","time":1541505434,"time_ms":1541505434123,"result":[{"contract":"BTC_USD","create_time":1628736847,"create_time_ms":1628736847325,"fill_price":40000.4,"finish_as":"position_closed","finish_time":1628736848,"finish_time_ms":1628736848321,"iceberg":0,"id":4872460,"is_close":false,"is_liq":false,"is_reduce_only":false,"left":0,"mkfr":-0.00025,"price":40000.4,"refr":0,"refu":0,"size":1,"status":"finished","text":"-","tif":"gtc","tkfr":0.0005,"user":"110xxxxx"}]}`, order.Closed},
|
||||
{`{"channel":"futures.orders","event":"update","time":1541505434,"time_ms":1541505434123,"result":[{"contract":"BTC_USD","create_time":1628736847,"create_time_ms":1628736847325,"fill_price":40000.4,"finish_as":"stp","finish_time":1628736848,"finish_time_ms":1628736848321,"iceberg":0,"id":4872460,"is_close":false,"is_liq":false,"is_reduce_only":false,"left":0,"mkfr":-0.00025,"price":40000.4,"refr":0,"refu":0,"size":1,"status":"finished","text":"-","tif":"gtc","tkfr":0.0005,"user":"110xxxxx"}]}`, order.STP},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
tc := tc
|
||||
t.Run("", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
processed, err := g.processFuturesOrdersPushData([]byte(tc.incoming), asset.Futures)
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, processed)
|
||||
for i := range processed {
|
||||
assert.Equal(t, tc.status.String(), processed[i].Status.String())
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -996,9 +996,6 @@ func (g *Gateio) SubmitOrder(ctx context.Context, s *order.Submit) (*order.Submi
|
||||
s.Pair = s.Pair.Upper()
|
||||
switch s.AssetType {
|
||||
case asset.Spot, asset.Margin, asset.CrossMargin:
|
||||
if s.Type != order.Limit {
|
||||
return nil, errOnlyLimitOrderType
|
||||
}
|
||||
switch {
|
||||
case s.Side.IsLong():
|
||||
s.Side = order.Buy
|
||||
@@ -1007,6 +1004,10 @@ func (g *Gateio) SubmitOrder(ctx context.Context, s *order.Submit) (*order.Submi
|
||||
default:
|
||||
return nil, errInvalidOrderSide
|
||||
}
|
||||
timeInForce, err := getTimeInForce(s)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
sOrder, err := g.PlaceSpotOrder(ctx, &CreateOrderRequestData{
|
||||
Side: s.Side.Lower(),
|
||||
Type: s.Type.Lower(),
|
||||
@@ -1015,6 +1016,7 @@ func (g *Gateio) SubmitOrder(ctx context.Context, s *order.Submit) (*order.Submi
|
||||
Price: types.Number(s.Price),
|
||||
CurrencyPair: s.Pair,
|
||||
Text: s.ClientOrderID,
|
||||
TimeInForce: timeInForce,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
@@ -244,7 +244,13 @@ func (g *Gateio) wsHandleFuturesData(respRaw []byte, assetType asset.Item) error
|
||||
case futuresCandlesticksChannel:
|
||||
return g.processFuturesCandlesticks(respRaw, assetType)
|
||||
case futuresOrdersChannel:
|
||||
return g.processFuturesOrdersPushData(respRaw, assetType)
|
||||
var processed []order.Detail
|
||||
processed, err = g.processFuturesOrdersPushData(respRaw, assetType)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
g.Websocket.DataHandler <- processed
|
||||
return nil
|
||||
case futuresUserTradesChannel:
|
||||
return g.procesFuturesUserTrades(respRaw, assetType)
|
||||
case futuresLiquidatesChannel:
|
||||
@@ -642,7 +648,7 @@ func (g *Gateio) processFuturesOrderbookSnapshot(event string, incoming []byte,
|
||||
return nil
|
||||
}
|
||||
|
||||
func (g *Gateio) processFuturesOrdersPushData(data []byte, assetType asset.Item) error {
|
||||
func (g *Gateio) processFuturesOrdersPushData(data []byte, assetType asset.Item) ([]order.Detail, error) {
|
||||
resp := struct {
|
||||
Time int64 `json:"time"`
|
||||
Channel string `json:"channel"`
|
||||
@@ -651,19 +657,28 @@ func (g *Gateio) processFuturesOrdersPushData(data []byte, assetType asset.Item)
|
||||
}{}
|
||||
err := json.Unmarshal(data, &resp)
|
||||
if err != nil {
|
||||
return err
|
||||
return nil, err
|
||||
}
|
||||
orderDetails := make([]order.Detail, len(resp.Result))
|
||||
for x := range resp.Result {
|
||||
status, err := order.StringToOrderStatus(func() string {
|
||||
if resp.Result[x].Status == "finished" {
|
||||
return "cancelled"
|
||||
var status order.Status
|
||||
if resp.Result[x].Status == "finished" {
|
||||
if resp.Result[x].FinishAs == "ioc" || resp.Result[x].FinishAs == "reduce_only" {
|
||||
status = order.Cancelled
|
||||
} else {
|
||||
status, err = order.StringToOrderStatus(resp.Result[x].FinishAs)
|
||||
}
|
||||
return resp.Result[x].Status
|
||||
}())
|
||||
if err != nil {
|
||||
return err
|
||||
} else {
|
||||
status, err = order.StringToOrderStatus(resp.Result[x].Status)
|
||||
}
|
||||
if err != nil {
|
||||
g.Websocket.DataHandler <- order.ClassificationError{
|
||||
Exchange: g.Name,
|
||||
OrderID: strconv.FormatInt(resp.Result[x].ID, 10),
|
||||
Err: err,
|
||||
}
|
||||
}
|
||||
|
||||
orderDetails[x] = order.Detail{
|
||||
Amount: resp.Result[x].Size,
|
||||
Exchange: g.Name,
|
||||
@@ -679,8 +694,7 @@ func (g *Gateio) processFuturesOrdersPushData(data []byte, assetType asset.Item)
|
||||
CloseTime: resp.Result[x].FinishTimeMs.Time(),
|
||||
}
|
||||
}
|
||||
g.Websocket.DataHandler <- orderDetails
|
||||
return nil
|
||||
return orderDetails, nil
|
||||
}
|
||||
|
||||
func (g *Gateio) procesFuturesUserTrades(data []byte, assetType asset.Item) error {
|
||||
|
||||
@@ -331,6 +331,7 @@ const (
|
||||
Pending
|
||||
Cancelling
|
||||
Liquidated
|
||||
STP
|
||||
)
|
||||
|
||||
// Type enforces a standard for order types across the code base
|
||||
|
||||
@@ -815,6 +815,10 @@ func (s Status) String() string {
|
||||
return "PENDING"
|
||||
case Cancelling:
|
||||
return "CANCELLING"
|
||||
case Liquidated:
|
||||
return "LIQUIDATED"
|
||||
case STP:
|
||||
return "SELF_TRADE_PREVENTION"
|
||||
default:
|
||||
return "UNKNOWN"
|
||||
}
|
||||
@@ -1141,7 +1145,7 @@ func StringToOrderStatus(status string) (Status, error) {
|
||||
return PartiallyFilledCancelled, nil
|
||||
case Open.String():
|
||||
return Open, nil
|
||||
case Closed.String():
|
||||
case Closed.String(), "POSITION_CLOSED":
|
||||
return Closed, nil
|
||||
case Cancelled.String(), "CANCELED", "ORDER_CANCELLED":
|
||||
return Cancelled, nil
|
||||
@@ -1161,6 +1165,12 @@ func StringToOrderStatus(status string) (Status, error) {
|
||||
return MarketUnavailable, nil
|
||||
case Cancelling.String():
|
||||
return Cancelling, nil
|
||||
case Liquidated.String():
|
||||
return Liquidated, nil
|
||||
case AutoDeleverage.String(), "AUTO_DELEVERAGED":
|
||||
return AutoDeleverage, nil
|
||||
case STP.String(), "STP":
|
||||
return STP, nil
|
||||
default:
|
||||
return UnknownStatus, fmt.Errorf("'%s' %w", status, errUnrecognisedOrderStatus)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user