Skip to content
This repository has been archived by the owner on Sep 12, 2024. It is now read-only.

Commit

Permalink
Merge pull request #453 from sandeep-deriv/sandeep/fix-dependabot-iss…
Browse files Browse the repository at this point in the history
…ues-1

refactor: 🔥 Removed outdated binary indicators package
  • Loading branch information
sandeep-deriv authored Apr 5, 2024
2 parents afaadad + 515996f commit 27f318e
Show file tree
Hide file tree
Showing 11 changed files with 560 additions and 763 deletions.
960 changes: 210 additions & 750 deletions package-lock.json

Large diffs are not rendered by default.

5 changes: 2 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@
"author": "Binary.com",
"license": "MIT",
"devDependencies": {
"@babel/core": "^7.24.0",
"@babel/core": "^7.24.4",
"@babel/eslint-parser": "^7.22.5",
"@babel/plugin-proposal-class-properties": "^7.18.6",
"@babel/plugin-proposal-decorators": "^7.22.6",
Expand All @@ -51,7 +51,6 @@
"@babel/preset-env": "^7.24.0",
"@babel/preset-react": "^7.16.7",
"@babel/register": "^7.16.8",
"@binary-com/binary-indicators": "^1.6.3",
"babel-jest": "^29.7.0",
"babel-loader": "^8.2.3",
"chai": "^4.3.4",
Expand Down Expand Up @@ -116,7 +115,7 @@
"blockly": "github:binary-com/blockly#fix-blockly",
"classnames": "^2.3.1",
"commander": "^8.3.0",
"core-js": "^3.18",
"core-js": "^3.36.1",
"crc-32": "^1.2.0",
"js-cookie": "^3.0.5",
"mobx": "^6.3.12",
Expand Down
16 changes: 11 additions & 5 deletions src/blockly/bot/Interface/IndicatorsInterface.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,14 @@
import sma, { simpleMovingAverageArray as smaa } from '@binary-com/binary-indicators/lib/simpleMovingAverage';
import ema, { exponentialMovingAverageArray as emaa } from '@binary-com/binary-indicators/lib/exponentialMovingAverage';
import bb, { bollingerBandsArray as bba } from '@binary-com/binary-indicators/lib/bollingerBands';
import rsi, { relativeStrengthIndexArray as rsia } from '@binary-com/binary-indicators/lib/relativeStrengthIndex';
import macda from '@binary-com/binary-indicators/lib/macd';
import {
simpleMovingAverage as sma,
simpleMovingAverageArray as smaa,
bollingerBands as bb,
bollingerBandsArray as bba,
exponentialMovingAverage as ema,
exponentialMovingAverageArray as emaa,
relativeStrengthIndex as rsi,
relativeStrengthIndexArray as rsia,
macdArray as macda,
} from './indicators';

export default Interface =>
class extends Interface {
Expand Down
42 changes: 42 additions & 0 deletions src/blockly/bot/Interface/indicators/bb.js
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));
};
53 changes: 53 additions & 0 deletions src/blockly/bot/Interface/indicators/ema.js
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))));
};
5 changes: 5 additions & 0 deletions src/blockly/bot/Interface/indicators/index.js
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';
59 changes: 59 additions & 0 deletions src/blockly/bot/Interface/indicators/macd.js
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);
};
16 changes: 16 additions & 0 deletions src/blockly/bot/Interface/indicators/math.js
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());
113 changes: 113 additions & 0 deletions src/blockly/bot/Interface/indicators/rsi.js
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)
);
};
38 changes: 38 additions & 0 deletions src/blockly/bot/Interface/indicators/sma.js
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)
);
};
Loading

0 comments on commit 27f318e

Please sign in to comment.