apply inventory-skew to fixedmaker

This commit is contained in:
narumi 2023-12-21 16:29:46 +08:00
parent 8ecba4378c
commit f160ea856f
3 changed files with 46 additions and 5 deletions

View File

@ -16,12 +16,19 @@ exchangeStrategies:
- on: max - on: max
fixedmaker: fixedmaker:
symbol: USDCUSDT symbol: USDCUSDT
interval: 5m interval: 1m
halfSpread: 0.05% halfSpread: 0.05%
quantity: 15 quantity: 15
orderType: LIMIT_MAKER orderType: LIMIT_MAKER
dryRun: false dryRun: true
positionHardLimit: 1500 positionHardLimit: 1500
maxPositionQuantity: 1500 maxPositionQuantity: 1500
circuitBreakLossThreshold: -0.15 circuitBreakLossThreshold: -0.15
circuitBreakEMA:
interval: 1m
window: 14
inventorySkew:
inventoryRangeMultiplier: 1.0
targetBaseRatio: 0.5

View File

@ -1,6 +1,8 @@
package fixedmaker package fixedmaker
import ( import (
"fmt"
"github.com/c9s/bbgo/pkg/fixedpoint" "github.com/c9s/bbgo/pkg/fixedpoint"
) )
@ -21,6 +23,17 @@ type InventorySkew struct {
TargetBaseRatio fixedpoint.Value `json:"targetBaseRatio"` TargetBaseRatio fixedpoint.Value `json:"targetBaseRatio"`
} }
func (s *InventorySkew) Validate() error {
if s.InventoryRangeMultiplier.Float64() < 0 {
return fmt.Errorf("inventoryRangeMultiplier should be positive")
}
if s.TargetBaseRatio.Float64() < 0 {
return fmt.Errorf("targetBaseRatio should be positive")
}
return nil
}
func (s *InventorySkew) CalculateBidAskRatios(quantity fixedpoint.Value, price fixedpoint.Value, baseBalance fixedpoint.Value, quoteBalance fixedpoint.Value) *InventorySkewBidAskRatios { func (s *InventorySkew) CalculateBidAskRatios(quantity fixedpoint.Value, price fixedpoint.Value, baseBalance fixedpoint.Value, quoteBalance fixedpoint.Value) *InventorySkewBidAskRatios {
baseValue := baseBalance.Mul(price) baseValue := baseBalance.Mul(price)
totalValue := baseValue.Add(quoteBalance) totalValue := baseValue.Add(quoteBalance)

View File

@ -35,6 +35,8 @@ type Strategy struct {
OrderType types.OrderType `json:"orderType"` OrderType types.OrderType `json:"orderType"`
DryRun bool `json:"dryRun"` DryRun bool `json:"dryRun"`
InventorySkew InventorySkew `json:"inventorySkew"`
activeOrderBook *bbgo.ActiveOrderBook activeOrderBook *bbgo.ActiveOrderBook
} }
@ -70,6 +72,10 @@ func (s *Strategy) Validate() error {
if s.HalfSpread.Float64() <= 0 { if s.HalfSpread.Float64() <= 0 {
return fmt.Errorf("halfSpread should be positive") return fmt.Errorf("halfSpread should be positive")
} }
if err := s.InventorySkew.Validate(); err != nil {
return err
}
return nil return nil
} }
@ -123,7 +129,7 @@ func (s *Strategy) Run(ctx context.Context, _ bbgo.OrderExecutor, session *bbgo.
} }
func (s *Strategy) cancelOrders(ctx context.Context) { func (s *Strategy) cancelOrders(ctx context.Context) {
if err := s.Session.Exchange.CancelOrders(ctx, s.activeOrderBook.Orders()...); err != nil { if err := s.activeOrderBook.GracefulCancel(ctx, s.Session.Exchange); err != nil {
log.WithError(err).Errorf("failed to cancel orders") log.WithError(err).Errorf("failed to cancel orders")
} }
} }
@ -180,6 +186,21 @@ func (s *Strategy) generateOrders(ctx context.Context) ([]types.SubmitOrder, err
buyPrice := midPrice.Mul(fixedpoint.One.Sub(s.HalfSpread)).Round(s.Market.PricePrecision, fixedpoint.Down) buyPrice := midPrice.Mul(fixedpoint.One.Sub(s.HalfSpread)).Round(s.Market.PricePrecision, fixedpoint.Down)
log.Infof("sell price: %s, buy price: %s", sellPrice.String(), buyPrice.String()) log.Infof("sell price: %s, buy price: %s", sellPrice.String(), buyPrice.String())
buyQuantity := s.Quantity
sellQuantity := s.Quantity
if !s.InventorySkew.InventoryRangeMultiplier.IsZero() {
ratios := s.InventorySkew.CalculateBidAskRatios(
s.Quantity,
midPrice,
baseBalance.Total(),
quoteBalance.Total(),
)
log.Infof("bid ratio: %s, ask ratio: %s", ratios.bidRatio.String(), ratios.askRatio.String())
buyQuantity = s.Quantity.Mul(ratios.bidRatio)
sellQuantity = s.Quantity.Mul(ratios.askRatio)
log.Infof("buy quantity: %s, sell quantity: %s", buyQuantity.String(), sellQuantity.String())
}
// check balance and generate orders // check balance and generate orders
amount := s.Quantity.Mul(buyPrice) amount := s.Quantity.Mul(buyPrice)
if quoteBalance.Available.Compare(amount) > 0 { if quoteBalance.Available.Compare(amount) > 0 {
@ -188,7 +209,7 @@ func (s *Strategy) generateOrders(ctx context.Context) ([]types.SubmitOrder, err
Side: types.SideTypeBuy, Side: types.SideTypeBuy,
Type: s.OrderType, Type: s.OrderType,
Price: buyPrice, Price: buyPrice,
Quantity: s.Quantity, Quantity: buyQuantity,
}) })
} else { } else {
log.Infof("not enough quote balance to buy, available: %s, amount: %s", quoteBalance.Available, amount) log.Infof("not enough quote balance to buy, available: %s, amount: %s", quoteBalance.Available, amount)
@ -200,7 +221,7 @@ func (s *Strategy) generateOrders(ctx context.Context) ([]types.SubmitOrder, err
Side: types.SideTypeSell, Side: types.SideTypeSell,
Type: s.OrderType, Type: s.OrderType,
Price: sellPrice, Price: sellPrice,
Quantity: s.Quantity, Quantity: sellQuantity,
}) })
} else { } else {
log.Infof("not enough base balance to sell, available: %s, quantity: %s", baseBalance.Available, s.Quantity) log.Infof("not enough base balance to sell, available: %s, quantity: %s", baseBalance.Available, s.Quantity)