/
convert.go
154 lines (137 loc) · 4.16 KB
/
convert.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
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
package ftx
import (
"fmt"
"strings"
"time"
log "github.com/sirupsen/logrus"
"github.com/c9s/bbgo/pkg/fixedpoint"
"github.com/c9s/bbgo/pkg/types"
)
func toGlobalCurrency(original string) string {
return TrimUpperString(original)
}
func toGlobalSymbol(original string) string {
return strings.ReplaceAll(TrimUpperString(original), "/", "")
}
func toLocalSymbol(original string) string {
if symbolMap[original] == "" {
return original
}
return symbolMap[original]
}
func TrimUpperString(original string) string {
return strings.ToUpper(strings.TrimSpace(original))
}
func TrimLowerString(original string) string {
return strings.ToLower(strings.TrimSpace(original))
}
var errUnsupportedOrderStatus = fmt.Errorf("unsupported order status")
func toGlobalOrder(r order) (types.Order, error) {
// In exchange/max/convert.go, it only parses these fields.
o := types.Order{
SubmitOrder: types.SubmitOrder{
ClientOrderID: r.ClientId,
Symbol: toGlobalSymbol(r.Market),
Side: types.SideType(TrimUpperString(r.Side)),
// order type definition: https://github.com/ftexchange/ftx/blob/master/rest/client.py#L122
Type: types.OrderType(TrimUpperString(r.Type)),
Quantity: r.Size,
Price: r.Price,
TimeInForce: "GTC",
},
Exchange: types.ExchangeFTX,
IsWorking: r.Status == "open",
OrderID: uint64(r.ID),
Status: "",
ExecutedQuantity: r.FilledSize,
CreationTime: types.Time(r.CreatedAt.Time),
UpdateTime: types.Time(r.CreatedAt.Time),
}
// `new` (accepted but not processed yet), `open`, or `closed` (filled or cancelled)
switch r.Status {
case "new":
o.Status = types.OrderStatusNew
case "open":
if fixedpoint.NewFromFloat(o.ExecutedQuantity) != fixedpoint.NewFromInt(0) {
o.Status = types.OrderStatusPartiallyFilled
} else {
o.Status = types.OrderStatusNew
}
case "closed":
// filled or canceled
if fixedpoint.NewFromFloat(o.Quantity) == fixedpoint.NewFromFloat(o.ExecutedQuantity) {
o.Status = types.OrderStatusFilled
} else {
// can't distinguish it's canceled or rejected from order response, so always set to canceled
o.Status = types.OrderStatusCanceled
}
default:
return types.Order{}, fmt.Errorf("unsupported status %s: %w", r.Status, errUnsupportedOrderStatus)
}
return o, nil
}
func toGlobalDeposit(input depositHistory) (types.Deposit, error) {
s, err := toGlobalDepositStatus(input.Status)
if err != nil {
log.WithError(err).Warnf("assign empty string to the deposit status")
}
t := input.Time
if input.ConfirmedTime.Time != (time.Time{}) {
t = input.ConfirmedTime
}
d := types.Deposit{
GID: 0,
Exchange: types.ExchangeFTX,
Time: types.Time(t.Time),
Amount: input.Size,
Asset: toGlobalCurrency(input.Coin),
TransactionID: input.TxID,
Status: s,
Address: input.Address.Address,
AddressTag: input.Address.Tag,
}
return d, nil
}
func toGlobalDepositStatus(input string) (types.DepositStatus, error) {
// The document only list `confirmed` status
switch input {
case "confirmed", "complete":
return types.DepositSuccess, nil
}
return "", fmt.Errorf("unsupported status %s", input)
}
func toGlobalTrade(f fill) (types.Trade, error) {
return types.Trade{
ID: f.TradeId,
GID: 0,
OrderID: f.OrderId,
Exchange: types.ExchangeFTX,
Price: f.Price,
Quantity: f.Size,
QuoteQuantity: f.Price * f.Size,
Symbol: toGlobalSymbol(f.Market),
Side: f.Side,
IsBuyer: f.Side == types.SideTypeBuy,
IsMaker: f.Liquidity == "maker",
Time: types.Time(f.Time.Time),
Fee: f.Fee,
FeeCurrency: f.FeeCurrency,
IsMargin: false,
IsIsolated: false,
}, nil
}
func toGlobalKLine(symbol string, interval types.Interval, h Candle) (types.KLine, error) {
return types.KLine{
Exchange: types.ExchangeFTX,
Symbol: toGlobalSymbol(symbol),
StartTime: h.StartTime.Time,
EndTime: h.StartTime.Add(interval.Duration()),
Interval: interval,
Open: h.Open,
Close: h.Close,
High: h.High,
Low: h.Low,
Volume: h.Volume,
Closed: true,
}, nil
}