|
|
|
|
@ -5,6 +5,7 @@ import random
@@ -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:
@@ -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 |
|
|
|
|
@ -122,6 +126,9 @@ class RsiSignalGenerator:
@@ -122,6 +126,9 @@ class RsiSignalGenerator:
|
|
|
|
|
ineq_type = random.randint(RsiSignal.LT, RsiSignal.GT) |
|
|
|
|
return RsiSignal(period, threshold, ineq_type, shift) |
|
|
|
|
|
|
|
|
|
def id(self): |
|
|
|
|
return 'RSI' |
|
|
|
|
|
|
|
|
|
class RsiSignal(Signal): |
|
|
|
|
|
|
|
|
|
LT = 0 |
|
|
|
|
@ -177,6 +184,9 @@ class AtrSignalGenerator:
@@ -177,6 +184,9 @@ class AtrSignalGenerator:
|
|
|
|
|
ineq_type = random.randint(AtrSignal.LT, AtrSignal.GT) |
|
|
|
|
return AtrSignal(period, threshold, ineq_type) |
|
|
|
|
|
|
|
|
|
def id(self): |
|
|
|
|
return 'ATR' |
|
|
|
|
|
|
|
|
|
class AtrSignal(Signal): |
|
|
|
|
|
|
|
|
|
LT = 0 |
|
|
|
|
@ -231,6 +241,9 @@ class AtrDeltaSignalGenerator:
@@ -231,6 +241,9 @@ class AtrDeltaSignalGenerator:
|
|
|
|
|
sign = random.randint(AtrDeltaSignal.PLUS, AtrDeltaSignal.MINUS) |
|
|
|
|
return AtrDeltaSignal(period, threshold, ineq_type, sign) |
|
|
|
|
|
|
|
|
|
def id(self): |
|
|
|
|
return 'ATR Delta' |
|
|
|
|
|
|
|
|
|
class AtrDeltaSignal(Signal): |
|
|
|
|
|
|
|
|
|
LT = 0 |
|
|
|
|
@ -302,6 +315,9 @@ class DayOfWeekSignalGenerator:
@@ -302,6 +315,9 @@ class DayOfWeekSignalGenerator:
|
|
|
|
|
dow = random.randint(0, 6) |
|
|
|
|
return DayOfWeekSignal(dow) |
|
|
|
|
|
|
|
|
|
def id(self): |
|
|
|
|
return 'Day of week' |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class DayOfWeekSignal(Signal): |
|
|
|
|
|
|
|
|
|
@ -335,6 +351,8 @@ class DayOfMonthSignalGenerator:
@@ -335,6 +351,8 @@ class DayOfMonthSignalGenerator:
|
|
|
|
|
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:
@@ -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 |
|
|
|
|
@ -436,6 +457,9 @@ class SmaSignalGenerator:
@@ -436,6 +457,9 @@ class SmaSignalGenerator:
|
|
|
|
|
ineq_sign = random.randint(SmaSignal.LT, SmaSignal.GT) |
|
|
|
|
return SmaSignal(period, lhs, rhs, ineq_sign) |
|
|
|
|
|
|
|
|
|
def id(self): |
|
|
|
|
return 'SMA' |
|
|
|
|
|
|
|
|
|
class SmaSignal(Signal): |
|
|
|
|
|
|
|
|
|
OPEN = 0 |
|
|
|
|
@ -514,6 +538,9 @@ class CciSignalGenerator:
@@ -514,6 +538,9 @@ class CciSignalGenerator:
|
|
|
|
|
ineq_type = random.randint(CciSignal.LT, CciSignal.GT) |
|
|
|
|
return CciSignal(shift, period, threshold, ineq_type) |
|
|
|
|
|
|
|
|
|
def id(self): |
|
|
|
|
return 'CCI' |
|
|
|
|
|
|
|
|
|
class CciSignal(Signal): |
|
|
|
|
|
|
|
|
|
LT = 0 |
|
|
|
|
@ -575,6 +602,9 @@ class BbandsSignalGenerator:
@@ -575,6 +602,9 @@ class BbandsSignalGenerator:
|
|
|
|
|
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): |
|
|
|
|
|
|
|
|
|
@ -659,3 +689,167 @@ class BbandsSignal(Signal):
@@ -659,3 +689,167 @@ class BbandsSignal(Signal):
|
|
|
|
|
else: |
|
|
|
|
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)) |
|
|
|
|
|
|
|
|
|
|