ohlcv-indicators 1.9.2 → 1.9.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,8 +1,28 @@
1
+ import { rsi } from "../oscillators/rsi.js"
2
+ import { sma } from "../moving-averages/sma.js"
3
+ import { ema } from "../moving-averages/ema.js"
4
+ import { macd } from "../moving-averages/macd.js"
5
+ import { relativeVolume } from "../moving-averages/relativeVolume.js"
6
+ import { donchianChannels } from "../moving-averages/donchianChannel.js"
7
+ import { bollingerBands } from "../moving-averages/bollingerBands.js"
8
+ import { volumeOscillator } from "../oscillators/volumeOscillator.js"
9
+ import { candlesStudies } from "../studies/candleStudies.js"
10
+ import { lag } from "../studies/lag.js"
11
+
12
+ const indicatorFunctions = {
13
+ rsi,
14
+ sma,
15
+ ema,
16
+ macd,
17
+ relativeVolume,
18
+ donchianChannels,
19
+ bollingerBands,
20
+ volumeOscillator,
21
+ candlesStudies,
22
+ lag
23
+ }
1
24
 
2
-
3
-
4
- //true if first row date starts with yyyy-mm-dd date
5
- const validateFirstDate = arr => arr[0].hasOwnProperty('date') && typeof arr[0].date === 'string' && /^\d{4}-\d{2}-\d{2}/.test(arr[0].date)
25
+ const validateFirstDate = (arr) => arr[0].hasOwnProperty('date') && typeof arr[0].date === 'string' && /^\d{4}-\d{2}-\d{2}/.test(arr[0].date)
6
26
 
7
27
  export const defaultStudyOptions = {
8
28
  midPriceOpenClose: false,
@@ -14,15 +34,29 @@ export const defaultStudyOptions = {
14
34
  weekOfTheMonth: false
15
35
  }
16
36
 
17
- export const parseOhlcvToVertical = (input, len, studyOptions) => {
37
+ const getDateInfo = (dateString) => {
38
+ const date = new Date(dateString);
39
+ const day_of_the_week = date.getDay();
40
+ const day_of_the_month = date.getDate();
41
+ const firstDayOfMonth = new Date(date.getFullYear(), date.getMonth(), 1);
42
+ const dayOffset = firstDayOfMonth.getDay();
43
+ const week_of_the_month = Math.ceil((day_of_the_month + dayOffset) / 7);
44
+
45
+ return {
46
+ day_of_the_week,
47
+ day_of_the_month,
48
+ week_of_the_month
49
+ };
50
+ }
18
51
 
52
+ export const parseOhlcvToVertical = (input, main) => {
53
+ const { len, studyOptions, inputParams } = main
19
54
 
20
- if(Boolean(studyOptions))
21
- {
22
- for(let k in studyOptions)
23
- {
24
- if(!defaultStudyOptions.hasOwnProperty(k))
25
- {
55
+ if (studyOptions) {
56
+ const studyOptionKeys = Object.keys(studyOptions)
57
+ for (let i = 0; i < studyOptionKeys.length; i++) {
58
+ const k = studyOptionKeys[i]
59
+ if (!defaultStudyOptions.hasOwnProperty(k)) {
26
60
  throw new Error(`Key ${k} not found in defaultStudyOptions. Available options: ${Object.keys(defaultStudyOptions).join(', ')}`)
27
61
  }
28
62
  }
@@ -38,170 +72,154 @@ export const parseOhlcvToVertical = (input, len, studyOptions) => {
38
72
  weekOfTheMonth
39
73
  } = studyOptions
40
74
 
41
- let highMax
42
- let lowMin
43
- let volMax
44
- let volMin
45
-
46
-
47
75
  const numberColsKeys = ['open', 'high', 'low', 'close', 'volume']
48
-
49
- if(midPriceOpenClose)
50
- {
51
- numberColsKeys.push('mid_price_open_close')
52
- }
53
-
54
- if(midPriceHighLow)
55
- {
56
- numberColsKeys.push('mid_price_high_low')
57
- }
76
+ if (midPriceOpenClose) numberColsKeys.push('mid_price_open_close')
77
+ if (midPriceHighLow) numberColsKeys.push('mid_price_high_low')
58
78
 
59
79
  const numberColsKeysSet = new Set(numberColsKeys)
60
- const verticalOhlcv = {}
80
+ const vert = main.verticalOhlcv
61
81
 
62
82
  // Initialize arrays for numerical columns
63
- for (const key of numberColsKeys) {
64
- verticalOhlcv[key] = new Array(len)
83
+ for (let i = 0; i < numberColsKeys.length; i++) {
84
+ vert[numberColsKeys[i]] = new Array(len)
65
85
  }
66
86
 
67
87
  // Extract other keys and initialize their arrays
68
88
  const inputKeys = Object.keys(input[0])
69
89
  const otherKeys = []
70
-
71
- for (const key of inputKeys) {
90
+ for (let i = 0; i < inputKeys.length; i++) {
91
+ const key = inputKeys[i]
72
92
  if (!numberColsKeysSet.has(key)) {
73
- verticalOhlcv[key] = new Array(len)
93
+ vert[key] = new Array(len)
74
94
  otherKeys.push(key)
75
95
  }
76
96
  }
77
97
 
78
-
98
+ const isValidDate = validateFirstDate(input)
79
99
  let prevDateStr
80
100
  let sessionIndexCount = 0
81
101
  let sessionIntradayIndexCount = 0
82
- const isValidDate = validateFirstDate(input)
83
102
 
84
- if(isValidDate)
85
- {
86
- if(sessionIndex)
87
- {
88
- verticalOhlcv['session_index'] = new Array(len)
103
+ // Initialize date-related arrays if necessary
104
+ if (isValidDate) {
105
+ if (sessionIndex) {
106
+ main.verticalOhlcv['session_index'] = new Array(len)
89
107
  }
90
-
91
- if(sessionIntradayIndex)
92
- {
93
- verticalOhlcv['session_intraday_index'] = new Array(len)
108
+ if (sessionIntradayIndex) {
109
+ main.verticalOhlcv['session_intraday_index'] = new Array(len)
94
110
  }
95
-
96
- if(dayOfTheWeek)
97
- {
98
- verticalOhlcv['day_of_the_week'] = new Array(len)
111
+ if (dayOfTheWeek) {
112
+ main.verticalOhlcv['day_of_the_week'] = new Array(len)
99
113
  }
100
-
101
- if(dayOfTheMonth)
102
- {
103
- verticalOhlcv['day_of_the_month'] = new Array(len)
114
+ if (dayOfTheMonth) {
115
+ main.verticalOhlcv['day_of_the_month'] = new Array(len)
104
116
  }
105
-
106
- if(weekOfTheMonth)
107
- {
108
- verticalOhlcv['week_of_the_month'] = new Array(len)
117
+ if (weekOfTheMonth) {
118
+ main.verticalOhlcv['week_of_the_month'] = new Array(len)
109
119
  }
110
-
120
+
111
121
  prevDateStr = input[0].date.slice(0, 10)
112
122
  }
113
-
114
- for (let x = 0; x < len; x++) {
115
- const current = input[x]
116
123
 
124
+ // Pre-process indicator params
125
+ const indicatorCalls = []
126
+ if (inputParams && typeof inputParams === 'object') {
127
+ for (const key in inputParams) {
128
+ if (key === 'crossPairs') continue
129
+ const technical = inputParams[key]
130
+ if (Array.isArray(technical)) {
131
+ for (let i = 0; i < technical.length; i++) {
132
+ const params = technical[i];
133
+ if (Array.isArray(params)) {
134
+ indicatorCalls.push({
135
+ fn: indicatorFunctions[key],
136
+ args: params
137
+ })
138
+ }
139
+ }
140
+ }
141
+ }
142
+ }
117
143
 
118
- verticalOhlcv.open[x] = current.open
119
- verticalOhlcv.high[x] = current.high
120
- verticalOhlcv.low[x] = current.low
121
- verticalOhlcv.close[x] = current.close
122
- verticalOhlcv.volume[x] = current.volume
144
+ // Store references for numeric arrays to avoid repeated dictionary lookups
145
+ const vo_open = vert.open
146
+ const vo_high = vert.high
147
+ const vo_low = vert.low
148
+ const vo_close = vert.close
149
+ const vo_volume = vert.volume
150
+ const vo_mid_oc = midPriceOpenClose ? vert.mid_price_open_close : null
151
+ const vo_mid_hl = midPriceHighLow ? vert.mid_price_high_low : null
152
+
153
+ // References for other keys arrays
154
+ const otherArrays = {}
155
+ for (let i = 0; i < otherKeys.length; i++) {
156
+ const k = otherKeys[i]
157
+ otherArrays[k] = vert[k]
158
+ }
159
+
160
+ // Cached date info for the current date
161
+ let cachedDayInfo = getDateInfo(prevDateStr) // initial date info if needed
162
+ for (let x = 0; x < len; x++) {
163
+ const current = input[x]
123
164
 
124
- if(midPriceOpenClose)
125
- {
126
- verticalOhlcv.mid_price_open_close[x] = (current.open + current.close) / 2
165
+ // Assign OHLCV
166
+ vo_open[x] = current.open
167
+ vo_high[x] = current.high
168
+ vo_low[x] = current.low
169
+ vo_close[x] = current.close
170
+ vo_volume[x] = current.volume
171
+
172
+ // Run indicator functions
173
+ for (let i = 0; i < indicatorCalls.length; i++) {
174
+ const { fn, args } = indicatorCalls[i]
175
+ fn(main, x, ...args)
127
176
  }
128
177
 
129
- if(midPriceHighLow)
130
- {
131
- verticalOhlcv.mid_price_high_low[x] = (current.high + current.low) / 2
178
+ // Mid-price calculations
179
+ if (vo_mid_oc) {
180
+ vo_mid_oc[x] = (current.open + current.close) / 2
132
181
  }
133
-
134
- // Process other keys
135
- for (const key of otherKeys) {
136
- verticalOhlcv[key][x] = current[key]
182
+ if (vo_mid_hl) {
183
+ vo_mid_hl[x] = (current.high + current.low) / 2
137
184
  }
138
185
 
139
- // Date processing for session indices
186
+ // Other keys
187
+ for (let i = 0; i < otherKeys.length; i++) {
188
+ const k = otherKeys[i]
189
+ otherArrays[k][x] = current[k]
190
+ }
191
+
192
+ // Date processing for session indices and date fields
140
193
  if (isValidDate) {
141
194
  const thisDateStr = current.date.slice(0, 10)
142
-
143
195
  if (thisDateStr !== prevDateStr) {
144
196
  prevDateStr = thisDateStr
145
197
  sessionIndexCount++
146
198
  sessionIntradayIndexCount = 0
199
+ cachedDayInfo = getDateInfo(thisDateStr)
147
200
  }
148
201
 
149
- const {
150
- day_of_the_week,
151
- day_of_the_month,
152
- week_of_the_month
153
- } = getDateInfo(thisDateStr)
154
-
155
- if(dayOfTheWeek)
156
- {
157
- verticalOhlcv.day_of_the_week[x] = day_of_the_week
202
+ if (dayOfTheWeek) {
203
+ main.verticalOhlcv.day_of_the_week[x] = cachedDayInfo.day_of_the_week
158
204
  }
159
-
160
- if(dayOfTheMonth)
161
- {
162
- verticalOhlcv.day_of_the_month[x] = day_of_the_month
205
+
206
+ if (dayOfTheMonth) {
207
+ main.verticalOhlcv.day_of_the_month[x] = cachedDayInfo.day_of_the_month
163
208
  }
164
-
165
- if(weekOfTheMonth)
166
- {
167
- verticalOhlcv.week_of_the_month[x] = week_of_the_month
209
+
210
+ if (weekOfTheMonth) {
211
+ main.verticalOhlcv.week_of_the_month[x] = cachedDayInfo.week_of_the_month
168
212
  }
169
213
 
170
- if(sessionIndex)
171
- {
172
- verticalOhlcv.session_index[x] = sessionIndexCount
214
+ if (sessionIndex) {
215
+ main.verticalOhlcv.session_index[x] = sessionIndexCount
173
216
  }
174
-
175
- if(sessionIntradayIndex)
176
- {
177
- verticalOhlcv.session_intraday_index[x] = sessionIntradayIndexCount
217
+
218
+ if (sessionIntradayIndex) {
219
+ main.verticalOhlcv.session_intraday_index[x] = sessionIntradayIndexCount
178
220
  }
179
221
 
180
222
  sessionIntradayIndexCount++
181
223
  }
182
224
  }
183
-
184
- return verticalOhlcv
185
225
  }
186
-
187
-
188
- const getDateInfo = dateString => {
189
- const date = new Date(dateString);
190
-
191
- // Get day of the week (0 for Sunday, 1 for Monday, etc.)
192
- const day_of_the_week = date.getDay()
193
-
194
- // Get day of the month
195
- const day_of_the_month = date.getDate();
196
-
197
- // Calculate the week of the month
198
- const firstDayOfMonth = new Date(date.getFullYear(), date.getMonth(), 1);
199
- const dayOffset = firstDayOfMonth.getDay(); // Day of the week for the 1st day of the month
200
- const week_of_the_month = Math.ceil((day_of_the_month + dayOffset) / 7);
201
-
202
- return {
203
- day_of_the_week,
204
- day_of_the_month,
205
- week_of_the_month
206
- };
207
- }
@@ -38,8 +38,6 @@ export const setIndicatorsFromInputParams = ({ input, inputParams, OHLCV_INDICAT
38
38
  }
39
39
  }
40
40
  }
41
-
42
- console.log(indicators.getLastValues());
43
-
41
+
44
42
  return indicators;
45
43
  };
@@ -1,41 +0,0 @@
1
- import { findCrosses } from "../studies/findCrosses.js"
2
-
3
- export const orb = main => {
4
- const {inputOhlcv, len} = main
5
- const cols = getOrbOfTheFirstCandle(inputOhlcv, len)
6
- return cols
7
- }
8
-
9
- const getOrbOfTheFirstCandle = (inputOhlcv, len) => {
10
- const orb_high = new Array(len).fill(0)
11
- const orb_low = new Array(len).fill(0)
12
- let startIndex = 0
13
- let currentDate = null
14
- let firstCandleHigh = 0
15
- let firstCandleLow = 0
16
-
17
- for (let i = 0; i < len; i++) {
18
- const current = inputOhlcv[i]
19
-
20
- if(i === 0){
21
- if(!current.hasOwnProperty('date'))
22
- {
23
- throw Error(`input ohlcv array must have a date property available in candle datapoint`)
24
- }
25
- }
26
-
27
- const date = current.date.split(' ')[0]
28
-
29
- if (date !== currentDate) {
30
- currentDate = date;
31
- firstCandleHigh = current.high
32
- firstCandleLow = current.low
33
- }
34
-
35
- orb_high[startIndex] = firstCandleHigh
36
- orb_low[startIndex] = firstCandleLow
37
- startIndex++
38
- }
39
-
40
- return {orb_high, orb_low}
41
- }