mirror of
https://github.com/c9s/bbgo.git
synced 2024-09-20 08:11:08 +00:00
add grid restore behavior
This commit is contained in:
parent
8c08cfebb7
commit
714d61a829
|
@ -13,9 +13,9 @@ func (n *NullNotifier) Notify(format string, args ...interface{}) {}
|
||||||
|
|
||||||
type Notifiability struct {
|
type Notifiability struct {
|
||||||
notifiers []Notifier
|
notifiers []Notifier
|
||||||
SessionChannelRouter *PatternChannelRouter
|
SessionChannelRouter *PatternChannelRouter `json:"-"`
|
||||||
SymbolChannelRouter *PatternChannelRouter
|
SymbolChannelRouter *PatternChannelRouter `json:"-"`
|
||||||
ObjectChannelRouter *ObjectChannelRouter
|
ObjectChannelRouter *ObjectChannelRouter `json:"-"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// RouteSession routes symbol name to channel
|
// RouteSession routes symbol name to channel
|
||||||
|
|
|
@ -92,8 +92,8 @@ func BootstrapEnvironment(ctx context.Context, environ *bbgo.Environment, userCo
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := environ.ConfigureNotificationSystem(userConfig) ; err != nil {
|
if err := environ.ConfigureNotificationSystem(userConfig); err != nil {
|
||||||
return errors.Wrap(err,"notification configure error")
|
return errors.Wrap(err, "notification configure error")
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
@ -108,7 +108,7 @@ func runConfig(basectx context.Context, userConfig *bbgo.Config, enableApiServer
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := environ.Sync(ctx) ; err != nil {
|
if err := environ.Sync(ctx); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -262,4 +262,3 @@ func buildAndRun(ctx context.Context, userConfig *bbgo.Config, args ...string) (
|
||||||
runCmd.Stderr = os.Stderr
|
runCmd.Stderr = os.Stderr
|
||||||
return runCmd, runCmd.Start()
|
return runCmd, runCmd.Start()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -180,7 +180,7 @@ func (e *Exchange) QueryClosedOrders(ctx context.Context, symbol string, since,
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
numBatches := 5
|
numBatches := 3
|
||||||
limit := 1000 // max limit = 1000
|
limit := 1000 // max limit = 1000
|
||||||
offset := limit * numBatches
|
offset := limit * numBatches
|
||||||
orderIDs := make(map[uint64]struct{}, limit*2)
|
orderIDs := make(map[uint64]struct{}, limit*2)
|
||||||
|
|
|
@ -212,7 +212,7 @@ func convertWebSocketTrade(t max.TradeUpdate) (*types.Trade, error) {
|
||||||
ID: int64(t.ID),
|
ID: int64(t.ID),
|
||||||
OrderID: t.OrderID,
|
OrderID: t.OrderID,
|
||||||
Symbol: toGlobalSymbol(t.Market),
|
Symbol: toGlobalSymbol(t.Market),
|
||||||
Exchange: "max",
|
Exchange: types.ExchangeMax.String(),
|
||||||
Price: price,
|
Price: price,
|
||||||
Quantity: quantity,
|
Quantity: quantity,
|
||||||
Side: side,
|
Side: side,
|
||||||
|
@ -246,8 +246,9 @@ func toGlobalOrderUpdate(u max.OrderUpdate) (*types.Order, error) {
|
||||||
Price: util.MustParseFloat(u.Price),
|
Price: util.MustParseFloat(u.Price),
|
||||||
StopPrice: util.MustParseFloat(u.StopPrice),
|
StopPrice: util.MustParseFloat(u.StopPrice),
|
||||||
TimeInForce: "GTC", // MAX only supports GTC
|
TimeInForce: "GTC", // MAX only supports GTC
|
||||||
|
GroupID: u.GroupID,
|
||||||
},
|
},
|
||||||
Exchange: "max",
|
Exchange: types.ExchangeMax.String(),
|
||||||
OrderID: u.ID,
|
OrderID: u.ID,
|
||||||
Status: toGlobalOrderStatus(u.State, executedVolume, remainingVolume),
|
Status: toGlobalOrderStatus(u.State, executedVolume, remainingVolume),
|
||||||
ExecutedQuantity: executedVolume.Float64(),
|
ExecutedQuantity: executedVolume.Float64(),
|
||||||
|
|
|
@ -6,6 +6,7 @@ import (
|
||||||
"hash/fnv"
|
"hash/fnv"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
|
"github.com/pkg/errors"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
|
|
||||||
"github.com/c9s/bbgo/pkg/bbgo"
|
"github.com/c9s/bbgo/pkg/bbgo"
|
||||||
|
@ -25,6 +26,13 @@ func init() {
|
||||||
bbgo.RegisterStrategy(ID, &Strategy{})
|
bbgo.RegisterStrategy(ID, &Strategy{})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Snapshot is the grid snapshot
|
||||||
|
type Snapshot struct {
|
||||||
|
Orders []types.SubmitOrder `json:"orders,omitempty"`
|
||||||
|
FilledBuyGrids map[fixedpoint.Value]struct{} `json:"filledBuyGrids"`
|
||||||
|
FilledSellGrids map[fixedpoint.Value]struct{} `json:"filledSellGrids"`
|
||||||
|
}
|
||||||
|
|
||||||
type Strategy struct {
|
type Strategy struct {
|
||||||
// The notification system will be injected into the strategy automatically.
|
// The notification system will be injected into the strategy automatically.
|
||||||
// This field will be injected automatically since it's a single exchange strategy.
|
// This field will be injected automatically since it's a single exchange strategy.
|
||||||
|
@ -32,6 +40,8 @@ type Strategy struct {
|
||||||
|
|
||||||
*bbgo.Graceful `json:"-" yaml:"-"`
|
*bbgo.Graceful `json:"-" yaml:"-"`
|
||||||
|
|
||||||
|
*bbgo.Persistence
|
||||||
|
|
||||||
// OrderExecutor is an interface for submitting order.
|
// OrderExecutor is an interface for submitting order.
|
||||||
// This field will be injected automatically since it's a single exchange strategy.
|
// This field will be injected automatically since it's a single exchange strategy.
|
||||||
bbgo.OrderExecutor `json:"-" yaml:"-"`
|
bbgo.OrderExecutor `json:"-" yaml:"-"`
|
||||||
|
@ -410,6 +420,19 @@ func (s *Strategy) Run(ctx context.Context, orderExecutor bbgo.OrderExecutor, se
|
||||||
return fmt.Errorf("upper price (%f) should not be less than lower price (%f)", s.UpperPrice.Float64(), s.LowerPrice.Float64())
|
return fmt.Errorf("upper price (%f) should not be less than lower price (%f)", s.UpperPrice.Float64(), s.LowerPrice.Float64())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var snapshot Snapshot
|
||||||
|
var snapshotLoaded = false
|
||||||
|
if s.Persistence != nil {
|
||||||
|
if err := s.Persistence.Load(&snapshot, ID, s.Symbol, "snapshot"); err != nil {
|
||||||
|
if err != service.ErrPersistenceNotExists {
|
||||||
|
return errors.Wrapf(err, "snapshot load error")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
log.Infof("active order snapshot loaded")
|
||||||
|
snapshotLoaded = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
s.filledBuyGrids = make(map[fixedpoint.Value]struct{})
|
s.filledBuyGrids = make(map[fixedpoint.Value]struct{})
|
||||||
s.filledSellGrids = make(map[fixedpoint.Value]struct{})
|
s.filledSellGrids = make(map[fixedpoint.Value]struct{})
|
||||||
|
|
||||||
|
@ -437,6 +460,20 @@ func (s *Strategy) Run(ctx context.Context, orderExecutor bbgo.OrderExecutor, se
|
||||||
s.Graceful.OnShutdown(func(ctx context.Context, wg *sync.WaitGroup) {
|
s.Graceful.OnShutdown(func(ctx context.Context, wg *sync.WaitGroup) {
|
||||||
defer wg.Done()
|
defer wg.Done()
|
||||||
|
|
||||||
|
if s.Persistence != nil {
|
||||||
|
log.Infof("backing up active orders...")
|
||||||
|
submitOrders := s.activeOrders.Backup()
|
||||||
|
snapshot := Snapshot{
|
||||||
|
Orders: submitOrders,
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := s.Persistence.Save(&snapshot, ID, s.Symbol, "snapshot"); err != nil {
|
||||||
|
log.WithError(err).Error("can not save active order backups")
|
||||||
|
} else {
|
||||||
|
log.Infof("active order snapshot saved")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
log.Infof("canceling active orders...")
|
log.Infof("canceling active orders...")
|
||||||
if err := session.Exchange.CancelOrders(ctx, s.activeOrders.Orders()...); err != nil {
|
if err := session.Exchange.CancelOrders(ctx, s.activeOrders.Orders()...); err != nil {
|
||||||
log.WithError(err).Errorf("cancel order error")
|
log.WithError(err).Errorf("cancel order error")
|
||||||
|
@ -453,7 +490,18 @@ func (s *Strategy) Run(ctx context.Context, orderExecutor bbgo.OrderExecutor, se
|
||||||
|
|
||||||
session.Stream.OnTradeUpdate(s.tradeUpdateHandler)
|
session.Stream.OnTradeUpdate(s.tradeUpdateHandler)
|
||||||
session.Stream.OnStart(func() {
|
session.Stream.OnStart(func() {
|
||||||
|
if snapshotLoaded && len(snapshot.Orders) > 0 {
|
||||||
|
createdOrders, err := orderExecutor.SubmitOrders(ctx, snapshot.Orders...)
|
||||||
|
if err != nil {
|
||||||
|
log.WithError(err).Error("active orders restore error")
|
||||||
|
}
|
||||||
|
s.activeOrders.Add(createdOrders...)
|
||||||
|
s.orderStore.Add(createdOrders...)
|
||||||
|
s.filledSellGrids = snapshot.FilledSellGrids
|
||||||
|
s.filledBuyGrids = snapshot.FilledBuyGrids
|
||||||
|
} else {
|
||||||
s.placeGridOrders(orderExecutor, session)
|
s.placeGridOrders(orderExecutor, session)
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|
|
@ -96,7 +96,7 @@ type SubmitOrder struct {
|
||||||
|
|
||||||
Quantity float64 `json:"quantity" db:"quantity"`
|
Quantity float64 `json:"quantity" db:"quantity"`
|
||||||
Price float64 `json:"price" db:"price"`
|
Price float64 `json:"price" db:"price"`
|
||||||
StopPrice float64 `json:"stopPrice" db:"stop_price"`
|
StopPrice float64 `json:"stopPrice,omitempty" db:"stop_price"`
|
||||||
|
|
||||||
Market Market `json:"-" db:"-"`
|
Market Market `json:"-" db:"-"`
|
||||||
|
|
||||||
|
@ -105,11 +105,11 @@ type SubmitOrder struct {
|
||||||
PriceString string `json:"-"`
|
PriceString string `json:"-"`
|
||||||
QuantityString string `json:"-"`
|
QuantityString string `json:"-"`
|
||||||
|
|
||||||
TimeInForce string `json:"timeInForce" db:"time_in_force"` // GTC, IOC, FOK
|
TimeInForce string `json:"timeInForce,omitempty" db:"time_in_force"` // GTC, IOC, FOK
|
||||||
|
|
||||||
GroupID int64 `json:"groupID"`
|
GroupID int64 `json:"groupID,omitempty"`
|
||||||
|
|
||||||
MarginSideEffect MarginOrderSideEffectType `json:"marginSideEffect"` // AUTO_REPAY = repay, MARGIN_BUY = borrow, defaults to NO_SIDE_EFFECT
|
MarginSideEffect MarginOrderSideEffectType `json:"marginSideEffect,omitempty"` // AUTO_REPAY = repay, MARGIN_BUY = borrow, defaults to NO_SIDE_EFFECT
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *SubmitOrder) String() string {
|
func (o *SubmitOrder) String() string {
|
||||||
|
@ -160,6 +160,9 @@ type Order struct {
|
||||||
func (o Order) Backup() SubmitOrder {
|
func (o Order) Backup() SubmitOrder {
|
||||||
so := o.SubmitOrder
|
so := o.SubmitOrder
|
||||||
so.Quantity = o.Quantity - o.ExecutedQuantity
|
so.Quantity = o.Quantity - o.ExecutedQuantity
|
||||||
|
|
||||||
|
// ClientOrderID can not be reused
|
||||||
|
so.ClientOrderID = ""
|
||||||
return so
|
return so
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user