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/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?: ctp.MarketData;
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<ctp.RspUserLoginField>(
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<ctp.SpecificInstrumentField>(
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<ctp.SpecificInstrumentField>(
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<ctp.DepthMarketDataField>(
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: ctp.CallbackOptions,
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 [hour, minute, second] = time.split(":").map((x) => parseInt(x));
73
- return hour * 10000 + minute * 100 + second;
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
@@ -9,7 +9,7 @@
9
9
  * https://github.com/shixiongfei/hft.js
10
10
  */
11
11
 
12
- import {
12
+ import type {
13
13
  TapeData,
14
14
  TapeDirection,
15
15
  TapeStatus,
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?: ctp.Trader;
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: ctp.TradingAccountField[];
103
- private readonly positionDetails: ctp.InvestorPositionDetailField[];
104
- private readonly instruments: Map<string, ctp.InstrumentField>;
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, ctp.OrderField>;
107
- private readonly trades: Map<string, ctp.TradeField[]>;
108
- private readonly marginRates: Map<string, ctp.InstrumentMarginRateField>;
109
- private readonly commRates: Map<string, ctp.InstrumentCommissionRateField>;
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<ctp.RspAuthenticateField>(
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<ctp.RspUserLoginField>(
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<ctp.SettlementInfoConfirmField>(
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<ctp.OrderField>(
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<ctp.TradeField>(
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<ctp.InstrumentField>(
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<ctp.InvestorPositionField>(
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<ctp.OrderField>(ctp.TraderEvent.RtnOrder, (order) => {
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<ctp.TradeField>(ctp.TraderEvent.RtnTrade, (trade) => {
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<ctp.InstrumentMarginRateField>(
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<ctp.InstrumentCommissionRateField>(
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<ctp.TradingAccountField>(
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<ctp.InvestorPositionDetailField>(
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<ctp.InputOrderField>(
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<ctp.InputOrderActionField>(
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<ctp.DepthMarketDataField>(
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: ctp.OrderField | ctp.TradeField) {
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: ctp.OrderField | ctp.InputOrderActionField) {
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: ctp.OrderPriceTypeType): OrderFlag {
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: ctp.DirectionType): SideType {
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: ctp.OffsetFlagType): OffsetType {
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: ctp.ProductClassType): ProductType {
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: ctp.TradeField): TradeData {
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: ctp.OrderField): OrderData {
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 ctp.OffsetFlagType),
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: ctp.InstrumentField): InstrumentData {
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: ctp.InstrumentCommissionRateField,
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: ctp.InstrumentMarginRateField,
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: ctp.TradingAccountField): TradingAccount {
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: ctp.InvestorPositionDetailField,
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].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 },
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);