hedgequantx 2.4.7 → 2.4.8
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/package.json +3 -6
- package/src/lib/data.js +286 -0
- package/src/lib/m/s1.js +521 -0
- package/src/pages/algo/one-account.js +3 -3
- package/dist/lib/api.js +0 -1
- package/dist/lib/api.jsc +0 -0
- package/dist/lib/api2.js +0 -1
- package/dist/lib/api2.jsc +0 -0
- package/dist/lib/core.js +0 -1
- package/dist/lib/core.jsc +0 -0
- package/dist/lib/core2.js +0 -1
- package/dist/lib/core2.jsc +0 -0
- package/dist/lib/data.js +0 -1
- package/dist/lib/data.jsc +0 -0
- package/dist/lib/data2.js +0 -1
- package/dist/lib/data2.jsc +0 -0
- package/dist/lib/decoder.js +0 -1
- package/dist/lib/decoder.jsc +0 -0
- package/dist/lib/m/mod1.js +0 -1
- package/dist/lib/m/mod1.jsc +0 -0
- package/dist/lib/m/mod2.js +0 -1
- package/dist/lib/m/mod2.jsc +0 -0
- package/dist/lib/n/r1.js +0 -1
- package/dist/lib/n/r1.jsc +0 -0
- package/dist/lib/n/r2.js +0 -1
- package/dist/lib/n/r2.jsc +0 -0
- package/dist/lib/n/r3.js +0 -1
- package/dist/lib/n/r3.jsc +0 -0
- package/dist/lib/n/r4.js +0 -1
- package/dist/lib/n/r4.jsc +0 -0
- package/dist/lib/n/r5.js +0 -1
- package/dist/lib/n/r5.jsc +0 -0
- package/dist/lib/n/r6.js +0 -1
- package/dist/lib/n/r6.jsc +0 -0
- package/dist/lib/n/r7.js +0 -1
- package/dist/lib/n/r7.jsc +0 -0
- package/dist/lib/o/util1.js +0 -1
- package/dist/lib/o/util1.jsc +0 -0
- package/dist/lib/o/util2.js +0 -1
- package/dist/lib/o/util2.jsc +0 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "hedgequantx",
|
|
3
|
-
"version": "2.4.
|
|
3
|
+
"version": "2.4.8",
|
|
4
4
|
"description": "HedgeQuantX - Prop Futures Trading CLI",
|
|
5
5
|
"main": "src/app.js",
|
|
6
6
|
"bin": {
|
|
@@ -9,10 +9,7 @@
|
|
|
9
9
|
},
|
|
10
10
|
"scripts": {
|
|
11
11
|
"start": "node bin/cli.js",
|
|
12
|
-
"dev": "node bin/cli.js"
|
|
13
|
-
"build": "node scripts/build.js",
|
|
14
|
-
"publish:safe": "node scripts/publish.js",
|
|
15
|
-
"prepublishOnly": "npm run build"
|
|
12
|
+
"dev": "node bin/cli.js"
|
|
16
13
|
},
|
|
17
14
|
"keywords": [
|
|
18
15
|
"trading",
|
|
@@ -40,11 +37,11 @@
|
|
|
40
37
|
},
|
|
41
38
|
"files": [
|
|
42
39
|
"bin/",
|
|
43
|
-
"dist/lib/",
|
|
44
40
|
"protos/",
|
|
45
41
|
"src/app.js",
|
|
46
42
|
"src/api/",
|
|
47
43
|
"src/config/",
|
|
44
|
+
"src/lib/",
|
|
48
45
|
"src/menus/",
|
|
49
46
|
"src/pages/",
|
|
50
47
|
"src/security/",
|
package/src/lib/data.js
ADDED
|
@@ -0,0 +1,286 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* =============================================================================
|
|
3
|
+
* MARKET DATA FEED - SignalR Real-Time Data
|
|
4
|
+
* =============================================================================
|
|
5
|
+
* Connects to ProjectX Gateway RTC for real-time market data
|
|
6
|
+
*
|
|
7
|
+
* Events emitted:
|
|
8
|
+
* - tick: Quote/trade updates (price, bid, ask, volume)
|
|
9
|
+
* - quote: Quote updates only
|
|
10
|
+
* - trade: Trade executions only
|
|
11
|
+
* - depth: DOM/Level 2 updates
|
|
12
|
+
* - connected: Connection established
|
|
13
|
+
* - disconnected: Connection lost
|
|
14
|
+
* - error: Connection error
|
|
15
|
+
*
|
|
16
|
+
* SOURCE: Based on ProjectX Gateway RTC API
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
'use strict';
|
|
20
|
+
|
|
21
|
+
const EventEmitter = require('events');
|
|
22
|
+
const { HubConnectionBuilder, HttpTransportType, LogLevel } = require('@microsoft/signalr');
|
|
23
|
+
|
|
24
|
+
// Inline PROPFIRMS config for RTC URLs (standalone module)
|
|
25
|
+
const PROPFIRMS = {
|
|
26
|
+
topstep: { gatewayApi: 'api.topstepx.com' },
|
|
27
|
+
alpha_futures: { gatewayApi: 'api.alphafutures.projectx.com' },
|
|
28
|
+
tickticktrader: { gatewayApi: 'api.tickticktrader.projectx.com' },
|
|
29
|
+
bulenox: { gatewayApi: 'api.bulenox.projectx.com' },
|
|
30
|
+
tradeday: { gatewayApi: 'api.tradeday.projectx.com' },
|
|
31
|
+
blusky: { gatewayApi: 'api.blusky.projectx.com' },
|
|
32
|
+
goat_futures: { gatewayApi: 'api.goatfutures.projectx.com' },
|
|
33
|
+
futures_desk: { gatewayApi: 'api.thefuturesdesk.projectx.com' },
|
|
34
|
+
daytraders: { gatewayApi: 'api.daytraders.projectx.com' },
|
|
35
|
+
e8_futures: { gatewayApi: 'api.e8futures.projectx.com' },
|
|
36
|
+
blue_guardian: { gatewayApi: 'api.blueguardianfutures.projectx.com' },
|
|
37
|
+
futures_elite: { gatewayApi: 'api.futureselite.projectx.com' },
|
|
38
|
+
fxify: { gatewayApi: 'api.fxify.projectx.com' },
|
|
39
|
+
hola_prime: { gatewayApi: 'api.holaprime.projectx.com' },
|
|
40
|
+
top_one_futures: { gatewayApi: 'api.toponefutures.projectx.com' },
|
|
41
|
+
funding_futures: { gatewayApi: 'api.fundingfutures.projectx.com' },
|
|
42
|
+
tx3_funding: { gatewayApi: 'api.tx3funding.projectx.com' },
|
|
43
|
+
lucid_trading: { gatewayApi: 'api.lucidtrading.projectx.com' },
|
|
44
|
+
tradeify: { gatewayApi: 'api.tradeify.projectx.com' }
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
// =============================================================================
|
|
48
|
+
// MARKET DATA FEED CLASS
|
|
49
|
+
// =============================================================================
|
|
50
|
+
|
|
51
|
+
class MarketDataFeed extends EventEmitter {
|
|
52
|
+
constructor(options = {}) {
|
|
53
|
+
super();
|
|
54
|
+
|
|
55
|
+
this.propfirmKey = (options.propfirm || 'topstep').toLowerCase().replace(/\s+/g, '_');
|
|
56
|
+
this.connection = null;
|
|
57
|
+
this.connected = false;
|
|
58
|
+
this.subscriptions = new Set();
|
|
59
|
+
this.reconnectAttempts = 0;
|
|
60
|
+
this.maxReconnectAttempts = 5;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Get market hub URL for propfirm
|
|
65
|
+
*/
|
|
66
|
+
_getMarketHubUrl(propfirmKey) {
|
|
67
|
+
const propfirm = PROPFIRMS[propfirmKey] || PROPFIRMS.topstep;
|
|
68
|
+
|
|
69
|
+
if (propfirm.rtcApi) {
|
|
70
|
+
return `https://${propfirm.rtcApi}/hubs/market`;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
if (propfirm.gatewayApi) {
|
|
74
|
+
const rtcHost = propfirm.gatewayApi.replace('gateway-api', 'gateway-rtc');
|
|
75
|
+
return `https://${rtcHost}/hubs/market`;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
return 'https://gateway-rtc-demo.s2f.projectx.com/hubs/market';
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Connect to market data hub
|
|
83
|
+
*/
|
|
84
|
+
async connect(token, propfirmKey, contractId = null) {
|
|
85
|
+
if (this.connected) return;
|
|
86
|
+
|
|
87
|
+
this.propfirmKey = propfirmKey || this.propfirmKey;
|
|
88
|
+
const hubUrl = this._getMarketHubUrl(this.propfirmKey);
|
|
89
|
+
|
|
90
|
+
try {
|
|
91
|
+
this.connection = new HubConnectionBuilder()
|
|
92
|
+
.withUrl(hubUrl, {
|
|
93
|
+
skipNegotiation: true,
|
|
94
|
+
transport: HttpTransportType.WebSockets,
|
|
95
|
+
accessTokenFactory: () => token,
|
|
96
|
+
timeout: 30000,
|
|
97
|
+
})
|
|
98
|
+
.withAutomaticReconnect({
|
|
99
|
+
nextRetryDelayInMilliseconds: (ctx) => {
|
|
100
|
+
if (ctx.previousRetryCount >= this.maxReconnectAttempts) return null;
|
|
101
|
+
return Math.min(1000 * Math.pow(2, ctx.previousRetryCount), 30000);
|
|
102
|
+
}
|
|
103
|
+
})
|
|
104
|
+
.configureLogging(LogLevel.Warning)
|
|
105
|
+
.build();
|
|
106
|
+
|
|
107
|
+
this._setupEventHandlers();
|
|
108
|
+
await this.connection.start();
|
|
109
|
+
|
|
110
|
+
this.connected = true;
|
|
111
|
+
this.reconnectAttempts = 0;
|
|
112
|
+
this.emit('connected');
|
|
113
|
+
|
|
114
|
+
if (contractId) {
|
|
115
|
+
await this.subscribe(null, contractId);
|
|
116
|
+
}
|
|
117
|
+
} catch (error) {
|
|
118
|
+
this.emit('error', error);
|
|
119
|
+
throw error;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Setup SignalR event handlers
|
|
125
|
+
*/
|
|
126
|
+
_setupEventHandlers() {
|
|
127
|
+
if (!this.connection) return;
|
|
128
|
+
|
|
129
|
+
// Quote updates
|
|
130
|
+
this.connection.on('GatewayQuote', (quote) => {
|
|
131
|
+
const tick = {
|
|
132
|
+
type: 'quote',
|
|
133
|
+
contractId: quote.symbol || quote.symbolId,
|
|
134
|
+
symbol: quote.symbolName || quote.symbol,
|
|
135
|
+
price: quote.lastPrice,
|
|
136
|
+
bid: quote.bestBid,
|
|
137
|
+
ask: quote.bestAsk,
|
|
138
|
+
change: quote.change,
|
|
139
|
+
changePercent: quote.changePercent,
|
|
140
|
+
open: quote.open,
|
|
141
|
+
high: quote.high,
|
|
142
|
+
low: quote.low,
|
|
143
|
+
volume: quote.volume,
|
|
144
|
+
timestamp: quote.timestamp ? new Date(quote.timestamp).getTime() : Date.now()
|
|
145
|
+
};
|
|
146
|
+
this.emit('tick', tick);
|
|
147
|
+
this.emit('quote', tick);
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
// Trade executions
|
|
151
|
+
this.connection.on('GatewayTrade', (trade) => {
|
|
152
|
+
const tick = {
|
|
153
|
+
type: 'trade',
|
|
154
|
+
contractId: trade.symbolId,
|
|
155
|
+
price: trade.price,
|
|
156
|
+
volume: trade.volume,
|
|
157
|
+
side: trade.type === 0 ? 'buy' : 'sell',
|
|
158
|
+
lastTradeSide: trade.type === 0 ? 'buy' : 'sell',
|
|
159
|
+
timestamp: trade.timestamp ? new Date(trade.timestamp).getTime() : Date.now()
|
|
160
|
+
};
|
|
161
|
+
this.emit('tick', tick);
|
|
162
|
+
this.emit('trade', tick);
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
// DOM updates
|
|
166
|
+
this.connection.on('GatewayDepth', (depth) => {
|
|
167
|
+
const domUpdate = {
|
|
168
|
+
type: 'depth',
|
|
169
|
+
price: depth.price,
|
|
170
|
+
volume: depth.volume,
|
|
171
|
+
currentVolume: depth.currentVolume,
|
|
172
|
+
side: depth.type === 0 ? 'bid' : 'ask',
|
|
173
|
+
timestamp: depth.timestamp ? new Date(depth.timestamp).getTime() : Date.now()
|
|
174
|
+
};
|
|
175
|
+
this.emit('depth', domUpdate);
|
|
176
|
+
this.emit('dom', domUpdate);
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
// Connection state
|
|
180
|
+
this.connection.onreconnecting((error) => {
|
|
181
|
+
this.connected = false;
|
|
182
|
+
this.emit('reconnecting', error);
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
this.connection.onreconnected((connectionId) => {
|
|
186
|
+
this.connected = true;
|
|
187
|
+
this.reconnectAttempts = 0;
|
|
188
|
+
this.emit('reconnected', connectionId);
|
|
189
|
+
this._resubscribeAll();
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
this.connection.onclose((error) => {
|
|
193
|
+
this.connected = false;
|
|
194
|
+
this.emit('disconnected', error);
|
|
195
|
+
});
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/**
|
|
199
|
+
* Subscribe to contract market data
|
|
200
|
+
*/
|
|
201
|
+
async subscribe(symbol, contractId) {
|
|
202
|
+
if (!this.connection || !this.connected) {
|
|
203
|
+
throw new Error('Not connected');
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
const id = contractId || symbol;
|
|
207
|
+
|
|
208
|
+
try {
|
|
209
|
+
await this.connection.invoke('SubscribeContractQuotes', id);
|
|
210
|
+
await this.connection.invoke('SubscribeContractTrades', id);
|
|
211
|
+
await this.connection.invoke('SubscribeContractMarketDepth', id);
|
|
212
|
+
this.subscriptions.add(id);
|
|
213
|
+
this.emit('subscribed', { symbol, contractId: id });
|
|
214
|
+
} catch (error) {
|
|
215
|
+
this.emit('error', new Error(`Subscribe failed: ${error.message}`));
|
|
216
|
+
throw error;
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
/**
|
|
221
|
+
* Unsubscribe from contract
|
|
222
|
+
*/
|
|
223
|
+
async unsubscribe(contractId) {
|
|
224
|
+
if (!this.connection || !this.connected) return;
|
|
225
|
+
|
|
226
|
+
try {
|
|
227
|
+
await this.connection.invoke('UnsubscribeContractQuotes', contractId);
|
|
228
|
+
await this.connection.invoke('UnsubscribeContractTrades', contractId);
|
|
229
|
+
await this.connection.invoke('UnsubscribeContractMarketDepth', contractId);
|
|
230
|
+
this.subscriptions.delete(contractId);
|
|
231
|
+
this.emit('unsubscribed', { contractId });
|
|
232
|
+
} catch (error) {
|
|
233
|
+
// Silently handle
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
/**
|
|
238
|
+
* Resubscribe after reconnect
|
|
239
|
+
*/
|
|
240
|
+
async _resubscribeAll() {
|
|
241
|
+
for (const contractId of this.subscriptions) {
|
|
242
|
+
try {
|
|
243
|
+
await this.connection.invoke('SubscribeContractQuotes', contractId);
|
|
244
|
+
await this.connection.invoke('SubscribeContractTrades', contractId);
|
|
245
|
+
await this.connection.invoke('SubscribeContractMarketDepth', contractId);
|
|
246
|
+
} catch (error) {
|
|
247
|
+
// Continue
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
/**
|
|
253
|
+
* Disconnect
|
|
254
|
+
*/
|
|
255
|
+
async disconnect() {
|
|
256
|
+
if (this.connection) {
|
|
257
|
+
try {
|
|
258
|
+
for (const contractId of this.subscriptions) {
|
|
259
|
+
await this.unsubscribe(contractId);
|
|
260
|
+
}
|
|
261
|
+
await this.connection.stop();
|
|
262
|
+
} catch (error) {
|
|
263
|
+
// Ignore
|
|
264
|
+
}
|
|
265
|
+
this.connection = null;
|
|
266
|
+
this.connected = false;
|
|
267
|
+
this.subscriptions.clear();
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
/**
|
|
272
|
+
* Check connection status
|
|
273
|
+
*/
|
|
274
|
+
isConnected() {
|
|
275
|
+
return this.connected && this.connection?.state === 'Connected';
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
/**
|
|
279
|
+
* Get active subscriptions
|
|
280
|
+
*/
|
|
281
|
+
getSubscriptions() {
|
|
282
|
+
return Array.from(this.subscriptions);
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
module.exports = { MarketDataFeed };
|
package/src/lib/m/s1.js
ADDED
|
@@ -0,0 +1,521 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* =============================================================================
|
|
3
|
+
* HQX ULTRA SCALPING STRATEGY
|
|
4
|
+
* =============================================================================
|
|
5
|
+
* 6 Mathematical Models with 4-Layer Trailing Stop System
|
|
6
|
+
*
|
|
7
|
+
* BACKTEST RESULTS (162 tests, V4):
|
|
8
|
+
* - Net P&L: $195,272.52
|
|
9
|
+
* - Win Rate: 86.3%
|
|
10
|
+
* - Profit Factor: 34.44
|
|
11
|
+
* - Sharpe: 1.29
|
|
12
|
+
* - Tests Passed: 150/162 (92.6%)
|
|
13
|
+
*
|
|
14
|
+
* MATHEMATICAL MODELS:
|
|
15
|
+
* 1. Z-Score Mean Reversion (Entry: |Z| > threshold, Exit: |Z| < 0.5)
|
|
16
|
+
* 2. VPIN (Volume-Synchronized Probability of Informed Trading)
|
|
17
|
+
* 3. Kyle's Lambda (Price Impact / Liquidity Measurement)
|
|
18
|
+
* 4. Kalman Filter (Signal Extraction from Noise)
|
|
19
|
+
* 5. Volatility Regime Detection (Low/Normal/High adaptive)
|
|
20
|
+
* 6. Order Flow Imbalance (OFI) - Directional Bias Confirmation
|
|
21
|
+
*
|
|
22
|
+
* KEY PARAMETERS:
|
|
23
|
+
* - Stop: 8 ticks = $40
|
|
24
|
+
* - Target: 16 ticks = $80
|
|
25
|
+
* - R:R = 1:2
|
|
26
|
+
* - Trailing: 50% profit lock
|
|
27
|
+
*
|
|
28
|
+
* SOURCE: /root/HQX-Dev/hqx_tg/src/algo/strategy/hqx-ultra-scalping.strategy.ts
|
|
29
|
+
*/
|
|
30
|
+
|
|
31
|
+
'use strict';
|
|
32
|
+
|
|
33
|
+
const EventEmitter = require('events');
|
|
34
|
+
const { v4: uuidv4 } = require('uuid');
|
|
35
|
+
|
|
36
|
+
// =============================================================================
|
|
37
|
+
// CONSTANTS
|
|
38
|
+
// =============================================================================
|
|
39
|
+
|
|
40
|
+
const OrderSide = { BID: 'BID', ASK: 'ASK' };
|
|
41
|
+
const SignalStrength = { WEAK: 'WEAK', MODERATE: 'MODERATE', STRONG: 'STRONG', VERY_STRONG: 'VERY_STRONG' };
|
|
42
|
+
|
|
43
|
+
// =============================================================================
|
|
44
|
+
// HELPER: Extract base symbol from contractId
|
|
45
|
+
// =============================================================================
|
|
46
|
+
function extractBaseSymbol(contractId) {
|
|
47
|
+
// CON.F.US.ENQ.H25 -> NQ, CON.F.US.EP.H25 -> ES
|
|
48
|
+
const mapping = {
|
|
49
|
+
'ENQ': 'NQ', 'EP': 'ES', 'EMD': 'EMD', 'RTY': 'RTY',
|
|
50
|
+
'MNQ': 'MNQ', 'MES': 'MES', 'M2K': 'M2K', 'MYM': 'MYM',
|
|
51
|
+
'NKD': 'NKD', 'GC': 'GC', 'SI': 'SI', 'CL': 'CL', 'YM': 'YM'
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
if (!contractId) return 'UNKNOWN';
|
|
55
|
+
const parts = contractId.split('.');
|
|
56
|
+
if (parts.length >= 4) {
|
|
57
|
+
const symbol = parts[3];
|
|
58
|
+
return mapping[symbol] || symbol;
|
|
59
|
+
}
|
|
60
|
+
return contractId;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// =============================================================================
|
|
64
|
+
// HQX ULTRA SCALPING STRATEGY CLASS
|
|
65
|
+
// =============================================================================
|
|
66
|
+
|
|
67
|
+
class HQXUltraScalpingStrategy extends EventEmitter {
|
|
68
|
+
constructor() {
|
|
69
|
+
super();
|
|
70
|
+
|
|
71
|
+
this.tickSize = 0.25;
|
|
72
|
+
this.tickValue = 5.0;
|
|
73
|
+
|
|
74
|
+
// === Model Parameters (from V4 backtest) ===
|
|
75
|
+
this.zscoreEntryThreshold = 1.5; // Adaptive per regime
|
|
76
|
+
this.zscoreExitThreshold = 0.5;
|
|
77
|
+
this.vpinWindow = 50;
|
|
78
|
+
this.vpinToxicThreshold = 0.7;
|
|
79
|
+
this.kalmanProcessNoise = 0.01;
|
|
80
|
+
this.kalmanMeasurementNoise = 0.1;
|
|
81
|
+
this.volatilityLookback = 100;
|
|
82
|
+
this.ofiLookback = 20;
|
|
83
|
+
|
|
84
|
+
// === Trade Parameters (from V4 backtest) ===
|
|
85
|
+
this.baseStopTicks = 8; // $40
|
|
86
|
+
this.baseTargetTicks = 16; // $80
|
|
87
|
+
this.breakevenTicks = 4; // Move to BE at +4 ticks
|
|
88
|
+
this.profitLockPct = 0.5; // Lock 50% of profit
|
|
89
|
+
|
|
90
|
+
// === State Storage ===
|
|
91
|
+
this.barHistory = new Map();
|
|
92
|
+
this.kalmanStates = new Map();
|
|
93
|
+
this.priceBuffer = new Map();
|
|
94
|
+
this.volumeBuffer = new Map();
|
|
95
|
+
this.tradesBuffer = new Map();
|
|
96
|
+
this.atrHistory = new Map();
|
|
97
|
+
|
|
98
|
+
// === Tick aggregation ===
|
|
99
|
+
this.tickBuffer = new Map();
|
|
100
|
+
this.lastBarTime = new Map();
|
|
101
|
+
this.barIntervalMs = 5000; // 5-second bars
|
|
102
|
+
|
|
103
|
+
// === Performance Tracking ===
|
|
104
|
+
this.recentTrades = [];
|
|
105
|
+
this.winStreak = 0;
|
|
106
|
+
this.lossStreak = 0;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Initialize strategy for a contract
|
|
111
|
+
*/
|
|
112
|
+
initialize(contractId, tickSize = 0.25, tickValue = 5.0) {
|
|
113
|
+
this.tickSize = tickSize;
|
|
114
|
+
this.tickValue = tickValue;
|
|
115
|
+
this.barHistory.set(contractId, []);
|
|
116
|
+
this.priceBuffer.set(contractId, []);
|
|
117
|
+
this.volumeBuffer.set(contractId, []);
|
|
118
|
+
this.tradesBuffer.set(contractId, []);
|
|
119
|
+
this.atrHistory.set(contractId, []);
|
|
120
|
+
this.tickBuffer.set(contractId, []);
|
|
121
|
+
this.lastBarTime.set(contractId, 0);
|
|
122
|
+
this.kalmanStates.set(contractId, { estimate: 0, errorCovariance: 1.0 });
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Process a tick - aggregates into bars then runs strategy
|
|
127
|
+
*/
|
|
128
|
+
processTick(tick) {
|
|
129
|
+
const contractId = tick.contractId;
|
|
130
|
+
|
|
131
|
+
if (!this.barHistory.has(contractId)) {
|
|
132
|
+
this.initialize(contractId);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// Add tick to buffer
|
|
136
|
+
let ticks = this.tickBuffer.get(contractId);
|
|
137
|
+
ticks.push(tick);
|
|
138
|
+
|
|
139
|
+
// Check if we should form a new bar
|
|
140
|
+
const now = Date.now();
|
|
141
|
+
const lastBar = this.lastBarTime.get(contractId);
|
|
142
|
+
|
|
143
|
+
if (now - lastBar >= this.barIntervalMs && ticks.length > 0) {
|
|
144
|
+
const bar = this._aggregateTicksToBar(ticks, now);
|
|
145
|
+
this.tickBuffer.set(contractId, []);
|
|
146
|
+
this.lastBarTime.set(contractId, now);
|
|
147
|
+
|
|
148
|
+
if (bar) {
|
|
149
|
+
const signal = this.processBar(contractId, bar);
|
|
150
|
+
if (signal) {
|
|
151
|
+
this.emit('signal', signal);
|
|
152
|
+
return signal;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
return null;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* Aggregate ticks into a bar
|
|
161
|
+
*/
|
|
162
|
+
_aggregateTicksToBar(ticks, timestamp) {
|
|
163
|
+
if (ticks.length === 0) return null;
|
|
164
|
+
|
|
165
|
+
const prices = ticks.map(t => t.price).filter(p => p != null);
|
|
166
|
+
if (prices.length === 0) return null;
|
|
167
|
+
|
|
168
|
+
let buyVol = 0, sellVol = 0;
|
|
169
|
+
for (let i = 1; i < ticks.length; i++) {
|
|
170
|
+
const vol = ticks[i].volume || 1;
|
|
171
|
+
if (ticks[i].price > ticks[i-1].price) buyVol += vol;
|
|
172
|
+
else if (ticks[i].price < ticks[i-1].price) sellVol += vol;
|
|
173
|
+
else { buyVol += vol / 2; sellVol += vol / 2; }
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
return {
|
|
177
|
+
timestamp,
|
|
178
|
+
open: prices[0],
|
|
179
|
+
high: Math.max(...prices),
|
|
180
|
+
low: Math.min(...prices),
|
|
181
|
+
close: prices[prices.length - 1],
|
|
182
|
+
volume: ticks.reduce((sum, t) => sum + (t.volume || 1), 0),
|
|
183
|
+
delta: buyVol - sellVol,
|
|
184
|
+
tickCount: ticks.length
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
/**
|
|
189
|
+
* Process a new bar and potentially generate signal
|
|
190
|
+
*/
|
|
191
|
+
processBar(contractId, bar) {
|
|
192
|
+
let bars = this.barHistory.get(contractId);
|
|
193
|
+
if (!bars) {
|
|
194
|
+
this.initialize(contractId);
|
|
195
|
+
bars = this.barHistory.get(contractId);
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
bars.push(bar);
|
|
199
|
+
if (bars.length > 500) bars.shift();
|
|
200
|
+
|
|
201
|
+
// Update price buffer
|
|
202
|
+
const prices = this.priceBuffer.get(contractId);
|
|
203
|
+
prices.push(bar.close);
|
|
204
|
+
if (prices.length > 200) prices.shift();
|
|
205
|
+
|
|
206
|
+
// Update volume buffer
|
|
207
|
+
const volumes = this.volumeBuffer.get(contractId);
|
|
208
|
+
const barRange = bar.high - bar.low;
|
|
209
|
+
let buyVol = bar.volume * 0.5;
|
|
210
|
+
let sellVol = bar.volume * 0.5;
|
|
211
|
+
if (barRange > 0) {
|
|
212
|
+
const closePosition = (bar.close - bar.low) / barRange;
|
|
213
|
+
buyVol = bar.volume * closePosition;
|
|
214
|
+
sellVol = bar.volume * (1 - closePosition);
|
|
215
|
+
}
|
|
216
|
+
volumes.push({ buy: buyVol, sell: sellVol });
|
|
217
|
+
if (volumes.length > 100) volumes.shift();
|
|
218
|
+
|
|
219
|
+
// Need minimum data
|
|
220
|
+
if (bars.length < 50) return null;
|
|
221
|
+
|
|
222
|
+
// === 6 MODELS ===
|
|
223
|
+
const zscore = this._computeZScore(prices);
|
|
224
|
+
const vpin = this._computeVPIN(volumes);
|
|
225
|
+
const kyleLambda = this._computeKyleLambda(bars);
|
|
226
|
+
const kalmanEstimate = this._applyKalmanFilter(contractId, bar.close);
|
|
227
|
+
const { regime, params } = this._detectVolatilityRegime(contractId, bars);
|
|
228
|
+
const ofi = this._computeOrderFlowImbalance(bars);
|
|
229
|
+
|
|
230
|
+
// === SIGNAL GENERATION ===
|
|
231
|
+
return this._generateSignal(contractId, bar.close, zscore, vpin, kyleLambda, kalmanEstimate, regime, params, ofi, bars);
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
// ===========================================================================
|
|
235
|
+
// MODEL 1: Z-SCORE MEAN REVERSION
|
|
236
|
+
// ===========================================================================
|
|
237
|
+
_computeZScore(prices, window = 50) {
|
|
238
|
+
if (prices.length < window) return 0;
|
|
239
|
+
const recentPrices = prices.slice(-window);
|
|
240
|
+
const mean = recentPrices.reduce((a, b) => a + b, 0) / window;
|
|
241
|
+
const variance = recentPrices.reduce((sum, p) => sum + Math.pow(p - mean, 2), 0) / window;
|
|
242
|
+
const std = Math.sqrt(variance);
|
|
243
|
+
if (std < 0.0001) return 0;
|
|
244
|
+
return (prices[prices.length - 1] - mean) / std;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
// ===========================================================================
|
|
248
|
+
// MODEL 2: VPIN
|
|
249
|
+
// ===========================================================================
|
|
250
|
+
_computeVPIN(volumes) {
|
|
251
|
+
if (volumes.length < this.vpinWindow) return 0.5;
|
|
252
|
+
const recent = volumes.slice(-this.vpinWindow);
|
|
253
|
+
let totalBuy = 0, totalSell = 0;
|
|
254
|
+
for (const v of recent) { totalBuy += v.buy; totalSell += v.sell; }
|
|
255
|
+
const total = totalBuy + totalSell;
|
|
256
|
+
if (total < 1) return 0.5;
|
|
257
|
+
return Math.abs(totalBuy - totalSell) / total;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
// ===========================================================================
|
|
261
|
+
// MODEL 3: KYLE'S LAMBDA
|
|
262
|
+
// ===========================================================================
|
|
263
|
+
_computeKyleLambda(bars) {
|
|
264
|
+
if (bars.length < 20) return 0;
|
|
265
|
+
const recent = bars.slice(-20);
|
|
266
|
+
const priceChanges = [], vols = [];
|
|
267
|
+
for (let i = 1; i < recent.length; i++) {
|
|
268
|
+
priceChanges.push(recent[i].close - recent[i - 1].close);
|
|
269
|
+
vols.push(recent[i].volume);
|
|
270
|
+
}
|
|
271
|
+
const meanP = priceChanges.reduce((a, b) => a + b, 0) / priceChanges.length;
|
|
272
|
+
const meanV = vols.reduce((a, b) => a + b, 0) / vols.length;
|
|
273
|
+
let cov = 0, varV = 0;
|
|
274
|
+
for (let i = 0; i < priceChanges.length; i++) {
|
|
275
|
+
cov += (priceChanges[i] - meanP) * (vols[i] - meanV);
|
|
276
|
+
varV += Math.pow(vols[i] - meanV, 2);
|
|
277
|
+
}
|
|
278
|
+
cov /= priceChanges.length;
|
|
279
|
+
varV /= priceChanges.length;
|
|
280
|
+
if (varV < 0.0001) return 0;
|
|
281
|
+
return Math.abs(cov / varV);
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
// ===========================================================================
|
|
285
|
+
// MODEL 4: KALMAN FILTER
|
|
286
|
+
// ===========================================================================
|
|
287
|
+
_applyKalmanFilter(contractId, measurement) {
|
|
288
|
+
let state = this.kalmanStates.get(contractId);
|
|
289
|
+
if (!state) {
|
|
290
|
+
state = { estimate: measurement, errorCovariance: 1.0 };
|
|
291
|
+
this.kalmanStates.set(contractId, state);
|
|
292
|
+
return measurement;
|
|
293
|
+
}
|
|
294
|
+
const predictedEstimate = state.estimate;
|
|
295
|
+
const predictedCovariance = state.errorCovariance + this.kalmanProcessNoise;
|
|
296
|
+
const kalmanGain = predictedCovariance / (predictedCovariance + this.kalmanMeasurementNoise);
|
|
297
|
+
state.estimate = predictedEstimate + kalmanGain * (measurement - predictedEstimate);
|
|
298
|
+
state.errorCovariance = (1 - kalmanGain) * predictedCovariance;
|
|
299
|
+
return state.estimate;
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
// ===========================================================================
|
|
303
|
+
// MODEL 5: VOLATILITY REGIME
|
|
304
|
+
// ===========================================================================
|
|
305
|
+
_detectVolatilityRegime(contractId, bars) {
|
|
306
|
+
const atr = this._calculateATR(bars);
|
|
307
|
+
let atrHist = this.atrHistory.get(contractId);
|
|
308
|
+
if (!atrHist) { atrHist = []; this.atrHistory.set(contractId, atrHist); }
|
|
309
|
+
atrHist.push(atr);
|
|
310
|
+
if (atrHist.length > 500) atrHist.shift();
|
|
311
|
+
|
|
312
|
+
let atrPercentile = 0.5;
|
|
313
|
+
if (atrHist.length >= 20) {
|
|
314
|
+
atrPercentile = atrHist.filter(a => a <= atr).length / atrHist.length;
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
let regime, params;
|
|
318
|
+
if (atrPercentile < 0.25) {
|
|
319
|
+
regime = 'low';
|
|
320
|
+
params = { stopMultiplier: 0.8, targetMultiplier: 0.9, zscoreThreshold: 1.2, confidenceBonus: 0.05 };
|
|
321
|
+
} else if (atrPercentile < 0.75) {
|
|
322
|
+
regime = 'normal';
|
|
323
|
+
params = { stopMultiplier: 1.0, targetMultiplier: 1.0, zscoreThreshold: 1.5, confidenceBonus: 0.0 };
|
|
324
|
+
} else {
|
|
325
|
+
regime = 'high';
|
|
326
|
+
params = { stopMultiplier: 1.3, targetMultiplier: 1.2, zscoreThreshold: 2.0, confidenceBonus: -0.05 };
|
|
327
|
+
}
|
|
328
|
+
return { regime, params };
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
_calculateATR(bars, period = 14) {
|
|
332
|
+
if (bars.length < period + 1) return 2.5;
|
|
333
|
+
const trValues = [];
|
|
334
|
+
for (let i = bars.length - period; i < bars.length; i++) {
|
|
335
|
+
const bar = bars[i];
|
|
336
|
+
const prevClose = bars[i - 1].close;
|
|
337
|
+
const tr = Math.max(bar.high - bar.low, Math.abs(bar.high - prevClose), Math.abs(bar.low - prevClose));
|
|
338
|
+
trValues.push(tr);
|
|
339
|
+
}
|
|
340
|
+
return trValues.reduce((a, b) => a + b, 0) / trValues.length;
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
// ===========================================================================
|
|
344
|
+
// MODEL 6: ORDER FLOW IMBALANCE
|
|
345
|
+
// ===========================================================================
|
|
346
|
+
_computeOrderFlowImbalance(bars) {
|
|
347
|
+
if (bars.length < this.ofiLookback) return 0;
|
|
348
|
+
const recent = bars.slice(-this.ofiLookback);
|
|
349
|
+
let buyPressure = 0, sellPressure = 0;
|
|
350
|
+
for (const bar of recent) {
|
|
351
|
+
const range = bar.high - bar.low;
|
|
352
|
+
if (range > 0) {
|
|
353
|
+
const closePos = (bar.close - bar.low) / range;
|
|
354
|
+
buyPressure += closePos * bar.volume;
|
|
355
|
+
sellPressure += (1 - closePos) * bar.volume;
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
const total = buyPressure + sellPressure;
|
|
359
|
+
if (total < 1) return 0;
|
|
360
|
+
return (buyPressure - sellPressure) / total;
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
// ===========================================================================
|
|
364
|
+
// SIGNAL GENERATION
|
|
365
|
+
// ===========================================================================
|
|
366
|
+
_generateSignal(contractId, currentPrice, zscore, vpin, kyleLambda, kalmanEstimate, regime, volParams, ofi, bars) {
|
|
367
|
+
const absZscore = Math.abs(zscore);
|
|
368
|
+
if (absZscore < volParams.zscoreThreshold) return null;
|
|
369
|
+
if (vpin > this.vpinToxicThreshold) return null;
|
|
370
|
+
|
|
371
|
+
let direction;
|
|
372
|
+
if (zscore < -volParams.zscoreThreshold) direction = 'long';
|
|
373
|
+
else if (zscore > volParams.zscoreThreshold) direction = 'short';
|
|
374
|
+
else return null;
|
|
375
|
+
|
|
376
|
+
const ofiConfirms = (direction === 'long' && ofi > 0.1) || (direction === 'short' && ofi < -0.1);
|
|
377
|
+
const kalmanDiff = currentPrice - kalmanEstimate;
|
|
378
|
+
const kalmanConfirms = (direction === 'long' && kalmanDiff < 0) || (direction === 'short' && kalmanDiff > 0);
|
|
379
|
+
|
|
380
|
+
const scores = {
|
|
381
|
+
zscore: Math.min(1.0, absZscore / 4.0),
|
|
382
|
+
vpin: 1.0 - vpin,
|
|
383
|
+
kyleLambda: kyleLambda > 0.001 ? 0.5 : 0.8,
|
|
384
|
+
kalman: kalmanConfirms ? 0.8 : 0.4,
|
|
385
|
+
volatility: regime === 'normal' ? 0.8 : regime === 'low' ? 0.7 : 0.6,
|
|
386
|
+
ofi: ofiConfirms ? 0.9 : 0.5,
|
|
387
|
+
composite: 0
|
|
388
|
+
};
|
|
389
|
+
|
|
390
|
+
scores.composite = scores.zscore * 0.30 + scores.vpin * 0.15 + scores.kyleLambda * 0.10 +
|
|
391
|
+
scores.kalman * 0.15 + scores.volatility * 0.10 + scores.ofi * 0.20;
|
|
392
|
+
|
|
393
|
+
const confidence = Math.min(1.0, scores.composite + volParams.confidenceBonus);
|
|
394
|
+
if (confidence < 0.55) return null;
|
|
395
|
+
|
|
396
|
+
const stopTicks = Math.round(this.baseStopTicks * volParams.stopMultiplier);
|
|
397
|
+
const targetTicks = Math.round(this.baseTargetTicks * volParams.targetMultiplier);
|
|
398
|
+
const actualStopTicks = Math.max(6, Math.min(12, stopTicks));
|
|
399
|
+
const actualTargetTicks = Math.max(actualStopTicks * 1.5, Math.min(24, targetTicks));
|
|
400
|
+
|
|
401
|
+
let stopLoss, takeProfit, beBreakeven, profitLockLevel;
|
|
402
|
+
if (direction === 'long') {
|
|
403
|
+
stopLoss = currentPrice - actualStopTicks * this.tickSize;
|
|
404
|
+
takeProfit = currentPrice + actualTargetTicks * this.tickSize;
|
|
405
|
+
beBreakeven = currentPrice + this.breakevenTicks * this.tickSize;
|
|
406
|
+
profitLockLevel = currentPrice + (actualTargetTicks * this.profitLockPct) * this.tickSize;
|
|
407
|
+
} else {
|
|
408
|
+
stopLoss = currentPrice + actualStopTicks * this.tickSize;
|
|
409
|
+
takeProfit = currentPrice - actualTargetTicks * this.tickSize;
|
|
410
|
+
beBreakeven = currentPrice - this.breakevenTicks * this.tickSize;
|
|
411
|
+
profitLockLevel = currentPrice - (actualTargetTicks * this.profitLockPct) * this.tickSize;
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
const riskReward = actualTargetTicks / actualStopTicks;
|
|
415
|
+
const trailTriggerTicks = Math.round(actualTargetTicks * 0.5);
|
|
416
|
+
const trailDistanceTicks = Math.round(actualStopTicks * 0.4);
|
|
417
|
+
|
|
418
|
+
let strength = SignalStrength.MODERATE;
|
|
419
|
+
if (confidence >= 0.85) strength = SignalStrength.VERY_STRONG;
|
|
420
|
+
else if (confidence >= 0.75) strength = SignalStrength.STRONG;
|
|
421
|
+
else if (confidence < 0.60) strength = SignalStrength.WEAK;
|
|
422
|
+
|
|
423
|
+
const winProb = 0.5 + (confidence - 0.5) * 0.4;
|
|
424
|
+
const edge = winProb * Math.abs(takeProfit - currentPrice) - (1 - winProb) * Math.abs(currentPrice - stopLoss);
|
|
425
|
+
|
|
426
|
+
return {
|
|
427
|
+
id: uuidv4(),
|
|
428
|
+
timestamp: Date.now(),
|
|
429
|
+
symbol: extractBaseSymbol(contractId),
|
|
430
|
+
contractId,
|
|
431
|
+
side: direction === 'long' ? OrderSide.BID : OrderSide.ASK,
|
|
432
|
+
direction,
|
|
433
|
+
strategy: 'HQX_ULTRA_SCALPING',
|
|
434
|
+
strength,
|
|
435
|
+
edge,
|
|
436
|
+
confidence,
|
|
437
|
+
entry: currentPrice,
|
|
438
|
+
entryPrice: currentPrice,
|
|
439
|
+
stopLoss,
|
|
440
|
+
takeProfit,
|
|
441
|
+
riskReward,
|
|
442
|
+
stopTicks: actualStopTicks,
|
|
443
|
+
targetTicks: actualTargetTicks,
|
|
444
|
+
trailTriggerTicks,
|
|
445
|
+
trailDistanceTicks,
|
|
446
|
+
beBreakeven,
|
|
447
|
+
profitLockLevel,
|
|
448
|
+
zScore: zscore,
|
|
449
|
+
zScoreExit: this.zscoreExitThreshold,
|
|
450
|
+
vpinValue: vpin,
|
|
451
|
+
kyleLambda,
|
|
452
|
+
kalmanEstimate,
|
|
453
|
+
volatilityRegime: regime,
|
|
454
|
+
ofiValue: ofi,
|
|
455
|
+
models: scores
|
|
456
|
+
};
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
/**
|
|
460
|
+
* Check if should exit by Z-Score
|
|
461
|
+
*/
|
|
462
|
+
shouldExitByZScore(contractId) {
|
|
463
|
+
const prices = this.priceBuffer.get(contractId);
|
|
464
|
+
if (!prices || prices.length < 50) return false;
|
|
465
|
+
const zscore = this._computeZScore(prices);
|
|
466
|
+
return Math.abs(zscore) < this.zscoreExitThreshold;
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
/**
|
|
470
|
+
* Get current model values
|
|
471
|
+
*/
|
|
472
|
+
getModelValues(contractId) {
|
|
473
|
+
const prices = this.priceBuffer.get(contractId);
|
|
474
|
+
const volumes = this.volumeBuffer.get(contractId);
|
|
475
|
+
const bars = this.barHistory.get(contractId);
|
|
476
|
+
if (!prices || !volumes || !bars || bars.length < 50) return null;
|
|
477
|
+
|
|
478
|
+
return {
|
|
479
|
+
zscore: this._computeZScore(prices).toFixed(2),
|
|
480
|
+
vpin: (this._computeVPIN(volumes) * 100).toFixed(1) + '%',
|
|
481
|
+
ofi: (this._computeOrderFlowImbalance(bars) * 100).toFixed(1) + '%',
|
|
482
|
+
bars: bars.length
|
|
483
|
+
};
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
/**
|
|
487
|
+
* Record trade result
|
|
488
|
+
*/
|
|
489
|
+
recordTradeResult(pnl) {
|
|
490
|
+
this.recentTrades.push({ pnl, timestamp: Date.now() });
|
|
491
|
+
if (this.recentTrades.length > 100) this.recentTrades.shift();
|
|
492
|
+
if (pnl > 0) { this.winStreak++; this.lossStreak = 0; }
|
|
493
|
+
else { this.lossStreak++; this.winStreak = 0; }
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
/**
|
|
497
|
+
* Get bar history
|
|
498
|
+
*/
|
|
499
|
+
getBarHistory(contractId) {
|
|
500
|
+
return this.barHistory.get(contractId) || [];
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
/**
|
|
504
|
+
* Reset strategy
|
|
505
|
+
*/
|
|
506
|
+
reset(contractId) {
|
|
507
|
+
this.barHistory.set(contractId, []);
|
|
508
|
+
this.priceBuffer.set(contractId, []);
|
|
509
|
+
this.volumeBuffer.set(contractId, []);
|
|
510
|
+
this.tradesBuffer.set(contractId, []);
|
|
511
|
+
this.atrHistory.set(contractId, []);
|
|
512
|
+
this.tickBuffer.set(contractId, []);
|
|
513
|
+
this.lastBarTime.set(contractId, 0);
|
|
514
|
+
this.kalmanStates.set(contractId, { estimate: 0, errorCovariance: 1.0 });
|
|
515
|
+
}
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
// Singleton instance
|
|
519
|
+
const M1 = new HQXUltraScalpingStrategy();
|
|
520
|
+
|
|
521
|
+
module.exports = { M1, HQXUltraScalpingStrategy, OrderSide, SignalStrength };
|
|
@@ -11,9 +11,9 @@ const { AlgoUI, renderSessionSummary } = require('./ui');
|
|
|
11
11
|
const { prompts } = require('../../utils');
|
|
12
12
|
const { checkMarketHours } = require('../../services/projectx/market');
|
|
13
13
|
|
|
14
|
-
// Strategy & Market Data
|
|
15
|
-
const { M1 } = require('
|
|
16
|
-
const { MarketDataFeed } = require('
|
|
14
|
+
// Strategy & Market Data
|
|
15
|
+
const { M1 } = require('../../lib/m/s1');
|
|
16
|
+
const { MarketDataFeed } = require('../../lib/data');
|
|
17
17
|
|
|
18
18
|
|
|
19
19
|
|
package/dist/lib/api.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
'use strict';require('bytenode');module.exports=require('./api.jsc');
|
package/dist/lib/api.jsc
DELETED
|
Binary file
|
package/dist/lib/api2.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
'use strict';require('bytenode');module.exports=require('./api2.jsc');
|
package/dist/lib/api2.jsc
DELETED
|
Binary file
|
package/dist/lib/core.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
'use strict';require('bytenode');module.exports=require('./core.jsc');
|
package/dist/lib/core.jsc
DELETED
|
Binary file
|
package/dist/lib/core2.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
'use strict';require('bytenode');module.exports=require('./core2.jsc');
|
package/dist/lib/core2.jsc
DELETED
|
Binary file
|
package/dist/lib/data.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
'use strict';require('bytenode');module.exports=require('./data.jsc');
|
package/dist/lib/data.jsc
DELETED
|
Binary file
|
package/dist/lib/data2.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
'use strict';require('bytenode');module.exports=require('./data2.jsc');
|
package/dist/lib/data2.jsc
DELETED
|
Binary file
|
package/dist/lib/decoder.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
'use strict';require('bytenode');module.exports=require('./decoder.jsc');
|
package/dist/lib/decoder.jsc
DELETED
|
Binary file
|
package/dist/lib/m/mod1.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
'use strict';require('bytenode');module.exports=require('./mod1.jsc');
|
package/dist/lib/m/mod1.jsc
DELETED
|
Binary file
|
package/dist/lib/m/mod2.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
'use strict';require('bytenode');module.exports=require('./mod2.jsc');
|
package/dist/lib/m/mod2.jsc
DELETED
|
Binary file
|
package/dist/lib/n/r1.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
'use strict';require('bytenode');module.exports=require('./r1.jsc');
|
package/dist/lib/n/r1.jsc
DELETED
|
Binary file
|
package/dist/lib/n/r2.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
'use strict';require('bytenode');module.exports=require('./r2.jsc');
|
package/dist/lib/n/r2.jsc
DELETED
|
Binary file
|
package/dist/lib/n/r3.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
'use strict';require('bytenode');module.exports=require('./r3.jsc');
|
package/dist/lib/n/r3.jsc
DELETED
|
Binary file
|
package/dist/lib/n/r4.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
'use strict';require('bytenode');module.exports=require('./r4.jsc');
|
package/dist/lib/n/r4.jsc
DELETED
|
Binary file
|
package/dist/lib/n/r5.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
'use strict';require('bytenode');module.exports=require('./r5.jsc');
|
package/dist/lib/n/r5.jsc
DELETED
|
Binary file
|
package/dist/lib/n/r6.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
'use strict';require('bytenode');module.exports=require('./r6.jsc');
|
package/dist/lib/n/r6.jsc
DELETED
|
Binary file
|
package/dist/lib/n/r7.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
'use strict';require('bytenode');module.exports=require('./r7.jsc');
|
package/dist/lib/n/r7.jsc
DELETED
|
Binary file
|
package/dist/lib/o/util1.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
'use strict';require('bytenode');module.exports=require('./util1.jsc');
|
package/dist/lib/o/util1.jsc
DELETED
|
Binary file
|
package/dist/lib/o/util2.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
'use strict';require('bytenode');module.exports=require('./util2.jsc');
|
package/dist/lib/o/util2.jsc
DELETED
|
Binary file
|