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/src/market.ts
CHANGED
|
@@ -9,12 +9,17 @@
|
|
|
9
9
|
* https://github.com/shixiongfei/hft.js
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
|
-
import ctp from "napi-ctp";
|
|
12
|
+
import ctp, { type MarketData as MarketApi } from "napi-ctp";
|
|
13
|
+
import type {
|
|
14
|
+
DepthMarketDataField,
|
|
15
|
+
RspUserLoginField,
|
|
16
|
+
SpecificInstrumentField,
|
|
17
|
+
} from "@napi-ctp/types";
|
|
13
18
|
import { CTPProvider } from "./provider.js";
|
|
14
|
-
import { InstrumentData, OrderBook, TickData } from "./typedef.js";
|
|
19
|
+
import type { InstrumentData, OrderBook, TickData } from "./typedef.js";
|
|
15
20
|
import { isValidPrice, isValidVolume, parseSymbol } from "./utils.js";
|
|
16
21
|
import { calcTapeData } from "./tape.js";
|
|
17
|
-
import {
|
|
22
|
+
import type {
|
|
18
23
|
ILifecycleListener,
|
|
19
24
|
IMarketProvider,
|
|
20
25
|
IMarketRecorderProvider,
|
|
@@ -36,7 +41,7 @@ export class Market
|
|
|
36
41
|
extends CTPProvider
|
|
37
42
|
implements IMarketProvider, IMarketRecorderProvider
|
|
38
43
|
{
|
|
39
|
-
private marketApi?:
|
|
44
|
+
private marketApi?: MarketApi;
|
|
40
45
|
private recorder?: IMarketRecorderReceiver;
|
|
41
46
|
private recorderSymbols?: IMarketRecorderSymbols;
|
|
42
47
|
private tradingDay: number;
|
|
@@ -96,7 +101,7 @@ export class Market
|
|
|
96
101
|
|
|
97
102
|
let fired = false;
|
|
98
103
|
|
|
99
|
-
this.marketApi.on<
|
|
104
|
+
this.marketApi.on<RspUserLoginField>(
|
|
100
105
|
ctp.MarketDataEvent.RspUserLogin,
|
|
101
106
|
(_, options) => {
|
|
102
107
|
if (this._isErrorResp(lifecycle, options, "login-error")) {
|
|
@@ -128,7 +133,7 @@ export class Market
|
|
|
128
133
|
},
|
|
129
134
|
);
|
|
130
135
|
|
|
131
|
-
this.marketApi.on<
|
|
136
|
+
this.marketApi.on<SpecificInstrumentField>(
|
|
132
137
|
ctp.MarketDataEvent.RspSubMarketData,
|
|
133
138
|
(instrument) => {
|
|
134
139
|
if (!this.listener) {
|
|
@@ -141,7 +146,7 @@ export class Market
|
|
|
141
146
|
},
|
|
142
147
|
);
|
|
143
148
|
|
|
144
|
-
this.marketApi.on<
|
|
149
|
+
this.marketApi.on<SpecificInstrumentField>(
|
|
145
150
|
ctp.MarketDataEvent.RspUnSubMarketData,
|
|
146
151
|
(instrument) => {
|
|
147
152
|
if (!this.listener) {
|
|
@@ -154,7 +159,7 @@ export class Market
|
|
|
154
159
|
},
|
|
155
160
|
);
|
|
156
161
|
|
|
157
|
-
this.marketApi.on<
|
|
162
|
+
this.marketApi.on<DepthMarketDataField>(
|
|
158
163
|
ctp.MarketDataEvent.RtnDepthMarketData,
|
|
159
164
|
(depthMarketData) => {
|
|
160
165
|
const instrumentId = depthMarketData.InstrumentID;
|
|
@@ -281,16 +286,15 @@ export class Market
|
|
|
281
286
|
orderBook: Object.freeze(orderBook),
|
|
282
287
|
});
|
|
283
288
|
|
|
289
|
+
const lastTick = this.lastTicks.get(instrumentId);
|
|
284
290
|
const receivers = this.subscribers.get(instrumentId);
|
|
285
291
|
|
|
292
|
+
this.lastTicks.set(instrumentId, tick);
|
|
293
|
+
|
|
286
294
|
if (receivers && receivers.length > 0) {
|
|
287
|
-
const lastTick = this.lastTicks.get(instrumentId);
|
|
288
295
|
const tape = calcTapeData(tick, lastTick);
|
|
289
|
-
|
|
290
296
|
receivers.forEach((receiver) => receiver.onTick(tick, tape));
|
|
291
297
|
}
|
|
292
|
-
|
|
293
|
-
this.lastTicks.set(instrumentId, tick);
|
|
294
298
|
},
|
|
295
299
|
);
|
|
296
300
|
|
package/src/provider.ts
CHANGED
|
@@ -10,8 +10,8 @@
|
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
12
|
import fs from "node:fs";
|
|
13
|
-
import ctp from "napi-ctp";
|
|
14
|
-
import { ErrorType, ILifecycleListener } from "./interfaces.js";
|
|
13
|
+
import ctp, { type CallbackOptions } from "napi-ctp";
|
|
14
|
+
import type { ErrorType, ILifecycleListener } from "./interfaces.js";
|
|
15
15
|
|
|
16
16
|
export class CTPProvider {
|
|
17
17
|
protected readonly flowPath: string;
|
|
@@ -53,7 +53,7 @@ export class CTPProvider {
|
|
|
53
53
|
|
|
54
54
|
protected _isErrorResp(
|
|
55
55
|
lifecycle: ILifecycleListener,
|
|
56
|
-
options:
|
|
56
|
+
options: CallbackOptions,
|
|
57
57
|
error: ErrorType,
|
|
58
58
|
) {
|
|
59
59
|
if (!options.rspInfo) {
|
|
@@ -69,7 +69,7 @@ export class CTPProvider {
|
|
|
69
69
|
}
|
|
70
70
|
|
|
71
71
|
protected _parseTime(time: string) {
|
|
72
|
-
const [
|
|
73
|
-
return
|
|
72
|
+
const [hh = 0, mm = 0, ss = 0] = time.split(":").map((x) => parseInt(x));
|
|
73
|
+
return hh * 10000 + mm * 100 + ss;
|
|
74
74
|
}
|
|
75
75
|
}
|
package/src/tape.ts
CHANGED
package/src/trader.ts
CHANGED
|
@@ -10,14 +10,36 @@
|
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
12
|
import Denque from "denque";
|
|
13
|
-
import ctp from "napi-ctp";
|
|
13
|
+
import ctp, { type Trader as TraderApi } from "napi-ctp";
|
|
14
|
+
import type {
|
|
15
|
+
DepthMarketDataField,
|
|
16
|
+
DirectionType,
|
|
17
|
+
InputOrderActionField,
|
|
18
|
+
InputOrderField,
|
|
19
|
+
InstrumentCommissionRateField,
|
|
20
|
+
InstrumentField,
|
|
21
|
+
InstrumentMarginRateField,
|
|
22
|
+
InvestorPositionDetailField,
|
|
23
|
+
InvestorPositionField,
|
|
24
|
+
OffsetFlagType,
|
|
25
|
+
OptionsTypeType,
|
|
26
|
+
OrderField,
|
|
27
|
+
OrderPriceTypeType,
|
|
28
|
+
ProductClassType,
|
|
29
|
+
RspAuthenticateField,
|
|
30
|
+
RspUserLoginField,
|
|
31
|
+
SettlementInfoConfirmField,
|
|
32
|
+
TradeField,
|
|
33
|
+
TradingAccountField,
|
|
34
|
+
} from "@napi-ctp/types";
|
|
14
35
|
import { CTPProvider } from "./provider.js";
|
|
15
36
|
import { isValidPrice, parseSymbol } from "./utils.js";
|
|
16
|
-
import {
|
|
37
|
+
import type {
|
|
17
38
|
CommissionRate,
|
|
18
39
|
InstrumentData,
|
|
19
40
|
MarginRate,
|
|
20
41
|
OffsetType,
|
|
42
|
+
OptionsType,
|
|
21
43
|
OrderData,
|
|
22
44
|
OrderFlag,
|
|
23
45
|
OrderStatistic,
|
|
@@ -32,7 +54,7 @@ import {
|
|
|
32
54
|
TradingAccount,
|
|
33
55
|
Writeable,
|
|
34
56
|
} from "./typedef.js";
|
|
35
|
-
import {
|
|
57
|
+
import type {
|
|
36
58
|
ICancelOrderResultReceiver,
|
|
37
59
|
ICommissionRateReceiver,
|
|
38
60
|
IInstrumentReceiver,
|
|
@@ -89,7 +111,7 @@ export type TraderOptions = {
|
|
|
89
111
|
};
|
|
90
112
|
|
|
91
113
|
export class Trader extends CTPProvider implements ITraderProvider {
|
|
92
|
-
private traderApi?:
|
|
114
|
+
private traderApi?: TraderApi;
|
|
93
115
|
private tradingDay: number;
|
|
94
116
|
private frontId: number;
|
|
95
117
|
private sessionId: number;
|
|
@@ -99,14 +121,14 @@ export class Trader extends CTPProvider implements ITraderProvider {
|
|
|
99
121
|
private readonly fastQueryLastTick?: FastQueryLastTickFunc;
|
|
100
122
|
private readonly userInfo: CTPUserInfo;
|
|
101
123
|
private readonly receivers: IOrderReceiver[];
|
|
102
|
-
private readonly accounts:
|
|
103
|
-
private readonly positionDetails:
|
|
104
|
-
private readonly instruments: Map<string,
|
|
124
|
+
private readonly accounts: TradingAccountField[];
|
|
125
|
+
private readonly positionDetails: InvestorPositionDetailField[];
|
|
126
|
+
private readonly instruments: Map<string, InstrumentField>;
|
|
105
127
|
private readonly positions: Map<string, PositionInfo>;
|
|
106
|
-
private readonly orders: Map<string,
|
|
107
|
-
private readonly trades: Map<string,
|
|
108
|
-
private readonly marginRates: Map<string,
|
|
109
|
-
private readonly commRates: Map<string,
|
|
128
|
+
private readonly orders: Map<string, OrderField>;
|
|
129
|
+
private readonly trades: Map<string, TradeField[]>;
|
|
130
|
+
private readonly marginRates: Map<string, InstrumentMarginRateField>;
|
|
131
|
+
private readonly commRates: Map<string, InstrumentCommissionRateField>;
|
|
110
132
|
private readonly placeOrders: Map<number, IPlaceOrderResultReceiver>;
|
|
111
133
|
private readonly cancelOrders: Map<number, ICancelOrderResultReceiver>;
|
|
112
134
|
private readonly marketOrdersQueue: Map<string, Denque<MarketOrder>>;
|
|
@@ -172,7 +194,7 @@ export class Trader extends CTPProvider implements ITraderProvider {
|
|
|
172
194
|
this.cancelOrders.clear();
|
|
173
195
|
});
|
|
174
196
|
|
|
175
|
-
this.traderApi.on<
|
|
197
|
+
this.traderApi.on<RspAuthenticateField>(
|
|
176
198
|
ctp.TraderEvent.RspAuthenticate,
|
|
177
199
|
(_, options) => {
|
|
178
200
|
if (this._isErrorResp(lifecycle, options, "login-error")) {
|
|
@@ -183,7 +205,7 @@ export class Trader extends CTPProvider implements ITraderProvider {
|
|
|
183
205
|
},
|
|
184
206
|
);
|
|
185
207
|
|
|
186
|
-
this.traderApi.on<
|
|
208
|
+
this.traderApi.on<RspUserLoginField>(
|
|
187
209
|
ctp.TraderEvent.RspUserLogin,
|
|
188
210
|
(rspUserLogin, options) => {
|
|
189
211
|
if (this._isErrorResp(lifecycle, options, "login-error")) {
|
|
@@ -210,7 +232,7 @@ export class Trader extends CTPProvider implements ITraderProvider {
|
|
|
210
232
|
},
|
|
211
233
|
);
|
|
212
234
|
|
|
213
|
-
this.traderApi.on<
|
|
235
|
+
this.traderApi.on<SettlementInfoConfirmField>(
|
|
214
236
|
ctp.TraderEvent.RspSettlementInfoConfirm,
|
|
215
237
|
(_, options) => {
|
|
216
238
|
if (this._isErrorResp(lifecycle, options, "login-error")) {
|
|
@@ -222,7 +244,7 @@ export class Trader extends CTPProvider implements ITraderProvider {
|
|
|
222
244
|
},
|
|
223
245
|
);
|
|
224
246
|
|
|
225
|
-
this.traderApi.on<
|
|
247
|
+
this.traderApi.on<OrderField>(
|
|
226
248
|
ctp.TraderEvent.RspQryOrder,
|
|
227
249
|
(order, options) => {
|
|
228
250
|
if (this._isErrorResp(lifecycle, options, "query-order-error")) {
|
|
@@ -241,7 +263,7 @@ export class Trader extends CTPProvider implements ITraderProvider {
|
|
|
241
263
|
},
|
|
242
264
|
);
|
|
243
265
|
|
|
244
|
-
this.traderApi.on<
|
|
266
|
+
this.traderApi.on<TradeField>(
|
|
245
267
|
ctp.TraderEvent.RspQryTrade,
|
|
246
268
|
(trade, options) => {
|
|
247
269
|
if (this._isErrorResp(lifecycle, options, "query-trade-error")) {
|
|
@@ -266,7 +288,7 @@ export class Trader extends CTPProvider implements ITraderProvider {
|
|
|
266
288
|
},
|
|
267
289
|
);
|
|
268
290
|
|
|
269
|
-
this.traderApi.on<
|
|
291
|
+
this.traderApi.on<InstrumentField>(
|
|
270
292
|
ctp.TraderEvent.RspQryInstrument,
|
|
271
293
|
(instrument, options) => {
|
|
272
294
|
if (this._isErrorResp(lifecycle, options, "query-instrument-error")) {
|
|
@@ -294,7 +316,7 @@ export class Trader extends CTPProvider implements ITraderProvider {
|
|
|
294
316
|
|
|
295
317
|
let fired = false;
|
|
296
318
|
|
|
297
|
-
this.traderApi.on<
|
|
319
|
+
this.traderApi.on<InvestorPositionField>(
|
|
298
320
|
ctp.TraderEvent.RspQryInvestorPosition,
|
|
299
321
|
(position, options) => {
|
|
300
322
|
if (this._isErrorResp(lifecycle, options, "query-positions-error")) {
|
|
@@ -362,7 +384,7 @@ export class Trader extends CTPProvider implements ITraderProvider {
|
|
|
362
384
|
},
|
|
363
385
|
);
|
|
364
386
|
|
|
365
|
-
this.traderApi.on<
|
|
387
|
+
this.traderApi.on<OrderField>(ctp.TraderEvent.RtnOrder, (order) => {
|
|
366
388
|
const orderId = this._calcOrderId(order);
|
|
367
389
|
const current = this.orders.get(orderId);
|
|
368
390
|
|
|
@@ -469,7 +491,7 @@ export class Trader extends CTPProvider implements ITraderProvider {
|
|
|
469
491
|
}
|
|
470
492
|
});
|
|
471
493
|
|
|
472
|
-
this.traderApi.on<
|
|
494
|
+
this.traderApi.on<TradeField>(ctp.TraderEvent.RtnTrade, (trade) => {
|
|
473
495
|
const orderId = this._calcOrderId(trade);
|
|
474
496
|
const trades = this.trades.get(orderId);
|
|
475
497
|
|
|
@@ -503,7 +525,7 @@ export class Trader extends CTPProvider implements ITraderProvider {
|
|
|
503
525
|
}
|
|
504
526
|
});
|
|
505
527
|
|
|
506
|
-
this.traderApi.on<
|
|
528
|
+
this.traderApi.on<InstrumentMarginRateField>(
|
|
507
529
|
ctp.TraderEvent.RspQryInstrumentMarginRate,
|
|
508
530
|
(marginRate, options) => {
|
|
509
531
|
const query = this.marginRatesQueue.shift();
|
|
@@ -530,7 +552,7 @@ export class Trader extends CTPProvider implements ITraderProvider {
|
|
|
530
552
|
},
|
|
531
553
|
);
|
|
532
554
|
|
|
533
|
-
this.traderApi.on<
|
|
555
|
+
this.traderApi.on<InstrumentCommissionRateField>(
|
|
534
556
|
ctp.TraderEvent.RspQryInstrumentCommissionRate,
|
|
535
557
|
(commRate, options) => {
|
|
536
558
|
const query = this.commRatesQueue.shift();
|
|
@@ -559,7 +581,7 @@ export class Trader extends CTPProvider implements ITraderProvider {
|
|
|
559
581
|
},
|
|
560
582
|
);
|
|
561
583
|
|
|
562
|
-
this.traderApi.on<
|
|
584
|
+
this.traderApi.on<TradingAccountField>(
|
|
563
585
|
ctp.TraderEvent.RspQryTradingAccount,
|
|
564
586
|
(account, options) => {
|
|
565
587
|
if (this._isErrorResp(lifecycle, options, "query-accounts-error")) {
|
|
@@ -589,7 +611,7 @@ export class Trader extends CTPProvider implements ITraderProvider {
|
|
|
589
611
|
},
|
|
590
612
|
);
|
|
591
613
|
|
|
592
|
-
this.traderApi.on<
|
|
614
|
+
this.traderApi.on<InvestorPositionDetailField>(
|
|
593
615
|
ctp.TraderEvent.RspQryInvestorPositionDetail,
|
|
594
616
|
(positionDetail, options) => {
|
|
595
617
|
if (
|
|
@@ -626,7 +648,7 @@ export class Trader extends CTPProvider implements ITraderProvider {
|
|
|
626
648
|
},
|
|
627
649
|
);
|
|
628
650
|
|
|
629
|
-
this.traderApi.on<
|
|
651
|
+
this.traderApi.on<InputOrderField>(
|
|
630
652
|
ctp.TraderEvent.RspOrderInsert,
|
|
631
653
|
(order, options) => {
|
|
632
654
|
if (options.rspInfo && order && options.requestId && options.isLast) {
|
|
@@ -643,7 +665,7 @@ export class Trader extends CTPProvider implements ITraderProvider {
|
|
|
643
665
|
},
|
|
644
666
|
);
|
|
645
667
|
|
|
646
|
-
this.traderApi.on<
|
|
668
|
+
this.traderApi.on<InputOrderActionField>(
|
|
647
669
|
ctp.TraderEvent.RspOrderAction,
|
|
648
670
|
(order, options) => {
|
|
649
671
|
if (options.rspInfo && order && options.requestId && options.isLast) {
|
|
@@ -660,7 +682,7 @@ export class Trader extends CTPProvider implements ITraderProvider {
|
|
|
660
682
|
},
|
|
661
683
|
);
|
|
662
684
|
|
|
663
|
-
this.traderApi.on<
|
|
685
|
+
this.traderApi.on<DepthMarketDataField>(
|
|
664
686
|
ctp.TraderEvent.RspQryDepthMarketData,
|
|
665
687
|
(depthMarketData, options) => {
|
|
666
688
|
if (
|
|
@@ -1179,6 +1201,11 @@ export class Trader extends CTPProvider implements ITraderProvider {
|
|
|
1179
1201
|
flag: OrderFlag,
|
|
1180
1202
|
receiver: IPlaceOrderResultReceiver,
|
|
1181
1203
|
) {
|
|
1204
|
+
if (volume <= 0) {
|
|
1205
|
+
receiver.onPlaceOrderError("Invalid Volume");
|
|
1206
|
+
return;
|
|
1207
|
+
}
|
|
1208
|
+
|
|
1182
1209
|
switch (flag) {
|
|
1183
1210
|
case "limit":
|
|
1184
1211
|
return this._placeLimitOrder(
|
|
@@ -1241,19 +1268,16 @@ export class Trader extends CTPProvider implements ITraderProvider {
|
|
|
1241
1268
|
return `${instrument.InstrumentID}.${instrument.ExchangeID}`;
|
|
1242
1269
|
}
|
|
1243
1270
|
|
|
1244
|
-
private _calcOrderId(orderOrTrade:
|
|
1271
|
+
private _calcOrderId(orderOrTrade: OrderField | TradeField) {
|
|
1245
1272
|
const { ExchangeID, TraderID, OrderLocalID } = orderOrTrade;
|
|
1246
1273
|
return `${ExchangeID}:${TraderID}:${OrderLocalID}`;
|
|
1247
1274
|
}
|
|
1248
1275
|
|
|
1249
|
-
private _calcReceiptId(order:
|
|
1276
|
+
private _calcReceiptId(order: OrderField | InputOrderActionField) {
|
|
1250
1277
|
return `${order.FrontID}:${order.SessionID}:${parseInt(order.OrderRef)}`;
|
|
1251
1278
|
}
|
|
1252
1279
|
|
|
1253
|
-
private _calcOrderStatus(
|
|
1254
|
-
order: ctp.OrderField,
|
|
1255
|
-
traded?: number,
|
|
1256
|
-
): OrderStatus {
|
|
1280
|
+
private _calcOrderStatus(order: OrderField, traded?: number): OrderStatus {
|
|
1257
1281
|
switch (order.OrderStatus) {
|
|
1258
1282
|
case ctp.OrderStatusType.Unknown:
|
|
1259
1283
|
return "submitted";
|
|
@@ -1279,7 +1303,7 @@ export class Trader extends CTPProvider implements ITraderProvider {
|
|
|
1279
1303
|
}
|
|
1280
1304
|
}
|
|
1281
1305
|
|
|
1282
|
-
private _calcOrderFlag(orderPriceType:
|
|
1306
|
+
private _calcOrderFlag(orderPriceType: OrderPriceTypeType): OrderFlag {
|
|
1283
1307
|
switch (orderPriceType) {
|
|
1284
1308
|
case ctp.OrderPriceTypeType.LimitPrice:
|
|
1285
1309
|
return "limit";
|
|
@@ -1289,7 +1313,7 @@ export class Trader extends CTPProvider implements ITraderProvider {
|
|
|
1289
1313
|
}
|
|
1290
1314
|
}
|
|
1291
1315
|
|
|
1292
|
-
private _calcSideType(direction:
|
|
1316
|
+
private _calcSideType(direction: DirectionType): SideType {
|
|
1293
1317
|
switch (direction) {
|
|
1294
1318
|
case ctp.DirectionType.Buy:
|
|
1295
1319
|
return "long";
|
|
@@ -1309,7 +1333,7 @@ export class Trader extends CTPProvider implements ITraderProvider {
|
|
|
1309
1333
|
}
|
|
1310
1334
|
}
|
|
1311
1335
|
|
|
1312
|
-
private _calcOffsetType(offset:
|
|
1336
|
+
private _calcOffsetType(offset: OffsetFlagType): OffsetType {
|
|
1313
1337
|
switch (offset) {
|
|
1314
1338
|
case ctp.OffsetFlagType.Open:
|
|
1315
1339
|
return "open";
|
|
@@ -1335,7 +1359,7 @@ export class Trader extends CTPProvider implements ITraderProvider {
|
|
|
1335
1359
|
}
|
|
1336
1360
|
}
|
|
1337
1361
|
|
|
1338
|
-
private _calcProductType(productClass:
|
|
1362
|
+
private _calcProductType(productClass: ProductClassType): ProductType {
|
|
1339
1363
|
switch (productClass) {
|
|
1340
1364
|
case ctp.ProductClassType.Futures:
|
|
1341
1365
|
return "futures";
|
|
@@ -1343,11 +1367,32 @@ export class Trader extends CTPProvider implements ITraderProvider {
|
|
|
1343
1367
|
case ctp.ProductClassType.Options:
|
|
1344
1368
|
return "options";
|
|
1345
1369
|
|
|
1370
|
+
case ctp.ProductClassType.Spot:
|
|
1371
|
+
return "spot";
|
|
1372
|
+
|
|
1373
|
+
case ctp.ProductClassType.SpotOption:
|
|
1374
|
+
return "spot-options";
|
|
1375
|
+
|
|
1346
1376
|
default:
|
|
1347
1377
|
throw new Error(`Unsupported product class: ${productClass}`);
|
|
1348
1378
|
}
|
|
1349
1379
|
}
|
|
1350
1380
|
|
|
1381
|
+
private _calcOptionsType(
|
|
1382
|
+
optionsType: OptionsTypeType,
|
|
1383
|
+
): OptionsType | undefined {
|
|
1384
|
+
switch (optionsType) {
|
|
1385
|
+
case ctp.OptionsTypeType.CallOptions:
|
|
1386
|
+
return "call";
|
|
1387
|
+
|
|
1388
|
+
case ctp.OptionsTypeType.PutOptions:
|
|
1389
|
+
return "put";
|
|
1390
|
+
|
|
1391
|
+
default:
|
|
1392
|
+
return undefined;
|
|
1393
|
+
}
|
|
1394
|
+
}
|
|
1395
|
+
|
|
1351
1396
|
private _ensurePositionInfo(symbol: string): PositionInfo {
|
|
1352
1397
|
let position = this.positions.get(symbol);
|
|
1353
1398
|
|
|
@@ -1671,7 +1716,7 @@ export class Trader extends CTPProvider implements ITraderProvider {
|
|
|
1671
1716
|
}
|
|
1672
1717
|
}
|
|
1673
1718
|
|
|
1674
|
-
private _toTradeData(trade:
|
|
1719
|
+
private _toTradeData(trade: TradeField): TradeData {
|
|
1675
1720
|
return Object.freeze({
|
|
1676
1721
|
id: trade.TradeID,
|
|
1677
1722
|
date: parseInt(trade.TradeDate),
|
|
@@ -1681,7 +1726,7 @@ export class Trader extends CTPProvider implements ITraderProvider {
|
|
|
1681
1726
|
});
|
|
1682
1727
|
}
|
|
1683
1728
|
|
|
1684
|
-
private _toOrderData(order:
|
|
1729
|
+
private _toOrderData(order: OrderField): OrderData {
|
|
1685
1730
|
const orderId = this._calcOrderId(order);
|
|
1686
1731
|
const trades = this.trades.get(orderId) ?? [];
|
|
1687
1732
|
|
|
@@ -1697,7 +1742,7 @@ export class Trader extends CTPProvider implements ITraderProvider {
|
|
|
1697
1742
|
time: this._parseTime(order.InsertTime),
|
|
1698
1743
|
flag: this._calcOrderFlag(order.OrderPriceType),
|
|
1699
1744
|
side: this._calcSideType(order.Direction),
|
|
1700
|
-
offset: this._calcOffsetType(order.CombOffsetFlag as
|
|
1745
|
+
offset: this._calcOffsetType(order.CombOffsetFlag as OffsetFlagType),
|
|
1701
1746
|
price: order.LimitPrice,
|
|
1702
1747
|
volume: order.VolumeTotalOriginal,
|
|
1703
1748
|
traded: traded,
|
|
@@ -1708,7 +1753,7 @@ export class Trader extends CTPProvider implements ITraderProvider {
|
|
|
1708
1753
|
});
|
|
1709
1754
|
}
|
|
1710
1755
|
|
|
1711
|
-
private _toInstrumentData(instrument:
|
|
1756
|
+
private _toInstrumentData(instrument: InstrumentField): InstrumentData {
|
|
1712
1757
|
return Object.freeze({
|
|
1713
1758
|
symbol: `${instrument.InstrumentID}.${instrument.ExchangeID}`,
|
|
1714
1759
|
id: instrument.InstrumentID,
|
|
@@ -1724,12 +1769,14 @@ export class Trader extends CTPProvider implements ITraderProvider {
|
|
|
1724
1769
|
priceTick: instrument.PriceTick,
|
|
1725
1770
|
maxLimitOrderVolume: instrument.MaxLimitOrderVolume,
|
|
1726
1771
|
minLimitOrderVolume: instrument.MinLimitOrderVolume,
|
|
1772
|
+
strikePrice: instrument.StrikePrice,
|
|
1773
|
+
optionsType: this._calcOptionsType(instrument.OptionsType),
|
|
1727
1774
|
});
|
|
1728
1775
|
}
|
|
1729
1776
|
|
|
1730
1777
|
private _toCommissionRate(
|
|
1731
1778
|
symbol: string,
|
|
1732
|
-
commRate:
|
|
1779
|
+
commRate: InstrumentCommissionRateField,
|
|
1733
1780
|
): CommissionRate {
|
|
1734
1781
|
return Object.freeze({
|
|
1735
1782
|
symbol: symbol,
|
|
@@ -1750,7 +1797,7 @@ export class Trader extends CTPProvider implements ITraderProvider {
|
|
|
1750
1797
|
|
|
1751
1798
|
private _toMarginRate(
|
|
1752
1799
|
symbol: string,
|
|
1753
|
-
marginRate:
|
|
1800
|
+
marginRate: InstrumentMarginRateField,
|
|
1754
1801
|
): MarginRate {
|
|
1755
1802
|
return Object.freeze({
|
|
1756
1803
|
symbol: symbol,
|
|
@@ -1765,11 +1812,12 @@ export class Trader extends CTPProvider implements ITraderProvider {
|
|
|
1765
1812
|
});
|
|
1766
1813
|
}
|
|
1767
1814
|
|
|
1768
|
-
private _toTradingAccount(account:
|
|
1815
|
+
private _toTradingAccount(account: TradingAccountField): TradingAccount {
|
|
1769
1816
|
return Object.freeze({
|
|
1770
1817
|
id: account.AccountID,
|
|
1771
1818
|
currency: account.CurrencyID,
|
|
1772
1819
|
preBalance: account.PreBalance - account.Withdraw + account.Deposit,
|
|
1820
|
+
preMargin: account.PreMargin,
|
|
1773
1821
|
balance: account.Balance,
|
|
1774
1822
|
cash: account.Available,
|
|
1775
1823
|
margin: account.CurrMargin,
|
|
@@ -1781,7 +1829,7 @@ export class Trader extends CTPProvider implements ITraderProvider {
|
|
|
1781
1829
|
}
|
|
1782
1830
|
|
|
1783
1831
|
private _toPositionDetail(
|
|
1784
|
-
positionDetail:
|
|
1832
|
+
positionDetail: InvestorPositionDetailField,
|
|
1785
1833
|
): PositionDetail {
|
|
1786
1834
|
return Object.freeze({
|
|
1787
1835
|
symbol: this._toSymbol(positionDetail.InstrumentID)!,
|
package/src/typedef.ts
CHANGED
|
@@ -168,6 +168,7 @@ export type TradingAccount = Readonly<{
|
|
|
168
168
|
id: string;
|
|
169
169
|
currency: string;
|
|
170
170
|
preBalance: number;
|
|
171
|
+
preMargin: number;
|
|
171
172
|
balance: number;
|
|
172
173
|
cash: number;
|
|
173
174
|
margin: number;
|
|
@@ -177,7 +178,8 @@ export type TradingAccount = Readonly<{
|
|
|
177
178
|
frozenCommission: number;
|
|
178
179
|
}>;
|
|
179
180
|
|
|
180
|
-
export type ProductType = "futures" | "options";
|
|
181
|
+
export type ProductType = "futures" | "options" | "spot" | "spot-options";
|
|
182
|
+
export type OptionsType = "call" | "put";
|
|
181
183
|
|
|
182
184
|
export type InstrumentData = Readonly<{
|
|
183
185
|
symbol: string;
|
|
@@ -194,6 +196,8 @@ export type InstrumentData = Readonly<{
|
|
|
194
196
|
priceTick: number;
|
|
195
197
|
maxLimitOrderVolume: number;
|
|
196
198
|
minLimitOrderVolume: number;
|
|
199
|
+
strikePrice: number;
|
|
200
|
+
optionsType?: OptionsType;
|
|
197
201
|
}>;
|
|
198
202
|
|
|
199
203
|
export type PriceVolume = Readonly<{
|
package/src/utils.ts
CHANGED
|
@@ -9,9 +9,9 @@
|
|
|
9
9
|
* https://github.com/shixiongfei/hft.js
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
|
-
import { BarData, OrderFlag } from "./typedef.js";
|
|
13
|
-
import { BarInfo } from "./bar.js";
|
|
14
|
-
import {
|
|
12
|
+
import type { BarData, OrderFlag } from "./typedef.js";
|
|
13
|
+
import type { BarInfo } from "./bar.js";
|
|
14
|
+
import type {
|
|
15
15
|
IPlaceOrderResultReceiver,
|
|
16
16
|
IRuntimeEngine,
|
|
17
17
|
IStrategy,
|
|
@@ -21,7 +21,7 @@ export const isValidPrice = (x: number) => x !== Number.MAX_VALUE && x !== 0;
|
|
|
21
21
|
export const isValidVolume = (x: number) => x !== Number.MAX_VALUE && x !== 0;
|
|
22
22
|
|
|
23
23
|
export const parseSymbol = (symbol: string): [string, string] => {
|
|
24
|
-
const [instrumentId, exchangeId] = symbol.split(".");
|
|
24
|
+
const [instrumentId = "", exchangeId = ""] = symbol.split(".");
|
|
25
25
|
return [instrumentId, exchangeId];
|
|
26
26
|
};
|
|
27
27
|
|
|
@@ -40,28 +40,28 @@ export const mergeBarData = (bars: BarData[]): BarData => {
|
|
|
40
40
|
}
|
|
41
41
|
|
|
42
42
|
if (bars.length === 1) {
|
|
43
|
-
return bars[1]
|
|
43
|
+
return bars[1]!;
|
|
44
44
|
}
|
|
45
45
|
|
|
46
46
|
const bar: BarInfo = {
|
|
47
|
-
symbol: bars[0]
|
|
48
|
-
date: bars[0]
|
|
49
|
-
time: bars[0]
|
|
50
|
-
openInterest: bars[0]
|
|
51
|
-
openPrice: bars[0]
|
|
52
|
-
highPrice: bars[0]
|
|
53
|
-
lowPrice: bars[0]
|
|
54
|
-
closePrice: bars[0]
|
|
55
|
-
volume: bars[0]
|
|
56
|
-
amount: bars[0]
|
|
57
|
-
delta: bars[0]
|
|
58
|
-
poc: bars[0]
|
|
59
|
-
buyVolumes: { ...bars[0]
|
|
60
|
-
sellVolumes: { ...bars[0]
|
|
47
|
+
symbol: bars[0]!.symbol,
|
|
48
|
+
date: bars[0]!.date,
|
|
49
|
+
time: bars[0]!.time,
|
|
50
|
+
openInterest: bars[0]!.openInterest,
|
|
51
|
+
openPrice: bars[0]!.openPrice,
|
|
52
|
+
highPrice: bars[0]!.highPrice,
|
|
53
|
+
lowPrice: bars[0]!.lowPrice,
|
|
54
|
+
closePrice: bars[0]!.closePrice,
|
|
55
|
+
volume: bars[0]!.volume,
|
|
56
|
+
amount: bars[0]!.volume,
|
|
57
|
+
delta: bars[0]!.delta,
|
|
58
|
+
poc: bars[0]!.poc,
|
|
59
|
+
buyVolumes: { ...bars[0]!.buyVolumes },
|
|
60
|
+
sellVolumes: { ...bars[0]!.sellVolumes },
|
|
61
61
|
};
|
|
62
62
|
|
|
63
63
|
for (let i = 1; i < bars.length; ++i) {
|
|
64
|
-
const nextBar = bars[i]
|
|
64
|
+
const nextBar = bars[i]!;
|
|
65
65
|
|
|
66
66
|
bar.openInterest = nextBar.openInterest;
|
|
67
67
|
bar.closePrice = nextBar.closePrice;
|
|
@@ -73,14 +73,9 @@ export const mergeBarData = (bars: BarData[]): BarData => {
|
|
|
73
73
|
bar.amount += nextBar.amount;
|
|
74
74
|
|
|
75
75
|
for (const price in nextBar.buyVolumes) {
|
|
76
|
-
const volumeDelta = nextBar.buyVolumes[price]
|
|
77
|
-
|
|
78
|
-
if (price in bar.buyVolumes) {
|
|
79
|
-
bar.buyVolumes[price] += volumeDelta;
|
|
80
|
-
} else {
|
|
81
|
-
bar.buyVolumes[price] = volumeDelta;
|
|
82
|
-
}
|
|
76
|
+
const volumeDelta = nextBar.buyVolumes[price]!;
|
|
83
77
|
|
|
78
|
+
bar.buyVolumes[price] = volumeDelta + (bar.buyVolumes[price] ?? 0);
|
|
84
79
|
bar.delta += volumeDelta;
|
|
85
80
|
|
|
86
81
|
const priceVP = bar.buyVolumes[price] + (bar.sellVolumes[price] ?? 0);
|
|
@@ -92,14 +87,9 @@ export const mergeBarData = (bars: BarData[]): BarData => {
|
|
|
92
87
|
}
|
|
93
88
|
|
|
94
89
|
for (const price in nextBar.sellVolumes) {
|
|
95
|
-
const volumeDelta = nextBar.sellVolumes[price]
|
|
96
|
-
|
|
97
|
-
if (price in bar.sellVolumes) {
|
|
98
|
-
bar.sellVolumes[price] += volumeDelta;
|
|
99
|
-
} else {
|
|
100
|
-
bar.sellVolumes[price] = volumeDelta;
|
|
101
|
-
}
|
|
90
|
+
const volumeDelta = nextBar.sellVolumes[price]!;
|
|
102
91
|
|
|
92
|
+
bar.sellVolumes[price] = volumeDelta + (bar.sellVolumes[price] ?? 0);
|
|
103
93
|
bar.delta -= volumeDelta;
|
|
104
94
|
|
|
105
95
|
const priceVP = bar.sellVolumes[price] + (bar.buyVolumes[price] ?? 0);
|