ta-crypto 0.1.5 → 0.2.3

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 CHANGED
@@ -1,21 +1,21 @@
1
- MIT License
2
-
3
- Copyright (c) 2026
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.
1
+ MIT License
2
+
3
+ Copyright (c) 2026
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.md CHANGED
@@ -1,157 +1,216 @@
1
- # ta-crypto
2
-
3
- [![npm version](https://img.shields.io/npm/v/ta-crypto.svg)](https://www.npmjs.com/package/ta-crypto)
4
- [![CI](https://github.com/TDamiao/ta-crypto/actions/workflows/ci.yml/badge.svg)](https://github.com/TDamiao/ta-crypto/actions/workflows/ci.yml)
5
-
6
- Technical analysis indicators for crypto markets in Node.js. Inspired by pandas-ta, but focused on crypto use-cases and Node-friendly APIs.
7
-
8
- ## Features
9
-
10
- - Typed, lightweight indicators for OHLCV arrays
11
- - Crypto-specific extras like session VWAP, funding rate helpers, volatility regimes, and orderflow proxies
12
- - Functions return arrays aligned to input length with `null` for insufficient data
13
-
14
- ## Install
15
-
16
- ```bash
17
- npm i ta-crypto
18
- ```
19
-
20
- ## Quick Start
21
-
22
- ```ts
23
- import {
24
- ta,
25
- sma,
26
- rsi,
27
- macd,
28
- bbands,
29
- atr,
30
- vwap,
31
- vwapSession,
32
- realizedVolatility,
33
- fundingRateCumulative,
34
- volatilityRegime,
35
- orderflowImbalance,
36
- obv,
37
- mfi,
38
- stoch,
39
- adx
40
- } from "ta-crypto";
41
-
42
- const close = [101, 102, 99, 105, 110, 108, 111];
43
- const open = [100, 101, 100, 103, 108, 109, 110];
44
- const high = [102, 103, 101, 106, 112, 110, 112];
45
- const low = [ 99, 100, 98, 102, 107, 106, 109];
46
- const volume =[ 10, 12, 11, 15, 17, 14, 18];
47
- const session=[ 1, 1, 1, 2, 2, 2, 3];
48
-
49
- const s = sma(close, 3);
50
- const r = rsi(close, 14);
51
- const m = macd(close);
52
- const b = bbands(close, 20, 2);
53
- const a = atr(high, low, close, 14);
54
- const v = vwap(high, low, close, volume);
55
- const vs = vwapSession(high, low, close, volume, session);
56
- const rv = realizedVolatility(close, 30, 365);
57
- const fr = fundingRateCumulative([0.0001, -0.0002, 0.00005]);
58
- const vr = volatilityRegime(close, 30, 365);
59
- const ofi = orderflowImbalance(open, close, volume, 20);
60
- const o = obv(close, volume);
61
- const moneyFlow = mfi(high, low, close, volume, 14);
62
- const st = stoch(high, low, close, 14, 3);
63
- const dx = adx(high, low, close, 14);
64
-
65
- const s2 = ta.sma(close, 3);
66
- ```
67
-
68
- ## API Conventions
69
-
70
- - Input arrays must be the same length.
71
- - Outputs are aligned to input length.
72
- - `null` marks periods with insufficient data.
73
-
74
- ## Indicators
75
-
76
- Overlap:
77
- - `sma`, `ema`, `rma`, `hl2`, `hlc3`, `ohlc4`, `vwap`, `bbands`
78
-
79
- Momentum:
80
- - `rsi`, `macd`, `stoch`
81
-
82
- Volatility:
83
- - `trueRange`, `atr`, `natr`, `realizedVolatility`
84
-
85
- Performance:
86
- - `logReturn`, `percentReturn`
87
-
88
- Volume:
89
- - `obv`, `mfi`
90
-
91
- Trend:
92
- - `adx`
93
-
94
- Crypto:
95
- - `vwapSession`, `fundingRateCumulative`, `fundingRateAPR`, `volatilityRegime`, `signedVolume`, `volumeDelta`, `orderflowImbalance`
96
-
97
- ## Crypto-Specific Notes
98
-
99
- Session VWAP:
100
- - Provide a `session` array with an id per candle. VWAP resets on each new session id.
101
-
102
- Funding rate:
103
- - `fundingRateCumulative` sums periodic rates over time.
104
- - `fundingRateAPR` annualizes a periodic rate using `periodsPerYear`.
105
-
106
- Volatility regimes:
107
- - `volatilityRegime` computes realized volatility and returns -1, 0, or 1 based on z-score thresholds.
108
-
109
- Orderflow proxies:
110
- - `signedVolume`, `volumeDelta`, and `orderflowImbalance` infer buy/sell pressure from candle direction.
111
-
112
- ## Release
113
-
114
- Automated npm publish runs on tag push. Steps:
115
-
116
- 1. Ensure `NPM_TOKEN` is set in GitHub Actions secrets.
117
- - For GitHub Packages, set `GITHUB_TOKEN` (already provided) or a PAT if needed.
118
- 2. Update changelog (recommended):
119
-
120
- ```bash
121
- npm run changelog
122
- ```
123
-
124
- 3. Bump version (optional):
125
-
126
- ```bash
127
- npm run version:patch
128
- ```
129
-
130
- 4. Run:
131
-
132
- ```bash
133
- npm run release
134
- ```
135
-
136
- Or do everything in one step:
137
-
138
- ```bash
139
- npm run release:patch
140
- ```
141
-
142
- GitHub Packages:
143
- - A separate workflow publishes `@TDamiao/ta-crypto` to GitHub Packages on the same tag.
144
-
145
- This creates and pushes a tag like `v0.1.1`, triggering the release workflow.
146
-
147
- ## License
148
-
149
- MIT
150
-
151
- ## GitHub Packages
152
-
153
- Install from GitHub Packages:
154
-
155
- ```bash
156
- npm i @TDamiao/ta-crypto
157
- ```
1
+ # ta-crypto
2
+
3
+ [![npm version](https://img.shields.io/npm/v/ta-crypto.svg)](https://www.npmjs.com/package/ta-crypto)
4
+ [![CI](https://github.com/TDamiao/ta-crypto/actions/workflows/ci.yml/badge.svg)](https://github.com/TDamiao/ta-crypto/actions/workflows/ci.yml)
5
+
6
+ Technical analysis indicators for crypto markets in Node.js.
7
+
8
+ ## Install
9
+
10
+ ```bash
11
+ npm i ta-crypto
12
+ ```
13
+
14
+ ## Quick Start
15
+
16
+ ```ts
17
+ import { sma, rsi, macd, bbands, atr, vwapSession, toOHLCV } from "ta-crypto";
18
+
19
+ const candles = [
20
+ { open: 100, high: 102, low: 99, close: 101, volume: 10, time: 1 },
21
+ { open: 101, high: 103, low: 100, close: 102, volume: 12, time: 2 }
22
+ ];
23
+
24
+ const { high, low, close, volume } = toOHLCV(candles, 0);
25
+ const s = sma(close, 14);
26
+ const r = rsi(close, 14);
27
+ const m = macd(close);
28
+ const b = bbands(close, 20, 2);
29
+ const a = atr(high, low, close, 14);
30
+ const vs = vwapSession(high, low, close, volume, [1, 1]);
31
+ ```
32
+
33
+ ## Stateful API (streaming)
34
+
35
+ ```ts
36
+ import { createRSI, createVWAPSession } from "ta-crypto";
37
+
38
+ const rsi14 = createRSI(14);
39
+ const nextRsi = rsi14.next(101.25);
40
+
41
+ const vwap = createVWAPSession();
42
+ const nextVwap = vwap.next({
43
+ high: 102,
44
+ low: 99,
45
+ close: 101,
46
+ volume: 10,
47
+ sessionId: "2026-02-10-asia"
48
+ });
49
+ ```
50
+
51
+ ## Compatibility
52
+
53
+ `ta-crypto` now ships golden tests (`test/fixtures/golden.json`) to lock behavior across releases.
54
+
55
+ Classic indicators:
56
+
57
+ | Indicator | Reference | Tolerance |
58
+ | --- | --- | --- |
59
+ | SMA, EMA, RSI | Golden baseline | 1e-10 |
60
+ | MACD, BBANDS | Golden baseline | 1e-10 |
61
+ | ATR, ADX | Golden baseline | 1e-10 |
62
+
63
+ Crypto indicators:
64
+
65
+ | Indicator | Reference | Tolerance |
66
+ | --- | --- | --- |
67
+ | VWAP Session | Golden baseline | 1e-10 |
68
+ | Stateful VWAP Session parity | Batch VWAP Session | 1e-10 |
69
+
70
+ Streaming parity:
71
+
72
+ | Indicator | Reference | Tolerance |
73
+ | --- | --- | --- |
74
+ | Stateful RSI(14) | Batch RSI(14) | 1e-10 |
75
+
76
+ External parity:
77
+
78
+ | Indicator set | Reference libs | Tolerance |
79
+ | --- | --- | --- |
80
+ | SMA/EMA/RSI/MACD/BBANDS/ATR/ADX | TA-Lib, pandas-ta, technicalindicators | 1e-8 |
81
+
82
+ Generate/review vectors:
83
+
84
+ ```bash
85
+ npm run generate:golden
86
+ npm run test:golden
87
+ npm run generate:compat
88
+ npm run test:compat:technicalindicators
89
+ # python deps: pip install -r scripts/requirements-compat.txt
90
+ npm run test:compat:python
91
+ ```
92
+
93
+ Note:
94
+ - CI uses Linux + Python 3.12 for full TA-Lib/pandas-ta coverage.
95
+ - On Windows, `pandas-ta` may be unavailable depending on upstream wheels; the script reports explicit skip in that case.
96
+ - `TA-Lib` and `technicalindicators` are strict release gates; `pandas-ta` runs as compatibility telemetry and reports warnings when it diverges by environment.
97
+
98
+ ## Crypto Playbooks
99
+
100
+ Session VWAP reset:
101
+ - Provide one `sessionId` per candle.
102
+ - VWAP resets exactly when `sessionId` changes.
103
+ - Use exchange session boundaries (UTC day, funding window, or custom market session).
104
+
105
+ Funding APR:
106
+ - `fundingRateAPR(values, periodsPerYear)` annualizes periodic funding.
107
+ - `periodsPerYear` presets:
108
+ - `3/day` funding: `1095`
109
+ - `1/hour` funding: `8760`
110
+ - `1/8h` funding: `1095`
111
+
112
+ Volatility regime:
113
+ - `volatilityRegime(values, length, periodsPerYear, lowZ, highZ)` returns `-1`, `0`, `1`.
114
+ - Default thresholds: `lowZ = -0.5`, `highZ = 0.5`.
115
+ - Calibration approach: increase absolute thresholds for noisier low-timeframe pairs, reduce for smoother higher timeframes.
116
+
117
+ ## Indicators
118
+
119
+ Overlap:
120
+ - `sma`, `ema`, `rma`, `hl2`, `hlc3`, `ohlc4`, `vwap`, `bbands`
121
+
122
+ Momentum:
123
+ - `rsi`, `macd`, `stoch`
124
+
125
+ Volatility:
126
+ - `trueRange`, `atr`, `natr`, `realizedVolatility`
127
+
128
+ Performance:
129
+ - `logReturn`, `percentReturn`
130
+
131
+ Volume:
132
+ - `obv`, `mfi`
133
+
134
+ Trend:
135
+ - `adx`
136
+
137
+ Crypto:
138
+ - `vwapSession`, `fundingRateCumulative`, `fundingRateAPR`, `volatilityRegime`, `signedVolume`, `volumeDelta`, `orderflowImbalance`
139
+
140
+ ## Hero Features (crypto edge)
141
+
142
+ 1. Session-aware VWAP (`vwapSession`, `createVWAPSession`)
143
+ 2. Funding analytics (`fundingRateCumulative`, `fundingRateAPR`)
144
+ 3. Volatility regime labeling (`volatilityRegime`)
145
+ 4. Orderflow proxies (`signedVolume`, `volumeDelta`, `orderflowImbalance`)
146
+ 5. Streaming/stateful indicators for low-allocation pipelines
147
+
148
+ Limitations:
149
+ - Orderflow proxies infer pressure from candle direction and volume; they are not a replacement for L2/L3 order book data.
150
+ - Different libraries use different warmup conventions; comparisons use overlapping non-null windows.
151
+
152
+ ## Candle Contracts
153
+
154
+ Use typed candles plus helpers:
155
+
156
+ ```ts
157
+ import { pluckClose, toOHLCV } from "ta-crypto";
158
+
159
+ const close = pluckClose(candles);
160
+ const { open, high, low, close: c, volume } = toOHLCV(candles, 0);
161
+ ```
162
+
163
+ Validation:
164
+ - Multi-series indicators enforce equal lengths (`assertSameLength`).
165
+ - Candle helpers validate finite numeric fields with index-specific error messages.
166
+
167
+ ## Module Imports
168
+
169
+ ```ts
170
+ import { sma } from "ta-crypto/indicators";
171
+ import { vwapSession } from "ta-crypto/crypto";
172
+ import { toOHLCV } from "ta-crypto/candles";
173
+ import { createRSI } from "ta-crypto/stateful";
174
+ ```
175
+
176
+ ## Bench (internal baseline, 10k candles)
177
+
178
+ ```text
179
+ sma(14): 0.619 ms/run
180
+ ema(14): 0.549 ms/run
181
+ rsi(14): 0.647 ms/run
182
+ macd: 2.887 ms/run
183
+ bbands: 2.159 ms/run
184
+ atr(14): 1.356 ms/run
185
+ adx(14): 5.371 ms/run
186
+ ```
187
+
188
+ Run locally:
189
+
190
+ ```bash
191
+ npm run bench
192
+ ```
193
+
194
+ ## Release
195
+
196
+ Publications are gated by GitHub Actions:
197
+ - `CI` runs build/tests + compatibility checks.
198
+ - `Release` workflows run tests/compat again before publish.
199
+
200
+ Recommended with GitHub CLI:
201
+
202
+ ```bash
203
+ gh auth login
204
+ gh workflow run ci.yml
205
+ gh run list --workflow ci.yml --limit 1
206
+ ```
207
+
208
+ ```bash
209
+ npm run changelog
210
+ npm run version:patch
211
+ npm run release
212
+ ```
213
+
214
+ ## License
215
+
216
+ MIT
@@ -0,0 +1,15 @@
1
+ import type { Candle } from "./types.js";
2
+ export type OHLCV = {
3
+ open: number[];
4
+ high: number[];
5
+ low: number[];
6
+ close: number[];
7
+ volume: number[];
8
+ time: Array<number | string | Date | undefined>;
9
+ };
10
+ export declare function pluckOpen(candles: Candle[]): number[];
11
+ export declare function pluckHigh(candles: Candle[]): number[];
12
+ export declare function pluckLow(candles: Candle[]): number[];
13
+ export declare function pluckClose(candles: Candle[]): number[];
14
+ export declare function pluckVolume(candles: Candle[], fallback?: number): number[];
15
+ export declare function toOHLCV(candles: Candle[], volumeFallback?: number): OHLCV;
@@ -0,0 +1,36 @@
1
+ import { assertFiniteSeries } from "./core/math.js";
2
+ export function pluckOpen(candles) {
3
+ const out = candles.map(c => c.open);
4
+ assertFiniteSeries("open", out);
5
+ return out;
6
+ }
7
+ export function pluckHigh(candles) {
8
+ const out = candles.map(c => c.high);
9
+ assertFiniteSeries("high", out);
10
+ return out;
11
+ }
12
+ export function pluckLow(candles) {
13
+ const out = candles.map(c => c.low);
14
+ assertFiniteSeries("low", out);
15
+ return out;
16
+ }
17
+ export function pluckClose(candles) {
18
+ const out = candles.map(c => c.close);
19
+ assertFiniteSeries("close", out);
20
+ return out;
21
+ }
22
+ export function pluckVolume(candles, fallback = 0) {
23
+ const out = candles.map(c => (c.volume === undefined ? fallback : c.volume));
24
+ assertFiniteSeries("volume", out);
25
+ return out;
26
+ }
27
+ export function toOHLCV(candles, volumeFallback = 0) {
28
+ return {
29
+ open: pluckOpen(candles),
30
+ high: pluckHigh(candles),
31
+ low: pluckLow(candles),
32
+ close: pluckClose(candles),
33
+ volume: pluckVolume(candles, volumeFallback),
34
+ time: candles.map(c => c.time)
35
+ };
36
+ }
@@ -1,4 +1,5 @@
1
1
  export declare function isNum(value: unknown): value is number;
2
+ export declare function assertFiniteSeries(name: string, values: number[]): void;
2
3
  export declare function assertSameLength(...series: number[][]): void;
3
4
  export declare function makeSeries(length: number): Array<number | null>;
4
5
  export declare function sum(values: number[], start: number, end: number): number;
package/dist/core/math.js CHANGED
@@ -1,13 +1,20 @@
1
1
  export function isNum(value) {
2
2
  return typeof value === "number" && Number.isFinite(value);
3
3
  }
4
+ export function assertFiniteSeries(name, values) {
5
+ for (let i = 0; i < values.length; i++) {
6
+ if (!isNum(values[i])) {
7
+ throw new Error(`${name}[${i}] must be a finite number`);
8
+ }
9
+ }
10
+ }
4
11
  export function assertSameLength(...series) {
5
12
  if (series.length === 0)
6
13
  return;
7
14
  const len = series[0].length;
8
15
  for (const s of series) {
9
16
  if (s.length !== len) {
10
- throw new Error("All series must have the same length");
17
+ throw new Error(`All series must have the same length (expected ${len}, got ${s.length})`);
11
18
  }
12
19
  }
13
20
  }
@@ -1,4 +1,4 @@
1
- import { makeSeries } from "./math.js";
1
+ import { assertSameLength, makeSeries } from "./math.js";
2
2
  import { ema } from "./overlap.js";
3
3
  export function macd(values, fast = 12, slow = 26, signal = 9) {
4
4
  const fastEma = ema(values, fast);
@@ -47,10 +47,8 @@ export function rsi(values, length = 14) {
47
47
  return out;
48
48
  }
49
49
  export function stoch(high, low, close, kLength = 14, dLength = 3) {
50
+ assertSameLength(high, low, close);
50
51
  const len = close.length;
51
- if (high.length !== len || low.length !== len) {
52
- throw new Error("All series must have the same length");
53
- }
54
52
  const k = makeSeries(len);
55
53
  const d = makeSeries(len);
56
54
  for (let i = kLength - 1; i < len; i++) {
@@ -1,11 +1,9 @@
1
- import { makeSeries } from "./math.js";
1
+ import { assertSameLength, makeSeries } from "./math.js";
2
2
  import { rma } from "./overlap.js";
3
3
  import { trueRange } from "./volatility.js";
4
4
  export function adx(high, low, close, length = 14) {
5
+ assertSameLength(high, low, close);
5
6
  const len = close.length;
6
- if (high.length !== len || low.length !== len) {
7
- throw new Error("All series must have the same length");
8
- }
9
7
  const plusDM = new Array(len).fill(0);
10
8
  const minusDM = new Array(len).fill(0);
11
9
  for (let i = 1; i < len; i++) {
@@ -1,8 +1,6 @@
1
- import { makeSeries } from "./math.js";
1
+ import { assertSameLength, makeSeries } from "./math.js";
2
2
  export function obv(close, volume) {
3
- if (close.length !== volume.length) {
4
- throw new Error("All series must have the same length");
5
- }
3
+ assertSameLength(close, volume);
6
4
  const out = makeSeries(close.length);
7
5
  let acc = 0;
8
6
  for (let i = 0; i < close.length; i++) {
@@ -19,10 +17,8 @@ export function obv(close, volume) {
19
17
  return out;
20
18
  }
21
19
  export function mfi(high, low, close, volume, length = 14) {
20
+ assertSameLength(high, low, close, volume);
22
21
  const len = close.length;
23
- if (high.length !== len || low.length !== len || volume.length !== len) {
24
- throw new Error("All series must have the same length");
25
- }
26
22
  const out = makeSeries(len);
27
23
  if (length <= 0)
28
24
  return out;
@@ -0,0 +1,2 @@
1
+ export { vwapSession, fundingRateCumulative, fundingRateAPR, volatilityRegime, signedVolume, volumeDelta, orderflowImbalance } from "./core/crypto.js";
2
+ export { createVWAPSession } from "./stateful.js";
package/dist/crypto.js ADDED
@@ -0,0 +1,2 @@
1
+ export { vwapSession, fundingRateCumulative, fundingRateAPR, volatilityRegime, signedVolume, volumeDelta, orderflowImbalance } from "./core/crypto.js";
2
+ export { createVWAPSession } from "./stateful.js";
package/dist/index.d.ts CHANGED
@@ -5,8 +5,20 @@ export { logReturn, percentReturn, realizedVolatility } from "./core/performance
5
5
  export { obv, mfi } from "./core/volume.js";
6
6
  export { adx } from "./core/trend.js";
7
7
  export { vwapSession, fundingRateCumulative, fundingRateAPR, volatilityRegime, signedVolume, volumeDelta, orderflowImbalance } from "./core/crypto.js";
8
+ export { pluckOpen, pluckHigh, pluckLow, pluckClose, pluckVolume, toOHLCV } from "./candles.js";
9
+ export { createRSI, createVWAPSession } from "./stateful.js";
8
10
  export * from "./types.js";
11
+ import * as candles from "./candles.js";
12
+ import * as stateful from "./stateful.js";
9
13
  export declare const ta: {
14
+ createRSI(period?: number): stateful.StatefulIndicator<number, number | null>;
15
+ createVWAPSession(): stateful.StatefulIndicator<stateful.VWAPSessionInput, number | null>;
16
+ pluckOpen(candles: import("./types.js").Candle[]): number[];
17
+ pluckHigh(candles: import("./types.js").Candle[]): number[];
18
+ pluckLow(candles: import("./types.js").Candle[]): number[];
19
+ pluckClose(candles: import("./types.js").Candle[]): number[];
20
+ pluckVolume(candles: import("./types.js").Candle[], fallback?: number): number[];
21
+ toOHLCV(candles: import("./types.js").Candle[], volumeFallback?: number): candles.OHLCV;
10
22
  vwapSession(high: number[], low: number[], close: number[], volume: number[], session: Array<string | number>): Array<number | null>;
11
23
  fundingRateCumulative(values: number[]): Array<number | null>;
12
24
  fundingRateAPR(values: number[], periodsPerYear?: number): Array<number | null>;
package/dist/index.js CHANGED
@@ -5,6 +5,8 @@ export { logReturn, percentReturn, realizedVolatility } from "./core/performance
5
5
  export { obv, mfi } from "./core/volume.js";
6
6
  export { adx } from "./core/trend.js";
7
7
  export { vwapSession, fundingRateCumulative, fundingRateAPR, volatilityRegime, signedVolume, volumeDelta, orderflowImbalance } from "./core/crypto.js";
8
+ export { pluckOpen, pluckHigh, pluckLow, pluckClose, pluckVolume, toOHLCV } from "./candles.js";
9
+ export { createRSI, createVWAPSession } from "./stateful.js";
8
10
  export * from "./types.js";
9
11
  import * as overlap from "./core/overlap.js";
10
12
  import * as momentum from "./core/momentum.js";
@@ -13,6 +15,8 @@ import * as performance from "./core/performance.js";
13
15
  import * as volume from "./core/volume.js";
14
16
  import * as trend from "./core/trend.js";
15
17
  import * as crypto from "./core/crypto.js";
18
+ import * as candles from "./candles.js";
19
+ import * as stateful from "./stateful.js";
16
20
  export const ta = {
17
21
  ...overlap,
18
22
  ...momentum,
@@ -20,5 +24,7 @@ export const ta = {
20
24
  ...performance,
21
25
  ...volume,
22
26
  ...trend,
23
- ...crypto
27
+ ...crypto,
28
+ ...candles,
29
+ ...stateful
24
30
  };
@@ -0,0 +1,6 @@
1
+ export { sma, ema, rma, hl2, hlc3, ohlc4, vwap, bbands } from "./core/overlap.js";
2
+ export { rsi, macd, stoch } from "./core/momentum.js";
3
+ export { trueRange, atr, natr } from "./core/volatility.js";
4
+ export { logReturn, percentReturn, realizedVolatility } from "./core/performance.js";
5
+ export { obv, mfi } from "./core/volume.js";
6
+ export { adx } from "./core/trend.js";
@@ -0,0 +1,6 @@
1
+ export { sma, ema, rma, hl2, hlc3, ohlc4, vwap, bbands } from "./core/overlap.js";
2
+ export { rsi, macd, stoch } from "./core/momentum.js";
3
+ export { trueRange, atr, natr } from "./core/volatility.js";
4
+ export { logReturn, percentReturn, realizedVolatility } from "./core/performance.js";
5
+ export { obv, mfi } from "./core/volume.js";
6
+ export { adx } from "./core/trend.js";
@@ -0,0 +1,13 @@
1
+ export type StatefulIndicator<TIn, TOut> = {
2
+ next(value: TIn): TOut;
3
+ reset(): void;
4
+ };
5
+ export declare function createRSI(period?: number): StatefulIndicator<number, number | null>;
6
+ export type VWAPSessionInput = {
7
+ high: number;
8
+ low: number;
9
+ close: number;
10
+ volume: number;
11
+ sessionId: string | number;
12
+ };
13
+ export declare function createVWAPSession(): StatefulIndicator<VWAPSessionInput, number | null>;
@@ -0,0 +1,83 @@
1
+ export function createRSI(period = 14) {
2
+ if (period <= 0) {
3
+ throw new Error("period must be > 0");
4
+ }
5
+ let prevPrice = null;
6
+ let avgGain = 0;
7
+ let avgLoss = 0;
8
+ let seedGain = 0;
9
+ let seedLoss = 0;
10
+ let seedCount = 0;
11
+ let count = 0;
12
+ return {
13
+ next(price) {
14
+ if (!Number.isFinite(price)) {
15
+ throw new Error("price must be a finite number");
16
+ }
17
+ count += 1;
18
+ if (prevPrice === null) {
19
+ prevPrice = price;
20
+ return null;
21
+ }
22
+ const diff = price - prevPrice;
23
+ prevPrice = price;
24
+ const gain = diff > 0 ? diff : 0;
25
+ const loss = diff < 0 ? -diff : 0;
26
+ if (seedCount < period) {
27
+ seedGain += gain;
28
+ seedLoss += loss;
29
+ seedCount += 1;
30
+ if (seedCount < period)
31
+ return null;
32
+ avgGain = seedGain / period;
33
+ avgLoss = seedLoss / period;
34
+ }
35
+ else {
36
+ avgGain = (avgGain * (period - 1) + gain) / period;
37
+ avgLoss = (avgLoss * (period - 1) + loss) / period;
38
+ }
39
+ if (count < period + 1)
40
+ return null;
41
+ if (avgLoss === 0)
42
+ return 100;
43
+ const rs = avgGain / avgLoss;
44
+ return 100 - 100 / (1 + rs);
45
+ },
46
+ reset() {
47
+ prevPrice = null;
48
+ avgGain = 0;
49
+ avgLoss = 0;
50
+ seedGain = 0;
51
+ seedLoss = 0;
52
+ seedCount = 0;
53
+ count = 0;
54
+ }
55
+ };
56
+ }
57
+ export function createVWAPSession() {
58
+ let cumPV = 0;
59
+ let cumV = 0;
60
+ let lastSession;
61
+ return {
62
+ next(candle) {
63
+ const { high, low, close, volume, sessionId } = candle;
64
+ if (!Number.isFinite(high) || !Number.isFinite(low) || !Number.isFinite(close) || !Number.isFinite(volume)) {
65
+ throw new Error("high, low, close and volume must be finite numbers");
66
+ }
67
+ if (lastSession !== sessionId) {
68
+ cumPV = 0;
69
+ cumV = 0;
70
+ lastSession = sessionId;
71
+ }
72
+ const typical = (high + low + close) / 3;
73
+ cumPV += typical * volume;
74
+ cumV += volume;
75
+ return cumV === 0 ? null : cumPV / cumV;
76
+ },
77
+ reset() {
78
+ cumPV = 0;
79
+ cumV = 0;
80
+ lastSession = undefined;
81
+ }
82
+ };
83
+ }
package/package.json CHANGED
@@ -1,55 +1,80 @@
1
- {
2
- "name": "ta-crypto",
3
- "version": "0.1.5",
4
- "description": "Technical analysis for crypto markets in Node.js",
5
- "type": "module",
6
- "license": "MIT",
7
- "author": "",
8
- "exports": {
9
- ".": {
10
- "types": "./dist/index.d.ts",
11
- "import": "./dist/index.js"
12
- }
13
- },
14
- "types": "dist/index.d.ts",
15
- "main": "dist/index.js",
16
- "files": [
17
- "dist",
18
- "README.md",
19
- "LICENSE"
20
- ],
21
- "scripts": {
22
- "build": "tsc -p tsconfig.json",
23
- "clean": "rimraf dist",
24
- "prepublishOnly": "npm run clean && npm run build",
25
- "release": "node ./scripts/release.js",
26
- "release:patch": "npm version patch && npm run release",
27
- "release:minor": "npm version minor && npm run release",
28
- "release:major": "npm version major && npm run release",
29
- "version:patch": "npm version patch",
30
- "version:minor": "npm version minor",
31
- "version:major": "npm version major",
32
- "changelog": "node ./scripts/changelog.js",
33
- "test": "node -e \"console.log('no tests yet')\""
34
- },
35
- "devDependencies": {
36
- "rimraf": "^5.0.5",
37
- "typescript": "^5.4.5"
38
- },
39
- "keywords": [
40
- "crypto",
41
- "bitcoin",
42
- "technical-analysis",
43
- "indicators",
44
- "trading",
45
- "ohlcv"
46
- ],
47
- "repository": {
48
- "type": "git",
49
- "url": "git+https://github.com/TDamiao/ta-crypto.git"
50
- },
51
- "bugs": {
52
- "url": "https://github.com/TDamiao/ta-crypto/issues"
53
- },
54
- "homepage": "https://github.com/TDamiao/ta-crypto#readme"
55
- }
1
+ {
2
+ "name": "ta-crypto",
3
+ "version": "0.2.3",
4
+ "description": "Technical analysis for crypto markets in Node.js",
5
+ "type": "module",
6
+ "license": "MIT",
7
+ "author": "",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "import": "./dist/index.js"
12
+ },
13
+ "./indicators": {
14
+ "types": "./dist/indicators.d.ts",
15
+ "import": "./dist/indicators.js"
16
+ },
17
+ "./crypto": {
18
+ "types": "./dist/crypto.d.ts",
19
+ "import": "./dist/crypto.js"
20
+ },
21
+ "./candles": {
22
+ "types": "./dist/candles.d.ts",
23
+ "import": "./dist/candles.js"
24
+ },
25
+ "./stateful": {
26
+ "types": "./dist/stateful.d.ts",
27
+ "import": "./dist/stateful.js"
28
+ }
29
+ },
30
+ "sideEffects": false,
31
+ "types": "dist/index.d.ts",
32
+ "main": "dist/index.js",
33
+ "files": [
34
+ "dist",
35
+ "README.md",
36
+ "LICENSE"
37
+ ],
38
+ "scripts": {
39
+ "build": "tsc -p tsconfig.json",
40
+ "clean": "rimraf dist",
41
+ "prepublishOnly": "npm run clean && npm run build",
42
+ "release": "node ./scripts/release.js",
43
+ "release:patch": "npm version patch && npm run release",
44
+ "release:minor": "npm version minor && npm run release",
45
+ "release:major": "npm version major && npm run release",
46
+ "version:patch": "npm version patch",
47
+ "version:minor": "npm version minor",
48
+ "version:major": "npm version major",
49
+ "changelog": "node ./scripts/changelog.js",
50
+ "generate:golden": "npm run build && node ./scripts/generate-golden.js",
51
+ "generate:compat": "npm run build && node ./scripts/export-compat-vectors.js",
52
+ "bench": "npm run build && node ./scripts/bench.js",
53
+ "test": "npm run build && node --test test/*.test.mjs",
54
+ "test:golden": "npm run build && node --test test/golden.test.mjs",
55
+ "test:compat:technicalindicators": "npm run generate:compat && node ./scripts/compare-technicalindicators.js",
56
+ "test:compat:python": "npm run generate:compat && python ./scripts/compare-python-refs.py",
57
+ "test:compat": "npm run test:compat:technicalindicators && npm run test:compat:python"
58
+ },
59
+ "devDependencies": {
60
+ "rimraf": "^5.0.5",
61
+ "technicalindicators": "^3.1.0",
62
+ "typescript": "^5.4.5"
63
+ },
64
+ "keywords": [
65
+ "crypto",
66
+ "bitcoin",
67
+ "technical-analysis",
68
+ "indicators",
69
+ "trading",
70
+ "ohlcv"
71
+ ],
72
+ "repository": {
73
+ "type": "git",
74
+ "url": "git+https://github.com/TDamiao/ta-crypto.git"
75
+ },
76
+ "bugs": {
77
+ "url": "https://github.com/TDamiao/ta-crypto/issues"
78
+ },
79
+ "homepage": "https://github.com/TDamiao/ta-crypto#readme"
80
+ }