Skip to content

Commit

Permalink
fix: Align MACD results with Tulip Indicators (#171)
Browse files Browse the repository at this point in the history
  • Loading branch information
bennycode authored Jan 31, 2021
1 parent 93a0261 commit 5923be1
Show file tree
Hide file tree
Showing 4 changed files with 67 additions and 156 deletions.
13 changes: 9 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Trading Signals

![Language Details](https://img.shields.io/github/languages/top/bennyn/trading-signals) ![Code Coverage](https://img.shields.io/codecov/c/github/bennyn/trading-signals/main) ![License](https://img.shields.io/npm/l/trading-signals.svg) ![Package Version](https://img.shields.io/npm/v/trading-signals.svg) ![Dependency Updates](https://img.shields.io/david/bennyn/trading-signals.svg)
![Language Details](https://img.shields.io/github/languages/top/bennycode/trading-signals) ![Code Coverage](https://img.shields.io/codecov/c/github/bennycode/trading-signals/main) ![License](https://img.shields.io/npm/l/trading-signals.svg) ![Package Version](https://img.shields.io/npm/v/trading-signals.svg) ![Dependency Updates](https://img.shields.io/david/bennycode/trading-signals.svg)

Technical indicators and overlays to run technical analysis with JavaScript / TypeScript.

Expand Down Expand Up @@ -52,9 +52,14 @@ console.log(sma.getResult().valueOf()); // "20"
console.log(sma.getResult().toFixed(2)); // "20.00"
```

## Alternatives

- [Tulip Indicators [ANSI C]](https://github.com/TulipCharts/tulipindicators)
- [Pandas TA [Python]](https://github.com/twopirllc/pandas-ta)

## Maintainers

[![Benny Neugebauer on Stack Exchange][stack_exchange_bennyn_badge]][stack_exchange_bennyn_url]
[![Benny Neugebauer on Stack Exchange][stack_exchange_bennycode_badge]][stack_exchange_bennycode_url]

## Contributing

Expand All @@ -76,5 +81,5 @@ If you like this project, you might also like these related projects:
- [**binance-api-node**](https://github.com/Ashlar/binance-api-node), Heavily tested and Promise-based Binance API.

[1]: http://mikemcl.github.io/big.js/
[stack_exchange_bennyn_badge]: https://stackexchange.com/users/flair/203782.png?theme=default
[stack_exchange_bennyn_url]: https://stackexchange.com/users/203782/benny-neugebauer?tab=accounts
[stack_exchange_bennycode_badge]: https://stackexchange.com/users/flair/203782.png?theme=default
[stack_exchange_bennycode_url]: https://stackexchange.com/users/203782/benny-neugebauer?tab=accounts
67 changes: 48 additions & 19 deletions src/MACD/MACD.test.ts
Original file line number Diff line number Diff line change
@@ -1,31 +1,60 @@
import {MACD} from './MACD';
import Big from 'big.js';

import prices from '../test/fixtures/prices.json';
import results from '../test/fixtures/MACD/results.json';
import {NotEnoughDataError} from '../error';
import {DEMA, EMA, NotEnoughDataError} from '..';

describe('MACD', () => {
describe('getResult', () => {
it('calculates MACD diff, signal & result with 12/26/9', () => {
const indicator = new MACD({longInterval: 26, shortInterval: 12, signalInterval: 9, useDEMA: false});
prices.forEach((price, index) => {
indicator.update(new Big(price));

const {macd, signal, diff} = indicator.getResult();
it('is compatible with values from "Tulip Indicators (TI)"', () => {
/** @see https://tulipindicators.org/macd */
const inputs = [
81.59,
81.06,
82.87,
83.0,
83.61,
83.15,
82.84,
83.99,
84.55,
84.36,
85.53,
86.54,
86.89,
87.77,
87.29,
];
const expectedMacds = [
undefined,
undefined,
undefined,
undefined,
'0.62',
'0.35',
'0.11',
'0.42',
'0.58',
'0.42',
'0.68',
'0.93',
'0.89',
'0.98',
'0.62',
];
const indicator = new MACD({longInterval: 5, shortInterval: 2, signalInterval: 9, indicator: EMA});

const resMACD = new Big(results.macd[index]);
const resSignal = new Big(results.signal[index]);
const resDiff = new Big(results.diff[index]);
for (const [index, input] of Object.entries(inputs)) {
indicator.update(input);

expect(macd.toPrecision(12)).toEqual(resMACD.toPrecision(12));
expect(signal.toPrecision(12)).toEqual(resSignal.toPrecision(12));
expect(diff.toPrecision(12)).toEqual(resDiff.toPrecision(12));
});
const expectedMacd = expectedMacds[parseInt(index, 10)];
if (expectedMacd !== undefined) {
const {macd} = indicator.getResult();
expect(macd.toFixed(2)).toBe(expectedMacd);
}
}
});

it('throws an error when there is not enough input data', () => {
const macd = new MACD({longInterval: 26, shortInterval: 12, signalInterval: 9, useDEMA: true});
const macd = new MACD({longInterval: 26, shortInterval: 12, signalInterval: 9, indicator: DEMA});

try {
macd.getResult();
Expand All @@ -39,7 +68,7 @@ describe('MACD', () => {
describe('isStable', () => {
it('knows when it can return reliable data', () => {
const longInterval = 18;
const macd = new MACD({longInterval, shortInterval: 9, signalInterval: 9, useDEMA: false});
const macd = new MACD({longInterval, shortInterval: 9, signalInterval: 9, indicator: EMA});

const mockedPrices = [
new Big('0.00019040'),
Expand Down
18 changes: 10 additions & 8 deletions src/MACD/MACD.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,14 @@ import Big, {BigSource} from 'big.js';
import {DEMA, NotEnoughDataError} from '..';

export type MACDConfig = {
indicator: typeof EMA | typeof DEMA;
longInterval: number;
shortInterval: number;
signalInterval: number;
useDEMA: boolean;
};

export type MACDResult = {
diff: Big;
histogram: Big;
macd: Big;
signal: Big;
};
Expand All @@ -24,9 +24,9 @@ export class MACD {
private result: MACDResult | undefined;

constructor(private readonly config: MACDConfig) {
this.long = config.useDEMA ? new DEMA(config.longInterval) : new EMA(config.longInterval);
this.short = config.useDEMA ? new DEMA(config.shortInterval) : new EMA(config.shortInterval);
this.signal = config.useDEMA ? new DEMA(config.signalInterval) : new EMA(config.signalInterval);
this.long = new config.indicator(config.longInterval);
this.short = new config.indicator(config.shortInterval);
this.signal = new config.indicator(config.signalInterval);
}

get isStable(): boolean {
Expand Down Expand Up @@ -54,13 +54,15 @@ export class MACD {
*/
this.signal.update(diff);

const signal = this.signal.getResult();

/**
* The MACD-Histogram represents the difference between MACD and its 9-day EMA, the signal line.
*/
this.result = {
diff: diff,
macd: diff.sub(this.signal.getResult()),
signal: this.signal.getResult(),
histogram: diff.sub(signal),
macd: diff,
signal,
};

this.age++;
Expand Down
125 changes: 0 additions & 125 deletions src/test/fixtures/MACD/results.json

This file was deleted.

0 comments on commit 5923be1

Please sign in to comment.