ohlcv-indicators 3.5.78 → 3.5.80

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.
Files changed (43) hide show
  1. package/AGENTS.md +113 -0
  2. package/README.md +456 -0
  3. package/dist/ohlcv-indicators.min.js +2 -1
  4. package/dist/ohlcv-indicators.min.js.LICENSE.txt +22 -0
  5. package/index.js +112 -84
  6. package/package.json +2 -5
  7. package/src/core-functions/initializeColumns.js +40 -0
  8. package/src/core-functions/mainLoop.js +35 -30
  9. package/src/core-functions/pushToMain.js +8 -27
  10. package/src/core-indicators/README.md +60 -0
  11. package/src/core-indicators/composites.js +136 -0
  12. package/src/core-indicators/index.js +5 -0
  13. package/src/core-indicators/indicator.js +81 -0
  14. package/src/core-indicators/movingAverages.js +88 -0
  15. package/src/core-indicators/rsi.js +41 -0
  16. package/src/core-indicators/volatility.js +107 -0
  17. package/src/moving-averages/bollingerBands.js +39 -31
  18. package/src/moving-averages/donchianChannel.js +62 -36
  19. package/src/moving-averages/heikenAshi.js +33 -52
  20. package/src/moving-averages/macd.js +10 -26
  21. package/src/moving-averages/movingAverages.js +19 -25
  22. package/src/moving-averages/relativeVolume.js +30 -24
  23. package/src/oscillators/mfi.js +56 -0
  24. package/src/oscillators/rsi.js +7 -26
  25. package/src/oscillators/stochastic.js +6 -19
  26. package/src/oscillators/volumeDelta.js +36 -28
  27. package/src/oscillators/volumeOscillator.js +24 -32
  28. package/src/studies/candleFeatures.js +40 -28
  29. package/src/studies/dateTime.js +54 -56
  30. package/src/studies/findCrosses.js +18 -16
  31. package/src/studies/lag.js +32 -20
  32. package/src/utilities/assignTypes.js +1 -1
  33. package/src/utilities/config.js +31 -0
  34. package/src/utilities/numberUtilities.js +5 -3
  35. package/src/utilities/precisionMultiplier.js +11 -6
  36. package/src/utilities/validators.js +40 -1
  37. package/src/utilities/verticalToHorizontal.js +26 -16
  38. package/src/volatility/adx.js +7 -20
  39. package/src/volatility/atr.js +10 -23
  40. package/test/test.js +1230 -0
  41. package/webpack.config.js +0 -11
  42. package/src/moving-averages/vidya.js +0 -181
  43. package/src/studies/mapCols.js +0 -46
package/webpack.config.js CHANGED
@@ -41,17 +41,6 @@ export default {
41
41
  plugins: ['@babel/plugin-proposal-class-properties']
42
42
  }
43
43
  }
44
- },
45
- {
46
- test: /\.js$/,
47
- include: /node_modules\/trading-signals/,
48
- use: {
49
- loader: 'babel-loader',
50
- options: {
51
- presets: ['@babel/preset-env'],
52
- plugins: ['@babel/plugin-proposal-class-properties']
53
- }
54
- }
55
44
  }
56
45
  ]
57
46
  }
@@ -1,181 +0,0 @@
1
- import { FasterSMA } from 'trading-signals';
2
- // Variable Index Dynamic Average (VIDYA) indicator with volume stats
3
-
4
- export const vidya = (main, index, size, momentum, options = {}) => {
5
- const { verticalOhlcv, instances, len, priceBased } = main;
6
- const { target, lag, atrLength = 200, bandDistance = 2, liquidityLookback = 5 } = options
7
- const indicatorKey = `${size}_${momentum}`;
8
-
9
- // Initialization on the first bar
10
- if (index === 0) {
11
- if (!(target in verticalOhlcv)) {
12
- throw new Error(`VIDYA could not find target "${target}"`)
13
- }
14
-
15
- const prefix = `vidya_${indicatorKey}`
16
- const keyBase = target === 'close' ? prefix : `${prefix}_${target}`
17
- const keys = {
18
- vidya: keyBase,
19
- upper: `${prefix}_upper`,
20
- lower: `${prefix}_lower`,
21
- delta_vol: `${prefix}_delta_vol`,
22
- cross: `${prefix}_cross`,
23
- liquidity: `${prefix}_liquidity`,
24
- }
25
-
26
- const priceBasedVidyaKeys = [keyBase, keys.upper, keys.lower, keys.liquidity]
27
-
28
- for(const k of priceBasedVidyaKeys) {
29
- priceBased.add(k)
30
- }
31
-
32
- // Prepare instances container
33
- if (!instances.vidya) instances.vidya = { settings: {} };
34
- instances.vidya.settings[indicatorKey] = {
35
- momentumBuffer: [], prevVidya: NaN,
36
- sma: new FasterSMA(15), atrBuffer: [],
37
- isTrendUp: false, upVol: 0, downVol: 0,
38
- liquidity: {
39
- high: [],
40
- low: []
41
- }
42
- };
43
-
44
- // Allocate output arrays
45
- Object.values(keys).forEach(key => {
46
- verticalOhlcv[key] = new Float64Array(len).fill(NaN)
47
- })
48
-
49
- if (lag > 0) main.lag(Object.values(keys), lag);
50
- }
51
-
52
- // Per-bar computation
53
- const inst = instances.vidya.settings[indicatorKey];
54
- const prefix = `vidya_${indicatorKey}`;
55
- const keyBase = target === 'close' ? prefix : `${prefix}_${target}`;
56
- const keys = {
57
- vidya: keyBase,
58
- upper: `${prefix}_upper`,
59
- lower: `${prefix}_lower`,
60
- delta_vol: `${prefix}_delta_vol`,
61
- cross: `${prefix}_cross`,
62
- liquidity: `${prefix}_liquidity`,
63
- };
64
-
65
- // Series inputs
66
- const price = verticalOhlcv[target][index]
67
- const high = verticalOhlcv.high[index]
68
- const low = verticalOhlcv.low[index]
69
- const close = verticalOhlcv.close[index]
70
- const open = verticalOhlcv.open[index]
71
- const vol = verticalOhlcv.volume[index]
72
- const prevCross = index > 0 ? verticalOhlcv[keys.cross][index - 1] : 0
73
-
74
- const highestHigh = (inst.liquidity.high.length === liquidityLookback) ? Math.max(...inst.liquidity.high) : NaN
75
- const lowestLow = (inst.liquidity.low.length === liquidityLookback) ? Math.min(...inst.liquidity.low) : NaN
76
-
77
- // Compute ATR (Wilder's RMA)
78
- if (index > 0) {
79
- const prevClose = verticalOhlcv.close[index - 1];
80
- const tr = Math.max(
81
- high - low,
82
- Math.abs(high - prevClose),
83
- Math.abs(low - prevClose)
84
- )
85
- inst.atrBuffer.push(tr)
86
- if (inst.atrBuffer.length > atrLength) inst.atrBuffer.shift()
87
- }
88
- const atr = inst.atrBuffer.length === atrLength
89
- ? inst.atrBuffer.reduce((a, b) => a + b, 0) / atrLength
90
- : NaN
91
-
92
- // Compute raw VIDYA
93
- let rawVidya = NaN
94
- let mom = NaN
95
- if (index > 0) mom = price - verticalOhlcv[target][index - 1]
96
- inst.momentumBuffer.push(mom)
97
- if (inst.momentumBuffer.length > momentum) inst.momentumBuffer.shift()
98
- if (inst.momentumBuffer.length === momentum) {
99
- let sumPos = 0, sumNeg = 0
100
- inst.momentumBuffer.forEach(m => m >= 0 ? sumPos += m : sumNeg += -m);
101
- const denom = sumPos + sumNeg
102
- const cmo = denom === 0 ? 0 : Math.abs((sumPos - sumNeg) / denom) * 100;
103
- const alpha = 2 / (size + 1)
104
- const a = alpha * (cmo / 100)
105
- rawVidya = isNaN(inst.prevVidya) ? price : (a * price + (1 - a) * inst.prevVidya);
106
- inst.prevVidya = rawVidya
107
- }
108
-
109
- // Smooth VIDYA using fixed 15-bar SMA
110
- inst.sma.update(rawVidya)
111
- let smoothedVidya = NaN
112
- try { smoothedVidya = inst.sma.getResult() } catch {}
113
-
114
- // Bands
115
- const upper = (!isNaN(atr) && !isNaN(smoothedVidya))
116
- ? smoothedVidya + atr * bandDistance
117
- : NaN
118
- const lower = (!isNaN(atr) && !isNaN(smoothedVidya))
119
- ? smoothedVidya - atr * bandDistance
120
- : NaN
121
-
122
- // Detect crosses
123
- const prevPrice = index > 0 ? verticalOhlcv[target][index - 1] : NaN
124
- const prevUpper = index > 0 ? verticalOhlcv[keys.upper][index - 1] : NaN
125
- const prevLower = index > 0 ? verticalOhlcv[keys.lower][index - 1] : NaN
126
- const crossUp = index > 0 && prevPrice <= prevUpper && price > upper
127
- const crossDown = index > 0 && prevPrice >= prevLower && price < lower
128
-
129
- // Update trend state
130
- if (crossUp) inst.isTrendUp = true
131
- if (crossDown) inst.isTrendUp = false
132
-
133
- // Cumulative cross counter: positive when uptrend, negative when downtrend
134
- let cross = 0;
135
- if (index > 0) {
136
- if (inst.isTrendUp) {
137
- cross = prevCross > 0 ? prevCross + 1 : 1
138
- } else {
139
- cross = prevCross < 0 ? prevCross - 1 : -1
140
- }
141
- }
142
-
143
- // Volume accumulation
144
- if (crossUp || crossDown) {
145
- inst.upVol = inst.downVol = 0
146
- } else {
147
- inst.upVol += (close > open ? vol : 0)
148
- inst.downVol += (close < open ? vol : 0)
149
- }
150
- const avgVol = (inst.upVol + inst.downVol) / 2 || 1
151
- const deltaPct = (inst.upVol - inst.downVol) / avgVol
152
-
153
- // Trend-based boundary (reset on crossover)
154
- const trendValue = (inst.isTrendUp) ? lower : upper
155
- let liquidity = NaN
156
-
157
- if(cross > 0)
158
- {
159
- liquidity = lowestLow
160
- }
161
- else if(cross < 0)
162
- {
163
- liquidity = highestHigh
164
- }
165
-
166
- // Push outputs
167
- main.pushToMain({ index, key: keys.vidya, value: trendValue })
168
- main.pushToMain({ index, key: keys.upper, value: upper })
169
- main.pushToMain({ index, key: keys.lower, value: lower })
170
- main.pushToMain({ index, key: keys.delta_vol, value: deltaPct })
171
- main.pushToMain({ index, key: keys.cross, value: cross })
172
- main.pushToMain({ index, key: keys.liquidity, value: liquidity })
173
-
174
- inst.liquidity.high.push(high)
175
- inst.liquidity.low.push(low)
176
-
177
- if(inst.liquidity.high.length > liquidityLookback) inst.liquidity.high.shift()
178
- if(inst.liquidity.low.length > liquidityLookback) inst.liquidity.low.shift()
179
-
180
- return true
181
- }
@@ -1,46 +0,0 @@
1
- export const mapCols = (main, index, newCols, callback, {lag, isPriceBased}) => {
2
-
3
- const {verticalOhlcv, len, priceBased, precision} = main
4
-
5
- if(index === 0)
6
- {
7
- for(const key of newCols)
8
- {
9
- if(verticalOhlcv.hasOwnProperty(key)) {
10
- throw new Error(`New property "${key}" already exist in "verticalOhlcv" and can not be modified using mapCols.`)
11
- }
12
-
13
- verticalOhlcv[key] = new Array(len).fill(0)
14
-
15
- if(precision && isPriceBased)
16
- {
17
- priceBased.add(key)
18
- }
19
- }
20
-
21
- if(lag > 0)
22
- {
23
- main.lag(newCols, lag)
24
- }
25
- }
26
-
27
- const cols = callback({index, main})
28
-
29
- if(cols == null) return true
30
-
31
- for(const [key, value] of Object.entries(cols))
32
- {
33
- main.pushToMain({ index, key, value })
34
- }
35
- }
36
-
37
- export const defaultMapColsCallback = ({main, index}) => {
38
- const {verticalOhlcv} = main
39
-
40
- const close = verticalOhlcv.close[index]
41
- const open = verticalOhlcv.open[index-1]
42
-
43
- return {
44
- change: ((close - open) / open) * 100
45
- }
46
- }