ohlcv-indicators 1.9.8 → 1.9.9

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ohlcv-indicators",
3
- "version": "1.9.8",
3
+ "version": "1.9.9",
4
4
  "description": "A JavaScript library featuring optimized trading indicators for OHLCV arrays [{open, high, low, close, value}]. This library is optimized for backtesting and trading bot development.",
5
5
  "main": "index.js",
6
6
  "type": "module",
@@ -26,13 +26,13 @@ const indicatorFunctions = {
26
26
  const validateFirstDate = arr => arr[0].hasOwnProperty('date') && typeof arr[0].date === 'string' && /^\d{4}-\d{2}-\d{2}/.test(arr[0].date)
27
27
 
28
28
  export const defaultStudyOptions = {
29
- midPriceOpenClose: true,
30
- midPriceHighLow: true,
31
- sessionIndex: true,
32
- sessionIntradayIndex: true,
33
- dayOfTheWeek: true,
34
- dayOfTheMonth: true,
35
- weekOfTheMonth: true
29
+ midPriceOpenClose: false,
30
+ midPriceHighLow: false,
31
+ sessionIndex: false,
32
+ sessionIntradayIndex: false,
33
+ dayOfTheWeek: false,
34
+ dayOfTheMonth: false,
35
+ weekOfTheMonth: false
36
36
  }
37
37
 
38
38
  const getDateInfo = (dateString) => {
@@ -51,17 +51,14 @@ const getDateInfo = (dateString) => {
51
51
  }
52
52
 
53
53
  export const parseOhlcvToVertical = (input, main, startIndex = 0) => {
54
- const { len, studyOptions = {}, inputParams } = main
55
-
56
-
57
-
54
+ const { len, studyOptions = {}, inputParams } = main;
58
55
 
59
56
  if (studyOptions) {
60
- const studyOptionKeys = Object.keys(studyOptions)
57
+ const studyOptionKeys = Object.keys(studyOptions);
61
58
  for (let i = 0; i < studyOptionKeys.length; i++) {
62
- const k = studyOptionKeys[i]
59
+ const k = studyOptionKeys[i];
63
60
  if (!defaultStudyOptions.hasOwnProperty(k)) {
64
- throw new Error(`Key ${k} not found in defaultStudyOptions. Available options: ${Object.keys(defaultStudyOptions).join(', ')}`)
61
+ throw new Error(`Key ${k} not found in defaultStudyOptions. Available options: ${Object.keys(defaultStudyOptions).join(', ')}`);
65
62
  }
66
63
  }
67
64
  }
@@ -74,187 +71,147 @@ export const parseOhlcvToVertical = (input, main, startIndex = 0) => {
74
71
  dayOfTheWeek,
75
72
  dayOfTheMonth,
76
73
  weekOfTheMonth
77
- } = studyOptions
74
+ } = studyOptions;
78
75
 
79
- const numberColsKeys = ['open', 'high', 'low', 'close', 'volume']
80
- if (midPriceOpenClose) numberColsKeys.push('mid_price_open_close')
81
- if (midPriceHighLow) numberColsKeys.push('mid_price_high_low')
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');
82
79
 
83
- const numberColsKeysSet = new Set(numberColsKeys)
84
- const vert = main.verticalOhlcv
80
+ const numberColsKeysSet = new Set(numberColsKeys);
85
81
 
86
- let isValidDate = false
82
+ let isValidDate = false;
87
83
  if (startIndex === 0) {
88
84
  // Fresh initialization
89
- // Initialize arrays for numerical columns
90
85
  for (let i = 0; i < numberColsKeys.length; i++) {
91
- vert[numberColsKeys[i]] = new Array(len)
86
+ main.verticalOhlcv[numberColsKeys[i]] = new Array(len);
92
87
  }
93
88
 
94
- // Extract other keys and initialize their arrays
95
- const inputKeys = Object.keys(input[0])
96
- const otherKeys = []
89
+ const inputKeys = Object.keys(input[0]);
90
+ const otherKeys = [];
97
91
  for (let i = 0; i < inputKeys.length; i++) {
98
- const key = inputKeys[i]
92
+ const key = inputKeys[i];
99
93
  if (!numberColsKeysSet.has(key)) {
100
- vert[key] = new Array(len)
101
- otherKeys.push(key)
94
+ main.verticalOhlcv[key] = new Array(len);
95
+ otherKeys.push(key);
102
96
  }
103
97
  }
104
- main.otherKeys = otherKeys
98
+ main.otherKeys = otherKeys;
105
99
 
106
- isValidDate = validateFirstDate(input)
100
+ isValidDate = validateFirstDate(input);
107
101
 
108
102
  if (isValidDate) {
109
- if (sessionIndex) {
110
- vert['session_index'] = new Array(len)
111
- }
112
- if (sessionIntradayIndex) {
113
- vert['session_intraday_index'] = new Array(len)
114
- }
115
- if (dayOfTheWeek) {
116
- vert['day_of_the_week'] = new Array(len)
117
- }
118
- if (dayOfTheMonth) {
119
- vert['day_of_the_month'] = new Array(len)
120
- }
121
- if (weekOfTheMonth) {
122
- vert['week_of_the_month'] = new Array(len)
123
- }
124
103
 
125
- main.prevDateStr = input[0].date.slice(0, 10)
126
- main.sessionIndexCount = 0
127
- main.sessionIntradayIndexCount = 0
128
- main.cachedDayInfo = getDateInfo(main.prevDateStr)
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
+
129
118
  } else {
130
- // If no valid date, ensure these are null
131
- main.prevDateStr = null
132
- main.sessionIndexCount = null
133
- main.sessionIntradayIndexCount = null
134
- main.cachedDayInfo = null
119
+
120
+ Object.assign(main, {
121
+ prevDateStr: null,
122
+ sessionIndexCount: null,
123
+ sessionIntradayIndexCount: null,
124
+ cachedDayInfo: null,
125
+ })
135
126
  }
136
127
  } else {
137
- // startIndex > 0
138
- // We assume arrays and keys are already set
139
128
  if (!main.otherKeys) {
140
- throw new Error("otherKeys not found in main. Ensure you run with startIndex=0 first to initialize.")
129
+ throw new Error("otherKeys not found in main. Ensure you run with startIndex=0 first to initialize.");
141
130
  }
142
131
 
143
- // Validate that state variables needed are present
144
132
  if (!main.hasOwnProperty('prevDateStr')) {
145
- throw new Error("prevDateStr missing in main. Make sure to store state after initial run.")
133
+ throw new Error("prevDateStr missing in main. Make sure to store state after initial run.");
146
134
  }
147
135
 
148
- // If we had a valid date initially, we continue with date computations
149
- isValidDate = main.prevDateStr !== null
136
+ isValidDate = main.prevDateStr !== null;
150
137
  }
151
138
 
152
- // Pre-process indicator params
153
- const indicatorCalls = processIndicatorCalls(inputParams)
154
-
155
- // Store references for numeric arrays to avoid repeated dictionary lookups
156
- const vo_open = vert.open
157
- const vo_high = vert.high
158
- const vo_low = vert.low
159
- const vo_close = vert.close
160
- const vo_volume = vert.volume
161
- const vo_mid_oc = midPriceOpenClose ? vert.mid_price_open_close : null
162
- const vo_mid_hl = midPriceHighLow ? vert.mid_price_high_low : null
163
-
164
- // References for other keys arrays
165
- const otherArrays = {}
166
- for (let i = 0; i < main.otherKeys.length; i++) {
167
- const k = main.otherKeys[i]
168
- otherArrays[k] = vert[k]
169
- }
170
-
171
- // For date/session logic, use previously stored state if startIndex > 0
172
- let prevDateStr = main.prevDateStr
173
- let sessionIndexCount = main.sessionIndexCount
174
- let sessionIntradayIndexCount = main.sessionIntradayIndexCount
175
- let cachedDayInfo = main.cachedDayInfo
139
+ const indicatorCalls = processIndicatorCalls(inputParams);
176
140
 
141
+ let {prevDateStr, sessionIndexCount, sessionIntradayIndexCount, cachedDayInfo} = main
177
142
 
143
+ for (let x = startIndex; x < len; x++) {
144
+ const current = input[x];
178
145
 
146
+ main.verticalOhlcv.open[x] = current.open;
147
+ main.verticalOhlcv.high[x] = current.high;
148
+ main.verticalOhlcv.low[x] = current.low;
149
+ main.verticalOhlcv.close[x] = current.close;
150
+ main.verticalOhlcv.volume[x] = current.volume;
179
151
 
180
- // Compute indicators and fill data from startIndex to len
181
- for (let x = startIndex; x < len; x++) {
182
- const current = input[x]
183
-
184
- // Assign OHLCV
185
- vo_open[x] = current.open
186
- vo_high[x] = current.high
187
- vo_low[x] = current.low
188
- vo_close[x] = current.close
189
- vo_volume[x] = current.volume
190
-
191
- // Mid-price calculations
192
- if (vo_mid_oc) {
193
- vo_mid_oc[x] = (current.open + current.close) / 2
152
+ if (midPriceOpenClose) {
153
+ main.verticalOhlcv.mid_price_open_close[x] = (current.open + current.close) / 2;
194
154
  }
195
- if (vo_mid_hl) {
196
- vo_mid_hl[x] = (current.high + current.low) / 2
155
+ if (midPriceHighLow) {
156
+ main.verticalOhlcv.mid_price_high_low[x] = (current.high + current.low) / 2;
197
157
  }
198
158
 
199
- // Other keys
200
159
  for (let i = 0; i < main.otherKeys.length; i++) {
201
- const k = main.otherKeys[i]
202
- otherArrays[k][x] = current[k]
160
+ const k = main.otherKeys[i];
161
+ main.verticalOhlcv[k][x] = current[k];
203
162
  }
204
163
 
205
- // Date processing for session indices and date fields
206
164
  if (isValidDate) {
207
- const thisDateStr = current.date.slice(0, 10)
165
+ const thisDateStr = current.date.slice(0, 10);
208
166
  if (thisDateStr !== prevDateStr) {
209
- prevDateStr = thisDateStr
210
- sessionIndexCount++
211
- sessionIntradayIndexCount = 0
212
- cachedDayInfo = getDateInfo(thisDateStr)
167
+ prevDateStr = thisDateStr;
168
+ sessionIndexCount++;
169
+ sessionIntradayIndexCount = 0;
170
+ cachedDayInfo = getDateInfo(thisDateStr);
213
171
  }
214
172
 
215
173
  if (dayOfTheWeek) {
216
- vert.day_of_the_week[x] = cachedDayInfo.day_of_the_week
174
+ main.verticalOhlcv.day_of_the_week[x] = cachedDayInfo.day_of_the_week;
217
175
  }
218
176
 
219
177
  if (dayOfTheMonth) {
220
- vert.day_of_the_month[x] = cachedDayInfo.day_of_the_month
178
+ main.verticalOhlcv.day_of_the_month[x] = cachedDayInfo.day_of_the_month;
221
179
  }
222
180
 
223
181
  if (weekOfTheMonth) {
224
- vert.week_of_the_month[x] = cachedDayInfo.week_of_the_month
182
+ main.verticalOhlcv.week_of_the_month[x] = cachedDayInfo.week_of_the_month;
225
183
  }
226
184
 
227
185
  if (sessionIndex) {
228
- vert.session_index[x] = sessionIndexCount
186
+ main.verticalOhlcv.session_index[x] = sessionIndexCount;
229
187
  }
230
188
 
231
189
  if (sessionIntradayIndex) {
232
- vert.session_intraday_index[x] = sessionIntradayIndexCount
190
+ main.verticalOhlcv.session_intraday_index[x] = sessionIntradayIndexCount;
233
191
  }
234
192
 
235
- sessionIntradayIndexCount++
236
-
193
+ sessionIntradayIndexCount++;
237
194
 
238
- // Run indicator functions
239
195
  for (let i = 0; i < indicatorCalls.length; i++) {
240
- const { fn, args, key } = indicatorCalls[i]
241
- if(key === 'crossPairs' || key === 'lag') continue
242
- fn(main, x, ...args)
196
+ const { fn, args, key } = indicatorCalls[i];
197
+ if (key === 'crossPairs' || key === 'lag') continue;
198
+ fn(main, x, ...args);
243
199
  }
244
200
  }
245
201
 
246
-
247
- lag(main, x, inputParams.lag)
248
- crossPairs(main, x, main.crossPairsList)
249
- main.lastComputedIndex++
202
+ lag(main, x, inputParams.lag);
203
+ crossPairs(main, x, main.crossPairsList);
204
+ main.lastComputedIndex++;
250
205
  }
251
206
 
252
- // Store current state so that we can continue from here in subsequent calls
253
- main.prevDateStr = prevDateStr
254
- main.sessionIndexCount = sessionIndexCount
255
- main.sessionIntradayIndexCount = sessionIntradayIndexCount
256
- main.cachedDayInfo = cachedDayInfo
257
- }
207
+ Object.assign(main, {
208
+ prevDateStr,
209
+ sessionIndexCount,
210
+ sessionIntradayIndexCount,
211
+ cachedDayInfo
212
+ })
213
+ };
214
+
258
215
 
259
216
  const processIndicatorCalls = (inputParams) => {
260
217
  if (!inputParams || typeof inputParams !== 'object') return [];