@vulcan-js/indicators 0.1.0 → 0.2.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/dist/index.js CHANGED
@@ -1,81 +1,179 @@
1
- import { assert, constants, createSignal, toDnum } from "@vulcan-js/core";
2
- import { abs, add, div, divide, eq, equal, from, gt, lt, mul, multiply, sub, subtract } from "dnum";
1
+ import { assert, createSignal, fp18 } from "@vulcan-js/core";
3
2
 
4
- //#region src/trend/exponentialMovingAverage.ts
5
- const defaultExponentialMovingAverageOptions = { period: 12 };
3
+ //#region src/primitives/ad.ts
6
4
  /**
7
- * Exponential Moving Average (EMA)
5
+ * Create an accumulation/distribution processor.
8
6
  *
9
- * EMA = Price * k + PrevEMA * (1 - k)
10
- * Where k = 2 / (period + 1)
7
+ * MFM = ((C - L) - (H - C)) / (H - L)
8
+ * MFV = MFM * Volume
9
+ * AD = Previous AD + MFV
11
10
  */
12
- const ema = createSignal(({ period }) => {
13
- assert(Number.isInteger(period) && period >= 1, /* @__PURE__ */ new RangeError(`Expected period to be a positive integer, got ${period}`));
14
- const k = divide(constants.TWO, toDnum(1 + period), constants.DECIMALS);
15
- const m = subtract(constants.ONE, k);
11
+ function ad$1() {
12
+ let prevAD = fp18.ZERO;
13
+ return (h, l, c, v) => {
14
+ const range = h - l;
15
+ const mfm = range === fp18.ZERO ? fp18.ZERO : fp18.div(c - l - (h - c), range);
16
+ const mfv = fp18.mul(mfm, v);
17
+ prevAD += mfv;
18
+ return prevAD;
19
+ };
20
+ }
21
+
22
+ //#endregion
23
+ //#region src/primitives/ewma.ts
24
+ /**
25
+ * Create an exponentially weighted moving average (EWMA) processor.
26
+ *
27
+ * new = value * k + prev * (1 - k)
28
+ *
29
+ * @param k - Smoothing factor as fp18 bigint
30
+ */
31
+ function ewma(k) {
32
+ const m = fp18.ONE - k;
16
33
  let prev;
17
34
  return (value) => {
18
35
  if (prev === void 0) {
19
- prev = toDnum(value);
36
+ prev = value;
20
37
  return prev;
21
38
  }
22
- prev = add(mul(value, k, constants.DECIMALS), mul(prev, m, constants.DECIMALS));
39
+ prev = (value * k + prev * m) / fp18.SCALE;
23
40
  return prev;
24
41
  };
25
- }, defaultExponentialMovingAverageOptions);
42
+ }
43
+ /** Compute EMA smoothing factor: k = 2 / (period + 1) */
44
+ ewma.k = (period) => fp18.div(fp18.TWO, BigInt(1 + period) * fp18.SCALE);
26
45
 
27
46
  //#endregion
28
- //#region src/momentum/absolutePriceOscillator.ts
29
- const defaultAbsolutePriceOscillatorOptions = {
30
- fastPeriod: 12,
31
- slowPeriod: 26
32
- };
33
- const apo = createSignal(({ fastPeriod, slowPeriod }) => {
34
- assert(Number.isInteger(fastPeriod) && fastPeriod >= 1, /* @__PURE__ */ new RangeError(`Expected fastPeriod to be a positive integer, got ${fastPeriod}`));
35
- assert(Number.isInteger(slowPeriod) && slowPeriod >= 1, /* @__PURE__ */ new RangeError(`Expected slowPeriod to be a positive integer, got ${slowPeriod}`));
36
- const fastProc = ema.create({ period: fastPeriod });
37
- const slowProc = ema.create({ period: slowPeriod });
38
- return (value) => sub(fastProc(value), slowProc(value));
39
- }, defaultAbsolutePriceOscillatorOptions);
47
+ //#region src/primitives/mmax.ts
48
+ /**
49
+ * Create a moving maximum processor.
50
+ *
51
+ * Tracks the maximum value in a sliding window of `period` values.
52
+ */
53
+ function mmax$1(period) {
54
+ assert(Number.isInteger(period) && period >= 1, /* @__PURE__ */ new RangeError(`Expected period to be a positive integer, got ${period}`));
55
+ const buffer = [];
56
+ return (value) => {
57
+ buffer.push(value);
58
+ if (buffer.length > period) buffer.shift();
59
+ return buffer.reduce((max, cur) => cur > max ? cur : max);
60
+ };
61
+ }
40
62
 
41
63
  //#endregion
42
- //#region src/trend/simpleMovingAverage.ts
43
- const defaultSMAOptions = { period: 2 };
64
+ //#region src/primitives/mmin.ts
44
65
  /**
45
- * Simple Moving Average (SMA)
66
+ * Create a moving minimum processor.
46
67
  *
47
- * Calculates the arithmetic mean of a set of values over a specified period.
48
- * The SMA is calculated by summing all values in the period and dividing by the period length.
68
+ * Tracks the minimum value in a sliding window of `period` values.
69
+ */
70
+ function mmin$1(period) {
71
+ assert(Number.isInteger(period) && period >= 1, /* @__PURE__ */ new RangeError(`Expected period to be a positive integer, got ${period}`));
72
+ const buffer = [];
73
+ return (value) => {
74
+ buffer.push(value);
75
+ if (buffer.length > period) buffer.shift();
76
+ return buffer.reduce((min, cur) => cur < min ? cur : min);
77
+ };
78
+ }
79
+
80
+ //#endregion
81
+ //#region src/primitives/msum.ts
82
+ /**
83
+ * Create a moving sum processor.
49
84
  *
50
- * Formula: SMA = (P1 + P2 + ... + Pn) / n
51
- * Where: P = Price values, n = Period
85
+ * Uses a ring buffer to maintain a sliding window of `period` values.
86
+ */
87
+ function msum$1(period) {
88
+ assert(Number.isInteger(period) && period >= 1, /* @__PURE__ */ new RangeError(`Expected period to be a positive integer, got ${period}`));
89
+ const buffer = Array.from({ length: period });
90
+ let head = 0;
91
+ let count = 0;
92
+ let runningSum = fp18.ZERO;
93
+ return (value) => {
94
+ if (count < period) {
95
+ buffer[count] = value;
96
+ runningSum += value;
97
+ count++;
98
+ } else {
99
+ runningSum = runningSum - buffer[head] + value;
100
+ buffer[head] = value;
101
+ head = (head + 1) % period;
102
+ }
103
+ return runningSum;
104
+ };
105
+ }
106
+
107
+ //#endregion
108
+ //#region src/primitives/rma.ts
109
+ /**
110
+ * Create a rolling moving average (RMA) processor.
52
111
  *
53
- * @param source - Iterable of price values
54
- * @param options - Configuration options
55
- * @param options.period - The period for calculating the moving average (default: 2)
56
- * @returns Generator yielding SMA values
112
+ * Warm-up: running SMA for the first `period` values.
113
+ * After: R[i] = (R[i-1] * (period - 1) + value) / period
57
114
  */
58
- const sma = createSignal(({ period }) => {
115
+ function rma$1(period) {
116
+ assert(Number.isInteger(period) && period >= 1, /* @__PURE__ */ new RangeError(`Expected period to be a positive integer, got ${period}`));
117
+ const periodBig = BigInt(period);
118
+ let count = 0;
119
+ let sum = fp18.ZERO;
120
+ let prev = fp18.ZERO;
121
+ return (value) => {
122
+ if (count < period) {
123
+ sum += value;
124
+ count++;
125
+ prev = sum / BigInt(count);
126
+ return prev;
127
+ }
128
+ prev = (prev * (periodBig - 1n) + value) / periodBig;
129
+ return prev;
130
+ };
131
+ }
132
+
133
+ //#endregion
134
+ //#region src/primitives/sma.ts
135
+ /**
136
+ * Create a simple moving average (SMA) processor.
137
+ *
138
+ * Uses a ring buffer to maintain a sliding window of `period` values.
139
+ * Returns the running average (sum / count) during warm-up.
140
+ */
141
+ function sma$1(period) {
59
142
  assert(Number.isInteger(period) && period >= 1, /* @__PURE__ */ new RangeError(`Expected period to be a positive integer, got ${period}`));
60
143
  const buffer = Array.from({ length: period });
61
144
  let head = 0;
62
145
  let count = 0;
63
- let runningSum = constants.ZERO;
146
+ let runningSum = fp18.ZERO;
64
147
  return (value) => {
65
- const v = toDnum(value);
66
148
  if (count < period) {
67
- buffer[count] = v;
68
- runningSum = add(runningSum, v);
149
+ buffer[count] = value;
150
+ runningSum += value;
69
151
  count++;
70
152
  } else {
71
- runningSum = subtract(runningSum, buffer[head]);
72
- runningSum = add(runningSum, v);
73
- buffer[head] = v;
153
+ runningSum = runningSum - buffer[head] + value;
154
+ buffer[head] = value;
74
155
  head = (head + 1) % period;
75
156
  }
76
- return div(runningSum, count, constants.DECIMALS);
157
+ return runningSum / BigInt(count);
77
158
  };
78
- }, defaultSMAOptions);
159
+ }
160
+
161
+ //#endregion
162
+ //#region src/momentum/absolutePriceOscillator.ts
163
+ const defaultAbsolutePriceOscillatorOptions = {
164
+ fastPeriod: 12,
165
+ slowPeriod: 26
166
+ };
167
+ const apo = createSignal(({ fastPeriod, slowPeriod }) => {
168
+ assert(Number.isInteger(fastPeriod) && fastPeriod >= 1, /* @__PURE__ */ new RangeError(`Expected fastPeriod to be a positive integer, got ${fastPeriod}`));
169
+ assert(Number.isInteger(slowPeriod) && slowPeriod >= 1, /* @__PURE__ */ new RangeError(`Expected slowPeriod to be a positive integer, got ${slowPeriod}`));
170
+ const fastProc = ewma(ewma.k(fastPeriod));
171
+ const slowProc = ewma(ewma.k(slowPeriod));
172
+ return (value) => {
173
+ const v = fp18.toFp18(value);
174
+ return fp18.toDnum(fastProc(v) - slowProc(v));
175
+ };
176
+ }, defaultAbsolutePriceOscillatorOptions);
79
177
 
80
178
  //#endregion
81
179
  //#region src/momentum/awesomeOscillator.ts
@@ -92,38 +190,14 @@ const defaultAwesomeOscillatorOptions = {
92
190
  const ao = createSignal(({ fastPeriod, slowPeriod }) => {
93
191
  assert(Number.isInteger(fastPeriod) && fastPeriod >= 1, /* @__PURE__ */ new RangeError(`Expected fastPeriod to be a positive integer, got ${fastPeriod}`));
94
192
  assert(Number.isInteger(slowPeriod) && slowPeriod >= 1, /* @__PURE__ */ new RangeError(`Expected slowPeriod to be a positive integer, got ${slowPeriod}`));
95
- const fastProc = sma.create({ period: fastPeriod });
96
- const slowProc = sma.create({ period: slowPeriod });
193
+ const fastProc = sma$1(fastPeriod);
194
+ const slowProc = sma$1(slowPeriod);
97
195
  return (bar) => {
98
- const median = div(add(toDnum(bar.h), toDnum(bar.l)), 2, constants.DECIMALS);
99
- return sub(fastProc(median), slowProc(median));
196
+ const median = (fp18.toFp18(bar.h) + fp18.toFp18(bar.l)) / 2n;
197
+ return fp18.toDnum(fastProc(median) - slowProc(median));
100
198
  };
101
199
  }, defaultAwesomeOscillatorOptions);
102
200
 
103
- //#endregion
104
- //#region src/volume/accumulationDistribution.ts
105
- /**
106
- * Accumulation/Distribution Indicator (A/D). Cumulative indicator
107
- * that uses volume and price to assess whether a stock is
108
- * being accumulated or distributed.
109
- *
110
- * MFM = ((Closing - Low) - (High - Closing)) / (High - Low)
111
- * MFV = MFM * Period Volume
112
- * AD = Previous AD + CMFV
113
- */
114
- const ad = createSignal(() => {
115
- let prevAD = constants.ZERO;
116
- return (bar) => {
117
- const h = toDnum(bar.h);
118
- const l = toDnum(bar.l);
119
- const c = toDnum(bar.c);
120
- const v = toDnum(bar.v);
121
- const range = subtract(h, l);
122
- prevAD = add(multiply(equal(range, 0) ? constants.ZERO : divide(subtract(subtract(c, l), subtract(h, c)), range, constants.DECIMALS), v), prevAD);
123
- return prevAD;
124
- };
125
- });
126
-
127
201
  //#endregion
128
202
  //#region src/momentum/chaikinOscillator.ts
129
203
  const defaultChaikinOscillatorOptions = {
@@ -142,18 +216,19 @@ const defaultChaikinOscillatorOptions = {
142
216
  const cmo = createSignal(({ fastPeriod, slowPeriod }) => {
143
217
  assert(Number.isInteger(fastPeriod) && fastPeriod >= 1, /* @__PURE__ */ new RangeError(`Expected fastPeriod to be a positive integer, got ${fastPeriod}`));
144
218
  assert(Number.isInteger(slowPeriod) && slowPeriod >= 1, /* @__PURE__ */ new RangeError(`Expected slowPeriod to be a positive integer, got ${slowPeriod}`));
145
- const adProc = ad.create();
146
- const fastProc = ema.create({ period: fastPeriod });
147
- const slowProc = ema.create({ period: slowPeriod });
219
+ const adProc = ad$1();
220
+ const fastProc = ewma(ewma.k(fastPeriod));
221
+ const slowProc = ewma(ewma.k(slowPeriod));
148
222
  return (bar) => {
149
- const adVal = adProc(bar);
150
- return sub(fastProc(adVal), slowProc(adVal));
223
+ const adVal = adProc(fp18.toFp18(bar.h), fp18.toFp18(bar.l), fp18.toFp18(bar.c), fp18.toFp18(bar.v));
224
+ return fp18.toDnum(fastProc(adVal) - slowProc(adVal));
151
225
  };
152
226
  }, defaultChaikinOscillatorOptions);
153
227
 
154
228
  //#endregion
155
229
  //#region src/momentum/commodityChannelIndex.ts
156
230
  const defaultCCIOptions = { period: 20 };
231
+ const LAMBERT = 15n * fp18.SCALE / 1000n;
157
232
  /**
158
233
  * Commodity Channel Index (CCI)
159
234
  *
@@ -175,24 +250,26 @@ const defaultCCIOptions = { period: 20 };
175
250
  const cci = createSignal(({ period }) => {
176
251
  assert(Number.isInteger(period) && period >= 1, /* @__PURE__ */ new RangeError(`Expected period to be a positive integer, got ${period}`));
177
252
  const buffer = [];
253
+ const periodBig = BigInt(period);
178
254
  return (bar) => {
179
- const h = toDnum(bar.h);
180
- const l = toDnum(bar.l);
181
- const c = toDnum(bar.c);
182
- const tp = divide(add(add(h, l), c), 3, constants.DECIMALS);
255
+ const h = fp18.toFp18(bar.h);
256
+ const l = fp18.toFp18(bar.l);
257
+ const c = fp18.toFp18(bar.c);
258
+ const tp = (h + l + c) / 3n;
183
259
  buffer.push(tp);
184
260
  if (buffer.length > period) buffer.shift();
185
261
  const n = buffer.length;
186
- if (n < period) return constants.ZERO;
187
- let sum = constants.ZERO;
188
- for (const v of buffer) sum = add(sum, v);
189
- const smaVal = divide(sum, n, constants.DECIMALS);
190
- let devSum = constants.ZERO;
191
- for (const v of buffer) devSum = add(devSum, abs(subtract(v, smaVal)));
192
- const meanDev = divide(devSum, n, constants.DECIMALS);
193
- if (equal(meanDev, 0)) return constants.ZERO;
194
- const currentTP = buffer[n - 1];
195
- return divide(subtract(currentTP, smaVal), divide([meanDev[0] * 15n, meanDev[1]], [1000n, 0], constants.DECIMALS), constants.DECIMALS);
262
+ if (n < period) return fp18.toDnum(fp18.ZERO);
263
+ let sum = fp18.ZERO;
264
+ for (const v of buffer) sum += v;
265
+ const smaVal = sum / periodBig;
266
+ let devSum = fp18.ZERO;
267
+ for (const v of buffer) devSum += fp18.abs(v - smaVal);
268
+ const meanDev = devSum / periodBig;
269
+ if (meanDev === fp18.ZERO) return fp18.toDnum(fp18.ZERO);
270
+ const numerator = buffer[n - 1] - smaVal;
271
+ const lambertMeanDev = fp18.mul(LAMBERT, meanDev);
272
+ return fp18.toDnum(fp18.div(numerator, lambertMeanDev));
196
273
  };
197
274
  }, defaultCCIOptions);
198
275
 
@@ -228,18 +305,19 @@ const ppo = createSignal(({ fastPeriod, slowPeriod, signalPeriod }) => {
228
305
  assert(Number.isInteger(fastPeriod) && fastPeriod >= 1, /* @__PURE__ */ new RangeError(`Expected fastPeriod to be a positive integer, got ${fastPeriod}`));
229
306
  assert(Number.isInteger(slowPeriod) && slowPeriod >= 1, /* @__PURE__ */ new RangeError(`Expected slowPeriod to be a positive integer, got ${slowPeriod}`));
230
307
  assert(Number.isInteger(signalPeriod) && signalPeriod >= 1, /* @__PURE__ */ new RangeError(`Expected signalPeriod to be a positive integer, got ${signalPeriod}`));
231
- const fastProc = ema.create({ period: fastPeriod });
232
- const slowProc = ema.create({ period: slowPeriod });
233
- const signalProc = ema.create({ period: signalPeriod });
308
+ const fastProc = ewma(ewma.k(fastPeriod));
309
+ const slowProc = ewma(ewma.k(slowPeriod));
310
+ const signalProc = ewma(ewma.k(signalPeriod));
234
311
  return (value) => {
235
- const fast = fastProc(toDnum(value));
236
- const slow = slowProc(toDnum(value));
237
- const ppoVal = eq(slow, 0) ? constants.ZERO : mul(div(sub(fast, slow), slow, constants.DECIMALS), 100, constants.DECIMALS);
312
+ const v = fp18.toFp18(value);
313
+ const fast = fastProc(v);
314
+ const slow = slowProc(v);
315
+ const ppoVal = slow === fp18.ZERO ? fp18.ZERO : fp18.div((fast - slow) * 100n, slow);
238
316
  const sig = signalProc(ppoVal);
239
317
  return {
240
- ppo: ppoVal,
241
- signal: sig,
242
- histogram: sub(ppoVal, sig)
318
+ ppo: fp18.toDnum(ppoVal),
319
+ signal: fp18.toDnum(sig),
320
+ histogram: fp18.toDnum(ppoVal - sig)
243
321
  };
244
322
  };
245
323
  }, defaultPercentagePriceOscillatorOptions);
@@ -280,18 +358,19 @@ const pvo = createSignal(({ fastPeriod, slowPeriod, signalPeriod }) => {
280
358
  assert(Number.isInteger(fastPeriod) && fastPeriod >= 1, /* @__PURE__ */ new RangeError(`Expected fastPeriod to be a positive integer, got ${fastPeriod}`));
281
359
  assert(Number.isInteger(slowPeriod) && slowPeriod >= 1, /* @__PURE__ */ new RangeError(`Expected slowPeriod to be a positive integer, got ${slowPeriod}`));
282
360
  assert(Number.isInteger(signalPeriod) && signalPeriod >= 1, /* @__PURE__ */ new RangeError(`Expected signalPeriod to be a positive integer, got ${signalPeriod}`));
283
- const fastProc = ema.create({ period: fastPeriod });
284
- const slowProc = ema.create({ period: slowPeriod });
285
- const signalProc = ema.create({ period: signalPeriod });
361
+ const fastProc = ewma(ewma.k(fastPeriod));
362
+ const slowProc = ewma(ewma.k(slowPeriod));
363
+ const signalProc = ewma(ewma.k(signalPeriod));
286
364
  return (value) => {
287
- const fast = fastProc(toDnum(value));
288
- const slow = slowProc(toDnum(value));
289
- const pvoVal = eq(slow, 0) ? constants.ZERO : mul(div(sub(fast, slow), slow, constants.DECIMALS), 100, constants.DECIMALS);
365
+ const v = fp18.toFp18(value);
366
+ const fast = fastProc(v);
367
+ const slow = slowProc(v);
368
+ const pvoVal = slow === fp18.ZERO ? fp18.ZERO : fp18.div((fast - slow) * 100n, slow);
290
369
  const sig = signalProc(pvoVal);
291
370
  return {
292
- pvo: pvoVal,
293
- signal: sig,
294
- histogram: sub(pvoVal, sig)
371
+ pvo: fp18.toDnum(pvoVal),
372
+ signal: fp18.toDnum(sig),
373
+ histogram: fp18.toDnum(pvoVal - sig)
295
374
  };
296
375
  };
297
376
  }, defaultPercentageVolumeOscillatorOptions);
@@ -319,52 +398,21 @@ const roc = createSignal(({ period }) => {
319
398
  let head = 0;
320
399
  let count = 0;
321
400
  return (value) => {
322
- const v = toDnum(value);
401
+ const v = fp18.toFp18(value);
323
402
  if (count < period) {
324
403
  buffer[count] = v;
325
404
  count++;
326
- return constants.ZERO;
405
+ return fp18.toDnum(fp18.ZERO);
327
406
  } else {
328
407
  const oldest = buffer[head];
329
408
  buffer[head] = v;
330
409
  head = (head + 1) % period;
331
- return eq(oldest, 0) ? constants.ZERO : mul(div(sub(v, oldest), oldest, constants.DECIMALS), 100, constants.DECIMALS);
410
+ if (oldest === fp18.ZERO) return fp18.toDnum(fp18.ZERO);
411
+ return fp18.toDnum(fp18.div((v - oldest) * 100n, oldest));
332
412
  }
333
413
  };
334
414
  }, defaultPriceRateOfChangeOptions);
335
415
 
336
- //#endregion
337
- //#region src/trend/movingMax.ts
338
- const defaultMovingMaxOptions = { period: 4 };
339
- /**
340
- * Moving Maximum (MovingMax)
341
- */
342
- const mmax = createSignal(({ period }) => {
343
- assert(Number.isInteger(period) && period >= 1, /* @__PURE__ */ new RangeError(`Expected period to be a positive integer, got ${period}`));
344
- const buffer = [];
345
- return (value) => {
346
- buffer.push(toDnum(value));
347
- if (buffer.length > period) buffer.shift();
348
- return buffer.reduce((max, cur) => gt(max, cur) ? max : cur);
349
- };
350
- }, defaultMovingMaxOptions);
351
-
352
- //#endregion
353
- //#region src/trend/movingMin.ts
354
- const defaultMovingMinOptions = { period: 4 };
355
- /**
356
- * Moving Minimum (MovingMin)
357
- */
358
- const mmin = createSignal(({ period }) => {
359
- assert(Number.isInteger(period) && period >= 1, /* @__PURE__ */ new RangeError(`Expected period to be a positive integer, got ${period}`));
360
- const buffer = [];
361
- return (value) => {
362
- buffer.push(toDnum(value));
363
- if (buffer.length > period) buffer.shift();
364
- return buffer.reduce((min, cur) => lt(min, cur) ? min : cur);
365
- };
366
- }, defaultMovingMinOptions);
367
-
368
416
  //#endregion
369
417
  //#region src/momentum/randomIndex.ts
370
418
  const defaultRandomIndexOptions = {
@@ -380,9 +428,9 @@ const defaultRandomIndexOptions = {
380
428
  * initial K and D values set to 50.
381
429
  *
382
430
  * Formula:
383
- * RSV = (Close - LowestLow(period)) / (HighestHigh(period) - LowestLow(period)) × 100
384
- * K = ((kPeriod - 1) / kPeriod) × prevK + (1 / kPeriod) × RSV
385
- * D = ((dPeriod - 1) / dPeriod) × prevD + (1 / dPeriod) × K
431
+ * RSV = (Close - LowestLow(period)) / (HighestHigh(period) - LowestLow(period)) * 100
432
+ * K = ((kPeriod - 1) / kPeriod) * prevK + (1 / kPeriod) * RSV
433
+ * D = ((dPeriod - 1) / dPeriod) * prevD + (1 / dPeriod) * K
386
434
  * J = 3K - 2D
387
435
  *
388
436
  * Interpretation:
@@ -401,69 +449,43 @@ const kdj = createSignal(({ period, kPeriod, dPeriod }) => {
401
449
  assert(Number.isInteger(period) && period >= 1, /* @__PURE__ */ new RangeError(`Expected period to be a positive integer, got ${period}`));
402
450
  assert(Number.isInteger(kPeriod) && kPeriod >= 1, /* @__PURE__ */ new RangeError(`Expected kPeriod to be a positive integer, got ${kPeriod}`));
403
451
  assert(Number.isInteger(dPeriod) && dPeriod >= 1, /* @__PURE__ */ new RangeError(`Expected dPeriod to be a positive integer, got ${dPeriod}`));
404
- const mmaxProc = mmax.create({ period });
405
- const mminProc = mmin.create({ period });
406
- const INITIAL = toDnum(50);
407
- const THREE = toDnum(3);
452
+ const mmaxProc = mmax$1(period);
453
+ const mminProc = mmin$1(period);
454
+ const INITIAL = 50n * fp18.SCALE;
455
+ const kPeriodBig = BigInt(kPeriod);
456
+ const dPeriodBig = BigInt(dPeriod);
408
457
  let prevK = INITIAL;
409
458
  let prevD = INITIAL;
410
459
  let isFirst = true;
411
460
  return (bar) => {
412
- const h = toDnum(bar.h);
413
- const l = toDnum(bar.l);
414
- const c = toDnum(bar.c);
461
+ const h = fp18.toFp18(bar.h);
462
+ const l = fp18.toFp18(bar.l);
463
+ const c = fp18.toFp18(bar.c);
415
464
  const highestHigh = mmaxProc(h);
416
465
  const lowestLow = mminProc(l);
417
- const range = sub(highestHigh, lowestLow, constants.DECIMALS);
418
- const rsv = eq(range, 0) ? constants.ZERO : mul(div(sub(c, lowestLow, constants.DECIMALS), range, constants.DECIMALS), constants.HUNDRED, constants.DECIMALS);
466
+ const range = highestHigh - lowestLow;
467
+ const rsv = range === fp18.ZERO ? fp18.ZERO : fp18.div((c - lowestLow) * 100n, range);
419
468
  let k;
420
469
  let d;
421
470
  if (isFirst) {
422
- k = add(mul(div(toDnum(kPeriod - 1), kPeriod, constants.DECIMALS), INITIAL, constants.DECIMALS), mul(div(constants.ONE, kPeriod, constants.DECIMALS), rsv, constants.DECIMALS));
423
- d = add(mul(div(toDnum(dPeriod - 1), dPeriod, constants.DECIMALS), INITIAL, constants.DECIMALS), mul(div(constants.ONE, dPeriod, constants.DECIMALS), k, constants.DECIMALS));
471
+ k = INITIAL * (kPeriodBig - 1n) / kPeriodBig + rsv / kPeriodBig;
472
+ d = INITIAL * (dPeriodBig - 1n) / dPeriodBig + k / dPeriodBig;
424
473
  isFirst = false;
425
474
  } else {
426
- k = add(mul(div(toDnum(kPeriod - 1), kPeriod, constants.DECIMALS), prevK, constants.DECIMALS), mul(div(constants.ONE, kPeriod, constants.DECIMALS), rsv, constants.DECIMALS));
427
- d = add(mul(div(toDnum(dPeriod - 1), dPeriod, constants.DECIMALS), prevD, constants.DECIMALS), mul(div(constants.ONE, dPeriod, constants.DECIMALS), k, constants.DECIMALS));
475
+ k = prevK * (kPeriodBig - 1n) / kPeriodBig + rsv / kPeriodBig;
476
+ d = prevD * (dPeriodBig - 1n) / dPeriodBig + k / dPeriodBig;
428
477
  }
429
- const j = sub(mul(THREE, k, constants.DECIMALS), mul(constants.TWO, d, constants.DECIMALS), constants.DECIMALS);
478
+ const j = k * 3n - d * 2n;
430
479
  prevK = k;
431
480
  prevD = d;
432
481
  return {
433
- k,
434
- d,
435
- j
482
+ k: fp18.toDnum(k),
483
+ d: fp18.toDnum(d),
484
+ j: fp18.toDnum(j)
436
485
  };
437
486
  };
438
487
  }, defaultRandomIndexOptions);
439
488
 
440
- //#endregion
441
- //#region src/trend/rollingMovingAverage.ts
442
- const defaultRMAOptions = { period: 4 };
443
- /**
444
- * Rolling moving average (RMA).
445
- *
446
- * R[0] to R[p-1] is SMA(values)
447
- *
448
- * R[p] and after is R[i] = ((R[i-1]*(p-1)) + v[i]) / p
449
- */
450
- const rma = createSignal(({ period }) => {
451
- assert(Number.isInteger(period) && period >= 1, /* @__PURE__ */ new RangeError(`Expected period to be a positive integer, got ${period}`));
452
- let count = 0;
453
- let sum = constants.ZERO;
454
- let prev = constants.ZERO;
455
- return (value) => {
456
- if (count < period) {
457
- sum = add(sum, value);
458
- count++;
459
- prev = div(sum, count, constants.DECIMALS);
460
- return prev;
461
- }
462
- prev = div(add(mul(prev, period - 1, constants.DECIMALS), value), period, constants.DECIMALS);
463
- return prev;
464
- };
465
- }, defaultRMAOptions);
466
-
467
489
  //#endregion
468
490
  //#region src/momentum/relativeStrengthIndex.ts
469
491
  const defaultRSIOptions = { period: 14 };
@@ -478,25 +500,26 @@ const defaultRSIOptions = { period: 14 };
478
500
  */
479
501
  const rsi = createSignal(({ period }) => {
480
502
  assert(Number.isInteger(period) && period >= 1, /* @__PURE__ */ new RangeError(`Expected period to be a positive integer, got ${period}`));
481
- const gainProc = rma.create({ period });
482
- const lossProc = rma.create({ period });
503
+ const gainProc = rma$1(period);
504
+ const lossProc = rma$1(period);
483
505
  let prev;
484
506
  return (value) => {
485
- const price = toDnum(value);
507
+ const price = fp18.toFp18(value);
486
508
  if (prev === void 0) {
487
509
  prev = price;
488
- gainProc(constants.ZERO);
489
- lossProc(constants.ZERO);
490
- return constants.ZERO;
510
+ gainProc(fp18.ZERO);
511
+ lossProc(fp18.ZERO);
512
+ return fp18.toDnum(fp18.ZERO);
491
513
  }
492
- const change = sub(price, prev);
514
+ const change = price - prev;
493
515
  prev = price;
494
- const gain = gt(change, 0) ? change : constants.ZERO;
495
- const loss = gt(change, 0) ? constants.ZERO : mul(change, -1, constants.DECIMALS);
516
+ const gain = change > fp18.ZERO ? change : fp18.ZERO;
517
+ const loss = change > fp18.ZERO ? fp18.ZERO : -change;
496
518
  const avgGain = gainProc(gain);
497
519
  const avgLoss = lossProc(loss);
498
- if (eq(avgLoss, 0)) return constants.HUNDRED;
499
- return sub(100, div(100, add(1, div(avgGain, avgLoss, constants.DECIMALS)), constants.DECIMALS));
520
+ if (avgLoss === fp18.ZERO) return fp18.toDnum(fp18.HUNDRED);
521
+ const rs = fp18.div(avgGain, avgLoss);
522
+ return fp18.toDnum(fp18.HUNDRED - fp18.div(fp18.HUNDRED, fp18.ONE + rs));
500
523
  };
501
524
  }, defaultRSIOptions);
502
525
 
@@ -517,22 +540,23 @@ const stoch = createSignal(({ kPeriod, slowingPeriod, dPeriod }) => {
517
540
  assert(Number.isInteger(kPeriod) && kPeriod >= 1, /* @__PURE__ */ new RangeError(`Expected kPeriod to be a positive integer, got ${kPeriod}`));
518
541
  assert(Number.isInteger(slowingPeriod) && slowingPeriod >= 1, /* @__PURE__ */ new RangeError(`Expected slowingPeriod to be a positive integer, got ${slowingPeriod}`));
519
542
  assert(Number.isInteger(dPeriod) && dPeriod >= 1, /* @__PURE__ */ new RangeError(`Expected dPeriod to be a positive integer, got ${dPeriod}`));
520
- const mmaxProc = mmax.create({ period: kPeriod });
521
- const mminProc = mmin.create({ period: kPeriod });
522
- const slowingProc = slowingPeriod > 1 ? sma.create({ period: slowingPeriod }) : null;
523
- const dProc = sma.create({ period: dPeriod });
543
+ const mmaxProc = mmax$1(kPeriod);
544
+ const mminProc = mmin$1(kPeriod);
545
+ const slowingProc = slowingPeriod > 1 ? sma$1(slowingPeriod) : null;
546
+ const dProc = sma$1(dPeriod);
524
547
  return (bar) => {
525
- const h = toDnum(bar.h);
526
- const l = toDnum(bar.l);
527
- const c = toDnum(bar.c);
548
+ const h = fp18.toFp18(bar.h);
549
+ const l = fp18.toFp18(bar.l);
550
+ const c = fp18.toFp18(bar.c);
528
551
  const highestHigh = mmaxProc(h);
529
552
  const lowestLow = mminProc(l);
530
- const range = sub(highestHigh, lowestLow, constants.DECIMALS);
531
- const rawK = eq(range, 0) ? constants.ZERO : mul(div(sub(c, lowestLow, constants.DECIMALS), range, constants.DECIMALS), 100, constants.DECIMALS);
553
+ const range = highestHigh - lowestLow;
554
+ const rawK = range === fp18.ZERO ? fp18.ZERO : fp18.div((c - lowestLow) * 100n, range);
532
555
  const k = slowingProc ? slowingProc(rawK) : rawK;
556
+ const d = dProc(k);
533
557
  return {
534
- k,
535
- d: dProc(k)
558
+ k: fp18.toDnum(k),
559
+ d: fp18.toDnum(d)
536
560
  };
537
561
  };
538
562
  }, defaultStochasticOscillatorOptions);
@@ -548,7 +572,7 @@ const defaultWilliamsROptions = { period: 14 };
548
572
  * over a specified period.
549
573
  *
550
574
  * Formula:
551
- * - %R = -100 × (Highest High - Close) / (Highest High - Lowest Low)
575
+ * - %R = -100 * (Highest High - Close) / (Highest High - Lowest Low)
552
576
  *
553
577
  * Range: -100 to 0
554
578
  * - Above -20: Overbought
@@ -561,15 +585,16 @@ const defaultWilliamsROptions = { period: 14 };
561
585
  */
562
586
  const willr = createSignal(({ period }) => {
563
587
  assert(Number.isInteger(period) && period >= 1, /* @__PURE__ */ new RangeError(`Expected period to be a positive integer, got ${period}`));
564
- const mmaxProc = mmax.create({ period });
565
- const mminProc = mmin.create({ period });
588
+ const mmaxProc = mmax$1(period);
589
+ const mminProc = mmin$1(period);
566
590
  return (bar) => {
567
- const h = toDnum(bar.h);
568
- const l = toDnum(bar.l);
569
- const c = toDnum(bar.c);
591
+ const h = fp18.toFp18(bar.h);
592
+ const l = fp18.toFp18(bar.l);
593
+ const c = fp18.toFp18(bar.c);
570
594
  const highestHigh = mmaxProc(h);
571
- const range = sub(highestHigh, mminProc(l), constants.DECIMALS);
572
- return eq(range, 0) ? constants.ZERO : mul(div(sub(highestHigh, c, constants.DECIMALS), range, constants.DECIMALS), -100, constants.DECIMALS);
595
+ const range = highestHigh - mminProc(l);
596
+ if (range === fp18.ZERO) return fp18.toDnum(fp18.ZERO);
597
+ return fp18.toDnum(fp18.div((highestHigh - c) * -100n, range));
573
598
  };
574
599
  }, defaultWilliamsROptions);
575
600
 
@@ -587,9 +612,10 @@ const aroon = createSignal(({ period }) => {
587
612
  assert(Number.isInteger(period) && period >= 1, /* @__PURE__ */ new RangeError(`Expected period to be a positive integer, got ${period}`));
588
613
  const highBuffer = [];
589
614
  const lowBuffer = [];
615
+ const periodBig = BigInt(period);
590
616
  return (bar) => {
591
- const h = toDnum(bar.h);
592
- const l = toDnum(bar.l);
617
+ const h = fp18.toFp18(bar.h);
618
+ const l = fp18.toFp18(bar.l);
593
619
  highBuffer.push(h);
594
620
  lowBuffer.push(l);
595
621
  if (highBuffer.length > period + 1) highBuffer.shift();
@@ -597,18 +623,17 @@ const aroon = createSignal(({ period }) => {
597
623
  let highestIdx = 0;
598
624
  let lowestIdx = 0;
599
625
  for (let j = 1; j < highBuffer.length; j++) {
600
- if (!gt(highBuffer[highestIdx], highBuffer[j])) highestIdx = j;
601
- if (!lt(lowBuffer[lowestIdx], lowBuffer[j])) lowestIdx = j;
626
+ if (highBuffer[j] >= highBuffer[highestIdx]) highestIdx = j;
627
+ if (lowBuffer[j] <= lowBuffer[lowestIdx]) lowestIdx = j;
602
628
  }
603
629
  const daysSinceHigh = highBuffer.length - 1 - highestIdx;
604
630
  const daysSinceLow = lowBuffer.length - 1 - lowestIdx;
605
- const periodDnum = toDnum(period);
606
- const up = divide(multiply(toDnum(period - daysSinceHigh), 100, constants.DECIMALS), periodDnum, constants.DECIMALS);
607
- const down = divide(multiply(toDnum(period - daysSinceLow), 100, constants.DECIMALS), periodDnum, constants.DECIMALS);
631
+ const up = BigInt(period - daysSinceHigh) * fp18.HUNDRED / periodBig;
632
+ const down = BigInt(period - daysSinceLow) * fp18.HUNDRED / periodBig;
608
633
  return {
609
- up,
610
- down,
611
- oscillator: subtract(up, down)
634
+ up: fp18.toDnum(up),
635
+ down: fp18.toDnum(down),
636
+ oscillator: fp18.toDnum(up - down)
612
637
  };
613
638
  };
614
639
  }, defaultAroonOptions);
@@ -617,13 +642,13 @@ const aroon = createSignal(({ period }) => {
617
642
  //#region src/trend/balanceOfPower.ts
618
643
  const bop = createSignal(() => {
619
644
  return (bar) => {
620
- const o = toDnum(bar.o);
621
- const h = toDnum(bar.h);
622
- const l = toDnum(bar.l);
623
- const c = toDnum(bar.c);
624
- const range = subtract(h, l);
625
- if (equal(range, 0)) return constants.ZERO;
626
- return divide(subtract(c, o), range, constants.DECIMALS);
645
+ const o = fp18.toFp18(bar.o);
646
+ const h = fp18.toFp18(bar.h);
647
+ const l = fp18.toFp18(bar.l);
648
+ const c = fp18.toFp18(bar.c);
649
+ const range = h - l;
650
+ if (range === fp18.ZERO) return fp18.toDnum(fp18.ZERO);
651
+ return fp18.toDnum(fp18.div(c - o, range));
627
652
  };
628
653
  });
629
654
 
@@ -649,24 +674,25 @@ const cfo = createSignal(({ period }) => {
649
674
  assert(Number.isInteger(period) && period >= 1, /* @__PURE__ */ new RangeError(`Expected period to be a positive integer, got ${period}`));
650
675
  const buffer = [];
651
676
  return (value) => {
652
- buffer.push(toDnum(value));
677
+ buffer.push(fp18.toFp18(value));
653
678
  if (buffer.length > period) buffer.shift();
654
679
  const n = buffer.length;
655
- if (n < 2) return constants.ZERO;
656
- const xSum = n * (n + 1) / 2;
657
- const denom = n * (n * (n + 1) * (2 * n + 1) / 6) - xSum * xSum;
658
- let sumY = constants.ZERO;
659
- let sumXY = constants.ZERO;
680
+ if (n < 2) return fp18.toDnum(fp18.ZERO);
681
+ const xSum = BigInt(n * (n + 1) / 2);
682
+ const x2Sum = BigInt(n * (n + 1) * (2 * n + 1) / 6);
683
+ const denom = BigInt(n) * x2Sum - xSum * xSum;
684
+ let sumY = fp18.ZERO;
685
+ let sumXY = fp18.ZERO;
660
686
  for (let i = 0; i < n; i++) {
661
- sumY = add(sumY, buffer[i]);
662
- sumXY = add(sumXY, multiply(buffer[i], i + 1));
687
+ sumY += buffer[i];
688
+ sumXY += buffer[i] * BigInt(i + 1);
663
689
  }
664
- const slope = divide(subtract(multiply(sumXY, n), multiply(sumY, xSum)), denom, constants.DECIMALS);
665
- const intercept = divide(subtract(sumY, multiply(slope, xSum)), n, constants.DECIMALS);
666
- const forecast = add(multiply(slope, n), intercept);
690
+ const slope = (sumXY * BigInt(n) - sumY * xSum) / denom;
691
+ const intercept = (sumY - slope * xSum) / BigInt(n);
692
+ const forecast = slope * BigInt(n) + intercept;
667
693
  const close = buffer[n - 1];
668
- if (equal(close, 0)) return constants.ZERO;
669
- return divide(multiply(subtract(close, forecast), 100), close, constants.DECIMALS);
694
+ if (close === fp18.ZERO) return fp18.toDnum(fp18.ZERO);
695
+ return fp18.toDnum(fp18.div((close - forecast) * 100n, close));
670
696
  };
671
697
  }, defaultCFOOptions);
672
698
 
@@ -686,15 +712,30 @@ const defaultDoubleExponentialMovingAverageOptions = { period: 12 };
686
712
  */
687
713
  const dema = createSignal(({ period }) => {
688
714
  assert(Number.isInteger(period) && period >= 1, /* @__PURE__ */ new RangeError(`Expected period to be a positive integer, got ${period}`));
689
- const ema1 = ema.create({ period });
690
- const ema2 = ema.create({ period });
715
+ const ema1 = ewma(ewma.k(period));
716
+ const ema2 = ewma(ewma.k(period));
691
717
  return (value) => {
692
- const e1 = ema1(value);
718
+ const e1 = ema1(fp18.toFp18(value));
693
719
  const e2 = ema2(e1);
694
- return sub(mul(e1, 2, 18), e2);
720
+ return fp18.toDnum(e1 * 2n - e2);
695
721
  };
696
722
  }, defaultDoubleExponentialMovingAverageOptions);
697
723
 
724
+ //#endregion
725
+ //#region src/trend/exponentialMovingAverage.ts
726
+ const defaultExponentialMovingAverageOptions = { period: 12 };
727
+ /**
728
+ * Exponential Moving Average (EMA)
729
+ *
730
+ * EMA = Price * k + PrevEMA * (1 - k)
731
+ * Where k = 2 / (period + 1)
732
+ */
733
+ const ema = createSignal(({ period }) => {
734
+ assert(Number.isInteger(period) && period >= 1, /* @__PURE__ */ new RangeError(`Expected period to be a positive integer, got ${period}`));
735
+ const proc = ewma(ewma.k(period));
736
+ return (value) => fp18.toDnum(proc(fp18.toFp18(value)));
737
+ }, defaultExponentialMovingAverageOptions);
738
+
698
739
  //#endregion
699
740
  //#region src/trend/ichimokuCloud.ts
700
741
  const defaultIchimokuCloudOptions = {
@@ -719,23 +760,25 @@ const ichimokuCloud = createSignal(({ conversionPeriod, basePeriod, leadingBPeri
719
760
  assert(Number.isInteger(conversionPeriod) && conversionPeriod >= 1, /* @__PURE__ */ new RangeError(`Expected conversionPeriod to be a positive integer, got ${conversionPeriod}`));
720
761
  assert(Number.isInteger(basePeriod) && basePeriod >= 1, /* @__PURE__ */ new RangeError(`Expected basePeriod to be a positive integer, got ${basePeriod}`));
721
762
  assert(Number.isInteger(leadingBPeriod) && leadingBPeriod >= 1, /* @__PURE__ */ new RangeError(`Expected leadingBPeriod to be a positive integer, got ${leadingBPeriod}`));
722
- const convHighProc = mmax.create({ period: conversionPeriod });
723
- const convLowProc = mmin.create({ period: conversionPeriod });
724
- const baseHighProc = mmax.create({ period: basePeriod });
725
- const baseLowProc = mmin.create({ period: basePeriod });
726
- const leadBHighProc = mmax.create({ period: leadingBPeriod });
727
- const leadBLowProc = mmin.create({ period: leadingBPeriod });
763
+ const convHighProc = mmax$1(conversionPeriod);
764
+ const convLowProc = mmin$1(conversionPeriod);
765
+ const baseHighProc = mmax$1(basePeriod);
766
+ const baseLowProc = mmin$1(basePeriod);
767
+ const leadBHighProc = mmax$1(leadingBPeriod);
768
+ const leadBLowProc = mmin$1(leadingBPeriod);
728
769
  return (bar) => {
729
- const h = from(bar.h, 18);
730
- const l = from(bar.l, 18);
731
- const conversion = div(add(convHighProc(h), convLowProc(l)), 2, 18);
732
- const base = div(add(baseHighProc(h), baseLowProc(l)), 2, 18);
770
+ const h = fp18.toFp18(bar.h);
771
+ const l = fp18.toFp18(bar.l);
772
+ const conversion = (convHighProc(h) + convLowProc(l)) / 2n;
773
+ const base = (baseHighProc(h) + baseLowProc(l)) / 2n;
774
+ const leadingA = (conversion + base) / 2n;
775
+ const leadingB = (leadBHighProc(h) + leadBLowProc(l)) / 2n;
733
776
  return {
734
- conversion,
735
- base,
736
- leadingA: div(add(conversion, base), 2, 18),
737
- leadingB: div(add(leadBHighProc(h), leadBLowProc(l)), 2, 18),
738
- lagging: from(bar.c, 18)
777
+ conversion: fp18.toDnum(conversion),
778
+ base: fp18.toDnum(base),
779
+ leadingA: fp18.toDnum(leadingA),
780
+ leadingB: fp18.toDnum(leadingB),
781
+ lagging: fp18.toDnum(fp18.toFp18(bar.c))
739
782
  };
740
783
  };
741
784
  }, defaultIchimokuCloudOptions);
@@ -772,20 +815,43 @@ const macd = createSignal(({ fastPeriod, slowPeriod, signalPeriod }) => {
772
815
  assert(Number.isInteger(fastPeriod) && fastPeriod >= 1, /* @__PURE__ */ new RangeError(`Expected fastPeriod to be a positive integer, got ${fastPeriod}`));
773
816
  assert(Number.isInteger(slowPeriod) && slowPeriod >= 1, /* @__PURE__ */ new RangeError(`Expected slowPeriod to be a positive integer, got ${slowPeriod}`));
774
817
  assert(Number.isInteger(signalPeriod) && signalPeriod >= 1, /* @__PURE__ */ new RangeError(`Expected signalPeriod to be a positive integer, got ${signalPeriod}`));
775
- const fastProc = ema.create({ period: fastPeriod });
776
- const slowProc = ema.create({ period: slowPeriod });
777
- const signalProc = ema.create({ period: signalPeriod });
818
+ const fastProc = ewma(ewma.k(fastPeriod));
819
+ const slowProc = ewma(ewma.k(slowPeriod));
820
+ const signalProc = ewma(ewma.k(signalPeriod));
778
821
  return (value) => {
779
- const m = sub(fastProc(value), slowProc(value));
822
+ const v = fp18.toFp18(value);
823
+ const m = fastProc(v) - slowProc(v);
780
824
  const sig = signalProc(m);
781
825
  return {
782
- macd: m,
783
- signal: sig,
784
- histogram: sub(m, sig)
826
+ macd: fp18.toDnum(m),
827
+ signal: fp18.toDnum(sig),
828
+ histogram: fp18.toDnum(m - sig)
785
829
  };
786
830
  };
787
831
  }, defaultMACDOptions);
788
832
 
833
+ //#endregion
834
+ //#region src/trend/movingMax.ts
835
+ const defaultMovingMaxOptions = { period: 4 };
836
+ /**
837
+ * Moving Maximum (MovingMax)
838
+ */
839
+ const mmax = createSignal(({ period }) => {
840
+ const proc = mmax$1(period);
841
+ return (value) => fp18.toDnum(proc(fp18.toFp18(value)));
842
+ }, defaultMovingMaxOptions);
843
+
844
+ //#endregion
845
+ //#region src/trend/movingMin.ts
846
+ const defaultMovingMinOptions = { period: 4 };
847
+ /**
848
+ * Moving Minimum (MovingMin)
849
+ */
850
+ const mmin = createSignal(({ period }) => {
851
+ const proc = mmin$1(period);
852
+ return (value) => fp18.toDnum(proc(fp18.toFp18(value)));
853
+ }, defaultMovingMinOptions);
854
+
789
855
  //#endregion
790
856
  //#region src/trend/movingSum.ts
791
857
  const defaultMovingSumOptions = { period: 4 };
@@ -795,25 +861,8 @@ const defaultMovingSumOptions = { period: 4 };
795
861
  * Calculates the sum of values in a sliding window of the specified period.
796
862
  */
797
863
  const msum = createSignal(({ period }) => {
798
- assert(Number.isInteger(period) && period >= 1, /* @__PURE__ */ new RangeError(`Expected period to be a positive integer, got ${period}`));
799
- const buffer = Array.from({ length: period });
800
- let head = 0;
801
- let count = 0;
802
- let runningSum = constants.ZERO;
803
- return (value) => {
804
- const v = toDnum(value);
805
- if (count < period) {
806
- buffer[count] = v;
807
- runningSum = add(runningSum, v);
808
- count++;
809
- } else {
810
- runningSum = subtract(runningSum, buffer[head]);
811
- runningSum = add(runningSum, v);
812
- buffer[head] = v;
813
- head = (head + 1) % period;
814
- }
815
- return runningSum;
816
- };
864
+ const proc = msum$1(period);
865
+ return (value) => fp18.toDnum(proc(fp18.toFp18(value)));
817
866
  }, defaultMovingSumOptions);
818
867
 
819
868
  //#endregion
@@ -862,12 +911,12 @@ const psar = createSignal(({ start, increment, max }) => {
862
911
  let prevLow;
863
912
  let prevPrevHigh;
864
913
  let prevPrevLow;
865
- const afStart = toDnum(start);
866
- const afIncrement = toDnum(increment);
867
- const afMax = toDnum(max);
914
+ const afStart = fp18.toFp18(start);
915
+ const afIncrement = fp18.toFp18(increment);
916
+ const afMax = fp18.toFp18(max);
868
917
  return (bar) => {
869
- const h = toDnum(bar.h);
870
- const l = toDnum(bar.l);
918
+ const h = fp18.toFp18(bar.h);
919
+ const l = fp18.toFp18(bar.l);
871
920
  count++;
872
921
  if (count === 1) {
873
922
  isUptrend = true;
@@ -879,12 +928,12 @@ const psar = createSignal(({ start, increment, max }) => {
879
928
  prevPrevHigh = h;
880
929
  prevPrevLow = l;
881
930
  return {
882
- psar: sar,
931
+ psar: fp18.toDnum(sar),
883
932
  isUptrend
884
933
  };
885
934
  }
886
935
  if (count === 2) {
887
- if (gt(h, prevHigh)) {
936
+ if (h > prevHigh) {
888
937
  isUptrend = true;
889
938
  sar = prevLow;
890
939
  ep = h;
@@ -899,27 +948,27 @@ const psar = createSignal(({ start, increment, max }) => {
899
948
  prevHigh = h;
900
949
  prevLow = l;
901
950
  return {
902
- psar: sar,
951
+ psar: fp18.toDnum(sar),
903
952
  isUptrend
904
953
  };
905
954
  }
906
- let nextSar = add(sar, mul(af, sub(ep, sar), constants.DECIMALS));
955
+ let nextSar = sar + fp18.mul(af, ep - sar);
907
956
  if (isUptrend) {
908
- if (gt(nextSar, prevLow)) nextSar = prevLow;
909
- if (gt(nextSar, prevPrevLow)) nextSar = prevPrevLow;
957
+ if (nextSar > prevLow) nextSar = prevLow;
958
+ if (nextSar > prevPrevLow) nextSar = prevPrevLow;
910
959
  } else {
911
- if (lt(nextSar, prevHigh)) nextSar = prevHigh;
912
- if (lt(nextSar, prevPrevHigh)) nextSar = prevPrevHigh;
960
+ if (nextSar < prevHigh) nextSar = prevHigh;
961
+ if (nextSar < prevPrevHigh) nextSar = prevPrevHigh;
913
962
  }
914
963
  sar = nextSar;
915
964
  let reversed = false;
916
- if (isUptrend && lt(l, sar)) {
965
+ if (isUptrend && l < sar) {
917
966
  isUptrend = false;
918
967
  sar = ep;
919
968
  ep = l;
920
969
  af = afStart;
921
970
  reversed = true;
922
- } else if (!isUptrend && gt(h, sar)) {
971
+ } else if (!isUptrend && h > sar) {
923
972
  isUptrend = true;
924
973
  sar = ep;
925
974
  ep = h;
@@ -927,14 +976,14 @@ const psar = createSignal(({ start, increment, max }) => {
927
976
  reversed = true;
928
977
  }
929
978
  if (!reversed) {
930
- if (isUptrend && gt(h, ep)) {
979
+ if (isUptrend && h > ep) {
931
980
  ep = h;
932
- const newAf = add(af, afIncrement);
933
- af = gt(newAf, afMax) ? afMax : newAf;
934
- } else if (!isUptrend && lt(l, ep)) {
981
+ const newAf = af + afIncrement;
982
+ af = newAf > afMax ? afMax : newAf;
983
+ } else if (!isUptrend && l < ep) {
935
984
  ep = l;
936
- const newAf = add(af, afIncrement);
937
- af = gt(newAf, afMax) ? afMax : newAf;
985
+ const newAf = af + afIncrement;
986
+ af = newAf > afMax ? afMax : newAf;
938
987
  }
939
988
  }
940
989
  prevPrevHigh = prevHigh;
@@ -942,7 +991,7 @@ const psar = createSignal(({ start, increment, max }) => {
942
991
  prevHigh = h;
943
992
  prevLow = l;
944
993
  return {
945
- psar: sar,
994
+ psar: fp18.toDnum(sar),
946
995
  isUptrend
947
996
  };
948
997
  };
@@ -976,23 +1025,59 @@ const qstick = createSignal(({ period }) => {
976
1025
  const buffer = Array.from({ length: period });
977
1026
  let head = 0;
978
1027
  let count = 0;
979
- let runningSum = constants.ZERO;
1028
+ let runningSum = fp18.ZERO;
980
1029
  return (bar) => {
981
- const diff = subtract(toDnum(bar.c), toDnum(bar.o));
1030
+ const diff = fp18.toFp18(bar.c) - fp18.toFp18(bar.o);
982
1031
  if (count < period) {
983
1032
  buffer[count] = diff;
984
- runningSum = add(runningSum, diff);
1033
+ runningSum += diff;
985
1034
  count++;
986
1035
  } else {
987
- runningSum = subtract(runningSum, buffer[head]);
988
- runningSum = add(runningSum, diff);
1036
+ runningSum = runningSum - buffer[head] + diff;
989
1037
  buffer[head] = diff;
990
1038
  head = (head + 1) % period;
991
1039
  }
992
- return divide(runningSum, count, constants.DECIMALS);
1040
+ return fp18.toDnum(runningSum / BigInt(count));
993
1041
  };
994
1042
  }, defaultQstickOptions);
995
1043
 
1044
+ //#endregion
1045
+ //#region src/trend/rollingMovingAverage.ts
1046
+ const defaultRMAOptions = { period: 4 };
1047
+ /**
1048
+ * Rolling moving average (RMA).
1049
+ *
1050
+ * R[0] to R[p-1] is SMA(values)
1051
+ *
1052
+ * R[p] and after is R[i] = ((R[i-1]*(p-1)) + v[i]) / p
1053
+ */
1054
+ const rma = createSignal(({ period }) => {
1055
+ const proc = rma$1(period);
1056
+ return (value) => fp18.toDnum(proc(fp18.toFp18(value)));
1057
+ }, defaultRMAOptions);
1058
+
1059
+ //#endregion
1060
+ //#region src/trend/simpleMovingAverage.ts
1061
+ const defaultSMAOptions = { period: 2 };
1062
+ /**
1063
+ * Simple Moving Average (SMA)
1064
+ *
1065
+ * Calculates the arithmetic mean of a set of values over a specified period.
1066
+ * The SMA is calculated by summing all values in the period and dividing by the period length.
1067
+ *
1068
+ * Formula: SMA = (P1 + P2 + ... + Pn) / n
1069
+ * Where: P = Price values, n = Period
1070
+ *
1071
+ * @param source - Iterable of price values
1072
+ * @param options - Configuration options
1073
+ * @param options.period - The period for calculating the moving average (default: 2)
1074
+ * @returns Generator yielding SMA values
1075
+ */
1076
+ const sma = createSignal(({ period }) => {
1077
+ const proc = sma$1(period);
1078
+ return (value) => fp18.toDnum(proc(fp18.toFp18(value)));
1079
+ }, defaultSMAOptions);
1080
+
996
1081
  //#endregion
997
1082
  //#region src/trend/sinceChange.ts
998
1083
  /**
@@ -1011,14 +1096,14 @@ const qstick = createSignal(({ period }) => {
1011
1096
  */
1012
1097
  const since = createSignal(() => {
1013
1098
  let last;
1014
- let count = constants.ZERO;
1099
+ let count = fp18.ZERO;
1015
1100
  return (value) => {
1016
- const v = toDnum(value);
1017
- if (last === void 0 || !equal(last, v)) {
1101
+ const v = fp18.toFp18(value);
1102
+ if (last === void 0 || last !== v) {
1018
1103
  last = v;
1019
- count = constants.ZERO;
1020
- } else count = add(count, constants.ONE);
1021
- return count;
1104
+ count = fp18.ZERO;
1105
+ } else count += fp18.ONE;
1106
+ return fp18.toDnum(count);
1022
1107
  };
1023
1108
  });
1024
1109
 
@@ -1036,10 +1121,11 @@ const trima = createSignal(({ period }) => {
1036
1121
  n1 = (period + 1) / 2;
1037
1122
  n2 = n1;
1038
1123
  }
1039
- const sma1 = sma.create({ period: n2 });
1040
- const sma2 = sma.create({ period: n1 });
1124
+ const sma1 = sma$1(n2);
1125
+ const sma2 = sma$1(n1);
1041
1126
  return (value) => {
1042
- return sma2(sma1(value));
1127
+ const s1 = sma1(fp18.toFp18(value));
1128
+ return fp18.toDnum(sma2(s1));
1043
1129
  };
1044
1130
  }, defaultTriangularMovingAverageOptions);
1045
1131
 
@@ -1064,19 +1150,19 @@ const defaultTripleExponentialAverageOptions = { period: 15 };
1064
1150
  */
1065
1151
  const trix = createSignal(({ period }) => {
1066
1152
  assert(Number.isInteger(period) && period >= 1, /* @__PURE__ */ new RangeError(`Expected period to be a positive integer, got ${period}`));
1067
- const ema1 = ema.create({ period });
1068
- const ema2 = ema.create({ period });
1069
- const ema3 = ema.create({ period });
1153
+ const ema1 = ewma(ewma.k(period));
1154
+ const ema2 = ewma(ewma.k(period));
1155
+ const ema3 = ewma(ewma.k(period));
1070
1156
  let prevEma3 = null;
1071
1157
  return (value) => {
1072
- const e3 = ema3(ema2(ema1(value)));
1158
+ const e3 = ema3(ema2(ema1(fp18.toFp18(value))));
1073
1159
  if (prevEma3 === null) {
1074
1160
  prevEma3 = e3;
1075
- return constants.ZERO;
1161
+ return fp18.toDnum(fp18.ZERO);
1076
1162
  }
1077
- const result = multiply(divide(subtract(e3, prevEma3), prevEma3, constants.DECIMALS), 100, constants.DECIMALS);
1163
+ const result = fp18.div((e3 - prevEma3) * 100n, prevEma3);
1078
1164
  prevEma3 = e3;
1079
- return result;
1165
+ return fp18.toDnum(result);
1080
1166
  };
1081
1167
  }, defaultTripleExponentialAverageOptions);
1082
1168
 
@@ -1096,14 +1182,14 @@ const defaultTripleExponentialMovingAverageOptions = { period: 12 };
1096
1182
  */
1097
1183
  const tema = createSignal(({ period }) => {
1098
1184
  assert(Number.isInteger(period) && period >= 1, /* @__PURE__ */ new RangeError(`Expected period to be a positive integer, got ${period}`));
1099
- const ema1 = ema.create({ period });
1100
- const ema2 = ema.create({ period });
1101
- const ema3 = ema.create({ period });
1185
+ const ema1 = ewma(ewma.k(period));
1186
+ const ema2 = ewma(ewma.k(period));
1187
+ const ema3 = ewma(ewma.k(period));
1102
1188
  return (value) => {
1103
- const e1 = ema1(value);
1189
+ const e1 = ema1(fp18.toFp18(value));
1104
1190
  const e2 = ema2(e1);
1105
1191
  const e3 = ema3(e2);
1106
- return add(sub(mul(e1, 3, 18), mul(e2, 3, 18)), e3);
1192
+ return fp18.toDnum(e1 * 3n - e2 * 3n + e3);
1107
1193
  };
1108
1194
  }, defaultTripleExponentialMovingAverageOptions);
1109
1195
 
@@ -1123,10 +1209,10 @@ const tema = createSignal(({ period }) => {
1123
1209
  */
1124
1210
  const typicalPrice = createSignal(() => {
1125
1211
  return (bar) => {
1126
- const h = from(bar.h, 18);
1127
- const l = from(bar.l, 18);
1128
- const c = from(bar.c, 18);
1129
- return divide(add(add(h, l), c), 3, 18);
1212
+ const h = fp18.toFp18(bar.h);
1213
+ const l = fp18.toFp18(bar.l);
1214
+ const c = fp18.toFp18(bar.c);
1215
+ return fp18.toDnum((h + l + c) / 3n);
1130
1216
  };
1131
1217
  });
1132
1218
 
@@ -1140,7 +1226,7 @@ const defaultVwmaOptions = { period: 20 };
1140
1226
  * influence to prices with higher trading activity. It is useful for
1141
1227
  * confirming trends and identifying divergences between price and volume.
1142
1228
  *
1143
- * Formula: VWMA = Sum(Close × Volume, period) / Sum(Volume, period)
1229
+ * Formula: VWMA = Sum(Close * Volume, period) / Sum(Volume, period)
1144
1230
  *
1145
1231
  * Interpretation:
1146
1232
  * - When VWMA is below price, it suggests bullish sentiment (higher volume at higher prices)
@@ -1158,28 +1244,28 @@ const vwma = createSignal(({ period }) => {
1158
1244
  const vBuffer = Array.from({ length: period });
1159
1245
  let head = 0;
1160
1246
  let count = 0;
1161
- let pvSum = constants.ZERO;
1162
- let vSum = constants.ZERO;
1247
+ let pvSum = fp18.ZERO;
1248
+ let vSum = fp18.ZERO;
1163
1249
  return (bar) => {
1164
- const close = toDnum(bar.c);
1165
- const volume = toDnum(bar.v);
1166
- const pv = multiply(close, volume, constants.DECIMALS);
1250
+ const close = fp18.toFp18(bar.c);
1251
+ const volume = fp18.toFp18(bar.v);
1252
+ const pv = fp18.mul(close, volume);
1167
1253
  if (count < period) {
1168
1254
  pvBuffer[count] = pv;
1169
1255
  vBuffer[count] = volume;
1170
- pvSum = add(pvSum, pv);
1171
- vSum = add(vSum, volume);
1256
+ pvSum += pv;
1257
+ vSum += volume;
1172
1258
  count++;
1173
1259
  } else {
1174
- pvSum = subtract(pvSum, pvBuffer[head]);
1175
- vSum = subtract(vSum, vBuffer[head]);
1260
+ pvSum -= pvBuffer[head];
1261
+ vSum -= vBuffer[head];
1176
1262
  pvBuffer[head] = pv;
1177
1263
  vBuffer[head] = volume;
1178
- pvSum = add(pvSum, pv);
1179
- vSum = add(vSum, volume);
1264
+ pvSum += pv;
1265
+ vSum += volume;
1180
1266
  head = (head + 1) % period;
1181
1267
  }
1182
- return divide(pvSum, vSum, constants.DECIMALS);
1268
+ return fp18.toDnum(fp18.div(pvSum, vSum));
1183
1269
  };
1184
1270
  }, defaultVwmaOptions);
1185
1271
 
@@ -1204,59 +1290,56 @@ const vortex = createSignal(({ period }) => {
1204
1290
  const trBuffer = Array.from({ length: period });
1205
1291
  let head = 0;
1206
1292
  let count = 0;
1207
- let sumVmPlus = constants.ZERO;
1208
- let sumVmMinus = constants.ZERO;
1209
- let sumTr = constants.ZERO;
1293
+ let sumVmPlus = fp18.ZERO;
1294
+ let sumVmMinus = fp18.ZERO;
1295
+ let sumTr = fp18.ZERO;
1210
1296
  let prevHigh = null;
1211
1297
  let prevLow = null;
1212
1298
  let prevClose = null;
1213
1299
  return (bar) => {
1214
- const h = toDnum(bar.h);
1215
- const l = toDnum(bar.l);
1216
- const c = toDnum(bar.c);
1300
+ const h = fp18.toFp18(bar.h);
1301
+ const l = fp18.toFp18(bar.l);
1302
+ const c = fp18.toFp18(bar.c);
1217
1303
  if (prevHigh === null || prevLow === null || prevClose === null) {
1218
1304
  prevHigh = h;
1219
1305
  prevLow = l;
1220
1306
  prevClose = c;
1221
1307
  return {
1222
- plus: constants.ZERO,
1223
- minus: constants.ZERO
1308
+ plus: fp18.toDnum(fp18.ZERO),
1309
+ minus: fp18.toDnum(fp18.ZERO)
1224
1310
  };
1225
1311
  }
1226
- const vmPlus = abs(subtract(h, prevLow));
1227
- const vmMinus = abs(subtract(l, prevHigh));
1228
- const hl = subtract(h, l);
1229
- const hpc = abs(subtract(h, prevClose));
1230
- const lpc = abs(subtract(l, prevClose));
1312
+ const vmPlus = fp18.abs(h - prevLow);
1313
+ const vmMinus = fp18.abs(l - prevHigh);
1314
+ const hl = h - l;
1315
+ const hpc = fp18.abs(h - prevClose);
1316
+ const lpc = fp18.abs(l - prevClose);
1231
1317
  let tr = hl;
1232
- if (gt(hpc, tr)) tr = hpc;
1233
- if (gt(lpc, tr)) tr = lpc;
1318
+ if (hpc > tr) tr = hpc;
1319
+ if (lpc > tr) tr = lpc;
1234
1320
  if (count < period) {
1235
1321
  vmPlusBuffer[count] = vmPlus;
1236
1322
  vmMinusBuffer[count] = vmMinus;
1237
1323
  trBuffer[count] = tr;
1238
- sumVmPlus = add(sumVmPlus, vmPlus);
1239
- sumVmMinus = add(sumVmMinus, vmMinus);
1240
- sumTr = add(sumTr, tr);
1324
+ sumVmPlus += vmPlus;
1325
+ sumVmMinus += vmMinus;
1326
+ sumTr += tr;
1241
1327
  count++;
1242
1328
  } else {
1243
- sumVmPlus = subtract(sumVmPlus, vmPlusBuffer[head]);
1244
- sumVmMinus = subtract(sumVmMinus, vmMinusBuffer[head]);
1245
- sumTr = subtract(sumTr, trBuffer[head]);
1329
+ sumVmPlus = sumVmPlus - vmPlusBuffer[head] + vmPlus;
1330
+ sumVmMinus = sumVmMinus - vmMinusBuffer[head] + vmMinus;
1331
+ sumTr = sumTr - trBuffer[head] + tr;
1246
1332
  vmPlusBuffer[head] = vmPlus;
1247
1333
  vmMinusBuffer[head] = vmMinus;
1248
1334
  trBuffer[head] = tr;
1249
- sumVmPlus = add(sumVmPlus, vmPlus);
1250
- sumVmMinus = add(sumVmMinus, vmMinus);
1251
- sumTr = add(sumTr, tr);
1252
1335
  head = (head + 1) % period;
1253
1336
  }
1254
1337
  prevHigh = h;
1255
1338
  prevLow = l;
1256
1339
  prevClose = c;
1257
1340
  return {
1258
- plus: divide(sumVmPlus, sumTr, constants.DECIMALS),
1259
- minus: divide(sumVmMinus, sumTr, constants.DECIMALS)
1341
+ plus: fp18.toDnum(fp18.div(sumVmPlus, sumTr)),
1342
+ minus: fp18.toDnum(fp18.div(sumVmMinus, sumTr))
1260
1343
  };
1261
1344
  };
1262
1345
  }, defaultVortexOptions);
@@ -1290,15 +1373,35 @@ const defaultMassIndexOptions = {
1290
1373
  const mi = createSignal(({ emaPeriod, miPeriod }) => {
1291
1374
  assert(Number.isInteger(emaPeriod) && emaPeriod >= 1, /* @__PURE__ */ new RangeError(`Expected emaPeriod to be a positive integer, got ${emaPeriod}`));
1292
1375
  assert(Number.isInteger(miPeriod) && miPeriod >= 1, /* @__PURE__ */ new RangeError(`Expected miPeriod to be a positive integer, got ${miPeriod}`));
1293
- const ema1Proc = ema.create({ period: emaPeriod });
1294
- const ema2Proc = ema.create({ period: emaPeriod });
1295
- const msumProc = msum.create({ period: miPeriod });
1376
+ const ema1Proc = ewma(ewma.k(emaPeriod));
1377
+ const ema2Proc = ewma(ewma.k(emaPeriod));
1378
+ const msumProc = msum$1(miPeriod);
1296
1379
  return (bar) => {
1297
- const e1 = ema1Proc(subtract(from(bar.h, 18), from(bar.l, 18)));
1298
- return msumProc(divide(e1, ema2Proc(e1), 18));
1380
+ const e1 = ema1Proc(fp18.toFp18(bar.h) - fp18.toFp18(bar.l));
1381
+ const e2 = ema2Proc(e1);
1382
+ const ratio = fp18.div(e1, e2);
1383
+ return fp18.toDnum(msumProc(ratio));
1299
1384
  };
1300
1385
  }, defaultMassIndexOptions);
1301
1386
 
1387
+ //#endregion
1388
+ //#region src/volume/accumulationDistribution.ts
1389
+ /**
1390
+ * Accumulation/Distribution Indicator (A/D). Cumulative indicator
1391
+ * that uses volume and price to assess whether a stock is
1392
+ * being accumulated or distributed.
1393
+ *
1394
+ * MFM = ((Closing - Low) - (High - Closing)) / (High - Low)
1395
+ * MFV = MFM * Period Volume
1396
+ * AD = Previous AD + CMFV
1397
+ */
1398
+ const ad = createSignal(() => {
1399
+ const proc = ad$1();
1400
+ return (bar) => {
1401
+ return fp18.toDnum(proc(fp18.toFp18(bar.h), fp18.toFp18(bar.l), fp18.toFp18(bar.c), fp18.toFp18(bar.v)));
1402
+ };
1403
+ });
1404
+
1302
1405
  //#endregion
1303
1406
  export { apo as absolutePriceOscillator, apo, ad as accumulationDistribution, ad, ao, ao as awesomeOscillator, aroon, bop as balanceOfPower, bop, cci, cci as commodityChannelIndex, cfo, cfo as chandeForecastOscillator, cmo as chaikinOscillator, cmo, defaultAbsolutePriceOscillatorOptions, defaultAroonOptions, defaultAwesomeOscillatorOptions, defaultCCIOptions, defaultCFOOptions, defaultChaikinOscillatorOptions, defaultDoubleExponentialMovingAverageOptions, defaultExponentialMovingAverageOptions, defaultIchimokuCloudOptions, defaultMACDOptions, defaultMassIndexOptions, defaultMovingMaxOptions, defaultMovingMinOptions, defaultMovingSumOptions, defaultParabolicSarOptions, defaultPercentagePriceOscillatorOptions, defaultPercentageVolumeOscillatorOptions, defaultPriceRateOfChangeOptions, defaultQstickOptions, defaultRMAOptions, defaultRSIOptions, defaultRandomIndexOptions, defaultSMAOptions, defaultStochasticOscillatorOptions, defaultTriangularMovingAverageOptions, defaultTripleExponentialAverageOptions, defaultTripleExponentialMovingAverageOptions, defaultVortexOptions, defaultVwmaOptions, defaultWilliamsROptions, dema, dema as doubleExponentialMovingAverage, ema, ema as exponentialMovingAverage, ichimokuCloud, kdj, kdj as randomIndex, macd, macd as movingAverageConvergenceDivergence, mi as massIndex, mi, mmax, mmax as movingMax, mmin, mmin as movingMin, msum, psar as parabolicSar, psar, ppo as percentagePriceOscillator, ppo, pvo as percentageVolumeOscillator, pvo, roc as priceRateOfChange, roc, qstick, qstick as qstickIndicator, rsi as relativeStrengthIndex, rsi, rma, rma as rollingMovingAverage, sma as simpleMovingAverage, sma, since, since as sinceChange, stoch, stoch as stochasticOscillator, tema, tema as tripleExponentialMovingAverage, trima as triangularMovingAverage, trima, trix as tripleExponentialAverage, trix, typicalPrice, typicalPrice as typicalPriceIndicator, vwma as volumeWeightedMovingAverage, vwma, vortex, vortex as vortexIndicator, willr as williamsR, willr };
1304
1407
  //# sourceMappingURL=index.js.map