hft-js 0.1.0 → 0.1.2

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/utils.js ADDED
@@ -0,0 +1,106 @@
1
+ "use strict";
2
+ /*
3
+ * utils.ts
4
+ *
5
+ * Copyright (c) 2025 Xiongfei Shi
6
+ *
7
+ * Author: Xiongfei Shi <xiongfei.shi(a)icloud.com>
8
+ * License: Apache-2.0
9
+ *
10
+ * https://github.com/shixiongfei/hft.js
11
+ */
12
+ var __assign = (this && this.__assign) || function () {
13
+ __assign = Object.assign || function(t) {
14
+ for (var s, i = 1, n = arguments.length; i < n; i++) {
15
+ s = arguments[i];
16
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
17
+ t[p] = s[p];
18
+ }
19
+ return t;
20
+ };
21
+ return __assign.apply(this, arguments);
22
+ };
23
+ Object.defineProperty(exports, "__esModule", { value: true });
24
+ exports.mergeBarData = exports.getBarVolume = exports.getBarSellVolume = exports.getBarBuyVolume = exports.parseSymbol = void 0;
25
+ var parseSymbol = function (symbol) {
26
+ var _a = symbol.split("."), instrumentId = _a[0], exchangeId = _a[1];
27
+ return [instrumentId, exchangeId];
28
+ };
29
+ exports.parseSymbol = parseSymbol;
30
+ var getBarBuyVolume = function (bar, price) { var _a; return (_a = bar.buyVolumes[price]) !== null && _a !== void 0 ? _a : 0; };
31
+ exports.getBarBuyVolume = getBarBuyVolume;
32
+ var getBarSellVolume = function (bar, price) { var _a; return (_a = bar.sellVolumes[price]) !== null && _a !== void 0 ? _a : 0; };
33
+ exports.getBarSellVolume = getBarSellVolume;
34
+ var getBarVolume = function (bar, price) {
35
+ return (0, exports.getBarBuyVolume)(bar, price) + (0, exports.getBarSellVolume)(bar, price);
36
+ };
37
+ exports.getBarVolume = getBarVolume;
38
+ var mergeBarData = function (bars) {
39
+ var _a, _b;
40
+ if (bars.length === 0) {
41
+ throw new Error("Bars is empty");
42
+ }
43
+ if (bars.length === 1) {
44
+ return bars[1];
45
+ }
46
+ var bar = {
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: __assign({}, bars[0].buyVolumes),
60
+ sellVolumes: __assign({}, bars[0].sellVolumes),
61
+ };
62
+ for (var i = 1; i < bars.length; ++i) {
63
+ var nextBar = bars[i];
64
+ bar.openInterest = nextBar.openInterest;
65
+ bar.closePrice = nextBar.closePrice;
66
+ bar.highPrice = Math.max(bar.highPrice, nextBar.highPrice);
67
+ bar.lowPrice = Math.min(bar.lowPrice, nextBar.lowPrice);
68
+ bar.volume += nextBar.volume;
69
+ bar.amount += nextBar.amount;
70
+ for (var price in nextBar.buyVolumes) {
71
+ var volumeDelta = nextBar.buyVolumes[price];
72
+ if (price in bar.buyVolumes) {
73
+ bar.buyVolumes[price] += volumeDelta;
74
+ }
75
+ else {
76
+ bar.buyVolumes[price] = volumeDelta;
77
+ }
78
+ bar.delta += volumeDelta;
79
+ var priceVP = bar.buyVolumes[price] + ((_a = bar.sellVolumes[price]) !== null && _a !== void 0 ? _a : 0);
80
+ var pocVP = (0, exports.getBarVolume)(bar, bar.poc);
81
+ if (priceVP > pocVP) {
82
+ bar.poc = parseFloat(price);
83
+ }
84
+ }
85
+ for (var price in nextBar.sellVolumes) {
86
+ var volumeDelta = nextBar.sellVolumes[price];
87
+ if (price in bar.sellVolumes) {
88
+ bar.sellVolumes[price] += volumeDelta;
89
+ }
90
+ else {
91
+ bar.sellVolumes[price] = volumeDelta;
92
+ }
93
+ bar.delta -= volumeDelta;
94
+ var priceVP = bar.sellVolumes[price] + ((_b = bar.buyVolumes[price]) !== null && _b !== void 0 ? _b : 0);
95
+ var pocVP = (0, exports.getBarVolume)(bar, bar.poc);
96
+ if (priceVP > pocVP) {
97
+ bar.poc = parseFloat(price);
98
+ }
99
+ }
100
+ }
101
+ Object.freeze(bar.buyVolumes);
102
+ Object.freeze(bar.sellVolumes);
103
+ return Object.freeze(bar);
104
+ };
105
+ exports.mergeBarData = mergeBarData;
106
+ //# sourceMappingURL=utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.js","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hft-js",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "description": "High-Frequency Trading in Node.js",
5
5
  "main": "./lib/index.js",
6
6
  "types": "./lib/index.d.ts",
package/src/bar.ts ADDED
@@ -0,0 +1,133 @@
1
+ /*
2
+ * bar.ts
3
+ *
4
+ * Copyright (c) 2025 Xiongfei Shi
5
+ *
6
+ * Author: Xiongfei Shi <xiongfei.shi(a)icloud.com>
7
+ * License: Apache-2.0
8
+ *
9
+ * https://github.com/shixiongfei/hft.js
10
+ */
11
+
12
+ import { BarData, TapeData, TickData, Writeable } from "./typedef.js";
13
+ import { IBarReceiver, ITickReceiver } from "./interfaces.js";
14
+ import { getBarVolume } from "./utils.js";
15
+
16
+ export type BarInfo = Writeable<BarData>;
17
+
18
+ export class BarGenerator implements ITickReceiver {
19
+ private readonly receivers: IBarReceiver[];
20
+ private readonly symbol: string;
21
+ private bar?: BarInfo;
22
+
23
+ constructor(symbol: string) {
24
+ this.receivers = [];
25
+ this.symbol = symbol;
26
+ }
27
+
28
+ get isWorking() {
29
+ return this.receivers.length > 0;
30
+ }
31
+
32
+ addReceiver(receiver: IBarReceiver) {
33
+ if (!this.receivers.includes(receiver)) {
34
+ this.receivers.push(receiver);
35
+ }
36
+ }
37
+
38
+ removeReceiver(receiver: IBarReceiver) {
39
+ const index = this.receivers.indexOf(receiver);
40
+
41
+ if (index >= 0) {
42
+ this.receivers.splice(index, 1);
43
+ }
44
+ }
45
+
46
+ onTick(tick: TickData, tape: TapeData) {
47
+ if (tick.symbol !== this.symbol) {
48
+ return;
49
+ }
50
+
51
+ const date = tick.date;
52
+ const time = Math.floor(tick.time / 100) * 100;
53
+
54
+ if (this.bar && (this.bar.date !== date || this.bar.time !== time)) {
55
+ const bar = Object.freeze(this.bar);
56
+
57
+ Object.freeze(bar.buyVolumes);
58
+ Object.freeze(bar.sellVolumes);
59
+
60
+ this.receivers.forEach((receiver) => receiver.onBar(bar));
61
+ this.bar = undefined;
62
+ }
63
+
64
+ if (tape.volumeDelta === 0) {
65
+ return;
66
+ }
67
+
68
+ if (!this.bar) {
69
+ this.bar = this._createBar(date, time, tick);
70
+ }
71
+
72
+ this.bar.openInterest = tick.openInterest;
73
+ this.bar.closePrice = tick.lastPrice;
74
+
75
+ this.bar.highPrice = Math.max(this.bar.highPrice, tick.lastPrice);
76
+ this.bar.lowPrice = Math.min(this.bar.lowPrice, tick.lastPrice);
77
+
78
+ this.bar.volume += tape.volumeDelta;
79
+ this.bar.amount += tape.amountDelta;
80
+
81
+ switch (tape.direction) {
82
+ case "up":
83
+ if (tick.lastPrice in this.bar.buyVolumes) {
84
+ this.bar.buyVolumes[tick.lastPrice] += tape.volumeDelta;
85
+ } else {
86
+ this.bar.buyVolumes[tick.lastPrice] = tape.volumeDelta;
87
+ }
88
+
89
+ this.bar.delta += tape.volumeDelta;
90
+ break;
91
+
92
+ case "down":
93
+ if (tick.lastPrice in this.bar.sellVolumes) {
94
+ this.bar.sellVolumes[tick.lastPrice] += tape.volumeDelta;
95
+ } else {
96
+ this.bar.sellVolumes[tick.lastPrice] = tape.volumeDelta;
97
+ }
98
+
99
+ this.bar.delta -= tape.volumeDelta;
100
+ break;
101
+ }
102
+
103
+ if (tape.direction !== "none") {
104
+ const tickVP = getBarVolume(this.bar, tick.lastPrice);
105
+ const pocVP = getBarVolume(this.bar, this.bar.poc);
106
+
107
+ if (tickVP > pocVP) {
108
+ this.bar.poc = tick.lastPrice;
109
+ }
110
+ }
111
+ }
112
+
113
+ private _createBar(date: number, time: number, tick: TickData): BarInfo {
114
+ return {
115
+ symbol: this.symbol,
116
+ date: date,
117
+ time: time,
118
+ openInterest: tick.openInterest,
119
+ openPrice: tick.lastPrice,
120
+ highPrice: tick.lastPrice,
121
+ lowPrice: tick.lastPrice,
122
+ closePrice: tick.lastPrice,
123
+ volume: 0,
124
+ amount: 0,
125
+ delta: 0,
126
+ poc: tick.lastPrice,
127
+ buyVolumes: {},
128
+ sellVolumes: {},
129
+ };
130
+ }
131
+ }
132
+
133
+ export const createBarGenerator = (symbol: string) => new BarGenerator(symbol);
package/src/broker.ts CHANGED
@@ -10,6 +10,7 @@
10
10
  */
11
11
 
12
12
  import { OffsetType, OrderData, OrderFlag, SideType } from "./typedef.js";
13
+ import { BarGenerator, createBarGenerator } from "./bar.js";
13
14
  import {
14
15
  ICancelOrderResultReceiver,
15
16
  ErrorType,
@@ -32,6 +33,7 @@ import {
32
33
  IPlaceOrderResultReceiver,
33
34
  IPositionReceiver,
34
35
  IPositionDetailsReceiver,
36
+ IBarReceiver,
35
37
  } from "./interfaces.js";
36
38
 
37
39
  export class Broker implements IRuntimeEngine {
@@ -42,6 +44,7 @@ export class Broker implements IRuntimeEngine {
42
44
  private readonly strategies: IStrategy[] = [];
43
45
  private readonly placeOrderRiskManagers: IPlaceOrderRiskManager[] = [];
44
46
  private readonly cancelOrderRiskManagers: ICancelOrderRiskManager[] = [];
47
+ private readonly generators: Map<string, BarGenerator>;
45
48
 
46
49
  constructor(
47
50
  trader: ITraderProvider,
@@ -50,6 +53,7 @@ export class Broker implements IRuntimeEngine {
50
53
  ) {
51
54
  this.trader = trader;
52
55
  this.market = market;
56
+ this.generators = new Map();
53
57
 
54
58
  this.marketLifecycle = {
55
59
  onOpen: () => {
@@ -63,12 +67,14 @@ export class Broker implements IRuntimeEngine {
63
67
  });
64
68
  }
65
69
 
66
- this.strategies.forEach((strategy) => strategy.onInit(this));
70
+ this.strategies.forEach((strategy) => strategy.onInit());
67
71
  },
72
+
68
73
  onClose: () => {
69
- this.strategies.forEach((strategy) => strategy.onDestroy(this));
74
+ this.strategies.forEach((strategy) => strategy.onDestroy());
70
75
  this.market.stopRecorder();
71
76
  },
77
+
72
78
  onError: (error: ErrorType, message: string) => {
73
79
  if (errorReceiver) {
74
80
  errorReceiver.onError(error, message);
@@ -80,9 +86,11 @@ export class Broker implements IRuntimeEngine {
80
86
  onOpen: () => {
81
87
  this.market.open(this.marketLifecycle);
82
88
  },
89
+
83
90
  onClose: () => {
84
91
  this.market.close(this.marketLifecycle);
85
92
  },
93
+
86
94
  onError: (error: ErrorType, message: string) => {
87
95
  if (errorReceiver) {
88
96
  errorReceiver.onError(error, message);
@@ -137,6 +145,38 @@ export class Broker implements IRuntimeEngine {
137
145
  return this.market.unsubscribe(symbols, receiver);
138
146
  }
139
147
 
148
+ subscribeBar(symbols: string[], receiver: IBarReceiver) {
149
+ symbols.forEach((symbol) => {
150
+ let generator = this.generators.get(symbol);
151
+
152
+ if (!generator) {
153
+ generator = createBarGenerator(symbol);
154
+
155
+ this.generators.set(symbol, generator);
156
+ this.subscribe([symbol], generator);
157
+ }
158
+
159
+ generator.addReceiver(receiver);
160
+ });
161
+ }
162
+
163
+ unsubscribeBar(symbols: string[], receiver: IBarReceiver) {
164
+ symbols.forEach((symbol) => {
165
+ const generator = this.generators.get(symbol);
166
+
167
+ if (!generator) {
168
+ return;
169
+ }
170
+
171
+ generator.removeReceiver(receiver);
172
+
173
+ if (!generator.isWorking) {
174
+ this.unsubscribe([symbol], generator);
175
+ this.generators.delete(symbol);
176
+ }
177
+ });
178
+ }
179
+
140
180
  placeOrder(
141
181
  strategy: IStrategy,
142
182
  symbol: string,
@@ -205,6 +245,84 @@ export class Broker implements IRuntimeEngine {
205
245
  return this.trader.cancelOrder(order, receiver);
206
246
  }
207
247
 
248
+ buyOpen(
249
+ strategy: IStrategy,
250
+ symbol: string,
251
+ volume: number,
252
+ price: number,
253
+ receiver: IPlaceOrderResultReceiver,
254
+ ) {
255
+ return this.placeOrder(
256
+ strategy,
257
+ symbol,
258
+ "open",
259
+ "long",
260
+ volume,
261
+ price,
262
+ "limit",
263
+ receiver,
264
+ );
265
+ }
266
+
267
+ buyClose(
268
+ strategy: IStrategy,
269
+ symbol: string,
270
+ volume: number,
271
+ price: number,
272
+ isToday: boolean,
273
+ receiver: IPlaceOrderResultReceiver,
274
+ ) {
275
+ return this.placeOrder(
276
+ strategy,
277
+ symbol,
278
+ isToday ? "close-today" : "close",
279
+ "long",
280
+ volume,
281
+ price,
282
+ "limit",
283
+ receiver,
284
+ );
285
+ }
286
+
287
+ sellOpen(
288
+ strategy: IStrategy,
289
+ symbol: string,
290
+ volume: number,
291
+ price: number,
292
+ receiver: IPlaceOrderResultReceiver,
293
+ ) {
294
+ return this.placeOrder(
295
+ strategy,
296
+ symbol,
297
+ "open",
298
+ "short",
299
+ volume,
300
+ price,
301
+ "limit",
302
+ receiver,
303
+ );
304
+ }
305
+
306
+ sellClose(
307
+ strategy: IStrategy,
308
+ symbol: string,
309
+ volume: number,
310
+ price: number,
311
+ isToday: boolean,
312
+ receiver: IPlaceOrderResultReceiver,
313
+ ) {
314
+ return this.placeOrder(
315
+ strategy,
316
+ symbol,
317
+ isToday ? "close-today" : "close",
318
+ "short",
319
+ volume,
320
+ price,
321
+ "limit",
322
+ receiver,
323
+ );
324
+ }
325
+
208
326
  getTradingDay() {
209
327
  return this.trader.getTradingDay();
210
328
  }
package/src/index.test.ts CHANGED
@@ -43,8 +43,9 @@ if (!existsFile(config.FlowMdPath)) {
43
43
  fs.mkdirSync(config.FlowMdPath, { recursive: true });
44
44
  }
45
45
 
46
- class Strategy implements hft.IStrategy, hft.ITickReceiver {
46
+ class Strategy implements hft.IStrategy, hft.ITickReceiver, hft.IBarReceiver {
47
47
  private lastTick?: hft.TickData;
48
+ private lastBar?: hft.BarData;
48
49
  private engine: hft.IRuntimeEngine;
49
50
  readonly symbol = "ni2505.SHFE";
50
51
 
@@ -52,10 +53,11 @@ class Strategy implements hft.IStrategy, hft.ITickReceiver {
52
53
  this.engine = engine;
53
54
  }
54
55
 
55
- onInit(subscriber: hft.ITickSubscriber) {
56
- subscriber.subscribe([this.symbol], this);
57
- console.log("Strategy init");
56
+ onInit() {
57
+ this.engine.subscribe([this.symbol], this);
58
+ this.engine.subscribeBar([this.symbol], this);
58
59
 
60
+ console.log("Strategy init");
59
61
  console.log("Trading Day", this.engine.getTradingDay());
60
62
 
61
63
  this.engine.queryInstrument(this.symbol, {
@@ -111,14 +113,15 @@ class Strategy implements hft.IStrategy, hft.ITickReceiver {
111
113
  return;
112
114
  }
113
115
 
114
- this.engine.placeOrder(
116
+ if (this.lastBar) {
117
+ console.log(this.lastBar);
118
+ }
119
+
120
+ this.engine.buyOpen(
115
121
  this,
116
122
  this.symbol,
117
- "open",
118
- "long",
119
123
  1,
120
124
  this.lastTick.orderBook.asks.price[0],
121
- "limit",
122
125
  {
123
126
  onPlaceOrderSent: (receiptId) => {
124
127
  console.log("Open Place Order Receipt Id", receiptId);
@@ -132,8 +135,9 @@ class Strategy implements hft.IStrategy, hft.ITickReceiver {
132
135
  }, 30 * 1000);
133
136
  }
134
137
 
135
- onDestroy(unsubscriber: hft.ITickUnsubscriber) {
136
- unsubscriber.unsubscribe([this.symbol], this);
138
+ onDestroy() {
139
+ this.engine.unsubscribeBar([this.symbol], this);
140
+ this.engine.unsubscribe([this.symbol], this);
137
141
  console.log("Strategy destroy");
138
142
  }
139
143
 
@@ -147,44 +151,44 @@ class Strategy implements hft.IStrategy, hft.ITickReceiver {
147
151
 
148
152
  onTrade(order: hft.OrderData, trade: hft.TradeData) {
149
153
  console.log("Order", order, "Traded", trade);
150
- }
151
-
152
- onFinish(order: hft.OrderData) {
153
- console.log("Finish Order", order);
154
-
155
- setTimeout(() => {
156
- this.engine.queryPosition(this.symbol, {
157
- onPosition: (position) => {
158
- if (!position || !this.lastTick) {
159
- return;
160
- }
161
-
162
- const todayLong =
163
- position.today.long.position - position.today.long.frozen;
164
-
165
- if (todayLong > 0) {
166
- this.engine.placeOrder(
167
- this,
168
- this.symbol,
169
- "close-today",
170
- "short",
171
- todayLong,
172
- this.lastTick.orderBook.bids.price[0],
173
- "limit",
174
- {
175
- onPlaceOrderSent: (receiptId) => {
176
- console.log("Close Place Order Receipt Id", receiptId);
177
- },
178
154
 
179
- onPlaceOrderError: (reason) => {
180
- console.error("Close Place Order Error", reason);
155
+ if (order.status === "filled") {
156
+ setTimeout(() => {
157
+ this.engine.queryPosition(this.symbol, {
158
+ onPosition: (position) => {
159
+ if (!position || !this.lastTick) {
160
+ return;
161
+ }
162
+
163
+ const todayLong =
164
+ position.today.long.position - position.today.long.frozen;
165
+
166
+ if (todayLong > 0) {
167
+ if (this.lastBar) {
168
+ console.log(this.lastBar);
169
+ }
170
+
171
+ this.engine.sellClose(
172
+ this,
173
+ this.symbol,
174
+ todayLong,
175
+ this.lastTick.orderBook.bids.price[0],
176
+ true,
177
+ {
178
+ onPlaceOrderSent: (receiptId) => {
179
+ console.log("Close Place Order Receipt Id", receiptId);
180
+ },
181
+
182
+ onPlaceOrderError: (reason) => {
183
+ console.error("Close Place Order Error", reason);
184
+ },
181
185
  },
182
- },
183
- );
184
- }
185
- },
186
- });
187
- }, 30 * 1000);
186
+ );
187
+ }
188
+ },
189
+ });
190
+ }, 30 * 1000);
191
+ }
188
192
  }
189
193
 
190
194
  onCancel(order: hft.OrderData) {
@@ -195,14 +199,18 @@ class Strategy implements hft.IStrategy, hft.ITickReceiver {
195
199
  console.log("Reject Order", order);
196
200
  }
197
201
 
198
- onTick(tick: hft.TickData) {
199
- //const tape = hft.calcTapeData(tick, this.lastTick);
200
-
202
+ onTick(tick: hft.TickData, tape: hft.TapeData) {
201
203
  //console.log(tick);
202
204
  //console.log(tape);
203
205
 
204
206
  this.lastTick = tick;
205
207
  }
208
+
209
+ onBar(bar: hft.BarData) {
210
+ //console.log(bar)
211
+
212
+ this.lastBar = bar;
213
+ }
206
214
  }
207
215
 
208
216
  const trader = hft.createTrader(
package/src/index.ts CHANGED
@@ -12,7 +12,7 @@
12
12
  export * from "./typedef.js";
13
13
  export * from "./interfaces.js";
14
14
  export * from "./broker.js";
15
- export * from "./tape.js";
16
15
  export * from "./trader.js";
17
16
  export * from "./market.js";
17
+ export * from "./utils.js";
18
18
  export { CTPUserInfo } from "./provider.js";