Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

FEATURE: redesign and refactor twap order executor #1697

Merged
merged 12 commits into from
Aug 20, 2024
9 changes: 6 additions & 3 deletions pkg/bbgo/order_executor_general.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,9 @@ var quantityReduceDelta = fixedpoint.NewFromFloat(0.005)
// This is for the maximum retries
const submitOrderRetryLimit = 5

// BaseOrderExecutor provides the common accessors for order executor
type BaseOrderExecutor struct {
exchange types.Exchange
session *ExchangeSession
activeMakerOrders *ActiveOrderBook
orderStore *core.OrderStore
Expand All @@ -43,8 +45,8 @@ func (e *BaseOrderExecutor) ActiveMakerOrders() *ActiveOrderBook {

// GracefulCancel cancels all active maker orders if orders are not given, otherwise cancel all the given orders
func (e *BaseOrderExecutor) GracefulCancel(ctx context.Context, orders ...types.Order) error {
if err := e.activeMakerOrders.GracefulCancel(ctx, e.session.Exchange, orders...); err != nil {
return errors.Wrap(err, "graceful cancel error")
if err := e.activeMakerOrders.GracefulCancel(ctx, e.exchange, orders...); err != nil {
return errors.Wrap(err, "graceful cancel order error")
}

return nil
Expand Down Expand Up @@ -84,6 +86,7 @@ func NewGeneralOrderExecutor(
executor := &GeneralOrderExecutor{
BaseOrderExecutor: BaseOrderExecutor{
session: session,
exchange: session.Exchange,
activeMakerOrders: NewActiveOrderBook(symbol),
orderStore: orderStore,
},
Expand Down Expand Up @@ -111,7 +114,7 @@ func (e *GeneralOrderExecutor) SetMaxRetries(maxRetries uint) {
}

func (e *GeneralOrderExecutor) startMarginAssetUpdater(ctx context.Context) {
marginService, ok := e.session.Exchange.(types.MarginBorrowRepayService)
marginService, ok := e.exchange.(types.MarginBorrowRepayService)
if !ok {
log.Warnf("session %s (%T) exchange does not support MarginBorrowRepayService", e.session.Name, e.session.Exchange)
return
Expand Down
1 change: 1 addition & 0 deletions pkg/bbgo/order_executor_simple.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ func NewSimpleOrderExecutor(session *ExchangeSession) *SimpleOrderExecutor {
return &SimpleOrderExecutor{
BaseOrderExecutor: BaseOrderExecutor{
session: session,
exchange: session.Exchange,
activeMakerOrders: NewActiveOrderBook(""),
orderStore: core.NewOrderStore(""),
},
Expand Down
3 changes: 2 additions & 1 deletion pkg/cmd/orders.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (
"github.com/spf13/cobra"

"github.com/c9s/bbgo/pkg/fixedpoint"
"github.com/c9s/bbgo/pkg/twap"

"github.com/c9s/bbgo/pkg/bbgo"
"github.com/c9s/bbgo/pkg/types"
Expand Down Expand Up @@ -255,7 +256,7 @@ var executeOrderCmd = &cobra.Command{
executionCtx, cancelExecution := context.WithCancel(ctx)
defer cancelExecution()

execution := &bbgo.TwapExecution{
execution := &twap.StreamExecutor{
Session: session,
Symbol: symbol,
Side: side,
Expand Down
16 changes: 9 additions & 7 deletions pkg/exchange/binance/exchange.go
Original file line number Diff line number Diff line change
Expand Up @@ -995,13 +995,15 @@ func (e *Exchange) submitMarginOrder(ctx context.Context, order types.SubmitOrde
}

// could be IOC or FOK
if len(order.TimeInForce) > 0 {
// TODO: check the TimeInForce value
req.TimeInForce(binance.TimeInForceType(order.TimeInForce))
} else {
switch order.Type {
case types.OrderTypeLimit, types.OrderTypeStopLimit:
req.TimeInForce(binance.TimeInForceTypeGTC)
switch order.Type {
case types.OrderTypeLimit, types.OrderTypeStopLimit:
req.TimeInForce(binance.TimeInForceTypeGTC)
case types.OrderTypeLimitMaker:
// do not set TimeInForce for LimitMaker
default:
if len(order.TimeInForce) > 0 {
// TODO: check the TimeInForce value
req.TimeInForce(binance.TimeInForceType(order.TimeInForce))
}
}

Expand Down
2 changes: 1 addition & 1 deletion pkg/risk/riskcontrol/position_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ func Test_ModifiedQuantity(t *testing.T) {
BaseCurrency: "BTC",
},
}
orderExecutor := bbgo.NewGeneralOrderExecutor(nil, "BTCUSDT", "strategy", "strategy-1", pos)
orderExecutor := bbgo.NewGeneralOrderExecutor(&bbgo.ExchangeSession{}, "BTCUSDT", "strategy", "strategy-1", pos)
riskControl := NewPositionRiskControl(orderExecutor, fixedpoint.NewFromInt(10), fixedpoint.NewFromInt(2))

cases := []struct {
Expand Down
7 changes: 4 additions & 3 deletions pkg/strategy/autobuy/strategy.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,14 @@ import (
"fmt"
"sync"

"github.com/robfig/cron/v3"
"github.com/sirupsen/logrus"

"github.com/c9s/bbgo/pkg/bbgo"
"github.com/c9s/bbgo/pkg/fixedpoint"
indicatorv2 "github.com/c9s/bbgo/pkg/indicator/v2"
"github.com/c9s/bbgo/pkg/strategy/common"
"github.com/c9s/bbgo/pkg/types"
"github.com/robfig/cron/v3"
"github.com/sirupsen/logrus"
)

const ID = "autobuy"
Expand Down Expand Up @@ -128,7 +129,7 @@ func (s *Strategy) autobuy(ctx context.Context) {
}

side := types.SideTypeBuy
price := s.PriceType.Map(ticker, side)
price := s.PriceType.GetPrice(ticker, side)

if price.Float64() > s.boll.UpBand.Last(0) {
log.Infof("price %s is higher than upper band %f, skip", price.String(), s.boll.UpBand.Last(0))
Expand Down
17 changes: 9 additions & 8 deletions pkg/strategy/dca2/recover_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,10 @@ import (
"testing"
"time"

"github.com/stretchr/testify/assert"

"github.com/c9s/bbgo/pkg/bbgo"
"github.com/c9s/bbgo/pkg/types"
"github.com/stretchr/testify/assert"
)

func generateTestOrder(side types.SideType, status types.OrderStatus, createdAt time.Time) types.Order {
Expand All @@ -29,7 +30,7 @@ func Test_RecoverState(t *testing.T) {
t.Run("new strategy", func(t *testing.T) {
currentRound := Round{}
position := types.NewPositionFromMarket(strategy.Market)
orderExecutor := bbgo.NewGeneralOrderExecutor(nil, strategy.Symbol, ID, "", position)
orderExecutor := bbgo.NewGeneralOrderExecutor(&bbgo.ExchangeSession{}, strategy.Symbol, ID, "", position)
state, err := recoverState(context.Background(), 5, currentRound, orderExecutor)
assert.NoError(t, err)
assert.Equal(t, WaitToOpenPosition, state)
Expand All @@ -47,7 +48,7 @@ func Test_RecoverState(t *testing.T) {
},
}
position := types.NewPositionFromMarket(strategy.Market)
orderExecutor := bbgo.NewGeneralOrderExecutor(nil, strategy.Symbol, ID, "", position)
orderExecutor := bbgo.NewGeneralOrderExecutor(&bbgo.ExchangeSession{}, strategy.Symbol, ID, "", position)
state, err := recoverState(context.Background(), 5, currentRound, orderExecutor)
assert.NoError(t, err)
assert.Equal(t, OpenPositionReady, state)
Expand All @@ -65,7 +66,7 @@ func Test_RecoverState(t *testing.T) {
},
}
position := types.NewPositionFromMarket(strategy.Market)
orderExecutor := bbgo.NewGeneralOrderExecutor(nil, strategy.Symbol, ID, "", position)
orderExecutor := bbgo.NewGeneralOrderExecutor(&bbgo.ExchangeSession{}, strategy.Symbol, ID, "", position)
state, err := recoverState(context.Background(), 5, currentRound, orderExecutor)
assert.NoError(t, err)
assert.Equal(t, OpenPositionOrderFilled, state)
Expand All @@ -83,7 +84,7 @@ func Test_RecoverState(t *testing.T) {
},
}
position := types.NewPositionFromMarket(strategy.Market)
orderExecutor := bbgo.NewGeneralOrderExecutor(nil, strategy.Symbol, ID, "", position)
orderExecutor := bbgo.NewGeneralOrderExecutor(&bbgo.ExchangeSession{}, strategy.Symbol, ID, "", position)
state, err := recoverState(context.Background(), 5, currentRound, orderExecutor)
assert.NoError(t, err)
assert.Equal(t, OpenPositionOrdersCancelling, state)
Expand All @@ -101,7 +102,7 @@ func Test_RecoverState(t *testing.T) {
},
}
position := types.NewPositionFromMarket(strategy.Market)
orderExecutor := bbgo.NewGeneralOrderExecutor(nil, strategy.Symbol, ID, "", position)
orderExecutor := bbgo.NewGeneralOrderExecutor(&bbgo.ExchangeSession{}, strategy.Symbol, ID, "", position)
state, err := recoverState(context.Background(), 5, currentRound, orderExecutor)
assert.NoError(t, err)
assert.Equal(t, OpenPositionOrdersCancelling, state)
Expand All @@ -122,7 +123,7 @@ func Test_RecoverState(t *testing.T) {
},
}
position := types.NewPositionFromMarket(strategy.Market)
orderExecutor := bbgo.NewGeneralOrderExecutor(nil, strategy.Symbol, ID, "", position)
orderExecutor := bbgo.NewGeneralOrderExecutor(&bbgo.ExchangeSession{}, strategy.Symbol, ID, "", position)
state, err := recoverState(context.Background(), 5, currentRound, orderExecutor)
assert.NoError(t, err)
assert.Equal(t, TakeProfitReady, state)
Expand All @@ -143,7 +144,7 @@ func Test_RecoverState(t *testing.T) {
},
}
position := types.NewPositionFromMarket(strategy.Market)
orderExecutor := bbgo.NewGeneralOrderExecutor(nil, strategy.Symbol, ID, "", position)
orderExecutor := bbgo.NewGeneralOrderExecutor(&bbgo.ExchangeSession{}, strategy.Symbol, ID, "", position)
state, err := recoverState(context.Background(), 5, currentRound, orderExecutor)
assert.NoError(t, err)
assert.Equal(t, WaitToOpenPosition, state)
Expand Down
2 changes: 1 addition & 1 deletion pkg/strategy/rebalance/strategy.go
Original file line number Diff line number Diff line change
Expand Up @@ -262,7 +262,7 @@ func (s *Strategy) generateOrder(ctx context.Context) (*types.SubmitOrder, error
}
quantity = market.RoundDownQuantityByPrecision(quantity)

price := s.PriceType.Map(ticker, side)
price := s.PriceType.GetPrice(ticker, side)

if s.MaxAmount.Float64() > 0 {
quantity = bbgo.AdjustQuantityByMaxAmount(quantity, price, s.MaxAmount)
Expand Down
Loading
Loading