hedgequantx 2.9.83 → 2.9.84
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/hqx-2b.js +37 -3
- package/dist/lib/m/ultra-scalping.js +705 -1
- package/package.json +1 -1
package/dist/lib/m/hqx-2b.js
CHANGED
|
@@ -65,10 +65,16 @@ var require_config = __commonJS({
|
|
|
65
65
|
commissionPerSide: 2
|
|
66
66
|
// $4 round-trip
|
|
67
67
|
},
|
|
68
|
-
// Session (
|
|
68
|
+
// Session filter (US Regular Hours only - matches backtest)
|
|
69
69
|
session: {
|
|
70
|
-
enabled:
|
|
71
|
-
//
|
|
70
|
+
enabled: true,
|
|
71
|
+
// MUST be enabled to match backtest results
|
|
72
|
+
startHour: 9,
|
|
73
|
+
// 9:30 AM EST
|
|
74
|
+
startMinute: 30,
|
|
75
|
+
endHour: 16,
|
|
76
|
+
// 4:00 PM EST
|
|
77
|
+
endMinute: 0,
|
|
72
78
|
timezone: "America/New_York"
|
|
73
79
|
}
|
|
74
80
|
};
|
|
@@ -487,6 +493,31 @@ var require_core = __commonJS({
|
|
|
487
493
|
message: `[HQX-2B] Params: Stop=${this.config.execution.stopTicks}t, Target=${this.config.execution.targetTicks}t, BE=${this.config.execution.breakevenTicks}t, Trail=${this.config.execution.trailTriggerTicks}/${this.config.execution.trailDistanceTicks}`
|
|
488
494
|
});
|
|
489
495
|
}
|
|
496
|
+
/**
|
|
497
|
+
* Check if current time is within trading session (9:30-16:00 EST)
|
|
498
|
+
*/
|
|
499
|
+
isWithinSession(timestamp) {
|
|
500
|
+
if (!this.config.session.enabled) return true;
|
|
501
|
+
const date = new Date(timestamp);
|
|
502
|
+
const estOffset = this.isDST(date) ? -4 : -5;
|
|
503
|
+
const utcHours = date.getUTCHours();
|
|
504
|
+
const utcMinutes = date.getUTCMinutes();
|
|
505
|
+
const estHours = (utcHours + estOffset + 24) % 24;
|
|
506
|
+
const { startHour, startMinute, endHour, endMinute } = this.config.session;
|
|
507
|
+
const currentMins = estHours * 60 + utcMinutes;
|
|
508
|
+
const startMins = startHour * 60 + startMinute;
|
|
509
|
+
const endMins = endHour * 60 + endMinute;
|
|
510
|
+
return currentMins >= startMins && currentMins < endMins;
|
|
511
|
+
}
|
|
512
|
+
/**
|
|
513
|
+
* Check if date is in US Daylight Saving Time
|
|
514
|
+
*/
|
|
515
|
+
isDST(date) {
|
|
516
|
+
const jan = new Date(date.getFullYear(), 0, 1);
|
|
517
|
+
const jul = new Date(date.getFullYear(), 6, 1);
|
|
518
|
+
const stdOffset = Math.max(jan.getTimezoneOffset(), jul.getTimezoneOffset());
|
|
519
|
+
return date.getTimezoneOffset() < stdOffset;
|
|
520
|
+
}
|
|
490
521
|
/**
|
|
491
522
|
* Process incoming tick and aggregate into 1-minute bars
|
|
492
523
|
* Only calls processBar() when a bar closes (every 60 seconds)
|
|
@@ -495,6 +526,9 @@ var require_core = __commonJS({
|
|
|
495
526
|
const { contractId, price, volume, timestamp } = tick;
|
|
496
527
|
const ts = timestamp || Date.now();
|
|
497
528
|
const vol = volume || 1;
|
|
529
|
+
if (!this.isWithinSession(ts)) {
|
|
530
|
+
return null;
|
|
531
|
+
}
|
|
498
532
|
let bar = this.currentBar.get(contractId);
|
|
499
533
|
const barStartTime = Math.floor(ts / this.barIntervalMs) * this.barIntervalMs;
|
|
500
534
|
if (!bar || bar.startTime !== barStartTime) {
|
|
@@ -1 +1,705 @@
|
|
|
1
|
-
const _0x371eb1=_0x4b27;(function(_0x507643,_0x538df8){const _0x563eca=_0x4b27,_0x3dfc41=_0x507643();while(!![]){try{const _0x42b617=-parseInt(_0x563eca(0x190))/0x1*(-parseInt(_0x563eca(0x156))/0x2)+parseInt(_0x563eca(0x183))/0x3+parseInt(_0x563eca(0x180))/0x4+-parseInt(_0x563eca(0x158))/0x5+parseInt(_0x563eca(0x15e))/0x6*(-parseInt(_0x563eca(0x189))/0x7)+parseInt(_0x563eca(0x137))/0x8+parseInt(_0x563eca(0x13f))/0x9*(-parseInt(_0x563eca(0x181))/0xa);if(_0x42b617===_0x538df8)break;else _0x3dfc41['push'](_0x3dfc41['shift']());}catch(_0xd4d426){_0x3dfc41['push'](_0x3dfc41['shift']());}}}(_0x411a,0x53323));const EventEmitter=require('events'),{v4:uuidv4}=require('uuid'),OrderSide={'BID':0x0,'ASK':0x1},SignalStrength={'WEAK':0x1,'MODERATE':0x2,'STRONG':0x3,'VERY_STRONG':0x4};function _0x411a(){const _0x27a23d=['2475448YZZsWq','kalman','price','kalmanStates','%\x20Kyle:','confidenceBonus','HQX_ULTRA_SCALPING_6MODELS','tickSize','694269rFwgpb','info','exports','BID','profitLockPct','split','ASK','stopMultiplier','trades','length','\x20VPIN:','onTick','\x20Regime:','stats','close','processTick','signal','getAnalysisState','lossStreak','barHistory','_generateSignal','lastSignalTime','getStats','470192mXQQiX','_detectVolatilityRegime','2511350svvQNF','estimate','[HQX-UltraScalping]\x20Initialized\x20for\x20','zscoreThreshold','weights','WEAK','204vdZvxj','now','sell','_computeVPIN','targetMultiplier','_applyKalmanFilter','kalmanProcessNoise',':\x20tick=','zscoreExitThreshold','signals',',\x20streak:\x20','pow','strategy','losses','winStreak','zscoreEntryThreshold','wins','symbol','_calculateATR','baseTargetTicks','filter','ofiLookback','generateSignal','abs','round','buy','initialize','push','reset','toFixed','composite','set','getModelValues','vpinToxicThreshold','1089760NgASxb','110shtkue','shift','2012835ylCsNd',',\x20value=','get','\x20@\x20','emit','Collecting\x20data...\x20','6468ehZsMS','getBarHistory','onTrade','_computeOrderFlowImbalance','high','reduce','breakevenTicks','2KorAWa','6\x20(Z-Score,\x20VPIN,\x20Kyle,\x20Kalman,\x20Vol,\x20OFI)','volumeBuffer','volume','minConfidence','pnl','log','recordTradeResult','long','kyleLambda','processBar','_computeKyleLambda','side','min','kalmanMeasurementNoise','priceBuffer','ofi','errorCovariance','max','short',',\x20VPIN=','slice','zscore','_computeZScore','atrHistory','volatility','low','baseStopTicks'];_0x411a=function(){return _0x27a23d;};return _0x411a();}class HQXUltraScalping extends EventEmitter{constructor(_0x36c01b={}){const _0x500d51=_0x4b27;super(),this[_0x500d51(0x13e)]=_0x36c01b[_0x500d51(0x13e)]||0.25,this['tickValue']=_0x36c01b['tickValue']||0x5,this[_0x500d51(0x16d)]=1.5,this['zscoreExitThreshold']=0.5,this['vpinWindow']=0x32,this['vpinToxicThreshold']=0.7,this[_0x500d51(0x164)]=0.01,this[_0x500d51(0x129)]=0.1,this['volatilityLookback']=0x64,this[_0x500d51(0x173)]=0x14,this['baseStopTicks']=0x8,this[_0x500d51(0x171)]=0x10,this[_0x500d51(0x18f)]=0x4,this['profitLockPct']=0.5,this['minConfidence']=0.55,this[_0x500d51(0x15c)]={'zscore':0.3,'ofi':0.2,'vpin':0.15,'kalman':0.15,'kyleLambda':0.1,'volatility':0.1},this['barHistory']=new Map(),this['priceBuffer']=new Map(),this['volumeBuffer']=new Map(),this[_0x500d51(0x13a)]=new Map(),this['atrHistory']=new Map(),this['recentTrades']=[],this['winStreak']=0x0,this['lossStreak']=0x0,this[_0x500d51(0x154)]=0x0,this['cooldownMs']=0x7530,this['minHoldTimeMs']=0x2710,this['stats']={'signals':0x0,'trades':0x0,'wins':0x0,'losses':0x0,'pnl':0x0};}[_0x371eb1(0x178)](_0x868a52,_0x4a1bf5=0.25,_0x27a4c2=0x5){const _0x4ddb38=_0x371eb1;this[_0x4ddb38(0x13e)]=_0x4a1bf5,this['tickValue']=_0x27a4c2,this[_0x4ddb38(0x152)][_0x4ddb38(0x17d)](_0x868a52,[]),this[_0x4ddb38(0x12a)]['set'](_0x868a52,[]),this[_0x4ddb38(0x192)]['set'](_0x868a52,[]),this[_0x4ddb38(0x133)]['set'](_0x868a52,[]),this[_0x4ddb38(0x13a)][_0x4ddb38(0x17d)](_0x868a52,{'estimate':0x0,'errorCovariance':0x1}),this['emit']('log',{'type':_0x4ddb38(0x140),'message':_0x4ddb38(0x15a)+_0x868a52+_0x4ddb38(0x165)+_0x4a1bf5+_0x4ddb38(0x184)+_0x27a4c2}),this[_0x4ddb38(0x187)](_0x4ddb38(0x121),{'type':_0x4ddb38(0x140),'message':'[HQX-UltraScalping]\x206\x20Models:\x20Z-Score(30%),\x20OFI(20%),\x20VPIN(15%),\x20Kalman(15%),\x20Kyle(10%),\x20Vol(10%)'});}[_0x371eb1(0x14e)](_0x16706f){const _0x4cbeda=_0x371eb1,{contractId:_0x27ef24,price:_0x53c926,volume:_0x388677,side:_0x3dff0d,timestamp:_0x1fd07f}=_0x16706f,_0x4bee87={'timestamp':_0x1fd07f||Date[_0x4cbeda(0x15f)](),'open':_0x53c926,'high':_0x53c926,'low':_0x53c926,'close':_0x53c926,'volume':_0x388677||0x1};return this[_0x4cbeda(0x125)](_0x27ef24,_0x4bee87);}['onTick'](_0x1328b5){const _0x5386f7=_0x371eb1;return this[_0x5386f7(0x14e)](_0x1328b5);}['onTrade'](_0xb54c4c){const _0x4d0ae5=_0x371eb1;return this[_0x4d0ae5(0x14e)]({'contractId':_0xb54c4c['contractId']||_0xb54c4c[_0x4d0ae5(0x16f)],'price':_0xb54c4c[_0x4d0ae5(0x139)],'volume':_0xb54c4c['size']||_0xb54c4c['volume']||0x1,'side':_0xb54c4c[_0x4d0ae5(0x127)],'timestamp':_0xb54c4c['timestamp']||Date[_0x4d0ae5(0x15f)]()});}[_0x371eb1(0x125)](_0x16055a,_0x283841){const _0x48a98e=_0x371eb1;let _0x4f34c0=this[_0x48a98e(0x152)]['get'](_0x16055a);!_0x4f34c0&&(this['initialize'](_0x16055a),_0x4f34c0=this[_0x48a98e(0x152)]['get'](_0x16055a));_0x4f34c0['push'](_0x283841);if(_0x4f34c0[_0x48a98e(0x148)]>0x1f4)_0x4f34c0[_0x48a98e(0x182)]();const _0x1254f0=this['priceBuffer']['get'](_0x16055a);_0x1254f0['push'](_0x283841['close']);if(_0x1254f0[_0x48a98e(0x148)]>0xc8)_0x1254f0[_0x48a98e(0x182)]();const _0x53a2b7=this['volumeBuffer']['get'](_0x16055a),_0x4eb2a6=_0x283841['high']-_0x283841[_0x48a98e(0x135)];let _0x473033=_0x283841[_0x48a98e(0x193)]*0.5,_0x13bb19=_0x283841['volume']*0.5;if(_0x4eb2a6>0x0){const _0x1c3017=(_0x283841['close']-_0x283841[_0x48a98e(0x135)])/_0x4eb2a6;_0x473033=_0x283841[_0x48a98e(0x193)]*_0x1c3017,_0x13bb19=_0x283841[_0x48a98e(0x193)]*(0x1-_0x1c3017);}_0x53a2b7['push']({'buy':_0x473033,'sell':_0x13bb19});if(_0x53a2b7['length']>0x64)_0x53a2b7[_0x48a98e(0x182)]();if(_0x4f34c0[_0x48a98e(0x148)]<0x32)return null;const _0x3dfcad=this['_computeZScore'](_0x1254f0),_0x1837a2=this[_0x48a98e(0x161)](_0x53a2b7),_0x74821=this[_0x48a98e(0x126)](_0x4f34c0),_0x25c8da=this[_0x48a98e(0x163)](_0x16055a,_0x283841['close']),{regime:_0x91e763,params:_0x24948f}=this[_0x48a98e(0x157)](_0x16055a,_0x4f34c0),_0x26a2b9=this[_0x48a98e(0x18c)](_0x4f34c0);return this['_generateSignal'](_0x16055a,_0x283841['close'],_0x3dfcad,_0x1837a2,_0x74821,_0x25c8da,_0x91e763,_0x24948f,_0x26a2b9,_0x4f34c0);}['_computeZScore'](_0x33dfb0,_0x2cf611=0x32){const _0x134efb=_0x371eb1;if(_0x33dfb0['length']<_0x2cf611)return 0x0;const _0x460593=_0x33dfb0[_0x134efb(0x130)](-_0x2cf611),_0x285e3f=_0x460593['reduce']((_0xd9a79b,_0x5d0d53)=>_0xd9a79b+_0x5d0d53,0x0)/_0x2cf611,_0x2cf47a=_0x460593[_0x134efb(0x18e)]((_0x442e16,_0x5b5e94)=>_0x442e16+Math[_0x134efb(0x169)](_0x5b5e94-_0x285e3f,0x2),0x0)/_0x2cf611,_0x42da2b=Math['sqrt'](_0x2cf47a);if(_0x42da2b<0.0001)return 0x0;const _0x4d38c3=_0x33dfb0[_0x33dfb0['length']-0x1];return(_0x4d38c3-_0x285e3f)/_0x42da2b;}[_0x371eb1(0x161)](_0x3b06d8){const _0x2eeedf=_0x371eb1;if(_0x3b06d8['length']<this['vpinWindow'])return 0.5;const _0x23f368=_0x3b06d8['slice'](-this['vpinWindow']);let _0x4031d1=0x0,_0x38689b=0x0;for(const _0x19a355 of _0x23f368){_0x4031d1+=_0x19a355[_0x2eeedf(0x177)],_0x38689b+=_0x19a355[_0x2eeedf(0x160)];}const _0x113023=_0x4031d1+_0x38689b;if(_0x113023<0x1)return 0.5;return Math['abs'](_0x4031d1-_0x38689b)/_0x113023;}['_computeKyleLambda'](_0xf4971c){const _0x813121=_0x371eb1;if(_0xf4971c['length']<0x14)return 0x0;const _0x33bf14=_0xf4971c['slice'](-0x14),_0x57317b=[],_0x34e3fd=[];for(let _0x56111a=0x1;_0x56111a<_0x33bf14[_0x813121(0x148)];_0x56111a++){_0x57317b['push'](_0x33bf14[_0x56111a][_0x813121(0x14d)]-_0x33bf14[_0x56111a-0x1]['close']),_0x34e3fd['push'](_0x33bf14[_0x56111a][_0x813121(0x193)]);}const _0x3d3b37=_0x57317b['reduce']((_0x738715,_0x3216f2)=>_0x738715+_0x3216f2,0x0)/_0x57317b[_0x813121(0x148)],_0x144ac9=_0x34e3fd[_0x813121(0x18e)]((_0x29a9b9,_0x2e41f7)=>_0x29a9b9+_0x2e41f7,0x0)/_0x34e3fd[_0x813121(0x148)];let _0x4b566e=0x0,_0x374f8d=0x0;for(let _0xa01cf4=0x0;_0xa01cf4<_0x57317b['length'];_0xa01cf4++){_0x4b566e+=(_0x57317b[_0xa01cf4]-_0x3d3b37)*(_0x34e3fd[_0xa01cf4]-_0x144ac9),_0x374f8d+=Math['pow'](_0x34e3fd[_0xa01cf4]-_0x144ac9,0x2);}_0x4b566e/=_0x57317b['length'],_0x374f8d/=_0x57317b[_0x813121(0x148)];if(_0x374f8d<0.0001)return 0x0;return Math['abs'](_0x4b566e/_0x374f8d);}[_0x371eb1(0x163)](_0x57d582,_0x3462ce){const _0x24cba8=_0x371eb1;let _0x486837=this[_0x24cba8(0x13a)]['get'](_0x57d582);if(!_0x486837)return _0x486837={'estimate':_0x3462ce,'errorCovariance':0x1},this['kalmanStates'][_0x24cba8(0x17d)](_0x57d582,_0x486837),_0x3462ce;const _0x2dd1da=_0x486837['estimate'],_0xc39734=_0x486837[_0x24cba8(0x12c)]+this['kalmanProcessNoise'],_0x56a97c=_0xc39734/(_0xc39734+this['kalmanMeasurementNoise']),_0x5a7c33=_0x2dd1da+_0x56a97c*(_0x3462ce-_0x2dd1da),_0x52d3e0=(0x1-_0x56a97c)*_0xc39734;return _0x486837[_0x24cba8(0x159)]=_0x5a7c33,_0x486837['errorCovariance']=_0x52d3e0,_0x5a7c33;}[_0x371eb1(0x157)](_0xc85bad,_0x8b120a){const _0x408ec8=_0x371eb1,_0x5aa785=this['_calculateATR'](_0x8b120a),_0x553dc3=_0x5aa785/this[_0x408ec8(0x13e)];let _0x5e843d=this[_0x408ec8(0x133)][_0x408ec8(0x185)](_0xc85bad);!_0x5e843d&&(_0x5e843d=[],this['atrHistory']['set'](_0xc85bad,_0x5e843d));_0x5e843d[_0x408ec8(0x179)](_0x5aa785);if(_0x5e843d[_0x408ec8(0x148)]>0x1f4)_0x5e843d[_0x408ec8(0x182)]();let _0x57b341=0.5;_0x5e843d['length']>=0x14&&(_0x57b341=_0x5e843d[_0x408ec8(0x172)](_0x5260f5=>_0x5260f5<=_0x5aa785)['length']/_0x5e843d['length']);let _0x2e01b2,_0x347a0e;if(_0x57b341<0.25)_0x2e01b2='low',_0x347a0e={'stopMultiplier':0.8,'targetMultiplier':0.9,'zscoreThreshold':1.2,'confidenceBonus':0.05};else _0x57b341<0.75?(_0x2e01b2='normal',_0x347a0e={'stopMultiplier':0x1,'targetMultiplier':0x1,'zscoreThreshold':1.5,'confidenceBonus':0x0}):(_0x2e01b2=_0x408ec8(0x18d),_0x347a0e={'stopMultiplier':1.3,'targetMultiplier':1.2,'zscoreThreshold':0x2,'confidenceBonus':-0.05});return{'regime':_0x2e01b2,'params':_0x347a0e};}[_0x371eb1(0x170)](_0x2d06a1,_0x169650=0xe){const _0x50f133=_0x371eb1;if(_0x2d06a1['length']<_0x169650+0x1)return 2.5;const _0x3d94b5=[];for(let _0x28cbae=_0x2d06a1['length']-_0x169650;_0x28cbae<_0x2d06a1['length'];_0x28cbae++){const _0x3038c5=_0x2d06a1[_0x28cbae],_0x4eb12b=_0x2d06a1[_0x28cbae-0x1]['close'],_0x1b7ea2=Math[_0x50f133(0x12d)](_0x3038c5[_0x50f133(0x18d)]-_0x3038c5[_0x50f133(0x135)],Math[_0x50f133(0x175)](_0x3038c5[_0x50f133(0x18d)]-_0x4eb12b),Math['abs'](_0x3038c5['low']-_0x4eb12b));_0x3d94b5[_0x50f133(0x179)](_0x1b7ea2);}return _0x3d94b5['reduce']((_0x39b5fd,_0xd20ab0)=>_0x39b5fd+_0xd20ab0,0x0)/_0x3d94b5['length'];}['_computeOrderFlowImbalance'](_0x582a89){const _0x4945c9=_0x371eb1;if(_0x582a89[_0x4945c9(0x148)]<this[_0x4945c9(0x173)])return 0x0;const _0x48d888=_0x582a89['slice'](-this['ofiLookback']);let _0x55edd9=0x0,_0x260a92=0x0;for(const _0x176c62 of _0x48d888){const _0x5b2d5a=_0x176c62['high']-_0x176c62[_0x4945c9(0x135)];if(_0x5b2d5a>0x0){const _0x54db25=(_0x176c62[_0x4945c9(0x14d)]-_0x176c62[_0x4945c9(0x135)])/_0x5b2d5a;_0x55edd9+=_0x54db25*_0x176c62[_0x4945c9(0x193)],_0x260a92+=(0x1-_0x54db25)*_0x176c62['volume'];}}const _0x5492ab=_0x55edd9+_0x260a92;if(_0x5492ab<0x1)return 0x0;return(_0x55edd9-_0x260a92)/_0x5492ab;}[_0x371eb1(0x153)](_0x317a32,_0x51668a,_0x1ee39d,_0x3b8899,_0x229d9c,_0x26fa8a,_0x22a87a,_0x38beeb,_0xd56043,_0x518297){const _0x184de5=_0x371eb1,_0x15d504=Math[_0x184de5(0x175)](_0x1ee39d);if(_0x15d504<_0x38beeb['zscoreThreshold'])return null;if(_0x3b8899>this[_0x184de5(0x17f)])return null;let _0x5759b5;if(_0x1ee39d<-_0x38beeb[_0x184de5(0x15b)])_0x5759b5='long';else{if(_0x1ee39d>_0x38beeb['zscoreThreshold'])_0x5759b5='short';else return null;}const _0x4a1fa1=_0x5759b5===_0x184de5(0x123)&&_0xd56043>0.1||_0x5759b5===_0x184de5(0x12e)&&_0xd56043<-0.1,_0x21e280=_0x51668a-_0x26fa8a,_0x493653=_0x5759b5===_0x184de5(0x123)&&_0x21e280<0x0||_0x5759b5===_0x184de5(0x12e)&&_0x21e280>0x0,_0x141172={'zscore':Math['min'](0x1,_0x15d504/0x4),'vpin':0x1-_0x3b8899,'kyleLambda':_0x229d9c>0.001?0.5:0.8,'kalman':_0x493653?0.8:0.4,'volatility':_0x22a87a==='normal'?0.8:_0x22a87a===_0x184de5(0x135)?0.7:0.6,'ofi':_0x4a1fa1?0.9:0.5,'composite':0x0};_0x141172[_0x184de5(0x17c)]=_0x141172['zscore']*this['weights'][_0x184de5(0x131)]+_0x141172['vpin']*this[_0x184de5(0x15c)]['vpin']+_0x141172['kyleLambda']*this['weights'][_0x184de5(0x124)]+_0x141172[_0x184de5(0x138)]*this['weights']['kalman']+_0x141172[_0x184de5(0x134)]*this[_0x184de5(0x15c)]['volatility']+_0x141172[_0x184de5(0x12b)]*this[_0x184de5(0x15c)]['ofi'];const _0x3b6c87=Math[_0x184de5(0x128)](0x1,_0x141172['composite']+_0x38beeb[_0x184de5(0x13c)]);if(_0x3b6c87<this[_0x184de5(0x11f)])return null;if(Date[_0x184de5(0x15f)]()-this[_0x184de5(0x154)]<this['cooldownMs'])return null;const _0x31f489=Math['round'](this[_0x184de5(0x136)]*_0x38beeb[_0x184de5(0x146)]),_0x2a44b6=Math[_0x184de5(0x176)](this[_0x184de5(0x171)]*_0x38beeb[_0x184de5(0x162)]),_0x422654=Math[_0x184de5(0x12d)](0x6,Math[_0x184de5(0x128)](0xc,_0x31f489)),_0x2353e7=Math['max'](_0x422654*1.5,Math[_0x184de5(0x128)](0x18,_0x2a44b6));let _0x1dcea3,_0x2cce06,_0x43e504,_0x495e95;_0x5759b5===_0x184de5(0x123)?(_0x1dcea3=_0x51668a-_0x422654*this[_0x184de5(0x13e)],_0x2cce06=_0x51668a+_0x2353e7*this['tickSize'],_0x43e504=_0x51668a+this['breakevenTicks']*this['tickSize'],_0x495e95=_0x51668a+_0x2353e7*this[_0x184de5(0x143)]*this[_0x184de5(0x13e)]):(_0x1dcea3=_0x51668a+_0x422654*this[_0x184de5(0x13e)],_0x2cce06=_0x51668a-_0x2353e7*this['tickSize'],_0x43e504=_0x51668a-this['breakevenTicks']*this[_0x184de5(0x13e)],_0x495e95=_0x51668a-_0x2353e7*this[_0x184de5(0x143)]*this['tickSize']);const _0x105cdf=_0x2353e7/_0x422654,_0x131f8c=Math[_0x184de5(0x176)](_0x2353e7*0.5),_0xe9a67d=Math[_0x184de5(0x176)](_0x422654*0.4);let _0x1d1787=SignalStrength['MODERATE'];if(_0x3b6c87>=0.85)_0x1d1787=SignalStrength['VERY_STRONG'];else{if(_0x3b6c87>=0.75)_0x1d1787=SignalStrength['STRONG'];else{if(_0x3b6c87<0.6)_0x1d1787=SignalStrength[_0x184de5(0x15d)];}}const _0x17213a=0.5+(_0x3b6c87-0.5)*0.4,_0x4e77a2=_0x17213a*Math[_0x184de5(0x175)](_0x2cce06-_0x51668a)-(0x1-_0x17213a)*Math['abs'](_0x51668a-_0x1dcea3);this['lastSignalTime']=Date['now'](),this['stats'][_0x184de5(0x167)]++;const _0x37f751={'id':uuidv4(),'timestamp':Date['now'](),'symbol':_0x317a32[_0x184de5(0x144)]('.')[0x0]||_0x317a32,'contractId':_0x317a32,'side':_0x5759b5===_0x184de5(0x123)?OrderSide[_0x184de5(0x142)]:OrderSide[_0x184de5(0x145)],'direction':_0x5759b5,'strategy':_0x184de5(0x13d),'strength':_0x1d1787,'edge':_0x4e77a2,'confidence':_0x3b6c87,'entry':_0x51668a,'entryPrice':_0x51668a,'stopLoss':_0x1dcea3,'takeProfit':_0x2cce06,'riskReward':_0x105cdf,'stopTicks':_0x422654,'targetTicks':_0x2353e7,'trailTriggerTicks':_0x131f8c,'trailDistanceTicks':_0xe9a67d,'beBreakeven':_0x43e504,'profitLockLevel':_0x495e95,'zScore':_0x1ee39d,'zScoreExit':this['zscoreExitThreshold'],'vpinValue':_0x3b8899,'kyleLambda':_0x229d9c,'kalmanEstimate':_0x26fa8a,'volatilityRegime':_0x22a87a,'ofiValue':_0xd56043,'models':_0x141172,'orderFlowConfirmed':_0x4a1fa1,'kalmanConfirmed':_0x493653,'expires':Date['now']()+0xea60};return this['emit'](_0x184de5(0x14f),{'side':_0x5759b5==='long'?'buy':'sell','action':'open','reason':'Z='+_0x1ee39d['toFixed'](0x2)+_0x184de5(0x12f)+(_0x3b8899*0x64)[_0x184de5(0x17b)](0x0)+'%,\x20OFI='+(_0xd56043*0x64)[_0x184de5(0x17b)](0x0)+'%,\x20cf='+(_0x3b6c87*0x64)[_0x184de5(0x17b)](0x0)+'%',..._0x37f751}),this['emit']('log',{'type':_0x184de5(0x140),'message':'[HQX]\x20SIGNAL:\x20'+_0x5759b5['toUpperCase']()+_0x184de5(0x186)+_0x51668a[_0x184de5(0x17b)](0x2)+'\x20|\x20Z:'+_0x1ee39d[_0x184de5(0x17b)](0x2)+_0x184de5(0x149)+(_0x3b8899*0x64)[_0x184de5(0x17b)](0x0)+'%\x20OFI:'+(_0xd56043*0x64)['toFixed'](0x0)+_0x184de5(0x13b)+_0x229d9c['toFixed'](0x5)+_0x184de5(0x14b)+_0x22a87a+'\x20|\x20Conf:'+(_0x3b6c87*0x64)['toFixed'](0x0)+'%'}),_0x37f751;}['shouldExitByZScore'](_0x18198d){const _0xe0018e=_0x371eb1,_0x9c72d7=this[_0xe0018e(0x12a)][_0xe0018e(0x185)](_0x18198d);if(!_0x9c72d7||_0x9c72d7[_0xe0018e(0x148)]<0x32)return![];const _0x287ecd=this[_0xe0018e(0x132)](_0x9c72d7);return Math[_0xe0018e(0x175)](_0x287ecd)<this[_0xe0018e(0x166)];}[_0x371eb1(0x17e)](_0x42ff12){const _0x453183=_0x371eb1,_0x4bc437=this[_0x453183(0x12a)][_0x453183(0x185)](_0x42ff12),_0x1d439f=this[_0x453183(0x192)][_0x453183(0x185)](_0x42ff12),_0xb50dc9=this['barHistory'][_0x453183(0x185)](_0x42ff12);if(!_0x4bc437||!_0x1d439f||!_0xb50dc9||_0xb50dc9['length']<0x32)return null;const _0x260c32=this['_computeZScore'](_0x4bc437),_0x276e0e=this[_0x453183(0x161)](_0x1d439f),_0x183dd3=this['_computeKyleLambda'](_0xb50dc9),_0x3df13c=this['_computeOrderFlowImbalance'](_0xb50dc9);return{'zscore':Math['min'](0x1,Math[_0x453183(0x175)](_0x260c32)/0x4),'vpin':0x1-_0x276e0e,'kyleLambda':_0x183dd3>0.001?0.5:0.8,'kalman':0.7,'volatility':0.7,'ofi':Math['abs'](_0x3df13c)>0.1?0.8:0.5,'composite':0.7,'raw':{'zscore':_0x260c32,'vpin':_0x276e0e,'kyleLambda':_0x183dd3,'ofi':_0x3df13c}};}[_0x371eb1(0x150)](_0x104d11,_0xe08a26){const _0x2a256e=_0x371eb1,_0xce6de4=this['barHistory'][_0x2a256e(0x185)](_0x104d11)||[];if(_0xce6de4['length']<0x32)return{'ready':![],'message':_0x2a256e(0x188)+_0xce6de4['length']+'/50\x20bars'};const _0x2b1fec=this[_0x2a256e(0x12a)][_0x2a256e(0x185)](_0x104d11)||[],_0x277c7d=this[_0x2a256e(0x192)]['get'](_0x104d11)||[],_0x529871=this[_0x2a256e(0x132)](_0x2b1fec),_0x34b9fc=this['_computeVPIN'](_0x277c7d),_0x2eab93=this['_computeOrderFlowImbalance'](_0xce6de4),_0x4e8e17=this[_0x2a256e(0x126)](_0xce6de4),{regime:_0x42fdf3,params:_0x14e667}=this[_0x2a256e(0x157)](_0x104d11,_0xce6de4);return{'ready':!![],'zScore':_0x529871,'vpin':_0x34b9fc,'ofi':_0x2eab93,'kyleLambda':_0x4e8e17,'regime':_0x42fdf3,'stopTicks':Math[_0x2a256e(0x176)](this[_0x2a256e(0x136)]*_0x14e667['stopMultiplier']),'targetTicks':Math[_0x2a256e(0x176)](this['baseTargetTicks']*_0x14e667['targetMultiplier']),'threshold':_0x14e667['zscoreThreshold'],'barsProcessed':_0xce6de4[_0x2a256e(0x148)],'models':_0x2a256e(0x191)};}[_0x371eb1(0x122)](_0x12a30f){const _0x9df8dc=_0x371eb1;this['recentTrades'][_0x9df8dc(0x179)]({'netPnl':_0x12a30f,'timestamp':Date['now']()});if(this['recentTrades'][_0x9df8dc(0x148)]>0x64)this['recentTrades']['shift']();_0x12a30f>0x0?(this['winStreak']++,this['lossStreak']=0x0,this[_0x9df8dc(0x14c)][_0x9df8dc(0x16e)]++):(this[_0x9df8dc(0x151)]++,this['winStreak']=0x0,this['stats'][_0x9df8dc(0x16b)]++),this[_0x9df8dc(0x14c)][_0x9df8dc(0x147)]++,this[_0x9df8dc(0x14c)][_0x9df8dc(0x120)]+=_0x12a30f,this[_0x9df8dc(0x187)]('log',{'type':'debug','message':'[HQX]\x20Trade\x20result:\x20'+(_0x12a30f>0x0?'WIN':'LOSS')+'\x20$'+_0x12a30f['toFixed'](0x2)+_0x9df8dc(0x168)+(_0x12a30f>0x0?this[_0x9df8dc(0x16c)]:-this['lossStreak'])});}[_0x371eb1(0x18a)](_0x48cb29){return this['barHistory']['get'](_0x48cb29)||[];}[_0x371eb1(0x155)](){return this['stats'];}[_0x371eb1(0x17a)](_0x2db903){const _0x29b967=_0x371eb1;this['barHistory']['set'](_0x2db903,[]),this[_0x29b967(0x12a)]['set'](_0x2db903,[]),this[_0x29b967(0x192)][_0x29b967(0x17d)](_0x2db903,[]),this[_0x29b967(0x133)]['set'](_0x2db903,[]),this['kalmanStates'][_0x29b967(0x17d)](_0x2db903,{'estimate':0x0,'errorCovariance':0x1}),this['emit'](_0x29b967(0x121),{'type':'info','message':'[HQX-UltraScalping]\x20Reset\x20state\x20for\x20'+_0x2db903});}}function _0x4b27(_0x5c3c89,_0x39f9b9){_0x5c3c89=_0x5c3c89-0x11f;const _0x411ae3=_0x411a();let _0x4b2782=_0x411ae3[_0x5c3c89];return _0x4b2782;}class UltraScalpingStrategy extends EventEmitter{constructor(_0x35d97c={}){const _0x594019=_0x371eb1;super(),this['config']=_0x35d97c,this[_0x594019(0x16a)]=new HQXUltraScalping(_0x35d97c),this['strategy']['on']('signal',_0x2742d2=>this['emit']('signal',_0x2742d2)),this['strategy']['on'](_0x594019(0x121),_0x3d29fb=>this['emit']('log',_0x3d29fb));}[_0x371eb1(0x14e)](_0x3b7fbe){return this['strategy']['processTick'](_0x3b7fbe);}[_0x371eb1(0x14a)](_0x56cfa0){return this['strategy']['onTick'](_0x56cfa0);}[_0x371eb1(0x18b)](_0xa016de){const _0x2f46cc=_0x371eb1;return this[_0x2f46cc(0x16a)][_0x2f46cc(0x18b)](_0xa016de);}['processBar'](_0x57a8c0,_0x277b59){const _0x126dbd=_0x371eb1;return this['strategy'][_0x126dbd(0x125)](_0x57a8c0,_0x277b59);}['initialize'](_0x23d70e,_0x18cd66,_0x2a4f00){const _0x2e7df3=_0x371eb1;return this[_0x2e7df3(0x16a)][_0x2e7df3(0x178)](_0x23d70e,_0x18cd66,_0x2a4f00);}['getAnalysisState'](_0x370971,_0x8ee12){return this['strategy']['getAnalysisState'](_0x370971,_0x8ee12);}[_0x371eb1(0x122)](_0x403f97){const _0x35f503=_0x371eb1;return this[_0x35f503(0x16a)][_0x35f503(0x122)](_0x403f97);}['reset'](_0x2adeff){const _0x3e03fc=_0x371eb1;return this['strategy'][_0x3e03fc(0x17a)](_0x2adeff);}['getStats'](){const _0x4c050e=_0x371eb1;return this[_0x4c050e(0x16a)][_0x4c050e(0x155)]();}[_0x371eb1(0x18a)](_0x3bc119){return this['strategy']['getBarHistory'](_0x3bc119);}['getModelValues'](_0x2e2674){const _0x30bb59=_0x371eb1;return this['strategy'][_0x30bb59(0x17e)](_0x2e2674);}['shouldExitByZScore'](_0x451471){const _0x2796fe=_0x371eb1;return this[_0x2796fe(0x16a)]['shouldExitByZScore'](_0x451471);}[_0x371eb1(0x174)](_0x32f693){return null;}}module[_0x371eb1(0x141)]={'HQXUltraScalping':HQXUltraScalping,'UltraScalpingStrategy':UltraScalpingStrategy,'M1':UltraScalpingStrategy,'S1':HQXUltraScalping,'OrderSide':OrderSide,'SignalStrength':SignalStrength};
|
|
1
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
2
|
+
var __commonJS = (cb, mod) => function __require() {
|
|
3
|
+
return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
|
|
4
|
+
};
|
|
5
|
+
|
|
6
|
+
// ultra-scalping/config.js
|
|
7
|
+
var require_config = __commonJS({
|
|
8
|
+
"ultra-scalping/config.js"(exports2, module2) {
|
|
9
|
+
var DEFAULT_CONFIG = {
|
|
10
|
+
// Model Parameters
|
|
11
|
+
zscoreEntryThreshold: 1.5,
|
|
12
|
+
// Live trading threshold (backtest: 2.5)
|
|
13
|
+
zscoreExitThreshold: 0.5,
|
|
14
|
+
vpinWindow: 50,
|
|
15
|
+
vpinToxicThreshold: 0.7,
|
|
16
|
+
// Skip if VPIN > 0.7
|
|
17
|
+
volatilityLookback: 100,
|
|
18
|
+
ofiLookback: 20,
|
|
19
|
+
// Trade Parameters
|
|
20
|
+
baseStopTicks: 8,
|
|
21
|
+
// $40
|
|
22
|
+
baseTargetTicks: 16,
|
|
23
|
+
// $80
|
|
24
|
+
breakevenTicks: 4,
|
|
25
|
+
// Move to BE at +4 ticks
|
|
26
|
+
profitLockPct: 0.5,
|
|
27
|
+
// Lock 50% of profit
|
|
28
|
+
minConfidence: 0.55,
|
|
29
|
+
// Minimum composite confidence
|
|
30
|
+
cooldownMs: 3e4,
|
|
31
|
+
// 30 seconds between signals
|
|
32
|
+
minHoldTimeMs: 1e4,
|
|
33
|
+
// Minimum 10 seconds hold
|
|
34
|
+
// Model Weights (from Python backtest)
|
|
35
|
+
weights: {
|
|
36
|
+
zscore: 0.3,
|
|
37
|
+
// 30%
|
|
38
|
+
ofi: 0.2,
|
|
39
|
+
// 20%
|
|
40
|
+
vpin: 0.15,
|
|
41
|
+
// 15%
|
|
42
|
+
kalman: 0.15,
|
|
43
|
+
// 15%
|
|
44
|
+
kyleLambda: 0.1,
|
|
45
|
+
// 10%
|
|
46
|
+
volatility: 0.1
|
|
47
|
+
// 10%
|
|
48
|
+
},
|
|
49
|
+
// Session (Futures Market Hours - Sunday 18:00 to Friday 17:00 EST)
|
|
50
|
+
session: {
|
|
51
|
+
enabled: false,
|
|
52
|
+
// Trade anytime markets are open
|
|
53
|
+
timezone: "America/New_York"
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
module2.exports = { DEFAULT_CONFIG };
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
// common/types.js
|
|
61
|
+
var require_types = __commonJS({
|
|
62
|
+
"common/types.js"(exports2, module2) {
|
|
63
|
+
var OrderSide2 = { BID: 0, ASK: 1 };
|
|
64
|
+
var SignalStrength2 = { WEAK: 1, MODERATE: 2, STRONG: 3, VERY_STRONG: 4 };
|
|
65
|
+
module2.exports = { OrderSide: OrderSide2, SignalStrength: SignalStrength2 };
|
|
66
|
+
}
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
// ultra-scalping/signal.js
|
|
70
|
+
var require_signal = __commonJS({
|
|
71
|
+
"ultra-scalping/signal.js"(exports2, module2) {
|
|
72
|
+
var { v4: uuidv4 } = require("uuid");
|
|
73
|
+
var { OrderSide: OrderSide2, SignalStrength: SignalStrength2 } = require_types();
|
|
74
|
+
function generateSignal(params) {
|
|
75
|
+
const {
|
|
76
|
+
contractId,
|
|
77
|
+
currentPrice,
|
|
78
|
+
zscore,
|
|
79
|
+
vpin,
|
|
80
|
+
kyleLambda,
|
|
81
|
+
kalmanEstimate,
|
|
82
|
+
regime,
|
|
83
|
+
volParams,
|
|
84
|
+
ofi,
|
|
85
|
+
config,
|
|
86
|
+
tickSize
|
|
87
|
+
} = params;
|
|
88
|
+
const absZscore = Math.abs(zscore);
|
|
89
|
+
if (absZscore < volParams.zscoreThreshold) {
|
|
90
|
+
return null;
|
|
91
|
+
}
|
|
92
|
+
if (vpin > config.vpinToxicThreshold) {
|
|
93
|
+
return null;
|
|
94
|
+
}
|
|
95
|
+
let direction;
|
|
96
|
+
if (zscore < -volParams.zscoreThreshold) {
|
|
97
|
+
direction = "long";
|
|
98
|
+
} else if (zscore > volParams.zscoreThreshold) {
|
|
99
|
+
direction = "short";
|
|
100
|
+
} else {
|
|
101
|
+
return null;
|
|
102
|
+
}
|
|
103
|
+
const ofiConfirms = direction === "long" && ofi > 0.1 || direction === "short" && ofi < -0.1;
|
|
104
|
+
const kalmanDiff = currentPrice - kalmanEstimate;
|
|
105
|
+
const kalmanConfirms = direction === "long" && kalmanDiff < 0 || direction === "short" && kalmanDiff > 0;
|
|
106
|
+
const scores = {
|
|
107
|
+
zscore: Math.min(1, absZscore / 4),
|
|
108
|
+
// Normalize to 0-1
|
|
109
|
+
vpin: 1 - vpin,
|
|
110
|
+
// Lower VPIN = better
|
|
111
|
+
kyleLambda: kyleLambda > 1e-3 ? 0.5 : 0.8,
|
|
112
|
+
// Moderate lambda is good
|
|
113
|
+
kalman: kalmanConfirms ? 0.8 : 0.4,
|
|
114
|
+
volatility: regime === "normal" ? 0.8 : regime === "low" ? 0.7 : 0.6,
|
|
115
|
+
ofi: ofiConfirms ? 0.9 : 0.5,
|
|
116
|
+
composite: 0
|
|
117
|
+
// Calculated below
|
|
118
|
+
};
|
|
119
|
+
scores.composite = scores.zscore * config.weights.zscore + // 30%
|
|
120
|
+
scores.vpin * config.weights.vpin + // 15%
|
|
121
|
+
scores.kyleLambda * config.weights.kyleLambda + // 10%
|
|
122
|
+
scores.kalman * config.weights.kalman + // 15%
|
|
123
|
+
scores.volatility * config.weights.volatility + // 10%
|
|
124
|
+
scores.ofi * config.weights.ofi;
|
|
125
|
+
const confidence = Math.min(1, scores.composite + volParams.confidenceBonus);
|
|
126
|
+
if (confidence < config.minConfidence) {
|
|
127
|
+
return null;
|
|
128
|
+
}
|
|
129
|
+
const stopTicks = Math.round(config.baseStopTicks * volParams.stopMultiplier);
|
|
130
|
+
const targetTicks = Math.round(config.baseTargetTicks * volParams.targetMultiplier);
|
|
131
|
+
const actualStopTicks = Math.max(6, Math.min(12, stopTicks));
|
|
132
|
+
const actualTargetTicks = Math.max(actualStopTicks * 1.5, Math.min(24, targetTicks));
|
|
133
|
+
let stopLoss, takeProfit, beBreakeven, profitLockLevel;
|
|
134
|
+
if (direction === "long") {
|
|
135
|
+
stopLoss = currentPrice - actualStopTicks * tickSize;
|
|
136
|
+
takeProfit = currentPrice + actualTargetTicks * tickSize;
|
|
137
|
+
beBreakeven = currentPrice + config.breakevenTicks * tickSize;
|
|
138
|
+
profitLockLevel = currentPrice + actualTargetTicks * config.profitLockPct * tickSize;
|
|
139
|
+
} else {
|
|
140
|
+
stopLoss = currentPrice + actualStopTicks * tickSize;
|
|
141
|
+
takeProfit = currentPrice - actualTargetTicks * tickSize;
|
|
142
|
+
beBreakeven = currentPrice - config.breakevenTicks * tickSize;
|
|
143
|
+
profitLockLevel = currentPrice - actualTargetTicks * config.profitLockPct * tickSize;
|
|
144
|
+
}
|
|
145
|
+
const riskReward = actualTargetTicks / actualStopTicks;
|
|
146
|
+
const trailTriggerTicks = Math.round(actualTargetTicks * 0.5);
|
|
147
|
+
const trailDistanceTicks = Math.round(actualStopTicks * 0.4);
|
|
148
|
+
let strength = SignalStrength2.MODERATE;
|
|
149
|
+
if (confidence >= 0.85) strength = SignalStrength2.VERY_STRONG;
|
|
150
|
+
else if (confidence >= 0.75) strength = SignalStrength2.STRONG;
|
|
151
|
+
else if (confidence < 0.6) strength = SignalStrength2.WEAK;
|
|
152
|
+
const winProb = 0.5 + (confidence - 0.5) * 0.4;
|
|
153
|
+
const edge = winProb * Math.abs(takeProfit - currentPrice) - (1 - winProb) * Math.abs(currentPrice - stopLoss);
|
|
154
|
+
return {
|
|
155
|
+
id: uuidv4(),
|
|
156
|
+
timestamp: Date.now(),
|
|
157
|
+
symbol: contractId.split(".")[0] || contractId,
|
|
158
|
+
contractId,
|
|
159
|
+
side: direction === "long" ? OrderSide2.BID : OrderSide2.ASK,
|
|
160
|
+
direction,
|
|
161
|
+
strategy: "HQX_ULTRA_SCALPING_6MODELS",
|
|
162
|
+
strength,
|
|
163
|
+
edge,
|
|
164
|
+
confidence,
|
|
165
|
+
entry: currentPrice,
|
|
166
|
+
entryPrice: currentPrice,
|
|
167
|
+
stopLoss,
|
|
168
|
+
takeProfit,
|
|
169
|
+
riskReward,
|
|
170
|
+
stopTicks: actualStopTicks,
|
|
171
|
+
targetTicks: actualTargetTicks,
|
|
172
|
+
trailTriggerTicks,
|
|
173
|
+
trailDistanceTicks,
|
|
174
|
+
beBreakeven,
|
|
175
|
+
profitLockLevel,
|
|
176
|
+
// Model values for debugging/monitoring
|
|
177
|
+
zScore: zscore,
|
|
178
|
+
zScoreExit: config.zscoreExitThreshold,
|
|
179
|
+
vpinValue: vpin,
|
|
180
|
+
kyleLambda,
|
|
181
|
+
kalmanEstimate,
|
|
182
|
+
volatilityRegime: regime,
|
|
183
|
+
ofiValue: ofi,
|
|
184
|
+
models: scores,
|
|
185
|
+
// Order flow confirmation flag
|
|
186
|
+
orderFlowConfirmed: ofiConfirms,
|
|
187
|
+
kalmanConfirmed: kalmanConfirms,
|
|
188
|
+
expires: Date.now() + 6e4
|
|
189
|
+
};
|
|
190
|
+
}
|
|
191
|
+
module2.exports = { generateSignal };
|
|
192
|
+
}
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
// ultra-scalping/models/zscore.js
|
|
196
|
+
var require_zscore = __commonJS({
|
|
197
|
+
"ultra-scalping/models/zscore.js"(exports2, module2) {
|
|
198
|
+
function computeZScore(prices, window = 50) {
|
|
199
|
+
if (prices.length < window) return 0;
|
|
200
|
+
const recentPrices = prices.slice(-window);
|
|
201
|
+
const mean = recentPrices.reduce((a, b) => a + b, 0) / window;
|
|
202
|
+
const variance = recentPrices.reduce((sum, p) => sum + Math.pow(p - mean, 2), 0) / window;
|
|
203
|
+
const std = Math.sqrt(variance);
|
|
204
|
+
if (std < 1e-4) return 0;
|
|
205
|
+
const currentPrice = prices[prices.length - 1];
|
|
206
|
+
return (currentPrice - mean) / std;
|
|
207
|
+
}
|
|
208
|
+
module2.exports = { computeZScore };
|
|
209
|
+
}
|
|
210
|
+
});
|
|
211
|
+
|
|
212
|
+
// ultra-scalping/models/vpin.js
|
|
213
|
+
var require_vpin = __commonJS({
|
|
214
|
+
"ultra-scalping/models/vpin.js"(exports2, module2) {
|
|
215
|
+
function computeVPIN(volumes, vpinWindow = 50) {
|
|
216
|
+
if (volumes.length < vpinWindow) return 0.5;
|
|
217
|
+
const recentVolumes = volumes.slice(-vpinWindow);
|
|
218
|
+
let totalBuy = 0;
|
|
219
|
+
let totalSell = 0;
|
|
220
|
+
for (const v of recentVolumes) {
|
|
221
|
+
totalBuy += v.buy;
|
|
222
|
+
totalSell += v.sell;
|
|
223
|
+
}
|
|
224
|
+
const totalVolume = totalBuy + totalSell;
|
|
225
|
+
if (totalVolume < 1) return 0.5;
|
|
226
|
+
return Math.abs(totalBuy - totalSell) / totalVolume;
|
|
227
|
+
}
|
|
228
|
+
module2.exports = { computeVPIN };
|
|
229
|
+
}
|
|
230
|
+
});
|
|
231
|
+
|
|
232
|
+
// ultra-scalping/models/kyle.js
|
|
233
|
+
var require_kyle = __commonJS({
|
|
234
|
+
"ultra-scalping/models/kyle.js"(exports2, module2) {
|
|
235
|
+
function computeKyleLambda(bars) {
|
|
236
|
+
if (bars.length < 20) return 0;
|
|
237
|
+
const recentBars = bars.slice(-20);
|
|
238
|
+
const priceChanges = [];
|
|
239
|
+
const volumes = [];
|
|
240
|
+
for (let i = 1; i < recentBars.length; i++) {
|
|
241
|
+
priceChanges.push(recentBars[i].close - recentBars[i - 1].close);
|
|
242
|
+
volumes.push(recentBars[i].volume);
|
|
243
|
+
}
|
|
244
|
+
const meanPrice = priceChanges.reduce((a, b) => a + b, 0) / priceChanges.length;
|
|
245
|
+
const meanVol = volumes.reduce((a, b) => a + b, 0) / volumes.length;
|
|
246
|
+
let covariance = 0;
|
|
247
|
+
let varianceVol = 0;
|
|
248
|
+
for (let i = 0; i < priceChanges.length; i++) {
|
|
249
|
+
covariance += (priceChanges[i] - meanPrice) * (volumes[i] - meanVol);
|
|
250
|
+
varianceVol += Math.pow(volumes[i] - meanVol, 2);
|
|
251
|
+
}
|
|
252
|
+
covariance /= priceChanges.length;
|
|
253
|
+
varianceVol /= priceChanges.length;
|
|
254
|
+
if (varianceVol < 1e-4) return 0;
|
|
255
|
+
return Math.abs(covariance / varianceVol);
|
|
256
|
+
}
|
|
257
|
+
module2.exports = { computeKyleLambda };
|
|
258
|
+
}
|
|
259
|
+
});
|
|
260
|
+
|
|
261
|
+
// ultra-scalping/models/kalman.js
|
|
262
|
+
var require_kalman = __commonJS({
|
|
263
|
+
"ultra-scalping/models/kalman.js"(exports2, module2) {
|
|
264
|
+
var KALMAN_PROCESS_NOISE = 0.01;
|
|
265
|
+
var KALMAN_MEASUREMENT_NOISE = 0.1;
|
|
266
|
+
function applyKalmanFilter(state, measurement) {
|
|
267
|
+
if (!state || state.estimate === 0) {
|
|
268
|
+
return {
|
|
269
|
+
estimate: measurement,
|
|
270
|
+
errorCovariance: 1,
|
|
271
|
+
newEstimate: measurement
|
|
272
|
+
};
|
|
273
|
+
}
|
|
274
|
+
const predictedEstimate = state.estimate;
|
|
275
|
+
const predictedCovariance = state.errorCovariance + KALMAN_PROCESS_NOISE;
|
|
276
|
+
const kalmanGain = predictedCovariance / (predictedCovariance + KALMAN_MEASUREMENT_NOISE);
|
|
277
|
+
const newEstimate = predictedEstimate + kalmanGain * (measurement - predictedEstimate);
|
|
278
|
+
const newCovariance = (1 - kalmanGain) * predictedCovariance;
|
|
279
|
+
return {
|
|
280
|
+
estimate: newEstimate,
|
|
281
|
+
errorCovariance: newCovariance,
|
|
282
|
+
newEstimate
|
|
283
|
+
};
|
|
284
|
+
}
|
|
285
|
+
function createKalmanState() {
|
|
286
|
+
return {
|
|
287
|
+
estimate: 0,
|
|
288
|
+
errorCovariance: 1
|
|
289
|
+
};
|
|
290
|
+
}
|
|
291
|
+
module2.exports = {
|
|
292
|
+
applyKalmanFilter,
|
|
293
|
+
createKalmanState,
|
|
294
|
+
KALMAN_PROCESS_NOISE,
|
|
295
|
+
KALMAN_MEASUREMENT_NOISE
|
|
296
|
+
};
|
|
297
|
+
}
|
|
298
|
+
});
|
|
299
|
+
|
|
300
|
+
// ultra-scalping/models/volatility.js
|
|
301
|
+
var require_volatility = __commonJS({
|
|
302
|
+
"ultra-scalping/models/volatility.js"(exports2, module2) {
|
|
303
|
+
function calculateATR(bars, period = 14) {
|
|
304
|
+
if (bars.length < period + 1) return 2.5;
|
|
305
|
+
const trValues = [];
|
|
306
|
+
for (let i = bars.length - period; i < bars.length; i++) {
|
|
307
|
+
const bar = bars[i];
|
|
308
|
+
const prevClose = bars[i - 1].close;
|
|
309
|
+
const tr = Math.max(
|
|
310
|
+
bar.high - bar.low,
|
|
311
|
+
Math.abs(bar.high - prevClose),
|
|
312
|
+
Math.abs(bar.low - prevClose)
|
|
313
|
+
);
|
|
314
|
+
trValues.push(tr);
|
|
315
|
+
}
|
|
316
|
+
return trValues.reduce((a, b) => a + b, 0) / trValues.length;
|
|
317
|
+
}
|
|
318
|
+
function detectVolatilityRegime(atr, atrHistory, tickSize) {
|
|
319
|
+
let atrPercentile = 0.5;
|
|
320
|
+
if (atrHistory.length >= 20) {
|
|
321
|
+
atrPercentile = atrHistory.filter((a) => a <= atr).length / atrHistory.length;
|
|
322
|
+
}
|
|
323
|
+
let regime, params;
|
|
324
|
+
if (atrPercentile < 0.25) {
|
|
325
|
+
regime = "low";
|
|
326
|
+
params = {
|
|
327
|
+
stopMultiplier: 0.8,
|
|
328
|
+
targetMultiplier: 0.9,
|
|
329
|
+
zscoreThreshold: 1.2,
|
|
330
|
+
confidenceBonus: 0.05
|
|
331
|
+
};
|
|
332
|
+
} else if (atrPercentile < 0.75) {
|
|
333
|
+
regime = "normal";
|
|
334
|
+
params = {
|
|
335
|
+
stopMultiplier: 1,
|
|
336
|
+
targetMultiplier: 1,
|
|
337
|
+
zscoreThreshold: 1.5,
|
|
338
|
+
confidenceBonus: 0
|
|
339
|
+
};
|
|
340
|
+
} else {
|
|
341
|
+
regime = "high";
|
|
342
|
+
params = {
|
|
343
|
+
stopMultiplier: 1.3,
|
|
344
|
+
targetMultiplier: 1.2,
|
|
345
|
+
zscoreThreshold: 2,
|
|
346
|
+
confidenceBonus: -0.05
|
|
347
|
+
};
|
|
348
|
+
}
|
|
349
|
+
return { regime, params, atrPercentile };
|
|
350
|
+
}
|
|
351
|
+
module2.exports = { calculateATR, detectVolatilityRegime };
|
|
352
|
+
}
|
|
353
|
+
});
|
|
354
|
+
|
|
355
|
+
// ultra-scalping/models/ofi.js
|
|
356
|
+
var require_ofi = __commonJS({
|
|
357
|
+
"ultra-scalping/models/ofi.js"(exports2, module2) {
|
|
358
|
+
function computeOrderFlowImbalance(bars, lookback = 20) {
|
|
359
|
+
if (bars.length < lookback) return 0;
|
|
360
|
+
const recentBars = bars.slice(-lookback);
|
|
361
|
+
let totalBuyPressure = 0;
|
|
362
|
+
let totalSellPressure = 0;
|
|
363
|
+
for (const bar of recentBars) {
|
|
364
|
+
const barRange = bar.high - bar.low;
|
|
365
|
+
if (barRange > 0) {
|
|
366
|
+
const closePosition = (bar.close - bar.low) / barRange;
|
|
367
|
+
totalBuyPressure += closePosition * bar.volume;
|
|
368
|
+
totalSellPressure += (1 - closePosition) * bar.volume;
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
const totalPressure = totalBuyPressure + totalSellPressure;
|
|
372
|
+
if (totalPressure < 1) return 0;
|
|
373
|
+
return (totalBuyPressure - totalSellPressure) / totalPressure;
|
|
374
|
+
}
|
|
375
|
+
module2.exports = { computeOrderFlowImbalance };
|
|
376
|
+
}
|
|
377
|
+
});
|
|
378
|
+
|
|
379
|
+
// ultra-scalping/models/index.js
|
|
380
|
+
var require_models = __commonJS({
|
|
381
|
+
"ultra-scalping/models/index.js"(exports2, module2) {
|
|
382
|
+
var { computeZScore } = require_zscore();
|
|
383
|
+
var { computeVPIN } = require_vpin();
|
|
384
|
+
var { computeKyleLambda } = require_kyle();
|
|
385
|
+
var { applyKalmanFilter, createKalmanState } = require_kalman();
|
|
386
|
+
var { calculateATR, detectVolatilityRegime } = require_volatility();
|
|
387
|
+
var { computeOrderFlowImbalance } = require_ofi();
|
|
388
|
+
module2.exports = {
|
|
389
|
+
computeZScore,
|
|
390
|
+
computeVPIN,
|
|
391
|
+
computeKyleLambda,
|
|
392
|
+
applyKalmanFilter,
|
|
393
|
+
createKalmanState,
|
|
394
|
+
calculateATR,
|
|
395
|
+
detectVolatilityRegime,
|
|
396
|
+
computeOrderFlowImbalance
|
|
397
|
+
};
|
|
398
|
+
}
|
|
399
|
+
});
|
|
400
|
+
|
|
401
|
+
// ultra-scalping/core.js
|
|
402
|
+
var require_core = __commonJS({
|
|
403
|
+
"ultra-scalping/core.js"(exports2, module2) {
|
|
404
|
+
var EventEmitter2 = require("events");
|
|
405
|
+
var { DEFAULT_CONFIG } = require_config();
|
|
406
|
+
var { generateSignal } = require_signal();
|
|
407
|
+
var {
|
|
408
|
+
computeZScore,
|
|
409
|
+
computeVPIN,
|
|
410
|
+
computeKyleLambda,
|
|
411
|
+
applyKalmanFilter,
|
|
412
|
+
createKalmanState,
|
|
413
|
+
calculateATR,
|
|
414
|
+
detectVolatilityRegime,
|
|
415
|
+
computeOrderFlowImbalance
|
|
416
|
+
} = require_models();
|
|
417
|
+
var HQXUltraScalping2 = class extends EventEmitter2 {
|
|
418
|
+
constructor(config = {}) {
|
|
419
|
+
super();
|
|
420
|
+
this.tickSize = config.tickSize || 0.25;
|
|
421
|
+
this.tickValue = config.tickValue || 5;
|
|
422
|
+
this.config = { ...DEFAULT_CONFIG, ...config };
|
|
423
|
+
this.barHistory = /* @__PURE__ */ new Map();
|
|
424
|
+
this.priceBuffer = /* @__PURE__ */ new Map();
|
|
425
|
+
this.volumeBuffer = /* @__PURE__ */ new Map();
|
|
426
|
+
this.kalmanStates = /* @__PURE__ */ new Map();
|
|
427
|
+
this.atrHistory = /* @__PURE__ */ new Map();
|
|
428
|
+
this.recentTrades = [];
|
|
429
|
+
this.winStreak = 0;
|
|
430
|
+
this.lossStreak = 0;
|
|
431
|
+
this.lastSignalTime = 0;
|
|
432
|
+
this.stats = { signals: 0, trades: 0, wins: 0, losses: 0, pnl: 0 };
|
|
433
|
+
}
|
|
434
|
+
initialize(contractId, tickSize = 0.25, tickValue = 5) {
|
|
435
|
+
this.tickSize = tickSize;
|
|
436
|
+
this.tickValue = tickValue;
|
|
437
|
+
this.barHistory.set(contractId, []);
|
|
438
|
+
this.priceBuffer.set(contractId, []);
|
|
439
|
+
this.volumeBuffer.set(contractId, []);
|
|
440
|
+
this.atrHistory.set(contractId, []);
|
|
441
|
+
this.kalmanStates.set(contractId, createKalmanState());
|
|
442
|
+
this.emit("log", {
|
|
443
|
+
type: "info",
|
|
444
|
+
message: `[HQX-UltraScalping] Initialized for ${contractId}: tick=${tickSize}, value=${tickValue}`
|
|
445
|
+
});
|
|
446
|
+
this.emit("log", {
|
|
447
|
+
type: "info",
|
|
448
|
+
message: `[HQX-UltraScalping] 6 Models: Z-Score(30%), OFI(20%), VPIN(15%), Kalman(15%), Kyle(10%), Vol(10%)`
|
|
449
|
+
});
|
|
450
|
+
}
|
|
451
|
+
processTick(tick) {
|
|
452
|
+
const { contractId, price, volume, timestamp } = tick;
|
|
453
|
+
const bar = {
|
|
454
|
+
timestamp: timestamp || Date.now(),
|
|
455
|
+
open: price,
|
|
456
|
+
high: price,
|
|
457
|
+
low: price,
|
|
458
|
+
close: price,
|
|
459
|
+
volume: volume || 1
|
|
460
|
+
};
|
|
461
|
+
return this.processBar(contractId, bar);
|
|
462
|
+
}
|
|
463
|
+
onTick(tick) {
|
|
464
|
+
return this.processTick(tick);
|
|
465
|
+
}
|
|
466
|
+
onTrade(trade) {
|
|
467
|
+
return this.processTick({
|
|
468
|
+
contractId: trade.contractId || trade.symbol,
|
|
469
|
+
price: trade.price,
|
|
470
|
+
volume: trade.size || trade.volume || 1,
|
|
471
|
+
side: trade.side,
|
|
472
|
+
timestamp: trade.timestamp || Date.now()
|
|
473
|
+
});
|
|
474
|
+
}
|
|
475
|
+
processBar(contractId, bar) {
|
|
476
|
+
let bars = this.barHistory.get(contractId);
|
|
477
|
+
if (!bars) {
|
|
478
|
+
this.initialize(contractId);
|
|
479
|
+
bars = this.barHistory.get(contractId);
|
|
480
|
+
}
|
|
481
|
+
bars.push(bar);
|
|
482
|
+
if (bars.length > 500) bars.shift();
|
|
483
|
+
const prices = this.priceBuffer.get(contractId);
|
|
484
|
+
prices.push(bar.close);
|
|
485
|
+
if (prices.length > 200) prices.shift();
|
|
486
|
+
const volumes = this.volumeBuffer.get(contractId);
|
|
487
|
+
const barRange = bar.high - bar.low;
|
|
488
|
+
let buyVol = bar.volume * 0.5;
|
|
489
|
+
let sellVol = bar.volume * 0.5;
|
|
490
|
+
if (barRange > 0) {
|
|
491
|
+
const closePosition = (bar.close - bar.low) / barRange;
|
|
492
|
+
buyVol = bar.volume * closePosition;
|
|
493
|
+
sellVol = bar.volume * (1 - closePosition);
|
|
494
|
+
}
|
|
495
|
+
volumes.push({ buy: buyVol, sell: sellVol });
|
|
496
|
+
if (volumes.length > 100) volumes.shift();
|
|
497
|
+
if (bars.length < 50) return null;
|
|
498
|
+
const zscore = computeZScore(prices);
|
|
499
|
+
const vpin = computeVPIN(volumes, this.config.vpinWindow);
|
|
500
|
+
const kyleLambda = computeKyleLambda(bars);
|
|
501
|
+
const kalmanState = this.kalmanStates.get(contractId);
|
|
502
|
+
const kalmanResult = applyKalmanFilter(kalmanState, bar.close);
|
|
503
|
+
this.kalmanStates.set(contractId, {
|
|
504
|
+
estimate: kalmanResult.estimate,
|
|
505
|
+
errorCovariance: kalmanResult.errorCovariance
|
|
506
|
+
});
|
|
507
|
+
const kalmanEstimate = kalmanResult.newEstimate;
|
|
508
|
+
const atr = calculateATR(bars);
|
|
509
|
+
const atrHist = this.atrHistory.get(contractId);
|
|
510
|
+
atrHist.push(atr);
|
|
511
|
+
if (atrHist.length > 500) atrHist.shift();
|
|
512
|
+
const { regime, params: volParams } = detectVolatilityRegime(atr, atrHist, this.tickSize);
|
|
513
|
+
const ofi = computeOrderFlowImbalance(bars, this.config.ofiLookback);
|
|
514
|
+
if (Date.now() - this.lastSignalTime < this.config.cooldownMs) {
|
|
515
|
+
return null;
|
|
516
|
+
}
|
|
517
|
+
const signal = generateSignal({
|
|
518
|
+
contractId,
|
|
519
|
+
currentPrice: bar.close,
|
|
520
|
+
zscore,
|
|
521
|
+
vpin,
|
|
522
|
+
kyleLambda,
|
|
523
|
+
kalmanEstimate,
|
|
524
|
+
regime,
|
|
525
|
+
volParams,
|
|
526
|
+
ofi,
|
|
527
|
+
config: this.config,
|
|
528
|
+
tickSize: this.tickSize
|
|
529
|
+
});
|
|
530
|
+
if (signal) {
|
|
531
|
+
this.lastSignalTime = Date.now();
|
|
532
|
+
this.stats.signals++;
|
|
533
|
+
this.emit("signal", {
|
|
534
|
+
side: signal.direction === "long" ? "buy" : "sell",
|
|
535
|
+
action: "open",
|
|
536
|
+
reason: `Z=${zscore.toFixed(2)}, VPIN=${(vpin * 100).toFixed(0)}%, OFI=${(ofi * 100).toFixed(0)}%, cf=${(signal.confidence * 100).toFixed(0)}%`,
|
|
537
|
+
...signal
|
|
538
|
+
});
|
|
539
|
+
this.emit("log", {
|
|
540
|
+
type: "info",
|
|
541
|
+
message: `[HQX] SIGNAL: ${signal.direction.toUpperCase()} @ ${bar.close.toFixed(2)} | Z:${zscore.toFixed(2)} VPIN:${(vpin * 100).toFixed(0)}% OFI:${(ofi * 100).toFixed(0)}% Kyle:${kyleLambda.toFixed(5)} Regime:${regime} | Conf:${(signal.confidence * 100).toFixed(0)}%`
|
|
542
|
+
});
|
|
543
|
+
}
|
|
544
|
+
return signal;
|
|
545
|
+
}
|
|
546
|
+
shouldExitByZScore(contractId) {
|
|
547
|
+
const prices = this.priceBuffer.get(contractId);
|
|
548
|
+
if (!prices || prices.length < 50) return false;
|
|
549
|
+
const zscore = computeZScore(prices);
|
|
550
|
+
return Math.abs(zscore) < this.config.zscoreExitThreshold;
|
|
551
|
+
}
|
|
552
|
+
getModelValues(contractId) {
|
|
553
|
+
const prices = this.priceBuffer.get(contractId);
|
|
554
|
+
const volumes = this.volumeBuffer.get(contractId);
|
|
555
|
+
const bars = this.barHistory.get(contractId);
|
|
556
|
+
if (!prices || !volumes || !bars || bars.length < 50) {
|
|
557
|
+
return null;
|
|
558
|
+
}
|
|
559
|
+
const zscore = computeZScore(prices);
|
|
560
|
+
const vpin = computeVPIN(volumes, this.config.vpinWindow);
|
|
561
|
+
const kyleLambda = computeKyleLambda(bars);
|
|
562
|
+
const ofi = computeOrderFlowImbalance(bars, this.config.ofiLookback);
|
|
563
|
+
return {
|
|
564
|
+
zscore: Math.min(1, Math.abs(zscore) / 4),
|
|
565
|
+
vpin: 1 - vpin,
|
|
566
|
+
kyleLambda: kyleLambda > 1e-3 ? 0.5 : 0.8,
|
|
567
|
+
kalman: 0.7,
|
|
568
|
+
volatility: 0.7,
|
|
569
|
+
ofi: Math.abs(ofi) > 0.1 ? 0.8 : 0.5,
|
|
570
|
+
composite: 0.7,
|
|
571
|
+
raw: { zscore, vpin, kyleLambda, ofi }
|
|
572
|
+
};
|
|
573
|
+
}
|
|
574
|
+
getAnalysisState(contractId, currentPrice) {
|
|
575
|
+
const bars = this.barHistory.get(contractId) || [];
|
|
576
|
+
if (bars.length < 50) {
|
|
577
|
+
return { ready: false, message: `Collecting data... ${bars.length}/50 bars` };
|
|
578
|
+
}
|
|
579
|
+
const prices = this.priceBuffer.get(contractId) || [];
|
|
580
|
+
const volumes = this.volumeBuffer.get(contractId) || [];
|
|
581
|
+
const atrHist = this.atrHistory.get(contractId) || [];
|
|
582
|
+
const zscore = computeZScore(prices);
|
|
583
|
+
const vpin = computeVPIN(volumes, this.config.vpinWindow);
|
|
584
|
+
const ofi = computeOrderFlowImbalance(bars, this.config.ofiLookback);
|
|
585
|
+
const kyleLambda = computeKyleLambda(bars);
|
|
586
|
+
const atr = calculateATR(bars);
|
|
587
|
+
const { regime, params } = detectVolatilityRegime(atr, atrHist, this.tickSize);
|
|
588
|
+
return {
|
|
589
|
+
ready: true,
|
|
590
|
+
zScore: zscore,
|
|
591
|
+
vpin,
|
|
592
|
+
ofi,
|
|
593
|
+
kyleLambda,
|
|
594
|
+
regime,
|
|
595
|
+
stopTicks: Math.round(this.config.baseStopTicks * params.stopMultiplier),
|
|
596
|
+
targetTicks: Math.round(this.config.baseTargetTicks * params.targetMultiplier),
|
|
597
|
+
threshold: params.zscoreThreshold,
|
|
598
|
+
barsProcessed: bars.length,
|
|
599
|
+
models: "6 (Z-Score, VPIN, Kyle, Kalman, Vol, OFI)"
|
|
600
|
+
};
|
|
601
|
+
}
|
|
602
|
+
recordTradeResult(pnl) {
|
|
603
|
+
this.recentTrades.push({ netPnl: pnl, timestamp: Date.now() });
|
|
604
|
+
if (this.recentTrades.length > 100) this.recentTrades.shift();
|
|
605
|
+
if (pnl > 0) {
|
|
606
|
+
this.winStreak++;
|
|
607
|
+
this.lossStreak = 0;
|
|
608
|
+
this.stats.wins++;
|
|
609
|
+
} else {
|
|
610
|
+
this.lossStreak++;
|
|
611
|
+
this.winStreak = 0;
|
|
612
|
+
this.stats.losses++;
|
|
613
|
+
}
|
|
614
|
+
this.stats.trades++;
|
|
615
|
+
this.stats.pnl += pnl;
|
|
616
|
+
this.emit("log", {
|
|
617
|
+
type: "debug",
|
|
618
|
+
message: `[HQX] Trade result: ${pnl > 0 ? "WIN" : "LOSS"} $${pnl.toFixed(2)}, streak: ${pnl > 0 ? this.winStreak : -this.lossStreak}`
|
|
619
|
+
});
|
|
620
|
+
}
|
|
621
|
+
getBarHistory(contractId) {
|
|
622
|
+
return this.barHistory.get(contractId) || [];
|
|
623
|
+
}
|
|
624
|
+
getStats() {
|
|
625
|
+
return this.stats;
|
|
626
|
+
}
|
|
627
|
+
reset(contractId) {
|
|
628
|
+
this.barHistory.set(contractId, []);
|
|
629
|
+
this.priceBuffer.set(contractId, []);
|
|
630
|
+
this.volumeBuffer.set(contractId, []);
|
|
631
|
+
this.atrHistory.set(contractId, []);
|
|
632
|
+
this.kalmanStates.set(contractId, createKalmanState());
|
|
633
|
+
this.emit("log", {
|
|
634
|
+
type: "info",
|
|
635
|
+
message: `[HQX-UltraScalping] Reset state for ${contractId}`
|
|
636
|
+
});
|
|
637
|
+
}
|
|
638
|
+
};
|
|
639
|
+
module2.exports = { HQXUltraScalping: HQXUltraScalping2 };
|
|
640
|
+
}
|
|
641
|
+
});
|
|
642
|
+
|
|
643
|
+
// ultra-scalping/index.js
|
|
644
|
+
var EventEmitter = require("events");
|
|
645
|
+
var { HQXUltraScalping } = require_core();
|
|
646
|
+
var { OrderSide, SignalStrength } = require_types();
|
|
647
|
+
var UltraScalpingStrategy = class extends EventEmitter {
|
|
648
|
+
constructor(config = {}) {
|
|
649
|
+
super();
|
|
650
|
+
this.config = config;
|
|
651
|
+
this.strategy = new HQXUltraScalping(config);
|
|
652
|
+
this.strategy.on("signal", (sig) => this.emit("signal", sig));
|
|
653
|
+
this.strategy.on("log", (log) => this.emit("log", log));
|
|
654
|
+
}
|
|
655
|
+
// Interface methods (compatible with M1)
|
|
656
|
+
processTick(tick) {
|
|
657
|
+
return this.strategy.processTick(tick);
|
|
658
|
+
}
|
|
659
|
+
onTick(tick) {
|
|
660
|
+
return this.strategy.onTick(tick);
|
|
661
|
+
}
|
|
662
|
+
onTrade(trade) {
|
|
663
|
+
return this.strategy.onTrade(trade);
|
|
664
|
+
}
|
|
665
|
+
processBar(contractId, bar) {
|
|
666
|
+
return this.strategy.processBar(contractId, bar);
|
|
667
|
+
}
|
|
668
|
+
initialize(contractId, tickSize, tickValue) {
|
|
669
|
+
return this.strategy.initialize(contractId, tickSize, tickValue);
|
|
670
|
+
}
|
|
671
|
+
getAnalysisState(contractId, price) {
|
|
672
|
+
return this.strategy.getAnalysisState(contractId, price);
|
|
673
|
+
}
|
|
674
|
+
recordTradeResult(pnl) {
|
|
675
|
+
return this.strategy.recordTradeResult(pnl);
|
|
676
|
+
}
|
|
677
|
+
reset(contractId) {
|
|
678
|
+
return this.strategy.reset(contractId);
|
|
679
|
+
}
|
|
680
|
+
getStats() {
|
|
681
|
+
return this.strategy.getStats();
|
|
682
|
+
}
|
|
683
|
+
getBarHistory(contractId) {
|
|
684
|
+
return this.strategy.getBarHistory(contractId);
|
|
685
|
+
}
|
|
686
|
+
getModelValues(contractId) {
|
|
687
|
+
return this.strategy.getModelValues(contractId);
|
|
688
|
+
}
|
|
689
|
+
shouldExitByZScore(contractId) {
|
|
690
|
+
return this.strategy.shouldExitByZScore(contractId);
|
|
691
|
+
}
|
|
692
|
+
generateSignal(params) {
|
|
693
|
+
return null;
|
|
694
|
+
}
|
|
695
|
+
// Signals come from processBar
|
|
696
|
+
};
|
|
697
|
+
module.exports = {
|
|
698
|
+
HQXUltraScalping,
|
|
699
|
+
UltraScalpingStrategy,
|
|
700
|
+
// Aliases for backward compatibility
|
|
701
|
+
M1: UltraScalpingStrategy,
|
|
702
|
+
S1: HQXUltraScalping,
|
|
703
|
+
OrderSide,
|
|
704
|
+
SignalStrength
|
|
705
|
+
};
|