-
Notifications
You must be signed in to change notification settings - Fork 91
/
match_with_orders.go
81 lines (70 loc) · 2.87 KB
/
match_with_orders.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
package types
import (
"errors"
satypes "github.com/dydxprotocol/v4-chain/protocol/x/subaccounts/types"
)
// MatchWithOrders represents a match which occurred between two orders and the amount that was matched.
type MatchWithOrders struct {
MakerOrder MatchableOrder
TakerOrder MatchableOrder
FillAmount satypes.BaseQuantums
MakerFee int64
TakerFee int64
}
// Validate performs stateless validation on an order match. This validation does
// not perform any state reads, or memclob reads.
//
// This validation ensures:
// - Order match does not constitute a self-trade.
// - Order match contains a `fillAmount` greater than 0.
// - Orders in match are for the same `ClobPairId`.
// - Orders in match are for opposing sides.
// - Orders are crossing.
// - The minimum of the takerOrder and makerOrder initial quantums does not exceed the FillAmount.
// - The maker order referenced in the match is not a liquidation order.
// - The maker order referenced in the match is not an IOC order.
func (match MatchWithOrders) Validate() error {
makerOrder := match.MakerOrder
takerOrder := match.TakerOrder
fillAmount := match.FillAmount
// Make sure the maker and taker order are not for the same Subaccount.
if makerOrder.GetSubaccountId() == takerOrder.GetSubaccountId() {
return errors.New("Match constitutes a self-trade")
}
// Make sure the fill amount is greater than zero.
if fillAmount == 0 {
return errors.New("fillAmount must be greater than 0")
}
// Make sure the maker and taker order are for the same `ClobPair`.
if makerOrder.GetClobPairId() != takerOrder.GetClobPairId() {
return errors.New("ClobPairIds do not match in match")
}
// Make sure the maker and taker order are for opposing sides of the book.
if makerOrder.IsBuy() == takerOrder.IsBuy() {
return errors.New("Orders are not on opposing sides of the book in match")
}
// Make sure the maker and taker order cross.
if makerOrder.IsBuy() {
if makerOrder.GetOrderSubticks() < takerOrder.GetOrderSubticks() {
return errors.New("Orders do not cross in match")
}
} else {
if takerOrder.GetOrderSubticks() < makerOrder.GetOrderSubticks() {
return errors.New("Orders do not cross in match")
}
}
// Verify that the minimum of the `makerOrder` and `takerOrder` initial quantums does not exceed the `fillAmount`.
if fillAmount > makerOrder.GetBaseQuantums() || fillAmount > takerOrder.GetBaseQuantums() {
return errors.New("Minimum initial order quantums exceeds fill amount")
}
// Make sure the maker order is not a liquidation order.
if makerOrder.IsLiquidation() {
return errors.New("Liquidation order cannot be matched as a maker order")
}
// Make sure the maker order is not an IOC order.
unwrappedMakerOrder := makerOrder.MustGetOrder()
if unwrappedMakerOrder.RequiresImmediateExecution() {
return errors.New("IOC / FOK order cannot be matched as a maker order")
}
return nil
}