garch 1.0.3 → 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.3",
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",
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
  */
@@ -196,6 +422,15 @@ declare function garmanKlassVariance(candles: Candle[]): number;
196
422
  * σ²_YZ = σ²_overnight + k·σ²_close + (1−k)·σ²_RS
197
423
  */
198
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[];
199
434
  /**
200
435
  * Expected value of |Z| where Z ~ N(0,1)
201
436
  * E[|Z|] = sqrt(2/π)
@@ -213,6 +448,45 @@ declare function ljungBox(data: number[], maxLag: number): {
213
448
  statistic: number;
214
449
  pValue: number;
215
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;
216
490
 
217
491
  type CandleInterval = '1m' | '3m' | '5m' | '15m' | '30m' | '1h' | '2h' | '4h' | '6h' | '8h';
218
492
  interface PredictionResult {
@@ -221,7 +495,7 @@ interface PredictionResult {
221
495
  move: number;
222
496
  upperPrice: number;
223
497
  lowerPrice: number;
224
- modelType: 'garch' | 'egarch';
498
+ modelType: 'garch' | 'egarch' | 'gjr-garch' | 'har-rv' | 'novas';
225
499
  reliable: boolean;
226
500
  }
227
501
  /**
@@ -256,6 +530,11 @@ declare function nelderMead(fn: (x: number[]) => number, x0: number[], options?:
256
530
  rho?: number;
257
531
  sigma?: number;
258
532
  }): OptimizerResult;
533
+ declare function nelderMeadMultiStart(fn: (x: number[]) => number, x0: number[], options?: {
534
+ maxIter?: number;
535
+ tol?: number;
536
+ restarts?: number;
537
+ }): OptimizerResult;
259
538
 
260
- export { EXPECTED_ABS_NORMAL, Egarch, Garch, backtest, calculateReturns, calculateReturnsFromPrices, calibrateEgarch, calibrateGarch, checkLeverageEffect, garmanKlassVariance, ljungBox, nelderMead, predict, predictRange, sampleVariance, sampleVarianceWithMean, yangZhangVariance };
261
- export type { CalibrationResult, Candle, CandleInterval, EgarchOptions, EgarchParams, GarchOptions, GarchParams, LeverageStats, OptimizerResult, PredictionResult, 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 };