class BollingerBands(Indicator): def __init__(self, args=[]): [period, mul] = args self._p = period self._m = mul self._sma = SMA([period]) self._stddev = StdDeviation([period]) super().__init__({ 'args': args, 'id': 'bbands', 'name': 'BBANDS(%f, %f)' % (period, mul), 'seed_period': period }) def reset(self): super().reset() self._sma.reset() self._stddev.reset() def update(self, v): self._sma.update(v) self._stddev.update(v) middle = self._sma.v() stddev = self._stddev.v() super().update({ 'top': middle + (self._m * stddev), 'middle': middle, 'bottom': middle - (self._m * stddev) }) return self.v() def add(self, v): self._sma.add(v) self._stddev.add(v) middle = self._sma.v() stddev = self._stddev.v() if middle is not None and stddev is not None: super().add({ 'top': middle + (self._m * stddev), 'middle': middle, 'bottom': middle - (self._m * stddev) }) return self.v()
class Envelope(Indicator): def __init__(self, args = []): [ length, percent ] = args self._sma = SMA([length]) self._p = percent / 100 super().__init__({ 'args': args, 'id': 'env', 'name': 'Env(%f, %f)' % (length, percent), 'seed_period': length, }) def reset(self): super().reset() self._sma.reset() def update(self, v): self._sma.update(v) basis = self._sma.v() if not isfinite(basis): return delta = basis * self._p super().update({ 'upper': basis + delta, 'basis': basis, 'lower': basis - delta }) return self.v() def add(self, v): self._sma.add(v) basis = self._sma.v() if not isfinite(basis): return delta = basis * self._p super().add({ 'upper': basis + delta, 'basis': basis, 'lower': basis - delta }) return self.v()
class Stochastic(Indicator): def __init__(self, args=[]): [period, smoothK, smoothD] = args self._p = period self._buffer = [] self._kSMA = SMA([smoothK]) self._dSMA = SMA([smoothD]) super().__init__({ 'args': args, 'id': 'stoch', 'name': 'Stoch(%f)' % (period), 'seed_period': period, 'data_type': 'candle', 'data_key': '*' }) def reset(self): super().reset() self._buffer = [] self._kSMA.reset() self._dSMA.reset() def update(self, candle): if len(self._buffer) == 0: self._buffer.append(candle) else: self._buffer[-1] = candle if len(self._buffer) < self._p: return self.v() close = candle['close'] lowestLow = min(map(lambda c: c['low'], self._buffer)) highestHigh = max(map(lambda c: c['high'], self._buffer)) k = 100 * ((close - lowestLow) / (highestHigh - lowestLow)) self._kSMA.update(k) self._dSMA.update(self._kSMA.v()) return super().update({'k': self._kSMA.v(), 'd': self._dSMA.v()}) def add(self, candle): self._buffer.append(candle) if len(self._buffer) > self._p: del self._buffer[0] elif len(self._buffer) < self._p: return self.v() close = candle['close'] lowestLow = min(map(lambda c: c['low'], self._buffer)) highestHigh = max(map(lambda c: c['high'], self._buffer)) k = 100 * ((close - lowestLow) / (highestHigh - lowestLow)) self._kSMA.add(k) self._dSMA.add(self._kSMA.v()) return super().add({'k': self._kSMA.v(), 'd': self._dSMA.v()})
class AO(Indicator): def __init__(self, period, cache_size=None): self._smaShort = SMA(period, cache_size) self._smaLong = SMA(period, cache_size) super().__init__({ 'args': [period, cache_size], 'id': 'ao', 'name': 'AO', 'seed_period': None, 'data_type': 'candle', 'data_key': '*', 'cache_size': cache_size }) def reset(self): super().reset() self._smaShort.reset() self._smaLong.reset() def update(self, candle): v = (candle['high'] + candle['low']) / 2 self._smaShort.update(v) self._smaLong.update(v) super().update(self._smaShort.v() - self._smaLong.v()) return self.v() def add(self, candle): v = (candle['high'] + candle['low']) / 2 self._smaShort.add(v) self._smaLong.add(v) super().add(self._smaShort.v() - self._smaLong.v()) return self.v()
class RVGI(Indicator): def __init__(self, period, cache_size=None): self._numeratorSMA = SMA(period, cache_size) self._denominatorSMA = SMA(period, cache_size) self._buffer = [] super().__init__({ 'args': [period, cache_size], 'id': 'rvgi', 'name': 'RVGI(%f)' % period, 'seed_period': period, 'data_type': 'candle', 'data_key': '*', 'cache_size': cache_size }) def reset(self): super().reset() self._numeratorSMA.reset() self._denominatorSMA.reset() self._buffer = [] def calc(candle, buffer): barA = candle['close'] - candle['open'] barB = buffer[2]['close'] - buffer[2]['open'] barC = buffer[1]['close'] - buffer[1]['open'] barD = buffer[0]['close'] - buffer[0]['open'] num = (barA + (barB * 2) + (barC * 2) + barD) / 6 e = candle['high'] - candle['low'] f = buffer[2]['high'] - buffer[2]['low'] g = buffer[1]['high'] - buffer[1]['low'] h = buffer[0]['high'] - buffer[0]['low'] den = (e + (f * 2) + (g * 2) + h) / 6 return [num, den] def update(self, candle): if len(self._buffer) == 0: self._buffer.append(candle) else: self._buffer[-1] = candle if len(self._buffer) < 4: return super().update(0) [num, den] = RVGI.calc(candle, self._buffer) self._numeratorSMA.update(num) self._denominatorSMA.update(den) rvi = self._numeratorSMA.v() / self._denominatorSMA.v() signal = 0 if self.l() >= 3: i = self.v()['rvi'] j = self.prev(1)['rvi'] k = self.prev(2)['rvi'] signal = (rvi + (i * 2) + (j * 2) + k) / 6 super().update({'rvi': rvi, 'signal': signal}) def add(self, candle): self._buffer.append(candle) if len(self._buffer) > 4: del self._buffer[0] elif len(self._buffer) < 4: return self.v() [num, den] = RVGI.calc(candle, self._buffer) self._numeratorSMA.add(num) self._denominatorSMA.add(den) rvi = self._numeratorSMA.v() / self._denominatorSMA.v() signal = 0 if self.l() >= 4: i = self.prev(1)['rvi'] j = self.prev(2)['rvi'] k = self.prev(3)['rvi'] signal = (rvi + (i * 2) + (j * 2) + k) / 6 super().add({'rvi': rvi, 'signal': signal})
class KST(Indicator): def __init__(self, rocA, rocB, rocC, rocD, smaA, smaB, smaC, smaD, smaSignal, cache_size=None): self._rocA = ROC(rocA, cache_size) self._rocB = ROC(rocB, cache_size) self._rocC = ROC(rocC, cache_size) self._rocD = ROC(rocD, cache_size) self._smaA = SMA(smaA, cache_size) self._smaB = SMA(smaB, cache_size) self._smaC = SMA(smaC, cache_size) self._smaD = SMA(smaD, cache_size) self._smaSignal = SMA([smaSignal]) super().__init__({ 'args': [ rocA, rocB, rocC, rocD, smaA, smaB, smaC, smaD, smaSignal, cache_size ], 'id': 'kst', 'name': 'KST(%f, %f, %f, %f, %f, %f, %f, %f, %f)' % (rocA, rocB, rocC, rocD, smaA, smaB, smaC, smaD, smaSignal), 'seed_period': max([ rocA + smaA, rocB + smaB, rocC + smaC, rocD + smaD, smaSignal ]), 'cache_size': cache_size }) def reset(self): super().reset() self._rocA.reset() self._rocB.reset() self._rocC.reset() self._rocD.reset() self._smaA.reset() self._smaB.reset() self._smaC.reset() self._smaD.reset() self._smaSignal.reset() def update(self, v): self._rocA.update(v) self._rocB.update(v) self._rocC.update(v) self._rocD.update(v) if self._rocA.ready(): self._smaA.update(self._rocA.v()) if self._rocB.ready(): self._smaB.update(self._rocB.v()) if self._rocC.ready(): self._smaC.update(self._rocC.v()) if self._rocD.ready(): self._smaD.update(self._rocD.v()) if not self._smaA.ready() or not self._smaB.ready( ) or not self._smaC.ready() or not self._smaD.ready(): return kst = self._smaA.v() + (self._smaB.v() * 2) + (self._smaC.v() * 3) + ( self._smaD.v() * 4) self._smaSignal.update(kst) super().update({'v': kst, 'signal': self._smaSignal.v()}) return self.v() def add(self, v): self._rocA.add(v) self._rocB.add(v) self._rocC.add(v) self._rocD.add(v) if self._rocA.ready(): self._smaA.add(self._rocA.v()) if self._rocB.ready(): self._smaB.add(self._rocB.v()) if self._rocC.ready(): self._smaC.add(self._rocC.v()) if self._rocD.ready(): self._smaD.add(self._rocD.v()) if not self._smaA.ready() or not self._smaB.ready( ) or not self._smaC.ready() or not self._smaD.ready(): return kst = self._smaA.v() + (self._smaB.v() * 2) + (self._smaC.v() * 3) + ( self._smaD.v() * 4) self._smaSignal.add(kst) super().add({'v': kst, 'signal': self._smaSignal.v()}) return self.v()
class StochasticRSI(Indicator): def __init__(self, args=[]): [lengthRSI, lengthStochastic, smoothStoch, smoothSignal] = args self._buffer = [] self._l = lengthStochastic self._rsi = RSI([lengthRSI]) self._smaStoch = SMA([smoothStoch]) self._smaSignal = SMA([smoothSignal]) super().__init__({ 'args': args, 'id': 'stochrsi', 'name': 'Stoch RSI(%f, %f, %f, %f)' % (lengthRSI, lengthStochastic, smoothStoch, smoothSignal), 'seed_period': lengthRSI + lengthStochastic + smoothStoch }) def reset(self): super().reset() self._buffer = [] self._rsi.reset() self._smaStoch.reset() self._smaSignal.reset() def update(self, v): self._rsi.update(v) rsi = self._rsi.v() if not isfinite(rsi): return self.v() if len(self._buffer) == 0: self._buffer.append(rsi) else: self._buffer[-1] = rsi if len(self._buffer) < self._l: return self.v() low = min(self._buffer) high = max(self._buffer) stoch = 1 if high == low else ((rsi - low) / (high - low)) self._smaStoch.update(stoch * 100) smaStoch = self._smaStoch.v() if not isfinite(smaStoch): return self.v() self._smaSignal.update(smaStoch) smaSignal = self._smaSignal.v() if isfinite(smaSignal): super().update({'v': smaStoch, 'signal': smaSignal}) return self.v() def add(self, v): self._rsi.add(v) rsi = self._rsi.v() if not isfinite(rsi): return self.v() self._buffer.append(rsi) if len(self._buffer) > self._l: del self._buffer[0] elif len(self._buffer) < self._l: return self.v() low = min(self._buffer) high = max(self._buffer) stoch = 1 if high == low else ((rsi - low) / (high - low)) self._smaStoch.add(stoch * 100) smaStoch = self._smaStoch.v() if not isfinite(smaStoch): return self.v() self._smaSignal.add(smaStoch) smaSignal = self._smaSignal.v() if isfinite(smaSignal): super().add({'v': smaStoch, 'signal': smaSignal}) return self.v()
class EOM(Indicator): def __init__(self, divisor, length, cache_size=None): self._d = divisor self._sma = SMA(length, cache_size) self._lastCandle = None super().__init__({ 'args': [divisor, length, cache_size], 'id': 'eom', 'name': 'EOM(%f, %f)' % (divisor, length), 'seed_period': length, 'data_type': 'candle', 'data_key': '*', 'cache_size': cache_size }) def reset(self): super().reset() self._lastCandle = None self._sma.reset() def calcEOM(candle, lastCandle, divisor): high = candle['high'] low = candle['low'] vol = candle['vol'] lastHigh = lastCandle['high'] lastLow = lastCandle['low'] moved = ((high + low) / 2) - ((lastHigh + lastLow) / 2) if high == low: boxRatio = 1 else: boxRatio = (vol / divisor) / (high - low) return moved / boxRatio def update(self, candle): if self._lastCandle == None: return eom = EOM.calcEOM(candle, self._lastCandle, self._d) self._sma.update(eom) v = self._sma.v() if isfinite(v): super().update(v) return self.v() def add(self, candle): if self._lastCandle == None: self._lastCandle = candle return eom = EOM.calcEOM(candle, self._lastCandle, self._d) self._sma.add(eom) v = self._sma.v() if isfinite(v): super().add(v) self._lastCandle = candle return self.v()