ohlcv-indicators 1.9.9 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,22 +1,22 @@
1
1
  import { FasterSMA } from 'trading-signals';
2
2
  import { classifySize } from '../utilities/classification.js';
3
3
 
4
- export const candlesStudies = (main, index, size, classify = true, classificationLevels = {}) => {
4
+ export const candleStudies = (main, index, size, classify = true, classificationLevels = {}) => {
5
5
 
6
6
  const { changeLevel = 7, sizeLevel = 5 } = classificationLevels;
7
7
 
8
8
  if(index === 0)
9
9
  {
10
10
  Object.assign(main.verticalOhlcv, {
11
- candle_gap_size: new Array(main.len).fill(null),
12
- candle_body_size: new Array(main.len).fill(null),
13
- candle_top_size: new Array(main.len).fill(null),
14
- candle_bottom_size: new Array(main.len).fill(null),
15
- candle_shadow_size: new Array(main.len).fill(null),
16
- candle_close_direction: new Array(main.len).fill(null),
17
- candle_high_direction: new Array(main.len).fill(null),
18
- candle_low_direction: new Array(main.len).fill(null),
19
- candle_open_direction: new Array(main.len).fill(null),
11
+ candle_gap_size: [...main.nullArray],
12
+ candle_body_size: [...main.nullArray],
13
+ candle_top_size: [...main.nullArray],
14
+ candle_bottom_size: [...main.nullArray],
15
+ candle_shadow_size: [...main.nullArray],
16
+ candle_close_direction: [...main.nullArray],
17
+ candle_high_direction: [...main.nullArray],
18
+ candle_low_direction: [...main.nullArray],
19
+ candle_open_direction: [...main.nullArray],
20
20
  })
21
21
  }
22
22
 
@@ -44,7 +44,7 @@ export const candlesStudies = (main, index, size, classify = true, classificatio
44
44
  const prevLow = main.verticalOhlcv.low[index-1]
45
45
  const prevClose = main.verticalOhlcv.close[index-1]
46
46
 
47
- if ([prevOpen, prevHigh, prevLow, prevClose].some(v => typeof v === 'undefined')) return true;
47
+ if (index === 0) return true;
48
48
 
49
49
  const currOpen = main.verticalOhlcv.open[index]
50
50
  const currHigh = main.verticalOhlcv.high[index]
@@ -88,15 +88,15 @@ export const candlesStudies = (main, index, size, classify = true, classificatio
88
88
  } = main.instances.candleStudies;
89
89
 
90
90
  // Update instances with current absolute values
91
- topInstance.update(Math.abs(topSize));
92
- bottomInstance.update(Math.abs(bottomSize));
93
- shadowSizeInstance.update(Math.abs(shadowSize));
94
- gapInstance.update(gapSize);
95
- bodySizeInstance.update(candleBodySize);
96
- closeDirectionInstance.update(closeDirection);
97
- highDirectionInstance.update(highDirection);
98
- lowDirectionInstance.update(lowDirection);
99
- openDirectionInstance.update(openDirection);
91
+ topInstance.update(Math.abs(topSize), main.lastIndexReplace);
92
+ bottomInstance.update(Math.abs(bottomSize), main.lastIndexReplace);
93
+ shadowSizeInstance.update(Math.abs(shadowSize), main.lastIndexReplace);
94
+ gapInstance.update(gapSize, main.lastIndexReplace);
95
+ bodySizeInstance.update(candleBodySize, main.lastIndexReplace);
96
+ closeDirectionInstance.update(closeDirection, main.lastIndexReplace);
97
+ highDirectionInstance.update(highDirection, main.lastIndexReplace);
98
+ lowDirectionInstance.update(lowDirection, main.lastIndexReplace);
99
+ openDirectionInstance.update(openDirection, main.lastIndexReplace);
100
100
 
101
101
  try {
102
102
  topSizeMean = topInstance.getResult();
@@ -0,0 +1,86 @@
1
+ export const dateTime = (main, index) => {
2
+
3
+ if(index === 0)
4
+ {
5
+
6
+ if(!main.isValidDate) throw Error('dateTime method found and invalid "date" in input ohlcv')
7
+
8
+ const index0DateStr = main.verticalOhlcv.date[0].slice(0, 10)
9
+
10
+ Object.assign(main.instances, {
11
+ dateTime: {
12
+ prevDateStr: index0DateStr,
13
+ sessionDailyIndexCount: 0,
14
+ sessionIntradayIndexCount: 0,
15
+ cachedDayInfo: index0DateStr
16
+ }
17
+ })
18
+
19
+ Object.assign(main.verticalOhlcv, {
20
+ day_of_the_week: [...main.nullArray],
21
+ day_of_the_month: [...main.nullArray],
22
+ week_of_the_month: [...main.nullArray],
23
+ hour: [...main.nullArray],
24
+ month: [...main.nullArray],
25
+ year: [...main.nullArray],
26
+ session_daily_index: [...main.nullArray],
27
+ session_intraday_index: [...main.nullArray],
28
+ })
29
+ }
30
+
31
+ const currDate = main.verticalOhlcv.date[index]
32
+ const {
33
+ day_of_the_week,
34
+ day_of_the_month,
35
+ week_of_the_month,
36
+ month,
37
+ year,
38
+ hour,
39
+ } = getDateInfo(currDate)
40
+
41
+
42
+ const currDateStr = currDate.slice(0, 10)
43
+
44
+ if(currDateStr !== main.instances.dateTime.prevDateStr)
45
+ {
46
+ main.instances.dateTime.prevDateStr = currDateStr
47
+ main.instances.dateTime.sessionDailyIndexCount++
48
+ main.instances.dateTime.sessionIntradayIndexCount = 0
49
+ }
50
+
51
+
52
+ main.verticalOhlcv.session_daily_index[index] = main.instances.dateTime.sessionDailyIndexCount
53
+ main.verticalOhlcv.session_intraday_index[index] = main.instances.dateTime.sessionIntradayIndexCount
54
+ main.verticalOhlcv.day_of_the_week[index] = day_of_the_week
55
+ main.verticalOhlcv.day_of_the_month[index] = day_of_the_month
56
+ main.verticalOhlcv.week_of_the_month[index] = week_of_the_month
57
+ main.verticalOhlcv.month[index] = month
58
+ main.verticalOhlcv.year[index] = year
59
+ main.verticalOhlcv.hour[index] = hour
60
+
61
+ }
62
+
63
+
64
+
65
+ const getDateInfo = dateString => {
66
+ const date = new Date(dateString)
67
+ const month = date.getMonth()
68
+ const year = date.getFullYear()
69
+ const hour = date.getHours()
70
+ const minute = date.getMinutes()
71
+ const day_of_the_week = date.getDay();
72
+ const day_of_the_month = date.getDate();
73
+ const firstDayOfMonth = new Date(date.getFullYear(), date.getMonth(), 1)
74
+ const dayOffset = firstDayOfMonth.getDay();
75
+ const week_of_the_month = Math.ceil((day_of_the_month + dayOffset) / 7)
76
+
77
+ return {
78
+ month,
79
+ year,
80
+ hour,
81
+ minute,
82
+ day_of_the_week,
83
+ day_of_the_month,
84
+ week_of_the_month,
85
+ }
86
+ }
@@ -12,18 +12,20 @@ class CrossInstance {
12
12
 
13
13
  constructor()
14
14
  {
15
- this.interval = 0
16
- this.prevState = 0.5
17
- this.prevFast = null
18
- this.prevSlow = null
19
- this.prevHigh = null
20
- this.prevLow = null
21
- this.areHighAndLowUndefined = false
22
- this.index = 0
23
- this.crossIndexes = {
24
- up: [],
25
- down: []
26
- }
15
+ Object.assign(this, {
16
+ interval: 0,
17
+ prevState: 0.5,
18
+ prevFast: null,
19
+ prevSlow: null,
20
+ prevHigh: null,
21
+ prevLow: null,
22
+ areHighAndLowUndefined: false,
23
+ index: 0,
24
+ crossIndexes: {
25
+ up: [],
26
+ down: []
27
+ }
28
+ })
27
29
 
28
30
  }
29
31
  update({fast, high, slow, low})
@@ -113,12 +115,14 @@ class CrossInstance {
113
115
  if(this.interval === -1) this.crossIndexes.down.push(this.index)
114
116
 
115
117
  //save prev state
116
- this.index++
117
- this.prevState = currState
118
- this.prevFast = fast
119
- this.prevSlow = slow
120
- this.prevHigh = high
121
- this.prevLow = low
118
+ Object.assign(this, {
119
+ index: this.index + 1,
120
+ prevState: currState,
121
+ prevFast: fast,
122
+ prevSlow: slow,
123
+ prevHigh: high,
124
+ prevLow: low
125
+ })
122
126
  }
123
127
 
124
128
  getResult()
@@ -128,11 +132,19 @@ class CrossInstance {
128
132
 
129
133
  }
130
134
 
131
- export const crossPairs = (main, index, arr) => {
135
+ export const crossPairs = (main, index) => {
132
136
 
133
- if(!arr) return
134
137
 
135
- for (const { fast, slow } of arr)
138
+ if(index === 0)
139
+ {
140
+ const findParams = main.inputParams.filter(o => o.key === 'crossPairs')
141
+
142
+ if(typeof findParams !== 'object') return
143
+
144
+ main.instances.crossPairs = {crossPairsList: findParams.flatMap(o => o.params.flat())}
145
+ }
146
+
147
+ for (const { fast, slow } of main.instances.crossPairs.crossPairsList)
136
148
  {
137
149
  if (!fast || !slow) continue
138
150
 
@@ -150,7 +162,7 @@ export const crossPairs = (main, index, arr) => {
150
162
 
151
163
 
152
164
  main.instances[crossName] = new CrossInstance()
153
- main.verticalOhlcv[crossName] = new Array(main.len).fill(null)
165
+ main.verticalOhlcv[crossName] = [...main.nullArray]
154
166
  }
155
167
 
156
168
  let fastValue
@@ -1,34 +1,43 @@
1
- export const lag = (main, index, params) => {
1
+ export const lag = (main, index) => {
2
2
 
3
- if(!params) return true
4
-
5
- for(let p = 0; p < params.length; p++)
3
+ if(index === 0)
6
4
  {
7
- const [colKeys, lags] = params[p]
5
+ const findParams = main.inputParams.filter(o => o.key === 'lag')
8
6
 
9
- // Ensure arrays exist for each lag key before we populate
10
- for (let x = 0; x < colKeys.length; x++) {
11
- for (let lag = 1; lag <= lags; lag++) {
12
- const key = `${colKeys[x]}_lag_${lag}`;
13
- // If the array does not exist, initialize it
14
- if (index === 0) {
15
- main.verticalOhlcv[key] = new Array(main.len).fill(null)
7
+ if(typeof findParams !== 'object') return
8
+
9
+ const params = findParams.map(o => o.params)
10
+
11
+ main.instances.lag = {
12
+ lagParams: params
13
+ }
14
+ }
15
+
16
+ for (const [colKeys, lags] of main.instances.lag.lagParams) {
17
+
18
+ for (const colKey of colKeys) {
19
+ const currentColumn = main.verticalOhlcv[colKey];
20
+
21
+ // Initialize lagged arrays only on the first index
22
+ if (index === 0) {
23
+ for (let lag = 1; lag <= lags; lag++) {
24
+ const key = `${colKey}_lag_${lag}`;
25
+ main.verticalOhlcv[key] = [...main.nullArray];
16
26
  }
27
+ }
17
28
 
18
- // Compute the lagged index
29
+ // Populate lagged values
30
+ for (let lag = 1; lag <= lags; lag++) {
31
+ const key = `${colKey}_lag_${lag}`;
19
32
  const laggedIndex = index - lag;
20
-
21
- // If laggedIndex is negative, we don't have a previous value
22
- const value = (laggedIndex >= 0)
23
- ? main.verticalOhlcv[colKeys[x]][laggedIndex]
24
- : null;
25
-
26
- main.verticalOhlcv[key][index] = value;
33
+
34
+ if(laggedIndex <= 0) break
35
+
36
+ main.verticalOhlcv[key][index] = currentColumn[laggedIndex]
27
37
  }
28
38
  }
29
39
  }
30
-
31
-
40
+
32
41
 
33
42
 
34
43
 
@@ -0,0 +1,22 @@
1
+ export const priceVariations = (main, index) => {
2
+
3
+
4
+ if(index === 0)
5
+ {
6
+ main.priceBased = [...new Set([...main.priceBased, 'mid_price_open_close', 'mid_price_high_low'])]
7
+
8
+ Object.assign(main.verticalOhlcv, {
9
+ mid_price_open_close: [...main.nullArray],
10
+ mid_price_high_low: [...main.nullArray]
11
+ })
12
+ }
13
+
14
+ const open = main.verticalOhlcv.open[index]
15
+ const high = main.verticalOhlcv.high[index]
16
+ const low = main.verticalOhlcv.low[index]
17
+ const close = main.verticalOhlcv.close[index]
18
+
19
+ main.verticalOhlcv.mid_price_open_close[index] = (open + close) / 2
20
+ main.verticalOhlcv.mid_price_high_low[index] = (high + low) / 2
21
+
22
+ }
@@ -1,3 +1,4 @@
1
+ import { validateInputParams } from "./validators.js"
1
2
  import { rsi } from "../oscillators/rsi.js"
2
3
  import { sma } from "../moving-averages/sma.js"
3
4
  import { ema } from "../moving-averages/ema.js"
@@ -6,11 +7,16 @@ import { relativeVolume } from "../moving-averages/relativeVolume.js"
6
7
  import { donchianChannels } from "../moving-averages/donchianChannel.js"
7
8
  import { bollingerBands } from "../moving-averages/bollingerBands.js"
8
9
  import { volumeOscillator } from "../oscillators/volumeOscillator.js"
9
- import { candlesStudies } from "../studies/candleStudies.js"
10
+ import { candleStudies } from "../studies/candleStudies.js"
10
11
  import { lag } from "../studies/lag.js"
11
12
  import {crossPairs} from "../studies/findCrosses.js"
13
+ import { dateTime } from "../studies/dateTime.js"
14
+ import { priceVariations } from "../studies/priceVariations.js"
15
+
12
16
 
13
17
  const indicatorFunctions = {
18
+ dateTime,
19
+ priceVariations,
14
20
  rsi,
15
21
  sma,
16
22
  ema,
@@ -19,126 +25,47 @@ const indicatorFunctions = {
19
25
  donchianChannels,
20
26
  bollingerBands,
21
27
  volumeOscillator,
22
- candlesStudies,
23
- lag,
24
- }
25
-
26
- const validateFirstDate = arr => arr[0].hasOwnProperty('date') && typeof arr[0].date === 'string' && /^\d{4}-\d{2}-\d{2}/.test(arr[0].date)
27
-
28
- export const defaultStudyOptions = {
29
- midPriceOpenClose: false,
30
- midPriceHighLow: false,
31
- sessionIndex: false,
32
- sessionIntradayIndex: false,
33
- dayOfTheWeek: false,
34
- dayOfTheMonth: false,
35
- weekOfTheMonth: false
28
+ candleStudies
36
29
  }
37
30
 
38
- const getDateInfo = (dateString) => {
39
- const date = new Date(dateString);
40
- const day_of_the_week = date.getDay();
41
- const day_of_the_month = date.getDate();
42
- const firstDayOfMonth = new Date(date.getFullYear(), date.getMonth(), 1);
43
- const dayOffset = firstDayOfMonth.getDay();
44
- const week_of_the_month = Math.ceil((day_of_the_month + dayOffset) / 7);
45
-
46
- return {
47
- day_of_the_week,
48
- day_of_the_month,
49
- week_of_the_month
50
- };
51
- }
52
31
 
53
32
  export const parseOhlcvToVertical = (input, main, startIndex = 0) => {
54
- const { len, studyOptions = {}, inputParams } = main;
55
-
56
- if (studyOptions) {
57
- const studyOptionKeys = Object.keys(studyOptions);
58
- for (let i = 0; i < studyOptionKeys.length; i++) {
59
- const k = studyOptionKeys[i];
60
- if (!defaultStudyOptions.hasOwnProperty(k)) {
61
- throw new Error(`Key ${k} not found in defaultStudyOptions. Available options: ${Object.keys(defaultStudyOptions).join(', ')}`);
62
- }
63
- }
64
- }
33
+ const { len, inputParams } = main
65
34
 
66
- const {
67
- midPriceOpenClose,
68
- midPriceHighLow,
69
- sessionIndex,
70
- sessionIntradayIndex,
71
- dayOfTheWeek,
72
- dayOfTheMonth,
73
- weekOfTheMonth
74
- } = studyOptions;
35
+ main.nullArray = new Array(len).fill(null)
75
36
 
76
- const numberColsKeys = ['open', 'high', 'low', 'close', 'volume'];
77
- if (midPriceOpenClose) numberColsKeys.push('mid_price_open_close');
78
- if (midPriceHighLow) numberColsKeys.push('mid_price_high_low');
37
+ if (startIndex === 0) {
79
38
 
80
- const numberColsKeysSet = new Set(numberColsKeys);
39
+ validateInputParams(main)
40
+
41
+ const baseKeys = ['open', 'high', 'low', 'close', 'volume'];
42
+ const baseKeysSet = new Set(baseKeys);
81
43
 
82
- let isValidDate = false;
83
- if (startIndex === 0) {
84
44
  // Fresh initialization
85
- for (let i = 0; i < numberColsKeys.length; i++) {
86
- main.verticalOhlcv[numberColsKeys[i]] = new Array(len);
45
+ for (let i = 0; i < baseKeys.length; i++) {
46
+ main.verticalOhlcv[baseKeys[i]] = [...main.nullArray]
87
47
  }
88
48
 
89
49
  const inputKeys = Object.keys(input[0]);
90
50
  const otherKeys = [];
91
51
  for (let i = 0; i < inputKeys.length; i++) {
92
- const key = inputKeys[i];
93
- if (!numberColsKeysSet.has(key)) {
94
- main.verticalOhlcv[key] = new Array(len);
95
- otherKeys.push(key);
52
+ const key = inputKeys[i]
53
+ if (!baseKeysSet.has(key)) {
54
+ main.verticalOhlcv[key] = [...main.nullArray]
55
+ otherKeys.push(key)
96
56
  }
97
57
  }
98
58
  main.otherKeys = otherKeys;
99
59
 
100
- isValidDate = validateFirstDate(input);
101
60
 
102
- if (isValidDate) {
103
-
104
-
105
- if(sessionIndex) main.verticalOhlcv.session_index = new Array(len)
106
- if(sessionIntradayIndex) main.verticalOhlcv.session_intraday_index = new Array(len)
107
- if(dayOfTheWeek) main.verticalOhlcv.day_of_the_week = new Array(len)
108
- if(dayOfTheMonth) main.verticalOhlcv.day_of_the_month = new Array(len)
109
- if(weekOfTheMonth) main.verticalOhlcv.week_of_the_month = new Array(len)
110
-
111
- Object.assign(main, {
112
- prevDateStr: input[0].date.slice(0, 10),
113
- sessionIndexCount: 0,
114
- sessionIntradayIndexCount: 0,
115
- cachedDayInfo: getDateInfo(main.prevDateStr)
116
- })
117
-
118
- } else {
119
-
120
- Object.assign(main, {
121
- prevDateStr: null,
122
- sessionIndexCount: null,
123
- sessionIntradayIndexCount: null,
124
- cachedDayInfo: null,
125
- })
126
- }
127
61
  } else {
128
62
  if (!main.otherKeys) {
129
63
  throw new Error("otherKeys not found in main. Ensure you run with startIndex=0 first to initialize.");
130
64
  }
131
-
132
- if (!main.hasOwnProperty('prevDateStr')) {
133
- throw new Error("prevDateStr missing in main. Make sure to store state after initial run.");
134
- }
135
-
136
- isValidDate = main.prevDateStr !== null;
137
65
  }
138
66
 
139
67
  const indicatorCalls = processIndicatorCalls(inputParams);
140
68
 
141
- let {prevDateStr, sessionIndexCount, sessionIntradayIndexCount, cachedDayInfo} = main
142
69
 
143
70
  for (let x = startIndex; x < len; x++) {
144
71
  const current = input[x];
@@ -149,86 +76,35 @@ export const parseOhlcvToVertical = (input, main, startIndex = 0) => {
149
76
  main.verticalOhlcv.close[x] = current.close;
150
77
  main.verticalOhlcv.volume[x] = current.volume;
151
78
 
152
- if (midPriceOpenClose) {
153
- main.verticalOhlcv.mid_price_open_close[x] = (current.open + current.close) / 2;
154
- }
155
- if (midPriceHighLow) {
156
- main.verticalOhlcv.mid_price_high_low[x] = (current.high + current.low) / 2;
157
- }
158
-
159
79
  for (let i = 0; i < main.otherKeys.length; i++) {
160
80
  const k = main.otherKeys[i];
161
81
  main.verticalOhlcv[k][x] = current[k];
162
82
  }
163
83
 
164
- if (isValidDate) {
165
- const thisDateStr = current.date.slice(0, 10);
166
- if (thisDateStr !== prevDateStr) {
167
- prevDateStr = thisDateStr;
168
- sessionIndexCount++;
169
- sessionIntradayIndexCount = 0;
170
- cachedDayInfo = getDateInfo(thisDateStr);
171
- }
172
-
173
- if (dayOfTheWeek) {
174
- main.verticalOhlcv.day_of_the_week[x] = cachedDayInfo.day_of_the_week;
175
- }
176
-
177
- if (dayOfTheMonth) {
178
- main.verticalOhlcv.day_of_the_month[x] = cachedDayInfo.day_of_the_month;
179
- }
180
-
181
- if (weekOfTheMonth) {
182
- main.verticalOhlcv.week_of_the_month[x] = cachedDayInfo.week_of_the_month;
183
- }
184
-
185
- if (sessionIndex) {
186
- main.verticalOhlcv.session_index[x] = sessionIndexCount;
187
- }
84
+ for (let i = 0; i < indicatorCalls.length; i++) {
85
+ const { fn, args, key } = indicatorCalls[i];
86
+ if (key === 'crossPairs' || key === 'lag') continue;
188
87
 
189
- if (sessionIntradayIndex) {
190
- main.verticalOhlcv.session_intraday_index[x] = sessionIntradayIndexCount;
191
- }
192
-
193
- sessionIntradayIndexCount++;
194
-
195
- for (let i = 0; i < indicatorCalls.length; i++) {
196
- const { fn, args, key } = indicatorCalls[i];
197
- if (key === 'crossPairs' || key === 'lag') continue;
198
- fn(main, x, ...args);
199
- }
88
+ fn(main, x, ...args)
200
89
  }
201
90
 
202
- lag(main, x, inputParams.lag);
203
- crossPairs(main, x, main.crossPairsList);
91
+ lag(main, x);
92
+ crossPairs(main, x);
204
93
  main.lastComputedIndex++;
205
94
  }
206
-
207
- Object.assign(main, {
208
- prevDateStr,
209
- sessionIndexCount,
210
- sessionIntradayIndexCount,
211
- cachedDayInfo
212
- })
213
95
  };
214
96
 
215
97
 
216
- const processIndicatorCalls = (inputParams) => {
217
- if (!inputParams || typeof inputParams !== 'object') return [];
218
-
219
- const indicatorCalls = [];
220
- for (const [key, technical] of Object.entries(inputParams)) {
221
- if (Array.isArray(technical)) {
222
- for (const params of technical) {
223
- if (Array.isArray(params)) {
224
- indicatorCalls.push({
225
- key,
226
- fn: indicatorFunctions[key],
227
- args: params,
228
- });
229
- }
230
- }
231
- }
98
+ const processIndicatorCalls = inputParams => {
99
+ if (!inputParams || typeof inputParams !== 'object') return []
100
+
101
+ const indicatorCalls = []
102
+
103
+ for(let x = 0; x < inputParams.length; x++)
104
+ {
105
+ const {key, params} = inputParams[x]
106
+ indicatorCalls.push({key, fn: indicatorFunctions[key], args: params})
232
107
  }
108
+
233
109
  return indicatorCalls;
234
110
  };
@@ -1,5 +1,5 @@
1
- export const setIndicatorsFromInputParams = ({ input, inputParams, OHLCV_INDICATORS, studyOptions }) => {
2
- const indicators = new OHLCV_INDICATORS({ input, studyOptions });
1
+ export const setIndicatorsFromInputParams = ({ input, inputParams, OHLCV_INDICATORS }) => {
2
+ const indicators = new OHLCV_INDICATORS({ input });
3
3
 
4
4
  for (const [key, technical] of Object.entries(inputParams)) {
5
5
 
@@ -0,0 +1,20 @@
1
+ export const validateDate = dateString => typeof dateString === 'string' && /^\d{4}-\d{2}-\d{2}/.test(dateString)
2
+
3
+
4
+ export const validateInputParams = main => {
5
+
6
+ const {inputParams, len} = main
7
+
8
+ for (const { params } of inputParams) {
9
+ for (const v of params) {
10
+ if (typeof v === 'number' && v > len) {
11
+ console.log(v, len);
12
+ throw new Error('At least one of the params of the indicator is greater than the input OHLCV length. Make sure to have enough datapoints in the input OHLCV.');
13
+ }
14
+ }
15
+ }
16
+ }
17
+
18
+ export const isAlreadyComputed = main => {
19
+ if(main.lastComputedIndex !== 0) throw Error('ohlcv is already computed, you can not add new indicators after "compute", "getLastValues" or "getData" methods are called.')
20
+ }