class MovingAverages(): """ Calculates the Moving Averages for a coin pair """ def __init__(self): self.logger = structlog.get_logger() self.utils = Utils() def calculate_sma(self, period_count, historical_data): """ Returns the Simple Moving Average for a coin pair """ total_closing = sum(self.utils.get_closing_prices(historical_data)) return total_closing / period_count def calculate_ema(self, period_count, historical_data): """ Returns the Exponential Moving Average for a coin pair """ closing_prices = self.utils.get_closing_prices(historical_data) previous_ema = self.calculate_sma(period_count, historical_data) period_constant = 2 / (1 + period_count) current_ema = (closing_prices[-1] * period_constant) \ + (previous_ema * (1 - period_constant)) return current_ema
class MovingAverages(): """ Calculates the Moving Averages for a coin pair """ def __init__(self): self.logger = structlog.get_logger() self.utils = Utils() def get_sma_value(self, period_count, historical_data): """ Returns the Simple Moving Average for a coin pair """ total_closing = sum(self.utils.get_closing_prices(historical_data)) return total_closing / period_count def get_ema_value(self, period_count, historical_data): """ Returns the Exponential Moving Average for a coin pair """ closing_prices = self.utils.get_closing_prices(historical_data) previous_ema = self.get_sma_value(period_count, historical_data) period_constant = 2 / (1 + period_count) current_ema = (closing_prices[-1] * period_constant) \ + (previous_ema * (1 - period_constant)) return current_ema def is_sma_trending(self, sma_value, sma_threshold): return bool(sma_threshold and sma_value >= sma_threshold) def is_ema_trending(self, ema_value, ema_threshold): return bool(ema_threshold and ema_value >= ema_threshold)
class IchimokuCloud(): """ Runs the ichimoku strategy over the market data """ def __init__(self): self.logger = structlog.get_logger() self.utils = Utils() def get_base_line(self, historical_data): """ Calculates (26 period high + 26 period low) / 2 Also known as the "Kijun-sen" line """ closing_prices = self.utils.get_closing_prices(historical_data) period_high = max(closing_prices) period_low = min(closing_prices) return (period_high + period_low) / 2 def get_conversion_line(self, historical_data): """ Calculates (9 period high + 9 period low) / 2 Also known as the "Tenkan-sen" line """ closing_prices = self.utils.get_closing_prices(historical_data) period_high = max(closing_prices) period_low = min(closing_prices) return (period_high + period_low) / 2 def get_leading_span_a(self, base_line_data, conversion_line_data): """ Calculates (Conversion Line + Base Line) / 2 Also known as the "Senkou Span A" line """ base_line = self.get_base_line(base_line_data) conversion_line = self.get_conversion_line(conversion_line_data) return (base_line + conversion_line) / 2 def get_leading_span_b(self, historical_data): """ Calculates (52 period high + 52 period low) / 2 Also known as the "Senkou Span B" line """ closing_prices = self.utils.get_closing_prices(historical_data) period_high = max(closing_prices) period_low = min(closing_prices) return (period_high + period_low) / 2 def is_ichimoku_trending(self, ichimoku_threshold): return False
class IchimokuCloud(): """ Runs the ichimoku strategy over the market data """ def __init__(self): self.logger = structlog.get_logger() self.utils = Utils() def get_kijunsen(self, historical_data): """ Calculates (26 period high + 26 period low) / 2 Also known as the "Kijun-sen" line """ closing_prices = self.utils.get_closing_prices(historical_data) period_high = max(closing_prices) period_low = min(closing_prices) return (period_high + period_low) / 2 def get_tenkansen(self, historical_data): """ Calculates (9 period high + 9 period low) / 2 Also known as the "Tenkan-sen" line """ closing_prices = self.utils.get_closing_prices(historical_data) period_high = max(closing_prices) period_low = min(closing_prices) return (period_high + period_low) / 2 def get_senkou_span_a(self, kijunsen_data, tenkansen_data): """ Calculates (Conversion Line + Base Line) / 2 Also known as the "Senkou Span A" line """ kijunsen_line = self.get_kijunsen(kijunsen_data) tenkansen_line = self.get_tenkansen(tenkansen_data) return (kijunsen_line + tenkansen_line) / 2 def get_senkou_span_b(self, senkou_span_b_data): """ Calculates (52 period high + 52 period low) / 2 Also known as the "Senkou Span B" line """ closing_prices = self.utils.get_closing_prices(senkou_span_b_data) period_high = max(closing_prices) period_low = min(closing_prices) return (period_high + period_low) / 2
class RelativeStrengthIndex(): """ Runs the RSI strategy over the market data """ def __init__(self): self.logger = structlog.get_logger() self.utils = Utils() # Improvemnts to calculate_rsi are courtesy of community contributor "pcartwright81" def find_rsi(self, historical_data): """ Calculates the Relative Strength Index for a coin_pair If the returned value is above 70, it's overbought (SELL IT!) If the returned value is below 30, it's oversold (BUY IT!) """ closing_prices = self.utils.get_closing_prices(historical_data) count = 0 changes = [] # Calculating price changes for closing_price in closing_prices: if count != 0: changes.append(closing_price - closing_prices[count - 1]) count += 1 if count == 15: break # Calculating gains and losses advances = [] declines = [] for change in changes: if change > 0: advances.append(change) if change < 0: declines.append(abs(change)) average_gain = (sum(advances) / 14) average_loss = (sum(declines) / 14) new_average_gain = average_gain new_average_loss = average_loss for closing_price in closing_prices: if count > 14 and count < len(closing_prices): close = closing_prices[count] new_change = close - closing_prices[count - 1] add_loss = 0 add_gain = 0 if new_change > 0: add_gain = new_change if new_change < 0: add_loss = abs(new_change) new_average_gain = (new_average_gain * 13 + add_gain) / 14 new_average_loss = (new_average_loss * 13 + add_loss) / 14 count += 1 if new_average_loss > 0: rs = new_average_gain / new_average_loss else: rs = 0 new_rs = 100 - 100 / (1 + rs) return new_rs
class BollingerBands(object): """ Bollinger Bands """ def __init__(self): self.logger = structlog.get_logger() self.utils = Utils() self.sma = MovingAverages() ''' Retrieves the upper and lower bollinger bands for the given parameters: :param historical_data: A list of historical data points for a coin pair :param period: The period of the moving average to be used in bollinger calculation (defaults to 21) :param k: The number of standard deviations away from the 'period'-length moving average to place the upper and lower band (defaults to 2) :returns A 2-element tuple containing the upper and lower band, respectively. ''' def get_bollinger_bands(self, historical_data, period=21, k=2): sma = self.sma.calculate_sma(period, historical_data) closing_prices = self.utils.get_closing_prices(historical_data) std_dev = np.std(closing_prices[-period:]) return sma + k * std_dev, sma - k * std_dev
class MovingAvgConvDiv(): def __init__(self): self.logger = structlog.get_logger() self.utils = Utils() def get_12_day_EMA(self, frame): twelve_day_EMA = frame.ewm(span=12) return list(twelve_day_EMA.mean()["Prices"]) def get_26_day_EMA(self, frame): twenty_six_day_EMA = frame.ewm(span=26) return list(twenty_six_day_EMA.mean()["Prices"]) def calculate_MACD_line(self, historical_data): closing_prices = self.utils.get_closing_prices(historical_data) emadict = {"Prices": closing_prices} frame = pd.DataFrame(emadict) twelve_day_EMA = self.get_12_day_EMA(frame) twenty_six_day_EMA = self.get_26_day_EMA(frame) macd = [] for i in range(len(twelve_day_EMA)): macd.append(twelve_day_EMA[i] - twenty_six_day_EMA[i]) return macd def calculate_signal_line(self, macd): signaldata = [] for i in macd: signaldata.append(i) signal_dict = {"Prices": signaldata} signal = pd.DataFrame(signal_dict) signal = signal.ewm(span=9) signal = list(signal.mean()["Prices"]) return signal def calculate_MACD_delta(self, historical_data): MACD_line = self.calculate_MACD_line(historical_data) signal_line = self.calculate_signal_line(MACD_line) length = len(MACD_line) # Returns the difference between the last items in MACD and signal line return MACD_line[length - 1] - signal_line[length - 1]
def __init__(self): self.logger = structlog.get_logger() self.utils = Utils()
class RelativeStrengthIndex(): """ Runs the RSI strategy over the market data """ def __init__(self): self.logger = structlog.get_logger() self.utils = Utils() # Improvemnts to calculate_rsi are courtesy of community contributor "pcartwright81" def find_rsi(self, historical_data, period_count): """ Calculates the Relative Strength Index for a coin_pair RSI = 100 - ( 100 / ( 1 + RS ) ) RS = Average Gains / Average Losses Average Gains 1st avg gain = sum of gains over past n period_count / n Everything after = (Prev Avg Gain * (n-1) + current gain) / n Average Loss 1st avg loss = sum of losses over past n period / n Everything after = (Prev Avg Gain * (n-1) + current loss) / n Args: historical_data: Data used to find price changes used for RSI calc. period_count: period_count used tocalculate avg gains & avg losses. Returns: The RSI of market. """ closing_prices = self.utils.get_closing_prices(historical_data) advances = [] declines = [] # Sort initial price changes from [first, period) # IE Orders [1, 14) [1, 13] for order_index in range(1, period_count): # subtract new from old change = closing_prices[order_index] - closing_prices[order_index - 1] # sort advances.append(change) if change > 0 else declines.append( abs(change)) avg_gain = sum(advances) / period_count avg_loss = sum(declines) / period_count # Process orders period_count to end. # IE [14, length) [14, length-1] for order_index in range(period_count, len(closing_prices)): change = closing_prices[order_index] - closing_prices[order_index - 1] # sort gain = change if change > 0 else 0 loss = abs(change) if change < 0 else 0 # Smooth RSI avg_gain = (avg_gain * (period_count - 1) + gain) / period_count avg_loss = (avg_loss * (period_count - 1) + loss) / period_count if avg_loss > 0: rs = avg_gain / avg_loss else: # No losses, prevents ZeroDivision Exception rs = 100 rsi = 100 - (100 / (1 + rs)) return rsi def is_overbought(self, rsi_value, overbought_threshold): if overbought_threshold: if rsi_value >= overbought_threshold: return True return False def is_oversold(self, rsi_value, oversold_threshold): if oversold_threshold: if rsi_value <= oversold_threshold: return True return False
class RelativeStrengthIndex(): """ Runs the RSI strategy over the market data """ def __init__(self): self.logger = structlog.get_logger() self.utils = Utils() # Improvemnts to calculate_rsi are courtesy of community contributor "pcartwright81" def get_rsi_value(self, historical_data, period_count): """ Calculates the Relative Strength Index for a coin_pair RSI = 100 - ( 100 / ( 1 + RS ) ) RS = Average Gains / Average Losses Average Gains 1st avg gain = sum of gains over past n period_count / n Everything after = (Prev Avg Gain * (n-1) + current gain) / n Average Loss 1st avg loss = sum of losses over past n period / n Everything after = (Prev Avg Gain * (n-1) + current loss) / n Args: historical_data: Data used to find price changes used for RSI calc. period_count: period_count used tocalculate avg gains & avg losses. Returns: The RSI of market. """ closing_prices = self.utils.get_closing_prices(historical_data) if period_count > len(closing_prices): period_count = len(closing_prices) advances = [] declines = [] # Sort initial price changes from [first, period) # IE Orders [1, 14) [1, 13] for order_index in range(1, period_count): # subtract new from old change = closing_prices[order_index] - closing_prices[order_index - 1] # sort advances.append(change) if change > 0 else declines.append(abs(change)) avg_gain = sum(advances) / period_count avg_loss = sum(declines) / period_count # Process orders period_count to end. # IE [14, length) [14, length-1] for order_index in range(period_count, len(closing_prices)): change = closing_prices[order_index] - closing_prices[order_index - 1] # sort gain = change if change > 0 else 0 loss = abs(change) if change < 0 else 0 # Smooth RSI avg_gain = (avg_gain * (period_count - 1) + gain) / period_count avg_loss = (avg_loss * (period_count - 1) + loss) / period_count if avg_loss > 0: rs = avg_gain / avg_loss else: # No losses, prevents ZeroDivision Exception rs = 100 rsi = 100 - (100 / (1 + rs)) return rsi def is_overbought(self, rsi_value, overbought_threshold): return bool(overbought_threshold and rsi_value >= overbought_threshold) def is_oversold(self, rsi_value, oversold_threshold): return bool(oversold_threshold and rsi_value >= oversold_threshold)
def __init__(self): self.logger = structlog.get_logger() self.utils = Utils() self.sma = MovingAverages()
def __init__(self): """Initializes IchimokuCloud class """ self.logger = structlog.get_logger() self.utils = Utils()
class IchimokuCloud(): """Runs the ichimoku strategy over the market data """ def __init__(self): """Initializes IchimokuCloud class """ self.logger = structlog.get_logger() self.utils = Utils() def get_kijunsen(self, historical_data): """Calculates (26 period high + 26 period low) / 2. Also known as the "Kijun-sen" line Args: historical_data (list): A matrix of historical OHCLV data. Returns: float: The Kijun-sen line value of ichimoku. """ closing_prices = self.utils.get_closing_prices(historical_data) period_high = max(closing_prices) period_low = min(closing_prices) return (period_high + period_low) / 2 def get_tenkansen(self, historical_data): """Calculates (9 period high + 9 period low) / 2. Also known as the "Tenkan-sen" line Args: historical_data (list): A matrix of historical OHCLV data. Returns: float: The Tenkan-sen line value of ichimoku. """ closing_prices = self.utils.get_closing_prices(historical_data) period_high = max(closing_prices) period_low = min(closing_prices) return (period_high + period_low) / 2 def get_senkou_span_a(self, kijunsen_data, tenkansen_data): """Calculates (Conversion Line + Base Line) / 2. Also known as the "Senkou Span A" line Args: kijunsen_data (float): The Kijun-sen line value of ichimoku. tenkansen_data (float): The Tenkan-sen line value of ichimoku. Returns: float: The Senkou span A value of ichimoku. """ kijunsen_line = self.get_kijunsen(kijunsen_data) tenkansen_line = self.get_tenkansen(tenkansen_data) return (kijunsen_line + tenkansen_line) / 2 def get_senkou_span_b(self, historical_data): """Calculates (52 period high + 52 period low) / 2. Also known as the "Senkou Span B" line Args: historical_data (list): A matrix of historical OHCLV data. Returns: float: The Senkou span B value of ichimoku. """ closing_prices = self.utils.get_closing_prices(historical_data) period_high = max(closing_prices) period_low = min(closing_prices) return (period_high + period_low) / 2
def __init__(self): self.utils = Utils()