diff --git a/pkg/strategy/dca2/openPosition.go b/pkg/strategy/dca2/open_position.go similarity index 81% rename from pkg/strategy/dca2/openPosition.go rename to pkg/strategy/dca2/open_position.go index 59988396e..6a25c5c64 100644 --- a/pkg/strategy/dca2/openPosition.go +++ b/pkg/strategy/dca2/open_position.go @@ -20,7 +20,7 @@ func (s *Strategy) placeOpenPositionOrders(ctx context.Context) error { return err } - orders, err := s.generateOpenPositionOrders(s.Short, s.Budget, price, s.PriceDeviation, s.MaxOrderNum) + orders, err := generateOpenPositionOrders(s.Market, s.Short, s.Budget, price, s.PriceDeviation, s.MaxOrderNum, s.OrderGroupID) if err != nil { return err } @@ -48,7 +48,7 @@ func getBestPriceUntilSuccess(ctx context.Context, ex types.Exchange, symbol str } } -func (s *Strategy) generateOpenPositionOrders(short bool, budget, price, priceDeviation fixedpoint.Value, maxOrderNum int64) ([]types.SubmitOrder, error) { +func generateOpenPositionOrders(market types.Market, short bool, budget, price, priceDeviation fixedpoint.Value, maxOrderNum int64, orderGroupID uint32) ([]types.SubmitOrder, error) { factor := fixedpoint.One.Sub(priceDeviation) if short { factor = fixedpoint.One.Add(priceDeviation) @@ -60,32 +60,37 @@ func (s *Strategy) generateOpenPositionOrders(short bool, budget, price, priceDe if i > 0 { price = price.Mul(factor) } - price = s.Market.TruncatePrice(price) - if price.Compare(s.Market.MinPrice) < 0 { + price = market.TruncatePrice(price) + if price.Compare(market.MinPrice) < 0 { break } prices = append(prices, price) } - notional, orderNum := calculateNotionalAndNum(s.Market, short, budget, prices) + notional, orderNum := calculateNotionalAndNum(market, short, budget, prices) if orderNum == 0 { return nil, fmt.Errorf("failed to calculate notional and num of open position orders, price: %s, budget: %s", price, budget) } + side := types.SideTypeBuy + if short { + side = types.SideTypeSell + } + var submitOrders []types.SubmitOrder for i := 0; i < orderNum; i++ { - quantity := s.Market.TruncateQuantity(notional.Div(prices[i])) + quantity := market.TruncateQuantity(notional.Div(prices[i])) submitOrders = append(submitOrders, types.SubmitOrder{ - Symbol: s.Symbol, - Market: s.Market, + Symbol: market.Symbol, + Market: market, Type: types.OrderTypeLimit, Price: prices[i], - Side: s.makerSide, + Side: side, TimeInForce: types.TimeInForceGTC, Quantity: quantity, Tag: orderTag, - GroupID: s.OrderGroupID, + GroupID: orderGroupID, }) } diff --git a/pkg/strategy/dca2/openPosition_test.go b/pkg/strategy/dca2/open_position_test.go similarity index 81% rename from pkg/strategy/dca2/openPosition_test.go rename to pkg/strategy/dca2/open_position_test.go index 440dadaf1..3d51bf6af 100644 --- a/pkg/strategy/dca2/openPosition_test.go +++ b/pkg/strategy/dca2/open_position_test.go @@ -12,6 +12,7 @@ import ( func newTestMarket() types.Market { return types.Market{ + Symbol: "BTCUSDT", BaseCurrency: "BTC", QuoteCurrency: "USDT", TickSize: Number(0.01), @@ -32,13 +33,13 @@ func newTestStrategy(va ...string) *Strategy { market := newTestMarket() s := &Strategy{ - logger: logrus.NewEntry(logrus.New()), - Symbol: symbol, - Market: market, - Short: false, - TakeProfitRatio: Number("10%"), - makerSide: types.SideTypeBuy, - takeProfitSide: types.SideTypeSell, + logger: logrus.NewEntry(logrus.New()), + Symbol: symbol, + Market: market, + Short: false, + TakeProfitRatio: Number("10%"), + openPositionSide: types.SideTypeBuy, + takeProfitSide: types.SideTypeSell, } return s } @@ -52,7 +53,7 @@ func TestGenerateOpenPositionOrders(t *testing.T) { budget := Number("10500") askPrice := Number("30000") margin := Number("0.05") - submitOrders, err := strategy.generateOpenPositionOrders(false, budget, askPrice, margin, 4) + submitOrders, err := generateOpenPositionOrders(strategy.Market, false, budget, askPrice, margin, 4, strategy.OrderGroupID) if !assert.NoError(err) { return } diff --git a/pkg/strategy/dca2/strategy.go b/pkg/strategy/dca2/strategy.go index 55e13433b..597eb69da 100644 --- a/pkg/strategy/dca2/strategy.go +++ b/pkg/strategy/dca2/strategy.go @@ -50,7 +50,7 @@ type Strategy struct { // private field mu sync.Mutex - makerSide types.SideType + openPositionSide types.SideType takeProfitSide types.SideType takeProfitPrice fixedpoint.Value startTimeOfNextRound time.Time @@ -106,10 +106,10 @@ func (s *Strategy) Run(ctx context.Context, _ bbgo.OrderExecutor, session *bbgo. instanceID := s.InstanceID() if s.Short { - s.makerSide = types.SideTypeSell + s.openPositionSide = types.SideTypeSell s.takeProfitSide = types.SideTypeBuy } else { - s.makerSide = types.SideTypeBuy + s.openPositionSide = types.SideTypeBuy s.takeProfitSide = types.SideTypeSell } diff --git a/pkg/strategy/dca2/takeProfit.go b/pkg/strategy/dca2/takeProfit.go deleted file mode 100644 index ea46f0b0d..000000000 --- a/pkg/strategy/dca2/takeProfit.go +++ /dev/null @@ -1,42 +0,0 @@ -package dca2 - -import ( - "context" - - "github.com/c9s/bbgo/pkg/fixedpoint" - "github.com/c9s/bbgo/pkg/types" -) - -func (s *Strategy) openTakeProfitOrders(ctx context.Context) error { - s.logger.Info("[DCA] open take profit orders") - takeProfitOrder := s.generateTakeProfitOrder(s.Short, s.Position) - createdOrders, err := s.OrderExecutor.SubmitOrders(ctx, takeProfitOrder) - if err != nil { - return err - } - - for _, createdOrder := range createdOrders { - s.logger.Info("SUBMIT TAKE PROFIT ORDER ", createdOrder.String()) - } - - return nil -} - -func (s *Strategy) generateTakeProfitOrder(short bool, position *types.Position) types.SubmitOrder { - takeProfitRatio := s.TakeProfitRatio - if s.Short { - takeProfitRatio = takeProfitRatio.Neg() - } - takeProfitPrice := s.Market.TruncatePrice(position.AverageCost.Mul(fixedpoint.One.Add(takeProfitRatio))) - return types.SubmitOrder{ - Symbol: s.Symbol, - Market: s.Market, - Type: types.OrderTypeLimit, - Price: takeProfitPrice, - Side: s.takeProfitSide, - TimeInForce: types.TimeInForceGTC, - Quantity: position.GetBase().Abs(), - Tag: orderTag, - GroupID: s.OrderGroupID, - } -} diff --git a/pkg/strategy/dca2/take_profit.go b/pkg/strategy/dca2/take_profit.go new file mode 100644 index 000000000..148312abb --- /dev/null +++ b/pkg/strategy/dca2/take_profit.go @@ -0,0 +1,43 @@ +package dca2 + +import ( + "context" + + "github.com/c9s/bbgo/pkg/fixedpoint" + "github.com/c9s/bbgo/pkg/types" +) + +func (s *Strategy) placeTakeProfitOrders(ctx context.Context) error { + s.logger.Info("[DCA] start placing take profit orders") + order := generateTakeProfitOrder(s.Market, s.Short, s.TakeProfitRatio, s.Position, s.OrderGroupID) + createdOrders, err := s.OrderExecutor.SubmitOrders(ctx, order) + if err != nil { + return err + } + + for _, createdOrder := range createdOrders { + s.logger.Info("SUBMIT TAKE PROFIT ORDER ", createdOrder.String()) + } + + return nil +} + +func generateTakeProfitOrder(market types.Market, short bool, takeProfitRatio fixedpoint.Value, position *types.Position, orderGroupID uint32) types.SubmitOrder { + side := types.SideTypeSell + if short { + takeProfitRatio = takeProfitRatio.Neg() + side = types.SideTypeBuy + } + takeProfitPrice := market.TruncatePrice(position.AverageCost.Mul(fixedpoint.One.Add(takeProfitRatio))) + return types.SubmitOrder{ + Symbol: market.Symbol, + Market: market, + Type: types.OrderTypeLimit, + Price: takeProfitPrice, + Side: side, + TimeInForce: types.TimeInForceGTC, + Quantity: position.GetBase().Abs(), + Tag: orderTag, + GroupID: orderGroupID, + } +} diff --git a/pkg/strategy/dca2/takeProfit_test.go b/pkg/strategy/dca2/take_profit_test.go similarity index 84% rename from pkg/strategy/dca2/takeProfit_test.go rename to pkg/strategy/dca2/take_profit_test.go index 47c69ddb0..1080e3ba8 100644 --- a/pkg/strategy/dca2/takeProfit_test.go +++ b/pkg/strategy/dca2/take_profit_test.go @@ -24,7 +24,7 @@ func TestGenerateTakeProfitOrder(t *testing.T) { FeeCurrency: strategy.Market.BaseCurrency, }) - o := strategy.generateTakeProfitOrder(false, position) + o := generateTakeProfitOrder(strategy.Market, false, strategy.TakeProfitRatio, position, strategy.OrderGroupID) assert.Equal(Number("31397.09"), o.Price) assert.Equal(Number("0.9985"), o.Quantity) assert.Equal(types.SideTypeSell, o.Side) @@ -38,7 +38,7 @@ func TestGenerateTakeProfitOrder(t *testing.T) { Fee: Number("0.00075"), FeeCurrency: strategy.Market.BaseCurrency, }) - o = strategy.generateTakeProfitOrder(false, position) + o = generateTakeProfitOrder(strategy.Market, false, strategy.TakeProfitRatio, position, strategy.OrderGroupID) assert.Equal(Number("30846.26"), o.Price) assert.Equal(Number("1.49775"), o.Quantity) assert.Equal(types.SideTypeSell, o.Side)