hft-js 0.2.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/bar.d.ts +2 -2
- package/lib/bar.js +42 -66
- package/lib/bar.js.map +1 -1
- package/lib/broker.d.ts +2 -2
- package/lib/broker.js +89 -95
- package/lib/broker.js.map +1 -1
- package/lib/index.js +8 -24
- package/lib/index.js.map +1 -1
- package/lib/index.test.d.ts +1 -1
- package/lib/index.test.js +75 -110
- package/lib/index.test.js.map +1 -1
- package/lib/interfaces.d.ts +1 -1
- package/lib/interfaces.js +1 -2
- package/lib/interfaces.js.map +1 -1
- package/lib/market.d.ts +2 -2
- package/lib/market.js +132 -162
- package/lib/market.js.map +1 -1
- package/lib/provider.d.ts +3 -3
- package/lib/provider.js +33 -85
- package/lib/provider.js.map +1 -1
- package/lib/tape.d.ts +1 -1
- package/lib/tape.js +18 -23
- package/lib/tape.js.map +1 -1
- package/lib/trader.d.ts +3 -2
- package/lib/trader.js +500 -509
- package/lib/trader.js.map +1 -1
- package/lib/typedef.d.ts +5 -1
- package/lib/typedef.js +1 -2
- package/lib/typedef.js.map +1 -1
- package/lib/utils.d.ts +2 -2
- package/lib/utils.js +27 -77
- package/lib/utils.js.map +1 -1
- package/package.json +9 -8
- package/src/bar.ts +6 -12
- package/src/broker.ts +2 -2
- package/src/index.test.ts +20 -20
- package/src/interfaces.ts +1 -1
- package/src/market.ts +16 -12
- package/src/provider.ts +5 -5
- package/src/tape.ts +1 -1
- package/src/trader.ts +93 -45
- package/src/typedef.ts +5 -1
- package/src/utils.ts +24 -34
package/lib/trader.js
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
"use strict";
|
|
2
1
|
/*
|
|
3
2
|
* trader.ts
|
|
4
3
|
*
|
|
@@ -9,183 +8,172 @@
|
|
|
9
8
|
*
|
|
10
9
|
* https://github.com/shixiongfei/hft.js
|
|
11
10
|
*/
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
11
|
+
import Denque from "denque";
|
|
12
|
+
import ctp, {} from "napi-ctp";
|
|
13
|
+
import { CTPProvider } from "./provider.js";
|
|
14
|
+
import { isValidPrice, parseSymbol } from "./utils.js";
|
|
15
|
+
export class Trader extends CTPProvider {
|
|
16
|
+
traderApi;
|
|
17
|
+
tradingDay;
|
|
18
|
+
frontId;
|
|
19
|
+
sessionId;
|
|
20
|
+
orderRef;
|
|
21
|
+
accountsQueryTime;
|
|
22
|
+
positionDetailsChanged;
|
|
23
|
+
fastQueryLastTick;
|
|
24
|
+
userInfo;
|
|
25
|
+
receivers;
|
|
26
|
+
accounts;
|
|
27
|
+
positionDetails;
|
|
28
|
+
instruments;
|
|
29
|
+
positions;
|
|
30
|
+
orders;
|
|
31
|
+
trades;
|
|
32
|
+
marginRates;
|
|
33
|
+
commRates;
|
|
34
|
+
placeOrders;
|
|
35
|
+
cancelOrders;
|
|
36
|
+
marketOrdersQueue;
|
|
37
|
+
priceLimit;
|
|
38
|
+
orderStatistics;
|
|
39
|
+
marginRatesQueue;
|
|
40
|
+
commRatesQueue;
|
|
41
|
+
accountsQueue;
|
|
42
|
+
positionDetailsQueue;
|
|
43
|
+
constructor(flowTdPath, frontTdAddrs, userInfo, options) {
|
|
44
|
+
super(flowTdPath, frontTdAddrs);
|
|
45
|
+
this.tradingDay = 0;
|
|
46
|
+
this.frontId = 0;
|
|
47
|
+
this.sessionId = 0;
|
|
48
|
+
this.orderRef = 0;
|
|
49
|
+
this.accountsQueryTime = 0;
|
|
50
|
+
this.positionDetailsChanged = true;
|
|
51
|
+
this.userInfo = userInfo;
|
|
52
|
+
this.receivers = [];
|
|
53
|
+
this.accounts = [];
|
|
54
|
+
this.positionDetails = [];
|
|
55
|
+
this.instruments = new Map();
|
|
56
|
+
this.positions = new Map();
|
|
57
|
+
this.orders = new Map();
|
|
58
|
+
this.trades = new Map();
|
|
59
|
+
this.marginRates = new Map();
|
|
60
|
+
this.commRates = new Map();
|
|
61
|
+
this.placeOrders = new Map();
|
|
62
|
+
this.cancelOrders = new Map();
|
|
63
|
+
this.marketOrdersQueue = new Map();
|
|
64
|
+
this.priceLimit = new Map();
|
|
65
|
+
this.orderStatistics = new Map();
|
|
66
|
+
this.marginRatesQueue = new Denque();
|
|
67
|
+
this.commRatesQueue = new Denque();
|
|
68
|
+
this.accountsQueue = new Denque();
|
|
69
|
+
this.positionDetailsQueue = new Denque();
|
|
70
|
+
if (options?.fastQueryLastTick) {
|
|
71
|
+
this.fastQueryLastTick = options.fastQueryLastTick;
|
|
33
72
|
}
|
|
34
|
-
return t;
|
|
35
|
-
};
|
|
36
|
-
return __assign.apply(this, arguments);
|
|
37
|
-
};
|
|
38
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
39
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
40
|
-
};
|
|
41
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
42
|
-
exports.createTrader = exports.Trader = void 0;
|
|
43
|
-
var denque_1 = __importDefault(require("denque"));
|
|
44
|
-
var napi_ctp_1 = __importDefault(require("napi-ctp"));
|
|
45
|
-
var provider_js_1 = require("./provider.js");
|
|
46
|
-
var utils_js_1 = require("./utils.js");
|
|
47
|
-
var Trader = /** @class */ (function (_super) {
|
|
48
|
-
__extends(Trader, _super);
|
|
49
|
-
function Trader(flowTdPath, frontTdAddrs, userInfo, options) {
|
|
50
|
-
var _this = _super.call(this, flowTdPath, frontTdAddrs) || this;
|
|
51
|
-
_this.tradingDay = 0;
|
|
52
|
-
_this.frontId = 0;
|
|
53
|
-
_this.sessionId = 0;
|
|
54
|
-
_this.orderRef = 0;
|
|
55
|
-
_this.accountsQueryTime = 0;
|
|
56
|
-
_this.positionDetailsChanged = true;
|
|
57
|
-
_this.userInfo = userInfo;
|
|
58
|
-
_this.receivers = [];
|
|
59
|
-
_this.accounts = [];
|
|
60
|
-
_this.positionDetails = [];
|
|
61
|
-
_this.instruments = new Map();
|
|
62
|
-
_this.positions = new Map();
|
|
63
|
-
_this.orders = new Map();
|
|
64
|
-
_this.trades = new Map();
|
|
65
|
-
_this.marginRates = new Map();
|
|
66
|
-
_this.commRates = new Map();
|
|
67
|
-
_this.placeOrders = new Map();
|
|
68
|
-
_this.cancelOrders = new Map();
|
|
69
|
-
_this.marketOrdersQueue = new Map();
|
|
70
|
-
_this.priceLimit = new Map();
|
|
71
|
-
_this.orderStatistics = new Map();
|
|
72
|
-
_this.marginRatesQueue = new denque_1.default();
|
|
73
|
-
_this.commRatesQueue = new denque_1.default();
|
|
74
|
-
_this.accountsQueue = new denque_1.default();
|
|
75
|
-
_this.positionDetailsQueue = new denque_1.default();
|
|
76
|
-
if (options === null || options === void 0 ? void 0 : options.fastQueryLastTick) {
|
|
77
|
-
_this.fastQueryLastTick = options.fastQueryLastTick;
|
|
78
|
-
}
|
|
79
|
-
return _this;
|
|
80
73
|
}
|
|
81
|
-
|
|
82
|
-
var _this = this;
|
|
74
|
+
open(lifecycle) {
|
|
83
75
|
if (this.traderApi) {
|
|
84
76
|
return true;
|
|
85
77
|
}
|
|
86
|
-
this.traderApi =
|
|
87
|
-
this.traderApi.on(
|
|
88
|
-
|
|
78
|
+
this.traderApi = ctp.createTrader(this.flowPath, this.frontAddrs);
|
|
79
|
+
this.traderApi.on(ctp.TraderEvent.FrontConnected, () => {
|
|
80
|
+
this._withRetry(() => this.traderApi.reqAuthenticate(this.userInfo));
|
|
89
81
|
});
|
|
90
|
-
this.traderApi.on(
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
82
|
+
this.traderApi.on(ctp.TraderEvent.FrontDisconnected, () => {
|
|
83
|
+
this._clearAllMarketOrders();
|
|
84
|
+
this.placeOrders.clear();
|
|
85
|
+
this.cancelOrders.clear();
|
|
94
86
|
});
|
|
95
|
-
this.traderApi.on(
|
|
96
|
-
if (
|
|
87
|
+
this.traderApi.on(ctp.TraderEvent.RspAuthenticate, (_, options) => {
|
|
88
|
+
if (this._isErrorResp(lifecycle, options, "login-error")) {
|
|
97
89
|
return;
|
|
98
90
|
}
|
|
99
|
-
|
|
91
|
+
this._withRetry(() => this.traderApi.reqUserLogin(this.userInfo));
|
|
100
92
|
});
|
|
101
|
-
this.traderApi.on(
|
|
102
|
-
if (
|
|
93
|
+
this.traderApi.on(ctp.TraderEvent.RspUserLogin, (rspUserLogin, options) => {
|
|
94
|
+
if (this._isErrorResp(lifecycle, options, "login-error")) {
|
|
103
95
|
return;
|
|
104
96
|
}
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
if (
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
97
|
+
this.frontId = rspUserLogin.FrontID;
|
|
98
|
+
this.sessionId = rspUserLogin.SessionID;
|
|
99
|
+
this.orderRef = parseInt(rspUserLogin.MaxOrderRef);
|
|
100
|
+
const tradingDay = parseInt(this.traderApi.getTradingDay());
|
|
101
|
+
if (this.tradingDay !== tradingDay) {
|
|
102
|
+
this.marginRates.clear();
|
|
103
|
+
this.commRates.clear();
|
|
104
|
+
this.orderStatistics.clear();
|
|
105
|
+
this.priceLimit.clear();
|
|
106
|
+
this.tradingDay = tradingDay;
|
|
115
107
|
}
|
|
116
|
-
|
|
117
|
-
return _this.traderApi.reqSettlementInfoConfirm(_this.userInfo);
|
|
118
|
-
});
|
|
108
|
+
this._withRetry(() => this.traderApi.reqSettlementInfoConfirm(this.userInfo));
|
|
119
109
|
});
|
|
120
|
-
this.traderApi.on(
|
|
121
|
-
if (
|
|
110
|
+
this.traderApi.on(ctp.TraderEvent.RspSettlementInfoConfirm, (_, options) => {
|
|
111
|
+
if (this._isErrorResp(lifecycle, options, "login-error")) {
|
|
122
112
|
return;
|
|
123
113
|
}
|
|
124
|
-
|
|
125
|
-
|
|
114
|
+
this.orders.clear();
|
|
115
|
+
this._withRetry(() => this.traderApi.reqQryOrder(this.userInfo));
|
|
126
116
|
});
|
|
127
|
-
this.traderApi.on(
|
|
128
|
-
if (
|
|
117
|
+
this.traderApi.on(ctp.TraderEvent.RspQryOrder, (order, options) => {
|
|
118
|
+
if (this._isErrorResp(lifecycle, options, "query-order-error")) {
|
|
129
119
|
return;
|
|
130
120
|
}
|
|
131
121
|
if (order) {
|
|
132
|
-
|
|
133
|
-
|
|
122
|
+
const orderId = this._calcOrderId(order);
|
|
123
|
+
this.orders.set(orderId, order);
|
|
134
124
|
}
|
|
135
125
|
if (options.isLast) {
|
|
136
|
-
|
|
137
|
-
|
|
126
|
+
this.trades.clear();
|
|
127
|
+
this._withRetry(() => this.traderApi.reqQryTrade(this.userInfo));
|
|
138
128
|
}
|
|
139
129
|
});
|
|
140
|
-
this.traderApi.on(
|
|
141
|
-
if (
|
|
130
|
+
this.traderApi.on(ctp.TraderEvent.RspQryTrade, (trade, options) => {
|
|
131
|
+
if (this._isErrorResp(lifecycle, options, "query-trade-error")) {
|
|
142
132
|
return;
|
|
143
133
|
}
|
|
144
134
|
if (trade) {
|
|
145
|
-
|
|
146
|
-
|
|
135
|
+
const orderId = this._calcOrderId(trade);
|
|
136
|
+
const trades = this.trades.get(orderId);
|
|
147
137
|
if (trades) {
|
|
148
138
|
trades.push(trade);
|
|
149
139
|
}
|
|
150
140
|
else {
|
|
151
|
-
|
|
141
|
+
this.trades.set(orderId, [trade]);
|
|
152
142
|
}
|
|
153
143
|
}
|
|
154
144
|
if (options.isLast) {
|
|
155
|
-
|
|
156
|
-
|
|
145
|
+
this.instruments.clear();
|
|
146
|
+
this._withRetry(() => this.traderApi.reqQryInstrument());
|
|
157
147
|
}
|
|
158
148
|
});
|
|
159
|
-
this.traderApi.on(
|
|
160
|
-
if (
|
|
149
|
+
this.traderApi.on(ctp.TraderEvent.RspQryInstrument, (instrument, options) => {
|
|
150
|
+
if (this._isErrorResp(lifecycle, options, "query-instrument-error")) {
|
|
161
151
|
return;
|
|
162
152
|
}
|
|
163
153
|
if (instrument) {
|
|
164
|
-
if (instrument.ProductClass ===
|
|
165
|
-
instrument.ProductClass ===
|
|
166
|
-
|
|
154
|
+
if (instrument.ProductClass === ctp.ProductClassType.Futures ||
|
|
155
|
+
instrument.ProductClass === ctp.ProductClassType.Options) {
|
|
156
|
+
this.instruments.set(instrument.InstrumentID, instrument);
|
|
167
157
|
}
|
|
168
158
|
}
|
|
169
159
|
if (options.isLast) {
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
return _this.traderApi.reqQryInvestorPosition(_this.userInfo);
|
|
173
|
-
});
|
|
160
|
+
this.positions.clear();
|
|
161
|
+
this._withRetry(() => this.traderApi.reqQryInvestorPosition(this.userInfo));
|
|
174
162
|
}
|
|
175
163
|
});
|
|
176
|
-
|
|
177
|
-
this.traderApi.on(
|
|
178
|
-
if (
|
|
164
|
+
let fired = false;
|
|
165
|
+
this.traderApi.on(ctp.TraderEvent.RspQryInvestorPosition, (position, options) => {
|
|
166
|
+
if (this._isErrorResp(lifecycle, options, "query-positions-error")) {
|
|
179
167
|
return;
|
|
180
168
|
}
|
|
181
169
|
if (position) {
|
|
182
|
-
|
|
170
|
+
const symbol = this._toSymbol(position.InstrumentID);
|
|
183
171
|
if (symbol) {
|
|
184
|
-
|
|
185
|
-
|
|
172
|
+
let posInfo = this._ensurePositionInfo(symbol);
|
|
173
|
+
const ExchangeSH = ["SHFE", "INE"];
|
|
186
174
|
switch (position.PosiDirection) {
|
|
187
|
-
case
|
|
188
|
-
if (position.PositionDate ===
|
|
175
|
+
case ctp.PosiDirectionType.Long:
|
|
176
|
+
if (position.PositionDate === ctp.PositionDateType.Today) {
|
|
189
177
|
if (ExchangeSH.includes(position.ExchangeID)) {
|
|
190
178
|
posInfo.today.long.position += position.TodayPosition;
|
|
191
179
|
}
|
|
@@ -198,8 +186,8 @@ var Trader = /** @class */ (function (_super) {
|
|
|
198
186
|
position.Position - position.TodayPosition;
|
|
199
187
|
}
|
|
200
188
|
break;
|
|
201
|
-
case
|
|
202
|
-
if (position.PositionDate ===
|
|
189
|
+
case ctp.PosiDirectionType.Short:
|
|
190
|
+
if (position.PositionDate === ctp.PositionDateType.Today) {
|
|
203
191
|
if (ExchangeSH.includes(position.ExchangeID)) {
|
|
204
192
|
posInfo.today.short.position += position.TodayPosition;
|
|
205
193
|
}
|
|
@@ -220,271 +208,259 @@ var Trader = /** @class */ (function (_super) {
|
|
|
220
208
|
fired = true;
|
|
221
209
|
lifecycle.onOpen();
|
|
222
210
|
}
|
|
223
|
-
if (
|
|
224
|
-
|
|
225
|
-
return _this.traderApi.reqQryTradingAccount(_this.userInfo);
|
|
226
|
-
});
|
|
211
|
+
if (this.accountsQueue.size() > 0) {
|
|
212
|
+
this._withRetry(() => this.traderApi.reqQryTradingAccount(this.userInfo));
|
|
227
213
|
}
|
|
228
|
-
if (
|
|
229
|
-
|
|
230
|
-
return _this.traderApi.reqQryInvestorPositionDetail(_this.userInfo);
|
|
231
|
-
});
|
|
214
|
+
if (this.positionDetailsQueue.size() > 0) {
|
|
215
|
+
this._withRetry(() => this.traderApi.reqQryInvestorPositionDetail(this.userInfo));
|
|
232
216
|
}
|
|
233
|
-
|
|
234
|
-
|
|
217
|
+
this._processMarginRatesQueue();
|
|
218
|
+
this._processCommissionRatesQueue();
|
|
235
219
|
}
|
|
236
220
|
});
|
|
237
|
-
this.traderApi.on(
|
|
238
|
-
|
|
239
|
-
|
|
221
|
+
this.traderApi.on(ctp.TraderEvent.RtnOrder, (order) => {
|
|
222
|
+
const orderId = this._calcOrderId(order);
|
|
223
|
+
const current = this.orders.get(orderId);
|
|
240
224
|
if (current) {
|
|
241
225
|
if (order.OrderSubmitStatus === current.OrderSubmitStatus &&
|
|
242
226
|
order.OrderStatus === current.OrderStatus) {
|
|
243
227
|
return;
|
|
244
228
|
}
|
|
245
229
|
}
|
|
246
|
-
|
|
247
|
-
switch (
|
|
230
|
+
this.orders.set(orderId, order);
|
|
231
|
+
switch (this._calcOrderStatus(order)) {
|
|
248
232
|
case "submitted":
|
|
249
233
|
{
|
|
250
|
-
|
|
251
|
-
|
|
234
|
+
const orderData = this._toOrderData(order);
|
|
235
|
+
const symbol = this._toSymbol(order.InstrumentID);
|
|
252
236
|
if (symbol) {
|
|
253
|
-
if (
|
|
254
|
-
|
|
237
|
+
if (orderData.offset === "open") {
|
|
238
|
+
this._recordPending(symbol, orderData.side, orderData.offset, orderData.volume);
|
|
255
239
|
}
|
|
256
240
|
else {
|
|
257
|
-
|
|
241
|
+
this._freezePosition(symbol, orderData.side, orderData.offset, orderData.volume);
|
|
258
242
|
}
|
|
259
|
-
|
|
243
|
+
const statistic = this._ensureOrderStatistic(symbol);
|
|
260
244
|
statistic.entrusts += 1;
|
|
261
245
|
}
|
|
262
|
-
|
|
246
|
+
this.receivers.forEach((receiver) => receiver.onEntrust(orderData));
|
|
263
247
|
}
|
|
264
248
|
break;
|
|
265
249
|
case "filled":
|
|
266
250
|
{
|
|
267
|
-
|
|
251
|
+
const symbol = this._toSymbol(order.InstrumentID);
|
|
268
252
|
if (symbol) {
|
|
269
|
-
|
|
253
|
+
const statistic = this._ensureOrderStatistic(symbol);
|
|
270
254
|
statistic.filleds += 1;
|
|
271
255
|
}
|
|
272
256
|
}
|
|
273
257
|
break;
|
|
274
258
|
case "canceled":
|
|
275
259
|
{
|
|
276
|
-
|
|
277
|
-
|
|
260
|
+
const orderData = this._toOrderData(order);
|
|
261
|
+
const symbol = this._toSymbol(order.InstrumentID);
|
|
278
262
|
if (symbol) {
|
|
279
|
-
if (
|
|
280
|
-
|
|
263
|
+
if (orderData.offset === "open") {
|
|
264
|
+
this._recoverPending(symbol, orderData.side, orderData.offset, orderData.volume);
|
|
281
265
|
}
|
|
282
266
|
else {
|
|
283
|
-
|
|
267
|
+
this._unfreezePosition(symbol, orderData.side, orderData.offset, orderData.volume);
|
|
284
268
|
}
|
|
285
|
-
|
|
269
|
+
const statistic = this._ensureOrderStatistic(symbol);
|
|
286
270
|
statistic.cancels += 1;
|
|
287
271
|
}
|
|
288
|
-
|
|
272
|
+
this.receivers.forEach((receiver) => receiver.onCancel(orderData));
|
|
289
273
|
}
|
|
290
274
|
break;
|
|
291
275
|
case "rejected":
|
|
292
276
|
{
|
|
293
|
-
|
|
294
|
-
|
|
277
|
+
const orderData = this._toOrderData(order);
|
|
278
|
+
const symbol = this._toSymbol(order.InstrumentID);
|
|
295
279
|
if (symbol) {
|
|
296
|
-
|
|
280
|
+
const statistic = this._ensureOrderStatistic(symbol);
|
|
297
281
|
statistic.rejects += 1;
|
|
298
282
|
}
|
|
299
|
-
|
|
283
|
+
this.receivers.forEach((receiver) => receiver.onReject(orderData));
|
|
300
284
|
}
|
|
301
285
|
break;
|
|
302
286
|
}
|
|
303
287
|
});
|
|
304
|
-
this.traderApi.on(
|
|
305
|
-
|
|
306
|
-
|
|
288
|
+
this.traderApi.on(ctp.TraderEvent.RtnTrade, (trade) => {
|
|
289
|
+
const orderId = this._calcOrderId(trade);
|
|
290
|
+
const trades = this.trades.get(orderId);
|
|
307
291
|
if (trades) {
|
|
308
292
|
trades.push(trade);
|
|
309
293
|
}
|
|
310
294
|
else {
|
|
311
|
-
|
|
295
|
+
this.trades.set(orderId, [trade]);
|
|
312
296
|
}
|
|
313
|
-
|
|
314
|
-
|
|
297
|
+
this.positionDetailsChanged = true;
|
|
298
|
+
const order = this.orders.get(orderId);
|
|
315
299
|
if (order) {
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
300
|
+
const orderData = this._toOrderData(order);
|
|
301
|
+
const tradeData = this._toTradeData(trade);
|
|
302
|
+
const symbol = this._toSymbol(order.InstrumentID);
|
|
319
303
|
if (symbol) {
|
|
320
|
-
|
|
304
|
+
this._calcPosition(symbol, orderData.side, orderData.offset, tradeData.volume);
|
|
321
305
|
}
|
|
322
|
-
|
|
323
|
-
return receiver.onTrade(orderData_4, tradeData_1);
|
|
324
|
-
});
|
|
306
|
+
this.receivers.forEach((receiver) => receiver.onTrade(orderData, tradeData));
|
|
325
307
|
}
|
|
326
308
|
});
|
|
327
|
-
this.traderApi.on(
|
|
328
|
-
|
|
329
|
-
if (
|
|
309
|
+
this.traderApi.on(ctp.TraderEvent.RspQryInstrumentMarginRate, (marginRate, options) => {
|
|
310
|
+
const query = this.marginRatesQueue.shift();
|
|
311
|
+
if (this._isErrorResp(lifecycle, options, "query-margin-rate-error")) {
|
|
330
312
|
if (query) {
|
|
331
313
|
query.receiver.onMarginRate(undefined);
|
|
332
314
|
}
|
|
333
315
|
return;
|
|
334
316
|
}
|
|
335
317
|
if (marginRate) {
|
|
336
|
-
|
|
318
|
+
this.marginRates.set(marginRate.InstrumentID, marginRate);
|
|
337
319
|
if (query) {
|
|
338
|
-
query.receiver.onMarginRate(
|
|
320
|
+
query.receiver.onMarginRate(this._toMarginRate(query.symbol, marginRate));
|
|
339
321
|
}
|
|
340
322
|
}
|
|
341
|
-
|
|
323
|
+
this._processMarginRatesQueue();
|
|
342
324
|
});
|
|
343
|
-
this.traderApi.on(
|
|
344
|
-
|
|
345
|
-
if (
|
|
325
|
+
this.traderApi.on(ctp.TraderEvent.RspQryInstrumentCommissionRate, (commRate, options) => {
|
|
326
|
+
const query = this.commRatesQueue.shift();
|
|
327
|
+
if (this._isErrorResp(lifecycle, options, "query-commission-rate-error")) {
|
|
346
328
|
if (query) {
|
|
347
329
|
query.receiver.onCommissionRate(undefined);
|
|
348
330
|
}
|
|
349
331
|
return;
|
|
350
332
|
}
|
|
351
333
|
if (commRate) {
|
|
352
|
-
|
|
334
|
+
this.commRates.set(commRate.InstrumentID, commRate);
|
|
353
335
|
if (query) {
|
|
354
|
-
query.receiver.onCommissionRate(
|
|
336
|
+
query.receiver.onCommissionRate(this._toCommissionRate(query.symbol, commRate));
|
|
355
337
|
}
|
|
356
338
|
}
|
|
357
|
-
|
|
339
|
+
this._processCommissionRatesQueue();
|
|
358
340
|
});
|
|
359
|
-
this.traderApi.on(
|
|
360
|
-
if (
|
|
361
|
-
|
|
362
|
-
receivers.forEach(
|
|
363
|
-
|
|
364
|
-
});
|
|
365
|
-
_this.accountsQueue.clear();
|
|
341
|
+
this.traderApi.on(ctp.TraderEvent.RspQryTradingAccount, (account, options) => {
|
|
342
|
+
if (this._isErrorResp(lifecycle, options, "query-accounts-error")) {
|
|
343
|
+
const receivers = this.accountsQueue.toArray();
|
|
344
|
+
receivers.forEach((receiver) => receiver.onTradingAccounts(undefined));
|
|
345
|
+
this.accountsQueue.clear();
|
|
366
346
|
return;
|
|
367
347
|
}
|
|
368
348
|
if (account) {
|
|
369
|
-
|
|
349
|
+
this.accounts.push(account);
|
|
370
350
|
}
|
|
371
351
|
if (options.isLast) {
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
receivers.forEach(
|
|
375
|
-
|
|
376
|
-
|
|
352
|
+
const accounts = this.accounts.map(this._toTradingAccount, this);
|
|
353
|
+
const receivers = this.accountsQueue.toArray();
|
|
354
|
+
receivers.forEach((receiver) => receiver.onTradingAccounts(accounts));
|
|
355
|
+
this.accountsQueue.clear();
|
|
356
|
+
this.accountsQueryTime = Date.now();
|
|
377
357
|
}
|
|
378
358
|
});
|
|
379
|
-
this.traderApi.on(
|
|
380
|
-
if (
|
|
381
|
-
|
|
382
|
-
receivers.forEach(
|
|
383
|
-
|
|
384
|
-
});
|
|
385
|
-
_this.positionDetailsQueue.clear();
|
|
359
|
+
this.traderApi.on(ctp.TraderEvent.RspQryInvestorPositionDetail, (positionDetail, options) => {
|
|
360
|
+
if (this._isErrorResp(lifecycle, options, "query-position-details-error")) {
|
|
361
|
+
const receivers = this.positionDetailsQueue.toArray();
|
|
362
|
+
receivers.forEach((receiver) => receiver.onPositionDetails(undefined));
|
|
363
|
+
this.positionDetailsQueue.clear();
|
|
386
364
|
return;
|
|
387
365
|
}
|
|
388
366
|
if (positionDetail) {
|
|
389
|
-
|
|
367
|
+
this.positionDetails.push(positionDetail);
|
|
390
368
|
}
|
|
391
369
|
if (options.isLast) {
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
receivers.forEach(
|
|
396
|
-
|
|
397
|
-
});
|
|
398
|
-
_this.positionDetailsQueue.clear();
|
|
370
|
+
const positionDetails = this.positionDetails.map(this._toPositionDetail, this);
|
|
371
|
+
const receivers = this.positionDetailsQueue.toArray();
|
|
372
|
+
this.positionDetailsChanged = false;
|
|
373
|
+
receivers.forEach((receiver) => receiver.onPositionDetails(positionDetails));
|
|
374
|
+
this.positionDetailsQueue.clear();
|
|
399
375
|
}
|
|
400
376
|
});
|
|
401
|
-
this.traderApi.on(
|
|
377
|
+
this.traderApi.on(ctp.TraderEvent.RspOrderInsert, (order, options) => {
|
|
402
378
|
if (options.rspInfo && order && options.requestId && options.isLast) {
|
|
403
|
-
|
|
379
|
+
const receiver = this.placeOrders.get(options.requestId);
|
|
404
380
|
if (receiver) {
|
|
405
|
-
|
|
406
|
-
receiver.onPlaceOrderError(
|
|
381
|
+
this.placeOrders.delete(options.requestId);
|
|
382
|
+
receiver.onPlaceOrderError(`${options.rspInfo.ErrorID}: ${options.rspInfo.ErrorMsg}`);
|
|
407
383
|
}
|
|
408
384
|
}
|
|
409
385
|
});
|
|
410
|
-
this.traderApi.on(
|
|
386
|
+
this.traderApi.on(ctp.TraderEvent.RspOrderAction, (order, options) => {
|
|
411
387
|
if (options.rspInfo && order && options.requestId && options.isLast) {
|
|
412
|
-
|
|
388
|
+
const receiver = this.cancelOrders.get(options.requestId);
|
|
413
389
|
if (receiver) {
|
|
414
|
-
|
|
415
|
-
receiver.onCancelOrderError(
|
|
390
|
+
this.cancelOrders.delete(options.requestId);
|
|
391
|
+
receiver.onCancelOrderError(`${options.rspInfo.ErrorID}: ${options.rspInfo.ErrorMsg}`);
|
|
416
392
|
}
|
|
417
393
|
}
|
|
418
394
|
});
|
|
419
|
-
this.traderApi.on(
|
|
420
|
-
if (
|
|
421
|
-
|
|
395
|
+
this.traderApi.on(ctp.TraderEvent.RspQryDepthMarketData, (depthMarketData, options) => {
|
|
396
|
+
if (this._isErrorResp(lifecycle, options, "query-depth-market-data-error")) {
|
|
397
|
+
this._clearAllMarketOrders();
|
|
422
398
|
return;
|
|
423
399
|
}
|
|
424
|
-
|
|
425
|
-
!
|
|
400
|
+
const isLimitPrice = !isValidPrice(depthMarketData.BandingUpperPrice) ||
|
|
401
|
+
!isValidPrice(depthMarketData.BandingLowerPrice);
|
|
426
402
|
if (isLimitPrice) {
|
|
427
|
-
|
|
403
|
+
this.priceLimit.set(depthMarketData.InstrumentID, {
|
|
428
404
|
upper: depthMarketData.UpperLimitPrice,
|
|
429
405
|
lower: depthMarketData.LowerLimitPrice,
|
|
430
406
|
});
|
|
431
407
|
}
|
|
432
|
-
|
|
408
|
+
const queue = this.marketOrdersQueue.get(depthMarketData.InstrumentID);
|
|
433
409
|
if (!queue) {
|
|
434
410
|
return;
|
|
435
411
|
}
|
|
436
412
|
if (!queue.isEmpty()) {
|
|
437
|
-
|
|
413
|
+
const upperPrice = isLimitPrice
|
|
438
414
|
? depthMarketData.UpperLimitPrice
|
|
439
415
|
: depthMarketData.BandingUpperPrice;
|
|
440
|
-
|
|
416
|
+
const lowerPrice = isLimitPrice
|
|
441
417
|
? depthMarketData.LowerLimitPrice
|
|
442
418
|
: depthMarketData.BandingLowerPrice;
|
|
443
|
-
|
|
444
|
-
orders.forEach(
|
|
419
|
+
const orders = queue.toArray();
|
|
420
|
+
orders.forEach((order) => {
|
|
445
421
|
switch (order.side) {
|
|
446
422
|
case "long":
|
|
447
|
-
|
|
423
|
+
this._placeLimitOrder(order.symbol, order.offset, order.side, order.volume, upperPrice, order.receiver);
|
|
448
424
|
break;
|
|
449
425
|
case "short":
|
|
450
|
-
|
|
426
|
+
this._placeLimitOrder(order.symbol, order.offset, order.side, order.volume, lowerPrice, order.receiver);
|
|
451
427
|
break;
|
|
452
428
|
}
|
|
453
429
|
});
|
|
454
430
|
}
|
|
455
|
-
|
|
431
|
+
this.marketOrdersQueue.delete(depthMarketData.InstrumentID);
|
|
456
432
|
});
|
|
457
433
|
return true;
|
|
458
|
-
}
|
|
459
|
-
|
|
434
|
+
}
|
|
435
|
+
close(lifecycle) {
|
|
460
436
|
if (!this.traderApi) {
|
|
461
437
|
return;
|
|
462
438
|
}
|
|
463
439
|
this.traderApi.close();
|
|
464
440
|
this.traderApi = undefined;
|
|
465
441
|
lifecycle.onClose();
|
|
466
|
-
}
|
|
467
|
-
|
|
442
|
+
}
|
|
443
|
+
addOrderReceiver(receiver) {
|
|
468
444
|
if (!this.receivers.includes(receiver)) {
|
|
469
445
|
this.receivers.push(receiver);
|
|
470
446
|
}
|
|
471
|
-
}
|
|
472
|
-
|
|
473
|
-
|
|
447
|
+
}
|
|
448
|
+
removeOrderReceiver(receiver) {
|
|
449
|
+
const index = this.receivers.indexOf(receiver);
|
|
474
450
|
if (index < 0) {
|
|
475
451
|
return;
|
|
476
452
|
}
|
|
477
453
|
this.receivers.splice(index, 1);
|
|
478
|
-
}
|
|
479
|
-
|
|
454
|
+
}
|
|
455
|
+
getTradingDay() {
|
|
480
456
|
return this.tradingDay;
|
|
481
|
-
}
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
return statistics.map(
|
|
485
|
-
}
|
|
486
|
-
|
|
487
|
-
|
|
457
|
+
}
|
|
458
|
+
getOrderStatistics() {
|
|
459
|
+
const statistics = Array.from(this.orderStatistics.values());
|
|
460
|
+
return statistics.map((stat) => Object.freeze({ ...stat }));
|
|
461
|
+
}
|
|
462
|
+
getOrderStatistic(symbol) {
|
|
463
|
+
const statistic = this.orderStatistics.get(symbol);
|
|
488
464
|
if (!statistic) {
|
|
489
465
|
return Object.freeze({
|
|
490
466
|
symbol: symbol,
|
|
@@ -495,54 +471,53 @@ var Trader = /** @class */ (function (_super) {
|
|
|
495
471
|
rejects: 0,
|
|
496
472
|
});
|
|
497
473
|
}
|
|
498
|
-
return Object.freeze(
|
|
499
|
-
}
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
var commRate = this.commRates.get(instrumentId);
|
|
474
|
+
return Object.freeze({ ...statistic });
|
|
475
|
+
}
|
|
476
|
+
queryCommissionRate(symbol, receiver) {
|
|
477
|
+
const [instrumentId] = parseSymbol(symbol);
|
|
478
|
+
const commRate = this.commRates.get(instrumentId);
|
|
504
479
|
if (commRate) {
|
|
505
480
|
receiver.onCommissionRate(this._toCommissionRate(symbol, commRate));
|
|
506
481
|
return;
|
|
507
482
|
}
|
|
508
|
-
this.commRatesQueue.push({ symbol
|
|
483
|
+
this.commRatesQueue.push({ symbol, receiver });
|
|
509
484
|
if (this.commRatesQueue.size() === 1) {
|
|
510
|
-
this._withRetry(
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
});
|
|
485
|
+
this._withRetry(() => this.traderApi?.reqQryInstrumentCommissionRate({
|
|
486
|
+
...this.userInfo,
|
|
487
|
+
InstrumentID: instrumentId,
|
|
488
|
+
}));
|
|
514
489
|
}
|
|
515
|
-
}
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
var marginRate = this.marginRates.get(instrumentId);
|
|
490
|
+
}
|
|
491
|
+
queryMarginRate(symbol, receiver) {
|
|
492
|
+
const [instrumentId] = parseSymbol(symbol);
|
|
493
|
+
const marginRate = this.marginRates.get(instrumentId);
|
|
520
494
|
if (marginRate) {
|
|
521
495
|
receiver.onMarginRate(this._toMarginRate(symbol, marginRate));
|
|
522
496
|
return;
|
|
523
497
|
}
|
|
524
|
-
this.marginRatesQueue.push({ symbol
|
|
498
|
+
this.marginRatesQueue.push({ symbol, receiver });
|
|
525
499
|
if (this.marginRatesQueue.size() === 1) {
|
|
526
|
-
this._withRetry(
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
500
|
+
this._withRetry(() => this.traderApi?.reqQryInstrumentMarginRate({
|
|
501
|
+
...this.userInfo,
|
|
502
|
+
HedgeFlag: ctp.HedgeFlagType.Speculation,
|
|
503
|
+
InstrumentID: instrumentId,
|
|
504
|
+
}));
|
|
530
505
|
}
|
|
531
|
-
}
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
506
|
+
}
|
|
507
|
+
queryInstrument(symbol, receiver) {
|
|
508
|
+
const [instrumentId, exchangeId] = parseSymbol(symbol);
|
|
509
|
+
const instrument = this.instruments.get(instrumentId);
|
|
535
510
|
receiver.onInstrument(instrument && instrument.ExchangeID === exchangeId
|
|
536
511
|
? this._toInstrumentData(instrument)
|
|
537
512
|
: undefined);
|
|
538
|
-
}
|
|
539
|
-
|
|
540
|
-
|
|
513
|
+
}
|
|
514
|
+
queryPosition(symbol, receiver) {
|
|
515
|
+
const position = this.positions.get(symbol);
|
|
541
516
|
if (position) {
|
|
542
517
|
receiver.onPosition(this._toPositionData(position));
|
|
543
518
|
return;
|
|
544
519
|
}
|
|
545
|
-
|
|
520
|
+
const [instrumentId] = parseSymbol(symbol);
|
|
546
521
|
if (!this.instruments.has(instrumentId)) {
|
|
547
522
|
receiver.onPosition(undefined);
|
|
548
523
|
return;
|
|
@@ -559,46 +534,40 @@ var Trader = /** @class */ (function (_super) {
|
|
|
559
534
|
}),
|
|
560
535
|
pending: Object.freeze({ long: 0, short: 0 }),
|
|
561
536
|
}));
|
|
562
|
-
}
|
|
563
|
-
|
|
564
|
-
|
|
537
|
+
}
|
|
538
|
+
queryInstruments(receiver, type) {
|
|
539
|
+
const instruments = Array.from(this.instruments.values());
|
|
565
540
|
switch (type) {
|
|
566
541
|
case "futures":
|
|
567
542
|
receiver.onInstruments(instruments
|
|
568
|
-
.filter(
|
|
569
|
-
return instrument.ProductClass === napi_ctp_1.default.ProductClassType.Futures;
|
|
570
|
-
})
|
|
543
|
+
.filter((instrument) => instrument.ProductClass === ctp.ProductClassType.Futures)
|
|
571
544
|
.map(this._toInstrumentData, this));
|
|
572
545
|
break;
|
|
573
546
|
case "options":
|
|
574
547
|
receiver.onInstruments(instruments
|
|
575
|
-
.filter(
|
|
576
|
-
return instrument.ProductClass === napi_ctp_1.default.ProductClassType.Options;
|
|
577
|
-
})
|
|
548
|
+
.filter((instrument) => instrument.ProductClass === ctp.ProductClassType.Options)
|
|
578
549
|
.map(this._toInstrumentData, this));
|
|
579
550
|
break;
|
|
580
551
|
default:
|
|
581
552
|
receiver.onInstruments(instruments.map(this._toInstrumentData, this));
|
|
582
553
|
break;
|
|
583
554
|
}
|
|
584
|
-
}
|
|
585
|
-
|
|
586
|
-
var _this = this;
|
|
555
|
+
}
|
|
556
|
+
queryTradingAccounts(receiver) {
|
|
587
557
|
if (this.accountsQueue.size() > 0) {
|
|
588
558
|
this.accountsQueue.push(receiver);
|
|
589
559
|
return;
|
|
590
560
|
}
|
|
591
|
-
|
|
561
|
+
const elapsed = Date.now() - this.accountsQueryTime;
|
|
592
562
|
if (elapsed < 3000) {
|
|
593
563
|
receiver.onTradingAccounts(this.accounts.map(this._toTradingAccount, this));
|
|
594
564
|
return;
|
|
595
565
|
}
|
|
596
566
|
this.accountsQueue.push(receiver);
|
|
597
567
|
this.accounts.splice(0, this.accounts.length);
|
|
598
|
-
this._withRetry(
|
|
599
|
-
}
|
|
600
|
-
|
|
601
|
-
var _this = this;
|
|
568
|
+
this._withRetry(() => this.traderApi?.reqQryTradingAccount(this.userInfo));
|
|
569
|
+
}
|
|
570
|
+
queryPositionDetails(receiver) {
|
|
602
571
|
if (this.positionDetailsQueue.size() > 0) {
|
|
603
572
|
this.positionDetailsQueue.push(receiver);
|
|
604
573
|
return;
|
|
@@ -609,28 +578,23 @@ var Trader = /** @class */ (function (_super) {
|
|
|
609
578
|
}
|
|
610
579
|
this.positionDetailsQueue.push(receiver);
|
|
611
580
|
this.positionDetails.splice(0, this.positionDetails.length);
|
|
612
|
-
this._withRetry(
|
|
613
|
-
}
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
this.positions.forEach(function (position) {
|
|
618
|
-
return positions.push(_this._toPositionData(position));
|
|
619
|
-
});
|
|
581
|
+
this._withRetry(() => this.traderApi?.reqQryInvestorPositionDetail(this.userInfo));
|
|
582
|
+
}
|
|
583
|
+
queryPositions(receiver) {
|
|
584
|
+
const positions = [];
|
|
585
|
+
this.positions.forEach((position) => positions.push(this._toPositionData(position)));
|
|
620
586
|
receiver.onPositions(positions);
|
|
621
|
-
}
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
orders.push(_this._toOrderData(order));
|
|
587
|
+
}
|
|
588
|
+
queryOrders(receiver) {
|
|
589
|
+
const orders = [];
|
|
590
|
+
this.orders.forEach((order) => {
|
|
591
|
+
orders.push(this._toOrderData(order));
|
|
627
592
|
});
|
|
628
593
|
receiver.onOrders(orders);
|
|
629
|
-
}
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
var instrument = this.instruments.get(instrumentId);
|
|
594
|
+
}
|
|
595
|
+
_placeLimitOrder(symbol, offset, side, volume, price, receiver) {
|
|
596
|
+
const [instrumentId, exchangeId] = parseSymbol(symbol);
|
|
597
|
+
const instrument = this.instruments.get(instrumentId);
|
|
634
598
|
if (!instrument) {
|
|
635
599
|
receiver.onPlaceOrderError("Instrument Not Found");
|
|
636
600
|
return;
|
|
@@ -639,37 +603,52 @@ var Trader = /** @class */ (function (_super) {
|
|
|
639
603
|
receiver.onPlaceOrderError("Exchange Id Error");
|
|
640
604
|
return;
|
|
641
605
|
}
|
|
642
|
-
|
|
643
|
-
this._withRetry(
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
606
|
+
let orderRef = 0;
|
|
607
|
+
this._withRetry(() => {
|
|
608
|
+
orderRef = ++this.orderRef;
|
|
609
|
+
return this.traderApi?.reqOrderInsert({
|
|
610
|
+
...this.userInfo,
|
|
611
|
+
OrderRef: `${orderRef}`,
|
|
612
|
+
InstrumentID: instrumentId,
|
|
613
|
+
ExchangeID: instrument.ExchangeID,
|
|
614
|
+
LimitPrice: price,
|
|
615
|
+
VolumeTotalOriginal: volume,
|
|
616
|
+
VolumeCondition: ctp.VolumeConditionType.AV,
|
|
617
|
+
TimeCondition: ctp.TimeConditionType.GFD,
|
|
618
|
+
Direction: this._toDirection(side),
|
|
619
|
+
OrderPriceType: ctp.OrderPriceTypeType.LimitPrice,
|
|
620
|
+
CombOffsetFlag: this._toOffsetFlag(offset),
|
|
621
|
+
CombHedgeFlag: ctp.HedgeFlagType.Speculation,
|
|
622
|
+
ContingentCondition: ctp.ContingentConditionType.Immediately,
|
|
623
|
+
ForceCloseReason: ctp.ForceCloseReasonType.NotForceClose,
|
|
624
|
+
IsAutoSuspend: 0,
|
|
625
|
+
UserForceClose: 0,
|
|
626
|
+
});
|
|
627
|
+
}).then((requestId) => {
|
|
648
628
|
if (!requestId || requestId < 0) {
|
|
649
629
|
receiver.onPlaceOrderError("Request Error");
|
|
650
630
|
return;
|
|
651
631
|
}
|
|
652
|
-
|
|
632
|
+
const statistic = this._ensureOrderStatistic(symbol);
|
|
653
633
|
statistic.places += 1;
|
|
654
|
-
|
|
655
|
-
|
|
634
|
+
this.placeOrders.set(requestId, receiver);
|
|
635
|
+
const receiptId = `${this.frontId}:${this.sessionId}:${orderRef}`;
|
|
656
636
|
receiver.onPlaceOrderSent(receiptId);
|
|
657
637
|
return receiptId;
|
|
658
638
|
});
|
|
659
|
-
}
|
|
660
|
-
|
|
661
|
-
this.marketOrdersQueue.forEach(
|
|
662
|
-
|
|
663
|
-
orders.forEach(
|
|
639
|
+
}
|
|
640
|
+
_clearAllMarketOrders() {
|
|
641
|
+
this.marketOrdersQueue.forEach((queue) => {
|
|
642
|
+
const orders = queue.toArray();
|
|
643
|
+
orders.forEach((order) => {
|
|
664
644
|
order.receiver.onPlaceOrderError("Request Error");
|
|
665
645
|
});
|
|
666
646
|
});
|
|
667
647
|
this.marketOrdersQueue.clear();
|
|
668
|
-
}
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
var instrument = this.instruments.get(instrumentId);
|
|
648
|
+
}
|
|
649
|
+
_placeMarketOrder(symbol, offset, side, volume, receiver) {
|
|
650
|
+
const [instrumentId, exchangeId] = parseSymbol(symbol);
|
|
651
|
+
const instrument = this.instruments.get(instrumentId);
|
|
673
652
|
if (!instrument) {
|
|
674
653
|
receiver.onPlaceOrderError("Instrument Not Found");
|
|
675
654
|
return;
|
|
@@ -678,7 +657,7 @@ var Trader = /** @class */ (function (_super) {
|
|
|
678
657
|
receiver.onPlaceOrderError("Exchange Id Error");
|
|
679
658
|
return;
|
|
680
659
|
}
|
|
681
|
-
|
|
660
|
+
const priceRange = this.priceLimit.get(instrumentId);
|
|
682
661
|
if (priceRange) {
|
|
683
662
|
switch (side) {
|
|
684
663
|
case "long":
|
|
@@ -691,17 +670,17 @@ var Trader = /** @class */ (function (_super) {
|
|
|
691
670
|
return;
|
|
692
671
|
}
|
|
693
672
|
if (this.fastQueryLastTick) {
|
|
694
|
-
|
|
673
|
+
const lastTick = this.fastQueryLastTick(instrumentId);
|
|
695
674
|
if (lastTick && lastTick.tradingDay === this.tradingDay) {
|
|
696
|
-
|
|
697
|
-
!
|
|
675
|
+
const isLimitPrice = !isValidPrice(lastTick.bandings.upper) ||
|
|
676
|
+
!isValidPrice(lastTick.bandings.lower);
|
|
698
677
|
if (isLimitPrice) {
|
|
699
|
-
this.priceLimit.set(instrumentId,
|
|
678
|
+
this.priceLimit.set(instrumentId, { ...lastTick.limits });
|
|
700
679
|
}
|
|
701
|
-
|
|
680
|
+
const upperPrice = isLimitPrice
|
|
702
681
|
? lastTick.limits.upper
|
|
703
682
|
: lastTick.bandings.upper;
|
|
704
|
-
|
|
683
|
+
const lowerPrice = isLimitPrice
|
|
705
684
|
? lastTick.limits.lower
|
|
706
685
|
: lastTick.bandings.lower;
|
|
707
686
|
switch (side) {
|
|
@@ -715,42 +694,42 @@ var Trader = /** @class */ (function (_super) {
|
|
|
715
694
|
return;
|
|
716
695
|
}
|
|
717
696
|
}
|
|
718
|
-
|
|
697
|
+
let queue = this.marketOrdersQueue.get(instrumentId);
|
|
719
698
|
if (queue) {
|
|
720
|
-
queue.push({ symbol
|
|
699
|
+
queue.push({ symbol, offset, side, volume, receiver });
|
|
721
700
|
return;
|
|
722
701
|
}
|
|
723
|
-
queue = new
|
|
702
|
+
queue = new Denque();
|
|
724
703
|
this.marketOrdersQueue.set(instrumentId, queue);
|
|
725
|
-
this._withRetry(
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
InstrumentID: instrumentId,
|
|
730
|
-
});
|
|
731
|
-
}).then(function (requestId) {
|
|
704
|
+
this._withRetry(() => this.traderApi?.reqQryDepthMarketData({
|
|
705
|
+
ExchangeID: exchangeId,
|
|
706
|
+
InstrumentID: instrumentId,
|
|
707
|
+
})).then((requestId) => {
|
|
732
708
|
if (!requestId || requestId < 0) {
|
|
733
|
-
|
|
734
|
-
orders.forEach(
|
|
709
|
+
const orders = queue.toArray();
|
|
710
|
+
orders.forEach((order) => {
|
|
735
711
|
order.receiver.onPlaceOrderError("Request Error");
|
|
736
712
|
});
|
|
737
|
-
|
|
713
|
+
this.marketOrdersQueue.delete(instrumentId);
|
|
738
714
|
return;
|
|
739
715
|
}
|
|
740
|
-
queue.push({ symbol
|
|
716
|
+
queue.push({ symbol, offset, side, volume, receiver });
|
|
741
717
|
});
|
|
742
|
-
}
|
|
743
|
-
|
|
718
|
+
}
|
|
719
|
+
placeOrder(symbol, offset, side, volume, price, flag, receiver) {
|
|
720
|
+
if (volume <= 0) {
|
|
721
|
+
receiver.onPlaceOrderError("Invalid Volume");
|
|
722
|
+
return;
|
|
723
|
+
}
|
|
744
724
|
switch (flag) {
|
|
745
725
|
case "limit":
|
|
746
726
|
return this._placeLimitOrder(symbol, offset, side, volume, price, receiver);
|
|
747
727
|
case "market":
|
|
748
728
|
return this._placeMarketOrder(symbol, offset, side, volume, receiver);
|
|
749
729
|
}
|
|
750
|
-
}
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
var current = this.orders.get(order.id);
|
|
730
|
+
}
|
|
731
|
+
cancelOrder(order, receiver) {
|
|
732
|
+
const current = this.orders.get(order.id);
|
|
754
733
|
if (!current) {
|
|
755
734
|
receiver.onCancelOrderError("Order Not Found");
|
|
756
735
|
return;
|
|
@@ -759,43 +738,49 @@ var Trader = /** @class */ (function (_super) {
|
|
|
759
738
|
receiver.onCancelOrderError("Already Canceled");
|
|
760
739
|
return;
|
|
761
740
|
}
|
|
762
|
-
this._withRetry(
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
741
|
+
this._withRetry(() => this.traderApi?.reqOrderAction({
|
|
742
|
+
...this.userInfo,
|
|
743
|
+
InstrumentID: current.InstrumentID,
|
|
744
|
+
FrontID: current.FrontID,
|
|
745
|
+
SessionID: current.SessionID,
|
|
746
|
+
OrderRef: current.OrderRef,
|
|
747
|
+
ExchangeID: current.ExchangeID,
|
|
748
|
+
OrderSysID: current.OrderSysID,
|
|
749
|
+
ActionFlag: ctp.ActionFlagType.Delete,
|
|
750
|
+
})).then((requestId) => {
|
|
766
751
|
if (!requestId || requestId < 0) {
|
|
767
752
|
receiver.onCancelOrderError("Request Error");
|
|
768
753
|
return;
|
|
769
754
|
}
|
|
770
|
-
|
|
755
|
+
this.cancelOrders.set(requestId, receiver);
|
|
771
756
|
receiver.onCancelOrderSent();
|
|
772
757
|
});
|
|
773
|
-
}
|
|
774
|
-
|
|
775
|
-
|
|
758
|
+
}
|
|
759
|
+
_toSymbol(instrumentId) {
|
|
760
|
+
const instrument = this.instruments.get(instrumentId);
|
|
776
761
|
if (!instrument) {
|
|
777
762
|
return undefined;
|
|
778
763
|
}
|
|
779
|
-
return
|
|
780
|
-
}
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
return
|
|
784
|
-
}
|
|
785
|
-
|
|
786
|
-
return
|
|
787
|
-
}
|
|
788
|
-
|
|
764
|
+
return `${instrument.InstrumentID}.${instrument.ExchangeID}`;
|
|
765
|
+
}
|
|
766
|
+
_calcOrderId(orderOrTrade) {
|
|
767
|
+
const { ExchangeID, TraderID, OrderLocalID } = orderOrTrade;
|
|
768
|
+
return `${ExchangeID}:${TraderID}:${OrderLocalID}`;
|
|
769
|
+
}
|
|
770
|
+
_calcReceiptId(order) {
|
|
771
|
+
return `${order.FrontID}:${order.SessionID}:${parseInt(order.OrderRef)}`;
|
|
772
|
+
}
|
|
773
|
+
_calcOrderStatus(order, traded) {
|
|
789
774
|
switch (order.OrderStatus) {
|
|
790
|
-
case
|
|
775
|
+
case ctp.OrderStatusType.Unknown:
|
|
791
776
|
return "submitted";
|
|
792
|
-
case
|
|
777
|
+
case ctp.OrderStatusType.AllTraded:
|
|
793
778
|
return "filled";
|
|
794
|
-
case
|
|
779
|
+
case ctp.OrderStatusType.Canceled:
|
|
795
780
|
switch (order.OrderSubmitStatus) {
|
|
796
|
-
case
|
|
797
|
-
case
|
|
798
|
-
case
|
|
781
|
+
case ctp.OrderSubmitStatusType.InsertRejected:
|
|
782
|
+
case ctp.OrderSubmitStatusType.CancelRejected:
|
|
783
|
+
case ctp.OrderSubmitStatusType.ModifyRejected:
|
|
799
784
|
return "rejected";
|
|
800
785
|
default:
|
|
801
786
|
return "canceled";
|
|
@@ -805,63 +790,77 @@ var Trader = /** @class */ (function (_super) {
|
|
|
805
790
|
? "filled"
|
|
806
791
|
: "partially-filled";
|
|
807
792
|
}
|
|
808
|
-
}
|
|
809
|
-
|
|
793
|
+
}
|
|
794
|
+
_calcOrderFlag(orderPriceType) {
|
|
810
795
|
switch (orderPriceType) {
|
|
811
|
-
case
|
|
796
|
+
case ctp.OrderPriceTypeType.LimitPrice:
|
|
812
797
|
return "limit";
|
|
813
798
|
default:
|
|
814
799
|
return "market";
|
|
815
800
|
}
|
|
816
|
-
}
|
|
817
|
-
|
|
801
|
+
}
|
|
802
|
+
_calcSideType(direction) {
|
|
818
803
|
switch (direction) {
|
|
819
|
-
case
|
|
804
|
+
case ctp.DirectionType.Buy:
|
|
820
805
|
return "long";
|
|
821
|
-
case
|
|
806
|
+
case ctp.DirectionType.Sell:
|
|
822
807
|
return "short";
|
|
823
808
|
}
|
|
824
|
-
}
|
|
825
|
-
|
|
809
|
+
}
|
|
810
|
+
_toDirection(side) {
|
|
826
811
|
switch (side) {
|
|
827
812
|
case "long":
|
|
828
|
-
return
|
|
813
|
+
return ctp.DirectionType.Buy;
|
|
829
814
|
case "short":
|
|
830
|
-
return
|
|
815
|
+
return ctp.DirectionType.Sell;
|
|
831
816
|
}
|
|
832
|
-
}
|
|
833
|
-
|
|
817
|
+
}
|
|
818
|
+
_calcOffsetType(offset) {
|
|
834
819
|
switch (offset) {
|
|
835
|
-
case
|
|
820
|
+
case ctp.OffsetFlagType.Open:
|
|
836
821
|
return "open";
|
|
837
|
-
case
|
|
822
|
+
case ctp.OffsetFlagType.CloseToday:
|
|
838
823
|
return "close-today";
|
|
839
824
|
default:
|
|
840
825
|
return "close";
|
|
841
826
|
}
|
|
842
|
-
}
|
|
843
|
-
|
|
827
|
+
}
|
|
828
|
+
_toOffsetFlag(offset) {
|
|
844
829
|
switch (offset) {
|
|
845
830
|
case "open":
|
|
846
|
-
return
|
|
831
|
+
return ctp.OffsetFlagType.Open;
|
|
847
832
|
case "close":
|
|
848
|
-
return
|
|
833
|
+
return ctp.OffsetFlagType.Close;
|
|
849
834
|
case "close-today":
|
|
850
|
-
return
|
|
835
|
+
return ctp.OffsetFlagType.CloseToday;
|
|
851
836
|
}
|
|
852
|
-
}
|
|
853
|
-
|
|
837
|
+
}
|
|
838
|
+
_calcProductType(productClass) {
|
|
854
839
|
switch (productClass) {
|
|
855
|
-
case
|
|
840
|
+
case ctp.ProductClassType.Futures:
|
|
856
841
|
return "futures";
|
|
857
|
-
case
|
|
842
|
+
case ctp.ProductClassType.Options:
|
|
858
843
|
return "options";
|
|
844
|
+
case ctp.ProductClassType.Spot:
|
|
845
|
+
return "spot";
|
|
846
|
+
case ctp.ProductClassType.SpotOption:
|
|
847
|
+
return "spot-options";
|
|
859
848
|
default:
|
|
860
|
-
throw new Error(
|
|
849
|
+
throw new Error(`Unsupported product class: ${productClass}`);
|
|
861
850
|
}
|
|
862
|
-
}
|
|
863
|
-
|
|
864
|
-
|
|
851
|
+
}
|
|
852
|
+
_calcOptionsType(optionsType) {
|
|
853
|
+
switch (optionsType) {
|
|
854
|
+
case ctp.OptionsTypeType.CallOptions:
|
|
855
|
+
return "call";
|
|
856
|
+
case ctp.OptionsTypeType.PutOptions:
|
|
857
|
+
return "put";
|
|
858
|
+
default:
|
|
859
|
+
return undefined;
|
|
860
|
+
}
|
|
861
|
+
}
|
|
862
|
+
_ensurePositionInfo(symbol) {
|
|
863
|
+
let position = this.positions.get(symbol);
|
|
865
864
|
if (!position) {
|
|
866
865
|
position = {
|
|
867
866
|
symbol: symbol,
|
|
@@ -878,9 +877,9 @@ var Trader = /** @class */ (function (_super) {
|
|
|
878
877
|
this.positions.set(symbol, position);
|
|
879
878
|
}
|
|
880
879
|
return position;
|
|
881
|
-
}
|
|
882
|
-
|
|
883
|
-
|
|
880
|
+
}
|
|
881
|
+
_ensureOrderStatistic(symbol) {
|
|
882
|
+
let statistic = this.orderStatistics.get(symbol);
|
|
884
883
|
if (!statistic) {
|
|
885
884
|
statistic = {
|
|
886
885
|
symbol: symbol,
|
|
@@ -893,9 +892,9 @@ var Trader = /** @class */ (function (_super) {
|
|
|
893
892
|
this.orderStatistics.set(symbol, statistic);
|
|
894
893
|
}
|
|
895
894
|
return statistic;
|
|
896
|
-
}
|
|
897
|
-
|
|
898
|
-
|
|
895
|
+
}
|
|
896
|
+
_calcPosition(symbol, side, offset, volume) {
|
|
897
|
+
const position = this._ensurePositionInfo(symbol);
|
|
899
898
|
switch (offset) {
|
|
900
899
|
case "open":
|
|
901
900
|
switch (side) {
|
|
@@ -926,7 +925,7 @@ var Trader = /** @class */ (function (_super) {
|
|
|
926
925
|
position.history.short.position -= volume;
|
|
927
926
|
}
|
|
928
927
|
else {
|
|
929
|
-
|
|
928
|
+
const rest = volume - position.history.short.position;
|
|
930
929
|
position.history.short.position -=
|
|
931
930
|
position.history.short.position;
|
|
932
931
|
if (rest > 0) {
|
|
@@ -942,7 +941,7 @@ var Trader = /** @class */ (function (_super) {
|
|
|
942
941
|
position.history.short.frozen -= volume;
|
|
943
942
|
}
|
|
944
943
|
else {
|
|
945
|
-
|
|
944
|
+
const rest = volume - position.history.short.frozen;
|
|
946
945
|
position.history.short.frozen -= position.history.short.frozen;
|
|
947
946
|
if (rest > 0) {
|
|
948
947
|
if (position.today.short.frozen >= rest) {
|
|
@@ -959,7 +958,7 @@ var Trader = /** @class */ (function (_super) {
|
|
|
959
958
|
position.history.long.position -= volume;
|
|
960
959
|
}
|
|
961
960
|
else {
|
|
962
|
-
|
|
961
|
+
const rest = volume - position.history.long.position;
|
|
963
962
|
position.history.long.position -= position.history.long.position;
|
|
964
963
|
if (rest > 0) {
|
|
965
964
|
if (position.today.long.position >= rest) {
|
|
@@ -974,7 +973,7 @@ var Trader = /** @class */ (function (_super) {
|
|
|
974
973
|
position.history.long.frozen -= volume;
|
|
975
974
|
}
|
|
976
975
|
else {
|
|
977
|
-
|
|
976
|
+
const rest = volume - position.history.long.frozen;
|
|
978
977
|
position.history.long.frozen -= position.history.long.frozen;
|
|
979
978
|
if (rest > 0) {
|
|
980
979
|
if (position.today.long.frozen >= rest) {
|
|
@@ -1021,12 +1020,12 @@ var Trader = /** @class */ (function (_super) {
|
|
|
1021
1020
|
}
|
|
1022
1021
|
break;
|
|
1023
1022
|
}
|
|
1024
|
-
}
|
|
1025
|
-
|
|
1023
|
+
}
|
|
1024
|
+
_recordPending(symbol, side, offset, volume) {
|
|
1026
1025
|
if (offset !== "open") {
|
|
1027
1026
|
return;
|
|
1028
1027
|
}
|
|
1029
|
-
|
|
1028
|
+
const position = this._ensurePositionInfo(symbol);
|
|
1030
1029
|
switch (side) {
|
|
1031
1030
|
case "long":
|
|
1032
1031
|
position.pending.long += volume;
|
|
@@ -1035,12 +1034,12 @@ var Trader = /** @class */ (function (_super) {
|
|
|
1035
1034
|
position.pending.short += volume;
|
|
1036
1035
|
break;
|
|
1037
1036
|
}
|
|
1038
|
-
}
|
|
1039
|
-
|
|
1037
|
+
}
|
|
1038
|
+
_recoverPending(symbol, side, offset, volume) {
|
|
1040
1039
|
if (offset !== "open") {
|
|
1041
1040
|
return;
|
|
1042
1041
|
}
|
|
1043
|
-
|
|
1042
|
+
const position = this.positions.get(symbol);
|
|
1044
1043
|
if (!position) {
|
|
1045
1044
|
return;
|
|
1046
1045
|
}
|
|
@@ -1052,9 +1051,9 @@ var Trader = /** @class */ (function (_super) {
|
|
|
1052
1051
|
position.pending.short -= volume;
|
|
1053
1052
|
break;
|
|
1054
1053
|
}
|
|
1055
|
-
}
|
|
1056
|
-
|
|
1057
|
-
|
|
1054
|
+
}
|
|
1055
|
+
_freezePosition(symbol, side, offset, volume) {
|
|
1056
|
+
const position = this.positions.get(symbol);
|
|
1058
1057
|
if (!position) {
|
|
1059
1058
|
return;
|
|
1060
1059
|
}
|
|
@@ -1080,9 +1079,9 @@ var Trader = /** @class */ (function (_super) {
|
|
|
1080
1079
|
}
|
|
1081
1080
|
break;
|
|
1082
1081
|
}
|
|
1083
|
-
}
|
|
1084
|
-
|
|
1085
|
-
|
|
1082
|
+
}
|
|
1083
|
+
_unfreezePosition(symbol, side, offset, volume) {
|
|
1084
|
+
const position = this.positions.get(symbol);
|
|
1086
1085
|
if (!position) {
|
|
1087
1086
|
return;
|
|
1088
1087
|
}
|
|
@@ -1128,8 +1127,8 @@ var Trader = /** @class */ (function (_super) {
|
|
|
1128
1127
|
}
|
|
1129
1128
|
break;
|
|
1130
1129
|
}
|
|
1131
|
-
}
|
|
1132
|
-
|
|
1130
|
+
}
|
|
1131
|
+
_toTradeData(trade) {
|
|
1133
1132
|
return Object.freeze({
|
|
1134
1133
|
id: trade.TradeID,
|
|
1135
1134
|
date: parseInt(trade.TradeDate),
|
|
@@ -1137,18 +1136,17 @@ var Trader = /** @class */ (function (_super) {
|
|
|
1137
1136
|
price: trade.Price,
|
|
1138
1137
|
volume: trade.Volume,
|
|
1139
1138
|
});
|
|
1140
|
-
}
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
.
|
|
1147
|
-
.reduce(function (a, b) { return a + b; }, 0);
|
|
1139
|
+
}
|
|
1140
|
+
_toOrderData(order) {
|
|
1141
|
+
const orderId = this._calcOrderId(order);
|
|
1142
|
+
const trades = this.trades.get(orderId) ?? [];
|
|
1143
|
+
const traded = trades
|
|
1144
|
+
.map((trade) => trade.Volume)
|
|
1145
|
+
.reduce((a, b) => a + b, 0);
|
|
1148
1146
|
return Object.freeze({
|
|
1149
1147
|
id: orderId,
|
|
1150
1148
|
receiptId: this._calcReceiptId(order),
|
|
1151
|
-
symbol:
|
|
1149
|
+
symbol: `${order.InstrumentID}.${order.ExchangeID}`,
|
|
1152
1150
|
date: parseInt(order.InsertDate),
|
|
1153
1151
|
time: this._parseTime(order.InsertTime),
|
|
1154
1152
|
flag: this._calcOrderFlag(order.OrderPriceType),
|
|
@@ -1161,10 +1159,10 @@ var Trader = /** @class */ (function (_super) {
|
|
|
1161
1159
|
trades: trades.map(this._toTradeData, this),
|
|
1162
1160
|
cancelTime: order.CancelTime !== "" ? this._parseTime(order.CancelTime) : undefined,
|
|
1163
1161
|
});
|
|
1164
|
-
}
|
|
1165
|
-
|
|
1162
|
+
}
|
|
1163
|
+
_toInstrumentData(instrument) {
|
|
1166
1164
|
return Object.freeze({
|
|
1167
|
-
symbol:
|
|
1165
|
+
symbol: `${instrument.InstrumentID}.${instrument.ExchangeID}`,
|
|
1168
1166
|
id: instrument.InstrumentID,
|
|
1169
1167
|
name: instrument.InstrumentName,
|
|
1170
1168
|
exchangeId: instrument.ExchangeID,
|
|
@@ -1178,9 +1176,11 @@ var Trader = /** @class */ (function (_super) {
|
|
|
1178
1176
|
priceTick: instrument.PriceTick,
|
|
1179
1177
|
maxLimitOrderVolume: instrument.MaxLimitOrderVolume,
|
|
1180
1178
|
minLimitOrderVolume: instrument.MinLimitOrderVolume,
|
|
1179
|
+
strikePrice: instrument.StrikePrice,
|
|
1180
|
+
optionsType: this._calcOptionsType(instrument.OptionsType),
|
|
1181
1181
|
});
|
|
1182
|
-
}
|
|
1183
|
-
|
|
1182
|
+
}
|
|
1183
|
+
_toCommissionRate(symbol, commRate) {
|
|
1184
1184
|
return Object.freeze({
|
|
1185
1185
|
symbol: symbol,
|
|
1186
1186
|
open: Object.freeze({
|
|
@@ -1196,8 +1196,8 @@ var Trader = /** @class */ (function (_super) {
|
|
|
1196
1196
|
amount: commRate.CloseTodayRatioByVolume,
|
|
1197
1197
|
}),
|
|
1198
1198
|
});
|
|
1199
|
-
}
|
|
1200
|
-
|
|
1199
|
+
}
|
|
1200
|
+
_toMarginRate(symbol, marginRate) {
|
|
1201
1201
|
return Object.freeze({
|
|
1202
1202
|
symbol: symbol,
|
|
1203
1203
|
long: Object.freeze({
|
|
@@ -1209,12 +1209,13 @@ var Trader = /** @class */ (function (_super) {
|
|
|
1209
1209
|
amount: marginRate.ShortMarginRatioByVolume,
|
|
1210
1210
|
}),
|
|
1211
1211
|
});
|
|
1212
|
-
}
|
|
1213
|
-
|
|
1212
|
+
}
|
|
1213
|
+
_toTradingAccount(account) {
|
|
1214
1214
|
return Object.freeze({
|
|
1215
1215
|
id: account.AccountID,
|
|
1216
1216
|
currency: account.CurrencyID,
|
|
1217
1217
|
preBalance: account.PreBalance - account.Withdraw + account.Deposit,
|
|
1218
|
+
preMargin: account.PreMargin,
|
|
1218
1219
|
balance: account.Balance,
|
|
1219
1220
|
cash: account.Available,
|
|
1220
1221
|
margin: account.CurrMargin,
|
|
@@ -1223,8 +1224,8 @@ var Trader = /** @class */ (function (_super) {
|
|
|
1223
1224
|
frozenCash: account.FrozenCash,
|
|
1224
1225
|
frozenCommission: account.FrozenCommission,
|
|
1225
1226
|
});
|
|
1226
|
-
}
|
|
1227
|
-
|
|
1227
|
+
}
|
|
1228
|
+
_toPositionDetail(positionDetail) {
|
|
1228
1229
|
return Object.freeze({
|
|
1229
1230
|
symbol: this._toSymbol(positionDetail.InstrumentID),
|
|
1230
1231
|
date: parseInt(positionDetail.OpenDate),
|
|
@@ -1233,66 +1234,56 @@ var Trader = /** @class */ (function (_super) {
|
|
|
1233
1234
|
volume: positionDetail.Volume,
|
|
1234
1235
|
margin: positionDetail.Margin,
|
|
1235
1236
|
});
|
|
1236
|
-
}
|
|
1237
|
-
|
|
1237
|
+
}
|
|
1238
|
+
_toPositionData(position) {
|
|
1238
1239
|
return Object.freeze({
|
|
1239
1240
|
symbol: position.symbol,
|
|
1240
1241
|
today: Object.freeze({
|
|
1241
|
-
long: Object.freeze(
|
|
1242
|
-
short: Object.freeze(
|
|
1242
|
+
long: Object.freeze({ ...position.today.long }),
|
|
1243
|
+
short: Object.freeze({ ...position.today.short }),
|
|
1243
1244
|
}),
|
|
1244
1245
|
history: Object.freeze({
|
|
1245
|
-
long: Object.freeze(
|
|
1246
|
-
short: Object.freeze(
|
|
1246
|
+
long: Object.freeze({ ...position.history.long }),
|
|
1247
|
+
short: Object.freeze({ ...position.history.short }),
|
|
1247
1248
|
}),
|
|
1248
|
-
pending: Object.freeze(
|
|
1249
|
+
pending: Object.freeze({ ...position.pending }),
|
|
1249
1250
|
});
|
|
1250
|
-
}
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
var marginRate = this_1.marginRates.get(instrumentId);
|
|
1251
|
+
}
|
|
1252
|
+
_processMarginRatesQueue() {
|
|
1253
|
+
while (!this.marginRatesQueue.isEmpty()) {
|
|
1254
|
+
const nextQuery = this.marginRatesQueue.peekFront();
|
|
1255
|
+
const [instrumentId] = parseSymbol(nextQuery.symbol);
|
|
1256
|
+
const marginRate = this.marginRates.get(instrumentId);
|
|
1257
1257
|
if (marginRate) {
|
|
1258
|
-
nextQuery.receiver.onMarginRate(
|
|
1259
|
-
|
|
1258
|
+
nextQuery.receiver.onMarginRate(this._toMarginRate(nextQuery.symbol, marginRate));
|
|
1259
|
+
this.marginRatesQueue.shift();
|
|
1260
1260
|
}
|
|
1261
1261
|
else {
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1262
|
+
this._withRetry(() => this.traderApi.reqQryInstrumentMarginRate({
|
|
1263
|
+
...this.userInfo,
|
|
1264
|
+
HedgeFlag: ctp.HedgeFlagType.Speculation,
|
|
1265
|
+
InstrumentID: instrumentId,
|
|
1266
|
+
}));
|
|
1265
1267
|
}
|
|
1266
|
-
};
|
|
1267
|
-
var this_1 = this;
|
|
1268
|
-
while (!this.marginRatesQueue.isEmpty()) {
|
|
1269
|
-
_loop_1();
|
|
1270
1268
|
}
|
|
1271
|
-
}
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
var commRate = this_2.commRates.get(instrumentId);
|
|
1269
|
+
}
|
|
1270
|
+
_processCommissionRatesQueue() {
|
|
1271
|
+
while (!this.commRatesQueue.isEmpty()) {
|
|
1272
|
+
const nextQuery = this.commRatesQueue.peekFront();
|
|
1273
|
+
const [instrumentId] = parseSymbol(nextQuery.symbol);
|
|
1274
|
+
const commRate = this.commRates.get(instrumentId);
|
|
1278
1275
|
if (commRate) {
|
|
1279
|
-
nextQuery.receiver.onCommissionRate(
|
|
1280
|
-
|
|
1276
|
+
nextQuery.receiver.onCommissionRate(this._toCommissionRate(nextQuery.symbol, commRate));
|
|
1277
|
+
this.commRatesQueue.shift();
|
|
1281
1278
|
}
|
|
1282
1279
|
else {
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1280
|
+
this._withRetry(() => this.traderApi.reqQryInstrumentCommissionRate({
|
|
1281
|
+
...this.userInfo,
|
|
1282
|
+
InstrumentID: instrumentId,
|
|
1283
|
+
}));
|
|
1286
1284
|
}
|
|
1287
|
-
};
|
|
1288
|
-
var this_2 = this;
|
|
1289
|
-
while (!this.commRatesQueue.isEmpty()) {
|
|
1290
|
-
_loop_2();
|
|
1291
1285
|
}
|
|
1292
|
-
}
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
exports.Trader = Trader;
|
|
1296
|
-
var createTrader = function (flowTdPath, frontTdAddrs, userInfo, options) { return new Trader(flowTdPath, frontTdAddrs, userInfo, options); };
|
|
1297
|
-
exports.createTrader = createTrader;
|
|
1286
|
+
}
|
|
1287
|
+
}
|
|
1288
|
+
export const createTrader = (flowTdPath, frontTdAddrs, userInfo, options) => new Trader(flowTdPath, frontTdAddrs, userInfo, options);
|
|
1298
1289
|
//# sourceMappingURL=trader.js.map
|