ohlcv-indicators 1.0.0 → 1.0.1
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/index.js +28 -13
- package/package.json +1 -1
- package/test/fetchLiveData.js +132 -9
- package/test/test.js +18 -5
package/index.js
CHANGED
|
@@ -17,24 +17,28 @@ export default class OHLCV_INDICATORS {
|
|
|
17
17
|
init(ohlcv) {
|
|
18
18
|
const { BigNumber } = this
|
|
19
19
|
|
|
20
|
-
const ohlcvObj = ohlcv.map(({ open, high, low, close, volume,
|
|
20
|
+
const ohlcvObj = ohlcv.map(({ open, high, low, close, volume, ...rest }) => ({
|
|
21
21
|
open: BigNumber(open),
|
|
22
22
|
high: BigNumber(high),
|
|
23
23
|
low: BigNumber(low),
|
|
24
24
|
close: BigNumber(close),
|
|
25
25
|
volume: BigNumber(volume),
|
|
26
|
-
|
|
27
|
-
}))
|
|
28
|
-
|
|
29
|
-
this.ohlcv = ohlcvObj.reduce((acc, { open, high, low, close, volume,
|
|
30
|
-
acc.open.push(open)
|
|
31
|
-
acc.high.push(high)
|
|
32
|
-
acc.low.push(low)
|
|
33
|
-
acc.close.push(close)
|
|
34
|
-
acc.volume.push(volume)
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
26
|
+
...rest
|
|
27
|
+
}));
|
|
28
|
+
|
|
29
|
+
this.ohlcv = ohlcvObj.reduce((acc, { open, high, low, close, volume, ...rest }) => {
|
|
30
|
+
acc.open.push(open);
|
|
31
|
+
acc.high.push(high);
|
|
32
|
+
acc.low.push(low);
|
|
33
|
+
acc.close.push(close);
|
|
34
|
+
acc.volume.push(volume);
|
|
35
|
+
Object.keys(rest).forEach(key => {
|
|
36
|
+
if (!acc[key]) acc[key] = [];
|
|
37
|
+
acc[key].push(rest[key]);
|
|
38
|
+
});
|
|
39
|
+
return acc;
|
|
40
|
+
}, { open: [], high: [], low: [], close: [], volume: [] });
|
|
41
|
+
|
|
38
42
|
|
|
39
43
|
return this
|
|
40
44
|
}
|
|
@@ -46,6 +50,17 @@ export default class OHLCV_INDICATORS {
|
|
|
46
50
|
getData() {
|
|
47
51
|
return this.ohlcv
|
|
48
52
|
}
|
|
53
|
+
getLastValues(){
|
|
54
|
+
const output = {}
|
|
55
|
+
|
|
56
|
+
for(let k in this.ohlcv)
|
|
57
|
+
{
|
|
58
|
+
const arr = this.ohlcv[k]
|
|
59
|
+
output[k] = arr[arr.length - 1]
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
return output
|
|
63
|
+
}
|
|
49
64
|
|
|
50
65
|
addColumn(key, arr) {
|
|
51
66
|
const ohlcvLength = this.ohlcv.open.length
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ohlcv-indicators",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.1",
|
|
4
4
|
"description": "A JavaScript library featuring optimized trading indicators for OHLCV arrays [{open, high, low, close, value}], utilizing BigNumber precision for enhanced accuracy.",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"type": "module",
|
package/test/fetchLiveData.js
CHANGED
|
@@ -2,19 +2,16 @@
|
|
|
2
2
|
const apiRoot = 'https://nasdaq.jaimelias.workers.dev/api'
|
|
3
3
|
const convertCurrencyToFloat = str => parseFloat(str.replace(/[,$]/g, ''))
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
5
|
export const getOHLCV = async (symbol, limit) => {
|
|
9
6
|
|
|
10
7
|
|
|
11
|
-
const oneDay = await (
|
|
8
|
+
const oneDay = await (getOneDayOHLCV(symbol, limit))
|
|
12
9
|
const latest = await getLatestOHLCV(symbol)
|
|
13
10
|
|
|
14
11
|
return [...oneDay, ...latest]
|
|
15
12
|
}
|
|
16
13
|
|
|
17
|
-
const
|
|
14
|
+
const getOneDayOHLCV = async (symbol, limit) => {
|
|
18
15
|
|
|
19
16
|
const {fromDate, toDate} = getDateRange(limit)
|
|
20
17
|
const response = await fetch(`${apiRoot}/quote/${symbol}/chart?assetclass=stocks&fromdate=${fromDate}&todate=${toDate}`)
|
|
@@ -26,13 +23,13 @@ const getOneDayOHLC = async (symbol, limit) => {
|
|
|
26
23
|
low: convertCurrencyToFloat(z.low),
|
|
27
24
|
close: convertCurrencyToFloat(z.close),
|
|
28
25
|
volume: convertCurrencyToFloat(z.volume),
|
|
29
|
-
|
|
26
|
+
...convertNyMillisecondsToUtc(x) //{utcTimestamp, utcDate}
|
|
30
27
|
}))
|
|
31
28
|
|
|
32
29
|
return ohlcv
|
|
33
30
|
}
|
|
34
31
|
|
|
35
|
-
const getLatestOHLCV = async (symbol) => {
|
|
32
|
+
export const getLatestOHLCV = async (symbol) => {
|
|
36
33
|
|
|
37
34
|
const response = await fetch(`${apiRoot}/quote/${symbol}/chart?assetClass=stocks`)
|
|
38
35
|
const data = await response.json()
|
|
@@ -45,7 +42,7 @@ const getLatestOHLCV = async (symbol) => {
|
|
|
45
42
|
low: Math.min(...allValues),
|
|
46
43
|
close: convertCurrencyToFloat(lastSalePrice),
|
|
47
44
|
volume: convertCurrencyToFloat(volume),
|
|
48
|
-
|
|
45
|
+
...convertNyMillisecondsToUtc(chart[chart.length -1].x)
|
|
49
46
|
}]
|
|
50
47
|
}
|
|
51
48
|
|
|
@@ -57,4 +54,130 @@ const getDateRange = limit => {
|
|
|
57
54
|
const fromDateFormatted = fromDate.toISOString().slice(0, 10) // Get the date limit number of days ago in yyyy-mm-dd format
|
|
58
55
|
|
|
59
56
|
return { fromDate: fromDateFormatted, toDate }
|
|
60
|
-
};
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
export const fetchHistoricalOHLCV = async ({symbol, days}) => {
|
|
61
|
+
|
|
62
|
+
//this function removes the lates "today result from output"
|
|
63
|
+
|
|
64
|
+
const response = await fetch(`https://charting.nasdaq.com/data/charting/intraday?symbol=${symbol}&mostRecent=${days}&includeLatestIntradayData=1&`, {
|
|
65
|
+
referrer: "https://charting.nasdaq.com/dynamic/chart.html"
|
|
66
|
+
})
|
|
67
|
+
|
|
68
|
+
const data = await response.json()
|
|
69
|
+
const {marketData} = data
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
const parsedData = marketData.map(o => ({
|
|
73
|
+
value: o.Value,
|
|
74
|
+
volume: o.Volume,
|
|
75
|
+
data: o.Date,
|
|
76
|
+
...convertNYDateStringToUTC(o.Date)
|
|
77
|
+
}))
|
|
78
|
+
|
|
79
|
+
const lastItem = parsedData[parsedData.length - 1]
|
|
80
|
+
const lastDay = new Date(lastItem.utcTimestamp);
|
|
81
|
+
lastDay.setUTCHours(0, 0, 0, 0)
|
|
82
|
+
const lastTimeStamp = lastDay.getTime()
|
|
83
|
+
|
|
84
|
+
const filteredData = parsedData.filter(o => o.utcTimestamp < lastTimeStamp)
|
|
85
|
+
|
|
86
|
+
return filteredData;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
const convertNyMillisecondsToUtc = milliseconds => {
|
|
91
|
+
// Create a new Date object using the milliseconds
|
|
92
|
+
const nyDate = new Date(milliseconds);
|
|
93
|
+
|
|
94
|
+
// Calculate the timezone offset in milliseconds (New York is UTC-5 or UTC-4 during Daylight Saving Time)
|
|
95
|
+
const offset = nyDate.getTimezoneOffset() * 60000;
|
|
96
|
+
|
|
97
|
+
// Create a new Date object in UTC by subtracting the offset
|
|
98
|
+
const utcDate = new Date(milliseconds + offset);
|
|
99
|
+
|
|
100
|
+
// Get the UTC milliseconds
|
|
101
|
+
const utcMilliseconds = utcDate.getTime();
|
|
102
|
+
|
|
103
|
+
// Get individual components of the date
|
|
104
|
+
const year = utcDate.getUTCFullYear();
|
|
105
|
+
const month = String(utcDate.getUTCMonth() + 1).padStart(2, '0'); // Months are zero-indexed, so add 1
|
|
106
|
+
const day = String(utcDate.getUTCDate()).padStart(2, '0');
|
|
107
|
+
const hours = String(utcDate.getUTCHours()).padStart(2, '0');
|
|
108
|
+
const minutes = String(utcDate.getUTCMinutes()).padStart(2, '0');
|
|
109
|
+
const seconds = String(utcDate.getUTCSeconds()).padStart(2, '0');
|
|
110
|
+
|
|
111
|
+
// Format the date string
|
|
112
|
+
const utcDateString = `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
|
|
113
|
+
|
|
114
|
+
// Return the result as an object
|
|
115
|
+
return {
|
|
116
|
+
utcTimestamp: utcMilliseconds,
|
|
117
|
+
utcDate: utcDateString
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
function convertNYDateStringToUTC(dateString) {
|
|
123
|
+
// Create a date object in the New York timezone
|
|
124
|
+
const nyDate = new Date(dateString + ' GMT-0400');
|
|
125
|
+
|
|
126
|
+
// Get the UTC date string
|
|
127
|
+
const utcDateString = nyDate.toISOString().replace('T', ' ').substring(0, 19);
|
|
128
|
+
|
|
129
|
+
// Get the UTC timestamp
|
|
130
|
+
const utcTimestamp = nyDate.getTime();
|
|
131
|
+
|
|
132
|
+
return {
|
|
133
|
+
utcDateString: utcDateString,
|
|
134
|
+
utcTimestamp: utcTimestamp
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
export const convertToOHLCV = (data, intervalMinutes) => {
|
|
140
|
+
const validMinuteIntervals = [5, 10, 15, 30, 45, 60, 120, 180, 240];
|
|
141
|
+
|
|
142
|
+
if (!validMinuteIntervals.includes(intervalMinutes)) {
|
|
143
|
+
const errMessage = `Invalid interval. Please use any of the following intervals: ${validMinuteIntervals.join(", ")}`;
|
|
144
|
+
throw Error(errMessage);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
const result = [];
|
|
148
|
+
let tempGroup = [];
|
|
149
|
+
let currentIntervalStart = null;
|
|
150
|
+
|
|
151
|
+
data.forEach(item => {
|
|
152
|
+
if (!currentIntervalStart) {
|
|
153
|
+
currentIntervalStart = item.utcTimestamp;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
if ((item.utcTimestamp - currentIntervalStart) < intervalMinutes * 60000) {
|
|
157
|
+
tempGroup.push(item);
|
|
158
|
+
} else {
|
|
159
|
+
result.push(calculateOHLCV(tempGroup));
|
|
160
|
+
tempGroup = [item];
|
|
161
|
+
currentIntervalStart = item.utcTimestamp;
|
|
162
|
+
}
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
if (tempGroup.length) {
|
|
166
|
+
result.push(calculateOHLCV(tempGroup));
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
return result;
|
|
170
|
+
};
|
|
171
|
+
|
|
172
|
+
const calculateOHLCV = (group) => {
|
|
173
|
+
const open = group[0].value;
|
|
174
|
+
const close = group[group.length - 1].value;
|
|
175
|
+
const high = Math.max(...group.map(item => item.value));
|
|
176
|
+
const low = Math.min(...group.map(item => item.value));
|
|
177
|
+
const volume = group[group.length - 1].volume;
|
|
178
|
+
const utcDateString = group[group.length - 1].utcDateString;
|
|
179
|
+
const utcTimestamp = group[group.length - 1].utcTimestamp;
|
|
180
|
+
|
|
181
|
+
return { open, high, low, close, volume, utcDateString, utcTimestamp };
|
|
182
|
+
};
|
|
183
|
+
|
package/test/test.js
CHANGED
|
@@ -1,11 +1,22 @@
|
|
|
1
1
|
import OHLCV_INDICATORS from '../index.js'
|
|
2
|
-
import { getOHLCV } from './fetchLiveData.js'
|
|
2
|
+
import { getOHLCV, fetchHistoricalOHLCV , getLatestOHLCV, convertToOHLCV} from './fetchLiveData.js'
|
|
3
3
|
|
|
4
4
|
const indicators = new OHLCV_INDICATORS();
|
|
5
5
|
const {BigNumber} = indicators
|
|
6
6
|
|
|
7
7
|
const TEST = async () => {
|
|
8
8
|
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
//console.log(await getLatestOHLCV('NVDA'))
|
|
12
|
+
|
|
13
|
+
//const historical = convertToOHLCV(await fetchHistoricalOHLCV({symbol: 'NVDA', days: 15}), 5)
|
|
14
|
+
//console.log(historical.length)
|
|
15
|
+
//console.log(historical[0])
|
|
16
|
+
//console.log(historical[historical.length - 1])
|
|
17
|
+
//return
|
|
18
|
+
|
|
19
|
+
|
|
9
20
|
const ohlcv = await getOHLCV('AAPL', 230)
|
|
10
21
|
|
|
11
22
|
indicators
|
|
@@ -40,12 +51,14 @@ const TEST = async () => {
|
|
|
40
51
|
}
|
|
41
52
|
})
|
|
42
53
|
|
|
43
|
-
console.log(`${k}: ${JSON.stringify({firstValue, firstValidIndex, lastValue})}`)
|
|
44
|
-
console.log('---\n')
|
|
54
|
+
//console.log(`${k}: ${JSON.stringify({firstValue, firstValidIndex, lastValue})}`)
|
|
55
|
+
//console.log('---\n')
|
|
45
56
|
}
|
|
46
57
|
|
|
47
|
-
console.log('<<<<<<<<<< HEADERS >>>>>>>>>>')
|
|
48
|
-
console.log(indicators.getHeaders())
|
|
58
|
+
//console.log('<<<<<<<<<< HEADERS >>>>>>>>>>')
|
|
59
|
+
//console.log(indicators.getHeaders())
|
|
60
|
+
|
|
61
|
+
console.log(indicators.getLastValues())
|
|
49
62
|
}
|
|
50
63
|
|
|
51
64
|
TEST()
|