mirror of
https://github.com/c9s/bbgo.git
synced 2024-11-10 09:11:55 +00:00
wall: refactor wall strategy with common.Strategy
This commit is contained in:
parent
a8ddf9a8d5
commit
9dc57f01cd
|
@ -10,6 +10,14 @@ sessions:
|
||||||
exchange: max
|
exchange: max
|
||||||
envVarPrefix: MAX
|
envVarPrefix: MAX
|
||||||
|
|
||||||
|
|
||||||
|
logging:
|
||||||
|
trade: true
|
||||||
|
order: true
|
||||||
|
# fields:
|
||||||
|
# env: prod
|
||||||
|
|
||||||
|
|
||||||
exchangeStrategies:
|
exchangeStrategies:
|
||||||
|
|
||||||
- on: max
|
- on: max
|
||||||
|
@ -33,6 +41,6 @@ exchangeStrategies:
|
||||||
byLayer:
|
byLayer:
|
||||||
linear:
|
linear:
|
||||||
domain: [ 1, 3 ]
|
domain: [ 1, 3 ]
|
||||||
range: [ 10.0, 30.0 ]
|
range: [ 10000.0, 30000.0 ]
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -6,12 +6,11 @@ import (
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/c9s/bbgo/pkg/core"
|
|
||||||
"github.com/c9s/bbgo/pkg/util"
|
|
||||||
|
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
|
|
||||||
|
"github.com/c9s/bbgo/pkg/strategy/common"
|
||||||
|
|
||||||
"github.com/c9s/bbgo/pkg/bbgo"
|
"github.com/c9s/bbgo/pkg/bbgo"
|
||||||
"github.com/c9s/bbgo/pkg/fixedpoint"
|
"github.com/c9s/bbgo/pkg/fixedpoint"
|
||||||
"github.com/c9s/bbgo/pkg/types"
|
"github.com/c9s/bbgo/pkg/types"
|
||||||
|
@ -31,8 +30,9 @@ func init() {
|
||||||
}
|
}
|
||||||
|
|
||||||
type Strategy struct {
|
type Strategy struct {
|
||||||
|
*common.Strategy
|
||||||
|
|
||||||
Environment *bbgo.Environment
|
Environment *bbgo.Environment
|
||||||
StandardIndicatorSet *bbgo.StandardIndicatorSet
|
|
||||||
Market types.Market
|
Market types.Market
|
||||||
|
|
||||||
// Symbol is the market symbol you want to trade
|
// Symbol is the market symbol you want to trade
|
||||||
|
@ -60,18 +60,8 @@ type Strategy struct {
|
||||||
|
|
||||||
session *bbgo.ExchangeSession
|
session *bbgo.ExchangeSession
|
||||||
|
|
||||||
// persistence fields
|
|
||||||
Position *types.Position `json:"position,omitempty" persistence:"position"`
|
|
||||||
ProfitStats *types.ProfitStats `json:"profitStats,omitempty" persistence:"profit_stats"`
|
|
||||||
|
|
||||||
activeAdjustmentOrders *bbgo.ActiveOrderBook
|
activeAdjustmentOrders *bbgo.ActiveOrderBook
|
||||||
activeWallOrders *bbgo.ActiveOrderBook
|
activeWallOrders *bbgo.ActiveOrderBook
|
||||||
orderStore *core.OrderStore
|
|
||||||
tradeCollector *core.TradeCollector
|
|
||||||
|
|
||||||
groupID uint32
|
|
||||||
|
|
||||||
stopC chan struct{}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Strategy) ID() string {
|
func (s *Strategy) ID() string {
|
||||||
|
@ -149,7 +139,6 @@ func (s *Strategy) placeAdjustmentOrders(ctx context.Context, orderExecutor bbgo
|
||||||
Price: askPrice,
|
Price: askPrice,
|
||||||
Quantity: quantity,
|
Quantity: quantity,
|
||||||
Market: s.Market,
|
Market: s.Market,
|
||||||
GroupID: s.groupID,
|
|
||||||
})
|
})
|
||||||
|
|
||||||
case types.SideTypeSell:
|
case types.SideTypeSell:
|
||||||
|
@ -175,7 +164,6 @@ func (s *Strategy) placeAdjustmentOrders(ctx context.Context, orderExecutor bbgo
|
||||||
Price: bidPrice,
|
Price: bidPrice,
|
||||||
Quantity: quantity,
|
Quantity: quantity,
|
||||||
Market: s.Market,
|
Market: s.Market,
|
||||||
GroupID: s.groupID,
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -189,12 +177,13 @@ func (s *Strategy) placeAdjustmentOrders(ctx context.Context, orderExecutor bbgo
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
s.orderStore.Add(createdOrders...)
|
|
||||||
s.activeAdjustmentOrders.Add(createdOrders...)
|
s.activeAdjustmentOrders.Add(createdOrders...)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Strategy) placeWallOrders(ctx context.Context, orderExecutor bbgo.OrderExecutor) error {
|
func (s *Strategy) placeWallOrders(ctx context.Context, orderExecutor bbgo.OrderExecutor) error {
|
||||||
|
log.Infof("placing wall orders...")
|
||||||
|
|
||||||
var submitOrders []types.SubmitOrder
|
var submitOrders []types.SubmitOrder
|
||||||
var startPrice = s.FixedPrice
|
var startPrice = s.FixedPrice
|
||||||
for i := 0; i < s.NumLayers; i++ {
|
for i := 0; i < s.NumLayers; i++ {
|
||||||
|
@ -217,7 +206,6 @@ func (s *Strategy) placeWallOrders(ctx context.Context, orderExecutor bbgo.Order
|
||||||
Price: price,
|
Price: price,
|
||||||
Quantity: quantity,
|
Quantity: quantity,
|
||||||
Market: s.Market,
|
Market: s.Market,
|
||||||
GroupID: s.groupID,
|
|
||||||
}
|
}
|
||||||
submitOrders = append(submitOrders, order)
|
submitOrders = append(submitOrders, order)
|
||||||
switch s.Side {
|
switch s.Side {
|
||||||
|
@ -240,74 +228,27 @@ func (s *Strategy) placeWallOrders(ctx context.Context, orderExecutor bbgo.Order
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
s.orderStore.Add(createdOrders...)
|
log.Infof("wall orders placed: %+v", createdOrders)
|
||||||
|
|
||||||
s.activeWallOrders.Add(createdOrders...)
|
s.activeWallOrders.Add(createdOrders...)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Strategy) Run(ctx context.Context, orderExecutor bbgo.OrderExecutor, session *bbgo.ExchangeSession) error {
|
func (s *Strategy) Run(ctx context.Context, _ bbgo.OrderExecutor, session *bbgo.ExchangeSession) error {
|
||||||
|
s.Strategy = &common.Strategy{}
|
||||||
|
s.Strategy.Initialize(ctx, s.Environment, session, s.Market, ID, s.InstanceID())
|
||||||
|
|
||||||
// initial required information
|
// initial required information
|
||||||
s.session = session
|
s.session = session
|
||||||
|
|
||||||
// calculate group id for orders
|
|
||||||
instanceID := s.InstanceID()
|
|
||||||
s.groupID = util.FNV32(instanceID)
|
|
||||||
|
|
||||||
// If position is nil, we need to allocate a new position for calculation
|
|
||||||
if s.Position == nil {
|
|
||||||
s.Position = types.NewPositionFromMarket(s.Market)
|
|
||||||
}
|
|
||||||
|
|
||||||
if s.ProfitStats == nil {
|
|
||||||
s.ProfitStats = types.NewProfitStats(s.Market)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Always update the position fields
|
|
||||||
s.Position.Strategy = ID
|
|
||||||
s.Position.StrategyInstanceID = instanceID
|
|
||||||
|
|
||||||
s.stopC = make(chan struct{})
|
|
||||||
|
|
||||||
s.activeWallOrders = bbgo.NewActiveOrderBook(s.Symbol)
|
s.activeWallOrders = bbgo.NewActiveOrderBook(s.Symbol)
|
||||||
s.activeWallOrders.BindStream(session.UserDataStream)
|
s.activeWallOrders.BindStream(session.UserDataStream)
|
||||||
|
|
||||||
s.activeAdjustmentOrders = bbgo.NewActiveOrderBook(s.Symbol)
|
s.activeAdjustmentOrders = bbgo.NewActiveOrderBook(s.Symbol)
|
||||||
s.activeAdjustmentOrders.BindStream(session.UserDataStream)
|
s.activeAdjustmentOrders.BindStream(session.UserDataStream)
|
||||||
|
|
||||||
s.orderStore = core.NewOrderStore(s.Symbol)
|
|
||||||
s.orderStore.BindStream(session.UserDataStream)
|
|
||||||
|
|
||||||
s.tradeCollector = core.NewTradeCollector(s.Symbol, s.Position, s.orderStore)
|
|
||||||
|
|
||||||
s.tradeCollector.OnTrade(func(trade types.Trade, profit, netProfit fixedpoint.Value) {
|
|
||||||
bbgo.Notify(trade)
|
|
||||||
s.ProfitStats.AddTrade(trade)
|
|
||||||
|
|
||||||
if profit.Compare(fixedpoint.Zero) == 0 {
|
|
||||||
s.Environment.RecordPosition(s.Position, trade, nil)
|
|
||||||
} else {
|
|
||||||
log.Infof("%s generated profit: %v", s.Symbol, profit)
|
|
||||||
p := s.Position.NewProfit(trade, profit, netProfit)
|
|
||||||
p.Strategy = ID
|
|
||||||
p.StrategyInstanceID = instanceID
|
|
||||||
bbgo.Notify(&p)
|
|
||||||
|
|
||||||
s.ProfitStats.AddProfit(p)
|
|
||||||
bbgo.Notify(&s.ProfitStats)
|
|
||||||
|
|
||||||
s.Environment.RecordPosition(s.Position, trade, &p)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
s.tradeCollector.OnPositionUpdate(func(position *types.Position) {
|
|
||||||
log.Infof("position changed: %s", s.Position)
|
|
||||||
bbgo.Notify(s.Position)
|
|
||||||
})
|
|
||||||
|
|
||||||
s.tradeCollector.BindStream(session.UserDataStream)
|
|
||||||
|
|
||||||
session.UserDataStream.OnStart(func() {
|
session.UserDataStream.OnStart(func() {
|
||||||
if err := s.placeWallOrders(ctx, orderExecutor); err != nil {
|
if err := s.placeWallOrders(ctx, s.OrderExecutor); err != nil {
|
||||||
log.WithError(err).Errorf("can not place order")
|
log.WithError(err).Errorf("can not place order")
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -318,9 +259,9 @@ func (s *Strategy) Run(ctx context.Context, orderExecutor bbgo.OrderExecutor, se
|
||||||
}
|
}
|
||||||
|
|
||||||
// check if there is a canceled order had partially filled.
|
// check if there is a canceled order had partially filled.
|
||||||
s.tradeCollector.Process()
|
s.OrderExecutor.TradeCollector().Process()
|
||||||
|
|
||||||
if err := s.placeAdjustmentOrders(ctx, orderExecutor); err != nil {
|
if err := s.placeAdjustmentOrders(ctx, s.OrderExecutor); err != nil {
|
||||||
log.WithError(err).Errorf("can not place order")
|
log.WithError(err).Errorf("can not place order")
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -331,9 +272,9 @@ func (s *Strategy) Run(ctx context.Context, orderExecutor bbgo.OrderExecutor, se
|
||||||
}
|
}
|
||||||
|
|
||||||
// check if there is a canceled order had partially filled.
|
// check if there is a canceled order had partially filled.
|
||||||
s.tradeCollector.Process()
|
s.OrderExecutor.TradeCollector().Process()
|
||||||
|
|
||||||
if err := s.placeWallOrders(ctx, orderExecutor); err != nil {
|
if err := s.placeWallOrders(ctx, s.OrderExecutor); err != nil {
|
||||||
log.WithError(err).Errorf("can not place order")
|
log.WithError(err).Errorf("can not place order")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -342,9 +283,9 @@ func (s *Strategy) Run(ctx context.Context, orderExecutor bbgo.OrderExecutor, se
|
||||||
}
|
}
|
||||||
|
|
||||||
// check if there is a canceled order had partially filled.
|
// check if there is a canceled order had partially filled.
|
||||||
s.tradeCollector.Process()
|
s.OrderExecutor.TradeCollector().Process()
|
||||||
|
|
||||||
if err := s.placeAdjustmentOrders(ctx, orderExecutor); err != nil {
|
if err := s.placeAdjustmentOrders(ctx, s.OrderExecutor); err != nil {
|
||||||
log.WithError(err).Errorf("can not place order")
|
log.WithError(err).Errorf("can not place order")
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -365,9 +306,9 @@ func (s *Strategy) Run(ctx context.Context, orderExecutor bbgo.OrderExecutor, se
|
||||||
}
|
}
|
||||||
|
|
||||||
// check if there is a canceled order had partially filled.
|
// check if there is a canceled order had partially filled.
|
||||||
s.tradeCollector.Process()
|
s.OrderExecutor.TradeCollector().Process()
|
||||||
|
|
||||||
if err := s.placeWallOrders(ctx, orderExecutor); err != nil {
|
if err := s.placeWallOrders(ctx, s.OrderExecutor); err != nil {
|
||||||
log.WithError(err).Errorf("can not place order")
|
log.WithError(err).Errorf("can not place order")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -377,7 +318,6 @@ func (s *Strategy) Run(ctx context.Context, orderExecutor bbgo.OrderExecutor, se
|
||||||
|
|
||||||
bbgo.OnShutdown(ctx, func(ctx context.Context, wg *sync.WaitGroup) {
|
bbgo.OnShutdown(ctx, func(ctx context.Context, wg *sync.WaitGroup) {
|
||||||
defer wg.Done()
|
defer wg.Done()
|
||||||
close(s.stopC)
|
|
||||||
|
|
||||||
if err := s.activeWallOrders.GracefulCancel(ctx, s.session.Exchange); err != nil {
|
if err := s.activeWallOrders.GracefulCancel(ctx, s.session.Exchange); err != nil {
|
||||||
log.WithError(err).Errorf("graceful cancel order error")
|
log.WithError(err).Errorf("graceful cancel order error")
|
||||||
|
@ -387,7 +327,8 @@ func (s *Strategy) Run(ctx context.Context, orderExecutor bbgo.OrderExecutor, se
|
||||||
log.WithError(err).Errorf("graceful cancel order error")
|
log.WithError(err).Errorf("graceful cancel order error")
|
||||||
}
|
}
|
||||||
|
|
||||||
s.tradeCollector.Process()
|
// check if there is a canceled order had partially filled.
|
||||||
|
s.OrderExecutor.TradeCollector().Process()
|
||||||
})
|
})
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|
Loading…
Reference in New Issue
Block a user