-
Notifications
You must be signed in to change notification settings - Fork 32
/
order.go
133 lines (122 loc) · 3.47 KB
/
order.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
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
package matching
import (
"fmt"
"strconv"
"github.com/shopspring/decimal"
)
type Order struct {
Id int
MarketId int
Type string
OrderType string
Price decimal.Decimal
Volume decimal.Decimal
Locked decimal.Decimal
Timestamp int64
BasePrecision int
}
func InitializeOrder(attrs map[string]string) (order Order, err error) {
order.Id, _ = strconv.Atoi(attrs["id"])
order.MarketId, _ = strconv.Atoi(attrs["market_id"])
order.Timestamp, _ = strconv.ParseInt(attrs["timestamp"], 10, 64)
order.Type = attrs["type"]
order.OrderType = attrs["order_type"]
order.Volume, _ = decimal.NewFromString(attrs["volume"])
order.Price, _ = decimal.NewFromString(attrs["price"])
order.Locked, _ = decimal.NewFromString(attrs["locked"])
if attrs["base_precision"] == "" {
order.BasePrecision = 8
} else {
order.BasePrecision, _ = strconv.Atoi(attrs["base_precision"])
}
return
}
func (order *Order) TradeWith(counterOrder Order, counterBook OrderBook) (trade Trade) {
if counterOrder.OrderType == "LimitOrder" {
if order.IsCrossed(counterOrder.Price) {
trade.Price = counterOrder.Price
trade.Volume = order.Volume
if order.Volume.GreaterThan(counterOrder.Volume) {
trade.Volume = counterOrder.Volume
}
trade.Funds = trade.Price.Mul(trade.Volume)
}
} else {
trade.Volume = order.Volume
if trade.Volume.GreaterThan(counterOrder.Volume) {
trade.Volume = counterOrder.Volume
}
volumeLimit := counterOrder.VolumeLimit(order.Price)
if trade.Volume.GreaterThan(volumeLimit) {
trade.Volume = volumeLimit
}
}
return
}
func (order *Order) IsValid() (result bool) {
if order.Type != "ask" && order.Type != "bid" {
return
}
zero := decimal.NewFromFloat(0.0)
if order.OrderType == "LimitOrder" && (order.Price.LessThanOrEqual(zero) || order.Volume.LessThanOrEqual(zero)) {
return
}
if order.OrderType == "MarketOrder" && order.Price.GreaterThan(zero) && order.Locked.LessThanOrEqual(zero) {
return
}
if order.Id > 0 && order.Timestamp > 0 && order.MarketId > 0 {
result = true
}
return
}
func (order *Order) IsFilled() (result bool) {
if order.OrderType == "LimitOrder" {
result = order.Volume.LessThanOrEqual(decimal.NewFromFloat(0.0))
} else if order.OrderType == "MarketOrder" {
result = order.Volume.LessThanOrEqual(decimal.NewFromFloat(0.0)) || order.Locked.LessThanOrEqual(decimal.NewFromFloat(0.0))
}
return
}
func (order *Order) Fill(trade Trade) {
if trade.Volume.GreaterThan(order.Volume) {
return
}
if order.OrderType == "LimitOrder" {
return
}
funds := trade.Funds
if order.Type == "ask" {
funds = trade.Volume
}
if funds.GreaterThan(order.Locked) {
return
}
order.Locked = order.Locked.Sub(funds)
return
}
// func for MarketOrder
func (order *Order) VolumeLimit(tradePrice decimal.Decimal) (result decimal.Decimal) {
if order.Type == "ask" {
result = order.Locked
} else {
result = order.Locked.DivRound(tradePrice, int32(order.BasePrecision))
}
return
}
// func for LimitOrder
func (order *Order) IsCrossed(price decimal.Decimal) (result bool) {
if order.Type == "ask" {
result = price.GreaterThanOrEqual(order.Price)
} else {
result = price.LessThanOrEqual(order.Price)
}
return
}
func (order *Order) Label() (label string) {
if order.OrderType == "LimitOrder" {
label = fmt.Sprintf("%d/$%s/%s", order.Id, order.Price.String(), order.Volume.String())
} else if order.OrderType == "MarketOrder" {
label = fmt.Sprintf("%d/%s", order.Id, order.Volume.String())
}
return
}