ftx: implement query open orders

This commit is contained in:
ycdesu 2021-03-07 12:47:11 +08:00
parent 3676450e4b
commit 6599f276db
5 changed files with 141 additions and 1 deletions

65
pkg/cmd/orders.go Normal file
View File

@ -0,0 +1,65 @@
package cmd
import (
"context"
"fmt"
log "github.com/sirupsen/logrus"
"github.com/spf13/cobra"
"github.com/c9s/bbgo/pkg/types"
)
// go run ./cmd/bbgo orders [open|closed] --session=ftx --symbol=BTC/USDT
var ordersCmd = &cobra.Command{
Use: "orders [status]",
Args: cobra.OnlyValidArgs,
// default is open which means we query open orders if you haven't provided args.
ValidArgs: []string{"", "open", "closed"},
SilenceUsage: true,
RunE: func(cmd *cobra.Command, args []string) error {
ctx := context.Background()
session, err := cmd.Flags().GetString("session")
if err != nil {
return fmt.Errorf("can't get session from flags: %w", err)
}
ex, err := newExchange(session)
if err != nil {
return err
}
symbol, err := cmd.Flags().GetString("symbol")
if err != nil {
return fmt.Errorf("can't get the symbol from flags: %w", err)
}
if symbol == "" {
return fmt.Errorf("symbol is not found")
}
status := "open"
if len(args) != 0 {
status = args[0]
}
var os []types.Order
switch status {
case "open":
os, err = ex.QueryOpenOrders(ctx, symbol)
if err != nil {
return err
}
case "closed":
default:
return fmt.Errorf("invalid status %s", status)
}
log.Infof("%s orders: %+v", status, os)
return nil
},
}
func init() {
ordersCmd.Flags().String("session", "", "the exchange session name for sync")
ordersCmd.Flags().String("symbol", "", "the trading pair, like btcusdt")
RootCmd.AddCommand(ordersCmd)
}

View File

@ -102,7 +102,21 @@ func (e *Exchange) SubmitOrders(ctx context.Context, orders ...types.SubmitOrder
}
func (e *Exchange) QueryOpenOrders(ctx context.Context, symbol string) (orders []types.Order, err error) {
panic("implement me")
resp, err := e.rest.OpenOrders(ctx, symbol)
if err != nil {
return nil, err
}
if !resp.Success {
return nil, fmt.Errorf("ftx returns querying open orders failure")
}
for _, r := range resp.Result {
o, err := toGlobalOrderFromOpenOrder(r)
if err != nil {
return nil, err
}
orders = append(orders, o)
}
return orders, nil
}
func (e *Exchange) QueryClosedOrders(ctx context.Context, symbol string, since, until time.Time, lastOrderID uint64) (orders []types.Order, err error) {

View File

@ -20,6 +20,7 @@ import (
type restRequest struct {
*balanceRequest
*orderRequest
key, secret string
// Optional sub-account name
@ -42,6 +43,7 @@ func newRestRequest(c *http.Client, baseURL *url.URL) *restRequest {
}
r.balanceRequest = &balanceRequest{restRequest: r}
r.orderRequest = &orderRequest{restRequest: r}
return r
}
@ -75,6 +77,7 @@ func (r *restRequest) buildURL() (*url.URL, error) {
}
func (r *restRequest) Payloads(payloads map[string]interface{}) *restRequest {
r.p = make(map[string]interface{})
for k, v := range payloads {
r.p[k] = v
}

View File

@ -0,0 +1,30 @@
package ftx
import (
"context"
"encoding/json"
"fmt"
)
type orderRequest struct {
*restRequest
}
func (r *orderRequest) OpenOrders(ctx context.Context, market string) (orders, error) {
resp, err := r.
Method("GET").
ReferenceURL("api/orders").
Payloads(map[string]interface{}{"market": market}).
DoAuthenticatedRequest(ctx)
if err != nil {
return orders{}, err
}
var o orders
if err := json.Unmarshal(resp.Body, &o); err != nil {
return orders{}, fmt.Errorf("failed to unmarshal open orders response body to json: %w", err)
}
return o, nil
}

View File

@ -1,5 +1,7 @@
package ftx
import "time"
type balances struct {
Success bool `json:"Success"`
@ -9,3 +11,29 @@ type balances struct {
Total float64 `json:"total"`
} `json:"result"`
}
type orders struct {
Success bool `json:"Success"`
Result []order `json:"result"`
}
type order struct {
CreatedAt time.Time `json:"createdAt"`
FilledSize float64 `json:"filledSize"`
// Future field is not defined in the response format table but in the response example.
Future string `json:"future"`
ID int64 `json:"id"`
Market string `json:"market"`
Price float64 `json:"price"`
AvgFillPrice float64 `json:"avgFillPrice"`
RemainingSize float64 `json:"remainingSize"`
Side string `json:"side"`
Size float64 `json:"size"`
Status string `json:"status"`
Type string `json:"type"`
ReduceOnly bool `json:"reduceOnly"`
Ioc bool `json:"ioc"`
PostOnly bool `json:"postOnly"`
ClientId string `json:"clientId"`
}