diff --git a/.github/workflows/pylint.yml b/.github/workflows/pylint.yml deleted file mode 100644 index 4fb5f0e..0000000 --- a/.github/workflows/pylint.yml +++ /dev/null @@ -1,25 +0,0 @@ -name: Pylint - -on: - pull_request: - branches: [develop] - -jobs: - build: - runs-on: ubuntu-latest - strategy: - matrix: - python-version: ["3.8", "3.9", "3.10"] - steps: - - uses: actions/checkout@v3 - - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v3 - with: - python-version: ${{ matrix.python-version }} - - name: Install dependencies - run: | - python -m pip install --upgrade pip - pip install pylint - - name: Analysing the code with pylint - run: | - pylint $(git ls-files '*.py') diff --git a/app/analyzers/crossover.py b/app/analyzers/crossover.py index 477282e..16471f2 100644 --- a/app/analyzers/crossover.py +++ b/app/analyzers/crossover.py @@ -31,15 +31,24 @@ def analyze(self, key_indicator, key_signal, key_indicator_index, new_key_indicator = key_indicator.copy(deep=True) for column in new_key_indicator: column_indexed_name = '{}_{}'.format(column, key_indicator_index) - new_key_indicator.rename(columns={column: column_indexed_name}, inplace=True) + new_key_indicator.rename( + columns={ + column: column_indexed_name}, + inplace=True) - crossed_indicator_name = '{}_{}'.format(crossed_signal, crossed_indicator_index) + crossed_indicator_name = '{}_{}'.format( + crossed_signal, crossed_indicator_index) new_crossed_indicator = crossed_indicator.copy(deep=True) for column in new_crossed_indicator: - column_indexed_name = '{}_{}'.format(column, crossed_indicator_index) - new_crossed_indicator.rename(columns={column: column_indexed_name}, inplace=True) - - combined_data = pandas.concat([new_key_indicator, new_crossed_indicator], axis=1) + column_indexed_name = '{}_{}'.format( + column, crossed_indicator_index) + new_crossed_indicator.rename( + columns={ + column: column_indexed_name}, + inplace=True) + + combined_data = pandas.concat( + [new_key_indicator, new_crossed_indicator], axis=1) combined_data.dropna(how='any', inplace=True) combined_data['is_hot'] = combined_data[key_indicator_name] > combined_data[crossed_indicator_name] diff --git a/app/analyzers/indicators/adx.py b/app/analyzers/indicators/adx.py index a266d8d..0895a9b 100644 --- a/app/analyzers/indicators/adx.py +++ b/app/analyzers/indicators/adx.py @@ -10,7 +10,8 @@ class Adx(IndicatorUtils): - def analyze(self, historical_data, signal=["adx"], period_count=14, hot_thresh=None, cold_thresh=None): + def analyze(self, historical_data, signal=[ + "adx"], period_count=14, hot_thresh=None, cold_thresh=None): """ strength of a trend ADX > 25 = strength @@ -114,8 +115,8 @@ def DM(self, high, low, pdm, ndm): """ for index in range(1, high.shape[0]): - up_move = high[index] - high[index-1] - down_move = low[index-1] - low[index] + up_move = high[index] - high[index - 1] + down_move = low[index - 1] - low[index] if up_move > down_move and up_move > 0: pdm[index] = up_move @@ -139,13 +140,13 @@ def DMsmooth(self, pdm, ndm, pdm_smooth, ndm_smooth, period_count): :return: pdm_smooth, ndm_smooth """ - pdm_smooth[period_count-1] = pdm[0:period_count].sum() / period_count + pdm_smooth[period_count - 1] = pdm[0:period_count].sum() / period_count ndm_smooth[period_count - 1] = ndm[0:period_count].sum() / period_count for index in range(period_count, pdm.shape[0]): pdm_smooth[index] = ( - pdm[index-1] - (pdm_smooth[index-1]/period_count)) + pdm_smooth[index-1] + pdm[index - 1] - (pdm_smooth[index - 1] / period_count)) + pdm_smooth[index - 1] ndm_smooth[index] = ( - ndm[index - 1] - (ndm_smooth[index-1] / period_count)) + ndm_smooth[index-1] + ndm[index - 1] - (ndm_smooth[index - 1] / period_count)) + ndm_smooth[index - 1] return pdm_smooth, ndm_smooth @@ -178,9 +179,9 @@ def ATR(self, tr, atr, period_count): :return: atr """ - atr[period_count-1] = tr[0:period_count].sum() / period_count + atr[period_count - 1] = tr[0:period_count].sum() / period_count for index in range(period_count, tr.shape[0]): - atr[index] = ((atr[index-1] * (period_count - 1)) + + atr[index] = ((atr[index - 1] * (period_count - 1)) + tr[index]) / period_count return atr @@ -200,11 +201,11 @@ def ADX(self, pdi, ndi, dx, adx, period_count): dx[index] = ((abs(pdi[index] - ndi[index])) / (abs(pdi[index] + ndi[index]))) * 100 - period_count2 = period_count*2 - adx[period_count2-1] = dx[period_count:period_count2].sum() / \ + period_count2 = period_count * 2 + adx[period_count2 - 1] = dx[period_count:period_count2].sum() / \ period_count for index in range(period_count2, dx.shape[0]): - adx[index] = ((adx[index-1] * (period_count - 1)) + + adx[index] = ((adx[index - 1] * (period_count - 1)) + dx[index]) / period_count return dx, adx diff --git a/app/analyzers/indicators/aroon_oscillator.py b/app/analyzers/indicators/aroon_oscillator.py index 9b17328..ca2e65f 100644 --- a/app/analyzers/indicators/aroon_oscillator.py +++ b/app/analyzers/indicators/aroon_oscillator.py @@ -10,7 +10,8 @@ class Aroon_oscillator(IndicatorUtils): - def analyze(self, historical_data, sma_vol_period, period_count=25, signal=["aroon"], hot_thresh=None, cold_thresh=None): + def analyze(self, historical_data, sma_vol_period, period_count=25, + signal=["aroon"], hot_thresh=None, cold_thresh=None): """Performs an aroon oscillator analysis on the historical data Args: @@ -39,18 +40,18 @@ def analyze(self, historical_data, sma_vol_period, period_count=25, signal=["aro index=dataframe.index ) - for index in range(0, dataframe.shape[0]-24): - id = dataframe.shape[0]-index + for index in range(0, dataframe.shape[0] - 24): + id = dataframe.shape[0] - index id_period = id - period_count high_date = dataframe['high'].iloc[id_period:id].idxmax() low_date = dataframe['low'].iloc[id_period:id].idxmin() periods_since_high = id - dataframe.index.get_loc(high_date) - 1 periods_since_low = id - dataframe.index.get_loc(low_date) - 1 - aroon_values['aroon_up'][id-1] = 100 * \ + aroon_values['aroon_up'][id - 1] = 100 * \ ((25 - periods_since_high) / 25) - aroon_values['aroon_down'][id-1] = 100 * \ + aroon_values['aroon_down'][id - 1] = 100 * \ ((25 - periods_since_low) / 25) aroon_values['aroon'] = aroon_values['aroon_up'] - \ diff --git a/app/analyzers/indicators/bbp.py b/app/analyzers/indicators/bbp.py index c6feb37..9a41c55 100644 --- a/app/analyzers/indicators/bbp.py +++ b/app/analyzers/indicators/bbp.py @@ -1,5 +1,5 @@ -""" +""" Bollinger Bands indicator """ @@ -13,7 +13,8 @@ class BBP(IndicatorUtils): - def analyze(self, historical_data, signal=['bbp'], hot_thresh=0, cold_thresh=0.8, period_count=20, std_dev=2): + def analyze(self, historical_data, signal=[ + 'bbp'], hot_thresh=0, cold_thresh=0.8, period_count=20, std_dev=2): """Check when close price cross the Upper/Lower bands. Args: @@ -23,7 +24,7 @@ def analyze(self, historical_data, signal=['bbp'], hot_thresh=0, cold_thresh=0.8 hot_thresh (float, optional): Defaults to 0. The threshold at which this might be good to purchase. cold_thresh (float, optional): Defaults to 0.8. The threshold at which this might be - good to sell. + good to sell. std_dev (int, optional): number of std dev to use. Common values are 2 or 1 Returns: diff --git a/app/analyzers/indicators/bollinger.py b/app/analyzers/indicators/bollinger.py index f118412..4a81492 100644 --- a/app/analyzers/indicators/bollinger.py +++ b/app/analyzers/indicators/bollinger.py @@ -1,5 +1,5 @@ -""" +""" Bollinger Bands indicator """ @@ -13,7 +13,8 @@ class Bollinger(IndicatorUtils): - def analyze(self, historical_data, signal=['close'], hot_thresh=None, cold_thresh=None, period_count=20, std_dev=2): + def analyze(self, historical_data, signal=[ + 'close'], hot_thresh=None, cold_thresh=None, period_count=20, std_dev=2): """Check when close price cross the Upper/Lower bands. Args: diff --git a/app/analyzers/indicators/candle_recognition.py b/app/analyzers/indicators/candle_recognition.py index ff88074..e7e6ef7 100644 --- a/app/analyzers/indicators/candle_recognition.py +++ b/app/analyzers/indicators/candle_recognition.py @@ -7,7 +7,8 @@ class Candle_recognition(IndicatorUtils): - def analyze(self, historical_data, signal, notification='hot', candle_check=1, hot_thresh=None, cold_thresh=None): + def analyze(self, historical_data, signal, notification='hot', + candle_check=1, hot_thresh=None, cold_thresh=None): """Performs an candle pattern analysis on the historical data Args: diff --git a/app/analyzers/indicators/ichimoku.py b/app/analyzers/indicators/ichimoku.py index 2ad1e46..54cb14d 100644 --- a/app/analyzers/indicators/ichimoku.py +++ b/app/analyzers/indicators/ichimoku.py @@ -28,8 +28,8 @@ def analyze(self, historical_data, tenkansen_period, kijunsen_period, senkou_spa tenkansen_period (int, optional) kijunsen_period (int, optional) senkou_span_b_period (int, optional) - custom_strategy (string, optional): Defaults to None. Name of the custom strategy. The file name and class name - should have the same name as the custom strategy. + custom_strategy (string, optional): Defaults to None. Name of the custom strategy. The file name and class name + should have the same name as the custom strategy. Returns: pandas.DataFrame: A dataframe containing the indicators and hot/cold values. @@ -42,7 +42,7 @@ def analyze(self, historical_data, tenkansen_period, kijunsen_period, senkou_spa 'kijunsen': [numpy.nan] * dataframe.index.shape[0], 'leading_span_a': [numpy.nan] * dataframe.index.shape[0], 'leading_span_b': [numpy.nan] * dataframe.index.shape[0], - 'chikou_span' : [numpy.nan] * dataframe.index.shape[0] + 'chikou_span': [numpy.nan] * dataframe.index.shape[0] } ichimoku_values = pandas.DataFrame(ichimoku_columns, @@ -60,7 +60,8 @@ def analyze(self, historical_data, tenkansen_period, kijunsen_period, senkou_spa window=senkou_span_b_period).max() chikou_span_delay = 26 - ichimoku_values['chikou_span'] = dataframe['close'].shift(-chikou_span_delay) + ichimoku_values['chikou_span'] = dataframe['close'].shift( + -chikou_span_delay) ichimoku_values['tenkansen'] = (low_tenkansen + high_tenkansen) / 2 ichimoku_values['kijunsen'] = (low_kijunsen + high_kijunsen) / 2 ichimoku_values['leading_span_a'] = ( @@ -79,21 +80,23 @@ def analyze(self, historical_data, tenkansen_period, kijunsen_period, senkou_spa newindex = pandas.date_range(last_time + timedelta, freq=timedelta, periods=cloud_displacement) - ichimoku_values = pd.concat([ichimoku_values, pandas.DataFrame(index=newindex)]) + ichimoku_values = pd.concat( + [ichimoku_values, pandas.DataFrame(index=newindex)]) # cloud offset ichimoku_values['leading_span_a'] = ichimoku_values['leading_span_a'].shift( cloud_displacement) ichimoku_values['leading_span_b'] = ichimoku_values['leading_span_b'].shift( cloud_displacement) - - if chart == None: - if custom_strategy == None: + + if chart is None: + if custom_strategy is None: leading_span_hot = False leading_span_cold = False tk_cross_hot = False tk_cross_cold = False tk_cross_enabled = (('tenkansen' and 'kijunsen') in signal) - leading_span_enabled = (('leading_span_a' and 'leading_span_b') in signal) + leading_span_enabled = ( + ('leading_span_a' and 'leading_span_b') in signal) date = dataframe.index[-1] leading_span_date = ichimoku_values.index[-1] @@ -102,19 +105,25 @@ def analyze(self, historical_data, tenkansen_period, kijunsen_period, senkou_spa tk_cross_cold = ichimoku_values['tenkansen'][date] < ichimoku_values['kijunsen'][date] if leading_span_enabled: - leading_span_hot = ichimoku_values['leading_span_a'][leading_span_date] > ichimoku_values['leading_span_b'][leading_span_date] - leading_span_cold = ichimoku_values['leading_span_a'][leading_span_date] < ichimoku_values['leading_span_b'][leading_span_date] + leading_span_hot = ichimoku_values['leading_span_a'][ + leading_span_date] > ichimoku_values['leading_span_b'][leading_span_date] + leading_span_cold = ichimoku_values['leading_span_a'][ + leading_span_date] < ichimoku_values['leading_span_b'][leading_span_date] if hot_thresh: - ichimoku_values.at[date, 'is_hot'] = tk_cross_hot or leading_span_hot + ichimoku_values.at[date, + 'is_hot'] = tk_cross_hot or leading_span_hot if cold_thresh: - ichimoku_values.at[date, 'is_cold'] = tk_cross_cold or leading_span_cold + ichimoku_values.at[date, + 'is_cold'] = tk_cross_cold or leading_span_cold else: - module = import_module("user_data.strategies." + custom_strategy) - attr = getattr(module, custom_strategy) + module = import_module( + "user_data.strategies." + custom_strategy) + attr = getattr(module, custom_strategy) - custom_hot, custom_cold = attr.analyze(ichimoku_values, dataframe) + custom_hot, custom_cold = attr.analyze( + ichimoku_values, dataframe) date = dataframe.index[-1] if hot_thresh: @@ -123,11 +132,14 @@ def analyze(self, historical_data, tenkansen_period, kijunsen_period, senkou_spa if cold_thresh: ichimoku_values.at[date, 'is_cold'] = custom_cold - # Undo shifting in order to have the values aligned for displaying + # Undo shifting in order to have the values aligned for + # displaying ichimoku_values['chikou_span'] = dataframe['close'] - ichimoku_values['leading_span_a'] = ichimoku_values['leading_span_a'].shift(-cloud_displacement) - ichimoku_values['leading_span_b'] = ichimoku_values['leading_span_b'].shift(-cloud_displacement) - + ichimoku_values['leading_span_a'] = ichimoku_values['leading_span_a'].shift( + -cloud_displacement) + ichimoku_values['leading_span_b'] = ichimoku_values['leading_span_b'].shift( + -cloud_displacement) + ichimoku_values.dropna(how='any', inplace=True) except Exception as e: diff --git a/app/analyzers/indicators/iiv.py b/app/analyzers/indicators/iiv.py index a606f64..893afe6 100644 --- a/app/analyzers/indicators/iiv.py +++ b/app/analyzers/indicators/iiv.py @@ -8,13 +8,14 @@ class IIV(IndicatorUtils): - def analyze(self, historical_data, signal=['iiv'], hot_thresh=10, cold_thresh=0): + def analyze(self, historical_data, signal=[ + 'iiv'], hot_thresh=10, cold_thresh=0): """Performs an analysis about the increase in volumen on the historical data Args: historical_data (list): A matrix of historical OHCLV data. signal (list, optional): Defaults to iiv. The indicator line to check hot against. - hot_thresh (float, optional): Defaults to 10. + hot_thresh (float, optional): Defaults to 10. cold_thresh: Unused diff --git a/app/analyzers/indicators/klinger_oscillator.py b/app/analyzers/indicators/klinger_oscillator.py index 2d32886..b0f69d1 100644 --- a/app/analyzers/indicators/klinger_oscillator.py +++ b/app/analyzers/indicators/klinger_oscillator.py @@ -17,7 +17,8 @@ class Klinger_oscillator(IndicatorUtils): - def analyze(self, historical_data, ema_short_period, ema_long_period, signal_period, signal=['kvo, kvo_signal'], hot_thresh=None, cold_thresh=None): + def analyze(self, historical_data, ema_short_period, ema_long_period, + signal_period, signal=['kvo, kvo_signal'], hot_thresh=None, cold_thresh=None): """Performs a Klinger Oscillator analysis on the historical data Args: @@ -42,19 +43,19 @@ def analyze(self, historical_data, ema_short_period, ema_long_period, signal_per Temp = 2*((dm/cm)-1) if (high+low+close)/3 > (high_1+low_1+close_1)/3 - Trend = +1 + Trend = +1 if < or = - Trend = -1 + Trend = -1 dm = high - low ----- CM[today] = / CM[yesterday] + DM[today] IF trend[today]==trend[yesterday] - \ DM[yesterday] + DM[today] IF trend[today]!=trend[yesterday] + \\ DM[yesterday] + DM[today] IF trend[today]!=trend[yesterday] if Trend = Trend_1 - cm = cm_1 + dm + cm = cm_1 + dm if Trend =/= Trend_1 - cm = dm_1 + dm + cm = dm_1 + dm ----- EMA = (c*A)+(E*B) C = current period's VF @@ -96,23 +97,23 @@ def analyze(self, historical_data, ema_short_period, ema_long_period, signal_per for index in range(1, (klinger_values.shape[0])): klinger_values['dm'] = dataframe['high'][index] - \ dataframe['low'][index] - if klinger_values['mean'][index] > klinger_values['mean'][index-1]: + if klinger_values['mean'][index] > klinger_values['mean'][index - 1]: klinger_values['trend'][index] = 1 else: klinger_values['trend'][index] = -1 for index in range(0, (klinger_values.shape[0])): klinger_values['cm_a'] = klinger_values['dm'][index] + \ - klinger_values['dm'][index-1] - if klinger_values['trend'][index] == klinger_values['trend'][index-1]: + klinger_values['dm'][index - 1] + if klinger_values['trend'][index] == klinger_values['trend'][index - 1]: klinger_values['cm'][index] = klinger_values['cm'][index - 1] + klinger_values['dm'][index] else: klinger_values['cm'][index] = klinger_values['dm'][index] + \ - klinger_values['dm'][index-1] + klinger_values['dm'][index - 1] klinger_values['vf'] = dataframe['volume'] * abs( - 2*((klinger_values['dm']/klinger_values['cm'])-1)) * klinger_values['trend'] * 100 + 2 * ((klinger_values['dm'] / klinger_values['cm']) - 1)) * klinger_values['trend'] * 100 klinger_values['vf_ema_short'] = klinger_values['vf'].ewm( span=ema_short_period, min_periods=0, adjust=False, ignore_na=True).mean() klinger_values['vf_ema_long'] = klinger_values['vf'].ewm( @@ -126,10 +127,11 @@ def analyze(self, historical_data, ema_short_period, ema_long_period, signal_per klinger_values['is_cold'] = False for index in range(1, klinger_values.shape[0]): - ## might want to change mean index-1 to longer period and not just last candle ## - if klinger_values['kvo_signal'][index] > 0 and klinger_values['mean'][index] > klinger_values['mean'][index-1]: + # might want to change mean index-1 to longer period and not just + # last candle ## + if klinger_values['kvo_signal'][index] > 0 and klinger_values['mean'][index] > klinger_values['mean'][index - 1]: klinger_values['is_hot'][index] = True - elif klinger_values['kvo_signal'][index] <= 0 and klinger_values['mean'][index] < klinger_values['mean'][index-1]: + elif klinger_values['kvo_signal'][index] <= 0 and klinger_values['mean'][index] < klinger_values['mean'][index - 1]: klinger_values['is_cold'][index] return klinger_values diff --git a/app/analyzers/indicators/ma_crossover.py b/app/analyzers/indicators/ma_crossover.py index 81ed401..fc3cf97 100644 --- a/app/analyzers/indicators/ma_crossover.py +++ b/app/analyzers/indicators/ma_crossover.py @@ -11,7 +11,8 @@ class MACrossover(IndicatorUtils): - def analyze(self, historical_data, signal=['close'], hot_thresh=None, cold_thresh=None, exponential=True, ma_fast=10, ma_slow=50): + def analyze(self, historical_data, signal=[ + 'close'], hot_thresh=None, cold_thresh=None, exponential=True, ma_fast=10, ma_slow=50): """Performs an analysis about a crossover in 2 moving averages Args: @@ -45,7 +46,9 @@ def analyze(self, historical_data, signal=['close'], hot_thresh=None, cold_thres ma_crossover['is_hot'] = False ma_crossover['is_cold'] = False - ma_crossover.at[ma_crossover.index[-1], 'is_hot'] = previous_fast < previous_slow and current_fast > current_slow - ma_crossover.at[ma_crossover.index[-1], 'is_cold'] = previous_fast > previous_slow and current_fast < current_slow + ma_crossover.at[ma_crossover.index[-1], + 'is_hot'] = previous_fast < previous_slow and current_fast > current_slow + ma_crossover.at[ma_crossover.index[-1], + 'is_cold'] = previous_fast > previous_slow and current_fast < current_slow return ma_crossover diff --git a/app/analyzers/indicators/ma_ribbon.py b/app/analyzers/indicators/ma_ribbon.py index adbf293..387d410 100644 --- a/app/analyzers/indicators/ma_ribbon.py +++ b/app/analyzers/indicators/ma_ribbon.py @@ -13,7 +13,8 @@ class MARibbon(IndicatorUtils): # Exponential Moving Average def EMA(self, df, n, field='close'): - return pandas.Series(talib.EMA(df[field].astype('f8').values, n), name='EMA_' + field.upper() + '_' + str(n), index=df.index) + return pandas.Series(talib.EMA(df[field].astype( + 'f8').values, n), name='EMA_' + field.upper() + '_' + str(n), index=df.index) def MA_RIBBON(self, df, ma_series): ma_array = np.zeros([len(df), len(ma_series)]) @@ -36,13 +37,14 @@ def MA_RIBBON(self, df, ma_series): ma_array[idy, :], range(len(ma_series), 0, -1)) dist[idy] = max(ma_array[idy, :]) - min(ma_array[idy, :]) - corr_ts = pandas.Series(corr*100, index=df.index, + corr_ts = pandas.Series(corr * 100, index=df.index, name="MARIBBON_CORR").round(2) - pval_ts = pandas.Series(pval*100, index=df.index, + pval_ts = pandas.Series(pval * 100, index=df.index, name="MARIBBON_PVAL").round(2) dist_ts = pandas.Series(dist, index=df.index, name="MARIBBON_DIST") - return pandas.concat([corr_ts, pval_ts, dist_ts] + ema_list, join='outer', axis=1) + return pandas.concat([corr_ts, pval_ts, dist_ts] + + ema_list, join='outer', axis=1) def analyze(self, historical_data, pval_th, ma_series, signal=['ma_ribbon'], hot_thresh=10, cold_thresh=-10): @@ -54,7 +56,7 @@ def analyze(self, historical_data, pval_th, ma_series, signal=['ma_ribbon'], pval_th (integer): hot_thresh (integer): cold_thresh (integer): - ma_series (list): + ma_series (list): Returns: pandas.DataFrame: A dataframe containing the indicator and hot/cold values. diff --git a/app/analyzers/indicators/macd.py b/app/analyzers/indicators/macd.py index 9336a08..ae07c21 100644 --- a/app/analyzers/indicators/macd.py +++ b/app/analyzers/indicators/macd.py @@ -10,7 +10,8 @@ class MACD(IndicatorUtils): - def analyze(self, historical_data, signal=['macd'], hot_thresh=None, cold_thresh=None): + def analyze(self, historical_data, signal=[ + 'macd'], hot_thresh=None, cold_thresh=None): """Performs a macd analysis on the historical data Args: diff --git a/app/analyzers/indicators/macd_cross.py b/app/analyzers/indicators/macd_cross.py index b4f40e3..e2d3e1c 100644 --- a/app/analyzers/indicators/macd_cross.py +++ b/app/analyzers/indicators/macd_cross.py @@ -11,7 +11,8 @@ class MACDCross(IndicatorUtils): - def analyze(self, historical_data, signal=['macd'], hot_thresh=None, cold_thresh=None): + def analyze(self, historical_data, signal=[ + 'macd'], hot_thresh=None, cold_thresh=None): """Performs a macd analysis on the historical data Args: @@ -41,7 +42,9 @@ def analyze(self, historical_data, signal=['macd'], hot_thresh=None, cold_thresh macd_cross['is_hot'] = False macd_cross['is_cold'] = False - macd_cross.at[macd_cross.index[-1], 'is_hot'] = previous_macd < previous_signal and current_macd > current_signal - macd_cross.at[macd_cross.index[-1], 'is_cold'] = previous_macd > previous_signal and current_macd < current_signal + macd_cross.at[macd_cross.index[-1], + 'is_hot'] = previous_macd < previous_signal and current_macd > current_signal + macd_cross.at[macd_cross.index[-1], + 'is_cold'] = previous_macd > previous_signal and current_macd < current_signal return macd_cross diff --git a/app/analyzers/indicators/obv.py b/app/analyzers/indicators/obv.py index b6f52a5..f8573bd 100644 --- a/app/analyzers/indicators/obv.py +++ b/app/analyzers/indicators/obv.py @@ -10,7 +10,8 @@ class OBV(IndicatorUtils): - def analyze(self, historical_data, signal=["obv"], hot_thresh=None, cold_thresh=None): + def analyze(self, historical_data, signal=[ + "obv"], hot_thresh=None, cold_thresh=None): """Performs OBV analysis on the historical data Args: diff --git a/app/analyzers/indicators/rsi.py b/app/analyzers/indicators/rsi.py index 1ec1256..cc47650 100644 --- a/app/analyzers/indicators/rsi.py +++ b/app/analyzers/indicators/rsi.py @@ -12,7 +12,7 @@ class RSI(IndicatorUtils): def analyze(self, historical_data, period_count=14, - signal=['rsi'], hot_thresh=None, cold_thresh=None, lrsi_filter=None): + signal=['rsi'], hot_thresh=None, cold_thresh=None, lrsi_filter=None): """Performs an RSI analysis on the historical data Args: diff --git a/app/analyzers/indicators/sqzmom.py b/app/analyzers/indicators/sqzmom.py index 53beafc..77dc909 100644 --- a/app/analyzers/indicators/sqzmom.py +++ b/app/analyzers/indicators/sqzmom.py @@ -1,7 +1,7 @@ -""" +""" Squeeze Momentum Indicator -This indicator is based on this code: +This indicator is based on this code: https://www.tradingview.com/script/nqQ1DT5a-Squeeze-Momentum-Indicator-LazyBear/ by LazyBear https://www.tradingview.com/u/LazyBear/ @@ -15,7 +15,8 @@ class SQZMOM(IndicatorUtils): - def analyze(self, historical_data, signal=['is_hot'], hot_thresh=None, cold_thresh=None): + def analyze(self, historical_data, signal=[ + 'is_hot'], hot_thresh=None, cold_thresh=None): """Performs a macd analysis on the historical data Args: @@ -29,7 +30,7 @@ def analyze(self, historical_data, signal=['is_hot'], hot_thresh=None, cold_thre """ df = self.convert_to_dataframe(historical_data) - sqzmom = df.copy(deep=True); + sqzmom = df.copy(deep=True) # parameter setup (default values in the original indicator) length = 20 @@ -45,7 +46,7 @@ def analyze(self, historical_data, signal=['is_hot'], hot_thresh=None, cold_thre m_std = df['close'].rolling(window=length).std(ddof=0) # upper Bollinger Bands df['upper_BB'] = m_avg + mult * m_std - # lower Bollinger Bands + # lower Bollinger Bands df['lower_BB'] = m_avg - mult * m_std # calculate Keltner Channel @@ -63,33 +64,38 @@ def analyze(self, historical_data, signal=['is_hot'], hot_thresh=None, cold_thre df['lower_KC'] = m_avg - range_ma * mult_KC # check for 'squeeze' - df['squeeze_on'] = (df['lower_BB'] > df['lower_KC']) & (df['upper_BB'] < df['upper_KC']) - df['squeeze_off'] = (df['lower_BB'] < df['lower_KC']) & (df['upper_BB'] > df['upper_KC']) + df['squeeze_on'] = ( + df['lower_BB'] > df['lower_KC']) & ( + df['upper_BB'] < df['upper_KC']) + df['squeeze_off'] = ( + df['lower_BB'] < df['lower_KC']) & ( + df['upper_BB'] > df['upper_KC']) # calculate momentum value - highest = df['high'].rolling(window = length_KC).max() - lowest = df['low'].rolling(window = length_KC).min() + highest = df['high'].rolling(window=length_KC).max() + lowest = df['low'].rolling(window=length_KC).min() m1 = (highest + lowest) / 2 - df['value'] = (df['close'] - (m1 + m_avg)/2) - fit_y = np.array(range(0,length_KC)) - df['value'] = df['value'].rolling(window = length_KC).apply(lambda x : np.polyfit(fit_y, x, 1)[0] * (length_KC-1) + - np.polyfit(fit_y, x, 1)[1], raw=True) + df['value'] = (df['close'] - (m1 + m_avg) / 2) + fit_y = np.array(range(0, length_KC)) + df['value'] = df['value'].rolling(window=length_KC).apply(lambda x: np.polyfit(fit_y, x, 1)[0] * (length_KC - 1) + + np.polyfit(fit_y, x, 1)[1], raw=True) - # entry point for long position: # 1. black cross becomes gray (the squeeze is released) - long_cond1 = (df['squeeze_off'][-2] == False) & (df['squeeze_off'][-1] == True) + long_cond1 = (df['squeeze_off'][-2] == + False) & (df['squeeze_off'][-1] == True) # 2. bar value is positive => the bar is light green long_cond2 = df['value'][-1] > 0 enter_long = long_cond1 and long_cond2 # entry point for short position: # 1. black cross becomes gray (the squeeze is released) - short_cond1 = (df['squeeze_off'][-2] == False) & (df['squeeze_off'][-1] == True) - # 2. bar value is negative => the bar is light red + short_cond1 = (df['squeeze_off'][-2] == + False) & (df['squeeze_off'][-1] == True) + # 2. bar value is negative => the bar is light red short_cond2 = df['value'][-1] < 0 - enter_short = short_cond1 and short_cond2 - + enter_short = short_cond1 and short_cond2 + sqzmom['is_hot'] = False sqzmom['is_cold'] = False diff --git a/app/analyzers/indicators/stoch_rsi.py b/app/analyzers/indicators/stoch_rsi.py index 6ce9416..12cd01a 100644 --- a/app/analyzers/indicators/stoch_rsi.py +++ b/app/analyzers/indicators/stoch_rsi.py @@ -34,7 +34,8 @@ def analyze(self, historical_data, period_count=14, rsi = abstract.RSI(dataframe, period_count) - stochrsi = (rsi - rsi.rolling(period_count).min()) / (rsi.rolling(period_count).max() - rsi.rolling(period_count).min()) + stochrsi = (rsi - rsi.rolling(period_count).min()) / \ + (rsi.rolling(period_count).max() - rsi.rolling(period_count).min()) stochrsi_K = stochrsi.rolling(3).mean() stochrsi_D = stochrsi_K.rolling(3).mean() diff --git a/app/analyzers/indicators/stochrsi_cross.py b/app/analyzers/indicators/stochrsi_cross.py index 8881dcc..6179498 100644 --- a/app/analyzers/indicators/stochrsi_cross.py +++ b/app/analyzers/indicators/stochrsi_cross.py @@ -10,7 +10,8 @@ class StochRSICross(IndicatorUtils): - def analyze(self, historical_data, period_count=14, signal=['stoch_rsi'], smooth_k = 10, smooth_d = 3, hot_thresh=None, cold_thresh=None): + def analyze(self, historical_data, period_count=14, signal=[ + 'stoch_rsi'], smooth_k=10, smooth_d=3, hot_thresh=None, cold_thresh=None): """Performs a StochRSI cross analysis on the historical data Args: @@ -19,7 +20,7 @@ def analyze(self, historical_data, period_count=14, signal=['stoch_rsi'], smooth smooth_k (integer): number of periods to calculate the smooth K line smooth_d (integer): number of periods to calculate the smooth D line hot_thresh (float, optional): Unused for this indicator - cold_thresh (float, optional): Unused for this indicator + cold_thresh (float, optional): Unused for this indicator Returns: pandas.DataFrame: A dataframe containing the indicator and hot/cold values. @@ -28,7 +29,8 @@ def analyze(self, historical_data, period_count=14, signal=['stoch_rsi'], smooth dataframe = self.convert_to_dataframe(historical_data) rsi = abstract.RSI(dataframe, period_count) - stochrsi = (rsi - rsi.rolling(period_count).min()) / (rsi.rolling(period_count).max() - rsi.rolling(period_count).min()) + stochrsi = (rsi - rsi.rolling(period_count).min()) / \ + (rsi.rolling(period_count).max() - rsi.rolling(period_count).min()) stochrsi_K = stochrsi.rolling(smooth_k).mean() stochrsi_D = stochrsi_K.rolling(smooth_d).mean() @@ -48,7 +50,9 @@ def analyze(self, historical_data, period_count=14, signal=['stoch_rsi'], smooth stoch_cross['is_hot'] = False stoch_cross['is_cold'] = False - stoch_cross.at[stoch_cross.index[-1], 'is_cold'] = previous_k > previous_d and current_k < current_d - stoch_cross.at[stoch_cross.index[-1], 'is_hot'] = previous_k < previous_d and current_k > current_d + stoch_cross.at[stoch_cross.index[-1], + 'is_cold'] = previous_k > previous_d and current_k < current_d + stoch_cross.at[stoch_cross.index[-1], + 'is_hot'] = previous_k < previous_d and current_k > current_d return stoch_cross diff --git a/app/analyzers/informants/lrsi.py b/app/analyzers/informants/lrsi.py index fb76135..35cdeec 100644 --- a/app/analyzers/informants/lrsi.py +++ b/app/analyzers/informants/lrsi.py @@ -1,16 +1,16 @@ -""" +""" LaguerreRSI from Backtrader https://github.com/backtrader/backtrader Defined by John F. Ehlers in `Cybernetic Analysis for Stock and Futures`, 2004, published by Wiley. `ISBN: 978-0-471-46307-8` - + The Laguerre RSI tries to implements a better RSI by providing a sort of - *Time Warp without Time Travel* using a Laguerre filter. - + *Time Warp without Time Travel* using a Laguerre filter. + This provides for faster reactions to price changes ``gamma`` is meant to have values between ``0.2`` and ``0.8``, with the - best balance found theoretically at the default of ``0.5`` + best balance found theoretically at the default of ``0.5`` """ import numpy as np diff --git a/app/app.py b/app/app.py index 1dafc54..913fa52 100644 --- a/app/app.py +++ b/app/app.py @@ -44,7 +44,8 @@ def main(): for exchange in market_data: num = 1 - for chunk in split_market_data(market_data[exchange], settings['market_data_chunk_size']): + for chunk in split_market_data( + market_data[exchange], settings['market_data_chunk_size']): market_data_chunk = dict() market_data_chunk[exchange] = { key: market_data[exchange][key] for key in chunk} @@ -84,7 +85,8 @@ def chunks(l, n): class AnalysisWorker(Thread): - def __init__(self, threadName, behaviour, notifier, market_data, settings, logger): + def __init__(self, threadName, behaviour, notifier, + market_data, settings, logger): Thread.__init__(self) self.threadName = threadName diff --git a/app/behaviour.py b/app/behaviour.py index f0f6465..c019b1b 100644 --- a/app/behaviour.py +++ b/app/behaviour.py @@ -254,7 +254,7 @@ def _get_indicator_results(self, exchange, market_pair): analysis_args['senkou_span_b_period'] = indicator_conf[ 'senkou_span_b_period'] if 'senkou_span_b_period' in indicator_conf else 120 analysis_args['custom_strategy'] = indicator_conf['custom_strategy'] if 'custom_strategy' in indicator_conf else None - + if indicator == 'candle_recognition': analysis_args['candle_check'] = indicator_conf['candle_check'] if 'candle_check' in indicator_conf else 1 analysis_args['notification'] = indicator_conf['notification'] if 'notification' in indicator_conf else 'hot' @@ -348,8 +348,10 @@ def _get_crossover_results(self, new_result): self.logger.debug("%s is disabled, skipping.", crossover) continue try: - key_indicator = new_result[crossover_conf['key_indicator_type']][crossover_conf['key_indicator']][crossover_conf['key_indicator_index']] - crossed_indicator = new_result[crossover_conf['crossed_indicator_type']][crossover_conf['crossed_indicator']][crossover_conf['crossed_indicator_index']] + key_indicator = new_result[crossover_conf['key_indicator_type'] + ][crossover_conf['key_indicator']][crossover_conf['key_indicator_index']] + crossed_indicator = new_result[crossover_conf['crossed_indicator_type'] + ][crossover_conf['crossed_indicator']][crossover_conf['crossed_indicator_index']] crossover_conf['candle_period'] = crossover_conf['key_indicator'] + \ str(crossover_conf['key_indicator_index']) @@ -417,7 +419,8 @@ def _get_historical_data(self, market_pair, exchange, candle_period): self.logger.debug(traceback.format_exc()) return historical_data - def _get_analysis_result(self, dispatcher, indicator, dispatcher_args, market_pair): + def _get_analysis_result(self, dispatcher, indicator, + dispatcher_args, market_pair): """Get the results of performing technical analysis Args: diff --git a/app/conf.py b/app/conf.py index 788e3c1..3805c0b 100644 --- a/app/conf.py +++ b/app/conf.py @@ -58,7 +58,7 @@ def __init__(self): self.exchanges = user_config['exchanges'] else: self.exchanges = dict() - + if 'conditionals' in user_config: self.conditionals = user_config['conditionals'] else: diff --git a/app/exchange.py b/app/exchange.py index bb17fea..b507577 100644 --- a/app/exchange.py +++ b/app/exchange.py @@ -56,8 +56,10 @@ def __init__(self, exchange_config): self.logger.error( "Unable to load exchange %s", new_exchange) - @retry(retry=retry_if_exception_type(ccxt.NetworkError), stop=stop_after_attempt(3)) - def get_historical_data(self, market_pair, exchange, time_unit, start_date=None, max_periods=240): + @retry(retry=retry_if_exception_type(ccxt.NetworkError), + stop=stop_after_attempt(3)) + def get_historical_data(self, market_pair, exchange, + time_unit, start_date=None, max_periods=240): """Get historical OHLCV for a symbol pair Decorators: @@ -132,7 +134,8 @@ def get_historical_data(self, market_pair, exchange, time_unit, start_date=None, return historical_data - @retry(retry=retry_if_exception_type(ccxt.NetworkError), stop=stop_after_attempt(3)) + @retry(retry=retry_if_exception_type(ccxt.NetworkError), + stop=stop_after_attempt(3)) def get_top_markets(self, exchange, base_markets): top_markets = [] @@ -161,7 +164,8 @@ def get_top_markets(self, exchange, base_markets): return top_markets - @retry(retry=retry_if_exception_type(ccxt.NetworkError), stop=stop_after_attempt(3)) + @retry(retry=retry_if_exception_type(ccxt.NetworkError), + stop=stop_after_attempt(3)) def get_exchange_markets(self, exchanges=[], markets=[]): """Get market data for all symbol pairs listed on all configured exchanges. @@ -216,7 +220,8 @@ def get_exchange_markets(self, exchanges=[], markets=[]): exchange_markets[exchange] = {key: curr_markets[key] for key in curr_markets if curr_markets[key]['quote'] in self.base_markets[exchange]} - if isinstance(self.exclude, list) and len(self.exclude) > 0: + if isinstance(self.exclude, list) and len( + self.exclude) > 0: for base_market in self.base_markets[exchange]: for pair_to_exclude in self.exclude: exchange_markets[exchange].pop( diff --git a/app/notification.py b/app/notification.py index 3e37952..beccc89 100755 --- a/app/notification.py +++ b/app/notification.py @@ -43,7 +43,8 @@ class Notifier(IndicatorUtils): """Handles sending notifications via the configured notifiers """ - def __init__(self, notifier_config, indicator_config, conditional_config, market_data): + def __init__(self, notifier_config, indicator_config, + conditional_config, market_data): """Initializes Notifier class Args: @@ -171,7 +172,8 @@ def notify_all(self, new_analysis): self.notify_conditional(exchange, market_pair, _messages) else: for candle_period in _messages: - if not isinstance(_messages[candle_period], list) or len(_messages[candle_period]) == 0: + if not isinstance(_messages[candle_period], list) or len( + _messages[candle_period]) == 0: continue self.notify_all_messages( @@ -213,7 +215,8 @@ def notify_conditional(self, exchange, market_pair, messages): if msg['status'] == stat and stat in condition.keys(): for indicator in condition[stat]: if msg['indicator'] in indicator.keys(): - if indicator[msg['indicator']] == msg['indicator_number']: + if indicator[msg['indicator'] + ] == msg['indicator_number']: new_message['values'].append( msg['values']) new_message['indicator'].append( @@ -240,7 +243,8 @@ def notify_conditional(self, exchange, market_pair, messages): asyncio.run(self.notify_telegram([new_message], None)) self.notify_stdout([new_message]) - def notify_all_messages(self, exchange, market_pair, candle_period, messages): + def notify_all_messages(self, exchange, market_pair, + candle_period, messages): chart_file = None if self.enable_charts: @@ -281,7 +285,8 @@ def notify_discord(self, messages, chart_file): if self.enable_charts: if chart_file: - self.discord_clients[notifier].send_chart_messages(chart_file, formatted_messages) + self.discord_clients[notifier].send_chart_messages( + chart_file, formatted_messages) else: self.logger.info( 'Chart file %s doesnt exist, sending text message.', chart_file) @@ -443,7 +448,8 @@ def _indicator_message_templater(self, new_analysis, template): if indicator_type == 'informants': continue for indicator in new_analysis[exchange][market][indicator_type]: - for index, analysis in enumerate(new_analysis[exchange][market][indicator_type][indicator]): + for index, analysis in enumerate( + new_analysis[exchange][market][indicator_type][indicator]): if analysis['result'].shape[0] == 0: continue @@ -507,7 +513,7 @@ def _indicator_message_templater(self, new_analysis, template): try: last_status = self.last_analysis[exchange][market][ indicator_type][indicator][index]['status'] - except: + except BaseException: last_status = str() should_alert = True @@ -565,7 +571,8 @@ def parse_alert_fequency(self, alert_frequency): def should_i_alert(self, alert_frequency_key, alert_frequency): if alert_frequency_key in self.alert_frequencies: - if self.alert_frequencies[alert_frequency_key] > datetime.datetime.now(): + if self.alert_frequencies[alert_frequency_key] > datetime.datetime.now( + ): return False timedelta = self.parse_alert_fequency(alert_frequency) if timedelta: @@ -610,7 +617,8 @@ def get_indicator_messages(self, new_analysis): for indicator_type in new_analysis[exchange][market_pair]: if indicator_type == 'informants': # Getting OHLC prices - for index, analysis in enumerate(new_analysis[exchange][market_pair]['informants']['ohlcv']): + for index, analysis in enumerate( + new_analysis[exchange][market_pair]['informants']['ohlcv']): values = dict() for signal in analysis['config']['signal']: values[signal] = analysis['result'].iloc[-1][signal] @@ -619,7 +627,8 @@ def get_indicator_messages(self, new_analysis): # Getting LRSI values if 'lrsi' in new_analysis[exchange][market_pair]['informants']: - for index, analysis in enumerate(new_analysis[exchange][market_pair]['informants']['lrsi']): + for index, analysis in enumerate( + new_analysis[exchange][market_pair]['informants']['lrsi']): values = dict() for signal in analysis['config']['signal']: values[signal] = analysis['result'].iloc[-1][signal] @@ -632,7 +641,8 @@ def get_indicator_messages(self, new_analysis): continue for indicator in new_analysis[exchange][market_pair][indicator_type]: - for index, analysis in enumerate(new_analysis[exchange][market_pair][indicator_type][indicator]): + for index, analysis in enumerate( + new_analysis[exchange][market_pair][indicator_type][indicator]): if analysis['result'].shape[0] == 0: continue @@ -702,7 +712,7 @@ def get_indicator_messages(self, new_analysis): try: last_status = self.last_analysis[exchange][market_pair][ indicator_type][indicator][index]['status'] - except: + except BaseException: last_status = str() should_alert = True @@ -719,7 +729,8 @@ def get_indicator_messages(self, new_analysis): if not analysis['config']['alert_enabled']: should_alert = False - if 'mute_cold' in analysis['config'] and analysis['config']['mute_cold'] == True and latest_result['is_cold'] == True: + if 'mute_cold' in analysis['config'] and analysis['config'][ + 'mute_cold'] == True and latest_result['is_cold'] == True: self.logger.info( 'Skiping cold notification for %s %s %s', market_pair, indicator, candle_period) should_alert = False @@ -739,7 +750,8 @@ def get_indicator_messages(self, new_analysis): candle_values = ohlcv_values[exchange][market_pair] if candle_period in candle_values: - for key, value in candle_values[candle_period].items(): + for key, value in candle_values[candle_period].items( + ): price_value[key] = value value = format( @@ -1043,7 +1055,7 @@ def plot_candlestick(self, ax, df, candle_period, candle_pattern): ma25 = self.EMA(df, 25) ma99 = self.EMA(df, 99) - if(df['close'].count() > 120): + if (df['close'].count() > 120): df = df.iloc[-120:] ma7 = ma7.iloc[-120:] ma25 = ma25.iloc[-120:] @@ -1062,7 +1074,7 @@ def plot_candlestick(self, ax, df, candle_period, candle_pattern): try: self.candlestick_ohlc(ax, zip(_time, df['open'], df['high'], df['low'], df['close']), cdl=candle_pattern, width=stick_width, colorup='olivedrab', colordown='crimson') - except: + except BaseException: print(traceback.print_exc()) ax.plot(df.index, ma7, color='darkorange', lw=0.8, label='EMA (7)') @@ -1073,9 +1085,9 @@ def plot_candlestick(self, ax, df, candle_period, candle_pattern): ax.text(0.04, 0.94, 'EMA (7, close)', color='darkorange', transform=ax.transAxes, fontsize=textsize, va='top') ax.text(0.24, 0.94, 'EMA (25, close)', color='mediumslateblue', - transform=ax.transAxes, fontsize=textsize, va='top') + transform=ax.transAxes, fontsize=textsize, va='top') ax.text(0.46, 0.94, 'EMA (99, close)', color='firebrick', - transform=ax.transAxes, fontsize=textsize, va='top') + transform=ax.transAxes, fontsize=textsize, va='top') def plot_rsi(self, ax, df): textsize = 11 @@ -1083,7 +1095,7 @@ def plot_rsi(self, ax, df): rsi = self.relative_strength(df["close"]) - if(df['close'].count() > 120): + if (df['close'].count() > 120): df = df.iloc[-120:] rsi = rsi[-120:] @@ -1105,7 +1117,7 @@ def plot_macd(self, ax, df, candle_period): df = StockDataFrame.retype(df) df['macd'] = df.get('macd') - if(df['macd'].count() > 120): + if (df['macd'].count() > 120): df = df.iloc[-120:] min_y = df.macd.min() @@ -1213,7 +1225,8 @@ def moving_average(self, x, n, type='simple'): return a def EMA(self, df, n, field='close'): - return pd.Series(talib.EMA(df[field].astype('f8').values, n), name='EMA_' + field.upper() + '_' + str(n), index=df.index) + return pd.Series(talib.EMA(df[field].astype( + 'f8').values, n), name='EMA_' + field.upper() + '_' + str(n), index=df.index) def plot_ichimoku(self, ax, df, historical_data, candle_period): indicator_conf = {} @@ -1232,9 +1245,10 @@ def plot_ichimoku(self, ax, df, historical_data, candle_period): ichimoku_data = ichimoku.Ichimoku().analyze(historical_data, tenkansen_period, kijunsen_period, senkou_span_b_period, chart=True) - if(df['close'].count() > 120): + if (df['close'].count() > 120): df = df.iloc[-120:] - ##change 146 if cloud displacement period changed in ichimoku.Ichimoku().calculate()## + # change 146 if cloud displacement period changed in + # ichimoku.Ichimoku().calculate()## ichimoku_data = ichimoku_data.iloc[-146:] _time = mdates.date2num(df.index.to_pydatetime()) diff --git a/app/notifiers/telegram_client.py b/app/notifiers/telegram_client.py index f451c28..bdc8c09 100644 --- a/app/notifiers/telegram_client.py +++ b/app/notifiers/telegram_client.py @@ -68,7 +68,7 @@ async def send_chart_messages(self, photo_url: str, messages=[]): try: with open(photo_url, 'rb') as f: await self.bot.send_photo(chat_id=self.chat_id, - photo=f.read(), timeout=__connect_timeout__) + photo=f.read(), timeout=__connect_timeout__) except Exception as e: self.logger.info('Unable to send chart messages using Telegram !') self.logger.debug(str(e)) diff --git a/app/notifiers/twilio_client.py b/app/notifiers/twilio_client.py index b82cbba..f1c9426 100644 --- a/app/notifiers/twilio_client.py +++ b/app/notifiers/twilio_client.py @@ -11,7 +11,8 @@ class TwilioNotifier(NotifierUtils): """Class for handling twilio notifications """ - def __init__(self, twilio_key, twilio_secret, twilio_sender_number, twilio_receiver_number): + def __init__(self, twilio_key, twilio_secret, + twilio_sender_number, twilio_receiver_number): """Initialize TwilioNotifer class Args: diff --git a/app/notifiers/utils.py b/app/notifiers/utils.py index c2f1dea..dd61db4 100644 --- a/app/notifiers/utils.py +++ b/app/notifiers/utils.py @@ -3,6 +3,7 @@ import structlog + class NotifierUtils(): """ Utilities for notifiers """ @@ -10,7 +11,6 @@ class NotifierUtils(): def __init__(self): self.logger = structlog.get_logger() - def chunk_message(self, message, max_message_size): """ Chunks message so that it meets max size of integration. @@ -38,4 +38,4 @@ def chunk_message(self, message, max_message_size): else: chunked_message.append(message) - return chunked_message \ No newline at end of file + return chunked_message diff --git a/app/notifiers/webhook_client.py b/app/notifiers/webhook_client.py index 2d80d7b..0db52e6 100644 --- a/app/notifiers/webhook_client.py +++ b/app/notifiers/webhook_client.py @@ -27,8 +27,8 @@ def notify(self, messages, chart_file): messages (dict): A dict with the messages to send. """ - #market_pair = market_pair.replace('/', '_').lower() - #chart_file = '{}/{}_{}_{}.png'.format('./charts', exchange, market_pair, candle_period) + # market_pair = market_pair.replace('/', '_').lower() + # chart_file = '{}/{}_{}_{}.png'.format('./charts', exchange, market_pair, candle_period) data = {'messages': json.dumps(messages)} diff --git a/app/outputs.py b/app/outputs.py index 3973b92..bfac534 100644 --- a/app/outputs.py +++ b/app/outputs.py @@ -41,7 +41,8 @@ def to_cli(self, results, market_pair): for indicator_type in results: output += '\n{}:\t'.format(indicator_type) for indicator in results[indicator_type]: - for i, analysis in enumerate(results[indicator_type][indicator]): + for i, analysis in enumerate( + results[indicator_type][indicator]): if analysis['result'].shape[0] == 0: self.logger.info('No results for %s #%s', indicator, i) continue @@ -89,7 +90,8 @@ def to_cli(self, results, market_pair): formatted_values = list() for signal in analysis['config']['signal']: value = analysis['result'].iloc[-1][signal] - if isinstance(value, float) or isinstance(value, np.int32): + if isinstance(value, float) or isinstance( + value, np.int32): formatted_values.append(format(value, '.8f')) else: formatted_values.append(value) @@ -122,21 +124,14 @@ def to_csv(self, results, market_pair): output = str() for indicator_type in results: for indicator in results[indicator_type]: - for i, analysis in enumerate(results[indicator_type][indicator]): + for i, analysis in enumerate( + results[indicator_type][indicator]): value = str() if indicator_type == 'crossovers': - key_signal = '{}_{}'.format( - analysis['config']['key_signal'], - analysis['config']['key_indicator_index'] - ) - + key_signal = f"{analysis['config']['key_signal']}_{analysis['config']['key_indicator_index']}" key_value = analysis['result'].iloc[-1][key_signal] - - crossed_signal = '{}_{}'.format( - analysis['config']['crossed_signal'], - analysis['config']['crossed_indicator_index'] - ) + crossed_signal = f"{analysis['config']['crossed_signal']}_{analysis['config']['crossed_indicator_index']}" crossed_value = analysis['result'].iloc[-1][crossed_signal] @@ -171,7 +166,7 @@ def to_csv(self, results, market_pair): is_cold ]) - output += '\n{}'.format(new_output) + output += f'\n{new_output}' return output @@ -186,12 +181,13 @@ def to_json(self, results, market_pair): str: Completed JSON message """ - logger.warn( + self.logger.warn( 'WARNING: JSON output is deprecated and will be removed in a future version') for indicator_type in results: for indicator in results[indicator_type]: - for index, analysis in enumerate(results[indicator_type][indicator]): + for index, analysis in enumerate( + results[indicator_type][indicator]): results[indicator_type][indicator][index]['result'] = analysis['result'].to_dict( orient='records' )[-1]