Skip to content

Commit

Permalink
core(feat): Add SMA indicator
Browse files Browse the repository at this point in the history
  • Loading branch information
Pratik Galoria committed Jul 22, 2019
1 parent 2ccf88e commit 32b65b7
Show file tree
Hide file tree
Showing 6 changed files with 221 additions and 3 deletions.
58 changes: 56 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,61 @@
# showr-core

![Travis (.org)](https://img.shields.io/travis/pratikgaloria/showr-core.svg)
[![npm (scoped)](https://img.shields.io/npm/v/@showr/core.svg)](https://www.npmjs.com/package/@showr/core)
[![Coverage Status](https://coveralls.io/repos/github/pratikgaloria/showr-core/badge.svg?branch=master)](https://coveralls.io/github/pratikgaloria/showr-core?branch=master)
[![npm (scoped)](https://img.shields.io/npm/v/@showr/core.svg)](https://www.npmjs.com/package/@showr/core)
![GitHub issues](https://img.shields.io/github/issues/pratikgaloria/showr-core.svg)
![npm bundle size](https://img.shields.io/bundlephobia/min/@showr/core.svg)

Showr: Open source JavaScript library to generate technical indicators over stock market data sets.

## Usage

### Indicators

To generate a value over any point, call `value` function of any indicator. This function accepts below parameters:

1. `point`: OHLC data point for which you need to generate an Indicator
2. `dataset`: Historical dataset consisting OHLC data points.
3. `options`: Other options for an indicator. For example, range, period etc.

To set custom options, use `set` function of any indicator.

Example:

#### Importing indicator

```JavaScript
import { SMA } from '@showr/core/indicators';
```

#### Using indicator

```JavaScript
// Historical dataset
const dataset = [{
timestamp: '07/20/2019T09:30:00Z',
open: 142,
high: 145,
low: 135,
close: 140,
}, {
timestamp: '07/21/2019T09:30:00Z',
open: 140,
high: 150,
low: 130,
close: 145,
}];

// Latest point
const point = {
timestamp: '07/22/2019T09:30:00Z',
open: 145,
high: 160,
low: 140,
close: 150,
};

// To calculate a simple moving average for a given Point over the last 3 periods.
console.log(SMA.set({ period: 3}).value(point, dataset)); // 145

Core library for showr
```
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@showr/core",
"version": "1.0.0",
"version": "1.1.0",
"description": "Core library for Showr",
"main": "build/index.js",
"scripts": {
Expand Down
30 changes: 30 additions & 0 deletions src/indicators.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import Indicator from './utils/indicator';
import { symbols } from './utils/symbols';

export const SMA = new Indicator('SMA', { period: 5, attribute: symbols.CLOSE }, function execute(
point,
dataset,
) {
const { period, attribute } = this.options;

if (dataset.length < period - 1) {
return point[attribute];
}

if (dataset.length === period - 1) {
const total = dataset.reduce((acc, data) => acc + data[attribute], 0);
return (point[attribute] + total) / period;
}

const reverseDataset = dataset.slice(0).reverse();
let total = point[attribute];
for (let i = 0; i < period - 1; i += 1) {
total += reverseDataset[i][attribute];
}

return total / period;
});

export default {
SMA,
};
22 changes: 22 additions & 0 deletions src/utils/indicator.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
class Indicator {
constructor(name, options, execute) {
this.name = name;
this.options = options;
this.execute = execute;
}

get value() {
return this.execute;
}

set(options) {
this.options = {
...this.options,
...options,
};

return this;
}
}

export default Indicator;
12 changes: 12 additions & 0 deletions src/utils/symbols.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
export const symbols = {
TIMESTAMP: 'timestamp',
OPEN: 'open',
HIGH: 'high',
LOW: 'low',
CLOSE: 'close',
VOLUME: 'volume',
};

export default {
symbols,
};
100 changes: 100 additions & 0 deletions tests/indicators.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
import { SMA } from '../src/indicators';
import { symbols } from '../src/utils/symbols';

describe('Indicators', () => {
describe('SMA', () => {
const dataset5 = [
{
[symbols.CLOSE]: 10,
},
{
[symbols.CLOSE]: 12,
},
{
[symbols.CLOSE]: 14,
},
{
[symbols.CLOSE]: 16,
},
{
[symbols.CLOSE]: 18,
},
];

it('Should return a valid value for a given point.', () => {
const point = { [symbols.CLOSE]: 20 };
const expectedValue = 16;

expect(SMA.value(point, dataset5)).toBe(expectedValue);
});

it('Should return the same value as attribute if dataset has fewer points than range.', () => {
const dataset = [
{
[symbols.CLOSE]: 10,
},
{
[symbols.CLOSE]: 12,
},
{
[symbols.CLOSE]: 14,
},
];
const point = { [symbols.CLOSE]: 20 };
const expectedValue = 20;

expect(SMA.value(point, dataset)).toBe(expectedValue);
});

it('Should return a valid value if dataset points are as equal as range.', () => {
const dataset = [
{
[symbols.CLOSE]: 10,
},
{
[symbols.CLOSE]: 12,
},
{
[symbols.CLOSE]: 14,
},
{
[symbols.CLOSE]: 16,
},
];
const point = { [symbols.CLOSE]: 20 };
const expectedValue = 14.4;

expect(SMA.value(point, dataset)).toBe(expectedValue);
});

it('Should return a valid value for a given period.', () => {
const point = { [symbols.CLOSE]: 20 };
const expectedValue = 18;

expect(SMA.set({ period: 3 }).value(point, dataset5)).toBe(expectedValue);
});

it('Should return a valid value for any given attribute', () => {
const dataset = [
{
[symbols.HIGH]: 10,
},
{
[symbols.HIGH]: 12,
},
];
const point = { [symbols.HIGH]: 14 };
const expectedValue = 12;

expect(SMA.set({ period: 3, attribute: symbols.HIGH }).value(point, dataset)).toBe(
expectedValue,
);
});

it('Should return NaN if attribute is not present', () => {
const point = { [symbols.HIGH]: 20 };

expect(SMA.value(point, dataset5)).toBeNaN();
});
});
});

0 comments on commit 32b65b7

Please sign in to comment.