hedgequantx 2.7.15 → 2.7.17

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.
@@ -0,0 +1,173 @@
1
+ /**
2
+ * Mathematical Models for HQX Ultra Scalping
3
+ * @module lib/m/s1-models
4
+ *
5
+ * 6 Mathematical Models:
6
+ * 1. Z-Score Mean Reversion
7
+ * 2. VPIN (Volume-Synchronized Probability of Informed Trading)
8
+ * 3. Kyle's Lambda (Price Impact / Liquidity)
9
+ * 4. Kalman Filter (Signal Extraction)
10
+ * 5. Volatility Regime Detection
11
+ * 6. Order Flow Imbalance (OFI)
12
+ */
13
+
14
+ /**
15
+ * MODEL 1: Z-SCORE MEAN REVERSION
16
+ * @param {number[]} prices - Price array
17
+ * @param {number} window - Lookback window
18
+ * @returns {number} Z-Score value
19
+ */
20
+ function computeZScore(prices, window = 50) {
21
+ if (prices.length < window) return 0;
22
+ const recentPrices = prices.slice(-window);
23
+ const mean = recentPrices.reduce((a, b) => a + b, 0) / window;
24
+ const variance = recentPrices.reduce((sum, p) => sum + Math.pow(p - mean, 2), 0) / window;
25
+ const std = Math.sqrt(variance);
26
+ if (std < 0.0001) return 0;
27
+ return (prices[prices.length - 1] - mean) / std;
28
+ }
29
+
30
+ /**
31
+ * MODEL 2: VPIN
32
+ * @param {Array<{buy: number, sell: number}>} volumes - Volume data
33
+ * @param {number} vpinWindow - VPIN window size
34
+ * @returns {number} VPIN value (0-1)
35
+ */
36
+ function computeVPIN(volumes, vpinWindow = 50) {
37
+ if (volumes.length < vpinWindow) return 0.5;
38
+ const recent = volumes.slice(-vpinWindow);
39
+ let totalBuy = 0, totalSell = 0;
40
+ for (const v of recent) { totalBuy += v.buy; totalSell += v.sell; }
41
+ const total = totalBuy + totalSell;
42
+ if (total < 1) return 0.5;
43
+ return Math.abs(totalBuy - totalSell) / total;
44
+ }
45
+
46
+ /**
47
+ * MODEL 3: KYLE'S LAMBDA
48
+ * @param {Array} bars - Bar data
49
+ * @returns {number} Kyle's Lambda value
50
+ */
51
+ function computeKyleLambda(bars) {
52
+ if (bars.length < 20) return 0;
53
+ const recent = bars.slice(-20);
54
+ const priceChanges = [], vols = [];
55
+ for (let i = 1; i < recent.length; i++) {
56
+ priceChanges.push(recent[i].close - recent[i - 1].close);
57
+ vols.push(recent[i].volume);
58
+ }
59
+ const meanP = priceChanges.reduce((a, b) => a + b, 0) / priceChanges.length;
60
+ const meanV = vols.reduce((a, b) => a + b, 0) / vols.length;
61
+ let cov = 0, varV = 0;
62
+ for (let i = 0; i < priceChanges.length; i++) {
63
+ cov += (priceChanges[i] - meanP) * (vols[i] - meanV);
64
+ varV += Math.pow(vols[i] - meanV, 2);
65
+ }
66
+ cov /= priceChanges.length;
67
+ varV /= priceChanges.length;
68
+ if (varV < 0.0001) return 0;
69
+ return Math.abs(cov / varV);
70
+ }
71
+
72
+ /**
73
+ * MODEL 4: KALMAN FILTER
74
+ * @param {Object} state - {estimate, errorCovariance}
75
+ * @param {number} measurement - New measurement
76
+ * @param {number} processNoise - Process noise
77
+ * @param {number} measurementNoise - Measurement noise
78
+ * @returns {Object} Updated state and estimate
79
+ */
80
+ function applyKalmanFilter(state, measurement, processNoise = 0.01, measurementNoise = 0.1) {
81
+ if (!state || state.estimate === 0) {
82
+ return {
83
+ state: { estimate: measurement, errorCovariance: 1.0 },
84
+ estimate: measurement
85
+ };
86
+ }
87
+ const predictedEstimate = state.estimate;
88
+ const predictedCovariance = state.errorCovariance + processNoise;
89
+ const kalmanGain = predictedCovariance / (predictedCovariance + measurementNoise);
90
+ const newEstimate = predictedEstimate + kalmanGain * (measurement - predictedEstimate);
91
+ const newCovariance = (1 - kalmanGain) * predictedCovariance;
92
+ return {
93
+ state: { estimate: newEstimate, errorCovariance: newCovariance },
94
+ estimate: newEstimate
95
+ };
96
+ }
97
+
98
+ /**
99
+ * Calculate ATR
100
+ * @param {Array} bars - Bar data
101
+ * @param {number} period - ATR period
102
+ * @returns {number} ATR value
103
+ */
104
+ function calculateATR(bars, period = 14) {
105
+ if (bars.length < period + 1) return 2.5;
106
+ const trValues = [];
107
+ for (let i = bars.length - period; i < bars.length; i++) {
108
+ const bar = bars[i];
109
+ const prevClose = bars[i - 1].close;
110
+ const tr = Math.max(bar.high - bar.low, Math.abs(bar.high - prevClose), Math.abs(bar.low - prevClose));
111
+ trValues.push(tr);
112
+ }
113
+ return trValues.reduce((a, b) => a + b, 0) / trValues.length;
114
+ }
115
+
116
+ /**
117
+ * MODEL 5: VOLATILITY REGIME
118
+ * @param {Array} atrHistory - ATR history
119
+ * @param {number} currentATR - Current ATR
120
+ * @returns {Object} Regime and parameters
121
+ */
122
+ function detectVolatilityRegime(atrHistory, currentATR) {
123
+ let atrPercentile = 0.5;
124
+ if (atrHistory.length >= 20) {
125
+ atrPercentile = atrHistory.filter(a => a <= currentATR).length / atrHistory.length;
126
+ }
127
+
128
+ let regime, params;
129
+ if (atrPercentile < 0.25) {
130
+ regime = 'low';
131
+ params = { stopMultiplier: 0.8, targetMultiplier: 0.9, zscoreThreshold: 1.2, confidenceBonus: 0.05 };
132
+ } else if (atrPercentile < 0.75) {
133
+ regime = 'normal';
134
+ params = { stopMultiplier: 1.0, targetMultiplier: 1.0, zscoreThreshold: 1.5, confidenceBonus: 0.0 };
135
+ } else {
136
+ regime = 'high';
137
+ params = { stopMultiplier: 1.3, targetMultiplier: 1.2, zscoreThreshold: 2.0, confidenceBonus: -0.05 };
138
+ }
139
+ return { regime, params };
140
+ }
141
+
142
+ /**
143
+ * MODEL 6: ORDER FLOW IMBALANCE
144
+ * @param {Array} bars - Bar data
145
+ * @param {number} ofiLookback - Lookback period
146
+ * @returns {number} OFI value (-1 to 1)
147
+ */
148
+ function computeOrderFlowImbalance(bars, ofiLookback = 20) {
149
+ if (bars.length < ofiLookback) return 0;
150
+ const recent = bars.slice(-ofiLookback);
151
+ let buyPressure = 0, sellPressure = 0;
152
+ for (const bar of recent) {
153
+ const range = bar.high - bar.low;
154
+ if (range > 0) {
155
+ const closePos = (bar.close - bar.low) / range;
156
+ buyPressure += closePos * bar.volume;
157
+ sellPressure += (1 - closePos) * bar.volume;
158
+ }
159
+ }
160
+ const total = buyPressure + sellPressure;
161
+ if (total < 1) return 0;
162
+ return (buyPressure - sellPressure) / total;
163
+ }
164
+
165
+ module.exports = {
166
+ computeZScore,
167
+ computeVPIN,
168
+ computeKyleLambda,
169
+ applyKalmanFilter,
170
+ calculateATR,
171
+ detectVolatilityRegime,
172
+ computeOrderFlowImbalance,
173
+ };