@alphacharts/indicators 0.1.0 → 0.1.1

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/README.md CHANGED
@@ -1,8 +1,8 @@
1
1
  # @alphacharts/indicators
2
2
 
3
- Technical studies for AlphaCharts: a typed study model, an incremental engine over the core's
3
+ Technical studies for alphacharts: a typed study model, an incremental engine over the core's
4
4
  columnar data, a Web Worker runner, chart integration through the core plugin API, and
5
- 210 studies (TA-Lib's catalogue plus TradingView's built-ins).
5
+ 211 studies (TA-Lib's catalogue plus TradingView's built-ins).
6
6
 
7
7
  ## Use
8
8
 
@@ -34,13 +34,23 @@ Subpaths: `.` (engine, runner, plugin), `./studies` (every study as a named expo
34
34
  (O(1) for recursive and running-sum nodes, O(period) for window scans), and a revision recomputes from committed
35
35
  state. Warm-up is NaN; absent values never become 0 (except where TA-Lib defines 0, noted in the study's reference).
36
36
  setData/prepend on the source recompute fully.
37
- - **Runner** (`src/runner.ts`): `createRunner(ids)` gives a `WorkerRunner` (arrays transferred, chunks of 65,536
37
+ - **Runner** (`src/runner.ts`): `createRunner(ids, factory)` gives a `WorkerRunner` on the worker `factory` makes (the host's bundler spells the worker URL out; the package never guesses it) (arrays transferred, chunks of 65,536
38
38
  bars so a `cancel` is serviced within a chunk; protocol documented in the file header) or the `InlineRunner`
39
- when Workers are unavailable. The worker returns every graph column; the main thread adopts them and keeps
39
+ when no factory is given or the worker would not start. The worker returns every graph column; the main thread adopts them and keeps
40
40
  streaming ticks. Studies not built in (defined at runtime) run inline (`canRun`).
41
41
  - **Chart integration** (`src/chart/studies.ts`): one core series per drawn plot (pane = the source's for overlays,
42
42
  the lowest free pane otherwise), the rest drawn on the overlay (fills, markers, ZigZag, lines shifted back in time
43
43
  or joined across gaps; these do not take part in autoscale). Layout JSON is keyed by study instance id.
44
+ - **Outside series** (`src/engine/feed.ts`, `Study.setFeed` / `pushFeedBar`): a study can read bars the host gives it (another
45
+ instrument, another timeframe). Each is a graph of its own on its own bars; the study's graph reads it through a join by time
46
+ (`Graph.joined` / `external`): `"same"` is the bar with exactly the study bar's time, else NaN, `"closed"` the latest bar whose
47
+ open + length is not after the study bar's start (no value contains data from after its bar, and the live bar sees the last finished one).
48
+ Lookups walk forward from the last answer, so a run and a tick are O(1) amortised; `StudyEngine.pushFeed` re-evaluates the last bar only
49
+ when it sees a different row. Runners: `RunRequest.feeds`, `StudyRunner.feedBar`.
50
+ - **Bar colours, background shading, per-point line colour, left axis** (`src/chart/studies.ts`): `barcolor` plots colour the source's candles
51
+ (core `Series.setBarColors`; several studies compose on one source, the latest wins, removal restores exactly), `bgcolor` plots draw through core's
52
+ `BarShading` primitive (no part in autoscale), a line plot's `colorBy: { col, color }` colours its segments per bar, `StudyDef.scale: "left"`
53
+ puts the series on the left axis.
44
54
  - **WASM** (`src/engine/kernels.ts`, `enableWasm()` from `src/wasm.ts`): optional batch kernels from `@alphacharts/wasm`
45
55
  for running sum, variance/stddev, rolling highest/lowest (+ bars) and linear regression, the kernels that won at 1M
46
56
  and 10M bars in its benchmark. They are bit-identical to the JS loops (test/wasm.test.ts runs every study both
@@ -49,7 +59,7 @@ Subpaths: `.` (engine, runner, plugin), `./studies` (every study as a named expo
49
59
  ## Verification
50
60
 
51
61
  Run `pnpm -C packages/indicators test`.
52
- - **TA-Lib** (`test/talib.test.ts`): fixtures generated offline by `scripts/gen_fixtures.py` (TA-Lib 0.8.2 in a
62
+ - **TA-Lib** (`test/talib.test.ts`; `atr` and `natr` are not here, see below): fixtures generated offline by `scripts/gen_fixtures.py` (TA-Lib 0.8.2 in a
53
63
  Python venv, see below) from `fixtures/cases/*.json` on a seeded 400-bar OHLCV set (`fixtures/dataset.json`;
54
64
  3,000 bars of mixed candle shapes for the patterns). Compared at 1e-9 relative (+1e-12 absolute floor), NaN positions
55
65
  must be identical; patterns are integers compared exactly. Case flags: `lead` (our study has valid values earlier
@@ -61,6 +71,7 @@ Run `pnpm -C packages/indicators test`.
61
71
  - Runner protocol, worker/inline parity and cancellation: `test/runner.test.ts`. Browser: `bench/tests/indicators.spec.ts`.
62
72
 
63
73
  Where a study is not TA-Lib's arithmetic it says so in its `reference` field. Known differences:
74
+ `atr`/`natr` (and every ATR band: keltner, supertrend, chande-kroll-stop, median) are Wilder's: bar 0's true range is high - low and the first value is at bar `length - 1`, TA-Lib's skips bar 0 and starts one bar later (hand case and an independent loop in `test/atr.test.ts`; `trange` stays TA-Lib's); `rsi` (and `stochrsi`) report 100 where RS is 0/0, the first `length` changes all zero (TA-Lib: 0; charting packages: 100, `test/rsi-flat.test.ts`);
64
75
  MACD/APO/PPO seed like TA-Lib (fast EMA at the slow EMA's first bar), TradingView seeds at bar 0 (gap < 1e-9 after
65
76
  ~150 bars); `cmo` defaults to TradingView's window-sum form (`method: "wilder"` is TA-Lib's); the linear regression
66
77
  studies are TA-Lib's (checked against numpy polyfit); `ht-trendmode` reports TA-Lib's 0 inside its warm-up;
@@ -69,17 +80,17 @@ Not checked against TradingView itself (no access): the TradingView-only studies
69
80
  `reference` field; pivot formulas, Klinger, Schaff, the Relative Volatility form and Fractals tie rules were written
70
81
  from memory of TradingView's scripts and are verified only by the hand-computed tests.
71
82
 
72
- ## Studies (210)
83
+ ## Studies (211)
73
84
 
74
85
  - **Overlap (TA-Lib + MAs, bands, SAR)** (17): `sma`, `ema`, `wma`, `dema`, `tema`, `trima`, `kama`, `t3`, `ma`, `bbands`, `bbpb`, `bbw`, `midpoint`, `midprice`, `mama`, `sar`, `sarext`
75
86
  - **Momentum (TA-Lib)** (30): `rsi`, `cmo`, `mom`, `roc`, `rocp`, `rocr`, `rocr100`, `trix`, `apo`, `ppo`, `macd`, `macdfix`, `macdext`, `stoch`, `stochf`, `stochrsi`, `willr`, `cci`, `bop`, `mfi`, `ultosc`, `aroon`, `aroonosc`, `adx`, `adxr`, `dx`, `plus-di`, `minus-di`, `plus-dm`, `minus-dm`
76
87
  - **Volume (TA-Lib)** (3): `ad`, `adosc`, `obv`
77
- - **Volatility (TA-Lib)** (3): `trange`, `atr`, `natr`
88
+ - **Volatility** (3): `trange` (TA-Lib's), `atr`, `natr` (Wilder's, not TA-Lib's)
78
89
  - **Price transforms (TA-Lib)** (4): `avgprice`, `medprice`, `typprice`, `wclprice`
79
90
  - **Statistics (TA-Lib)** (9): `linearreg`, `linearreg-slope`, `linearreg-intercept`, `linearreg-angle`, `tsf`, `stddev`, `var`, `correl`, `beta`
80
91
  - **Math transforms and operators (TA-Lib)** (26): `acos`, `asin`, `atan`, `ceil`, `cos`, `cosh`, `exp`, `floor`, `ln`, `log10`, `sin`, `sinh`, `sqrt`, `tan`, `tanh`, `add`, `sub`, `mult`, `div`, `max`, `min`, `sum`, `maxindex`, `minindex`, `minmax`, `minmaxindex`
81
92
  - **Cycle / Hilbert (TA-Lib)** (6): `ht-dcperiod`, `ht-dcphase`, `ht-phasor`, `ht-sine`, `ht-trendline`, `ht-trendmode`
82
- - **TradingView-only** (51): `smma`, `vwma`, `hma`, `alma`, `lsma`, `mcginley`, `ma-ribbon`, `ma-cross`, `envelopes`, `keltner`, `donchian`, `price-channel`, `chande-kroll-stop`, `linreg-channel`, `median`, `ichimoku`, `supertrend`, `alligator`, `fractals`, `zigzag`, `fisher`, `kst`, `tsi`, `vortex`, `coppock`, `connors-rsi`, `choppiness`, `rvi-vigor`, `rvi-volatility`, `smi-ergodic`, `rank-corr`, `bull-bear-power`, `awesome`, `accelerator`, `mass-index`, `dpo`, `schaff-tc`, `stoch-tv`, `volume`, `volume-osc`, `pvt`, `net-volume`, `elder-force`, `eom`, `chaikin-mf`, `klinger`, `vwap`, `anchored-vwap`, `pivot-points`, `hist-vol`, `adr`
93
+ - **TradingView-only** (52): `smma`, `vwma`, `hma`, `alma`, `lsma`, `mcginley`, `ma-ribbon`, `ma-cross`, `envelopes`, `keltner`, `donchian`, `price-channel`, `chande-kroll-stop`, `linreg-channel`, `median`, `ichimoku`, `supertrend`, `alligator`, `fractals`, `zigzag`, `fisher`, `kst`, `tsi`, `vortex`, `coppock`, `connors-rsi`, `choppiness`, `rvi-vigor`, `rvi-volatility`, `smi-ergodic`, `rank-corr`, `bull-bear-power`, `awesome`, `accelerator`, `mass-index`, `dpo`, `schaff-tc`, `stoch-tv`, `volume`, `volume-osc`, `pvt`, `net-volume`, `elder-force`, `eom`, `chaikin-mf`, `klinger`, `vwap` (Session VWAP), `anchored-vwap`, `pivot-points`, `hist-vol`, `adr`, `bars-per-year`
83
94
  - **Candlestick patterns (TA-Lib CDL*)** (61): `cdl-<name>` for every TA-Lib pattern, e.g. `cdl-2crows`, `cdl-3blackcrows`, `cdl-3inside`, `cdl-3linestrike`, `cdl-3outside`, ...
84
95
 
85
96
  ## Regenerating the TA-Lib fixtures
@@ -1,21 +1,21 @@
1
- import { $n as e, M as t, Mn as n, Mr as r, Q as i, ar as a, cn as o, d as s, dr as c, fn as l, hr as u, ni as d, un as f } from "./tv-volume-7hh6ajKt.js";
1
+ import { $ as e, N as t, Nn as n, Nr as r, dn as i, er as a, f as o, fr as s, gr as c, ln as l, or as u, pn as d, ri as f } from "./tv-volume-BYSbfrVk.js";
2
2
  //#region src/studies/all.ts
3
3
  var p = (e) => typeof e == "object" && !!e && "build" in e && "columns" in e && "plots" in e, m = [
4
- d,
4
+ f,
5
5
  r,
6
- u,
7
6
  c,
7
+ s,
8
+ u,
8
9
  a,
9
- e,
10
10
  n,
11
- l,
12
- f,
13
- o,
11
+ d,
14
12
  i,
13
+ l,
14
+ e,
15
15
  t,
16
- s
16
+ o
17
17
  ].flatMap((e) => Object.values(e).filter(p));
18
18
  //#endregion
19
19
  export { m as t };
20
20
 
21
- //# sourceMappingURL=all-DeXJJd7D.js.map
21
+ //# sourceMappingURL=all-_xzUPrL7.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"all-DeXJJd7D.js","names":["overlap","momentum","volume","volatility","price","statistic","math","cycle","sar","patterns","tvTrend","tvOsc","tvVolume","statistic_exports","tv_osc_exports","math_exports","momentum_exports","tv_trend_exports","price_exports","patterns_exports","tv_volume_exports","volatility_exports","cycle_exports","volume_exports","overlap_exports","sar_exports","isStudy","x","ALL_STUDIES","m"],"sources":["../src/studies/all.ts"],"sourcesContent":["// Every built-in study, collected from the group modules. Importing this pulls\n// them all in; import single studies from their group module to stay small.\n\nimport type { StudyDef } from \"../types.js\";\nimport * as overlap from \"./overlap.js\";\nimport * as momentum from \"./momentum.js\";\nimport * as volume from \"./volume.js\";\nimport * as volatility from \"./volatility.js\";\nimport * as price from \"./price.js\";\nimport * as statistic from \"./statistic.js\";\nimport * as math from \"./math.js\";\nimport * as cycle from \"./cycle.js\";\nimport * as sar from \"./sar.js\";\nimport * as patterns from \"./patterns.js\";\nimport * as tvTrend from \"./tv-trend.js\";\nimport * as tvOsc from \"./tv-osc.js\";\nimport * as tvVolume from \"./tv-volume.js\";\n\nconst isStudy = (x: unknown): x is StudyDef => typeof x === \"object\" && x !== null && \"build\" in x && \"columns\" in x && \"plots\" in x;\n\nexport const ALL_STUDIES: readonly StudyDef[] = [overlap, momentum, volume, volatility, price, statistic, math, cycle, sar, patterns, tvTrend, tvOsc, tvVolume].flatMap((m) =>\n Object.values(m).filter(isStudy),\n);\n"],"mappings":";;AAkBA,IAAM0B,KAAW,MAA8B,OAAOC,KAAM,cAAYA,KAAc,WAAWA,KAAK,aAAaA,KAAK,WAAWA,GAEtHC,IAAmC;CAAC5B;CAASC;CAAUC;CAAQC;CAAYC;CAAOC;CAAWC;CAAMC;CAAOC;CAAKC;CAAUC;CAASC;CAAOC;AAAQ,CAAC,CAAC,SAAS,MACvK,OAAO,OAAOiB,CAAC,CAAC,CAAC,OAAOH,CAAO,CACjC"}
1
+ {"version":3,"file":"all-_xzUPrL7.js","names":["overlap","momentum","volume","volatility","price","statistic","math","cycle","sar","patterns","tvTrend","tvOsc","tvVolume","tv_trend_exports","tv_osc_exports","math_exports","momentum_exports","sar_exports","statistic_exports","tv_volume_exports","volatility_exports","volume_exports","patterns_exports","price_exports","cycle_exports","overlap_exports","isStudy","x","ALL_STUDIES","m"],"sources":["../src/studies/all.ts"],"sourcesContent":["// Every built-in study, collected from the group modules. Importing this pulls\n// them all in; import single studies from their group module to stay small.\n\nimport type { StudyDef } from \"../types.js\";\nimport * as overlap from \"./overlap.js\";\nimport * as momentum from \"./momentum.js\";\nimport * as volume from \"./volume.js\";\nimport * as volatility from \"./volatility.js\";\nimport * as price from \"./price.js\";\nimport * as statistic from \"./statistic.js\";\nimport * as math from \"./math.js\";\nimport * as cycle from \"./cycle.js\";\nimport * as sar from \"./sar.js\";\nimport * as patterns from \"./patterns.js\";\nimport * as tvTrend from \"./tv-trend.js\";\nimport * as tvOsc from \"./tv-osc.js\";\nimport * as tvVolume from \"./tv-volume.js\";\n\nconst isStudy = (x: unknown): x is StudyDef => typeof x === \"object\" && x !== null && \"build\" in x && \"columns\" in x && \"plots\" in x;\n\nexport const ALL_STUDIES: readonly StudyDef[] = [overlap, momentum, volume, volatility, price, statistic, math, cycle, sar, patterns, tvTrend, tvOsc, tvVolume].flatMap((m) =>\n Object.values(m).filter(isStudy),\n);\n"],"mappings":";;AAkBA,IAAM0B,KAAW,MAA8B,OAAOC,KAAM,cAAYA,KAAc,WAAWA,KAAK,aAAaA,KAAK,WAAWA,GAEtHC,IAAmC;CAAC5B;CAASC;CAAUC;CAAQC;CAAYC;CAAOC;CAAWC;CAAMC;CAAOC;CAAKC;CAAUC;CAASC;CAAOC;AAAQ,CAAC,CAAC,SAAS,MACvK,OAAO,OAAOiB,CAAC,CAAC,CAAC,OAAOH,CAAO,CACjC"}
package/dist/all.js CHANGED
@@ -1,5 +1,5 @@
1
- import { r as e } from "./registry-CYZuqhXX.js";
2
- import { t } from "./all-DeXJJd7D.js";
1
+ import { r as e } from "./registry-DdYYyZN_.js";
2
+ import { t } from "./all-_xzUPrL7.js";
3
3
  //#region src/all.ts
4
4
  function n() {
5
5
  e(t);