This commit is contained in:
chiahung.lin 2023-12-07 14:38:13 +08:00
parent 092d5cfb07
commit e3d51777d3
6 changed files with 72 additions and 65 deletions

View File

@ -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,
})
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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,
}
}

View File

@ -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,
}
}

View File

@ -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)