This repository has been archived by the owner on Sep 12, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 97
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #453 from sandeep-deriv/sandeep/fix-dependabot-iss…
…ues-1 refactor: 🔥 Removed outdated binary indicators package
- Loading branch information
Showing
11 changed files
with
560 additions
and
763 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
import { simpleMovingAverage } from './sma'; | ||
import { stddev, takeLast, sequence } from './math'; | ||
|
||
/** | ||
* @param {Array} data | ||
* @param {Object} config of type | ||
* { | ||
* periods: number, | ||
* field?: 'open' | 'high' | 'low' | 'close', | ||
* type: 'SMA' | 'WMA' | 'EMA' | 'TEMA' | 'TRIMA', | ||
* stdDevUp: number, | ||
* stdDevDown: number, | ||
* pipSize: number, | ||
* } | ||
*/ | ||
export const bollingerBands = (data, config) => { | ||
const { periods = 20, field, stdDevUp = 2, stdDevDown = 2, pipSize = 2 } = config; | ||
const vals = takeLast(data, periods, field); | ||
const middle = simpleMovingAverage(vals, { periods }); | ||
const std_dev = stddev(vals); | ||
const upper = middle + std_dev * stdDevUp; | ||
const lower = middle - std_dev * stdDevDown; | ||
|
||
return [+middle.toFixed(pipSize), +upper.toFixed(pipSize), +lower.toFixed(pipSize)]; | ||
}; | ||
|
||
/** | ||
* @param {Array} data | ||
* @param {Object} config of type | ||
* { | ||
* periods: number, | ||
* field?: 'open' | 'high' | 'low' | 'close', | ||
* type: 'SMA' | 'WMA' | 'EMA' | 'TEMA' | 'TRIMA', | ||
* stdDevUp: number, | ||
* stdDevDown: number, | ||
* pipSize: number, | ||
* } | ||
*/ | ||
export const bollingerBandsArray = (data, config) => { | ||
const { periods } = config; | ||
return sequence(data.length - periods + 1).map((x, i) => bollingerBands(data.slice(i, i + periods), config)); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
import { takeField, mean } from './math'; | ||
|
||
/** | ||
* @param {Array} data | ||
* @param {Object} config of type | ||
* { | ||
* periods: number, | ||
* field?: 'open' | 'high' | 'low' | 'close', | ||
* pipSize: number, | ||
* } | ||
* @param {Number} init_val | ||
*/ | ||
export const exponentialMovingAverage = (data, config, init_val) => { | ||
const { periods, field, pipSize = 2 } = config; | ||
|
||
const weighting_multiplier = 2 / (periods + 1); | ||
|
||
const vals = takeField(data, field); | ||
|
||
if (init_val) { | ||
return (vals[0] - init_val) * weighting_multiplier + init_val; | ||
} | ||
|
||
if (data.length < periods) { | ||
throw new Error('Periods longer than data length'); | ||
} | ||
|
||
const mean_val = mean(takeField(data.slice(0, periods), field)); | ||
|
||
return +vals | ||
.slice(periods) | ||
.reduce((prev, e) => (e - prev) * weighting_multiplier + prev, mean_val) | ||
.toFixed(pipSize); | ||
}; | ||
|
||
/** | ||
* @param {Array} data | ||
* @param {Object} config of type | ||
* { | ||
* periods: number, | ||
* field?: 'open' | 'high' | 'low' | 'close', | ||
* pipSize: number, | ||
* } | ||
*/ | ||
export const exponentialMovingAverageArray = (data, config) => { | ||
const { periods } = config; | ||
|
||
let init_val = exponentialMovingAverage(data.slice(0, periods), config); | ||
|
||
return data | ||
.slice(periods - 1) | ||
.map((x, i) => (!i ? init_val : (init_val = exponentialMovingAverage([x], config, init_val)))); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
export * from './bb'; | ||
export * from './ema'; | ||
export * from './macd'; | ||
export * from './rsi'; | ||
export * from './sma'; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
import { exponentialMovingAverageArray } from './ema'; | ||
import { takeField } from './math'; | ||
|
||
const paddingLeft = (data, length) => { | ||
const arr = []; | ||
arr.length = length - data.length; | ||
arr.fill(0); | ||
return [...arr, ...data]; | ||
}; | ||
|
||
/** | ||
* @param {Array} data | ||
* @param {Object} config of type | ||
* { | ||
* fastEmaPeriod: number, | ||
* slowEmaPeriod: number, | ||
* signalEmaPeriod: number | ||
* field?: 'open' | 'high' | 'low' | 'close', | ||
* pipSize: number, | ||
* } | ||
*/ | ||
export const macdArray = (data, config) => { | ||
const { field, fastEmaPeriod = 12, slowEmaPeriod = 26, signalEmaPeriod = 9, pipSize = 2 } = config; | ||
|
||
const vals = takeField(data, field); | ||
|
||
const { length } = vals; | ||
|
||
const fast_ema_array = paddingLeft( | ||
exponentialMovingAverageArray( | ||
vals, | ||
{ periods: fastEmaPeriod, pipSize: 20, field } | ||
// -------------------------- ^ set pipSize to 20 to prevent rounding | ||
), | ||
length | ||
); | ||
const slow_ema_array = paddingLeft( | ||
exponentialMovingAverageArray(vals, { periods: slowEmaPeriod, pipSize: 20, field }), | ||
length | ||
); | ||
|
||
const macd_calc_array = paddingLeft( | ||
slow_ema_array.map((x, i) => +(fast_ema_array[i] - x).toFixed(pipSize)), | ||
length | ||
); | ||
|
||
const signal_ema_array = paddingLeft( | ||
exponentialMovingAverageArray(macd_calc_array.slice(slowEmaPeriod - 1), { | ||
periods: signalEmaPeriod, | ||
pipSize: 20, | ||
field, | ||
}), | ||
length | ||
); | ||
|
||
return macd_calc_array | ||
.map((x, i) => [+(x - signal_ema_array[i]).toFixed(pipSize), x, +signal_ema_array[i].toFixed(pipSize)]) | ||
.slice(slowEmaPeriod + signalEmaPeriod - 2); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
export const takeField = (arr, field) => arr.map(x => (field ? x[field] : x)); | ||
|
||
export const takeLast = (arr, n, field) => takeField(arr.slice(n > arr.length ? 0 : arr.length - n, arr.length), field); | ||
|
||
export const sum = data => data.reduce((acc, x) => acc + x, 0); | ||
|
||
export const mean = data => data.reduce((a, b) => a + b, 0) / data.length; | ||
|
||
export const stddev = data => { | ||
const data_mean = mean(data); | ||
const sq_diff = data.map(n => (n - data_mean) ** 2); | ||
const avg_sq_diff = mean(sq_diff); | ||
return Math.sqrt(avg_sq_diff); | ||
}; | ||
|
||
export const sequence = n => Array.from(Array(n).keys()); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,113 @@ | ||
import { takeField, sequence } from './math'; | ||
|
||
const calcGain = (q1, q2) => (q2 > q1 ? q2 - q1 : 0); | ||
const calcLoss = (q1, q2) => (q2 < q1 ? q1 - q2 : 0); | ||
|
||
const calcFirstAvgDiff = (vals, comp, periods) => { | ||
let prev; | ||
return ( | ||
vals.reduce((r, q, i) => { | ||
if (i === 1) { | ||
prev = r; | ||
} | ||
const diff = comp(prev, q); | ||
prev = q; | ||
return diff + (i === 1 ? 0 : r); | ||
}) / periods | ||
); | ||
}; | ||
|
||
const calcSecondAvgDiff = (vals, comp, periods, init_avg) => { | ||
let prev; | ||
if (vals.length === 1) { | ||
// There is no data to calc avg | ||
return init_avg; | ||
} | ||
return vals.reduce((r, q, i) => { | ||
if (i === 1) { | ||
prev = r; | ||
} | ||
const diff = comp(prev, q); | ||
prev = q; | ||
const prev_avg = i === 1 ? init_avg : r; | ||
return (prev_avg * (periods - 1) + diff) / periods; | ||
}); | ||
}; | ||
|
||
/** | ||
* @param {Array} data | ||
* @param {Object} config of type | ||
* { | ||
* periods: number, | ||
* field?: 'open' | 'high' | 'low' | 'close', | ||
* pipSize: number, | ||
* } | ||
* @param {any} memoized_diff | ||
*/ | ||
export const relativeStrengthIndex = (data, config, memoized_diff) => { | ||
const { periods, field } = config; | ||
|
||
if (data.length < periods) { | ||
throw new Error('Periods longer than data length'); | ||
} | ||
|
||
if (data.length === periods) { | ||
return 0; | ||
} | ||
|
||
const vals = takeField(data.slice(0, periods + 1), field); | ||
|
||
let rest_seq; | ||
let init_avg_gain; | ||
let init_avg_loss; | ||
|
||
if (memoized_diff && 'gain' in memoized_diff) { | ||
rest_seq = takeField(data.slice(-2), field); | ||
|
||
init_avg_gain = memoized_diff.gain; | ||
init_avg_loss = memoized_diff.loss; | ||
} else { | ||
// include last element from above to calc diff | ||
rest_seq = takeField(data.slice(periods, data.length), field); | ||
|
||
init_avg_gain = calcFirstAvgDiff(vals, calcGain, periods); | ||
init_avg_loss = calcFirstAvgDiff(vals, calcLoss, periods); | ||
} | ||
|
||
const avg_gain = calcSecondAvgDiff(rest_seq, calcGain, periods, init_avg_gain); | ||
const avg_loss = calcSecondAvgDiff(rest_seq, calcLoss, periods, init_avg_loss); | ||
|
||
if (memoized_diff) { | ||
memoized_diff.gain = avg_gain; | ||
memoized_diff.loss = avg_loss; | ||
} | ||
|
||
if (avg_gain === 0) { | ||
return 0; | ||
} | ||
|
||
if (avg_loss === 0) { | ||
return 100; | ||
} | ||
|
||
const RS = avg_gain / avg_loss; | ||
|
||
return 100 - 100 / (1 + RS); | ||
}; | ||
|
||
/** | ||
* @param {Array} data | ||
* @param {Object} config of type | ||
* { | ||
* periods: number, | ||
* field?: 'open' | 'high' | 'low' | 'close', | ||
* pipSize: number, | ||
* } | ||
*/ | ||
export const relativeStrengthIndexArray = (data, config) => { | ||
const { periods, pipSize = 2 } = config; | ||
const memoized_diff = {}; | ||
return sequence(data.length - periods).map( | ||
(x, i) => +relativeStrengthIndex(data.slice(0, i + periods + 1), config, memoized_diff).toFixed(pipSize) | ||
); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
import { sum, takeLast, sequence } from './math'; | ||
|
||
/** | ||
* @param {Array} data | ||
* @param {Object} config of type | ||
* { | ||
* periods: number, | ||
* field?: 'open' | 'high' | 'low' | 'close', | ||
* pipSize: number, | ||
* } | ||
*/ | ||
export const simpleMovingAverage = (data, config) => { | ||
const { periods, field } = config; | ||
|
||
if (data.length < periods) { | ||
throw new Error('Periods longer than data length'); | ||
} | ||
|
||
const vals = takeLast(data, periods, field); | ||
|
||
return sum(vals) / periods; | ||
}; | ||
|
||
/** | ||
* @param {Array} data | ||
* @param {Object} config of type | ||
* { | ||
* periods: number, | ||
* field?: 'open' | 'high' | 'low' | 'close', | ||
* pipSize: number, | ||
* } | ||
*/ | ||
export const simpleMovingAverageArray = (data, config) => { | ||
const { periods, pipSize = 2 } = config; | ||
return sequence(data.length - periods + 1).map( | ||
(x, i) => +simpleMovingAverage(data.slice(i, i + periods), config).toFixed(pipSize) | ||
); | ||
}; |
Oops, something went wrong.