From 3812d99022dc0f67f808bd37cbfbb049b0728bbd Mon Sep 17 00:00:00 2001 From: Denis Tereshkin Date: Tue, 24 Apr 2018 17:30:39 +0700 Subject: [PATCH] More signals --- data/signal.py | 200 ++++++++++++++++++++++++++++++++++++++++++++++- ui/mainwindow.py | 5 +- 2 files changed, 201 insertions(+), 4 deletions(-) diff --git a/data/signal.py b/data/signal.py index bb13f64..bf5e1fa 100644 --- a/data/signal.py +++ b/data/signal.py @@ -5,6 +5,7 @@ import random import numpy import talib +from scipy.integrate.tests.test_odeint_jac import rhs class Signal: @@ -33,6 +34,9 @@ class PriceComparisonSignalGenerator: rhs_shift = random.randint(0, 10) return PriceComparisonSignal(lhs, lhs_shift, rhs, rhs_shift) + def id(self): + return 'Price' + class PriceComparisonSignal(Signal): OPEN = 0 @@ -121,6 +125,9 @@ class RsiSignalGenerator: threshold = random.randrange(1, 9) * 10 ineq_type = random.randint(RsiSignal.LT, RsiSignal.GT) return RsiSignal(period, threshold, ineq_type, shift) + + def id(self): + return 'RSI' class RsiSignal(Signal): @@ -176,6 +183,9 @@ class AtrSignalGenerator: threshold = random.randint(1, 30) * 0.001 ineq_type = random.randint(AtrSignal.LT, AtrSignal.GT) return AtrSignal(period, threshold, ineq_type) + + def id(self): + return 'ATR' class AtrSignal(Signal): @@ -230,6 +240,9 @@ class AtrDeltaSignalGenerator: ineq_type = random.randint(AtrDeltaSignal.LT, AtrDeltaSignal.GT) sign = random.randint(AtrDeltaSignal.PLUS, AtrDeltaSignal.MINUS) return AtrDeltaSignal(period, threshold, ineq_type, sign) + + def id(self): + return 'ATR Delta' class AtrDeltaSignal(Signal): @@ -301,6 +314,9 @@ class DayOfWeekSignalGenerator: def generate(self): dow = random.randint(0, 6) return DayOfWeekSignal(dow) + + def id(self): + return 'Day of week' class DayOfWeekSignal(Signal): @@ -334,7 +350,9 @@ class DayOfMonthSignalGenerator: month_day = random.randint(1, 31) ineq_type = random.randint(DayOfMonthSignal.LT, DayOfMonthSignal.GT) return DayOfMonthSignal(month_day, ineq_type) - + + def id(self): + return 'Day of Month' class DayOfMonthSignal(Signal): @@ -377,6 +395,9 @@ class CrtdrSignalGenerator: threshold = 0.05 * random.randint(1, 19) return CrtdrSignal(shift, threshold, ineq_type) + def id(self): + return 'CRTDR' + class CrtdrSignal(Signal): LT = 0 @@ -435,6 +456,9 @@ class SmaSignalGenerator: rhs = random.randint(SmaSignal.OPEN, SmaSignal.CLOSE) ineq_sign = random.randint(SmaSignal.LT, SmaSignal.GT) return SmaSignal(period, lhs, rhs, ineq_sign) + + def id(self): + return 'SMA' class SmaSignal(Signal): @@ -513,6 +537,9 @@ class CciSignalGenerator: threshold = random.randint(1, 30) * 10 ineq_type = random.randint(CciSignal.LT, CciSignal.GT) return CciSignal(shift, period, threshold, ineq_type) + + def id(self): + return 'CCI' class CciSignal(Signal): @@ -574,6 +601,9 @@ class BbandsSignalGenerator: dev = random.randint(1, 6) * 0.5 band_type = random.randint(BbandsSignal.UP, BbandsSignal.DOWN) return BbandsSignal(period, lhs, rhs, dev, ineq_sign, band_type) + + def id(self): + return 'Bollinger bands' class BbandsSignal(Signal): @@ -657,5 +687,169 @@ class BbandsSignal(Signal): elif component == BbandsSignal.CLOSE: return "close" else: - return "??" - \ No newline at end of file + return "??" + +class PivotPointsSignalGenerator: + + def __init__(self): + pass + + def generate(self): + lhs = random.randint(PivotPointsSignal.OPEN, PivotPointsSignal.R3) + lhs_shift = random.randint(0, 10) + rhs = random.randint(PivotPointsSignal.OPEN, PivotPointsSignal.R3) + rhs_shift = random.randint(0, 10) + return PivotPointsSignal(lhs, lhs_shift, rhs, rhs_shift) + + def id(self): + return 'Pivot points' + + +class PivotPointsSignal(Signal): + + OPEN = 0 + HIGH = 1 + LOW = 2 + CLOSE = 3 + + PP = 4 + S1 = 5 + S2 = 6 + S3 = 7 + + R1 = 8 + R2 = 9 + R3 = 10 + + def __init__(self, lhs, lhs_shift, rhs, rhs_shift): + self.lhs = lhs + self.lhs_shift = lhs_shift + self.rhs = rhs + self.rhs_shift = rhs_shift + + def calculate(self, series): + result = [] + for i in range(0, series.length()): + lhs = self.calculate_signal(series, self.lhs, i - self.lhs_shift) + rhs = self.calculate_signal(series, self.rhs, i - self.rhs_shift) + if i - self.lhs_shift >= 0 and i - self.rhs_shift >= 0: + result.append(lhs < rhs) + else: + result.append(False) + + return result + + def calculate_signal(self, series, signal_type, ix): + if signal_type == PivotPointsSignal.OPEN: + return series.get_open(ix) + elif signal_type == PivotPointsSignal.HIGH: + return series.get_high(ix) + elif signal_type == PivotPointsSignal.LOW: + return series.get_low(ix) + elif signal_type == PivotPointsSignal.CLOSE: + return series.get_close(ix) + elif signal_type == PivotPointsSignal.PP: + return (series.get_close(ix) + series.get_high(ix) + series.get_low(ix)) / 3 + elif signal_type == PivotPointsSignal.S1: + pp = (series.get_close(ix) + series.get_high(ix) + series.get_low(ix)) / 3 + return pp * 2 - series.get_high(ix) + elif signal_type == PivotPointsSignal.S2: + pp = (series.get_close(ix) + series.get_high(ix) + series.get_low(ix)) / 3 + return pp - series.get_high(ix) + series.get_low(ix) + elif signal_type == PivotPointsSignal.S3: + pp = (series.get_close(ix) + series.get_high(ix) + series.get_low(ix)) / 3 + return pp - 2 * series.get_high(ix) + 2 * series.get_low(ix) + elif signal_type == PivotPointsSignal.R1: + pp = (series.get_close(ix) + series.get_high(ix) + series.get_low(ix)) / 3 + return pp * 2 - series.get_low(ix) + elif signal_type == PivotPointsSignal.R2: + pp = (series.get_close(ix) + series.get_high(ix) + series.get_low(ix)) / 3 + return pp + series.get_high(ix) - series.get_low(ix) + elif signal_type == PivotPointsSignal.R3: + pp = (series.get_close(ix) + series.get_high(ix) + series.get_low(ix)) / 3 + return pp + 2 * series.get_high(ix) - 2 * series.get_low(ix) + + + def get_text(self): + return "{:s}[{:d}] < {:s}[{:d}]".format(self.component_str(self.lhs), self.lhs_shift, self.component_str(self.rhs), self.rhs_shift) + + def component_str(self, comp_id): + if comp_id == PivotPointsSignal.OPEN: + return "open" + elif comp_id == PivotPointsSignal.HIGH: + return "high" + elif comp_id == PivotPointsSignal.LOW: + return "low" + elif comp_id == PivotPointsSignal.CLOSE: + return "close" + elif comp_id == PivotPointsSignal.PP: + return "pivot" + elif comp_id == PivotPointsSignal.S1: + return "s1" + elif comp_id == PivotPointsSignal.S2: + return "s2" + elif comp_id == PivotPointsSignal.S3: + return "s3" + elif comp_id == PivotPointsSignal.R1: + return "r1" + elif comp_id == PivotPointsSignal.R2: + return "r2" + elif comp_id == PivotPointsSignal.R3: + return "r3" + +class StochasticSignalGenerator: + + def __init__(self): + pass + + def generate(self): + shift = random.randint(0, 3) + period = random.randint(2, 30) + period2 = random.randint(2, 30) + threshold = random.randrange(1, 9) * 10 + ineq_type = random.randint(StochasticSignal.LT, StochasticSignal.GT) + return StochasticSignal(period, period2, threshold, ineq_type, shift) + + def id(self): + return 'Stochastic' + + +class StochasticSignal(Signal): + + LT = 0 + GT = 1 + + def __init__(self, period, period2, threshold, inequality_type, shift): + self.period = period + self.period2 = period2 + self.threshold = threshold + self.inequality_type = inequality_type + self.shift = shift + if inequality_type == StochasticSignal.LT: + self.inequality_sign_str = '<' + else: + self.inequality_sign_str = '>' + + def calculate(self, series): + closes = numpy.array([series.get_close(i) for i in range(0, series.length())]) + highs = numpy.array([series.get_high(i) for i in range(0, series.length())]) + lows = numpy.array([series.get_low(i) for i in range(0, series.length())]) + + stoch_k, stoch_d = talib.STOCHF(highs, lows, closes, self.period, self.period2) + + result = [self.calc_signal(v) for v in stoch_k] + if self.shift == 0: + return result + else: + return [False] * self.shift + result[:-self.shift] + + def calc_signal(self, value): + if self.inequality_type == StochasticSignal.LT: + return value < self.threshold + else: + return value > self.threshold + + def get_text(self): + return "stoch(c, {:d})[{:d}] {:s} {:d}".format(self.period, self.shift, self.inequality_sign_str, int(self.threshold)) + + \ No newline at end of file diff --git a/ui/mainwindow.py b/ui/mainwindow.py index 1524755..f4bade1 100644 --- a/ui/mainwindow.py +++ b/ui/mainwindow.py @@ -9,7 +9,8 @@ from data.series import Series from data.signal import PriceComparisonSignalGenerator, RsiSignalGenerator,\ AtrSignalGenerator, DayOfWeekSignalGenerator, CrtdrSignalGenerator,\ AtrDeltaSignalGenerator, SmaSignalGenerator, DayOfMonthSignalGenerator,\ - CciSignalGenerator, BbandsSignalGenerator + CciSignalGenerator, BbandsSignalGenerator, PivotPointsSignalGenerator,\ + StochasticSignalGenerator from PyQt5.Qt import Qt, QFileDialog, QThread, Q_ARG, QMetaObject import pyqtgraph @@ -48,6 +49,8 @@ class MainWindow(QMainWindow, Ui_MainWindow): self.solver.add_generator(CrtdrSignalGenerator()) self.solver.add_generator(CciSignalGenerator()) self.solver.add_generator(BbandsSignalGenerator()) + self.solver.add_generator(PivotPointsSignalGenerator()) + self.solver.add_generator(StochasticSignalGenerator()) params = { 'num_strategies' : self.sb_strategiesNum.value() } if self.cb_minTradesFilter.isChecked():