diff --git a/pkg/strategy/dca2/open_position.go b/pkg/strategy/dca2/open_position.go index 42bc6a678..1b9abfcc4 100644 --- a/pkg/strategy/dca2/open_position.go +++ b/pkg/strategy/dca2/open_position.go @@ -21,7 +21,7 @@ func (s *Strategy) placeOpenPositionOrders(ctx context.Context) error { return err } - orders, err := generateOpenPositionOrders(s.Market, s.ProfitStats.QuoteInvestment, price, s.PriceDeviation, s.MaxOrderCount, s.OrderGroupID) + orders, err := generateOpenPositionOrders(s.Market, s.QuoteInvestment, s.ProfitStats.TotalProfit, price, s.PriceDeviation, s.MaxOrderCount, s.OrderGroupID) if err != nil { return err } @@ -60,8 +60,9 @@ func getBestPriceUntilSuccess(ctx context.Context, ex types.Exchange, symbol str return ticker.Sell, nil } -func generateOpenPositionOrders(market types.Market, quoteInvestment, price, priceDeviation fixedpoint.Value, maxOrderCount int64, orderGroupID uint32) ([]types.SubmitOrder, error) { +func generateOpenPositionOrders(market types.Market, quoteInvestment, profit, price, priceDeviation fixedpoint.Value, maxOrderCount int64, orderGroupID uint32) ([]types.SubmitOrder, error) { factor := fixedpoint.One.Sub(priceDeviation) + profit = market.TruncatePrice(profit) // calculate all valid prices var prices []fixedpoint.Value @@ -86,7 +87,13 @@ func generateOpenPositionOrders(market types.Market, quoteInvestment, price, pri var submitOrders []types.SubmitOrder for i := 0; i < orderNum; i++ { - quantity := market.TruncateQuantity(notional.Div(prices[i])) + var quantity fixedpoint.Value + // all the profit will use in the first order + if i == 0 { + quantity = market.TruncateQuantity(notional.Add(profit).Div(prices[i])) + } else { + quantity = market.TruncateQuantity(notional.Div(prices[i])) + } submitOrders = append(submitOrders, types.SubmitOrder{ Symbol: market.Symbol, Market: market, diff --git a/pkg/strategy/dca2/open_position_test.go b/pkg/strategy/dca2/open_position_test.go index 28b00c0ea..b735b7084 100644 --- a/pkg/strategy/dca2/open_position_test.go +++ b/pkg/strategy/dca2/open_position_test.go @@ -48,16 +48,17 @@ func TestGenerateOpenPositionOrders(t *testing.T) { t.Run("case 1: all config is valid and we can place enough orders", func(t *testing.T) { quoteInvestment := Number("10500") + profit := Number("300") askPrice := Number("30000") margin := Number("0.05") - submitOrders, err := generateOpenPositionOrders(strategy.Market, quoteInvestment, askPrice, margin, 4, strategy.OrderGroupID) + submitOrders, err := generateOpenPositionOrders(strategy.Market, quoteInvestment, profit, askPrice, margin, 4, strategy.OrderGroupID) if !assert.NoError(err) { return } assert.Len(submitOrders, 4) assert.Equal(Number("30000"), submitOrders[0].Price) - assert.Equal(Number("0.0875"), submitOrders[0].Quantity) + assert.Equal(Number("0.0975"), submitOrders[0].Quantity) assert.Equal(Number("28500"), submitOrders[1].Price) assert.Equal(Number("0.092105"), submitOrders[1].Quantity) assert.Equal(Number("27075"), submitOrders[2].Price) @@ -66,12 +67,29 @@ func TestGenerateOpenPositionOrders(t *testing.T) { assert.Equal(Number("0.102055"), submitOrders[3].Quantity) }) - t.Run("case 2: some orders' price will below 0, so we should not create such order", func(t *testing.T) { + t.Run("case 2: profit need to be truncated to avoid precision problem", func(t *testing.T) { + quoteInvestment := Number("1000") + profit := Number("99.47871711") + askPrice := Number("40409.72") + margin := Number("0.1") + submitOrders, err := generateOpenPositionOrders(strategy.Market, quoteInvestment, profit, askPrice, margin, 2, strategy.OrderGroupID) + if !assert.NoError(err) { + return + } + + assert.Len(submitOrders, 2) + assert.Equal(Number("40409.72"), submitOrders[0].Price) + assert.Equal(Number("0.014834"), submitOrders[0].Quantity) + assert.Equal(Number("36368.74"), submitOrders[1].Price) + assert.Equal(Number("0.013748"), submitOrders[1].Quantity) }) - t.Run("case 3: notional is too small, so we should decrease num of orders", func(t *testing.T) { + t.Run("case 3: some orders' price will below 0, so we should not create such order", func(t *testing.T) { }) - t.Run("case 4: quantity is too small, so we should decrease num of orders", func(t *testing.T) { + t.Run("case 4: notional is too small, so we should decrease num of orders", func(t *testing.T) { + }) + + t.Run("case 5: quantity is too small, so we should decrease num of orders", func(t *testing.T) { }) }