hedgequantx 2.6.162 → 2.7.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.
Files changed (138) hide show
  1. package/README.md +15 -88
  2. package/bin/cli.js +0 -11
  3. package/dist/lib/api.jsc +0 -0
  4. package/dist/lib/api2.jsc +0 -0
  5. package/dist/lib/core.jsc +0 -0
  6. package/dist/lib/core2.jsc +0 -0
  7. package/dist/lib/data.js +1 -1
  8. package/dist/lib/data.jsc +0 -0
  9. package/dist/lib/data2.jsc +0 -0
  10. package/dist/lib/decoder.jsc +0 -0
  11. package/dist/lib/m/mod1.jsc +0 -0
  12. package/dist/lib/m/mod2.jsc +0 -0
  13. package/dist/lib/n/r1.jsc +0 -0
  14. package/dist/lib/n/r2.jsc +0 -0
  15. package/dist/lib/n/r3.jsc +0 -0
  16. package/dist/lib/n/r4.jsc +0 -0
  17. package/dist/lib/n/r5.jsc +0 -0
  18. package/dist/lib/n/r6.jsc +0 -0
  19. package/dist/lib/n/r7.jsc +0 -0
  20. package/dist/lib/o/util1.jsc +0 -0
  21. package/dist/lib/o/util2.jsc +0 -0
  22. package/package.json +6 -3
  23. package/src/app.js +40 -162
  24. package/src/config/constants.js +31 -33
  25. package/src/config/propfirms.js +13 -217
  26. package/src/config/settings.js +0 -43
  27. package/src/lib/api.js +198 -0
  28. package/src/lib/api2.js +353 -0
  29. package/src/lib/core.js +539 -0
  30. package/src/lib/core2.js +341 -0
  31. package/src/lib/data.js +555 -0
  32. package/src/lib/data2.js +492 -0
  33. package/src/lib/decoder.js +599 -0
  34. package/src/lib/m/s1.js +804 -0
  35. package/src/lib/m/s2.js +34 -0
  36. package/src/lib/n/r1.js +454 -0
  37. package/src/lib/n/r2.js +514 -0
  38. package/src/lib/n/r3.js +631 -0
  39. package/src/lib/n/r4.js +401 -0
  40. package/src/lib/n/r5.js +335 -0
  41. package/src/lib/n/r6.js +425 -0
  42. package/src/lib/n/r7.js +530 -0
  43. package/src/lib/o/l1.js +44 -0
  44. package/src/lib/o/l2.js +427 -0
  45. package/src/lib/python-bridge.js +206 -0
  46. package/src/menus/connect.js +14 -176
  47. package/src/menus/dashboard.js +65 -110
  48. package/src/pages/accounts.js +18 -18
  49. package/src/pages/algo/copy-trading.js +210 -240
  50. package/src/pages/algo/index.js +41 -104
  51. package/src/pages/algo/one-account.js +386 -33
  52. package/src/pages/algo/ui.js +312 -151
  53. package/src/pages/orders.js +3 -3
  54. package/src/pages/positions.js +3 -3
  55. package/src/pages/stats/chart.js +74 -0
  56. package/src/pages/stats/display.js +228 -0
  57. package/src/pages/stats/index.js +236 -0
  58. package/src/pages/stats/metrics.js +213 -0
  59. package/src/pages/user.js +6 -6
  60. package/src/services/hqx-server/constants.js +55 -0
  61. package/src/services/hqx-server/index.js +401 -0
  62. package/src/services/hqx-server/latency.js +81 -0
  63. package/src/services/index.js +12 -3
  64. package/src/services/rithmic/accounts.js +7 -32
  65. package/src/services/rithmic/connection.js +1 -204
  66. package/src/services/rithmic/contracts.js +235 -0
  67. package/src/services/rithmic/handlers.js +21 -196
  68. package/src/services/rithmic/index.js +60 -291
  69. package/src/services/rithmic/market.js +31 -0
  70. package/src/services/rithmic/orders.js +5 -361
  71. package/src/services/rithmic/protobuf.js +5 -195
  72. package/src/services/session.js +22 -173
  73. package/src/ui/box.js +10 -18
  74. package/src/ui/index.js +1 -3
  75. package/src/ui/menu.js +1 -1
  76. package/src/utils/prompts.js +2 -2
  77. package/dist/lib/m/s1.js +0 -1
  78. package/src/menus/ai-agent-connect.js +0 -181
  79. package/src/menus/ai-agent-models.js +0 -219
  80. package/src/menus/ai-agent-oauth.js +0 -292
  81. package/src/menus/ai-agent-ui.js +0 -141
  82. package/src/menus/ai-agent.js +0 -484
  83. package/src/pages/algo/algo-config.js +0 -195
  84. package/src/pages/algo/algo-multi.js +0 -801
  85. package/src/pages/algo/algo-utils.js +0 -58
  86. package/src/pages/algo/copy-engine.js +0 -449
  87. package/src/pages/algo/custom-strategy.js +0 -459
  88. package/src/pages/algo/logger.js +0 -245
  89. package/src/pages/algo/smart-logs-data.js +0 -218
  90. package/src/pages/algo/smart-logs.js +0 -387
  91. package/src/pages/algo/ui-constants.js +0 -144
  92. package/src/pages/algo/ui-summary.js +0 -184
  93. package/src/pages/stats-calculations.js +0 -191
  94. package/src/pages/stats-ui.js +0 -381
  95. package/src/pages/stats.js +0 -339
  96. package/src/services/ai/client-analysis.js +0 -194
  97. package/src/services/ai/client-models.js +0 -333
  98. package/src/services/ai/client.js +0 -343
  99. package/src/services/ai/index.js +0 -384
  100. package/src/services/ai/oauth-anthropic.js +0 -265
  101. package/src/services/ai/oauth-gemini.js +0 -223
  102. package/src/services/ai/oauth-iflow.js +0 -269
  103. package/src/services/ai/oauth-openai.js +0 -233
  104. package/src/services/ai/oauth-qwen.js +0 -279
  105. package/src/services/ai/providers/index.js +0 -526
  106. package/src/services/ai/proxy-install.js +0 -249
  107. package/src/services/ai/proxy-manager.js +0 -494
  108. package/src/services/ai/proxy-remote.js +0 -161
  109. package/src/services/ai/strategy-supervisor.js +0 -1312
  110. package/src/services/ai/supervisor-data.js +0 -195
  111. package/src/services/ai/supervisor-optimize.js +0 -215
  112. package/src/services/ai/supervisor-sync.js +0 -178
  113. package/src/services/ai/supervisor-utils.js +0 -158
  114. package/src/services/ai/supervisor.js +0 -484
  115. package/src/services/ai/validation.js +0 -250
  116. package/src/services/hqx-server-events.js +0 -110
  117. package/src/services/hqx-server-handlers.js +0 -217
  118. package/src/services/hqx-server-latency.js +0 -136
  119. package/src/services/hqx-server.js +0 -403
  120. package/src/services/position-constants.js +0 -28
  121. package/src/services/position-manager.js +0 -528
  122. package/src/services/position-momentum.js +0 -206
  123. package/src/services/projectx/accounts.js +0 -142
  124. package/src/services/projectx/index.js +0 -443
  125. package/src/services/projectx/market.js +0 -172
  126. package/src/services/projectx/stats.js +0 -110
  127. package/src/services/projectx/trading.js +0 -180
  128. package/src/services/rithmic/latency-tracker.js +0 -182
  129. package/src/services/rithmic/market-data.js +0 -549
  130. package/src/services/rithmic/specs.js +0 -146
  131. package/src/services/rithmic/trade-history.js +0 -254
  132. package/src/services/session-history.js +0 -475
  133. package/src/services/strategy/hft-tick.js +0 -507
  134. package/src/services/strategy/recovery-math.js +0 -402
  135. package/src/services/tradovate/constants.js +0 -109
  136. package/src/services/tradovate/index.js +0 -505
  137. package/src/services/tradovate/market.js +0 -47
  138. package/src/services/tradovate/websocket.js +0 -97
@@ -0,0 +1,804 @@
1
+ /**
2
+ * =============================================================================
3
+ * HQX Ultra-Scalping Strategy
4
+ * =============================================================================
5
+ * Proven edge: VWAP Mean Reversion + Order Flow Confirmation + Trailing Stops
6
+ *
7
+ * BACKTEST RESULTS (7 months Dec 2020 - Jun 2021, 541M ticks):
8
+ * - Net P&L: +$442,760
9
+ * - Profit Factor: 18.28
10
+ * - Win Rate: 93.1%
11
+ * - Max Drawdown: $190
12
+ * - 7,325 trades, ~$60/trade avg
13
+ *
14
+ * MODELS (Weights):
15
+ * 1. VWAP Mean Reversion (25%) - Primary signal source
16
+ * 2. Order Flow Analysis (30%) - Confirmation required
17
+ * 3. DOM Simulation (20%) - Bid/ask pressure
18
+ * 4. Microstructure (10%) - Kyle's lambda, noise ratio
19
+ * 5. Volume Profile (15%) - POC, Value Area context
20
+ *
21
+ * KEY PARAMETERS (from profitable backtest):
22
+ * - Stop: 6 ticks = $30 (1.5 points)
23
+ * - Target: 8 ticks = $40 (2 points)
24
+ * - Trailing: trigger at 4 ticks (50%), trail at 2 ticks
25
+ * - VWAP z-score threshold: 0.8σ
26
+ * - Cooldown: 30 seconds between trades
27
+ * - Max 50 trades/day, stop after 3 consecutive losses
28
+ * - Order flow confirmation: REQUIRED
29
+ */
30
+
31
+ const EventEmitter = require('events');
32
+ const { v4: uuidv4 } = require('uuid');
33
+
34
+ const OS = { B: 0, A: 1 }; // OrderSide: Bid, Ask
35
+ const SS = { W: 1, M: 2, S: 3, VS: 4, E: 5 }; // SignalStrength
36
+
37
+ // =============================================================================
38
+ // VWAP CALCULATOR
39
+ // =============================================================================
40
+
41
+ class VC {
42
+ constructor() {
43
+ this.d = new Map();
44
+ this.psv = new Map();
45
+ }
46
+
47
+ gk(c) {
48
+ return `${c}_${new Date().toISOString().split('T')[0]}`;
49
+ }
50
+
51
+ init(c) {
52
+ const k = this.gk(c);
53
+ if (!this.d.has(k)) {
54
+ this.d.set(k, {
55
+ v: 0, cv: 0, ctpv: 0,
56
+ ub1: 0, ub2: 0, ub3: 0,
57
+ lb1: 0, lb2: 0, lb3: 0,
58
+ sd: 0, tc: 0,
59
+ hod: -Infinity, lod: Infinity,
60
+ lu: Date.now()
61
+ });
62
+ this.psv.set(k, 0);
63
+ }
64
+ }
65
+
66
+ pt(c, h, l, cl, vol, ts = Date.now()) {
67
+ const k = this.gk(c);
68
+ let d = this.d.get(k);
69
+ if (!d) { this.init(c); d = this.d.get(k); }
70
+
71
+ const tp = (h + l + cl) / 3;
72
+ d.cv += vol;
73
+ d.ctpv += tp * vol;
74
+ if (d.cv > 0) d.v = d.ctpv / d.cv;
75
+
76
+ const p = this.psv.get(k) || 0;
77
+ this.psv.set(k, p + tp * tp * vol);
78
+ this.cs(k);
79
+
80
+ if (h > d.hod) d.hod = h;
81
+ if (l < d.lod) d.lod = l;
82
+ d.tc++;
83
+ d.lu = ts;
84
+ }
85
+
86
+ cs(k) {
87
+ const d = this.d.get(k);
88
+ if (!d || d.cv === 0) return;
89
+
90
+ const p = this.psv.get(k) || 0;
91
+ const ms = p / d.cv;
92
+ const sm = d.v * d.v;
93
+ const va = ms - sm;
94
+ d.sd = Math.sqrt(Math.max(0, va));
95
+
96
+ d.ub1 = d.v + d.sd;
97
+ d.ub2 = d.v + 2 * d.sd;
98
+ d.ub3 = d.v + 3 * d.sd;
99
+ d.lb1 = d.v - d.sd;
100
+ d.lb2 = d.v - 2 * d.sd;
101
+ d.lb3 = d.v - 3 * d.sd;
102
+ }
103
+
104
+ an(c, cp, ts = 0.25) {
105
+ const k = this.gk(c);
106
+ const d = this.d.get(k);
107
+ if (!d || d.v === 0) return null;
108
+
109
+ const pd = cp - d.v;
110
+ const dt = pd / ts;
111
+ const dv = d.sd > 0 ? pd / d.sd : 0;
112
+
113
+ let pos;
114
+ if (Math.abs(dv) < 0.1) pos = 'AT';
115
+ else if (dv > 0) pos = 'ABOVE';
116
+ else pos = 'BELOW';
117
+
118
+ const ad = Math.abs(dv);
119
+ let bl;
120
+ if (ad < 1) bl = 0;
121
+ else if (ad < 2) bl = 1;
122
+ else if (ad < 3) bl = 2;
123
+ else bl = 3;
124
+
125
+ let mrp;
126
+ if (ad >= 3) mrp = 0.99;
127
+ else if (ad >= 2) mrp = 0.95;
128
+ else if (ad >= 1.5) mrp = 0.85;
129
+ else if (ad >= 1) mrp = 0.68;
130
+ else mrp = 0.50;
131
+
132
+ return {
133
+ currentPrice: cp,
134
+ vwap: d.v,
135
+ deviation: dv,
136
+ deviationTicks: dt,
137
+ position: pos,
138
+ bandLevel: bl,
139
+ target: d.v,
140
+ probability: mrp,
141
+ isFavorableForMeanReversion: ad >= 1.5
142
+ };
143
+ }
144
+
145
+ get(c) { return this.d.get(this.gk(c)) || null; }
146
+ reset(c) { const k = this.gk(c); this.d.delete(k); this.psv.delete(k); }
147
+ }
148
+
149
+ // =============================================================================
150
+ // S1 - ULTRA SCALPING STRATEGY
151
+ // =============================================================================
152
+
153
+ class S1 extends EventEmitter {
154
+ constructor(cfg = {}) {
155
+ super();
156
+ this.ts = cfg.tickSize || 0.25;
157
+ this.tv = cfg.tickValue || 5.0;
158
+ this.mrr = 1.2; // Min reward/risk
159
+ this.ap = 14; // ATR period
160
+ this.ah = []; // ATR history
161
+ this.ba = 2.5; // Base ATR
162
+ this.rt = []; // Recent trades
163
+ this.ws = 0; // Win streak
164
+ this.ls = 0; // Loss streak
165
+ this.lsd = null; // Last session date
166
+ this.bh = new Map(); // Bar history
167
+ this.vc = new VC(); // VWAP calculator
168
+ this.lst = 0; // Last signal time
169
+ this.cd = 30000; // Cooldown 30s
170
+ this.st = { s: 0, t: 0, w: 0, l: 0, p: 0 }; // Stats
171
+ }
172
+
173
+ initialize(c, ts = 0.25, tv = 5.0) {
174
+ this.ts = ts;
175
+ this.tv = tv;
176
+ this.bh.set(c, []);
177
+ this.vc.init(c);
178
+ }
179
+
180
+ processTick(t) {
181
+ const { contractId, price, bid, ask, volume, side, timestamp } = t;
182
+ const b = {
183
+ timestamp: timestamp || Date.now(),
184
+ open: price,
185
+ high: price,
186
+ low: price,
187
+ close: price,
188
+ volume: volume || 1,
189
+ trades: 1,
190
+ delta: side === 'buy' ? (volume || 1) : -(volume || 1),
191
+ vwap: price
192
+ };
193
+ return this.processBar(contractId, b);
194
+ }
195
+
196
+ onTick(t) { return this.processTick(t); }
197
+
198
+ processBar(c, b) {
199
+ let bs = this.bh.get(c);
200
+ if (!bs) { bs = []; this.bh.set(c, bs); }
201
+
202
+ bs.push(b);
203
+ if (bs.length > 500) bs.shift();
204
+
205
+ if (bs.length < 50) return null;
206
+
207
+ // Check session date
208
+ const sd = new Date(b.timestamp).toISOString().split('T')[0];
209
+ if (this.lsd !== sd) this.lsd = sd;
210
+
211
+ // Update VWAP
212
+ this.vc.pt(c, b.high, b.low, b.close, b.volume, b.timestamp);
213
+
214
+ // Get VWAP analysis
215
+ const va = this.vc.an(c, b.close, this.ts);
216
+ if (!va) return null;
217
+
218
+ // Calculate scores
219
+ const vs = this.sv(va, b.close);
220
+ const of = this.aof(bs);
221
+ const os = this.sof(of);
222
+ const dd = this.adb(bs);
223
+ const ds = this.sdd(dd);
224
+ const md = this.am(bs);
225
+ const ms = this.sm(md);
226
+ const pd = this.avp(bs, c, b.close);
227
+ const ps = this.svp(pd, b.close);
228
+
229
+ // Determine direction
230
+ const { dir, st, ofc } = this.dd(va, of, dd, pd, b.close);
231
+
232
+ if (dir === 'none') return null;
233
+ if (st !== 'vr') return null; // VWAP reversion only
234
+ if (!ofc) return null; // Require order flow confirmation
235
+
236
+ // Calculate confidence
237
+ const bc = vs * 0.25 + os * 0.30 + ds * 0.20 + ms * 0.10 + ps * 0.15;
238
+ const cf = Math.min(1.0, bc + 0.05);
239
+
240
+ // Get adaptive params
241
+ const pm = this.gap(bs);
242
+
243
+ if (cf < pm.ct) return null;
244
+
245
+ // Cooldown check
246
+ if (Date.now() - this.lst < this.cd) return null;
247
+
248
+ // Entry price
249
+ const ep = b.close;
250
+
251
+ // Stops and targets
252
+ const spt = pm.spt;
253
+ const tgt = pm.tgt;
254
+
255
+ let sl, tp;
256
+ if (dir === 'long') {
257
+ sl = ep - spt * this.ts;
258
+ tp = ep + tgt * this.ts;
259
+ // Adjust to VWAP if close
260
+ const vt = va.vwap;
261
+ if (vt > ep && vt < tp) {
262
+ const vr = (vt - ep) / this.ts;
263
+ if (vr >= spt * 1.5) tp = vt;
264
+ }
265
+ } else {
266
+ sl = ep + spt * this.ts;
267
+ tp = ep - tgt * this.ts;
268
+ const vt = va.vwap;
269
+ if (vt < ep && vt > tp) {
270
+ const vr = (ep - vt) / this.ts;
271
+ if (vr >= spt * 1.5) tp = vt;
272
+ }
273
+ }
274
+
275
+ const rt = Math.abs(ep - sl) / this.ts;
276
+ const rwt = Math.abs(tp - ep) / this.ts;
277
+
278
+ if (rwt / rt < this.mrr) return null;
279
+
280
+ // Partial targets
281
+ let p1, p2;
282
+ if (dir === 'long') {
283
+ p1 = ep + pm.p1t * this.ts;
284
+ p2 = ep + pm.p2t * this.ts;
285
+ } else {
286
+ p1 = ep - pm.p1t * this.ts;
287
+ p2 = ep - pm.p2t * this.ts;
288
+ }
289
+
290
+ // Signal strength
291
+ let str = SS.M;
292
+ if (cf >= 0.75) str = SS.S;
293
+ else if (cf >= 0.85) str = SS.VS;
294
+ else if (cf < 0.55) str = SS.W;
295
+
296
+ // Edge calculation
297
+ const wp = 0.5 + (cf - 0.5) * 0.3;
298
+ const aw = Math.abs(tp - ep);
299
+ const al = Math.abs(ep - sl);
300
+ const eg = wp * aw - (1 - wp) * al;
301
+
302
+ this.lst = Date.now();
303
+ this.st.s++;
304
+
305
+ const sig = {
306
+ id: uuidv4(),
307
+ timestamp: Date.now(),
308
+ symbol: c.split('.')[0] || c,
309
+ contractId: c,
310
+ side: dir === 'long' ? OS.B : OS.A,
311
+ direction: dir,
312
+ strategy: 'ULTRA_SCALPING_VWAP_REVERSION',
313
+ strength: str,
314
+ edge: eg,
315
+ confidence: cf,
316
+ entry: ep,
317
+ entryPrice: ep,
318
+ stopLoss: sl,
319
+ takeProfit: tp,
320
+ riskReward: rwt / rt,
321
+ stopTicks: spt,
322
+ targetTicks: tgt,
323
+ trailTriggerTicks: pm.ttt,
324
+ trailDistanceTicks: pm.tdt,
325
+ partial1Price: p1,
326
+ partial2Price: p2,
327
+ vwapScore: vs,
328
+ orderFlowScore: os,
329
+ domScore: ds,
330
+ microstructureScore: ms,
331
+ volumeProfileScore: ps,
332
+ orderFlowConfirmed: ofc,
333
+ zScore: va.deviation,
334
+ vwap: va.vwap,
335
+ regime: pm.rg,
336
+ expires: Date.now() + 60000
337
+ };
338
+
339
+ this.emit('signal', sig);
340
+ return sig;
341
+ }
342
+
343
+ recordTradeResult(p) {
344
+ this.rt.push({ netPnl: p, timestamp: Date.now() });
345
+ if (this.rt.length > 100) this.rt.shift();
346
+ if (p > 0) { this.ws++; this.ls = 0; this.st.w++; }
347
+ else { this.ls++; this.ws = 0; this.st.l++; }
348
+ this.st.p += p;
349
+ this.st.t++;
350
+ }
351
+
352
+ // Score VWAP
353
+ sv(v, cp) {
354
+ const z = Math.abs(v.deviation);
355
+ if (z < 0.5) return 0.3;
356
+ else if (z < 1.0) return 0.6;
357
+ else if (z < 2.0) return 0.9;
358
+ else if (z < 2.5) return 0.7;
359
+ else return 0.4;
360
+ }
361
+
362
+ // Score Order Flow
363
+ sof(o) {
364
+ let s = 0.5;
365
+ s += o.ir * 0.3;
366
+ if (o.dd) s += 0.2;
367
+ if (o.ad) s += 0.15;
368
+ return Math.min(1.0, s);
369
+ }
370
+
371
+ // Score DOM
372
+ sdd(d) {
373
+ let s = 0.5;
374
+ s += Math.abs(d.pi) * 0.25;
375
+ if (d.sb || d.sa) s += 0.15;
376
+ if (d.al !== null) s += 0.1;
377
+ return Math.min(1.0, s);
378
+ }
379
+
380
+ // Score Microstructure
381
+ sm(m) {
382
+ const ns = 1.0 - m.nr;
383
+ const ls = 0.0001 < m.kl && m.kl < 0.001 ? 0.7 : 0.5;
384
+ return ns * 0.6 + ls * 0.4;
385
+ }
386
+
387
+ // Score Volume Profile
388
+ svp(p, cp) {
389
+ let s = 0.5;
390
+ const pd = Math.abs(cp - p.poc) / this.ts;
391
+ if (pd < 10) s += 0.2;
392
+ if (p.val <= cp && cp <= p.vah) s += 0.15;
393
+ for (const h of p.hvn) {
394
+ if (Math.abs(cp - h) < 5 * this.ts) { s += 0.15; break; }
395
+ }
396
+ return Math.min(1.0, s);
397
+ }
398
+
399
+ // Analyze Order Flow
400
+ aof(bs) {
401
+ if (bs.length < 2) return { d: 0, cd: 0, dd: false, ad: false, ir: 0, as: 'neutral' };
402
+
403
+ const cb = bs[bs.length - 1];
404
+ const pb = bs[bs.length - 2];
405
+ const br = cb.high - cb.low;
406
+
407
+ let bv, sv;
408
+ if (br > 0) {
409
+ const cp = (cb.close - cb.low) / br;
410
+ bv = cb.volume * cp;
411
+ sv = cb.volume * (1 - cp);
412
+ } else {
413
+ bv = cb.volume * 0.5;
414
+ sv = cb.volume * 0.5;
415
+ }
416
+
417
+ const d = bv - sv;
418
+ const cd = cb.delta || d;
419
+
420
+ // Detect divergence
421
+ let dv = false;
422
+ if (bs.length >= 5) {
423
+ const rb = bs.slice(-5);
424
+ const pc = rb[4].close - rb[0].close;
425
+ const ds = rb.reduce((s, b) => s + (b.delta || 0), 0);
426
+ if ((pc > 0 && ds < -cb.volume * 0.5) || (pc < 0 && ds > cb.volume * 0.5)) dv = true;
427
+ }
428
+
429
+ // Detect absorption
430
+ const lb = Math.min(20, bs.length);
431
+ const rbs = bs.slice(-lb);
432
+ const ar = rbs.reduce((s, b) => s + (b.high - b.low), 0) / lb;
433
+ const av = rbs.reduce((s, b) => s + b.volume, 0) / lb;
434
+ const ab = cb.volume > av * 1.5 && br < ar * 0.6;
435
+
436
+ const tv = bv + sv;
437
+ const im = tv > 0 ? Math.abs(bv - sv) / tv : 0;
438
+
439
+ let ag;
440
+ if (bv > sv * 1.3) ag = 'buy';
441
+ else if (sv > bv * 1.3) ag = 'sell';
442
+ else ag = 'neutral';
443
+
444
+ return { d, cd, dd: dv, ad: ab, ir: im, as: ag };
445
+ }
446
+
447
+ // Analyze DOM from bars
448
+ adb(bs) {
449
+ const lb = Math.min(10, bs.length);
450
+ if (lb < 2) return { bp: 0.5, ap: 0.5, pi: 0, sb: false, sa: false, al: null };
451
+
452
+ const rbs = bs.slice(-lb);
453
+ let bss = [], ass = [];
454
+
455
+ for (const b of rbs) {
456
+ const br = b.high - b.low;
457
+ if (br > 0) {
458
+ const cp = (b.close - b.low) / br;
459
+ bss.push(cp * b.volume);
460
+ ass.push((1 - cp) * b.volume);
461
+ }
462
+ }
463
+
464
+ const t = bss.reduce((a, b) => a + b, 0) + ass.reduce((a, b) => a + b, 0);
465
+ const bp = t > 0 ? bss.reduce((a, b) => a + b, 0) / t : 0.5;
466
+ const ap = t > 0 ? ass.reduce((a, b) => a + b, 0) / t : 0.5;
467
+ const pi = bp - ap;
468
+
469
+ const lf = rbs.slice(-5);
470
+ let hc = 0, lc = 0;
471
+ for (const b of lf) {
472
+ const br = b.high - b.low;
473
+ if (br > 0) {
474
+ const cp = (b.close - b.low) / br;
475
+ if (cp > 0.7) hc++;
476
+ if (cp < 0.3) lc++;
477
+ }
478
+ }
479
+
480
+ let al = null;
481
+ const ar = rbs.reduce((s, b) => s + (b.high - b.low), 0) / lb;
482
+ const av = rbs.reduce((s, b) => s + b.volume, 0) / lb;
483
+ for (const b of rbs) {
484
+ const br = b.high - b.low;
485
+ if (b.volume > av * 1.5 && br < ar * 0.5) {
486
+ al = (b.high + b.low) / 2;
487
+ break;
488
+ }
489
+ }
490
+
491
+ return { bp, ap, pi, sb: hc >= 3, sa: lc >= 3, al };
492
+ }
493
+
494
+ // Analyze Microstructure
495
+ am(bs) {
496
+ const lb = Math.min(50, bs.length);
497
+ if (lb < 10) return { kl: 0, rs: 0, es: 0, rv: 0, nr: 0.5 };
498
+
499
+ const rbs = bs.slice(-lb);
500
+ const pc = [], vs = [];
501
+
502
+ for (let i = 1; i < rbs.length; i++) {
503
+ pc.push(rbs[i].close - rbs[i - 1].close);
504
+ vs.push(rbs[i].volume);
505
+ }
506
+
507
+ // Kyle's Lambda
508
+ let kl = 0;
509
+ if (pc.length > 5) {
510
+ const mp = pc.reduce((a, b) => a + b, 0) / pc.length;
511
+ const mv = vs.reduce((a, b) => a + b, 0) / vs.length;
512
+ let cv = 0, vv = 0;
513
+ for (let i = 0; i < pc.length; i++) {
514
+ cv += (pc[i] - mp) * (vs[i] - mv);
515
+ vv += Math.pow(vs[i] - mv, 2);
516
+ }
517
+ cv /= pc.length;
518
+ vv /= pc.length;
519
+ kl = vv > 0 ? Math.abs(cv / vv) : 0;
520
+ }
521
+
522
+ // Roll's Spread
523
+ let rs = 0;
524
+ if (pc.length > 2) {
525
+ const c1 = pc.slice(1), c0 = pc.slice(0, -1);
526
+ const m1 = c1.reduce((a, b) => a + b, 0) / c1.length;
527
+ const m0 = c0.reduce((a, b) => a + b, 0) / c0.length;
528
+ let ac = 0;
529
+ for (let i = 0; i < c1.length; i++) ac += (c1[i] - m1) * (c0[i] - m0);
530
+ ac /= c1.length;
531
+ rs = Math.sqrt(Math.max(0, -ac)) * 2;
532
+ }
533
+
534
+ const es = rbs.reduce((s, b) => s + (b.high - b.low), 0) / lb;
535
+
536
+ // Realized volatility
537
+ const rt = [];
538
+ for (let i = 1; i < rbs.length; i++) {
539
+ if (rbs[i - 1].close > 0) rt.push(Math.log(rbs[i].close / rbs[i - 1].close));
540
+ }
541
+ let rv = 0;
542
+ if (rt.length > 0) {
543
+ const mr = rt.reduce((a, b) => a + b, 0) / rt.length;
544
+ const va = rt.reduce((s, r) => s + Math.pow(r - mr, 2), 0) / rt.length;
545
+ rv = Math.sqrt(va) * Math.sqrt(252 * 390);
546
+ }
547
+
548
+ // Noise ratio
549
+ const sv = pc.length >= 10 ? Math.sqrt(pc.slice(-10).reduce((s, p) => s + p * p, 0) / 10) : 0;
550
+ const lv = pc.length > 0 ? Math.sqrt(pc.reduce((s, p) => s + p * p, 0) / pc.length) : 1;
551
+ const nr = lv > 0 ? Math.min(1, sv / lv) : 0.5;
552
+
553
+ return { kl, rs, es, rv, nr };
554
+ }
555
+
556
+ // Analyze Volume Profile
557
+ avp(bs, c, cp) {
558
+ const lb = Math.min(100, bs.length);
559
+ if (lb < 10) return { poc: cp, vah: cp, val: cp, hvn: [], lvn: [] };
560
+
561
+ const rbs = bs.slice(-lb);
562
+ const vap = new Map();
563
+
564
+ for (const b of rbs) {
565
+ const br = b.high - b.low;
566
+ const nl = Math.max(1, Math.round(br / this.ts));
567
+ const vpl = b.volume / nl;
568
+ let p = b.low;
569
+ while (p <= b.high) {
570
+ const r = Math.round(p / this.ts) * this.ts;
571
+ vap.set(r, (vap.get(r) || 0) + vpl);
572
+ p += this.ts;
573
+ }
574
+ }
575
+
576
+ if (vap.size === 0) return { poc: cp, vah: cp, val: cp, hvn: [], lvn: [] };
577
+
578
+ // POC
579
+ let poc = cp, mv = 0;
580
+ for (const [p, v] of vap) {
581
+ if (v > mv) { mv = v; poc = p; }
582
+ }
583
+
584
+ // Value Area
585
+ const tv = Array.from(vap.values()).reduce((a, b) => a + b, 0);
586
+ const tgv = tv * 0.7;
587
+ const sp = Array.from(vap.keys()).sort((a, b) => a - b);
588
+ const pi = sp.indexOf(poc);
589
+ let vv = vap.get(poc) || 0, li = pi, hi = pi;
590
+
591
+ while (vv < tgv && (li > 0 || hi < sp.length - 1)) {
592
+ const lv = li > 0 ? (vap.get(sp[li - 1]) || 0) : 0;
593
+ const hv = hi < sp.length - 1 ? (vap.get(sp[hi + 1]) || 0) : 0;
594
+ if (lv >= hv && li > 0) { li--; vv += vap.get(sp[li]) || 0; }
595
+ else if (hi < sp.length - 1) { hi++; vv += vap.get(sp[hi]) || 0; }
596
+ else break;
597
+ }
598
+
599
+ const val = sp[li], vah = sp[hi];
600
+ const av = tv / vap.size;
601
+ const hvn = [], lvn = [];
602
+
603
+ for (const [p, v] of vap) {
604
+ if (v > av * 1.5) hvn.push(p);
605
+ if (v < av * 0.5) lvn.push(p);
606
+ }
607
+
608
+ return { poc, vah, val, hvn, lvn };
609
+ }
610
+
611
+ // Determine Direction
612
+ dd(v, o, d, p, cp) {
613
+ let ls = 0, ss = 0, st = 'mixed', ofc = false;
614
+
615
+ // VWAP Mean Reversion (0.8 std dev)
616
+ if (v.deviation < -0.8) {
617
+ ls += 2;
618
+ st = 'vr';
619
+ if (o.as === 'buy' || o.dd) ofc = true;
620
+ } else if (v.deviation > 0.8) {
621
+ ss += 2;
622
+ st = 'vr';
623
+ if (o.as === 'sell' || o.dd) ofc = true;
624
+ }
625
+
626
+ // Order flow strength
627
+ if (o.as === 'buy' && o.ir > 0.35) ls += 1;
628
+ else if (o.as === 'sell' && o.ir > 0.35) ss += 1;
629
+
630
+ // Delta Divergence
631
+ if (o.dd) {
632
+ if (o.cd < 0) { ls += 2; st = 'dv'; ofc = true; }
633
+ else { ss += 2; st = 'dv'; ofc = true; }
634
+ }
635
+
636
+ // DOM Pressure
637
+ if (d.pi > 0.35) ls += 1;
638
+ else if (d.pi < -0.35) ss += 1;
639
+
640
+ // Stacked Orders
641
+ if (d.sb) ls += 1;
642
+ if (d.sa) ss += 1;
643
+
644
+ // Volume Profile (POC attraction)
645
+ if (cp < p.poc - 5 * this.ts) ls += 1;
646
+ else if (cp > p.poc + 5 * this.ts) ss += 1;
647
+
648
+ // Decision
649
+ if (ls >= 2 && ls > ss) return { dir: 'long', st, ofc };
650
+ else if (ss >= 2 && ss > ls) return { dir: 'short', st, ofc };
651
+ else return { dir: 'none', st: 'none', ofc: false };
652
+ }
653
+
654
+ // Calculate ATR
655
+ catr(bs) {
656
+ if (bs.length < this.ap + 1) return this.ba;
657
+
658
+ const tv = [];
659
+ for (let i = bs.length - this.ap; i < bs.length; i++) {
660
+ const b = bs[i];
661
+ const pc = bs[i - 1].close;
662
+ const tr = Math.max(b.high - b.low, Math.abs(b.high - pc), Math.abs(b.low - pc));
663
+ tv.push(tr);
664
+ }
665
+
666
+ const a = tv.reduce((a, b) => a + b, 0) / tv.length;
667
+ this.ah.push(a);
668
+ if (this.ah.length > 500) this.ah.shift();
669
+
670
+ return a;
671
+ }
672
+
673
+ // Get Adaptive Params
674
+ gap(bs) {
675
+ const a = this.catr(bs);
676
+ const at = a / this.ts;
677
+
678
+ let ap = 0.5;
679
+ if (this.ah.length >= 20) ap = this.ah.filter(x => x <= a).length / this.ah.length;
680
+
681
+ let rg, vm;
682
+ if (ap < 0.25) { rg = 'low'; vm = 0.9; }
683
+ else if (ap < 0.70) { rg = 'normal'; vm = 1.0; }
684
+ else if (ap < 0.90) { rg = 'high'; vm = 1.15; }
685
+ else { rg = 'extreme'; vm = 1.25; }
686
+
687
+ const pm = this.gpm();
688
+
689
+ // Stop: 6 ticks base, scale 5-8
690
+ const bs6 = 6;
691
+ let spt = Math.round(bs6 * vm);
692
+ spt = Math.max(5, Math.min(8, spt));
693
+
694
+ // Target: 8 ticks base, scale 6-10
695
+ const bt8 = 8;
696
+ let tgt = Math.round(bt8 * vm);
697
+ tgt = Math.max(6, Math.min(10, tgt));
698
+
699
+ if (tgt / spt < 1.2) tgt = Math.round(spt * 1.33);
700
+
701
+ // Trailing
702
+ const ttt = Math.max(3, Math.min(5, Math.round(tgt * 0.5)));
703
+ const tdt = Math.max(2, Math.min(3, Math.round(spt * 0.35)));
704
+
705
+ // Confidence threshold
706
+ const bc = 0.45;
707
+ const ra = { low: 0.05, normal: 0.0, high: 0.03, extreme: 0.10 };
708
+ let ct = bc + ra[rg];
709
+ ct = Math.min(0.65, ct * pm);
710
+
711
+ // Partials
712
+ const p1t = Math.round(tgt * 0.5);
713
+ const p2t = Math.round(tgt * 0.75);
714
+
715
+ return { spt, tgt, ct, ttt, tdt, p1t, p2t, rg, at, vm };
716
+ }
717
+
718
+ // Performance Multiplier
719
+ gpm() {
720
+ if (this.rt.length === 0) return 1.0;
721
+
722
+ const r = this.rt.slice(-20);
723
+ const w = r.filter(t => t.netPnl > 0).length;
724
+ const wr = w / r.length;
725
+
726
+ let m = 1.0;
727
+
728
+ if (this.ls >= 2) {
729
+ m += 0.05 * this.ls;
730
+ m = Math.min(m, 1.3);
731
+ }
732
+
733
+ if (r.length >= 5 && wr < 0.40) m *= 1.1;
734
+ if (this.ws >= 4 && wr > 0.50) m *= 0.95;
735
+
736
+ return Math.max(0.9, Math.min(1.3, m));
737
+ }
738
+
739
+ getBarHistory(c) { return this.bh.get(c) || []; }
740
+ reset(c) { this.bh.set(c, []); this.lsd = null; this.vc.reset(c); }
741
+ getStats() { return this.st; }
742
+
743
+ getAnalysisState(c, cp) {
744
+ const bs = this.bh.get(c) || [];
745
+ if (bs.length < 10) return { ready: false, message: 'Collecting...' };
746
+
747
+ const va = this.vc.an(c, cp, this.ts);
748
+ const of = this.aof(bs);
749
+ const pm = this.gap(bs);
750
+
751
+ return {
752
+ ready: true,
753
+ vwap: va?.vwap || 0,
754
+ zScore: va?.deviation || 0,
755
+ orderFlow: of.as,
756
+ ratio: of.ir,
757
+ regime: pm.rg,
758
+ stopTicks: pm.spt,
759
+ targetTicks: pm.tgt,
760
+ barsProcessed: bs.length
761
+ };
762
+ }
763
+ }
764
+
765
+ // =============================================================================
766
+ // M1 - STRATEGY WRAPPER
767
+ // =============================================================================
768
+
769
+ class M1 extends EventEmitter {
770
+ constructor(cfg = {}) {
771
+ super();
772
+ this.cfg = cfg;
773
+ this.s = new S1(cfg);
774
+ this.s.on('signal', (sig) => {
775
+ this.emit('signal', {
776
+ side: sig.direction === 'long' ? 'buy' : 'sell',
777
+ action: 'open',
778
+ reason: `Z=${sig.zScore.toFixed(2)}, cf=${(sig.confidence * 100).toFixed(0)}%`,
779
+ ...sig
780
+ });
781
+ });
782
+ }
783
+
784
+ processTick(t) { return this.s.processTick(t); }
785
+ onTick(t) { return this.processTick(t); }
786
+ processBar(c, b) { return this.s.processBar(c, b); }
787
+ onTrade(t) {
788
+ this.s.processTick({
789
+ contractId: t.contractId || t.symbol,
790
+ price: t.price,
791
+ volume: t.size || t.volume || 1,
792
+ side: t.side,
793
+ timestamp: t.timestamp || Date.now()
794
+ });
795
+ }
796
+ initialize(c, ts, tv) { this.s.initialize(c, ts, tv); }
797
+ getAnalysisState(c, p) { return this.s.getAnalysisState(c, p); }
798
+ recordTradeResult(p) { this.s.recordTradeResult(p); }
799
+ reset(c) { this.s.reset(c); this.emit('log', { type: 'info', message: 'Reset' }); }
800
+ getStats() { return this.s.getStats(); }
801
+ generateSignal(p) { return null; }
802
+ }
803
+
804
+ module.exports = { S1, M1, VC, OS, SS };