kucoin: implement order submit

This commit is contained in:
c9s 2021-12-26 00:27:52 +08:00
parent 50fac9d491
commit 471d86c801
6 changed files with 93 additions and 14 deletions

View File

@ -91,9 +91,20 @@ func NewExchangeStandard(n types.ExchangeName, key, secret, passphrase, subAccou
} }
``` ```
## Testing order book stream
```shell
godotenv -f .env.local -- go run ./cmd/bbgo orderbook --config config/bbgo.yaml --session kucoin --symbol BTCUSDT
```
## Testing user data stream ## Testing user data stream
```shell ```shell
go run ./cmd/bbgo --config config/bbgo.yaml userdatastream --session kucoin godotenv -f .env.local -- go run ./cmd/bbgo --config config/bbgo.yaml userdatastream --session kucoin
```
### Testing order submit
```shell
godotenv -f .env.local -- go run ./cmd/bbgo submit-order --session=kucoin --symbol=BTCUSDT --side=buy --price=18000 --quantity=0.001
``` ```

View File

@ -260,9 +260,9 @@ var executeOrderCmd = &cobra.Command{
}, },
} }
// go run ./cmd/bbgo submit-order --session=ftx --symbol=BTCUSDT --side=buy --price=<price> --quantity=<quantity> // go run ./cmd/bbgo submit-order --session=ftx --symbol=BTCUSDT --side=buy --price=18000 --quantity=0.001
var submitOrderCmd = &cobra.Command{ var submitOrderCmd = &cobra.Command{
Use: "submit-order", Use: "submit-order --session SESSION --symbol SYMBOL --side SIDE --quantity QUANTITY [--price PRICE]",
SilenceUsage: true, SilenceUsage: true,
RunE: func(cmd *cobra.Command, args []string) error { RunE: func(cmd *cobra.Command, args []string) error {
ctx := context.Background() ctx := context.Background()

View File

@ -160,3 +160,16 @@ func toGlobalOrderType(s string) types.OrderType {
return "" return ""
} }
func toLocalSide(side types.SideType) kucoinapi.SideType {
switch side {
case types.SideTypeBuy:
return kucoinapi.SideTypeBuy
case types.SideTypeSell:
return kucoinapi.SideTypeSell
}
return ""
}

View File

@ -3,6 +3,7 @@ package kucoin
import ( import (
"context" "context"
"strconv" "strconv"
"time"
"github.com/c9s/bbgo/pkg/exchange/kucoin/kucoinapi" "github.com/c9s/bbgo/pkg/exchange/kucoin/kucoinapi"
"github.com/c9s/bbgo/pkg/types" "github.com/c9s/bbgo/pkg/types"
@ -10,6 +11,8 @@ import (
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
) )
var ErrMissingSequence = errors.New("sequence is missing")
// OKB is the platform currency of OKEx, pre-allocate static string here // OKB is the platform currency of OKEx, pre-allocate static string here
const KCS = "KCS" const KCS = "KCS"
@ -114,7 +117,7 @@ func (e *Exchange) QueryTickers(ctx context.Context, symbols ...string) (map[str
} }
for _, s := range allTickers.Ticker { for _, s := range allTickers.Ticker {
tickers[ s.Symbol ] = toGlobalTicker(s) tickers[s.Symbol] = toGlobalTicker(s)
} }
return tickers, nil return tickers, nil
@ -125,12 +128,67 @@ func (e *Exchange) QueryKLines(ctx context.Context, symbol string, interval type
} }
func (e *Exchange) SubmitOrders(ctx context.Context, orders ...types.SubmitOrder) (createdOrders types.OrderSlice, err error) { func (e *Exchange) SubmitOrders(ctx context.Context, orders ...types.SubmitOrder) (createdOrders types.OrderSlice, err error) {
panic("implement me") for _, order := range orders {
return nil, nil req := e.client.TradeService.NewPlaceOrderRequest()
req.Symbol(toLocalSymbol(order.Symbol))
req.Side(toLocalSide(order.Side))
if order.ClientOrderID != "" {
req.ClientOrderID(order.ClientOrderID)
}
if len(order.QuantityString) > 0 {
req.Size(order.QuantityString)
} else if order.Market.Symbol != "" {
req.Size(order.Market.FormatQuantity(order.Quantity))
} else {
req.Size(strconv.FormatFloat(order.Quantity, 'f', 8, 64))
}
// set price field for limit orders
switch order.Type {
case types.OrderTypeStopLimit, types.OrderTypeLimit:
if len(order.PriceString) > 0 {
req.Price(order.PriceString)
} else if order.Market.Symbol != "" {
req.Price(order.Market.FormatPrice(order.Price))
}
}
switch order.TimeInForce {
case "FOK":
req.TimeInForce(kucoinapi.TimeInForceFOK)
case "IOC":
req.TimeInForce(kucoinapi.TimeInForceIOC)
default:
// default to GTC
req.TimeInForce(kucoinapi.TimeInForceGTC)
}
orderResponse, err := req.Do(ctx)
if err != nil {
return createdOrders, err
}
createdOrders = append(createdOrders, types.Order{
SubmitOrder: order,
Exchange: types.ExchangeKucoin,
OrderID: hashStringID(orderResponse.OrderID),
Status: types.OrderStatusNew,
ExecutedQuantity: 0,
IsWorking: true,
CreationTime: types.Time(time.Now()),
UpdateTime: types.Time(time.Now()),
})
}
return createdOrders, err
} }
func (e *Exchange) QueryOpenOrders(ctx context.Context, symbol string) (orders []types.Order, err error) { func (e *Exchange) QueryOpenOrders(ctx context.Context, symbol string) (orders []types.Order, err error) {
panic("implement me") req := e.client.TradeService.NewListOrdersRequest()
req.Symbol(toLocalSymbol(symbol))
return nil, nil return nil, nil
} }
@ -143,8 +201,6 @@ func (e *Exchange) NewStream() types.Stream {
return NewStream(e.client, e) return NewStream(e.client, e)
} }
var ErrMissingSequence = errors.New("sequence is missing")
func (e *Exchange) QueryDepth(ctx context.Context, symbol string) (types.SliceOrderBook, int64, error) { func (e *Exchange) QueryDepth(ctx context.Context, symbol string) (types.SliceOrderBook, int64, error) {
orderBook, err := e.client.MarketDataService.GetOrderBook(toLocalSymbol(symbol), 100) orderBook, err := e.client.MarketDataService.GetOrderBook(toLocalSymbol(symbol), 100)
if err != nil { if err != nil {

View File

@ -28,7 +28,6 @@ type Stream struct {
connCancel context.CancelFunc connCancel context.CancelFunc
bullet *kucoinapi.Bullet bullet *kucoinapi.Bullet
candleEventCallbacks []func(candle *WebSocketCandleEvent, e *WebSocketEvent) candleEventCallbacks []func(candle *WebSocketCandleEvent, e *WebSocketEvent)
orderBookL2EventCallbacks []func(e *WebSocketOrderBookL2Event) orderBookL2EventCallbacks []func(e *WebSocketOrderBookL2Event)
tickerEventCallbacks []func(e *WebSocketTickerEvent) tickerEventCallbacks []func(e *WebSocketTickerEvent)
@ -41,11 +40,11 @@ type Stream struct {
func NewStream(client *kucoinapi.RestClient, ex *Exchange) *Stream { func NewStream(client *kucoinapi.RestClient, ex *Exchange) *Stream {
stream := &Stream{ stream := &Stream{
client: client,
exchange: ex,
StandardStream: types.StandardStream{ StandardStream: types.StandardStream{
ReconnectC: make(chan struct{}, 1), ReconnectC: make(chan struct{}, 1),
}, },
client: client,
exchange: ex,
lastCandle: make(map[string]types.KLine), lastCandle: make(map[string]types.KLine),
depthBuffers: make(map[string]*depth.Buffer), depthBuffers: make(map[string]*depth.Buffer),
} }

View File

@ -48,7 +48,7 @@ const (
ExchangeBacktest = ExchangeName("backtest") ExchangeBacktest = ExchangeName("backtest")
) )
var SupportedExchanges = []ExchangeName{"binance", "max", "ftx", "okex"} var SupportedExchanges = []ExchangeName{"binance", "max", "ftx", "okex", "kucoin"}
func ValidExchangeName(a string) (ExchangeName, error) { func ValidExchangeName(a string) (ExchangeName, error) {
switch strings.ToLower(a) { switch strings.ToLower(a) {