mirror of
https://github.com/c9s/bbgo.git
synced 2024-11-26 16:55:15 +00:00
Merge pull request #1119 from c9s/feature/grids/recover-from-trades
FEATURE: make PinOrderMap's key from string to Pin
This commit is contained in:
commit
294c09b9e8
|
@ -4,11 +4,12 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/c9s/bbgo/pkg/fixedpoint"
|
||||||
"github.com/c9s/bbgo/pkg/types"
|
"github.com/c9s/bbgo/pkg/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
// PinOrderMap store the pin-order's relation, we will change key from string to fixedpoint.Value when FormatString fixed
|
// PinOrderMap store the pin-order's relation, we will change key from string to fixedpoint.Value when FormatString fixed
|
||||||
type PinOrderMap map[string]types.Order
|
type PinOrderMap map[fixedpoint.Value]types.Order
|
||||||
|
|
||||||
// AscendingOrders get the orders from pin order map and sort it in asc order
|
// AscendingOrders get the orders from pin order map and sort it in asc order
|
||||||
func (m PinOrderMap) AscendingOrders() []types.Order {
|
func (m PinOrderMap) AscendingOrders() []types.Order {
|
||||||
|
@ -41,7 +42,7 @@ func (m PinOrderMap) String() string {
|
||||||
|
|
||||||
sb.WriteString("================== PIN ORDER MAP ==================\n")
|
sb.WriteString("================== PIN ORDER MAP ==================\n")
|
||||||
for pin, order := range m {
|
for pin, order := range m {
|
||||||
sb.WriteString(fmt.Sprintf("%s -> %s\n", pin, order.String()))
|
sb.WriteString(fmt.Sprintf("%+v -> %s\n", pin, order.String()))
|
||||||
}
|
}
|
||||||
sb.WriteString("================== END OF PIN ORDER MAP ==================\n")
|
sb.WriteString("================== END OF PIN ORDER MAP ==================\n")
|
||||||
return sb.String()
|
return sb.String()
|
||||||
|
|
|
@ -1465,11 +1465,11 @@ func (s *Strategy) verifyFilledGrid(pins []Pin, pinOrders PinOrderMap, filledOrd
|
||||||
s.debugOrders("filled orders", filledOrders)
|
s.debugOrders("filled orders", filledOrders)
|
||||||
|
|
||||||
for _, filledOrder := range filledOrders {
|
for _, filledOrder := range filledOrders {
|
||||||
price := s.Market.FormatPrice(filledOrder.Price)
|
price := filledOrder.Price
|
||||||
if o, exist := pinOrders[price]; !exist {
|
if o, exist := pinOrders[price]; !exist {
|
||||||
return fmt.Errorf("the price (%s) is not in pins", price)
|
return fmt.Errorf("the price (%+v) is not in pins", price)
|
||||||
} else if o.OrderID != 0 {
|
} else if o.OrderID != 0 {
|
||||||
return fmt.Errorf("there is already an order at this price (%s)", price)
|
return fmt.Errorf("there is already an order at this price (%+v)", price)
|
||||||
} else {
|
} else {
|
||||||
pinOrders[price] = filledOrder
|
pinOrders[price] = filledOrder
|
||||||
}
|
}
|
||||||
|
@ -1479,10 +1479,9 @@ func (s *Strategy) verifyFilledGrid(pins []Pin, pinOrders PinOrderMap, filledOrd
|
||||||
|
|
||||||
side := types.SideTypeBuy
|
side := types.SideTypeBuy
|
||||||
for _, pin := range pins {
|
for _, pin := range pins {
|
||||||
price := s.Market.FormatPrice(fixedpoint.Value(pin))
|
order, exist := pinOrders[fixedpoint.Value(pin)]
|
||||||
order, exist := pinOrders[price]
|
|
||||||
if !exist {
|
if !exist {
|
||||||
return fmt.Errorf("there is no order at price (%s)", price)
|
return fmt.Errorf("there is no order at price (%+v)", pin)
|
||||||
}
|
}
|
||||||
|
|
||||||
// if there is order with OrderID = 0, means we hit the empty pin
|
// if there is order with OrderID = 0, means we hit the empty pin
|
||||||
|
@ -1516,13 +1515,12 @@ func (s *Strategy) buildPinOrderMap(pins []Pin, openOrders []types.Order) (PinOr
|
||||||
pinOrderMap := make(PinOrderMap)
|
pinOrderMap := make(PinOrderMap)
|
||||||
|
|
||||||
for _, pin := range pins {
|
for _, pin := range pins {
|
||||||
priceStr := s.Market.FormatPrice(fixedpoint.Value(pin))
|
pinOrderMap[fixedpoint.Value(pin)] = types.Order{}
|
||||||
pinOrderMap[priceStr] = types.Order{}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, openOrder := range openOrders {
|
for _, openOrder := range openOrders {
|
||||||
priceStr := s.Market.FormatPrice(openOrder.Price)
|
pin := openOrder.Price
|
||||||
v, exist := pinOrderMap[priceStr]
|
v, exist := pinOrderMap[pin]
|
||||||
if !exist {
|
if !exist {
|
||||||
return nil, fmt.Errorf("the price of the order (id: %d) is not in pins", openOrder.OrderID)
|
return nil, fmt.Errorf("the price of the order (id: %d) is not in pins", openOrder.OrderID)
|
||||||
}
|
}
|
||||||
|
@ -1531,7 +1529,7 @@ func (s *Strategy) buildPinOrderMap(pins []Pin, openOrders []types.Order) (PinOr
|
||||||
return nil, fmt.Errorf("there are duplicated open orders at the same pin")
|
return nil, fmt.Errorf("there are duplicated open orders at the same pin")
|
||||||
}
|
}
|
||||||
|
|
||||||
pinOrderMap[priceStr] = openOrder
|
pinOrderMap[pin] = openOrder
|
||||||
}
|
}
|
||||||
|
|
||||||
return pinOrderMap, nil
|
return pinOrderMap, nil
|
||||||
|
@ -1590,8 +1588,8 @@ func (s *Strategy) buildFilledPinOrderMapFromTrades(ctx context.Context, history
|
||||||
}
|
}
|
||||||
|
|
||||||
// checked the trade's order is filled order
|
// checked the trade's order is filled order
|
||||||
priceStr := s.Market.FormatPrice(order.Price)
|
pin := order.Price
|
||||||
v, exist := pinOrdersOpen[priceStr]
|
v, exist := pinOrdersOpen[pin]
|
||||||
if !exist {
|
if !exist {
|
||||||
return nil, fmt.Errorf("the price of the order with the same GroupID is not in pins")
|
return nil, fmt.Errorf("the price of the order with the same GroupID is not in pins")
|
||||||
}
|
}
|
||||||
|
@ -1602,13 +1600,13 @@ func (s *Strategy) buildFilledPinOrderMapFromTrades(ctx context.Context, history
|
||||||
}
|
}
|
||||||
|
|
||||||
// check the order's creation time
|
// check the order's creation time
|
||||||
if pinOrder, exist := pinOrdersFilled[priceStr]; exist && pinOrder.CreationTime.Time().After(order.CreationTime.Time()) {
|
if pinOrder, exist := pinOrdersFilled[pin]; exist && pinOrder.CreationTime.Time().After(order.CreationTime.Time()) {
|
||||||
// do not replace the pin order if the order's creation time is not after pin order's creation time
|
// do not replace the pin order if the order's creation time is not after pin order's creation time
|
||||||
// this situation should not happen actually, because the trades is already sorted.
|
// this situation should not happen actually, because the trades is already sorted.
|
||||||
s.logger.Infof("pinOrder's creation time (%s) should not be after order's creation time (%s)", pinOrder.CreationTime, order.CreationTime)
|
s.logger.Infof("pinOrder's creation time (%s) should not be after order's creation time (%s)", pinOrder.CreationTime, order.CreationTime)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
pinOrdersFilled[priceStr] = *order
|
pinOrdersFilled[pin] = *order
|
||||||
|
|
||||||
// wait 100 ms to avoid rate limit
|
// wait 100 ms to avoid rate limit
|
||||||
time.Sleep(100 * time.Millisecond)
|
time.Sleep(100 * time.Millisecond)
|
||||||
|
|
|
@ -1100,7 +1100,7 @@ func Test_buildPinOrderMap(t *testing.T) {
|
||||||
assert.Len(m, 11)
|
assert.Len(m, 11)
|
||||||
|
|
||||||
for pin, order := range m {
|
for pin, order := range m {
|
||||||
if pin == s.FormatPrice(openOrders[0].Price) {
|
if pin == openOrders[0].Price {
|
||||||
assert.Equal(openOrders[0].OrderID, order.OrderID)
|
assert.Equal(openOrders[0].OrderID, order.OrderID)
|
||||||
} else {
|
} else {
|
||||||
assert.Equal(uint64(0), order.OrderID)
|
assert.Equal(uint64(0), order.OrderID)
|
||||||
|
@ -1184,19 +1184,19 @@ func Test_getOrdersFromPinOrderMapInAscOrder(t *testing.T) {
|
||||||
assert := assert.New(t)
|
assert := assert.New(t)
|
||||||
now := time.Now()
|
now := time.Now()
|
||||||
pinOrderMap := PinOrderMap{
|
pinOrderMap := PinOrderMap{
|
||||||
"1000": types.Order{
|
number("1000"): types.Order{
|
||||||
OrderID: 1,
|
OrderID: 1,
|
||||||
CreationTime: types.Time(now.Add(1 * time.Hour)),
|
CreationTime: types.Time(now.Add(1 * time.Hour)),
|
||||||
UpdateTime: types.Time(now.Add(5 * time.Hour)),
|
UpdateTime: types.Time(now.Add(5 * time.Hour)),
|
||||||
},
|
},
|
||||||
"1100": types.Order{},
|
number("1100"): types.Order{},
|
||||||
"1200": types.Order{},
|
number("1200"): types.Order{},
|
||||||
"1300": types.Order{
|
number("1300"): types.Order{
|
||||||
OrderID: 3,
|
OrderID: 3,
|
||||||
CreationTime: types.Time(now.Add(3 * time.Hour)),
|
CreationTime: types.Time(now.Add(3 * time.Hour)),
|
||||||
UpdateTime: types.Time(now.Add(6 * time.Hour)),
|
UpdateTime: types.Time(now.Add(6 * time.Hour)),
|
||||||
},
|
},
|
||||||
"1400": types.Order{
|
number("1400"): types.Order{
|
||||||
OrderID: 2,
|
OrderID: 2,
|
||||||
CreationTime: types.Time(now.Add(2 * time.Hour)),
|
CreationTime: types.Time(now.Add(2 * time.Hour)),
|
||||||
UpdateTime: types.Time(now.Add(4 * time.Hour)),
|
UpdateTime: types.Time(now.Add(4 * time.Hour)),
|
||||||
|
@ -1220,20 +1220,20 @@ func Test_verifyFilledGrid(t *testing.T) {
|
||||||
|
|
||||||
t.Run("valid grid with buy/sell orders", func(t *testing.T) {
|
t.Run("valid grid with buy/sell orders", func(t *testing.T) {
|
||||||
pinOrderMap := PinOrderMap{
|
pinOrderMap := PinOrderMap{
|
||||||
"100.00": types.Order{
|
number("100.00"): types.Order{
|
||||||
OrderID: 1,
|
OrderID: 1,
|
||||||
SubmitOrder: types.SubmitOrder{
|
SubmitOrder: types.SubmitOrder{
|
||||||
Side: types.SideTypeBuy,
|
Side: types.SideTypeBuy,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"200.00": types.Order{},
|
number("200.00"): types.Order{},
|
||||||
"300.00": types.Order{
|
number("300.00"): types.Order{
|
||||||
OrderID: 3,
|
OrderID: 3,
|
||||||
SubmitOrder: types.SubmitOrder{
|
SubmitOrder: types.SubmitOrder{
|
||||||
Side: types.SideTypeSell,
|
Side: types.SideTypeSell,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"400.00": types.Order{
|
number("400.00"): types.Order{
|
||||||
OrderID: 4,
|
OrderID: 4,
|
||||||
SubmitOrder: types.SubmitOrder{
|
SubmitOrder: types.SubmitOrder{
|
||||||
Side: types.SideTypeSell,
|
Side: types.SideTypeSell,
|
||||||
|
@ -1245,45 +1245,45 @@ func Test_verifyFilledGrid(t *testing.T) {
|
||||||
})
|
})
|
||||||
t.Run("valid grid with only buy orders", func(t *testing.T) {
|
t.Run("valid grid with only buy orders", func(t *testing.T) {
|
||||||
pinOrderMap := PinOrderMap{
|
pinOrderMap := PinOrderMap{
|
||||||
"100.00": types.Order{
|
number("100.00"): types.Order{
|
||||||
OrderID: 1,
|
OrderID: 1,
|
||||||
SubmitOrder: types.SubmitOrder{
|
SubmitOrder: types.SubmitOrder{
|
||||||
Side: types.SideTypeBuy,
|
Side: types.SideTypeBuy,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"200.00": types.Order{
|
number("200.00"): types.Order{
|
||||||
OrderID: 2,
|
OrderID: 2,
|
||||||
SubmitOrder: types.SubmitOrder{
|
SubmitOrder: types.SubmitOrder{
|
||||||
Side: types.SideTypeBuy,
|
Side: types.SideTypeBuy,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"300.00": types.Order{
|
number("300.00"): types.Order{
|
||||||
OrderID: 3,
|
OrderID: 3,
|
||||||
SubmitOrder: types.SubmitOrder{
|
SubmitOrder: types.SubmitOrder{
|
||||||
Side: types.SideTypeBuy,
|
Side: types.SideTypeBuy,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"400.00": types.Order{},
|
number("400.00"): types.Order{},
|
||||||
}
|
}
|
||||||
|
|
||||||
assert.NoError(s.verifyFilledGrid(s.grid.Pins, pinOrderMap, nil))
|
assert.NoError(s.verifyFilledGrid(s.grid.Pins, pinOrderMap, nil))
|
||||||
})
|
})
|
||||||
t.Run("valid grid with only sell orders", func(t *testing.T) {
|
t.Run("valid grid with only sell orders", func(t *testing.T) {
|
||||||
pinOrderMap := PinOrderMap{
|
pinOrderMap := PinOrderMap{
|
||||||
"100.00": types.Order{},
|
number("100.00"): types.Order{},
|
||||||
"200.00": types.Order{
|
number("200.00"): types.Order{
|
||||||
OrderID: 2,
|
OrderID: 2,
|
||||||
SubmitOrder: types.SubmitOrder{
|
SubmitOrder: types.SubmitOrder{
|
||||||
Side: types.SideTypeSell,
|
Side: types.SideTypeSell,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"300.00": types.Order{
|
number("300.00"): types.Order{
|
||||||
OrderID: 3,
|
OrderID: 3,
|
||||||
SubmitOrder: types.SubmitOrder{
|
SubmitOrder: types.SubmitOrder{
|
||||||
Side: types.SideTypeSell,
|
Side: types.SideTypeSell,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"400.00": types.Order{
|
number("400.00"): types.Order{
|
||||||
OrderID: 4,
|
OrderID: 4,
|
||||||
SubmitOrder: types.SubmitOrder{
|
SubmitOrder: types.SubmitOrder{
|
||||||
Side: types.SideTypeSell,
|
Side: types.SideTypeSell,
|
||||||
|
@ -1295,15 +1295,15 @@ func Test_verifyFilledGrid(t *testing.T) {
|
||||||
})
|
})
|
||||||
t.Run("invalid grid with multiple empty pins", func(t *testing.T) {
|
t.Run("invalid grid with multiple empty pins", func(t *testing.T) {
|
||||||
pinOrderMap := PinOrderMap{
|
pinOrderMap := PinOrderMap{
|
||||||
"100.00": types.Order{
|
number("100.00"): types.Order{
|
||||||
OrderID: 1,
|
OrderID: 1,
|
||||||
SubmitOrder: types.SubmitOrder{
|
SubmitOrder: types.SubmitOrder{
|
||||||
Side: types.SideTypeBuy,
|
Side: types.SideTypeBuy,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"200.00": types.Order{},
|
number("200.00"): types.Order{},
|
||||||
"300.00": types.Order{},
|
number("300.00"): types.Order{},
|
||||||
"400.00": types.Order{
|
number("400.00"): types.Order{
|
||||||
OrderID: 4,
|
OrderID: 4,
|
||||||
SubmitOrder: types.SubmitOrder{
|
SubmitOrder: types.SubmitOrder{
|
||||||
Side: types.SideTypeSell,
|
Side: types.SideTypeSell,
|
||||||
|
@ -1315,25 +1315,25 @@ func Test_verifyFilledGrid(t *testing.T) {
|
||||||
})
|
})
|
||||||
t.Run("invalid grid without empty pin", func(t *testing.T) {
|
t.Run("invalid grid without empty pin", func(t *testing.T) {
|
||||||
pinOrderMap := PinOrderMap{
|
pinOrderMap := PinOrderMap{
|
||||||
"100.00": types.Order{
|
number("100.00"): types.Order{
|
||||||
OrderID: 1,
|
OrderID: 1,
|
||||||
SubmitOrder: types.SubmitOrder{
|
SubmitOrder: types.SubmitOrder{
|
||||||
Side: types.SideTypeBuy,
|
Side: types.SideTypeBuy,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"200.00": types.Order{
|
number("200.00"): types.Order{
|
||||||
OrderID: 2,
|
OrderID: 2,
|
||||||
SubmitOrder: types.SubmitOrder{
|
SubmitOrder: types.SubmitOrder{
|
||||||
Side: types.SideTypeBuy,
|
Side: types.SideTypeBuy,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"300.00": types.Order{
|
number("300.00"): types.Order{
|
||||||
OrderID: 3,
|
OrderID: 3,
|
||||||
SubmitOrder: types.SubmitOrder{
|
SubmitOrder: types.SubmitOrder{
|
||||||
Side: types.SideTypeSell,
|
Side: types.SideTypeSell,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"400.00": types.Order{
|
number("400.00"): types.Order{
|
||||||
OrderID: 4,
|
OrderID: 4,
|
||||||
SubmitOrder: types.SubmitOrder{
|
SubmitOrder: types.SubmitOrder{
|
||||||
Side: types.SideTypeSell,
|
Side: types.SideTypeSell,
|
||||||
|
@ -1345,20 +1345,20 @@ func Test_verifyFilledGrid(t *testing.T) {
|
||||||
})
|
})
|
||||||
t.Run("invalid grid with Buy-empty-Sell-Buy order", func(t *testing.T) {
|
t.Run("invalid grid with Buy-empty-Sell-Buy order", func(t *testing.T) {
|
||||||
pinOrderMap := PinOrderMap{
|
pinOrderMap := PinOrderMap{
|
||||||
"100.00": types.Order{
|
number("100.00"): types.Order{
|
||||||
OrderID: 1,
|
OrderID: 1,
|
||||||
SubmitOrder: types.SubmitOrder{
|
SubmitOrder: types.SubmitOrder{
|
||||||
Side: types.SideTypeBuy,
|
Side: types.SideTypeBuy,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"200.00": types.Order{},
|
number("200.00"): types.Order{},
|
||||||
"300.00": types.Order{
|
number("300.00"): types.Order{
|
||||||
OrderID: 3,
|
OrderID: 3,
|
||||||
SubmitOrder: types.SubmitOrder{
|
SubmitOrder: types.SubmitOrder{
|
||||||
Side: types.SideTypeSell,
|
Side: types.SideTypeSell,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"400.00": types.Order{
|
number("400.00"): types.Order{
|
||||||
OrderID: 4,
|
OrderID: 4,
|
||||||
SubmitOrder: types.SubmitOrder{
|
SubmitOrder: types.SubmitOrder{
|
||||||
Side: types.SideTypeBuy,
|
Side: types.SideTypeBuy,
|
||||||
|
@ -1370,45 +1370,45 @@ func Test_verifyFilledGrid(t *testing.T) {
|
||||||
})
|
})
|
||||||
t.Run("invalid grid with Sell-empty order", func(t *testing.T) {
|
t.Run("invalid grid with Sell-empty order", func(t *testing.T) {
|
||||||
pinOrderMap := PinOrderMap{
|
pinOrderMap := PinOrderMap{
|
||||||
"100.00": types.Order{
|
number("100.00"): types.Order{
|
||||||
OrderID: 1,
|
OrderID: 1,
|
||||||
SubmitOrder: types.SubmitOrder{
|
SubmitOrder: types.SubmitOrder{
|
||||||
Side: types.SideTypeSell,
|
Side: types.SideTypeSell,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"200.00": types.Order{
|
number("200.00"): types.Order{
|
||||||
OrderID: 2,
|
OrderID: 2,
|
||||||
SubmitOrder: types.SubmitOrder{
|
SubmitOrder: types.SubmitOrder{
|
||||||
Side: types.SideTypeSell,
|
Side: types.SideTypeSell,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"300.00": types.Order{
|
number("300.00"): types.Order{
|
||||||
OrderID: 3,
|
OrderID: 3,
|
||||||
SubmitOrder: types.SubmitOrder{
|
SubmitOrder: types.SubmitOrder{
|
||||||
Side: types.SideTypeSell,
|
Side: types.SideTypeSell,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"400.00": types.Order{},
|
number("400.00"): types.Order{},
|
||||||
}
|
}
|
||||||
|
|
||||||
assert.Error(s.verifyFilledGrid(s.grid.Pins, pinOrderMap, nil))
|
assert.Error(s.verifyFilledGrid(s.grid.Pins, pinOrderMap, nil))
|
||||||
})
|
})
|
||||||
t.Run("invalid grid with empty-Buy order", func(t *testing.T) {
|
t.Run("invalid grid with empty-Buy order", func(t *testing.T) {
|
||||||
pinOrderMap := PinOrderMap{
|
pinOrderMap := PinOrderMap{
|
||||||
"100.00": types.Order{},
|
number("100.00"): types.Order{},
|
||||||
"200.00": types.Order{
|
number("200.00"): types.Order{
|
||||||
OrderID: 2,
|
OrderID: 2,
|
||||||
SubmitOrder: types.SubmitOrder{
|
SubmitOrder: types.SubmitOrder{
|
||||||
Side: types.SideTypeBuy,
|
Side: types.SideTypeBuy,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"300.00": types.Order{
|
number("300.00"): types.Order{
|
||||||
OrderID: 3,
|
OrderID: 3,
|
||||||
SubmitOrder: types.SubmitOrder{
|
SubmitOrder: types.SubmitOrder{
|
||||||
Side: types.SideTypeBuy,
|
Side: types.SideTypeBuy,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"400.00": types.Order{
|
number("400.00"): types.Order{
|
||||||
OrderID: 4,
|
OrderID: 4,
|
||||||
SubmitOrder: types.SubmitOrder{
|
SubmitOrder: types.SubmitOrder{
|
||||||
Side: types.SideTypeBuy,
|
Side: types.SideTypeBuy,
|
||||||
|
|
Loading…
Reference in New Issue
Block a user