class PCorrelIndicator: def __init__(self, capacity, period): self.values = ObjectPool(capacity, lambda: PCorrelIndicatorItem()) self.period = period self.correlation = ObjectPool(period, lambda: PCorrelPriceItem()) self.is_indicator_primed = False self.is_primed = False def calculate(self, x_var, y_var): xy = x_var * y_var x_squared = x_var**2 y_squared = y_var**2 self.correlation.update( lambda item: item.update(x_var, y_var, xy, x_squared, y_squared)) if (not self.is_indicator_primed): self.is_indicator_primed = self.correlation.length >= self.period if (self.is_indicator_primed): items = list( self.correlation.read_back(self.period, lambda item: item)) sum_of_x = sum(map(lambda item: item.x_var, items)) sum_of_y = sum(map(lambda item: item.y_var, items)) sum_of_xy = sum(map(lambda item: item.xy, items)) sum_of_x_squared = sum(map(lambda item: item.x_squared, items)) sum_of_y_squared = sum(map(lambda item: item.y_squared, items)) r_dividend = (self.period * sum_of_xy) - (sum_of_x * sum_of_y) r_divisor_base = ((self.period * sum_of_x_squared) - (sum_of_x**2)) * ( (self.period * sum_of_y_squared) - (sum_of_y**2)) coefficient = 0 if self.is_primed: coefficient = self.values.current.coefficient else: self.is_primed = self.values.has_current if r_divisor_base > 0: r_divisor = math.sqrt(r_divisor_base) coefficient = r_dividend / r_divisor self.values.update(lambda item: item.update(coefficient)) return self.values.current.as_dictionary() return None
class AtrIndicator: def __init__(self, capacity, period): self.values = ObjectPool(capacity, lambda: AtrIndicatorItem()) self.period = period self.previous_high = float('NaN') self.previous_low = float('NaN') self.previous_close = float('NaN') self.current_high = float('NaN') self.current_low = float('NaN') self.current_close = float('NaN') self.tr = ObjectPool(period, lambda: TrItem()) self.is_primed = False self.is_tr_primed = False self.is_initialized = False def calculate(self, high, low, close): if (self.is_initialized): self.previous_high = self.current_high self.previous_low = self.current_low self.previous_close = self.current_close self.current_high = high self.current_low = low self.current_close = close true_range = max(self.current_high - self.current_low, abs(self.current_high - self.previous_close), abs(self.current_low - self.previous_close)) self.tr.update(lambda item: item.update(true_range)) if (not self.is_tr_primed): self.is_tr_primed = self.tr.length >= self.period if (self.is_tr_primed): atr = sum( self.tr.read_back( self.period, lambda item: item.true_range)) / self.period self.values.update(lambda item: item.update(atr)) return self.values.current.as_dictionary() else: self.current_high = high self.current_low = low self.current_close = close self.is_initialized = True return None
class RsiIndicator: def __init__(self, capacity, period): self.values = ObjectPool(capacity, lambda: RsiIndicatorItem()) self.period = period self.price_change = ObjectPool(period, lambda: RsiChangeItem()) self.previous_price = float('NaN') self.current_price = float('NaN') self.is_initialized = False self.is_price_change_primed = False def calculate(self, price): if (self.is_initialized): self.previous_price = self.current_price self.current_price = price change = self.current_price - self.previous_price gain = change if change > 0 else 0 loss = -change if change < 0 else 0 self.price_change.update(lambda item: item.update(change, gain, loss)) if (not self.is_price_change_primed): self.is_price_change_primed = self.price_change.length >= self.period if (self.is_price_change_primed): items = list(self.price_change.read_back(self.period, lambda item: item)) average_gain = sum(map(lambda item: item.gain, items)) / self.period average_loss = sum(map(lambda item: item.loss, items)) / self.period rs = 0 if average_loss == 0 else average_gain / average_loss rsi = 100 if average_loss == 0 else 100 - (100 / (1 + rs)) self.values.update(lambda item: item.update(average_gain, average_loss, rs, rsi)) return self.values.current.as_dictionary() else: self.current_price = price self.is_initialized = True return None
class AdxIndicator: def __init__(self, capacity, period): self.values = ObjectPool(capacity, lambda: AdxIndicatorItem()) self.period = period self.previous_high = float('NaN') self.previous_low = float('NaN') self.previous_close = float('NaN') self.current_high = float('NaN') self.current_low = float('NaN') self.current_close = float('NaN') self.dm = ObjectPool(period, lambda: AdxDmItem()) self.periodic_dm = ObjectPool(period, lambda: AdxPeriodicDmItem()) self.is_primed = False self.is_dm_primed = False self.is_periodic_dm_initialized = False self.is_periodic_dm_primed = False self.is_initialized = False self.are_values_initialized = False def calculate(self, high, low, close): if (self.is_initialized): self.previous_high = self.current_high self.previous_low = self.current_low self.previous_close = self.current_close self.current_high = high self.current_low = low self.current_close = close #calculate Directional Movement true_range = max(self.current_high - self.current_low, abs(self.current_high - self.previous_close), abs(self.current_low - self.previous_close)) plus_high_diff = self.current_high - self.previous_high plus_low_diff = self.previous_low - self.current_low plus_dm = max(plus_high_diff, 0) if plus_high_diff > plus_low_diff else 0 minus_low_diff = self.previous_low - self.current_low minus_high_diff = self.current_high - self.previous_high minus_dm = max(minus_low_diff, 0) if minus_low_diff > minus_high_diff else 0 self.dm.update( lambda item: item.update(true_range, plus_dm, minus_dm)) if (not self.is_dm_primed): self.is_dm_primed = self.dm.length >= self.period if (self.is_dm_primed): periodic_true_range = float('NaN') periodic_plus_dm = float('NaN') periodic_minus_dm = float('NaN') if (self.is_periodic_dm_initialized): periodic_true_range = self.periodic_dm.current.periodic_true_range - ( self.periodic_dm.current.periodic_true_range / self.period) + self.dm.current.true_range periodic_plus_dm = self.periodic_dm.current.periodic_plus_dm - ( self.periodic_dm.current.periodic_plus_dm / self.period) + self.dm.current.plus_dm periodic_minus_dm = self.periodic_dm.current.periodic_minus_dm - ( self.periodic_dm.current.periodic_minus_dm / self.period) + self.dm.current.minus_dm else: items = list( self.dm.read_back(self.period, lambda item: item)) periodic_true_range = sum( map(lambda item: item.true_range, items)) periodic_plus_dm = sum( map(lambda item: item.plus_dm, items)) periodic_minus_dm = sum( map(lambda item: item.minus_dm, items)) self.is_periodic_dm_initialized = True periodic_plus_di = 100 * (periodic_plus_dm / periodic_true_range) periodic_minus_di = 100 * (periodic_minus_dm / periodic_true_range) di_diff = abs(periodic_plus_di - periodic_minus_di) di_sum = periodic_plus_di + periodic_minus_di dx = 0 if di_sum == 0 else 100 * (di_diff / di_sum) self.periodic_dm.update(lambda item: item.update( periodic_true_range, periodic_plus_dm, periodic_minus_dm, periodic_plus_di, periodic_minus_di, di_diff, di_sum, dx)) if (not self.is_periodic_dm_primed): self.is_periodic_dm_primed = self.periodic_dm.length >= self.period if (self.is_periodic_dm_primed): adx = float('NaN') if (self.are_values_initialized): adx = ((self.values.current.adx * (self.period - 1)) + self.periodic_dm.current.dx) / self.period else: adx = sum( map( lambda item: item.dx, self.periodic_dm.read_back( self.period, lambda item: item))) / self.period self.are_values_initialized = True self.values.update(lambda item: item.update( self.periodic_dm.current.periodic_plus_di, self. periodic_dm.current.periodic_minus_di, adx)) return self.values.current.as_dictionary() else: self.current_high = high self.current_low = low self.current_close = close self.is_initialized = True return None