From 109ee36338046d48e5079f347dca93d4492a1bda Mon Sep 17 00:00:00 2001 From: Denis Tereshkin Date: Tue, 20 Mar 2018 21:18:26 +0700 Subject: [PATCH] Basic indicators: rsi and ema --- examples/multiple_assets.py | 2 +- src/naiback/indicators/__init__.py | 0 src/naiback/indicators/ema.py | 21 +++++++++++++++++++++ src/naiback/indicators/rsi.py | 20 ++++++++++++++++++++ tests/test_ema.py | 25 +++++++++++++++++++++++++ tests/test_rsi.py | 14 ++++++++++++++ 6 files changed, 81 insertions(+), 1 deletion(-) create mode 100644 src/naiback/indicators/__init__.py create mode 100644 src/naiback/indicators/ema.py create mode 100644 src/naiback/indicators/rsi.py create mode 100644 tests/test_ema.py create mode 100644 tests/test_rsi.py diff --git a/examples/multiple_assets.py b/examples/multiple_assets.py index 8058eed..a8bd1e2 100644 --- a/examples/multiple_assets.py +++ b/examples/multiple_assets.py @@ -1,6 +1,6 @@ from naiback.strategy import Strategy -from naiback.data.feeds import FinamCSVFeed +from naiback.data.feeds import GenericCSVFeed from naiback.indicators import SMA, RSI class MyStrategy(Strategy): diff --git a/src/naiback/indicators/__init__.py b/src/naiback/indicators/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/naiback/indicators/ema.py b/src/naiback/indicators/ema.py new file mode 100644 index 0000000..691b36f --- /dev/null +++ b/src/naiback/indicators/ema.py @@ -0,0 +1,21 @@ + +def _update(v, d, alpha): + return v * (1 - alpha) + d * alpha + +def EMA(data, period, alpha=None): + if alpha is None: + alpha = 2. / (period + 1) + result = [] + v = None + for d in data: + if d is None: + result.append(None) + elif v is None: + result.append(None) + v = d + else: + v = _update(v, d, alpha) + result.append(v) + return result + + diff --git a/src/naiback/indicators/rsi.py b/src/naiback/indicators/rsi.py new file mode 100644 index 0000000..3027b7d --- /dev/null +++ b/src/naiback/indicators/rsi.py @@ -0,0 +1,20 @@ + +from naiback.indicators.ema import EMA + +def _calc_rsi(g, l): + if g is None or l is None: + return None + if l == 0: + return 100 + return 100 - 100 / (1 + g / l) + +def RSI(data, period): + diffs = [0] + prevd = data[0] + for d in data[1:]: + diffs.append(d - prevd) + prevd = d + + gains = EMA([max(x, 0) for x in diffs], period, 1. / period) + losses = EMA([-min(x, 0) for x in diffs], period, 1. / period) + return [_calc_rsi(g, l) for (g, l) in zip(gains, losses)] diff --git a/tests/test_ema.py b/tests/test_ema.py new file mode 100644 index 0000000..215a861 --- /dev/null +++ b/tests/test_ema.py @@ -0,0 +1,25 @@ + +import pytest +import datetime + +from naiback.indicators.ema import EMA + +def test_ema_1(): + data = [1, 1, 1] + ema = EMA(data, 1) + + assert(ema == [None, 1, 1]) + +def test_ema_2(): + data = [1, 3, 5] + ema = EMA(data, 3) + + assert(ema == [None, 2, 3.5]) + +def test_ema_3(): + data = [252.12, 253.97, 253.73, 255.06, 255.14, 256.71, 256.15, 258.51, 255.24, 252.63] + ema = EMA(data, 3) + + assert(abs(ema[-1] - 254.43) < 0.01) + assert(len(ema) == len(data)) + diff --git a/tests/test_rsi.py b/tests/test_rsi.py new file mode 100644 index 0000000..41c29c8 --- /dev/null +++ b/tests/test_rsi.py @@ -0,0 +1,14 @@ + +import pytest +import datetime + +from naiback.indicators.rsi import RSI + +def test_rsi_1(): + data = [252.12, 253.97, 253.73, 255.06, 255.14, 256.71, 256.15, 258.51, 255.24, 252.63, 253.82, 254.16, 253.99, 254.47, + 255.93, 255, 253.21, 251.03] + rsi = RSI(data, 3) + + assert(abs(rsi[-1] - 14.7) < 0.1) + assert(len(rsi) == len(data)) +