|
5 | 5 | "fmt"
|
6 | 6 | "strconv"
|
7 | 7 | "sync"
|
| 8 | + "time" |
8 | 9 |
|
9 | 10 | "github.com/pkg/errors"
|
10 | 11 | "github.com/sirupsen/logrus"
|
@@ -986,6 +987,86 @@ func (s *Strategy) checkMinimalQuoteInvestment() error {
|
986 | 987 | return nil
|
987 | 988 | }
|
988 | 989 |
|
| 990 | +func (s *Strategy) recoverGrid(ctx context.Context, session *bbgo.ExchangeSession) error { |
| 991 | + historyService, implemented := session.Exchange.(types.ExchangeTradeHistoryService) |
| 992 | + if !implemented { |
| 993 | + return nil |
| 994 | + } |
| 995 | + |
| 996 | + openOrders, err := session.Exchange.QueryOpenOrders(ctx, s.Symbol) |
| 997 | + if err != nil { |
| 998 | + return err |
| 999 | + } |
| 1000 | + |
| 1001 | + // no open orders, the grid is not placed yet |
| 1002 | + if len(openOrders) == 0 { |
| 1003 | + return nil |
| 1004 | + } |
| 1005 | + |
| 1006 | + lastOrderID := uint64(0) |
| 1007 | + firstOrderTime := openOrders[0].CreationTime.Time() |
| 1008 | + lastOrderTime := firstOrderTime |
| 1009 | + for _, o := range openOrders { |
| 1010 | + if o.OrderID > lastOrderID { |
| 1011 | + lastOrderID = o.OrderID |
| 1012 | + } |
| 1013 | + |
| 1014 | + createTime := o.CreationTime.Time() |
| 1015 | + if createTime.Before(firstOrderTime) { |
| 1016 | + firstOrderTime = createTime |
| 1017 | + } else if createTime.After(lastOrderTime) { |
| 1018 | + lastOrderTime = createTime |
| 1019 | + } |
| 1020 | + } |
| 1021 | + |
| 1022 | + // Allocate a local order book |
| 1023 | + orderBook := bbgo.NewActiveOrderBook(s.Symbol) |
| 1024 | + |
| 1025 | + // Add all open orders to the local order book |
| 1026 | + gridPriceMap := make(map[string]fixedpoint.Value) |
| 1027 | + for _, pin := range s.grid.Pins { |
| 1028 | + price := fixedpoint.Value(pin) |
| 1029 | + gridPriceMap[price.String()] = price |
| 1030 | + } |
| 1031 | + |
| 1032 | + // Ensure that orders are grid orders |
| 1033 | + // The price must be at the grid pin |
| 1034 | + for _, openOrder := range openOrders { |
| 1035 | + if _, exists := gridPriceMap[openOrder.Price.String()]; exists { |
| 1036 | + orderBook.Add(openOrder) |
| 1037 | + } |
| 1038 | + } |
| 1039 | + |
| 1040 | + // Note that for MAX Exchange, the order history API only uses fromID parameter to query history order. |
| 1041 | + // The time range does not matter. |
| 1042 | + closedOrders, err := historyService.QueryClosedOrders(ctx, s.Symbol, firstOrderTime, time.Now(), lastOrderID) |
| 1043 | + if err != nil { |
| 1044 | + return err |
| 1045 | + } |
| 1046 | + |
| 1047 | + // types.SortOrdersAscending() |
| 1048 | + // for each closed order, if it's newer than the open order's update time, we will update it. |
| 1049 | + for _, closedOrder := range closedOrders { |
| 1050 | + // skip non-grid order prices |
| 1051 | + if _, ok := gridPriceMap[closedOrder.Price.String()]; !ok { |
| 1052 | + continue |
| 1053 | + } |
| 1054 | + |
| 1055 | + existingOrder := orderBook.Lookup(func(o types.Order) bool { |
| 1056 | + return o.Price.Compare(closedOrder.Price) == 0 |
| 1057 | + }) |
| 1058 | + |
| 1059 | + if existingOrder == nil { |
| 1060 | + orderBook.Add(closedOrder) |
| 1061 | + } else { |
| 1062 | + // TODO: Compare update time and create time |
| 1063 | + orderBook.Update(closedOrder) |
| 1064 | + } |
| 1065 | + } |
| 1066 | + |
| 1067 | + return nil |
| 1068 | +} |
| 1069 | + |
989 | 1070 | func (s *Strategy) Run(ctx context.Context, _ bbgo.OrderExecutor, session *bbgo.ExchangeSession) error {
|
990 | 1071 | instanceID := s.InstanceID()
|
991 | 1072 |
|
|
0 commit comments