binary-indicators
Advanced tools
Comparing version 1.4.1 to 1.5.0
@@ -8,21 +8,20 @@ 'use strict'; | ||
var _binaryUtils = require('binary-utils'); | ||
var _math = require('./math'); | ||
var ema = function ema(vals, periods) { | ||
if (vals.length === 1) { | ||
return vals[0]; | ||
} | ||
var prev = ema(vals.slice(0, vals.length - 1), periods); | ||
return (vals.slice(-1)[0] - prev) * (0, _math.weightingMultiplier)(periods) + prev; | ||
}; | ||
var exponentialMovingAverage = function exponentialMovingAverage(data, config) { | ||
var initVal = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 0; | ||
var periods = config.periods; | ||
var field = config.field; | ||
var _config$pipSize = config.pipSize; | ||
var pipSize = _config$pipSize === undefined ? 2 : _config$pipSize; | ||
var weightingMultiplier = 2 / (periods + 1); | ||
var vals = (0, _math.takeField)(data, field); | ||
if (initVal) { | ||
return (vals[0] - initVal) * weightingMultiplier + initVal; | ||
} | ||
if (data.length < periods) { | ||
@@ -32,5 +31,7 @@ throw new Error('Periods longer than data length'); | ||
var vals = (0, _math.takeLast)(data, periods, field); | ||
var meanVal = (0, _math.mean)((0, _math.takeField)(data.slice(0, periods), field)); | ||
return ema(vals, periods); | ||
return +vals.slice(periods).reduce(function (prev, e) { | ||
return (e - prev) * weightingMultiplier + prev; | ||
}, meanVal).toFixed(pipSize); | ||
}; | ||
@@ -40,7 +41,8 @@ | ||
var periods = config.periods; | ||
var _config$pipSize = config.pipSize; | ||
var pipSize = _config$pipSize === undefined ? 2 : _config$pipSize; | ||
return (0, _binaryUtils.sequence)(data.length - periods + 1).map(function (x, i) { | ||
return +exponentialMovingAverage(data.slice(i, i + periods), config).toFixed(pipSize); | ||
var initVal = exponentialMovingAverage(data.slice(0, periods), config); | ||
return data.slice(periods - 1).map(function (x, i) { | ||
return !i ? initVal : initVal = exponentialMovingAverage([x], config, initVal); | ||
}); | ||
@@ -47,0 +49,0 @@ }; |
@@ -7,4 +7,47 @@ 'use strict'; | ||
exports.default = function (data, config) { | ||
// TODO | ||
}; | ||
var _math = require('./math'); | ||
var _simpleMovingAverage = require('./simpleMovingAverage'); | ||
var _exponentialMovingAverage = require('./exponentialMovingAverage'); | ||
function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } } | ||
var paddingLeft = function paddingLeft(data, length) { | ||
var arr = []; | ||
arr.length = length - data.length; | ||
arr.fill(0); | ||
return [].concat(arr, _toConsumableArray(data)); | ||
}; | ||
var macdArray = function macdArray(data, config) { | ||
var field = config.field; | ||
var _config$fastEmaPeriod = config.fastEmaPeriod; | ||
var fastEmaPeriod = _config$fastEmaPeriod === undefined ? 12 : _config$fastEmaPeriod; | ||
var _config$slowEmaPeriod = config.slowEmaPeriod; | ||
var slowEmaPeriod = _config$slowEmaPeriod === undefined ? 26 : _config$slowEmaPeriod; | ||
var _config$signalSmaPeri = config.signalSmaPeriod; | ||
var signalSmaPeriod = _config$signalSmaPeri === undefined ? 9 : _config$signalSmaPeri; | ||
var _config$pipSize = config.pipSize; | ||
var pipSize = _config$pipSize === undefined ? 2 : _config$pipSize; | ||
var vals = (0, _math.takeField)(data, field); | ||
var length = vals.length; | ||
var fastEmaArray = paddingLeft((0, _exponentialMovingAverage.exponentialMovingAverageArray)(vals, { periods: fastEmaPeriod, pipSize: pipSize, field: field }), length); | ||
var slowEmaArray = paddingLeft((0, _exponentialMovingAverage.exponentialMovingAverageArray)(vals, { periods: slowEmaPeriod, pipSize: pipSize, field: field }), length); | ||
var macdCalcArray = paddingLeft(slowEmaArray.map(function (x, i) { | ||
return +(fastEmaArray[i] - x).toFixed(pipSize); | ||
}), length); | ||
var smaArray = paddingLeft((0, _simpleMovingAverage.simpleMovingAverageArray)(macdCalcArray.slice(slowEmaPeriod - 1), { periods: signalSmaPeriod, pipSize: pipSize }), length); | ||
return macdCalcArray.map(function (x, i) { | ||
return [+(x - smaArray[i]).toFixed(pipSize), x, smaArray[i]]; | ||
}); | ||
}; | ||
exports.default = macdArray; |
@@ -22,6 +22,2 @@ "use strict"; | ||
var weightingMultiplier = exports.weightingMultiplier = function weightingMultiplier(periods) { | ||
return 2 / (periods + 1); | ||
}; | ||
var mean = exports.mean = function mean(data) { | ||
@@ -28,0 +24,0 @@ return data.reduce(function (a, b) { |
{ | ||
"name": "binary-indicators", | ||
"version": "1.4.1", | ||
"version": "1.5.0", | ||
"description": "Binary.com Indicators", | ||
@@ -5,0 +5,0 @@ "main": "index.js", |
@@ -10,5 +10,4 @@ import exponentialMovingAverage, { exponentialMovingAverageArray } from '../exponentialMovingAverage'; | ||
it('whole data sample', () => { | ||
const result = exponentialMovingAverage([1, 2, 3], { periods: 3 }); | ||
// const roundedResult = roundResult(result); | ||
expect(result).toEqual(2.25); | ||
const result = exponentialMovingAverage([1, 2, 3, 4, 5, 6], { periods: 3 }); | ||
expect(result).toEqual(5); | ||
}); | ||
@@ -19,3 +18,3 @@ | ||
const result = exponentialMovingAverageArray(data, { periods: 3 }); | ||
expect(result).toEqual([2.25, 3.25, 4.25]); | ||
expect(result).toEqual([2, 3, 4]); | ||
}); | ||
@@ -27,5 +26,5 @@ | ||
23.87, 23.65, 23.19, 23.10, 23.33, 22.68, 23.10, 22.40, 22.17]; | ||
const ema10days = [22.25, 22.22, 22.24, 22.28, 22.34, 22.52, 22.81, | ||
23.01, 23.13, 23.29, 23.33, 23.45, 23.53, 23.58, 23.61, | ||
23.61, 23.52, 23.38, 23.34, 23.13, 22.98]; | ||
const ema10days = [22.22, 22.21, 22.24, 22.27, 22.33, 22.52, 22.79, | ||
22.97, 23.13, 23.28, 23.34, 23.43, 23.51, 23.53, 23.47, 23.4, | ||
23.39, 23.26, 23.23, 23.08, 22.91]; | ||
const result = exponentialMovingAverageArray(data, { periods: 10 }); | ||
@@ -32,0 +31,0 @@ const roundedResult = result.map(x => Math.round(x * 100) / 100); |
@@ -1,31 +0,19 @@ | ||
import macd, { macdArray } from '../relativeStrengthIndex'; | ||
import macdArray from '../macd'; | ||
import { data, histogram, macd, signal } from '../macd-data'; | ||
describe('macd', () => { | ||
it.skip('single value with periods of 1 equals the value', () => { | ||
const result = macd([1], { periods: 1 }); | ||
expect(result).toEqual(1); | ||
}); | ||
it('real world', () => { | ||
const result = macdArray(data, { fastEmaPeriod: 12, slowEmaPeriod: 26, signalSmaPeriod: 9 }).slice(-100); | ||
const expectedHistogram = histogram.slice(-100); | ||
const expectedMacd = macd.slice(-100); | ||
const expectedSignal = signal.slice(-100); | ||
it.skip('whole data sample', () => { | ||
const result = macd([1, 2, 3], { periods: 3 }); | ||
// const roundedResult = roundResult(result); | ||
expect(result).toEqual(1); | ||
}); | ||
const diff = result.reduce((p2, val, i) => | ||
p2 + Math.abs(val[0] - expectedHistogram[i]) + | ||
Math.abs(val[1] - expectedMacd[i]) + | ||
Math.abs(val[2] - expectedSignal[i]) | ||
, 0); | ||
it.skip('wuut2', () => { | ||
const data = [1, 2, 3, 4, 5]; | ||
const result = macd(data, { periods: 3 }); | ||
expect(result).toEqual([1, 1.5, 2.25, 3.125, 4.063]); | ||
expect(parseInt((diff / (3 * 100)) * 10, 10)).toEqual(0); // expect diff to be less than 0.1 for each sample | ||
}); | ||
it.skip('real world', () => { | ||
const data = [22.27, 22.19, 22.08, 22.17, 22.18, 22.13, 22.23, 22.43, 22.24, 22.29, | ||
22.15, 22.39, 22.38, 22.61, 23.36, 24.05, 23.75, 23.83, 23.95, 23.63, 23.82, | ||
23.87, 23.65, 23.19, 23.10, 23.33, 22.68, 23.10, 22.40, 22.17]; | ||
const ema10days = [22.22, 22.21, 22.24, 22.27, 22.33, 22.52, 22.80, 22.97, 23.13, | ||
23.28, 23.34, 23.43, 23.51, 23.54, 23.47, 23.40, 23.39, 23.26, 23.23, 23.08, 22.92]; | ||
const result = macdArray(data, { periods: 10 }); | ||
const roundedResult = result.map(x => Math.round(x * 100) / 100); | ||
expect(roundedResult).toEqual(ema10days); | ||
}); | ||
}); |
@@ -1,2 +0,2 @@ | ||
import { mean, stddev, sum, takeLast, weightingMultiplier } from '../math'; | ||
import { mean, stddev, sum, takeLast, takeField } from '../math'; | ||
@@ -32,6 +32,5 @@ describe('math', () => { | ||
it('weightingMultiplier', () => { | ||
expect(weightingMultiplier(10)).toBeCloseTo(0.1818); | ||
expect(weightingMultiplier(20)).toBeCloseTo(0.0952); | ||
it('takeField', () => { | ||
expect(takeLast([{ close: 123 }, { close: 321 }], 2, 'close')).toEqual([123, 321]); | ||
}); | ||
}); |
@@ -1,3 +0,2 @@ | ||
import { sequence } from 'binary-utils'; | ||
import { takeLast, weightingMultiplier } from './math'; | ||
import { takeField, mean } from './math'; | ||
@@ -12,14 +11,12 @@ type CandleField = 'open' | 'high' | 'low' | 'close'; | ||
const ema = (vals: [], periods: number) => { | ||
if (vals.length === 1) { | ||
return vals[0]; | ||
} | ||
const exponentialMovingAverage = (data: Candle[], config: ExponentialMovingAverageConfig, initVal: number = 0): number => { | ||
const { periods, field, pipSize = 2 } = config; | ||
const prev = ema(vals.slice(0, vals.length - 1), periods); | ||
const weightingMultiplier = (2 / (periods + 1)); | ||
return (vals.slice(-1)[0] - prev) * weightingMultiplier(periods) + prev; | ||
}; | ||
const vals = takeField(data, field); | ||
const exponentialMovingAverage = (data: Candle[], config: ExponentialMovingAverageConfig): number => { | ||
const { periods, field } = config; | ||
if (initVal) { | ||
return ((vals[0] - initVal) * weightingMultiplier + initVal); | ||
} | ||
@@ -30,15 +27,19 @@ if (data.length < periods) { | ||
const vals = takeLast(data, periods, field); | ||
const meanVal = mean(takeField(data.slice(0, periods), field)); | ||
return ema(vals, periods); | ||
return +(vals.slice(periods) | ||
.reduce((prev, e) => (e - prev) * weightingMultiplier + prev, meanVal)).toFixed(pipSize); | ||
}; | ||
export const exponentialMovingAverageArray = (data: Candle[], config: ExponentialMovingAverageConfig): number[] => { | ||
const { periods, pipSize = 2 } = config; | ||
return sequence(data.length - periods + 1) | ||
.map((x, i) => | ||
+(exponentialMovingAverage(data.slice(i, i + periods), config).toFixed(pipSize)) | ||
); | ||
const { periods } = config; | ||
let initVal = exponentialMovingAverage(data.slice(0, periods), config); | ||
return data.slice(periods - 1).map((x, i) => | ||
!i ? initVal : | ||
(initVal = exponentialMovingAverage([x], config, initVal)) | ||
); | ||
}; | ||
export default exponentialMovingAverage; |
@@ -1,8 +0,42 @@ | ||
type MomentumConfig = { | ||
periods: number, | ||
field: 'open' | 'high' | 'low' | 'close', | ||
import { takeField } from './math'; | ||
import { simpleMovingAverageArray } from './simpleMovingAverage'; | ||
import { exponentialMovingAverageArray } from './exponentialMovingAverage'; | ||
type CandleField = 'open' | 'high' | 'low' | 'close'; | ||
type MacdConfig = { | ||
fastEmaPeriod: number, | ||
slowEmaPeriod: number, | ||
signalSmaPeriod: number, | ||
field?: CandleField, | ||
pipSize: number, | ||
}; | ||
export default (data: Candle[], config: MomentumConfig) => { | ||
// TODO | ||
type MacdEntry = number[]; | ||
const paddingLeft = (data: any[], length: number): any[] => { | ||
const arr = []; | ||
arr.length = length - data.length; | ||
arr.fill(0); | ||
return [...arr, ...data]; | ||
}; | ||
const macdArray = (data: Candle[], config: MacdConfig): MacdEntry[] => { | ||
const { field, fastEmaPeriod = 12, slowEmaPeriod = 26, signalSmaPeriod = 9, pipSize = 2 } = config; | ||
const vals = takeField(data, field); | ||
const length = vals.length; | ||
const fastEmaArray = paddingLeft(exponentialMovingAverageArray(vals, { periods: fastEmaPeriod, pipSize, field }), length); | ||
const slowEmaArray = paddingLeft(exponentialMovingAverageArray(vals, { periods: slowEmaPeriod, pipSize, field }), length); | ||
const macdCalcArray = paddingLeft(slowEmaArray.map((x, i) => +(fastEmaArray[i] - x).toFixed(pipSize)), length); | ||
const smaArray = paddingLeft(simpleMovingAverageArray(macdCalcArray.slice(slowEmaPeriod - 1), { periods: signalSmaPeriod, pipSize }), length); | ||
return macdCalcArray.map((x, i) => | ||
[+(x - smaArray[i]).toFixed(pipSize), x, smaArray[i]]); | ||
}; | ||
export default macdArray; |
@@ -11,5 +11,2 @@ export const takeField = (arr: any[], field?: string): any[] => | ||
export const weightingMultiplier = (periods: number): number => | ||
(2 / (periods + 1)); | ||
export const mean = (data: number[]): number => | ||
@@ -16,0 +13,0 @@ data.reduce((a, b) => a + b) / data.length; |
214988
35
949