mirror of
https://github.com/c9s/bbgo.git
synced 2024-11-25 16:25:16 +00:00
Merge pull request #1494 from c9s/edwin/okx/place-order
FEATURE: [okx] generate place order request by requestgen
This commit is contained in:
commit
8eb555619f
|
@ -28,6 +28,7 @@ var (
|
|||
queryTickerLimiter = rate.NewLimiter(rate.Every(100*time.Millisecond), 10)
|
||||
queryTickersLimiter = rate.NewLimiter(rate.Every(100*time.Millisecond), 10)
|
||||
queryAccountLimiter = rate.NewLimiter(rate.Every(200*time.Millisecond), 5)
|
||||
placeOrderLimiter = rate.NewLimiter(rate.Every(30*time.Millisecond), 30)
|
||||
)
|
||||
|
||||
const ID = "okex"
|
||||
|
@ -198,63 +199,68 @@ func (e *Exchange) QueryAccountBalances(ctx context.Context) (types.BalanceMap,
|
|||
func (e *Exchange) SubmitOrder(ctx context.Context, order types.SubmitOrder) (*types.Order, error) {
|
||||
orderReq := e.client.NewPlaceOrderRequest()
|
||||
|
||||
orderReq.InstrumentID(toLocalSymbol(order.Symbol))
|
||||
orderReq.Side(toLocalSideType(order.Side))
|
||||
orderReq.Size(order.Market.FormatQuantity(order.Quantity))
|
||||
|
||||
// set price field for limit orders
|
||||
switch order.Type {
|
||||
case types.OrderTypeStopLimit, types.OrderTypeLimit:
|
||||
orderReq.Price(order.Market.FormatPrice(order.Price))
|
||||
case types.OrderTypeMarket:
|
||||
// Because our order.Quantity unit is base coin, so we indicate the target currency to Base.
|
||||
if order.Side == types.SideTypeBuy {
|
||||
orderReq.Size(order.Market.FormatQuantity(order.Quantity))
|
||||
orderReq.TargetCurrency(okexapi.TargetCurrencyBase)
|
||||
} else {
|
||||
orderReq.Size(order.Market.FormatQuantity(order.Quantity))
|
||||
orderReq.TargetCurrency(okexapi.TargetCurrencyQuote)
|
||||
}
|
||||
}
|
||||
|
||||
orderType, err := toLocalOrderType(order.Type)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
orderReq.InstrumentID(toLocalSymbol(order.Symbol))
|
||||
orderReq.Side(toLocalSideType(order.Side))
|
||||
|
||||
if order.Market.Symbol != "" {
|
||||
orderReq.Quantity(order.Market.FormatQuantity(order.Quantity))
|
||||
} else {
|
||||
// TODO report error
|
||||
orderReq.Quantity(order.Quantity.FormatString(8))
|
||||
}
|
||||
|
||||
// set price field for limit orders
|
||||
switch order.Type {
|
||||
case types.OrderTypeStopLimit, types.OrderTypeLimit:
|
||||
if order.Market.Symbol != "" {
|
||||
orderReq.Price(order.Market.FormatPrice(order.Price))
|
||||
} else {
|
||||
// TODO report error
|
||||
orderReq.Price(order.Price.FormatString(8))
|
||||
}
|
||||
}
|
||||
|
||||
switch order.TimeInForce {
|
||||
case "FOK":
|
||||
case types.TimeInForceFOK:
|
||||
orderReq.OrderType(okexapi.OrderTypeFOK)
|
||||
case "IOC":
|
||||
case types.TimeInForceIOC:
|
||||
orderReq.OrderType(okexapi.OrderTypeIOC)
|
||||
default:
|
||||
orderReq.OrderType(orderType)
|
||||
}
|
||||
|
||||
orderHead, err := orderReq.Do(ctx)
|
||||
if err := placeOrderLimiter.Wait(ctx); err != nil {
|
||||
return nil, fmt.Errorf("place order rate limiter wait error: %w", err)
|
||||
}
|
||||
|
||||
_, err = strconv.ParseInt(order.ClientOrderID, 10, 64)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("client order id should be numberic: %s, err: %w", order.ClientOrderID, err)
|
||||
}
|
||||
orderReq.ClientOrderID(order.ClientOrderID)
|
||||
|
||||
orders, err := orderReq.Do(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
orderID, err := strconv.ParseInt(orderHead.OrderID, 10, 64)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
if len(orders) != 1 {
|
||||
return nil, fmt.Errorf("unexpected length of order response: %v", orders)
|
||||
}
|
||||
|
||||
return &types.Order{
|
||||
SubmitOrder: order,
|
||||
Exchange: types.ExchangeOKEx,
|
||||
OrderID: uint64(orderID),
|
||||
Status: types.OrderStatusNew,
|
||||
ExecutedQuantity: fixedpoint.Zero,
|
||||
IsWorking: true,
|
||||
CreationTime: types.Time(time.Now()),
|
||||
UpdateTime: types.Time(time.Now()),
|
||||
IsMargin: false,
|
||||
IsIsolated: false,
|
||||
}, nil
|
||||
orderRes, err := e.QueryOrder(ctx, types.OrderQuery{
|
||||
Symbol: order.Symbol,
|
||||
OrderID: orders[0].OrderID,
|
||||
ClientOrderID: orders[0].ClientOrderID,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to query order by id: %s, clientOrderId: %s, err: %w", orders[0].OrderID, orders[0].ClientOrderID, err)
|
||||
}
|
||||
|
||||
return orderRes, nil
|
||||
|
||||
// TODO: move this to batch place orders interface
|
||||
/*
|
||||
|
|
|
@ -91,15 +91,21 @@ func TestClient_PlaceOrderRequest(t *testing.T) {
|
|||
|
||||
order, err := req.
|
||||
InstrumentID("BTC-USDT").
|
||||
TradeMode("cash").
|
||||
Side(SideTypeBuy).
|
||||
TradeMode(TradeModeCash).
|
||||
Side(SideTypeSell).
|
||||
OrderType(OrderTypeLimit).
|
||||
Price("15000").
|
||||
Quantity("0.0001").
|
||||
TargetCurrency(TargetCurrencyBase).
|
||||
Price("48000").
|
||||
Size("0.001").
|
||||
Do(ctx)
|
||||
assert.NoError(t, err)
|
||||
assert.NotEmpty(t, order)
|
||||
t.Logf("place order: %+v", order)
|
||||
|
||||
c := client.NewGetOrderDetailsRequest().OrderID(order[0].OrderID).InstrumentID("BTC-USDT")
|
||||
res, err := c.Do(ctx)
|
||||
assert.NoError(t, err)
|
||||
t.Log(res)
|
||||
}
|
||||
|
||||
func TestClient_GetPendingOrderRequest(t *testing.T) {
|
||||
|
|
67
pkg/exchange/okex/okexapi/place_order_request.go
Normal file
67
pkg/exchange/okex/okexapi/place_order_request.go
Normal file
|
@ -0,0 +1,67 @@
|
|||
package okexapi
|
||||
|
||||
import "github.com/c9s/requestgen"
|
||||
|
||||
type TradeMode string
|
||||
|
||||
const (
|
||||
TradeModeCash TradeMode = "cash"
|
||||
TradeModeIsolated TradeMode = "isolated"
|
||||
TradeModeCross TradeMode = "cross"
|
||||
)
|
||||
|
||||
type TargetCurrency string
|
||||
|
||||
const (
|
||||
TargetCurrencyBase TargetCurrency = "base_ccy"
|
||||
TargetCurrencyQuote TargetCurrency = "quote_ccy"
|
||||
)
|
||||
|
||||
//go:generate -command GetRequest requestgen -method GET -responseType .APIResponse -responseDataField Data
|
||||
//go:generate -command PostRequest requestgen -method POST -responseType .APIResponse -responseDataField Data
|
||||
|
||||
type OrderResponse struct {
|
||||
OrderID string `json:"ordId"`
|
||||
ClientOrderID string `json:"clOrdId"`
|
||||
Tag string `json:"tag"`
|
||||
Code string `json:"sCode"`
|
||||
Message string `json:"sMsg"`
|
||||
}
|
||||
|
||||
//go:generate PostRequest -url "/api/v5/trade/order" -type PlaceOrderRequest -responseDataType []OrderResponse
|
||||
type PlaceOrderRequest struct {
|
||||
client requestgen.AuthenticatedAPIClient
|
||||
|
||||
instrumentID string `param:"instId"`
|
||||
|
||||
// tdMode
|
||||
// margin mode: "cross", "isolated"
|
||||
// non-margin mode cash
|
||||
tradeMode TradeMode `param:"tdMode" validValues:"cross,isolated,cash"`
|
||||
|
||||
// A combination of case-sensitive alphanumerics, all numbers, or all letters of up to 32 characters.
|
||||
clientOrderID *string `param:"clOrdId"`
|
||||
|
||||
// A combination of case-sensitive alphanumerics, all numbers, or all letters of up to 8 characters.
|
||||
tag *string `param:"tag"`
|
||||
|
||||
// "buy" or "sell"
|
||||
side SideType `param:"side" validValues:"buy,sell"`
|
||||
|
||||
orderType OrderType `param:"ordType"`
|
||||
|
||||
size string `param:"sz"`
|
||||
|
||||
// price
|
||||
price *string `param:"px"`
|
||||
|
||||
// Whether the target currency uses the quote or base currency.
|
||||
// base_ccy: Base currency ,quote_ccy: Quote currency
|
||||
// Only applicable to SPOT Market Orders
|
||||
// Default is quote_ccy for buy, base_ccy for sell
|
||||
targetCurrency *TargetCurrency `param:"tgtCcy" validValues:"quote_ccy,base_ccy"`
|
||||
}
|
||||
|
||||
func (c *RestClient) NewPlaceOrderRequest() *PlaceOrderRequest {
|
||||
return &PlaceOrderRequest{client: c}
|
||||
}
|
|
@ -1,151 +0,0 @@
|
|||
// Code generated by "requestgen -type PlaceOrderRequest"; DO NOT EDIT.
|
||||
|
||||
package okexapi
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/url"
|
||||
)
|
||||
|
||||
func (p *PlaceOrderRequest) InstrumentID(instrumentID string) *PlaceOrderRequest {
|
||||
p.instrumentID = instrumentID
|
||||
return p
|
||||
}
|
||||
|
||||
func (p *PlaceOrderRequest) TradeMode(tradeMode string) *PlaceOrderRequest {
|
||||
p.tradeMode = tradeMode
|
||||
return p
|
||||
}
|
||||
|
||||
func (p *PlaceOrderRequest) ClientOrderID(clientOrderID string) *PlaceOrderRequest {
|
||||
p.clientOrderID = &clientOrderID
|
||||
return p
|
||||
}
|
||||
|
||||
func (p *PlaceOrderRequest) Tag(tag string) *PlaceOrderRequest {
|
||||
p.tag = &tag
|
||||
return p
|
||||
}
|
||||
|
||||
func (p *PlaceOrderRequest) Side(side SideType) *PlaceOrderRequest {
|
||||
p.side = side
|
||||
return p
|
||||
}
|
||||
|
||||
func (p *PlaceOrderRequest) OrderType(orderType OrderType) *PlaceOrderRequest {
|
||||
p.orderType = orderType
|
||||
return p
|
||||
}
|
||||
|
||||
func (p *PlaceOrderRequest) Quantity(quantity string) *PlaceOrderRequest {
|
||||
p.quantity = quantity
|
||||
return p
|
||||
}
|
||||
|
||||
func (p *PlaceOrderRequest) Price(price string) *PlaceOrderRequest {
|
||||
p.price = &price
|
||||
return p
|
||||
}
|
||||
|
||||
func (p *PlaceOrderRequest) GetParameters() (map[string]interface{}, error) {
|
||||
var params = map[string]interface{}{}
|
||||
|
||||
// check instrumentID field -> json key instId
|
||||
instrumentID := p.instrumentID
|
||||
|
||||
// assign parameter of instrumentID
|
||||
params["instId"] = instrumentID
|
||||
|
||||
// check tradeMode field -> json key tdMode
|
||||
tradeMode := p.tradeMode
|
||||
|
||||
switch tradeMode {
|
||||
case "cross", "isolated", "cash":
|
||||
params["tdMode"] = tradeMode
|
||||
|
||||
default:
|
||||
return params, fmt.Errorf("tdMode value %v is invalid", tradeMode)
|
||||
|
||||
}
|
||||
|
||||
// assign parameter of tradeMode
|
||||
params["tdMode"] = tradeMode
|
||||
|
||||
// check clientOrderID field -> json key clOrdId
|
||||
if p.clientOrderID != nil {
|
||||
clientOrderID := *p.clientOrderID
|
||||
|
||||
// assign parameter of clientOrderID
|
||||
params["clOrdId"] = clientOrderID
|
||||
}
|
||||
|
||||
// check tag field -> json key tag
|
||||
if p.tag != nil {
|
||||
tag := *p.tag
|
||||
|
||||
// assign parameter of tag
|
||||
params["tag"] = tag
|
||||
}
|
||||
|
||||
// check side field -> json key side
|
||||
side := p.side
|
||||
|
||||
switch side {
|
||||
case "buy", "sell":
|
||||
params["side"] = side
|
||||
|
||||
default:
|
||||
return params, fmt.Errorf("side value %v is invalid", side)
|
||||
|
||||
}
|
||||
|
||||
// assign parameter of side
|
||||
params["side"] = side
|
||||
|
||||
// check orderType field -> json key ordType
|
||||
orderType := p.orderType
|
||||
|
||||
// assign parameter of orderType
|
||||
params["ordType"] = orderType
|
||||
|
||||
// check quantity field -> json key sz
|
||||
quantity := p.quantity
|
||||
|
||||
// assign parameter of quantity
|
||||
params["sz"] = quantity
|
||||
|
||||
// check price field -> json key px
|
||||
if p.price != nil {
|
||||
price := *p.price
|
||||
|
||||
// assign parameter of price
|
||||
params["px"] = price
|
||||
}
|
||||
|
||||
return params, nil
|
||||
}
|
||||
|
||||
func (p *PlaceOrderRequest) GetParametersQuery() (url.Values, error) {
|
||||
query := url.Values{}
|
||||
|
||||
params, err := p.GetParameters()
|
||||
if err != nil {
|
||||
return query, err
|
||||
}
|
||||
|
||||
for k, v := range params {
|
||||
query.Add(k, fmt.Sprintf("%v", v))
|
||||
}
|
||||
|
||||
return query, nil
|
||||
}
|
||||
|
||||
func (p *PlaceOrderRequest) GetParametersJSON() ([]byte, error) {
|
||||
params, err := p.GetParameters()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return json.Marshal(params)
|
||||
}
|
305
pkg/exchange/okex/okexapi/place_order_request_requestgen.go
Normal file
305
pkg/exchange/okex/okexapi/place_order_request_requestgen.go
Normal file
|
@ -0,0 +1,305 @@
|
|||
// Code generated by "requestgen -method POST -responseType .APIResponse -responseDataField Data -url /api/v5/trade/order -type PlaceOrderRequest -responseDataType []OrderResponse"; DO NOT EDIT.
|
||||
|
||||
package okexapi
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"reflect"
|
||||
"regexp"
|
||||
)
|
||||
|
||||
func (r *PlaceOrderRequest) InstrumentID(instrumentID string) *PlaceOrderRequest {
|
||||
r.instrumentID = instrumentID
|
||||
return r
|
||||
}
|
||||
|
||||
func (r *PlaceOrderRequest) TradeMode(tradeMode TradeMode) *PlaceOrderRequest {
|
||||
r.tradeMode = tradeMode
|
||||
return r
|
||||
}
|
||||
|
||||
func (r *PlaceOrderRequest) ClientOrderID(clientOrderID string) *PlaceOrderRequest {
|
||||
r.clientOrderID = &clientOrderID
|
||||
return r
|
||||
}
|
||||
|
||||
func (r *PlaceOrderRequest) Tag(tag string) *PlaceOrderRequest {
|
||||
r.tag = &tag
|
||||
return r
|
||||
}
|
||||
|
||||
func (r *PlaceOrderRequest) Side(side SideType) *PlaceOrderRequest {
|
||||
r.side = side
|
||||
return r
|
||||
}
|
||||
|
||||
func (r *PlaceOrderRequest) OrderType(orderType OrderType) *PlaceOrderRequest {
|
||||
r.orderType = orderType
|
||||
return r
|
||||
}
|
||||
|
||||
func (r *PlaceOrderRequest) Size(size string) *PlaceOrderRequest {
|
||||
r.size = size
|
||||
return r
|
||||
}
|
||||
|
||||
func (r *PlaceOrderRequest) Price(price string) *PlaceOrderRequest {
|
||||
r.price = &price
|
||||
return r
|
||||
}
|
||||
|
||||
func (r *PlaceOrderRequest) TargetCurrency(targetCurrency TargetCurrency) *PlaceOrderRequest {
|
||||
r.targetCurrency = &targetCurrency
|
||||
return r
|
||||
}
|
||||
|
||||
// GetQueryParameters builds and checks the query parameters and returns url.Values
|
||||
func (r *PlaceOrderRequest) GetQueryParameters() (url.Values, error) {
|
||||
var params = map[string]interface{}{}
|
||||
|
||||
query := url.Values{}
|
||||
for _k, _v := range params {
|
||||
query.Add(_k, fmt.Sprintf("%v", _v))
|
||||
}
|
||||
|
||||
return query, nil
|
||||
}
|
||||
|
||||
// GetParameters builds and checks the parameters and return the result in a map object
|
||||
func (r *PlaceOrderRequest) GetParameters() (map[string]interface{}, error) {
|
||||
var params = map[string]interface{}{}
|
||||
// check instrumentID field -> json key instId
|
||||
instrumentID := r.instrumentID
|
||||
|
||||
// assign parameter of instrumentID
|
||||
params["instId"] = instrumentID
|
||||
// check tradeMode field -> json key tdMode
|
||||
tradeMode := r.tradeMode
|
||||
|
||||
// TEMPLATE check-valid-values
|
||||
switch tradeMode {
|
||||
case "cross", "isolated", "cash":
|
||||
params["tdMode"] = tradeMode
|
||||
|
||||
default:
|
||||
return nil, fmt.Errorf("tdMode value %v is invalid", tradeMode)
|
||||
|
||||
}
|
||||
// END TEMPLATE check-valid-values
|
||||
|
||||
// assign parameter of tradeMode
|
||||
params["tdMode"] = tradeMode
|
||||
// check clientOrderID field -> json key clOrdId
|
||||
if r.clientOrderID != nil {
|
||||
clientOrderID := *r.clientOrderID
|
||||
|
||||
// assign parameter of clientOrderID
|
||||
params["clOrdId"] = clientOrderID
|
||||
} else {
|
||||
}
|
||||
// check tag field -> json key tag
|
||||
if r.tag != nil {
|
||||
tag := *r.tag
|
||||
|
||||
// assign parameter of tag
|
||||
params["tag"] = tag
|
||||
} else {
|
||||
}
|
||||
// check side field -> json key side
|
||||
side := r.side
|
||||
|
||||
// TEMPLATE check-valid-values
|
||||
switch side {
|
||||
case "buy", "sell":
|
||||
params["side"] = side
|
||||
|
||||
default:
|
||||
return nil, fmt.Errorf("side value %v is invalid", side)
|
||||
|
||||
}
|
||||
// END TEMPLATE check-valid-values
|
||||
|
||||
// assign parameter of side
|
||||
params["side"] = side
|
||||
// check orderType field -> json key ordType
|
||||
orderType := r.orderType
|
||||
|
||||
// TEMPLATE check-valid-values
|
||||
switch orderType {
|
||||
case OrderTypeMarket, OrderTypeLimit, OrderTypePostOnly, OrderTypeFOK, OrderTypeIOC:
|
||||
params["ordType"] = orderType
|
||||
|
||||
default:
|
||||
return nil, fmt.Errorf("ordType value %v is invalid", orderType)
|
||||
|
||||
}
|
||||
// END TEMPLATE check-valid-values
|
||||
|
||||
// assign parameter of orderType
|
||||
params["ordType"] = orderType
|
||||
// check size field -> json key sz
|
||||
size := r.size
|
||||
|
||||
// assign parameter of size
|
||||
params["sz"] = size
|
||||
// check price field -> json key px
|
||||
if r.price != nil {
|
||||
price := *r.price
|
||||
|
||||
// assign parameter of price
|
||||
params["px"] = price
|
||||
} else {
|
||||
}
|
||||
// check targetCurrency field -> json key tgtCcy
|
||||
if r.targetCurrency != nil {
|
||||
targetCurrency := *r.targetCurrency
|
||||
|
||||
// TEMPLATE check-valid-values
|
||||
switch targetCurrency {
|
||||
case "quote_ccy", "base_ccy":
|
||||
params["tgtCcy"] = targetCurrency
|
||||
|
||||
default:
|
||||
return nil, fmt.Errorf("tgtCcy value %v is invalid", targetCurrency)
|
||||
|
||||
}
|
||||
// END TEMPLATE check-valid-values
|
||||
|
||||
// assign parameter of targetCurrency
|
||||
params["tgtCcy"] = targetCurrency
|
||||
} else {
|
||||
}
|
||||
|
||||
return params, nil
|
||||
}
|
||||
|
||||
// GetParametersQuery converts the parameters from GetParameters into the url.Values format
|
||||
func (r *PlaceOrderRequest) GetParametersQuery() (url.Values, error) {
|
||||
query := url.Values{}
|
||||
|
||||
params, err := r.GetParameters()
|
||||
if err != nil {
|
||||
return query, err
|
||||
}
|
||||
|
||||
for _k, _v := range params {
|
||||
if r.isVarSlice(_v) {
|
||||
r.iterateSlice(_v, func(it interface{}) {
|
||||
query.Add(_k+"[]", fmt.Sprintf("%v", it))
|
||||
})
|
||||
} else {
|
||||
query.Add(_k, fmt.Sprintf("%v", _v))
|
||||
}
|
||||
}
|
||||
|
||||
return query, nil
|
||||
}
|
||||
|
||||
// GetParametersJSON converts the parameters from GetParameters into the JSON format
|
||||
func (r *PlaceOrderRequest) GetParametersJSON() ([]byte, error) {
|
||||
params, err := r.GetParameters()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return json.Marshal(params)
|
||||
}
|
||||
|
||||
// GetSlugParameters builds and checks the slug parameters and return the result in a map object
|
||||
func (r *PlaceOrderRequest) GetSlugParameters() (map[string]interface{}, error) {
|
||||
var params = map[string]interface{}{}
|
||||
|
||||
return params, nil
|
||||
}
|
||||
|
||||
func (r *PlaceOrderRequest) applySlugsToUrl(url string, slugs map[string]string) string {
|
||||
for _k, _v := range slugs {
|
||||
needleRE := regexp.MustCompile(":" + _k + "\\b")
|
||||
url = needleRE.ReplaceAllString(url, _v)
|
||||
}
|
||||
|
||||
return url
|
||||
}
|
||||
|
||||
func (r *PlaceOrderRequest) iterateSlice(slice interface{}, _f func(it interface{})) {
|
||||
sliceValue := reflect.ValueOf(slice)
|
||||
for _i := 0; _i < sliceValue.Len(); _i++ {
|
||||
it := sliceValue.Index(_i).Interface()
|
||||
_f(it)
|
||||
}
|
||||
}
|
||||
|
||||
func (r *PlaceOrderRequest) isVarSlice(_v interface{}) bool {
|
||||
rt := reflect.TypeOf(_v)
|
||||
switch rt.Kind() {
|
||||
case reflect.Slice:
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (r *PlaceOrderRequest) GetSlugsMap() (map[string]string, error) {
|
||||
slugs := map[string]string{}
|
||||
params, err := r.GetSlugParameters()
|
||||
if err != nil {
|
||||
return slugs, nil
|
||||
}
|
||||
|
||||
for _k, _v := range params {
|
||||
slugs[_k] = fmt.Sprintf("%v", _v)
|
||||
}
|
||||
|
||||
return slugs, nil
|
||||
}
|
||||
|
||||
// GetPath returns the request path of the API
|
||||
func (r *PlaceOrderRequest) GetPath() string {
|
||||
return "/api/v5/trade/order"
|
||||
}
|
||||
|
||||
// Do generates the request object and send the request object to the API endpoint
|
||||
func (r *PlaceOrderRequest) Do(ctx context.Context) ([]OrderResponse, error) {
|
||||
|
||||
params, err := r.GetParameters()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
query := url.Values{}
|
||||
|
||||
var apiURL string
|
||||
|
||||
apiURL = r.GetPath()
|
||||
|
||||
req, err := r.client.NewAuthenticatedRequest(ctx, "POST", apiURL, query, params)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
response, err := r.client.SendRequest(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var apiResponse APIResponse
|
||||
if err := response.DecodeJSON(&apiResponse); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
type responseValidator interface {
|
||||
Validate() error
|
||||
}
|
||||
validator, ok := interface{}(apiResponse).(responseValidator)
|
||||
if ok {
|
||||
if err := validator.Validate(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
var data []OrderResponse
|
||||
if err := json.Unmarshal(apiResponse.Data, &data); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return data, nil
|
||||
}
|
|
@ -11,20 +11,6 @@ import (
|
|||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
type OrderResponse struct {
|
||||
OrderID string `json:"ordId"`
|
||||
ClientOrderID string `json:"clOrdId"`
|
||||
Tag string `json:"tag"`
|
||||
Code string `json:"sCode"`
|
||||
Message string `json:"sMsg"`
|
||||
}
|
||||
|
||||
func (c *RestClient) NewPlaceOrderRequest() *PlaceOrderRequest {
|
||||
return &PlaceOrderRequest{
|
||||
client: c,
|
||||
}
|
||||
}
|
||||
|
||||
func (c *RestClient) NewBatchPlaceOrderRequest() *BatchPlaceOrderRequest {
|
||||
return &BatchPlaceOrderRequest{
|
||||
client: c,
|
||||
|
@ -61,67 +47,11 @@ func (c *RestClient) NewGetTransactionDetailsRequest() *GetTransactionDetailsReq
|
|||
}
|
||||
}
|
||||
|
||||
//go:generate requestgen -type PlaceOrderRequest
|
||||
type PlaceOrderRequest struct {
|
||||
client *RestClient
|
||||
|
||||
instrumentID string `param:"instId"`
|
||||
|
||||
// tdMode
|
||||
// margin mode: "cross", "isolated"
|
||||
// non-margin mode cash
|
||||
tradeMode string `param:"tdMode" validValues:"cross,isolated,cash"`
|
||||
|
||||
// A combination of case-sensitive alphanumerics, all numbers, or all letters of up to 32 characters.
|
||||
clientOrderID *string `param:"clOrdId"`
|
||||
|
||||
// A combination of case-sensitive alphanumerics, all numbers, or all letters of up to 8 characters.
|
||||
tag *string `param:"tag"`
|
||||
|
||||
// "buy" or "sell"
|
||||
side SideType `param:"side" validValues:"buy,sell"`
|
||||
|
||||
orderType OrderType `param:"ordType"`
|
||||
|
||||
quantity string `param:"sz"`
|
||||
|
||||
// price
|
||||
price *string `param:"px"`
|
||||
}
|
||||
|
||||
func (r *PlaceOrderRequest) Parameters() map[string]interface{} {
|
||||
params, _ := r.GetParameters()
|
||||
return params
|
||||
}
|
||||
|
||||
func (r *PlaceOrderRequest) Do(ctx context.Context) (*OrderResponse, error) {
|
||||
payload := r.Parameters()
|
||||
req, err := r.client.NewAuthenticatedRequest(ctx, "POST", "/api/v5/trade/order", nil, payload)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
response, err := r.client.SendRequest(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var apiResponse APIResponse
|
||||
if err := response.DecodeJSON(&apiResponse); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var data []OrderResponse
|
||||
if err := json.Unmarshal(apiResponse.Data, &data); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(data) == 0 {
|
||||
return nil, errors.New("order create error")
|
||||
}
|
||||
|
||||
return &data[0], nil
|
||||
}
|
||||
|
||||
//go:generate requestgen -type CancelOrderRequest
|
||||
type CancelOrderRequest struct {
|
||||
client *RestClient
|
||||
|
|
Loading…
Reference in New Issue
Block a user