@@ -162,15 +162,19 @@ type Strategy struct {
162162 // it makes sure that your grid configuration is profitable.
163163 FeeRate fixedpoint.Value `json:"feeRate"`
164164
165- SkipSpreadCheck bool `json:"skipSpreadCheck"`
166- RecoverGridByScanningTrades bool `json:"recoverGridByScanningTrades"`
165+ SkipSpreadCheck bool `json:"skipSpreadCheck"`
166+ RecoverGridByScanningTrades bool `json:"recoverGridByScanningTrades"`
167+ RecoverFailedOrdersWhenGridOpening bool `json:"recoverFailedOrdersWhenGridOpening"`
167168
168169 // Debug enables the debug mode
169170 Debug bool `json:"debug"`
170171
171172 GridProfitStats * GridProfitStats `persistence:"grid_profit_stats"`
172173 Position * types.Position `persistence:"position"`
173174
175+ // this is used to check all generated orders are placed
176+ GridOrderStates * GridOrderStates `persistence:"grid_order_states"`
177+
174178 // ExchangeSession is an injection field
175179 ExchangeSession * bbgo.ExchangeSession
176180
@@ -1068,6 +1072,10 @@ func (s *Strategy) openGrid(ctx context.Context, session *bbgo.ExchangeSession)
10681072 return err
10691073 }
10701074
1075+ // use grid order states to check the orders are placed when opening grid
1076+ s .GridOrderStates = newGridOrderStates ()
1077+ s .GridOrderStates .AddSubmitOrders (submitOrders ... )
1078+
10711079 s .debugGridOrders (submitOrders , lastPrice )
10721080
10731081 writeCtx := s .getWriteContext (ctx )
@@ -1078,6 +1086,8 @@ func (s *Strategy) openGrid(ctx context.Context, session *bbgo.ExchangeSession)
10781086 return err2
10791087 }
10801088
1089+ s .GridOrderStates .AddCreatedOrders (createdOrders ... )
1090+
10811091 // try to always emit grid ready
10821092 defer s .EmitGridReady ()
10831093
@@ -1230,14 +1240,33 @@ func (s *Strategy) debugOrders(desc string, orders []types.Order) {
12301240 s .logger .Infof (sb .String ())
12311241}
12321242
1243+ func (s * Strategy ) debugSubmitOrders (desc string , orders []types.SubmitOrder ) {
1244+ if ! s .Debug {
1245+ return
1246+ }
1247+
1248+ var sb strings.Builder
1249+
1250+ if desc == "" {
1251+ desc = "ORDERS"
1252+ }
1253+
1254+ sb .WriteString (desc + " [\n " )
1255+ for i , order := range orders {
1256+ sb .WriteString (fmt .Sprintf (" - %d) %s\n " , i , order .String ()))
1257+ }
1258+ sb .WriteString ("]" )
1259+
1260+ s .logger .Infof (sb .String ())
1261+ }
1262+
12331263func (s * Strategy ) debugGridProfitStats (trigger string ) {
12341264 if ! s .Debug {
12351265 return
12361266 }
12371267
12381268 stats := * s .GridProfitStats
12391269 // ProfitEntries may have too many profits, make it nil to readable
1240- stats .ProfitEntries = nil
12411270 b , err := json .Marshal (stats )
12421271 if err != nil {
12431272 s .logger .WithError (err ).Errorf ("[%s] failed to debug grid profit stats" , trigger )
@@ -1936,6 +1965,15 @@ func (s *Strategy) Run(ctx context.Context, _ bbgo.OrderExecutor, session *bbgo.
19361965
19371966func (s * Strategy ) startProcess (ctx context.Context , session * bbgo.ExchangeSession ) {
19381967 s .debugGridProfitStats ("startProcess" )
1968+ if s .RecoverFailedOrdersWhenGridOpening {
1969+ s .logger .Info ("recover failed orders when grid opening" )
1970+ if err := s .recoverFailedOrdersWhenGridOpening (ctx ); err != nil {
1971+ s .logger .WithError (err ).Error ("failed to start process, recover failed orders when grid opening error" )
1972+ s .EmitGridError (errors .Wrapf (err , "failed to start process, recover failed orders when grid opening error" ))
1973+ return
1974+ }
1975+ }
1976+
19391977 if s .RecoverOrdersWhenStart {
19401978 // do recover only when triggerPrice is not set and not in the back-test mode
19411979 s .logger .Infof ("recoverWhenStart is set, trying to recover grid orders..." )
@@ -1954,6 +1992,44 @@ func (s *Strategy) startProcess(ctx context.Context, session *bbgo.ExchangeSessi
19541992 }
19551993}
19561994
1995+ func (s * Strategy ) recoverFailedOrdersWhenGridOpening (ctx context.Context ) error {
1996+ if s .GridOrderStates == nil {
1997+ return nil
1998+ }
1999+
2000+ failedOrders , err := s .GridOrderStates .GetFailedOrdersWhenGridOpening (ctx , s .orderQueryService )
2001+ if err != nil {
2002+ return errors .Wrapf (err , "failed to get failed orders" )
2003+ }
2004+
2005+ var submitOrders []types.SubmitOrder
2006+ for _ , failedOrder := range failedOrders {
2007+ submitOrders = append (submitOrders , types.SubmitOrder {
2008+ Symbol : s .Symbol ,
2009+ Type : types .OrderTypeLimit ,
2010+ Side : failedOrder .Side ,
2011+ Price : failedOrder .Price ,
2012+ Quantity : failedOrder .Quantity ,
2013+ Market : s .Market ,
2014+ TimeInForce : types .TimeInForceGTC ,
2015+ Tag : orderTag ,
2016+ GroupID : s .OrderGroupID ,
2017+ ClientOrderID : failedOrder .ClientOrderID ,
2018+ })
2019+ }
2020+
2021+ s .debugSubmitOrders ("RECOVER FAILED ORDERS WHEN GRID OPENING" , submitOrders )
2022+
2023+ writeCtx := s .getWriteContext (ctx )
2024+ createdOrders , err := s .orderExecutor .SubmitOrders (writeCtx , submitOrders ... )
2025+ if err != nil {
2026+ return errors .Wrapf (err , "failed to submit orders" )
2027+ }
2028+
2029+ s .GridOrderStates .AddCreatedOrders (createdOrders ... )
2030+ return nil
2031+ }
2032+
19572033func (s * Strategy ) recoverGrid (ctx context.Context , session * bbgo.ExchangeSession ) error {
19582034 if s .RecoverGridByScanningTrades {
19592035 s .debugLog ("recovering grid by scanning trades" )
0 commit comments