hedgequantx 2.9.227 → 2.9.228
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/dist/lib/m/ultra-scalping.js +76 -1
- package/package.json +1 -1
|
@@ -151,9 +151,18 @@ class HQXUltraScalpingStrategy extends EventEmitter {
|
|
|
151
151
|
// Add tick to buffer
|
|
152
152
|
let ticks = this.tickBuffer.get(contractId);
|
|
153
153
|
ticks.push(tick);
|
|
154
|
+
|
|
155
|
+
// Track total ticks for status log
|
|
156
|
+
this._totalTicks = (this._totalTicks || 0) + 1;
|
|
157
|
+
|
|
158
|
+
// Emit status log every second
|
|
159
|
+
const now = Date.now();
|
|
160
|
+
if (!this._lastStatusLog || now - this._lastStatusLog >= 1000) {
|
|
161
|
+
this._lastStatusLog = now;
|
|
162
|
+
this._emitStatusLog(contractId, tick.price);
|
|
163
|
+
}
|
|
154
164
|
|
|
155
165
|
// Check if we should form a new bar
|
|
156
|
-
const now = Date.now();
|
|
157
166
|
const lastBar = this.lastBarTime.get(contractId);
|
|
158
167
|
|
|
159
168
|
if (now - lastBar >= this.barIntervalMs && ticks.length > 0) {
|
|
@@ -171,6 +180,72 @@ class HQXUltraScalpingStrategy extends EventEmitter {
|
|
|
171
180
|
}
|
|
172
181
|
return null;
|
|
173
182
|
}
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* Emit status log with QUANT metrics
|
|
186
|
+
*/
|
|
187
|
+
_emitStatusLog(contractId, currentPrice) {
|
|
188
|
+
const prices = this.priceBuffer.get(contractId) || [];
|
|
189
|
+
const volumes = this.volumeBuffer.get(contractId) || [];
|
|
190
|
+
const bars = this.barHistory.get(contractId) || [];
|
|
191
|
+
|
|
192
|
+
if (prices.length < 20) return; // Not enough data yet
|
|
193
|
+
|
|
194
|
+
// Compute current metrics
|
|
195
|
+
const zscore = computeZScore(prices);
|
|
196
|
+
const vpin = volumes.length >= 10 ? computeVPIN(volumes, this.vpinWindow) : 0;
|
|
197
|
+
const ofi = bars.length >= 10 ? computeOrderFlowImbalance(bars, this.ofiLookback) : 0;
|
|
198
|
+
|
|
199
|
+
// Determine market state
|
|
200
|
+
const absZ = Math.abs(zscore);
|
|
201
|
+
let zState = 'normal';
|
|
202
|
+
if (absZ >= 2.0) zState = 'EXTREME';
|
|
203
|
+
else if (absZ >= 1.5) zState = 'HIGH';
|
|
204
|
+
else if (absZ >= 1.0) zState = 'building';
|
|
205
|
+
|
|
206
|
+
// Determine direction bias
|
|
207
|
+
let bias = 'neutral';
|
|
208
|
+
if (zscore < -1.5 && ofi > 0.1) bias = 'LONG setup';
|
|
209
|
+
else if (zscore > 1.5 && ofi < -0.1) bias = 'SHORT setup';
|
|
210
|
+
else if (zscore < -1.0) bias = 'oversold';
|
|
211
|
+
else if (zscore > 1.0) bias = 'overbought';
|
|
212
|
+
|
|
213
|
+
// Extract symbol
|
|
214
|
+
const sym = (contractId || '').replace(/[A-Z]\d+$/, '');
|
|
215
|
+
|
|
216
|
+
// Build message based on state
|
|
217
|
+
let message;
|
|
218
|
+
if (!this.tradingEnabled) {
|
|
219
|
+
message = `[${sym}] ${currentPrice.toFixed(2)} | PAUSED (${this.lossStreak} losses) | Cooldown active`;
|
|
220
|
+
} else if (absZ >= 2.0) {
|
|
221
|
+
const dir = zscore < 0 ? 'LONG' : 'SHORT';
|
|
222
|
+
const ofiPct = (Math.abs(ofi) * 100).toFixed(0);
|
|
223
|
+
const ofiConfirm = (zscore < 0 && ofi > 0.15) || (zscore > 0 && ofi < -0.15);
|
|
224
|
+
if (ofiConfirm) {
|
|
225
|
+
message = `[${sym}] ${currentPrice.toFixed(2)} | Z: ${zscore.toFixed(1)}σ ${zState} | ${dir} | OFI ${ofiPct}% confirms`;
|
|
226
|
+
} else {
|
|
227
|
+
message = `[${sym}] ${currentPrice.toFixed(2)} | Z: ${zscore.toFixed(1)}σ ${zState} | ${dir} signal | OFI ${ofiPct}% pending`;
|
|
228
|
+
}
|
|
229
|
+
} else if (absZ >= 1.5) {
|
|
230
|
+
message = `[${sym}] ${currentPrice.toFixed(2)} | Z: ${zscore.toFixed(1)}σ ${zState} | ${bias} | Monitoring`;
|
|
231
|
+
} else if (absZ >= 1.0) {
|
|
232
|
+
message = `[${sym}] ${currentPrice.toFixed(2)} | Z: ${zscore.toFixed(1)}σ ${zState} | Awaiting extremity`;
|
|
233
|
+
} else {
|
|
234
|
+
// Normal state - show different context messages
|
|
235
|
+
const vpinPct = (vpin * 100).toFixed(0);
|
|
236
|
+
const contexts = [
|
|
237
|
+
`VPIN ${vpinPct}% | Mean reversion scan`,
|
|
238
|
+
`OFI balanced | Price discovery`,
|
|
239
|
+
`Z normalized | Statistical scan`,
|
|
240
|
+
`Tick flow stable | Edge detection`,
|
|
241
|
+
`Volatility normal | Alpha scan`,
|
|
242
|
+
];
|
|
243
|
+
const ctx = contexts[Math.floor(Date.now() / 5000) % contexts.length];
|
|
244
|
+
message = `[${sym}] ${currentPrice.toFixed(2)} | Z: ${zscore.toFixed(1)}σ | ${ctx}`;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
this.emit('log', { type: 'info', message });
|
|
248
|
+
}
|
|
174
249
|
|
|
175
250
|
/**
|
|
176
251
|
* Aggregate ticks into a bar
|