-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathorders.go
252 lines (223 loc) · 9 KB
/
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
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
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
package alor
import (
"bytes"
"context"
"encoding/json"
"log/slog"
"net/http"
"net/url"
"path"
)
// GetOrders получение информации о всех заявках
func (c *Client) GetOrders(ctx context.Context, portfolio string) ([]Order, error) {
queryURL, _ := url.Parse("/md/v2/Clients")
queryURL.Path = path.Join(queryURL.Path, c.Exchange, portfolio, "orders")
r := &request{
method: http.MethodGet,
endpoint: queryURL.String(),
}
result := make([]Order, 0)
data, err := c.callAPI(ctx, r)
if err != nil {
return result, err
}
err = json.Unmarshal(data, &result)
if err != nil {
return result, err
}
return result, nil
}
// GetOrder получение информации о выбранной заявке
func (c *Client) GetOrder(ctx context.Context, portfolio, orderId string) (Order, error) {
queryURL, _ := url.Parse("/md/v2/Clients")
queryURL.Path = path.Join(queryURL.Path, c.Exchange, portfolio, "orders", orderId)
r := &request{
method: http.MethodGet,
endpoint: queryURL.String(),
}
result := Order{}
data, err := c.callAPI(ctx, r)
if err != nil {
return result, err
}
err = json.Unmarshal(data, &result)
if err != nil {
return result, err
}
return result, nil
}
// структура ответа
type OrderResponse struct {
Code string `json:"code"`
Message string `json:"message"`
OrderNumber string `json:"orderNumber"`
}
// если ордер с таким номером не найден (или уже отменен) = error HTTP 400: Bad Request
// если 200 = то успешно
// как обрабатывать разные ситуации? нет ошибки = Ок
// CancelOrder отменить заявку
// TODO решить что возвращать
func (c *Client) CancelOrder(ctx context.Context, portfolio, orderId string) (bool, error) {
queryURL, _ := url.Parse("/commandapi/warptrans/TRADE/v2/client/orders")
queryURL.Path = path.Join(queryURL.Path, orderId)
r := &request{
method: http.MethodDelete,
endpoint: queryURL.String(),
}
r.setParam("exchange", c.Exchange)
r.setParam("portfolio", portfolio)
r.setParam("jsonResponse", "true")
//result := OrderResponse{}
data, err := c.callAPI(ctx, r)
if err != nil {
//return result, err
return false, err
}
log.Debug("CancelOrder", slog.Any("response body", string(data)))
//err = json.Unmarshal(data, &result)
//if err != nil {
// return false, err
//}
return true, nil
}
// TODO SendOrder(ctx context.Context, order OrderRequest) (string, error)
//
// NewCreateOrderService создать новый ордер
func (c *Client) NewCreateOrderService() *CreateOrderService {
user := User{
Portfolio: c.portfolioID, // проставим по умолчанию
}
ticker := Instrument{
Symbol: "",
Exchange: c.Exchange,
//InstrumentGroup: board,
}
return &CreateOrderService{
c: c,
order: OrderRequest{
//OrderType: orderType, // лимитная или рыночная
//Side: side, // направление: покупка или продажа
TimeInForce: TimeInForceDAY, // сразу проставим "До конца дня"
Instrument: ticker,
User: user,
Quantity: 0,
Price: 0,
},
}
}
// послать команду на создание нового ордера
// возвращает ID созданной заявки
func (s *CreateOrderService) Do(ctx context.Context) (string, error) {
r := &request{
method: http.MethodPost,
endpoint: "/commandapi/warptrans/TRADE/v2/client/orders/actions/market",
}
if s.order.OrderType == OrderTypeLimit {
r.endpoint = "/commandapi/warptrans/TRADE/v2/client/orders/actions/limit"
}
// в request.body надо записать order
buf := new(bytes.Buffer)
_ = json.NewEncoder(buf).Encode(&s.order)
r.body = buf
// "X-ALOR-REQID"
// Требуется уникальная случайная строка в качестве идентификатора запроса.
// Если уже приходил запрос с таким идентификатором, то заявка не будет исполнена повторно,
// а в качестве ответа будет возвращена копия ответа на первый запрос с таким значением идентификатора
// Текущее время в наносекундах, прошедших с 01.01.1970 в UTC
r.setHeader("X-ALOR-REQID", s.c.getRequestID())
// установим заголовок json
r.setHeader("Content-Type", "application/json")
result := OrderResponse{}
data, err := s.c.callAPI(ctx, r)
if err != nil {
return "", err
}
log.Debug("SendOrder", slog.Any("response body", string(data)))
err = json.Unmarshal(data, &result)
if err != nil {
return "", err
}
return result.OrderNumber, nil
}
// BuyMarket покупка по рынку
func (c *Client) BuyMarket(ctx context.Context, symbol string, lot int32, comment string) (string, error) {
return c.NewCreateOrderService().Side(SideTypeBuy).OrderType(OrderTypeMarket).
Symbol(symbol).Qty(lot).Comment(comment).Do(ctx)
}
// BuyLimit лимитная покупка
func (c *Client) BuyLimit(ctx context.Context, symbol string, lot int32, price float64, comment string) (string, error) {
return c.NewCreateOrderService().Side(SideTypeBuy).OrderType(OrderTypeLimit).
Symbol(symbol).Qty(lot).Price(price).Comment(comment).Do(ctx)
}
// SellMarket продажа по рынку
func (c *Client) SellMarket(ctx context.Context, symbol string, lot int32, comment string) (string, error) {
return c.NewCreateOrderService().Side(SideTypeSell).OrderType(OrderTypeMarket).
Symbol(symbol).Qty(lot).Comment(comment).Do(ctx)
}
// SellLimit лимитная продажа
func (c *Client) SellLimit(ctx context.Context, symbol string, lot int32, price float64, comment string) (string, error) {
return c.NewCreateOrderService().Side(SideTypeSell).OrderType(OrderTypeLimit).
Symbol(symbol).Qty(lot).Price(price).Comment(comment).Do(ctx)
}
type OrderRequest struct {
OrderType OrderType `json:"-"`
Side SideType `json:"side"` // Направление сделки: buy — Купля sell — Продажа
Quantity int32 `json:"quantity"` // Количество (лоты)
Price float64 `json:"price,omitempty"` // Цена (только для лимитной)
Comment string `json:"comment"` // Пользовательский комментарий к заявке
Instrument Instrument `json:"instrument"` // тикер
User User `json:"user"` // данные portfolio
TimeInForce TimeInForce `json:"timeInForce"` // Условие по времени действия заявки
IcebergFixed int32 `json:"icebergFixed,omitempty"` // Видимая постоянная часть айсберг-заявки в лотах
IcebergVariance float64 `json:"icebergVariance,omitempty"` // Амплитуда отклонения (в % от icebergFixed) случайной надбавки к видимой части айсберг-заявки. Только срочный рынок
}
// CreateOrderService создать новую заявку (ордер)
type CreateOrderService struct {
c *Client
order OrderRequest
}
// Side установим направление ордера
func (s *CreateOrderService) Side(side SideType) *CreateOrderService {
s.order.Side = side
return s
}
// Comment установим комментарий
func (s *CreateOrderService) Comment(comment string) *CreateOrderService {
s.order.Comment = comment
return s
}
// Symbol установим символ
func (s *CreateOrderService) Symbol(symbol string) *CreateOrderService {
s.order.Instrument.Symbol = symbol
return s
}
// Board установим Код режима торгов
func (s *CreateOrderService) Board(board string) *CreateOrderService {
s.order.Instrument.InstrumentGroup = board
return s
}
// Qty установим кол-во лот (Quantity)
func (s *CreateOrderService) Qty(quantity int32) *CreateOrderService {
s.order.Quantity = quantity
return s
}
// Price установить цену. Для лимитной заявки
func (s *CreateOrderService) Price(price float64) *CreateOrderService {
s.order.Price = price
return s
}
// TimeInForce установим Условие по времени действия заявки
func (s *CreateOrderService) TimeInForce(timeInForce TimeInForce) *CreateOrderService {
s.order.TimeInForce = timeInForce
return s
}
// Portfolio установим номер торгового счета
func (s *CreateOrderService) Portfolio(portfolio string) *CreateOrderService {
s.order.User.Portfolio = portfolio
return s
}
// OrderType установим тип заявки
func (s *CreateOrderService) OrderType(orderType OrderType) *CreateOrderService {
s.order.OrderType = orderType
return s
}