@stvy/fund-indicators 1.0.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 fund-indicators contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.en.md ADDED
@@ -0,0 +1,617 @@
1
+ # @stvy/fund-indicators
2
+
3
+ **[中文](README.md)** | English
4
+
5
+ **Automated Trading Indicator Library for Funds** — Compute all technical indicators from historical NAV (Net Asset Value) data.
6
+
7
+ [![npm version](https://img.shields.io/npm/v/@stvy/fund-indicators)](https://www.npmjs.com/package/@stvy/fund-indicators)
8
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
9
+ [![TypeScript](https://img.shields.io/badge/TypeScript-5.x-blue)](https://www.typescriptlang.org/)
10
+ [![CI](https://github.com/stevieyu/fund-indicators/actions/workflows/ci.yml/badge.svg)](https://github.com/stevieyu/fund-indicators/actions/workflows/ci.yml)
11
+
12
+ A quantitative analysis library designed specifically for OTC funds, index funds, and ETF feeder funds. Simply pass in a daily NAV array to compute 70+ technical indicators, risk metrics, performance metrics, statistical features, DCA (Dollar-Cost Averaging) analysis, and pattern recognition signals.
13
+
14
+ ---
15
+
16
+ ## Features
17
+
18
+ - **Zero-friction input**: Every function requires only a single `number[]` (daily NAV array)
19
+ - **TypeScript native**: Full type definitions and JSDoc annotations for excellent IDE support
20
+ - **Comprehensive coverage**: Technical indicators + risk/performance + statistical features + DCA analysis + pattern recognition — 5 modules, 70+ functions
21
+ - **Fund-optimized**: Annualization parameters based on 242 A-share trading days; supports OTC fund NAV analysis
22
+ - **Lightweight dependencies**: Only depends on `technicalindicators` + `simple-statistics` + `jstat`
23
+ - **Battle-tested**: 35 automated tests covering all core functionality
24
+
25
+ ---
26
+
27
+ ## Installation
28
+
29
+ ```bash
30
+ npm install @stvy/fund-indicators
31
+ ```
32
+
33
+ ### Browser Usage
34
+
35
+ This library also ships browser-ready builds that can be used directly in HTML pages.
36
+
37
+ **Option 1: `<script>` tag (IIFE)**
38
+
39
+ ```html
40
+ <script src="https://unpkg.com/@stvy/fund-indicators/dist/browser/fund-indicators.min.js"></script>
41
+ <script>
42
+ const nav = [1.0, 1.02, 1.01, 1.05, 1.03, 1.08];
43
+
44
+ const ma = FundIndicators.sma(nav, 3);
45
+ console.log('SMA(3):', ma.current);
46
+
47
+ const rsi = FundIndicators.rsi(nav, 3);
48
+ console.log('RSI(3):', rsi.current);
49
+
50
+ const sharpe = FundIndicators.sharpeRatio(nav);
51
+ console.log('Sharpe Ratio:', sharpe);
52
+ </script>
53
+ ```
54
+
55
+ **Option 2: `<script type="module">` (ESM)**
56
+
57
+ ```html
58
+ <script type="module">
59
+ import { sma, rsi, sharpeRatio } from 'https://unpkg.com/@stvy/fund-indicators/dist/browser/fund-indicators.esm.js';
60
+
61
+ const nav = [1.0, 1.02, 1.01, 1.05, 1.03, 1.08];
62
+
63
+ console.log('SMA(3):', sma(nav, 3).current);
64
+ console.log('RSI(3):', rsi(nav, 3).current);
65
+ console.log('Sharpe Ratio:', sharpeRatio(nav));
66
+ </script>
67
+ ```
68
+
69
+ **Build artifacts:**
70
+
71
+ | File | Format | Size | Use Case |
72
+ |------|--------|------|----------|
73
+ | `fund-indicators.js` | IIFE | ~257 KB | `<script>` tag; exposes global `FundIndicators` |
74
+ | `fund-indicators.min.js` | IIFE minified | ~99 KB | Recommended for production |
75
+ | `fund-indicators.esm.js` | ESM | ~241 KB | `<script type="module">` or frontend bundlers |
76
+ | `fund-indicators.esm.min.js` | ESM minified | ~99 KB | Recommended for production ESM |
77
+
78
+ > Browser builds bundle all dependencies inline — no additional installations required.
79
+
80
+ ---
81
+
82
+ ## Quick Start
83
+
84
+ ```typescript
85
+ import {
86
+ sma, macd, rsi, kdj, bollingerBands,
87
+ sharpeRatio, maxDrawdown, performanceMetrics,
88
+ hurstExponent, simulateDCA,
89
+ } from '@stvy/fund-indicators';
90
+
91
+ // Your fund's historical NAV series (sorted by date ascending)
92
+ const nav = [1.0, 1.02, 1.01, 1.05, 1.03, 1.08, /* ... */];
93
+
94
+ // ── Technical Indicators ──
95
+ const ma20 = sma(nav, 20);
96
+ console.log('20-day MA:', ma20.current);
97
+
98
+ const m = macd(nav);
99
+ console.log('MACD DIF/DEA:', m.currentDIF, m.currentDEA);
100
+
101
+ const r = rsi(nav, 14);
102
+ console.log('RSI(14):', r.current);
103
+
104
+ const k = kdj(nav);
105
+ console.log('KDJ:', k.currentK, k.currentD, k.currentJ);
106
+
107
+ // ── Risk & Performance ──
108
+ console.log('Sharpe Ratio:', sharpeRatio(nav, 0.025));
109
+ console.log('Max Drawdown:', maxDrawdown(nav).maxDrawdown);
110
+
111
+ const perf = performanceMetrics(nav);
112
+ console.log('Annualized Return:', perf.annualizedReturn);
113
+ console.log('Sortino Ratio:', perf.sortinoRatio);
114
+
115
+ // ── Statistical Features ──
116
+ const hurst = hurstExponent(nav);
117
+ console.log('Hurst Exponent:', hurst.hurstExponent, '→', hurst.interpretation);
118
+
119
+ // ── DCA Simulation ──
120
+ const dca = simulateDCA(nav, { amount: 1000, interval: 22 });
121
+ console.log('DCA Return Rate:', dca.returnRate, 'IRR:', dca.irr);
122
+ ```
123
+
124
+ ---
125
+
126
+ ## Module Documentation
127
+
128
+ ### 1. Technical Indicators Module (`technical`)
129
+
130
+ Compute trend, momentum, oscillator, and channel indicators from historical NAV data.
131
+
132
+ #### Moving Averages
133
+
134
+ | Function | Description | Parameters |
135
+ |----------|-------------|------------|
136
+ | `sma(nav, period)` | Simple Moving Average | `period` default 20 |
137
+ | `ema(nav, period)` | Exponential Moving Average | `period` default 20 |
138
+ | `wma(nav, period)` | Weighted Moving Average | `period` default 20 |
139
+ | `dema(nav, period)` | Double Exponential Moving Average | `period` default 20 |
140
+ | `tema(nav, period)` | Triple Exponential Moving Average | `period` default 20 |
141
+ | `kama(nav, period, fast?, slow?)` | Kaufman Adaptive Moving Average | `period` default 10 |
142
+
143
+ All moving average functions return `MAResult`:
144
+
145
+ ```typescript
146
+ interface MAResult {
147
+ values: (number | null)[]; // Array same length as input; first N-1 entries are null
148
+ current: number | null; // Last valid value
149
+ period: number;
150
+ type: string;
151
+ }
152
+ ```
153
+
154
+ **Example — Moving average crossover detection:**
155
+
156
+ ```typescript
157
+ const fast = ema(nav, 10);
158
+ const slow = ema(nav, 30);
159
+ const signal = detectCrossSignal(fast, slow);
160
+
161
+ if (signal.type === 'golden_cross') console.log('Golden Cross! Buy signal');
162
+ if (signal.type === 'death_cross') console.log('Death Cross! Sell signal');
163
+ ```
164
+
165
+ **Example — Moving average alignment:**
166
+
167
+ ```typescript
168
+ const alignment = detectMAAlignment([
169
+ sma(nav, 5), sma(nav, 10), sma(nav, 20), sma(nav, 60),
170
+ ]);
171
+ console.log(alignment.alignment); // 'bullish' | 'bearish' | 'neutral'
172
+ ```
173
+
174
+ #### MACD
175
+
176
+ ```typescript
177
+ const result = macd(nav, 12, 26, 9);
178
+ // result.currentDIF — DIF line (fast line)
179
+ // result.currentDEA — DEA line (slow line)
180
+ // result.currentHistogram — Histogram (bar chart values)
181
+ // result.dif / .dea / .histogram — Full series arrays
182
+ ```
183
+
184
+ #### Momentum & Oscillator Indicators
185
+
186
+ | Function | Description | Typical Usage |
187
+ |----------|-------------|---------------|
188
+ | `rsi(nav, period?)` | RSI (Relative Strength Index) | >70 overbought, <30 oversold |
189
+ | `kdj(nav, kPeriod?, kSmooth?, dPeriod?)` | KDJ Stochastic (includes J value) | K/D golden/death cross |
190
+ | `roc(nav, period?)` | Rate of Change | Momentum strength |
191
+ | `momentum(nav, period?)` | Momentum Indicator | Trend acceleration/deceleration |
192
+ | `williamsR(nav, period?)` | Williams %R | Overbought/oversold |
193
+ | `cci(nav, period?)` | Commodity Channel Index | >100 / <-100 |
194
+ | `trix(nav, period?)` | Triple-Smoothed Exponential | Noise-filtered trend |
195
+ | `dpo(nav, period?)` | Detrended Price Oscillator | Cycle identification |
196
+ | `stochasticRSI(nav, ...)` | Stochastic RSI | More sensitive overbought/oversold |
197
+ | `massIndex(nav, emaPeriod?, sumPeriod?)` | Mass Index | Reversal point detection |
198
+
199
+ #### Channels & Volatility
200
+
201
+ | Function | Description |
202
+ |----------|-------------|
203
+ | `bollingerBands(nav, period?, stdDev?)` | Bollinger Bands (includes bandwidth and %B) |
204
+ | `donchianChannel(nav, period?)` | Donchian Channel |
205
+ | `keltnerChannel(nav, emaPeriod?, atrPeriod?, multiplier?)` | Keltner Channel |
206
+ | `adx(nav, period?)` | ADX (Average Directional Index) + DI+/DI- |
207
+ | `atr(nav, period?)` | ATR (Average True Range, approximated) |
208
+ | `sar(nav, step?, max?)` | Parabolic SAR |
209
+
210
+ #### Derived Indicators
211
+
212
+ | Function | Description |
213
+ |----------|-------------|
214
+ | `bias(nav, period?)` | BIAS = (NAV - MA) / MA × 100 |
215
+ | `navPercentile(nav, lookback?)` | NAV percentile within historical range (0–100) |
216
+
217
+ ---
218
+
219
+ ### 2. Risk & Performance Module (`risk`)
220
+
221
+ #### Basic Utilities
222
+
223
+ ```typescript
224
+ import { navToReturns, totalReturn, annualizeReturn } from '@stvy/fund-indicators';
225
+
226
+ const returns = navToReturns(nav); // NAV → daily returns
227
+ const tr = totalReturn(nav); // Cumulative return
228
+ const ar = annualizeReturn(returns); // Annualized return (geometric mean)
229
+ ```
230
+
231
+ #### Volatility
232
+
233
+ ```typescript
234
+ import { annualizedVolatility, downsideVolatility, rollingVolatility, volatilityCone } from '@stvy/fund-indicators';
235
+
236
+ annualizedVolatility(returns); // Annualized volatility
237
+ downsideVolatility(returns, 0.025); // Downside volatility
238
+ rollingVolatility(returns, 20); // Rolling 20-day volatility
239
+ volatilityCone(returns, [5,10,20,60,120]); // Volatility cone
240
+ ```
241
+
242
+ #### Drawdown Analysis
243
+
244
+ ```typescript
245
+ const dd = maxDrawdown(nav, dates?);
246
+
247
+ // dd.maxDrawdown — Maximum drawdown (negative value, e.g. -0.25)
248
+ // dd.peakIndex — Index of the drawdown peak (start)
249
+ // dd.troughIndex — Index of the drawdown trough (bottom)
250
+ // dd.durationDays — Duration of the drawdown in days
251
+ // dd.recoveryDays — Recovery days (null if not yet recovered)
252
+ // dd.drawdownSeries — Full drawdown series
253
+ ```
254
+
255
+ #### VaR / CVaR
256
+
257
+ ```typescript
258
+ calculateVaR(returns, 0.95, 'historical'); // 95% Historical Simulation VaR
259
+ calculateVaR(returns, 0.99, 'parametric'); // 99% Parametric VaR
260
+ calculateCVaR(returns, 0.95); // 95% Conditional Value at Risk
261
+ ```
262
+
263
+ #### Risk Metrics Summary
264
+
265
+ ```typescript
266
+ const risk = riskMetrics(nav, 0.025);
267
+ // risk.annualizedVolatility — Annualized volatility
268
+ // risk.downsideVolatility — Downside volatility
269
+ // risk.maxDrawdown — Maximum drawdown
270
+ // risk.maxDrawdownDuration — Max drawdown duration in days
271
+ // risk.var95 / risk.var99 — VaR
272
+ // risk.cvar95 / risk.cvar99 — CVaR
273
+ ```
274
+
275
+ #### Performance Metrics
276
+
277
+ | Function | Formula |
278
+ |----------|---------|
279
+ | `sharpeRatio(nav, rf?)` | (Annualized Return - Risk-Free Rate) / Annualized Volatility |
280
+ | `sortinoRatio(nav, rf?)` | (Annualized Return - Risk-Free Rate) / Downside Volatility |
281
+ | `calmarRatio(nav)` | Annualized Return / \|Max Drawdown\| |
282
+ | `treynorRatio(nav, benchmark, rf?)` | (Annualized Return - Risk-Free Rate) / Beta |
283
+ | `omegaRatio(nav, threshold?)` | Weighted Upside Return / Weighted Downside Loss |
284
+ | `winRate(returns)` | Positive-return days / Total days |
285
+ | `profitLossRatio(returns)` | Average Gain / Average Loss |
286
+ | `profitFactor(returns)` | Total Gains / Total Losses |
287
+ | `consecutiveWinLoss(returns)` | Max consecutive winning/losing days |
288
+
289
+ **Get all performance metrics at once:**
290
+
291
+ ```typescript
292
+ const perf = performanceMetrics(nav, 0.025);
293
+ // perf.totalReturn / .annualizedReturn
294
+ // perf.sharpeRatio / .sortinoRatio / .calmarRatio
295
+ // perf.omegaRatio / .winRate / .profitLossRatio / .profitFactor
296
+ // perf.maxConsecutiveWins / .maxConsecutiveLosses
297
+ ```
298
+
299
+ #### Benchmark Comparison Metrics
300
+
301
+ ```typescript
302
+ const bm = benchmarkMetrics(fundNav, benchmarkNav, 0.025);
303
+ // bm.alpha — Alpha (excess return)
304
+ // bm.beta — Beta coefficient
305
+ // bm.trackingError — Tracking error (annualized)
306
+ // bm.informationRatio — Information ratio
307
+ // bm.correlation — Correlation coefficient
308
+ // bm.rSquared — R²
309
+ ```
310
+
311
+ ---
312
+
313
+ ### 3. Statistical Features Module (`statistics`)
314
+
315
+ ```typescript
316
+ import {
317
+ statisticalFeatures, hurstExponent, autocorrelation,
318
+ ljungBoxTest, garch11, returnQuantiles,
319
+ rollingSkewness, rollingKurtosis,
320
+ } from '@stvy/fund-indicators';
321
+
322
+ // Full statistical feature set
323
+ const stats = statisticalFeatures(nav);
324
+ // stats.mean / .median / .stdDev
325
+ // stats.skewness / .kurtosis
326
+ // stats.jarqueBera — Normality test
327
+
328
+ // Hurst Exponent
329
+ const h = hurstExponent(nav);
330
+ // h.hurstExponent — >0.5 trending / <0.5 mean-reverting / ≈0.5 random
331
+ // h.interpretation — 'trending' | 'mean_reverting' | 'random_walk'
332
+
333
+ // Autocorrelation analysis
334
+ const acf = autocorrelation(nav, 20);
335
+ // acf.coefficients — Autocorrelation coefficients at each lag
336
+ // acf.interpretation — 'persistent' | 'anti_persistent' | 'no_correlation'
337
+
338
+ // Ljung-Box test
339
+ const lb = ljungBoxTest(returns, 10);
340
+ // lb.qStatistic / lb.approximatePValue
341
+
342
+ // GARCH(1,1) volatility forecast
343
+ const g = garch11(returns);
344
+ // g.nextPeriodForecast — Next-period conditional variance forecast
345
+ // g.omega / g.alpha / g.beta — GARCH parameters
346
+
347
+ // Return quantiles
348
+ const quantiles = returnQuantiles(nav, [0.01, 0.05, 0.5, 0.95, 0.99]);
349
+
350
+ // Rolling skewness / kurtosis
351
+ const skew = rollingSkewness(returns, 60);
352
+ const kurt = rollingKurtosis(returns, 60);
353
+ ```
354
+
355
+ ---
356
+
357
+ ### 4. DCA & PnL Analysis Module (`dca`)
358
+
359
+ #### DCA Simulation
360
+
361
+ ```typescript
362
+ const dca = simulateDCA(nav, {
363
+ amount: 1000, // Investment amount per period
364
+ interval: 22, // DCA interval (trading days), 22 ≈ monthly
365
+ startIndex: 0, // Starting index
366
+ });
367
+
368
+ // dca.totalInvestments — Number of investments made
369
+ // dca.totalInvested — Total amount invested
370
+ // dca.currentValue — Current market value
371
+ // dca.averageCost — Average holding cost
372
+ // dca.returnRate — Return rate
373
+ // dca.irr — Internal Rate of Return (annualized)
374
+ ```
375
+
376
+ #### Take-Profit & Stop-Loss
377
+
378
+ ```typescript
379
+ // Fixed take-profit / stop-loss
380
+ const signal = takeProfitStopLoss(nav, costPrice, 0.30, -0.15);
381
+ // signal.takeProfitTriggered — Whether the 30% take-profit was triggered
382
+ // signal.stopLossTriggered — Whether the 15% stop-loss was triggered
383
+
384
+ // Trailing stop (triggered when price drops N% from peak)
385
+ const trail = trailingStop(nav, 0.10, costPrice);
386
+ // trail.triggered — Whether triggered
387
+ // trail.drawdownFromPeak — Drawdown from peak
388
+ ```
389
+
390
+ #### Smart DCA
391
+
392
+ ```typescript
393
+ // Dynamically adjust investment amount based on NAV relative to moving average
394
+ const multiplier = smartDCAMultiplier(nav, 250, 2.0, 0.5);
395
+ // > 1 when below MA (invest more), < 1 when above MA (invest less)
396
+
397
+ // Tiered buy / sell signals
398
+ const buyLevel = tieredBuySignal(nav, [0.3, 0.2, 0.1]);
399
+ const sellLevel = tieredSellSignal(nav, [0.7, 0.8, 0.9]);
400
+ ```
401
+
402
+ #### Utility Functions
403
+
404
+ ```typescript
405
+ safetyMargin(nav); // Drawdown from all-time high
406
+ pricePosition(nav); // Current price position between historical high and low (0–1)
407
+ positionPnL(nav, buyIdx, sellIdx?, amount?); // Single-position PnL details
408
+ ```
409
+
410
+ ---
411
+
412
+ ### 5. Pattern Recognition Module (`pattern`)
413
+
414
+ ```typescript
415
+ import {
416
+ supportResistance, doubleBottomTop,
417
+ detectGaps, trendStrength, headAndShoulders,
418
+ } from '@stvy/fund-indicators';
419
+
420
+ // Support / Resistance levels
421
+ const sr = supportResistance(nav, 0.02, 3);
422
+ // sr.supports[0].level / .strength / .touches
423
+ // sr.resistances[0].level / .strength / .touches
424
+
425
+ // Double Bottom (W-bottom) / Double Top (M-top)
426
+ const dbt = doubleBottomTop(nav, 60, 0.03, 10);
427
+ // dbt.type — 'double_bottom' | 'double_top' | 'none'
428
+ // dbt.breakout — Whether neckline breakout occurred
429
+ // dbt.confidence — Signal strength 0–1
430
+
431
+ // Gap detection
432
+ const gaps = detectGaps(nav, 0.02);
433
+ // gaps[i].type — 'gap_up' | 'gap_down'
434
+ // gaps[i].gapSize — Gap size
435
+ // gaps[i].filled — Whether the gap has been filled
436
+
437
+ // Trend strength score
438
+ const score = trendStrength(nav, 20); // 0–100
439
+
440
+ // Head and Shoulders pattern
441
+ const hs = headAndShoulders(nav, 90);
442
+ // hs.type — 'head_and_shoulders_top' | 'head_and_shoulders_bottom' | 'none'
443
+ ```
444
+
445
+ ---
446
+
447
+ ## Full API Reference
448
+
449
+ | Module | Functions | Input | Output |
450
+ |--------|-----------|-------|--------|
451
+ | **Moving Averages** | `sma` `ema` `wma` `dema` `tema` `kama` | `nav, period` | `MAResult` |
452
+ | **Trend** | `macd` | `nav, fast?, slow?, signal?` | `MACDResult` |
453
+ | **Momentum** | `rsi` `kdj` `roc` `momentum` `williamsR` `cci` `trix` `dpo` `stochasticRSI` `massIndex` | `nav, period?` | `MAResult` / `KDJResult` |
454
+ | **Channels** | `bollingerBands` `donchianChannel` `keltnerChannel` | `nav, ...params` | `BollingerResult` / `ChannelResult` |
455
+ | **Trend Strength** | `adx` `atr` `sar` | `nav, period?` | `ADXResult` / `MAResult` / `SARResult` |
456
+ | **Derived** | `bias` `navPercentile` `detectCrossSignal` `detectMAAlignment` | `nav, ...` | Varies |
457
+ | **Volatility** | `annualizedVolatility` `downsideVolatility` `rollingVolatility` `volatilityCone` | `returns` | `number` / `array` |
458
+ | **Drawdown** | `maxDrawdown` `maxDrawdownDuration` | `nav, dates?` | `DrawdownResult` / `number` |
459
+ | **VaR** | `calculateVaR` `calculateCVaR` | `returns, confidence` | `number` |
460
+ | **Risk Summary** | `riskMetrics` | `nav, rf?` | `RiskMetrics` |
461
+ | **Performance** | `sharpeRatio` `sortinoRatio` `calmarRatio` `treynorRatio` `omegaRatio` `winRate` `profitLossRatio` `profitFactor` `consecutiveWinLoss` `performanceMetrics` | `nav` / `returns` | `number` / `PerformanceMetrics` |
462
+ | **Benchmark** | `calculateBeta` `calculateAlpha` `trackingError` `informationRatio` `benchmarkMetrics` | `nav, benchmark` | `number` / `BenchmarkMetrics` |
463
+ | **Statistics** | `statisticalFeatures` `navStatisticalFeatures` | `nav` | `StatisticalFeatures` |
464
+ | **Hurst** | `hurstExponent` | `nav, ...` | `HurstResult` |
465
+ | **Autocorrelation** | `autocorrelation` `ljungBoxTest` | `nav, maxLag` | `AutocorrelationResult` |
466
+ | **GARCH** | `garch11` | `returns` | `{ conditionalVariance, nextPeriodForecast, ... }` |
467
+ | **Distribution** | `returnQuantiles` `rollingSkewness` `rollingKurtosis` | `nav` / `returns` | `Map` / `array` |
468
+ | **DCA** | `simulateDCA` | `nav, config` | `DCAResult` |
469
+ | **Take-Profit / Stop-Loss** | `takeProfitStopLoss` `trailingStop` | `nav, cost, ...` | `TakeProfitStopLossSignal` |
470
+ | **Smart DCA** | `smartDCAMultiplier` `tieredBuySignal` `tieredSellSignal` | `nav, ...` | `number` |
471
+ | **Utilities** | `safetyMargin` `pricePosition` `positionPnL` | `nav, ...` | `number` / `object` |
472
+ | **Patterns** | `supportResistance` `doubleBottomTop` `detectGaps` `trendStrength` `headAndShoulders` | `nav, ...` | Varies |
473
+
474
+ ---
475
+
476
+ ## Data Requirements
477
+
478
+ This library only requires a **historical daily NAV series** — no volume, holdings, or fund flow data is needed.
479
+
480
+ Input format:
481
+
482
+ ```typescript
483
+ // NAV array sorted by date ascending
484
+ const nav: number[] = [1.0000, 1.0032, 0.9985, 1.0120, ...];
485
+ ```
486
+
487
+ Important notes:
488
+
489
+ - The NAV series should be sorted in chronological order (earliest first)
490
+ - A minimum of 60 data points is recommended; some indicators (e.g. Hurst Exponent, GARCH) work best with 250+
491
+ - Dividend distributions cause abrupt NAV drops — use **adjusted NAV** (cumulative NAV or dividend-reinvested NAV) for accurate results
492
+ - Annualization parameters are based on **242 A-share trading days**; modify the `TRADING_DAYS_PER_YEAR` constant to adapt to other markets
493
+
494
+ ---
495
+
496
+ ## Development Guide
497
+
498
+ ### Prerequisites
499
+
500
+ - Node.js >= 18
501
+ - npm >= 9
502
+
503
+ ### Local Development
504
+
505
+ ```bash
506
+ # Clone the repository
507
+ git clone https://github.com/stevieyu/fund-indicators.git
508
+ cd fund-indicators
509
+
510
+ # Install dependencies
511
+ npm install
512
+
513
+ # Run tests
514
+ npm test
515
+
516
+ # Compile TypeScript
517
+ npm run build
518
+ ```
519
+
520
+ ### Project Structure
521
+
522
+ ```
523
+ fund-indicators/
524
+ ├── src/
525
+ │ ├── index.ts # Unified export entry point
526
+ │ ├── types.ts # Full type definitions (30+ interfaces)
527
+ │ ├── technical.ts # Technical indicators (MA/MACD/RSI/KDJ/Bollinger/Channels)
528
+ │ ├── risk.ts # Risk & performance (Volatility/Drawdown/VaR/Sharpe/Alpha/Beta)
529
+ │ ├── statistics.ts # Statistical features (Skewness/Kurtosis/Hurst/GARCH/Autocorrelation)
530
+ │ ├── dca.ts # DCA analysis (Simulation/IRR/Smart DCA/Take-Profit & Stop-Loss)
531
+ │ ├── pattern.ts # Pattern recognition (Support/Resistance/Double Bottom-Top/H&S/Gaps)
532
+ │ └── jstat.d.ts # jstat type declarations
533
+ ├── scripts/
534
+ │ └── build-browser.mjs # Browser build script (esbuild)
535
+ ├── test/
536
+ │ └── index.test.ts # 35 validation tests
537
+ ├── dist/
538
+ │ ├── *.js / *.d.ts # Node.js build artifacts (CommonJS + type declarations)
539
+ │ └── browser/ # Browser build artifacts (IIFE + ESM)
540
+ ├── .github/
541
+ │ └── workflows/
542
+ │ ├── ci.yml # CI pipeline (Node LTS)
543
+ │ └── publish.yml # Auto-publish to npm on release
544
+ ├── package.json
545
+ ├── tsconfig.json
546
+ ├── .gitignore
547
+ ├── LICENSE
548
+ └── README.md
549
+ ```
550
+
551
+ ---
552
+
553
+ ## Dependencies
554
+
555
+ | Dependency | Purpose | Size |
556
+ |------------|---------|------|
557
+ | [technicalindicators](https://github.com/anandanand84/technicalindicators) | Classic technical indicator calculations (MA/MACD/RSI/Bollinger Bands, etc.) | ~150KB |
558
+ | [simple-statistics](https://github.com/simple-statistics/simple-statistics) | Statistical functions (std dev, skewness, kurtosis, regression, quantiles, etc.) | ~50KB |
559
+ | [jstat](https://github.com/jstat/jstat) | Probability distribution functions (normal, chi-squared, t-distribution; used for VaR) | ~30KB |
560
+
561
+ ---
562
+
563
+ ## Contributing
564
+
565
+ Contributions are welcome! Please follow these steps:
566
+
567
+ 1. Fork the repository
568
+ 2. Create a feature branch (`git checkout -b feature/amazing-feature`)
569
+ 3. Write code and corresponding tests
570
+ 4. Make sure tests pass (`npm test`) and TypeScript compiles without errors (`npm run build`)
571
+ 5. Commit your changes (`git commit -m 'feat: add amazing feature'`)
572
+ 6. Push to the branch (`git push origin feature/amazing-feature`)
573
+ 7. Open a Pull Request
574
+
575
+ ### Commit Convention
576
+
577
+ This project follows the [Conventional Commits](https://www.conventionalcommits.org/) specification:
578
+
579
+ - `feat:` New features
580
+ - `fix:` Bug fixes
581
+ - `docs:` Documentation changes
582
+ - `test:` Test-related changes
583
+ - `refactor:` Code refactoring
584
+ - `perf:` Performance improvements
585
+ - `chore:` Build/tooling changes
586
+
587
+ ---
588
+
589
+ ## FAQ
590
+
591
+ **Q: Fund NAV data has no volume — can I still use indicators like ATR and OBV?**
592
+
593
+ A: Yes, partially. Since fund NAV has no intraday high/low, this library sets high, low, and close all to the daily NAV. ATR degenerates to EMA(|ΔNAV|), which still serves as a useful measure of daily volatility magnitude. OBV, however, is meaningless without volume data and is not recommended.
594
+
595
+ **Q: Why is the annualization parameter set to 242?**
596
+
597
+ A: The A-share market has approximately 242 trading days per year. If you are analyzing Hong Kong stocks (~250 days) or US stocks (~252 days), you can fork the repository and modify the `TRADING_DAYS_PER_YEAR` constant.
598
+
599
+ **Q: How should I handle NAV drops caused by dividend distributions?**
600
+
601
+ A: Use **adjusted NAV** (cumulative NAV or dividend-reinvested NAV) as input. If you use unit NAV, dividend distributions will cause sudden drops that distort indicator calculations. The library's `detectGaps` function can help identify such anomalous jumps.
602
+
603
+ **Q: Why are my Hurst Exponent results unstable?**
604
+
605
+ A: The Hurst Exponent's R/S analysis is sensitive to data length. At least 500 data points are recommended. With short datasets, R² tends to be low and results are unreliable. You can assess result reliability via `hurst.rSquared` (R² > 0.9 is considered good).
606
+
607
+ ---
608
+
609
+ ## License
610
+
611
+ [MIT](LICENSE)
612
+
613
+ ---
614
+
615
+ ## Acknowledgments
616
+
617
+ Technical indicator calculations in this project are powered by [technicalindicators](https://github.com/anandanand84/technicalindicators), statistical analysis by [simple-statistics](https://github.com/simple-statistics/simple-statistics), and probability distribution computations by [jstat](https://github.com/jstat/jstat). Our thanks to these outstanding open-source projects.