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
```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{
Use: "submit-order",
Use: "submit-order --session SESSION --symbol SYMBOL --side SIDE --quantity QUANTITY [--price PRICE]",
SilenceUsage: true,
RunE: func(cmd *cobra.Command, args []string) error {
ctx := context.Background()

View File

@ -160,3 +160,16 @@ func toGlobalOrderType(s string) types.OrderType {
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 (
"context"
"strconv"
"time"
"github.com/c9s/bbgo/pkg/exchange/kucoin/kucoinapi"
"github.com/c9s/bbgo/pkg/types"
@ -10,6 +11,8 @@ import (
"github.com/sirupsen/logrus"
)
var ErrMissingSequence = errors.New("sequence is missing")
// OKB is the platform currency of OKEx, pre-allocate static string here
const KCS = "KCS"
@ -114,7 +117,7 @@ func (e *Exchange) QueryTickers(ctx context.Context, symbols ...string) (map[str
}
for _, s := range allTickers.Ticker {
tickers[ s.Symbol ] = toGlobalTicker(s)
tickers[s.Symbol] = toGlobalTicker(s)
}
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) {
panic("implement me")
return nil, nil
for _, order := range orders {
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) {
panic("implement me")
req := e.client.TradeService.NewListOrdersRequest()
req.Symbol(toLocalSymbol(symbol))
return nil, nil
}
@ -143,8 +201,6 @@ func (e *Exchange) NewStream() types.Stream {
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) {
orderBook, err := e.client.MarketDataService.GetOrderBook(toLocalSymbol(symbol), 100)
if err != nil {
@ -165,4 +221,4 @@ func (e *Exchange) QueryDepth(ctx context.Context, symbol string) (types.SliceOr
Bids: orderBook.Bids,
Asks: orderBook.Asks,
}, sequence, nil
}
}

View File

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

View File

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