garch 1.0.2 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "garch",
3
- "version": "1.0.2",
3
+ "version": "1.1.0",
4
4
  "description": "GARCH and EGARCH volatility models for TypeScript",
5
5
  "type": "module",
6
6
  "main": "./build/index.cjs",
@@ -37,6 +37,7 @@
37
37
  "devDependencies": {
38
38
  "@rollup/plugin-typescript": "^12.3.0",
39
39
  "@types/node": "^20.10.0",
40
+ "@vitest/coverage-v8": "^1.6.1",
40
41
  "rollup": "^4.57.1",
41
42
  "rollup-plugin-dts": "^6.3.0",
42
43
  "rollup-plugin-peer-deps-external": "^2.2.4",
package/types.d.ts CHANGED
@@ -13,6 +13,7 @@ interface GarchParams {
13
13
  persistence: number;
14
14
  unconditionalVariance: number;
15
15
  annualizedVol: number;
16
+ df: number;
16
17
  }
17
18
  interface EgarchParams {
18
19
  omega: number;
@@ -23,6 +24,18 @@ interface EgarchParams {
23
24
  unconditionalVariance: number;
24
25
  annualizedVol: number;
25
26
  leverageEffect: number;
27
+ df: number;
28
+ }
29
+ interface GjrGarchParams {
30
+ omega: number;
31
+ alpha: number;
32
+ gamma: number;
33
+ beta: number;
34
+ persistence: number;
35
+ unconditionalVariance: number;
36
+ annualizedVol: number;
37
+ leverageEffect: number;
38
+ df: number;
26
39
  }
27
40
  interface CalibrationResult<T> {
28
41
  params: T;
@@ -45,6 +58,28 @@ interface LeverageStats {
45
58
  ratio: number;
46
59
  recommendation: 'garch' | 'egarch';
47
60
  }
61
+ interface HarRvParams {
62
+ beta0: number;
63
+ betaShort: number;
64
+ betaMedium: number;
65
+ betaLong: number;
66
+ persistence: number;
67
+ unconditionalVariance: number;
68
+ annualizedVol: number;
69
+ r2: number;
70
+ df: number;
71
+ }
72
+ interface NoVaSParams {
73
+ weights: number[];
74
+ forecastWeights: number[];
75
+ lags: number;
76
+ persistence: number;
77
+ unconditionalVariance: number;
78
+ annualizedVol: number;
79
+ dSquared: number;
80
+ r2: number;
81
+ df: number;
82
+ }
48
83
  interface OptimizerResult {
49
84
  x: number[];
50
85
  fx: number;
@@ -70,6 +105,7 @@ interface GarchOptions {
70
105
  */
71
106
  declare class Garch {
72
107
  private returns;
108
+ private rv;
73
109
  private periodsPerYear;
74
110
  private initialVariance;
75
111
  constructor(data: Candle[] | number[], options?: GarchOptions);
@@ -118,10 +154,11 @@ interface EgarchOptions {
118
154
  * - α (alpha): magnitude effect
119
155
  * - γ (gamma): leverage effect (typically negative)
120
156
  * - β (beta): persistence
121
- * - E[|z|] = (2/π) for standard normal
157
+ * - E[|z|] = expectedAbsStudentT(df) for Student-t(df)
122
158
  */
123
159
  declare class Egarch {
124
160
  private returns;
161
+ private rv;
125
162
  private periodsPerYear;
126
163
  private initialVariance;
127
164
  constructor(data: Candle[] | number[], options?: EgarchOptions);
@@ -158,6 +195,195 @@ declare class Egarch {
158
195
  */
159
196
  declare function calibrateEgarch(data: Candle[] | number[], options?: EgarchOptions): CalibrationResult<EgarchParams>;
160
197
 
198
+ interface HarRvOptions {
199
+ periodsPerYear?: number;
200
+ shortLag?: number;
201
+ mediumLag?: number;
202
+ longLag?: number;
203
+ }
204
+ /**
205
+ * HAR-RV model (Corsi, 2009)
206
+ *
207
+ * RV_{t+1} = β₀ + β₁·RV_short + β₂·RV_medium + β₃·RV_long + ε
208
+ *
209
+ * where:
210
+ * - RV_short = mean(rv[t-s+1..t]) (default s=1)
211
+ * - RV_medium = mean(rv[t-m+1..t]) (default m=5)
212
+ * - RV_long = mean(rv[t-l+1..t]) (default l=22)
213
+ * - rv[t] = Parkinson(candle_t) for OHLC data, r[t]² for prices-only
214
+ *
215
+ * Parkinson (1980): RV = (1/(4·ln2))·(ln(H/L))², ~5x more efficient than r².
216
+ *
217
+ * Uses OLS for estimation — closed-form, always converges.
218
+ */
219
+ declare class HarRv {
220
+ private returns;
221
+ private rv;
222
+ private periodsPerYear;
223
+ private shortLag;
224
+ private mediumLag;
225
+ private longLag;
226
+ constructor(data: Candle[] | number[], options?: HarRvOptions);
227
+ /**
228
+ * Calibrate HAR-RV via OLS.
229
+ */
230
+ fit(): CalibrationResult<HarRvParams>;
231
+ /**
232
+ * Internal: compute variance series from beta vector.
233
+ */
234
+ private getVarianceSeriesInternal;
235
+ /**
236
+ * Calculate conditional variance series given parameters.
237
+ */
238
+ getVarianceSeries(params: HarRvParams): number[];
239
+ /**
240
+ * Forecast variance forward.
241
+ *
242
+ * Uses iterative substitution: each forecast step feeds back
243
+ * into the rolling RV components for subsequent steps.
244
+ */
245
+ forecast(params: HarRvParams, steps?: number): VolatilityForecast;
246
+ /**
247
+ * Get the return series.
248
+ */
249
+ getReturns(): number[];
250
+ /**
251
+ * Get realized variance series (squared returns).
252
+ */
253
+ getRv(): number[];
254
+ }
255
+ /**
256
+ * Convenience function to calibrate HAR-RV from candles or prices.
257
+ */
258
+ declare function calibrateHarRv(data: Candle[] | number[], options?: HarRvOptions): CalibrationResult<HarRvParams>;
259
+
260
+ interface GjrGarchOptions {
261
+ periodsPerYear?: number;
262
+ maxIter?: number;
263
+ tol?: number;
264
+ }
265
+ /**
266
+ * GJR-GARCH(1,1) model (Glosten, Jagannathan & Runkle, 1993)
267
+ *
268
+ * σ²ₜ = ω + α·ε²ₜ₋₁ + γ·ε²ₜ₋₁·I(rₜ₋₁<0) + β·σ²ₜ₋₁
269
+ *
270
+ * where:
271
+ * - ω (omega) > 0: constant term
272
+ * - α (alpha) ≥ 0: symmetric shock response
273
+ * - γ (gamma) ≥ 0: asymmetric leverage coefficient
274
+ * - β (beta) ≥ 0: persistence
275
+ * - I(r<0) = 1 when return is negative, 0 otherwise
276
+ * - Stationarity: α + γ/2 + β < 1
277
+ *
278
+ * With Candle[] input, ε² is replaced by Parkinson per-candle RV.
279
+ * Leverage direction still comes from close-to-close return sign.
280
+ */
281
+ declare class GjrGarch {
282
+ private returns;
283
+ private rv;
284
+ private periodsPerYear;
285
+ private initialVariance;
286
+ constructor(data: Candle[] | number[], options?: GjrGarchOptions);
287
+ /**
288
+ * Calibrate GJR-GARCH(1,1) parameters using Maximum Likelihood Estimation
289
+ */
290
+ fit(options?: {
291
+ maxIter?: number;
292
+ tol?: number;
293
+ }): CalibrationResult<GjrGarchParams>;
294
+ /**
295
+ * Calculate conditional variance series given parameters
296
+ */
297
+ getVarianceSeries(params: GjrGarchParams): number[];
298
+ /**
299
+ * Forecast variance forward
300
+ */
301
+ forecast(params: GjrGarchParams, steps?: number): VolatilityForecast;
302
+ /**
303
+ * Get the return series
304
+ */
305
+ getReturns(): number[];
306
+ /**
307
+ * Get initial variance estimate
308
+ */
309
+ getInitialVariance(): number;
310
+ }
311
+ /**
312
+ * Convenience function to calibrate GJR-GARCH(1,1) from candles
313
+ */
314
+ declare function calibrateGjrGarch(data: Candle[] | number[], options?: GjrGarchOptions): CalibrationResult<GjrGarchParams>;
315
+
316
+ interface NoVaSOptions {
317
+ periodsPerYear?: number;
318
+ lags?: number;
319
+ maxIter?: number;
320
+ tol?: number;
321
+ }
322
+ /**
323
+ * NoVaS (Normalizing and Variance-Stabilizing) model (Politis, 2003)
324
+ *
325
+ * Two-stage calibration:
326
+ *
327
+ * Stage 1 — D² minimization (model-free normality):
328
+ * σ²_t = a_0 + a_1·X²_{t-1} + a_2·X²_{t-2} + ... + a_p·X²_{t-p}
329
+ * W_t = X_t / σ_t
330
+ * Minimize D² = S² + (K - 3)² where S, K are skewness and kurtosis of {W_t}.
331
+ *
332
+ * Stage 2 — OLS rescaling (forecast-optimal):
333
+ * RV_{t+1} = β₀ + β₁·σ²_t(D²)
334
+ * The D²-discovered σ²_t acts as a data-driven smoother over RV lags.
335
+ * OLS rescales it to minimize forecast error (RSS on RV).
336
+ * Only 2 parameters → robust on small samples with noisy per-candle RV.
337
+ *
338
+ * D² discovers lag structure (model-free). OLS rescales for prediction accuracy.
339
+ * Both weight sets are stored in params — no identity loss.
340
+ */
341
+ declare class NoVaS {
342
+ private returns;
343
+ private rv;
344
+ private periodsPerYear;
345
+ private lags;
346
+ constructor(data: Candle[] | number[], options?: NoVaSOptions);
347
+ /**
348
+ * Calibrate NoVaS weights via two-stage procedure:
349
+ * Stage 1: D² minimization (normality of W_t)
350
+ * Stage 2: OLS rescaling of D²-variance (forecast-optimal)
351
+ */
352
+ fit(options?: {
353
+ maxIter?: number;
354
+ tol?: number;
355
+ }): CalibrationResult<NoVaSParams>;
356
+ /**
357
+ * Internal: compute variance series from D² weight vector.
358
+ */
359
+ private getVarianceSeriesInternal;
360
+ /**
361
+ * Calculate conditional variance series using D² weights (normalization identity).
362
+ */
363
+ getVarianceSeries(params: NoVaSParams): number[];
364
+ /**
365
+ * Calculate forecast variance series using OLS-rescaled D² variance.
366
+ * forecast_σ²_t = β₀ + β₁·σ²_t(D²)
367
+ * Used for QLIKE model comparison — measures forecast quality.
368
+ */
369
+ getForecastVarianceSeries(params: NoVaSParams): number[];
370
+ /**
371
+ * Forecast variance forward using OLS-rescaled D² weights.
372
+ *
373
+ * Step 1: compute D²-based σ²_{t+h} using D² weights
374
+ * Step 2: rescale via β₀ + β₁·σ²_{t+h}
375
+ */
376
+ forecast(params: NoVaSParams, steps?: number): VolatilityForecast;
377
+ /**
378
+ * Get the return series.
379
+ */
380
+ getReturns(): number[];
381
+ }
382
+ /**
383
+ * Convenience function to calibrate NoVaS from candles or prices.
384
+ */
385
+ declare function calibrateNoVaS(data: Candle[] | number[], options?: NoVaSOptions): CalibrationResult<NoVaSParams>;
386
+
161
387
  /**
162
388
  * Calculate log returns from candles
163
389
  */
@@ -178,11 +404,123 @@ declare function sampleVarianceWithMean(returns: number[]): number;
178
404
  * Check for leverage effect (asymmetry in volatility)
179
405
  */
180
406
  declare function checkLeverageEffect(returns: number[]): LeverageStats;
407
+ /**
408
+ * Garman-Klass (1980) variance estimator using OHLC data.
409
+ *
410
+ * σ²_GK = (1/n) Σ [ 0.5·(ln(H/L))² − (2ln2−1)·(ln(C/O))² ]
411
+ *
412
+ * ~5x more efficient than close-to-close variance.
413
+ */
414
+ declare function garmanKlassVariance(candles: Candle[]): number;
415
+ /**
416
+ * Yang-Zhang (2000) variance estimator using OHLC data.
417
+ *
418
+ * Combines overnight (open vs prev close), open-to-close,
419
+ * and Rogers-Satchell components. More efficient than Garman-Klass
420
+ * and handles overnight gaps (relevant for stocks).
421
+ *
422
+ * σ²_YZ = σ²_overnight + k·σ²_close + (1−k)·σ²_RS
423
+ */
424
+ declare function yangZhangVariance(candles: Candle[]): number;
425
+ /**
426
+ * Per-candle Parkinson (1980) realized variance proxy.
427
+ *
428
+ * RV_i = (1/(4·ln2)) · ln(H/L)²
429
+ *
430
+ * ~5× more efficient than squared returns. Falls back to r² when H === L.
431
+ * rv[i] aligned with returns[i], using candles[i+1]'s OHLC.
432
+ */
433
+ declare function perCandleParkinson(candles: Candle[], returns: number[]): number[];
181
434
  /**
182
435
  * Expected value of |Z| where Z ~ N(0,1)
183
436
  * E[|Z|] = sqrt(2/π)
184
437
  */
185
438
  declare const EXPECTED_ABS_NORMAL: number;
439
+ /**
440
+ * Ljung-Box test for autocorrelation.
441
+ *
442
+ * Q = n(n+2) Σ(k=1..m) ρ²_k / (n−k)
443
+ *
444
+ * Under H₀ (no autocorrelation), Q ~ χ²(m).
445
+ * Use on squared standardized residuals to test GARCH adequacy.
446
+ */
447
+ declare function ljungBox(data: number[], maxLag: number): {
448
+ statistic: number;
449
+ pValue: number;
450
+ };
451
+ /**
452
+ * Log-Gamma function via Lanczos approximation (g=7, n=9).
453
+ * Accurate to ~15 digits for x > 0.
454
+ */
455
+ declare function logGamma(x: number): number;
456
+ /**
457
+ * Per-observation Student-t negative log-likelihood contribution.
458
+ *
459
+ * For standardized t(df) with variance σ²_t:
460
+ * -LL_i = 0.5·ln(σ²_t) + ((df+1)/2)·ln(1 + r²_t / ((df-2)·σ²_t))
461
+ * - lnΓ((df+1)/2) + lnΓ(df/2) + 0.5·ln(π·(df-2))
462
+ *
463
+ * Returns the per-observation neg-LL (without the constant terms).
464
+ * Caller accumulates and adds the constant once.
465
+ */
466
+ declare function studentTNegLL(returns: number[], varianceSeries: number[], df: number): number;
467
+ /**
468
+ * E[|Z|] where Z follows a standardized Student-t(df) distribution (variance = 1).
469
+ *
470
+ * E[|Z|] = √((df-2)/π) · Γ((df-1)/2) / Γ(df/2)
471
+ *
472
+ * Converges to √(2/π) as df → ∞ (Gaussian limit).
473
+ */
474
+ declare function expectedAbsStudentT(df: number): number;
475
+ /**
476
+ * 1D grid search for optimal df that minimizes Student-t neg-LL.
477
+ * Used by HAR-RV and NoVaS where df is profiled after main optimization.
478
+ */
479
+ declare function profileStudentTDf(returns: number[], varianceSeries: number[]): number;
480
+ /**
481
+ * QLIKE loss (Patton 2011) — standard loss function for volatility forecasts.
482
+ *
483
+ * QLIKE = (1/n) · Σ (RV_t / σ²_t − log(RV_t / σ²_t) − 1)
484
+ *
485
+ * Lower = better forecast. Neutral to calibration method — judges only
486
+ * how well the variance series predicts realized variance, regardless
487
+ * of how the model was calibrated (MLE, OLS, D², etc.).
488
+ */
489
+ declare function qlike(varianceSeries: number[], rv: number[]): number;
490
+
491
+ type CandleInterval = '1m' | '3m' | '5m' | '15m' | '30m' | '1h' | '2h' | '4h' | '6h' | '8h';
492
+ interface PredictionResult {
493
+ currentPrice: number;
494
+ sigma: number;
495
+ move: number;
496
+ upperPrice: number;
497
+ lowerPrice: number;
498
+ modelType: 'garch' | 'egarch' | 'gjr-garch' | 'har-rv' | 'novas';
499
+ reliable: boolean;
500
+ }
501
+ /**
502
+ * Forecast expected price range for t+1 (next candle).
503
+ *
504
+ * Auto-selects GARCH or EGARCH based on leverage effect.
505
+ * Returns ±1σ price corridor so you can set SL/TP yourself.
506
+ */
507
+ declare function predict(candles: Candle[], interval: CandleInterval, currentPrice?: number): PredictionResult;
508
+ /**
509
+ * Forecast expected price range over multiple candles.
510
+ *
511
+ * Cumulative σ = √(σ₁² + σ₂² + ... + σₙ²) — total expected move over N periods.
512
+ * Use for swing trades where you hold across multiple candles.
513
+ */
514
+ declare function predictRange(candles: Candle[], interval: CandleInterval, steps: number, currentPrice?: number): PredictionResult;
515
+ /**
516
+ * Walk-forward backtest of predict.
517
+ *
518
+ * Window is computed automatically: 75% of candles for fitting, 25% for testing.
519
+ * Throws if not enough candles for the given interval.
520
+ * Returns true if the model's hit rate meets the required threshold.
521
+ * Default threshold is 68% (±1σ should contain ~68% of moves).
522
+ */
523
+ declare function backtest(candles: Candle[], interval: CandleInterval, requiredPercent?: number): boolean;
186
524
 
187
525
  declare function nelderMead(fn: (x: number[]) => number, x0: number[], options?: {
188
526
  maxIter?: number;
@@ -192,6 +530,11 @@ declare function nelderMead(fn: (x: number[]) => number, x0: number[], options?:
192
530
  rho?: number;
193
531
  sigma?: number;
194
532
  }): OptimizerResult;
533
+ declare function nelderMeadMultiStart(fn: (x: number[]) => number, x0: number[], options?: {
534
+ maxIter?: number;
535
+ tol?: number;
536
+ restarts?: number;
537
+ }): OptimizerResult;
195
538
 
196
- export { EXPECTED_ABS_NORMAL, Egarch, Garch, calculateReturns, calculateReturnsFromPrices, calibrateEgarch, calibrateGarch, checkLeverageEffect, nelderMead, sampleVariance, sampleVarianceWithMean };
197
- export type { CalibrationResult, Candle, EgarchOptions, EgarchParams, GarchOptions, GarchParams, LeverageStats, OptimizerResult, VolatilityForecast };
539
+ export { EXPECTED_ABS_NORMAL, Egarch, Garch, GjrGarch, HarRv, NoVaS, backtest, calculateReturns, calculateReturnsFromPrices, calibrateEgarch, calibrateGarch, calibrateGjrGarch, calibrateHarRv, calibrateNoVaS, checkLeverageEffect, expectedAbsStudentT, garmanKlassVariance, ljungBox, logGamma, nelderMead, nelderMeadMultiStart, perCandleParkinson, predict, predictRange, profileStudentTDf, qlike, sampleVariance, sampleVarianceWithMean, studentTNegLL, yangZhangVariance };
540
+ export type { CalibrationResult, Candle, CandleInterval, EgarchOptions, EgarchParams, GarchOptions, GarchParams, GjrGarchOptions, GjrGarchParams, HarRvOptions, HarRvParams, LeverageStats, NoVaSOptions, NoVaSParams, OptimizerResult, PredictionResult, VolatilityForecast };