Merge pull request #787 from c9s/strategy/pivotshort

strategy: pivotshort: use active orderbook to maintain the resistance orders
This commit is contained in:
Yo-An Lin 2022-07-01 01:02:54 +08:00 committed by GitHub
commit 2816e42084
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 31 additions and 23 deletions

View File

@ -86,9 +86,9 @@ func (e *GeneralOrderExecutor) Bind() {
e.tradeCollector.BindStream(e.session.UserDataStream) e.tradeCollector.BindStream(e.session.UserDataStream)
} }
// CancelOrders cancels the given order objects directly
func (e *GeneralOrderExecutor) CancelOrders(ctx context.Context, orders ...types.Order) error { func (e *GeneralOrderExecutor) CancelOrders(ctx context.Context, orders ...types.Order) error {
err := e.session.Exchange.CancelOrders(ctx, orders...) return e.session.Exchange.CancelOrders(ctx, orders...)
return err
} }
func (e *GeneralOrderExecutor) SubmitOrders(ctx context.Context, submitOrders ...types.SubmitOrder) (types.OrderSlice, error) { func (e *GeneralOrderExecutor) SubmitOrders(ctx context.Context, submitOrders ...types.SubmitOrder) (types.OrderSlice, error) {
@ -108,8 +108,9 @@ func (e *GeneralOrderExecutor) SubmitOrders(ctx context.Context, submitOrders ..
return createdOrders, err return createdOrders, err
} }
func (e *GeneralOrderExecutor) GracefulCancel(ctx context.Context) error { // GracefulCancelActiveOrderBook cancels the orders from the active orderbook.
if err := e.activeMakerOrders.GracefulCancel(ctx, e.session.Exchange); err != nil { func (e *GeneralOrderExecutor) GracefulCancelActiveOrderBook(ctx context.Context, activeOrders *ActiveOrderBook) error {
if err := activeOrders.GracefulCancel(ctx, e.session.Exchange); err != nil {
log.WithError(err).Errorf("graceful cancel order error") log.WithError(err).Errorf("graceful cancel order error")
return err return err
} }
@ -118,6 +119,11 @@ func (e *GeneralOrderExecutor) GracefulCancel(ctx context.Context) error {
return nil return nil
} }
// GracefulCancel cancels all active maker orders
func (e *GeneralOrderExecutor) GracefulCancel(ctx context.Context) error {
return e.GracefulCancelActiveOrderBook(ctx, e.activeMakerOrders)
}
func (e *GeneralOrderExecutor) ClosePosition(ctx context.Context, percentage fixedpoint.Value, tags ...string) error { func (e *GeneralOrderExecutor) ClosePosition(ctx context.Context, percentage fixedpoint.Value, tags ...string) error {
submitOrder := e.position.NewMarketCloseOrder(percentage) submitOrder := e.position.NewMarketCloseOrder(percentage)
if submitOrder == nil { if submitOrder == nil {

View File

@ -68,16 +68,16 @@ type ResistanceShort struct {
resistancePrices []float64 resistancePrices []float64
nextResistancePrice fixedpoint.Value nextResistancePrice fixedpoint.Value
resistanceOrders []types.Order activeOrders *bbgo.ActiveOrderBook
} }
func (s *ResistanceShort) Bind(session *bbgo.ExchangeSession, orderExecutor *bbgo.GeneralOrderExecutor) { func (s *ResistanceShort) Bind(session *bbgo.ExchangeSession, orderExecutor *bbgo.GeneralOrderExecutor) {
s.session = session s.session = session
s.orderExecutor = orderExecutor s.orderExecutor = orderExecutor
s.activeOrders = bbgo.NewActiveOrderBook(s.Symbol)
s.activeOrders.BindStream(session.UserDataStream)
position := orderExecutor.Position() store, _ := session.MarketDataStore(s.Symbol)
symbol := position.Symbol
store, _ := session.MarketDataStore(symbol)
s.resistancePivot = &indicator.Pivot{IntervalWindow: s.IntervalWindow} s.resistancePivot = &indicator.Pivot{IntervalWindow: s.IntervalWindow}
s.resistancePivot.Bind(store) s.resistancePivot.Bind(store)
@ -87,22 +87,25 @@ func (s *ResistanceShort) Bind(session *bbgo.ExchangeSession, orderExecutor *bbg
lastKLine := preloadPivot(s.resistancePivot, store) lastKLine := preloadPivot(s.resistancePivot, store)
// use the last kline from the history before we get the next closed kline // use the last kline from the history before we get the next closed kline
s.findNextResistancePriceAndPlaceOrders(lastKLine.Close) if lastKLine != nil {
s.findNextResistancePriceAndPlaceOrders(lastKLine.Close)
}
session.MarketDataStream.OnKLineClosed(func(kline types.KLine) { session.MarketDataStream.OnKLineClosed(func(kline types.KLine) {
if kline.Symbol != s.Symbol || kline.Interval != s.Interval { if kline.Symbol != s.Symbol || kline.Interval != s.Interval {
return return
} }
position := s.orderExecutor.Position()
if position.IsOpened(kline.Close) {
return
}
s.findNextResistancePriceAndPlaceOrders(kline.Close) s.findNextResistancePriceAndPlaceOrders(kline.Close)
}) })
} }
func (s *ResistanceShort) findNextResistancePriceAndPlaceOrders(closePrice fixedpoint.Value) { func (s *ResistanceShort) findNextResistancePriceAndPlaceOrders(closePrice fixedpoint.Value) {
position := s.orderExecutor.Position()
if position.IsOpened(closePrice) {
return
}
minDistance := s.MinDistance.Float64() minDistance := s.MinDistance.Float64()
lows := s.resistancePivot.Lows lows := s.resistancePivot.Lows
@ -114,6 +117,7 @@ func (s *ResistanceShort) findNextResistancePriceAndPlaceOrders(closePrice fixed
if len(resistancePrices) > 0 { if len(resistancePrices) > 0 {
nextResistancePrice := fixedpoint.NewFromFloat(resistancePrices[0]) nextResistancePrice := fixedpoint.NewFromFloat(resistancePrices[0])
if nextResistancePrice.Compare(s.nextResistancePrice) != 0 { if nextResistancePrice.Compare(s.nextResistancePrice) != 0 {
bbgo.Notify("Found next resistance price: %f", nextResistancePrice.Float64())
s.nextResistancePrice = nextResistancePrice s.nextResistancePrice = nextResistancePrice
s.placeResistanceOrders(ctx, nextResistancePrice) s.placeResistanceOrders(ctx, nextResistancePrice)
} }
@ -134,10 +138,9 @@ func (s *ResistanceShort) placeResistanceOrders(ctx context.Context, resistanceP
layerSpread := s.LayerSpread layerSpread := s.LayerSpread
quantity := totalQuantity.Div(numLayersF) quantity := totalQuantity.Div(numLayersF)
if err := s.orderExecutor.CancelOrders(ctx, s.resistanceOrders...); err != nil { if err := s.orderExecutor.CancelOrders(ctx, s.activeOrders.Orders()...); err != nil {
log.WithError(err).Errorf("can not cancel resistance orders: %+v", s.resistanceOrders) log.WithError(err).Errorf("can not cancel resistance orders: %+v", s.activeOrders.Orders())
} }
s.resistanceOrders = nil
log.Infof("placing resistance orders: resistance price = %f, layer quantity = %f, num of layers = %d", resistancePrice.Float64(), quantity.Float64(), numLayers) log.Infof("placing resistance orders: resistance price = %f, layer quantity = %f, num of layers = %d", resistancePrice.Float64(), quantity.Float64(), numLayers)
@ -179,7 +182,7 @@ func (s *ResistanceShort) placeResistanceOrders(ctx context.Context, resistanceP
if err != nil { if err != nil {
log.WithError(err).Errorf("can not place resistance order") log.WithError(err).Errorf("can not place resistance order")
} }
s.resistanceOrders = createdOrders s.activeOrders.Add(createdOrders...)
} }
type Strategy struct { type Strategy struct {
@ -206,12 +209,11 @@ type Strategy struct {
session *bbgo.ExchangeSession session *bbgo.ExchangeSession
orderExecutor *bbgo.GeneralOrderExecutor orderExecutor *bbgo.GeneralOrderExecutor
lastLow fixedpoint.Value lastLow fixedpoint.Value
pivot *indicator.Pivot pivot *indicator.Pivot
resistancePivot *indicator.Pivot resistancePivot *indicator.Pivot
stopEWMA *indicator.EWMA stopEWMA *indicator.EWMA
pivotLowPrices []fixedpoint.Value pivotLowPrices []fixedpoint.Value
currentBounceShortPrice fixedpoint.Value
// StrategyController // StrategyController
bbgo.StrategyController bbgo.StrategyController