Ejemplo n.º 1
0
def test_should_calculate_addChangePct():
    """
      Adds the close percentage to the DataFrame : close_pc
      Adds the cumulative returns the DataFrame : close_cpc

      Excellent video to understand cumulative returns : https://www.youtube.com/watch?v=fWHQwqT3lNY
    """

    # GIVEN a series of values
    closes_list = [0.0003, 0.0004, 0.0010, 0.0020, 0.0009]
    df = pd.DataFrame({
        'date': [
            '2021-10-10 14:30:00', '2021-10-10 14:31:00',
            '2021-10-10 14:32:00', '2021-10-10 14:33:00', '2021-10-10 14:34:00'
        ],
        'close':
        closes_list
    })
    df['date'] = pd.to_datetime(df['date'], format="%Y-%d-%m %H:%M:%S")
    df.set_index(['date'])

    ta = TechnicalAnalysis(df)

    # WHEN calculate the percentage evolution and cumulative returns percentage
    ta.addChangePct()

    # THEN percentage evolution and cumulative returns percentage should be added to dataframe
    actual = ta.getDataFrame()

    close_pc = [
        calculate_percentage_evol(closes_list[0], closes_list[0]),
        calculate_percentage_evol(closes_list[0], closes_list[1]),
        calculate_percentage_evol(closes_list[1], closes_list[2]),
        calculate_percentage_evol(closes_list[2], closes_list[3]),
        calculate_percentage_evol(closes_list[3], closes_list[4]),
    ]

    close_cpc = []
    close_cpc.append(0.000000)
    close_cpc.append((1 + close_pc[1]) * (1 + close_cpc[0]) - 1)
    close_cpc.append((1 + close_pc[2]) * (1 + close_cpc[1]) - 1)
    close_cpc.append((1 + close_pc[3]) * (1 + close_cpc[2]) - 1)
    close_cpc.append((1 + close_pc[4]) * (1 + close_cpc[3]) - 1)

    expected = pd.DataFrame({
        'date': [
            '2021-10-10 14:30:00', '2021-10-10 14:31:00',
            '2021-10-10 14:32:00', '2021-10-10 14:33:00', '2021-10-10 14:34:00'
        ],
        'close':
        closes_list,
        'close_pc':
        close_pc,
        'close_cpc':
        close_cpc
    })
    expected['date'] = pd.to_datetime(df['date'], format="%Y-%d-%m %H:%M:%S")
    expected.set_index(['date'])
    assert_frame_equal(actual, expected)
Ejemplo n.º 2
0
def test_should_calculate_addCMA():
    """
      Adds the Cumulative Moving Average (CMA) to the DataFrame : cma
    """

    # GIVEN a series of values
    closes_list = [0.0003, 0.0004, 0.0010, 0.0020, 0.0009]
    df = pd.DataFrame({
        'date': [
            '2021-10-10 14:30:00', '2021-10-10 14:31:00',
            '2021-10-10 14:32:00', '2021-10-10 14:33:00', '2021-10-10 14:34:00'
        ],
        'close':
        closes_list
    })
    df['date'] = pd.to_datetime(df['date'], format="%Y-%d-%m %H:%M:%S")
    df.set_index(['date'])

    ta = TechnicalAnalysis(df)

    # WHEN calculate the cumulative moving average
    ta.addCMA()

    # THEN Cumulative Moving Average should be added to dataframe
    actual = ta.getDataFrame()
    expected = pd.DataFrame({
        'date': [
            '2021-10-10 14:30:00', '2021-10-10 14:31:00',
            '2021-10-10 14:32:00', '2021-10-10 14:33:00', '2021-10-10 14:34:00'
        ],
        'close':
        closes_list,
        'cma': [
            calculate_mean_on_range(0, 1, closes_list),
            calculate_mean_on_range(0, 2, closes_list),
            calculate_mean_on_range(0, 3, closes_list),
            calculate_mean_on_range(0, 4, closes_list),
            calculate_mean_on_range(0, 5, closes_list),
        ]
    })
    expected['date'] = pd.to_datetime(df['date'], format="%Y-%d-%m %H:%M:%S")
    expected.set_index(['date'])
    assert_frame_equal(actual, expected)
Ejemplo n.º 3
0
    def is6hEMA1226Bull(self, iso8601end: str = ''):
        try:
            if self.isSimulation() and isinstance(self.ema1226_6h_cache,
                                                  pd.DataFrame):
                df_data = self.ema1226_6h_cache[(self.ema1226_6h_cache['date']
                                                 <= iso8601end)]
            elif self.exchange == 'coinbasepro':
                api = CBPublicAPI()
                df_data = api.getHistoricalData(self.market, 21600)
                self.ema1226_6h_cache = df_data
            elif self.exchange == 'binance':
                api = BPublicAPI()
                df_data = api.getHistoricalData(self.market, '6h')
                self.ema1226_6h_cache = df_data
            else:
                return False

            ta = TechnicalAnalysis(df_data)

            if 'ema12' not in df_data:
                ta.addEMA(12)

            if 'ema26' not in df_data:
                ta.addEMA(26)

            df_last = ta.getDataFrame().copy().iloc[-1, :]
            df_last['bull'] = df_last['ema12'] > df_last['ema26']

            Logger.debug("---- EMA1226 6H Check----")
            if self.isSimulation():
                Logger.debug("simdate: " + str(df_last['date']))
                Logger.debug("ema12 6h: " + str(df_last['ema12']))
                Logger.debug("ema26 6h: " + str(df_last['ema26']))

            Logger.debug("bull 6h: " +
                         str(df_last['ema12'] > df_last['ema26']))

            return bool(df_last['bull'])
        except Exception:
            return False
Ejemplo n.º 4
0
    def is1hSMA50200Bull(self, iso8601end: str = ''):
        try:
            if self.isSimulation() and isinstance(self.sma50200_1h_cache,
                                                  pd.DataFrame):
                df_data = self.sma50200_1h_cache[(
                    self.sma50200_1h_cache['date'] <= iso8601end)]
            elif self.exchange == 'coinbasepro':
                api = CBPublicAPI()
                df_data = api.getHistoricalData(self.market, 3600)
                self.sma50200_1h_cache = df_data
            elif self.exchange == 'binance':
                api = BPublicAPI()
                df_data = api.getHistoricalData(self.market, '1h')
                self.sma50200_1h_cache = df_data
            else:
                return False

            ta = TechnicalAnalysis(df_data)

            if 'sma50' not in df_data:
                ta.addSMA(50)

            if 'sma200' not in df_data:
                ta.addSMA(200)

            df_last = ta.getDataFrame().copy().iloc[-1, :]

            Logger.debug("---- SMA50200 1H Check----")
            if self.isSimulation():
                Logger.debug("simdate: " + str(df_last['date']))
                Logger.debug("sma50 1h: " + str(df_last['sma50']))
                Logger.debug("sma200 1h: " + str(df_last['sma200']))

            Logger.debug("bull 1h: " +
                         str(df_last['sma50'] > df_last['sma200']))

            df_last['bull'] = df_last['sma50'] > df_last['sma200']
            return bool(df_last['bull'])
        except Exception:
            return False
Ejemplo n.º 5
0
def executeJob(sc=None,
               app: PyCryptoBot = None,
               state: AppState = None,
               trading_data=pd.DataFrame()):
    """Trading bot job which runs at a scheduled interval"""

    global technical_analysis

    # connectivity check (only when running live)
    if app.isLive() and app.getTime() is None:
        Logger.warning(
            'Your connection to the exchange has gone down, will retry in 1 minute!'
        )

        # poll every 5 minute
        list(map(s.cancel, s.queue))
        s.enter(300, 1, executeJob, (sc, app, state))
        return

    # increment state.iterations
    state.iterations = state.iterations + 1

    if not app.isSimulation():
        # retrieve the app.getMarket() data
        trading_data = app.getHistoricalData(app.getMarket(),
                                             app.getGranularity())

    else:
        if len(trading_data) == 0:
            return None

    # analyse the market data
    if app.isSimulation() and len(trading_data.columns) > 8:
        df = trading_data
        # if smartswitch the get the market data using new granularity
        if app.sim_smartswitch:
            df_last = app.getInterval(df, state.iterations)
            if len(df_last.index.format()) > 0:

                current_df_index = str(df_last.index.format()[0])
                current_sim_date = f'{current_df_index} 00:00:00' if len(
                    current_df_index) == 10 else current_df_index
                dt = current_sim_date.split(' ')
                date = dt[0].split('-')
                time = dt[1].split(':')
                startDate = datetime(int(date[0]), int(date[1]), int(date[2]),
                                     int(time[0]), int(time[1]), int(time[2]))
                trading_data = app.getHistoricalData(
                    app.getMarket(), app.getGranularity(),
                    startDate.isoformat(timespec='milliseconds'),
                    datetime.now().isoformat(timespec='milliseconds'))
                trading_dataCopy = trading_data.copy()
                technical_analysis = TechnicalAnalysis(trading_dataCopy)
                technical_analysis.addAll()
                df = technical_analysis.getDataFrame()
                state.iterations = 1
            app.sim_smartswitch = False

    else:
        trading_dataCopy = trading_data.copy()
        technical_analysis = TechnicalAnalysis(trading_dataCopy)
        technical_analysis.addAll()
        df = technical_analysis.getDataFrame()

    if app.isSimulation():
        df_last = app.getInterval(df, state.iterations)
    else:
        df_last = app.getInterval(df)

    if len(df_last.index.format()) > 0:
        current_df_index = str(df_last.index.format()[0])
    else:
        current_df_index = state.last_df_index

    formatted_current_df_index = f'{current_df_index} 00:00:00' if len(
        current_df_index) == 10 else current_df_index

    current_sim_date = formatted_current_df_index

    # use actual sim mode date to check smartchswitch
    if app.getSmartSwitch() == 1 and app.getGranularity(
    ) == 3600 and app.is1hEMA1226Bull(
            current_sim_date) is True and app.is6hEMA1226Bull(
                current_sim_date) is True:
        Logger.info(
            '*** smart switch from granularity 3600 (1 hour) to 900 (15 min) ***'
        )

        if app.isSimulation():
            app.sim_smartswitch = True

        app.notifyTelegram(
            app.getMarket() +
            " smart switch from granularity 3600 (1 hour) to 900 (15 min)")

        app.setGranularity(900)
        list(map(s.cancel, s.queue))
        s.enter(5, 1, executeJob, (sc, app, state))

    # use actual sim mode date to check smartchswitch
    if app.getSmartSwitch() == 1 and app.getGranularity(
    ) == 900 and app.is1hEMA1226Bull(
            current_sim_date) is False and app.is6hEMA1226Bull(
                current_sim_date) is False:
        Logger.info(
            "*** smart switch from granularity 900 (15 min) to 3600 (1 hour) ***"
        )

        if app.isSimulation():
            app.sim_smartswitch = True

        app.notifyTelegram(
            app.getMarket() +
            " smart switch from granularity 900 (15 min) to 3600 (1 hour)")

        app.setGranularity(3600)
        list(map(s.cancel, s.queue))
        s.enter(5, 1, executeJob, (sc, app, state))

    if app.getExchange() == 'binance' and app.getGranularity() == 86400:
        if len(df) < 250:
            # data frame should have 250 rows, if not retry
            Logger.error('error: data frame length is < 250 (' + str(len(df)) +
                         ')')
            list(map(s.cancel, s.queue))
            s.enter(300, 1, executeJob, (sc, app, state))
    else:
        if len(df) < 300:
            if not app.isSimulation():
                # data frame should have 300 rows, if not retry
                Logger.error('error: data frame length is < 300 (' +
                             str(len(df)) + ')')
                list(map(s.cancel, s.queue))
                s.enter(300, 1, executeJob, (sc, app, state))

    if len(df_last) > 0:
        now = datetime.today().strftime('%Y-%m-%d %H:%M:%S')

        # last_action polling if live
        if app.isLive():
            last_action_current = state.last_action
            state.pollLastAction()
            if last_action_current != state.last_action:
                Logger.info(
                    f'last_action change detected from {last_action_current} to {state.last_action}'
                )
                app.notifyTelegram(
                    f"{app.getMarket} last_action change detected from {last_action_current} to {state.last_action}"
                )

        if not app.isSimulation():
            ticker = app.getTicker(app.getMarket())
            now = ticker[0]
            price = ticker[1]
            if price < df_last['low'].values[0] or price == 0:
                price = float(df_last['close'].values[0])
        else:
            price = float(df_last['close'].values[0])

        if price < 0.0001:
            raise Exception(
                app.getMarket() +
                ' is unsuitable for trading, quote price is less than 0.0001!')

        # technical indicators
        ema12gtema26 = bool(df_last['ema12gtema26'].values[0])
        ema12gtema26co = bool(df_last['ema12gtema26co'].values[0])
        goldencross = bool(df_last['goldencross'].values[0])
        macdgtsignal = bool(df_last['macdgtsignal'].values[0])
        macdgtsignalco = bool(df_last['macdgtsignalco'].values[0])
        ema12ltema26 = bool(df_last['ema12ltema26'].values[0])
        ema12ltema26co = bool(df_last['ema12ltema26co'].values[0])
        macdltsignal = bool(df_last['macdltsignal'].values[0])
        macdltsignalco = bool(df_last['macdltsignalco'].values[0])
        obv = float(df_last['obv'].values[0])
        obv_pc = float(df_last['obv_pc'].values[0])
        elder_ray_buy = bool(df_last['eri_buy'].values[0])
        elder_ray_sell = bool(df_last['eri_sell'].values[0])

        # if simulation, set goldencross based on actual sim date
        if app.isSimulation():
            goldencross = app.is1hSMA50200Bull(current_sim_date)

        # if simulation interations < 200 set goldencross to true
        #if app.isSimulation() and state.iterations < 200:
        #    goldencross = True

        # candlestick detection
        hammer = bool(df_last['hammer'].values[0])
        inverted_hammer = bool(df_last['inverted_hammer'].values[0])
        hanging_man = bool(df_last['hanging_man'].values[0])
        shooting_star = bool(df_last['shooting_star'].values[0])
        three_white_soldiers = bool(df_last['three_white_soldiers'].values[0])
        three_black_crows = bool(df_last['three_black_crows'].values[0])
        morning_star = bool(df_last['morning_star'].values[0])
        evening_star = bool(df_last['evening_star'].values[0])
        three_line_strike = bool(df_last['three_line_strike'].values[0])
        abandoned_baby = bool(df_last['abandoned_baby'].values[0])
        morning_doji_star = bool(df_last['morning_doji_star'].values[0])
        evening_doji_star = bool(df_last['evening_doji_star'].values[0])
        two_black_gapping = bool(df_last['two_black_gapping'].values[0])

        strategy = Strategy(app, state, df, state.iterations)
        state.action = strategy.getAction()

        immediate_action = False
        margin, profit, sell_fee = 0, 0, 0

        if state.last_buy_size > 0 and state.last_buy_price > 0 and price > 0 and state.last_action == 'BUY':
            # update last buy high
            if price > state.last_buy_high:
                state.last_buy_high = price

            if state.last_buy_high > 0:
                change_pcnt_high = ((price / state.last_buy_high) - 1) * 100
            else:
                change_pcnt_high = 0

            # buy and sell calculations
            state.last_buy_fee = round(state.last_buy_size * app.getTakerFee(),
                                       8)
            state.last_buy_filled = round(
                ((state.last_buy_size - state.last_buy_fee) /
                 state.last_buy_price), 8)

            # if not a simulation, sync with exchange orders
            if not app.isSimulation():
                exchange_last_buy = app.getLastBuy()
                if exchange_last_buy is not None:
                    if state.last_buy_size != exchange_last_buy['size']:
                        state.last_buy_size = exchange_last_buy['size']
                    if state.last_buy_filled != exchange_last_buy['filled']:
                        state.last_buy_filled = exchange_last_buy['filled']
                    if state.last_buy_price != exchange_last_buy['price']:
                        state.last_buy_price = exchange_last_buy['price']

                    if app.getExchange() == 'coinbasepro':
                        if state.last_buy_fee != exchange_last_buy['fee']:
                            state.last_buy_fee = exchange_last_buy['fee']

            margin, profit, sell_fee = calculate_margin(
                buy_size=state.last_buy_size,
                buy_filled=state.last_buy_filled,
                buy_price=state.last_buy_price,
                buy_fee=state.last_buy_fee,
                sell_percent=app.getSellPercent(),
                sell_price=price,
                sell_taker_fee=app.getTakerFee())

            # handle immedate sell actions
            if strategy.isSellTrigger(price,
                                      technical_analysis.getTradeExit(price),
                                      margin, change_pcnt_high, obv_pc,
                                      macdltsignal):
                state.action = 'SELL'
                state.last_action = 'BUY'
                immediate_action = True

            # handle overriding wait actions (do not sell if sell at loss disabled!)
            if strategy.isWaitTrigger(margin):
                state.action = 'WAIT'
                state.last_action = 'BUY'
                immediate_action = False

        bullbeartext = ''
        if app.disableBullOnly() is True or (df_last['sma50'].values[0]
                                             == df_last['sma200'].values[0]):
            bullbeartext = ''
        elif goldencross is True:
            bullbeartext = ' (BULL)'
        elif goldencross is False:
            bullbeartext = ' (BEAR)'

        # polling is every 5 minutes (even for hourly intervals), but only process once per interval
        if (immediate_action is True
                or state.last_df_index != current_df_index):
            precision = 4

            if (price < 0.01):
                precision = 8

            # Since precision does not change after this point, it is safe to prepare a tailored `truncate()` that would
            # work with this precision. It should save a couple of `precision` uses, one for each `truncate()` call.
            truncate = functools.partial(_truncate, n=precision)

            price_text = 'Close: ' + truncate(price)
            ema_text = ''
            if app.disableBuyEMA() is False:
                ema_text = app.compare(df_last['ema12'].values[0],
                                       df_last['ema26'].values[0], 'EMA12/26',
                                       precision)

            macd_text = ''
            if app.disableBuyMACD() is False:
                macd_text = app.compare(df_last['macd'].values[0],
                                        df_last['signal'].values[0], 'MACD',
                                        precision)

            obv_text = ''
            if app.disableBuyOBV() is False:
                obv_text = 'OBV: ' + truncate(
                    df_last['obv'].values[0]) + ' (' + str(
                        truncate(df_last['obv_pc'].values[0])) + '%)'

            state.eri_text = ''
            if app.disableBuyElderRay() is False:
                if elder_ray_buy is True:
                    state.eri_text = 'ERI: buy | '
                elif elder_ray_sell is True:
                    state.eri_text = 'ERI: sell | '
                else:
                    state.eri_text = 'ERI: | '

            if hammer is True:
                log_text = '* Candlestick Detected: Hammer ("Weak - Reversal - Bullish Signal - Up")'
                Logger.info(log_text)

            if shooting_star is True:
                log_text = '* Candlestick Detected: Shooting Star ("Weak - Reversal - Bearish Pattern - Down")'
                Logger.info(log_text)

            if hanging_man is True:
                log_text = '* Candlestick Detected: Hanging Man ("Weak - Continuation - Bearish Pattern - Down")'
                Logger.info(log_text)

            if inverted_hammer is True:
                log_text = '* Candlestick Detected: Inverted Hammer ("Weak - Continuation - Bullish Pattern - Up")'
                Logger.info(log_text)

            if three_white_soldiers is True:
                log_text = '*** Candlestick Detected: Three White Soldiers ("Strong - Reversal - Bullish Pattern - Up")'
                Logger.info(log_text)

                app.notifyTelegram(app.getMarket() + ' (' +
                                   app.printGranularity() + ') ' + log_text)

            if three_black_crows is True:
                log_text = '* Candlestick Detected: Three Black Crows ("Strong - Reversal - Bearish Pattern - Down")'
                Logger.info(log_text)

                app.notifyTelegram(app.getMarket() + ' (' +
                                   app.printGranularity() + ') ' + log_text)

            if morning_star is True:
                log_text = '*** Candlestick Detected: Morning Star ("Strong - Reversal - Bullish Pattern - Up")'
                Logger.info(log_text)

                app.notifyTelegram(app.getMarket() + ' (' +
                                   app.printGranularity() + ') ' + log_text)

            if evening_star is True:
                log_text = '*** Candlestick Detected: Evening Star ("Strong - Reversal - Bearish Pattern - Down")'
                Logger.info(log_text)

                app.notifyTelegram(app.getMarket() + ' (' +
                                   app.printGranularity() + ') ' + log_text)

            if three_line_strike is True:
                log_text = '** Candlestick Detected: Three Line Strike ("Reliable - Reversal - Bullish Pattern - Up")'
                Logger.info(log_text)

                app.notifyTelegram(app.getMarket() + ' (' +
                                   app.printGranularity() + ') ' + log_text)

            if abandoned_baby is True:
                log_text = '** Candlestick Detected: Abandoned Baby ("Reliable - Reversal - Bullish Pattern - Up")'
                Logger.info(log_text)

                app.notifyTelegram(app.getMarket() + ' (' +
                                   app.printGranularity() + ') ' + log_text)

            if morning_doji_star is True:
                log_text = '** Candlestick Detected: Morning Doji Star ("Reliable - Reversal - Bullish Pattern - Up")'
                Logger.info(log_text)

                app.notifyTelegram(app.getMarket() + ' (' +
                                   app.printGranularity() + ') ' + log_text)

            if evening_doji_star is True:
                log_text = '** Candlestick Detected: Evening Doji Star ("Reliable - Reversal - Bearish Pattern - Down")'
                Logger.info(log_text)

                app.notifyTelegram(app.getMarket() + ' (' +
                                   app.printGranularity() + ') ' + log_text)

            if two_black_gapping is True:
                log_text = '*** Candlestick Detected: Two Black Gapping ("Reliable - Reversal - Bearish Pattern - Down")'
                Logger.info(log_text)

                app.notifyTelegram(app.getMarket() + ' (' +
                                   app.printGranularity() + ') ' + log_text)

            ema_co_prefix = ''
            ema_co_suffix = ''
            if app.disableBuyEMA() is False:
                if ema12gtema26co is True:
                    ema_co_prefix = '*^ '
                    ema_co_suffix = ' ^*'
                elif ema12ltema26co is True:
                    ema_co_prefix = '*v '
                    ema_co_suffix = ' v*'
                elif ema12gtema26 is True:
                    ema_co_prefix = '^ '
                    ema_co_suffix = ' ^'
                elif ema12ltema26 is True:
                    ema_co_prefix = 'v '
                    ema_co_suffix = ' v'

            macd_co_prefix = ''
            macd_co_suffix = ''
            if app.disableBuyMACD() is False:
                if macdgtsignalco is True:
                    macd_co_prefix = '*^ '
                    macd_co_suffix = ' ^*'
                elif macdltsignalco is True:
                    macd_co_prefix = '*v '
                    macd_co_suffix = ' v*'
                elif macdgtsignal is True:
                    macd_co_prefix = '^ '
                    macd_co_suffix = ' ^'
                elif macdltsignal is True:
                    macd_co_prefix = 'v '
                    macd_co_suffix = ' v'

            obv_prefix = ''
            obv_suffix = ''
            if app.disableBuyOBV() is False:
                if float(obv_pc) > 0:
                    obv_prefix = '^ '
                    obv_suffix = ' ^ | '
                elif float(obv_pc) < 0:
                    obv_prefix = 'v '
                    obv_suffix = ' v | '

            if not app.isVerbose():
                if state.last_action != '':
                    output_text = formatted_current_df_index + ' | ' + app.getMarket() + bullbeartext + ' | ' + \
                                  app.printGranularity() + ' | ' + price_text + ' | ' + ema_co_prefix + \
                                  ema_text + ema_co_suffix + ' | ' + macd_co_prefix + macd_text + macd_co_suffix + \
                                  obv_prefix + obv_text + obv_suffix + state.eri_text + ' | ' + state.action + \
                                  ' | Last Action: ' + state.last_action
                else:
                    output_text = formatted_current_df_index + ' | ' + app.getMarket() + bullbeartext + ' | ' + \
                                  app.printGranularity() + ' | ' + price_text + ' | ' + ema_co_prefix + \
                                  ema_text + ema_co_suffix + ' | ' + macd_co_prefix + macd_text + macd_co_suffix + \
                                  obv_prefix + obv_text + obv_suffix + state.eri_text + ' | ' + state.action + ' '

                if state.last_action == 'BUY':
                    if state.last_buy_size > 0:
                        margin_text = truncate(margin) + '%'
                    else:
                        margin_text = '0%'

                    output_text += ' | ' + margin_text + ' (delta: ' + str(
                        round(price - state.last_buy_price, precision)) + ')'

                Logger.info(output_text)

                # Seasonal Autoregressive Integrated Moving Average (ARIMA) model (ML prediction for 3 intervals from now)
                if not app.isSimulation():
                    try:
                        prediction = technical_analysis.seasonalARIMAModelPrediction(
                            int(app.getGranularity() / 60) *
                            3)  # 3 intervals from now
                        Logger.info(
                            f'Seasonal ARIMA model predicts the closing price will be {str(round(prediction[1], 2))} at {prediction[0]} (delta: {round(prediction[1] - price, 2)})'
                        )
                    except:
                        pass

                if state.last_action == 'BUY':
                    # display support, resistance and fibonacci levels
                    Logger.info(
                        technical_analysis.
                        printSupportResistanceFibonacciLevels(price))

            else:
                Logger.debug('-- Iteration: ' + str(state.iterations) + ' --' +
                             bullbeartext)

                if state.last_action == 'BUY':
                    if state.last_buy_size > 0:
                        margin_text = truncate(margin) + '%'
                    else:
                        margin_text = '0%'

                    Logger.debug('-- Margin: ' + margin_text + ' --')

                Logger.debug('price: ' + truncate(price))
                Logger.debug('ema12: ' +
                             truncate(float(df_last['ema12'].values[0])))
                Logger.debug('ema26: ' +
                             truncate(float(df_last['ema26'].values[0])))
                Logger.debug('ema12gtema26co: ' + str(ema12gtema26co))
                Logger.debug('ema12gtema26: ' + str(ema12gtema26))
                Logger.debug('ema12ltema26co: ' + str(ema12ltema26co))
                Logger.debug('ema12ltema26: ' + str(ema12ltema26))
                Logger.debug('sma50: ' +
                             truncate(float(df_last['sma50'].values[0])))
                Logger.debug('sma200: ' +
                             truncate(float(df_last['sma200'].values[0])))
                Logger.debug('macd: ' +
                             truncate(float(df_last['macd'].values[0])))
                Logger.debug('signal: ' +
                             truncate(float(df_last['signal'].values[0])))
                Logger.debug('macdgtsignal: ' + str(macdgtsignal))
                Logger.debug('macdltsignal: ' + str(macdltsignal))
                Logger.debug('obv: ' + str(obv))
                Logger.debug('obv_pc: ' + str(obv_pc))
                Logger.debug('action: ' + state.action)

                # informational output on the most recent entry
                Logger.info('')
                Logger.info(
                    '================================================================================'
                )
                txt = '        Iteration : ' + str(
                    state.iterations) + bullbeartext
                Logger.info(' | ' + txt + (' ' * (75 - len(txt))) + ' | ')
                txt = '        Timestamp : ' + str(df_last.index.format()[0])
                Logger.info(' | ' + txt + (' ' * (75 - len(txt))) + ' | ')
                Logger.info(
                    '--------------------------------------------------------------------------------'
                )
                txt = '            Close : ' + truncate(price)
                Logger.info(' | ' + txt + (' ' * (75 - len(txt))) + ' | ')
                txt = '            EMA12 : ' + truncate(
                    float(df_last['ema12'].values[0]))
                Logger.info(' | ' + txt + (' ' * (75 - len(txt))) + ' | ')
                txt = '            EMA26 : ' + truncate(
                    float(df_last['ema26'].values[0]))
                Logger.info(' | ' + txt + (' ' * (75 - len(txt))) + ' | ')
                txt = '   Crossing Above : ' + str(ema12gtema26co)
                Logger.info(' | ' + txt + (' ' * (75 - len(txt))) + ' | ')
                txt = '  Currently Above : ' + str(ema12gtema26)
                Logger.info(' | ' + txt + (' ' * (75 - len(txt))) + ' | ')
                txt = '   Crossing Below : ' + str(ema12ltema26co)
                Logger.info(' | ' + txt + (' ' * (75 - len(txt))) + ' | ')
                txt = '  Currently Below : ' + str(ema12ltema26)
                Logger.info(' | ' + txt + (' ' * (75 - len(txt))) + ' | ')

                if (ema12gtema26 is True and ema12gtema26co is True):
                    txt = '        Condition : EMA12 is currently crossing above EMA26'
                elif (ema12gtema26 is True and ema12gtema26co is False):
                    txt = '        Condition : EMA12 is currently above EMA26 and has crossed over'
                elif (ema12ltema26 is True and ema12ltema26co is True):
                    txt = '        Condition : EMA12 is currently crossing below EMA26'
                elif (ema12ltema26 is True and ema12ltema26co is False):
                    txt = '        Condition : EMA12 is currently below EMA26 and has crossed over'
                else:
                    txt = '        Condition : -'
                Logger.info(' | ' + txt + (' ' * (75 - len(txt))) + ' | ')

                txt = '            SMA20 : ' + truncate(
                    float(df_last['sma20'].values[0]))
                Logger.info(' | ' + txt + (' ' * (75 - len(txt))) + ' | ')
                txt = '           SMA200 : ' + truncate(
                    float(df_last['sma200'].values[0]))
                Logger.info(' | ' + txt + (' ' * (75 - len(txt))) + ' | ')

                Logger.info(
                    '--------------------------------------------------------------------------------'
                )
                txt = '             MACD : ' + truncate(
                    float(df_last['macd'].values[0]))
                Logger.info(' | ' + txt + (' ' * (75 - len(txt))) + ' | ')
                txt = '           Signal : ' + truncate(
                    float(df_last['signal'].values[0]))
                Logger.info(' | ' + txt + (' ' * (75 - len(txt))) + ' | ')
                txt = '  Currently Above : ' + str(macdgtsignal)
                Logger.info(' | ' + txt + (' ' * (75 - len(txt))) + ' | ')
                txt = '  Currently Below : ' + str(macdltsignal)
                Logger.info(' | ' + txt + (' ' * (75 - len(txt))) + ' | ')

                if (macdgtsignal is True and macdgtsignalco is True):
                    txt = '        Condition : MACD is currently crossing above Signal'
                elif (macdgtsignal is True and macdgtsignalco is False):
                    txt = '        Condition : MACD is currently above Signal and has crossed over'
                elif (macdltsignal is True and macdltsignalco is True):
                    txt = '        Condition : MACD is currently crossing below Signal'
                elif (macdltsignal is True and macdltsignalco is False):
                    txt = '        Condition : MACD is currently below Signal and has crossed over'
                else:
                    txt = '        Condition : -'
                Logger.info(' | ' + txt + (' ' * (75 - len(txt))) + ' | ')

                Logger.info(
                    '--------------------------------------------------------------------------------'
                )
                txt = '           Action : ' + state.action
                Logger.info(' | ' + txt + (' ' * (75 - len(txt))) + ' | ')
                Logger.info(
                    '================================================================================'
                )
                if state.last_action == 'BUY':
                    txt = '           Margin : ' + margin_text
                    Logger.info(' | ' + txt + (' ' * (75 - len(txt))) + ' | ')
                    Logger.info(
                        '================================================================================'
                    )

            # if a buy signal
            if state.action == 'BUY':
                state.last_buy_price = price
                state.last_buy_high = state.last_buy_price

                # if live
                if app.isLive():
                    app.notifyTelegram(app.getMarket() + ' (' +
                                       app.printGranularity() + ') BUY at ' +
                                       price_text)

                    if not app.isVerbose():
                        Logger.info(formatted_current_df_index + ' | ' +
                                    app.getMarket() + ' | ' +
                                    app.printGranularity() + ' | ' +
                                    price_text + ' | BUY')
                    else:
                        Logger.info(
                            '--------------------------------------------------------------------------------'
                        )
                        Logger.info(
                            '|                      *** Executing LIVE Buy Order ***                        |'
                        )
                        Logger.info(
                            '--------------------------------------------------------------------------------'
                        )

                    # display balances
                    Logger.info(app.getBaseCurrency() +
                                ' balance before order: ' +
                                str(account.getBalance(app.getBaseCurrency())))
                    Logger.info(
                        app.getQuoteCurrency() + ' balance before order: ' +
                        str(account.getBalance(app.getQuoteCurrency())))

                    # execute a live market buy
                    state.last_buy_size = float(
                        account.getBalance(app.getQuoteCurrency()))
                    if app.getBuyMaxSize(
                    ) and state.last_buy_size > app.getBuyMaxSize():
                        state.last_buy_size = app.getBuyMaxSize()

                    resp = app.marketBuy(app.getMarket(), state.last_buy_size,
                                         app.getBuyPercent())
                    Logger.debug(resp)

                    # display balances
                    Logger.info(app.getBaseCurrency() +
                                ' balance after order: ' +
                                str(account.getBalance(app.getBaseCurrency())))
                    Logger.info(
                        app.getQuoteCurrency() + ' balance after order: ' +
                        str(account.getBalance(app.getQuoteCurrency())))
                # if not live
                else:
                    app.notifyTelegram(app.getMarket() + ' (' +
                                       app.printGranularity() +
                                       ') TEST BUY at ' + price_text)
                    # TODO: Improve simulator calculations by including calculations for buy and sell limit configurations.
                    if state.last_buy_size == 0 and state.last_buy_filled == 0:
                        state.last_buy_size = 1000
                        state.first_buy_size = 1000

                    state.buy_count = state.buy_count + 1
                    state.buy_sum = state.buy_sum + state.last_buy_size

                    if not app.isVerbose():
                        Logger.info(formatted_current_df_index + ' | ' +
                                    app.getMarket() + ' | ' +
                                    app.printGranularity() + ' | ' +
                                    price_text + ' | BUY')

                        bands = technical_analysis.getFibonacciRetracementLevels(
                            float(price))
                        Logger.info(' Fibonacci Retracement Levels:' +
                                    str(bands))
                        technical_analysis.printSupportResistanceLevel(
                            float(price))

                        if len(bands) >= 1 and len(bands) <= 2:
                            if len(bands) == 1:
                                first_key = list(bands.keys())[0]
                                if first_key == 'ratio1':
                                    state.fib_low = 0
                                    state.fib_high = bands[first_key]
                                if first_key == 'ratio1_618':
                                    state.fib_low = bands[first_key]
                                    state.fib_high = bands[first_key] * 2
                                else:
                                    state.fib_low = bands[first_key]

                            elif len(bands) == 2:
                                first_key = list(bands.keys())[0]
                                second_key = list(bands.keys())[1]
                                state.fib_low = bands[first_key]
                                state.fib_high = bands[second_key]

                    else:
                        Logger.info(
                            '--------------------------------------------------------------------------------'
                        )
                        Logger.info(
                            '|                      *** Executing TEST Buy Order ***                        |'
                        )
                        Logger.info(
                            '--------------------------------------------------------------------------------'
                        )

                if app.shouldSaveGraphs():
                    tradinggraphs = TradingGraphs(technical_analysis)
                    ts = datetime.now().timestamp()
                    filename = app.getMarket() + '_' + app.printGranularity(
                    ) + '_buy_' + str(ts) + '.png'
                    tradinggraphs.renderEMAandMACD(len(trading_data),
                                                   'graphs/' + filename, True)

            # if a sell signal
            elif state.action == 'SELL':
                # if live
                if app.isLive():
                    app.notifyTelegram(
                        app.getMarket() + ' (' + app.printGranularity() +
                        ') SELL at ' + price_text + ' (margin: ' +
                        margin_text + ', (delta: ' +
                        str(round(price - state.last_buy_price, precision)) +
                        ')')

                    if not app.isVerbose():
                        Logger.info(formatted_current_df_index + ' | ' +
                                    app.getMarket() + ' | ' +
                                    app.printGranularity() + ' | ' +
                                    price_text + ' | SELL')

                        bands = technical_analysis.getFibonacciRetracementLevels(
                            float(price))
                        Logger.info(' Fibonacci Retracement Levels:' +
                                    str(bands))

                        if len(bands) >= 1 and len(bands) <= 2:
                            if len(bands) == 1:
                                first_key = list(bands.keys())[0]
                                if first_key == 'ratio1':
                                    state.fib_low = 0
                                    state.fib_high = bands[first_key]
                                if first_key == 'ratio1_618':
                                    state.fib_low = bands[first_key]
                                    state.fib_high = bands[first_key] * 2
                                else:
                                    state.fib_low = bands[first_key]

                            elif len(bands) == 2:
                                first_key = list(bands.keys())[0]
                                second_key = list(bands.keys())[1]
                                state.fib_low = bands[first_key]
                                state.fib_high = bands[second_key]

                    else:
                        Logger.info(
                            '--------------------------------------------------------------------------------'
                        )
                        Logger.info(
                            '|                      *** Executing LIVE Sell Order ***                        |'
                        )
                        Logger.info(
                            '--------------------------------------------------------------------------------'
                        )

                    # display balances
                    Logger.info(app.getBaseCurrency() +
                                ' balance before order: ' +
                                str(account.getBalance(app.getBaseCurrency())))
                    Logger.info(
                        app.getQuoteCurrency() + ' balance before order: ' +
                        str(account.getBalance(app.getQuoteCurrency())))

                    # execute a live market sell
                    resp = app.marketSell(
                        app.getMarket(),
                        float(account.getBalance(app.getBaseCurrency())),
                        app.getSellPercent())
                    Logger.debug(resp)

                    # display balances
                    Logger.info(app.getBaseCurrency() +
                                ' balance after order: ' +
                                str(account.getBalance(app.getBaseCurrency())))
                    Logger.info(
                        app.getQuoteCurrency() + ' balance after order: ' +
                        str(account.getBalance(app.getQuoteCurrency())))

                # if not live
                else:
                    margin, profit, sell_fee = calculate_margin(
                        buy_size=state.last_buy_size,
                        buy_filled=state.last_buy_filled,
                        buy_price=state.last_buy_price,
                        buy_fee=state.last_buy_fee,
                        sell_percent=app.getSellPercent(),
                        sell_price=price,
                        sell_taker_fee=app.getTakerFee())

                    if state.last_buy_size > 0:
                        margin_text = truncate(margin) + '%'
                    else:
                        margin_text = '0%'
                    app.notifyTelegram(
                        app.getMarket() + ' (' + app.printGranularity() +
                        ') TEST SELL at ' + price_text + ' (margin: ' +
                        margin_text + ', (delta: ' +
                        str(round(price - state.last_buy_price, precision)) +
                        ')')

                    # Preserve next buy values for simulator
                    state.sell_count = state.sell_count + 1
                    buy_size = ((app.getSellPercent() / 100) *
                                ((price / state.last_buy_price) *
                                 (state.last_buy_size - state.last_buy_fee)))
                    state.last_buy_size = buy_size - sell_fee
                    state.sell_sum = state.sell_sum + state.last_buy_size

                    if not app.isVerbose():
                        if price > 0:
                            margin_text = truncate(margin) + '%'
                        else:
                            margin_text = '0%'

                        Logger.info(formatted_current_df_index + ' | ' +
                                    app.getMarket() + ' | ' +
                                    app.printGranularity() + ' | SELL | ' +
                                    str(price) + ' | BUY | ' +
                                    str(state.last_buy_price) + ' | DIFF | ' +
                                    str(price - state.last_buy_price) +
                                    ' | DIFF | ' + str(profit) +
                                    ' | MARGIN NO FEES | ' + margin_text +
                                    ' | MARGIN FEES | ' +
                                    str(round(sell_fee, precision)))

                    else:
                        Logger.info(
                            '--------------------------------------------------------------------------------'
                        )
                        Logger.info(
                            '|                      *** Executing TEST Sell Order ***                        |'
                        )
                        Logger.info(
                            '--------------------------------------------------------------------------------'
                        )

                if app.shouldSaveGraphs():
                    tradinggraphs = TradingGraphs(technical_analysis)
                    ts = datetime.now().timestamp()
                    filename = app.getMarket() + '_' + app.printGranularity(
                    ) + '_sell_' + str(ts) + '.png'
                    tradinggraphs.renderEMAandMACD(len(trading_data),
                                                   'graphs/' + filename, True)

            # last significant action
            if state.action in ['BUY', 'SELL']:
                state.last_action = state.action

            state.last_df_index = str(df_last.index.format()[0])

            if not app.isLive() and state.iterations == len(df):
                Logger.info("\nSimulation Summary: ")

                if state.buy_count > state.sell_count and app.allowSellAtLoss(
                ):
                    # Calculate last sell size
                    state.last_buy_size = ((app.getSellPercent() / 100) * (
                        (price / state.last_buy_price) *
                        (state.last_buy_size - state.last_buy_fee)))
                    # Reduce sell fee from last sell size
                    state.last_buy_size = state.last_buy_size - state.last_buy_price * app.getTakerFee(
                    )
                    state.sell_sum = state.sell_sum + state.last_buy_size
                    state.sell_count = state.sell_count + 1

                elif state.buy_count > state.sell_count and not app.allowSellAtLoss(
                ):
                    Logger.info("\n")
                    Logger.info(
                        '        Note : "sell at loss" is disabled and you have an open trade, if the margin'
                    )
                    Logger.info(
                        '               result below is negative it will assume you sold at the end of the'
                    )
                    Logger.info(
                        '               simulation which may not be ideal. Try setting --sellatloss 1'
                    )

                Logger.info("\n")
                Logger.info('   Buy Count : ' + str(state.buy_count))
                Logger.info('  Sell Count : ' + str(state.sell_count))
                Logger.info('   First Buy : ' + str(state.first_buy_size))
                Logger.info('   Last Sell : ' + str(state.last_buy_size))

                app.notifyTelegram(
                    f"Simulation Summary\n   Buy Count: {state.buy_count}\n   Sell Count: {state.sell_count}\n   First Buy: {state.first_buy_size}\n   Last Sell: {state.last_buy_size}\n"
                )

                if state.sell_count > 0:
                    Logger.info("\n")
                    Logger.info('      Margin : ' + _truncate((
                        ((state.last_buy_size - state.first_buy_size) /
                         state.first_buy_size) * 100), 4) + '%')
                    Logger.info("\n")
                    Logger.info(
                        '  ** non-live simulation, assuming highest fees')
                    app.notifyTelegram(
                        f"      Margin: {_truncate((((state.last_buy_size - state.first_buy_size) / state.first_buy_size) * 100), 4)}%\n  ** non-live simulation, assuming highest fees\n"
                    )

        else:
            if state.last_buy_size > 0 and state.last_buy_price > 0 and price > 0 and state.last_action == 'BUY':
                # show profit and margin if already bought
                Logger.info(now + ' | ' + app.getMarket() + bullbeartext +
                            ' | ' + app.printGranularity() +
                            ' | Current Price: ' + str(price) + ' | Margin: ' +
                            str(margin) + ' | Profit: ' + str(profit))
            else:
                Logger.info(now + ' | ' + app.getMarket() + bullbeartext +
                            ' | ' + app.printGranularity() +
                            ' | Current Price: ' + str(price))

            # decrement ignored iteration
            state.iterations = state.iterations - 1

        # if live
        if not app.disableTracker() and app.isLive():
            # update order tracker csv
            if app.getExchange() == 'binance':
                account.saveTrackerCSV(app.getMarket())
            elif app.getExchange() == 'coinbasepro':
                account.saveTrackerCSV()

        if app.isSimulation():
            if state.iterations < 300:
                if app.simuluationSpeed() in ['fast', 'fast-sample']:
                    # fast processing
                    list(map(s.cancel, s.queue))
                    s.enter(0, 1, executeJob, (sc, app, state, df))
                else:
                    # slow processing
                    list(map(s.cancel, s.queue))
                    s.enter(1, 1, executeJob, (sc, app, state, df))

        else:
            # poll every 1 minute
            list(map(s.cancel, s.queue))
            s.enter(60, 1, executeJob, (sc, app, state))
Ejemplo n.º 6
0
def executeJob(sc, app=PyCryptoBot(), trading_data=pd.DataFrame()):
    """Trading bot job which runs at a scheduled interval"""
    global action, buy_count, buy_sum, iterations, last_action, last_buy, eri_text, last_df_index, sell_count, sell_sum, buy_state, fib_high, fib_low

    # increment iterations
    iterations = iterations + 1

    if app.isSimulation() == 0:
        # retrieve the app.getMarket() data
        trading_data = app.getHistoricalData(app.getMarket(), app.getGranularity())
    else:
        if len(trading_data) == 0:
            return None

    # analyse the market data
    trading_dataCopy = trading_data.copy()
    ta = TechnicalAnalysis(trading_dataCopy)
    ta.addAll()
    df = ta.getDataFrame()

    if app.isSimulation() == 1:
        # with a simulation df_last will iterate through data
        df_last = df.iloc[iterations-1:iterations]
    else:
        # df_last contains the most recent entry
        df_last = df.tail(1)
    
    if len(df_last.index.format()) > 0:
        current_df_index = str(df_last.index.format()[0])
    else:
        current_df_index = last_df_index

    if app.getSmartSwitch() == 1 and app.getExchange() == 'binance' and app.getGranularity() == '1h' and app.is1hEMA1226Bull() == True and app.is6hEMA1226Bull() == True:
        print ("*** smart switch from granularity '1h' (1 hour) to '15m' (15 min) ***")

        # telegram
        if app.isTelegramEnabled():
            telegram = Telegram(app.getTelegramToken(), app.getTelegramClientId())
            telegram.send(app.getMarket() + " smart switch from granularity '1h' (1 hour) to '15m' (15 min)")

        app.setGranularity('15m')
        list(map(s.cancel, s.queue))
        s.enter(5, 1, executeJob, (sc, app))

    elif app.getSmartSwitch() == 1 and app.getExchange() == 'coinbasepro' and app.getGranularity() == 3600 and app.is1hEMA1226Bull() == True and app.is6hEMA1226Bull() == True:
        print ('*** smart switch from granularity 3600 (1 hour) to 900 (15 min) ***')

        # telegram
        if app.isTelegramEnabled():
            telegram = Telegram(app.getTelegramToken(), app.getTelegramClientId())
            telegram.send(app.getMarket() + " smart switch from granularity 3600 (1 hour) to 900 (15 min)")

        app.setGranularity(900)
        list(map(s.cancel, s.queue))
        s.enter(5, 1, executeJob, (sc, app))

    if app.getSmartSwitch() == 1 and app.getExchange() == 'binance' and app.getGranularity() == '15m' and app.is1hEMA1226Bull() == False and app.is6hEMA1226Bull() == False:
        print ("*** smart switch from granularity '15m' (15 min) to '1h' (1 hour) ***")

        # telegram
        if app.isTelegramEnabled():
            telegram = Telegram(app.getTelegramToken(), app.getTelegramClientId())
            telegram.send(app.getMarket() + " smart switch from granularity '15m' (15 min) to '1h' (1 hour)")

        app.setGranularity('1h')
        list(map(s.cancel, s.queue))
        s.enter(5, 1, executeJob, (sc, app))

    elif app.getSmartSwitch() == 1 and app.getExchange() == 'coinbasepro' and app.getGranularity() == 900 and app.is1hEMA1226Bull() == False and app.is6hEMA1226Bull() == False:
        print ("*** smart switch from granularity 900 (15 min) to 3600 (1 hour) ***")

        # telegram
        if app.isTelegramEnabled():
            telegram = Telegram(app.getTelegramToken(), app.getTelegramClientId())
            telegram.send(app.getMarket() + " smart switch from granularity 900 (15 min) to 3600 (1 hour)")

        app.setGranularity(3600)
        list(map(s.cancel, s.queue))
        s.enter(5, 1, executeJob, (sc, app))

    if app.getExchange() == 'binance' and str(app.getGranularity()) == '1d':
        if len(df) < 250:
            # data frame should have 250 rows, if not retry
            print('error: data frame length is < 250 (' + str(len(df)) + ')')
            logging.error('error: data frame length is < 250 (' + str(len(df)) + ')')
            list(map(s.cancel, s.queue))
            s.enter(300, 1, executeJob, (sc, app))
    else:
        if len(df) < 300:
            # data frame should have 300 rows, if not retry
            print('error: data frame length is < 300 (' + str(len(df)) + ')')
            logging.error('error: data frame length is < 300 (' + str(len(df)) + ')')
            list(map(s.cancel, s.queue))
            s.enter(300, 1, executeJob, (sc, app))

    if len(df_last) > 0:
        if app.isSimulation() == 0:
            price = app.getTicker(app.getMarket())
            if price < df_last['low'].values[0] or price == 0:
                price = float(df_last['close'].values[0])
        else:
            price = float(df_last['close'].values[0])

        if price < 0.0001:
            raise Exception(app.getMarket() + ' is unsuitable for trading, quote price is less than 0.0001!')

        # technical indicators
        ema12gtema26 = bool(df_last['ema12gtema26'].values[0])
        ema12gtema26co = bool(df_last['ema12gtema26co'].values[0])
        goldencross = bool(df_last['goldencross'].values[0])
        #deathcross = bool(df_last['deathcross'].values[0])
        macdgtsignal = bool(df_last['macdgtsignal'].values[0])
        macdgtsignalco = bool(df_last['macdgtsignalco'].values[0])
        ema12ltema26 = bool(df_last['ema12ltema26'].values[0])
        ema12ltema26co = bool(df_last['ema12ltema26co'].values[0])
        macdltsignal = bool(df_last['macdltsignal'].values[0])
        macdltsignalco = bool(df_last['macdltsignalco'].values[0])
        obv = float(df_last['obv'].values[0])
        obv_pc = float(df_last['obv_pc'].values[0])
        elder_ray_buy = bool(df_last['eri_buy'].values[0])
        elder_ray_sell = bool(df_last['eri_sell'].values[0])

        # candlestick detection
        hammer = bool(df_last['hammer'].values[0])
        inverted_hammer = bool(df_last['inverted_hammer'].values[0])
        hanging_man = bool(df_last['hanging_man'].values[0])
        shooting_star = bool(df_last['shooting_star'].values[0])
        three_white_soldiers = bool(df_last['three_white_soldiers'].values[0])
        three_black_crows = bool(df_last['three_black_crows'].values[0])
        morning_star = bool(df_last['morning_star'].values[0])
        evening_star = bool(df_last['evening_star'].values[0])
        three_line_strike = bool(df_last['three_line_strike'].values[0])
        abandoned_baby = bool(df_last['abandoned_baby'].values[0])
        morning_doji_star = bool(df_last['morning_doji_star'].values[0])
        evening_doji_star = bool(df_last['evening_doji_star'].values[0])
        two_black_gapping = bool(df_last['two_black_gapping'].values[0])

        # criteria for a buy signal
        if ema12gtema26co == True and macdgtsignal == True and goldencross == True and obv_pc > -5 and elder_ray_buy == True and last_action != 'BUY':
            action = 'BUY'
        # criteria for a sell signal
        elif ema12ltema26co == True and macdltsignal == True and last_action not in ['','SELL']:
            action = 'SELL'
        # anything other than a buy or sell, just wait
        else:
            action = 'WAIT'

        last_buy_minus_fees = 0
        if last_buy > 0 and last_action == 'BUY':
            change_pcnt = ((price / last_buy) - 1) * 100

            # calculate last buy minus fees
            fee = last_buy * 0.005
            last_buy_minus_fees = last_buy + fee
            margin = ((price - last_buy_minus_fees) / price) * 100

            # loss failsafe sell at fibonacci band
            if app.allowSellAtLoss() and app.sellLowerPcnt() == None and fib_low > 0 and fib_low >= float(price):
                action = 'SELL'
                last_action = 'BUY'
                log_text = '! Loss Failsafe Triggered (Fibonacci Band: ' + str(fib_low) + ')'
                print (log_text, "\n")
                logging.warning(log_text)

                # telegram
                if app.isTelegramEnabled():
                    telegram = Telegram(app.getTelegramToken(), app.getTelegramClientId())
                    telegram.send(app.getMarket() + ' (' + str(app.getGranularity()) + ') ' + log_text)

            # loss failsafe sell at sell_lower_pcnt
            if app.allowSellAtLoss() and app.sellLowerPcnt() != None and change_pcnt < app.sellLowerPcnt():
                action = 'SELL'
                last_action = 'BUY'
                log_text = '! Loss Failsafe Triggered (< ' + str(app.sellLowerPcnt()) + '%)'
                print (log_text, "\n")
                logging.warning(log_text)

                # telegram
                if app.isTelegramEnabled():
                    telegram = Telegram(app.getTelegramToken(), app.getTelegramClientId())
                    telegram.send(app.getMarket() + ' (' + str(app.getGranularity()) + ') ' + log_text)

            if app.getSmartSwitch() == 1 and app.getExchange() == 'binance' and app.getGranularity() == '15m' and change_pcnt >= 2:
                # profit bank at 2% in smart switched mode
                action = 'SELL'
                last_action = 'BUY'
                log_text = '! Profit Bank Triggered (Smart Switch 2%)'
                print (log_text, "\n")
                logging.warning(log_text)

                # telegram
                if app.isTelegramEnabled():
                    telegram = Telegram(app.getTelegramToken(), app.getTelegramClientId())
                    telegram.send(app.getMarket() + ' (' + str(app.getGranularity()) + ') ' + log_text)

            if app.getSmartSwitch() == 1 and app.getExchange() == 'coinbasepro' and app.getGranularity() == 900 and change_pcnt >= 2:
                # profit bank at 2% in smart switched mode
                action = 'SELL'
                last_action = 'BUY'
                log_text = '! Profit Bank Triggered (Smart Switch 2%)'
                print (log_text, "\n")
                logging.warning(log_text)

                # telegram
                if app.isTelegramEnabled():
                    telegram = Telegram(app.getTelegramToken(), app.getTelegramClientId())
                    telegram.send(app.getMarket() + ' (' + str(app.getGranularity()) + ') ' + log_text)

            # profit bank at sell_upper_pcnt
            if app.sellUpperPcnt() != None and change_pcnt > app.sellUpperPcnt():
                action = 'SELL'
                last_action = 'BUY'
                log_text = '! Profit Bank Triggered (> ' + str(app.sellUpperPcnt()) + '%)'
                print (log_text, "\n")
                logging.warning(log_text)

                # telegram
                if app.isTelegramEnabled():
                    telegram = Telegram(app.getTelegramToken(), app.getTelegramClientId())
                    telegram.send(app.getMarket() + ' (' + str(app.getGranularity()) + ') ' + log_text)

            # profit bank at sell at fibonacci band
            if margin > 3 and app.sellUpperPcnt() != None and fib_high > fib_low and fib_high <= float(price):
                action = 'SELL'
                last_action = 'BUY'
                log_text = '! Profit Bank Triggered (Fibonacci Band: ' + str(fib_high) + ')'
                print (log_text, "\n")
                logging.warning(log_text)

                # telegram
                if app.isTelegramEnabled():
                    telegram = Telegram(app.getTelegramToken(), app.getTelegramClientId())
                    telegram.send(app.getMarket() + ' (' + str(app.getGranularity()) + ') ' + log_text)

            # profit bank when strong reversal detected
            if margin > 3 and obv_pc < 0 and macdltsignal == True:
                action = 'SELL'
                last_action = 'BUY'
                log_text = '! Profit Bank Triggered (Strong Reversal Detected)'
                print (log_text, "\n")
                logging.warning(log_text)

                # telegram
                if app.isTelegramEnabled():
                    telegram = Telegram(app.getTelegramToken(), app.getTelegramClientId())
                    telegram.send(app.getMarket() + ' (' + str(app.getGranularity()) + ') ' + log_text)

            # configuration specifies to not sell at a loss
            if not app.allowSellAtLoss() and margin <= 0:
                action = 'WAIT'
                last_action = 'BUY'
                log_text = '! Ignore Sell Signal (No Sell At Loss)'
                print (log_text, "\n")
                logging.warning(log_text)

        bullbeartext = ''
        if df_last['sma50'].values[0] == df_last['sma200'].values[0]:
            bullbeartext = ''
        elif goldencross == True:
            bullbeartext = ' (BULL)'
        elif goldencross == False:
            bullbeartext = ' (BEAR)'

        # polling is every 5 minutes (even for hourly intervals), but only process once per interval
        if (last_df_index != current_df_index):
            precision = 2

            if (price < 0.01):
                precision = 8

            price_text = 'Close: ' + str(app.truncate(price, precision))
            ema_text = app.compare(df_last['ema12'].values[0], df_last['ema26'].values[0], 'EMA12/26', precision)
            macd_text = app.compare(df_last['macd'].values[0], df_last['signal'].values[0], 'MACD', precision)
            obv_text = 'OBV: ' + str(app.truncate(df_last['obv'].values[0], 4)) + ' (' + str(app.truncate(df_last['obv_pc'].values[0], 2)) + '%)'

            if elder_ray_buy == True:
                eri_text = 'ERI: buy'
            elif elder_ray_sell == True:
                eri_text = 'ERI: sell'
            else:
                eri_text = 'ERI:'

            if hammer == True:
                log_text = '* Candlestick Detected: Hammer ("Weak - Reversal - Bullish Signal - Up")'
                print (log_text, "\n")
                logging.debug(log_text)

            if shooting_star == True:
                log_text = '* Candlestick Detected: Shooting Star ("Weak - Reversal - Bearish Pattern - Down")'
                print (log_text, "\n")
                logging.debug(log_text)

            if hanging_man == True:
                log_text = '* Candlestick Detected: Hanging Man ("Weak - Continuation - Bearish Pattern - Down")'
                print (log_text, "\n")
                logging.debug(log_text)

            if inverted_hammer == True:
                log_text = '* Candlestick Detected: Inverted Hammer ("Weak - Continuation - Bullish Pattern - Up")'
                print (log_text, "\n")
                logging.debug(log_text)
   
            if three_white_soldiers == True:
                log_text = '*** Candlestick Detected: Three White Soldiers ("Strong - Reversal - Bullish Pattern - Up")'
                print (log_text, "\n")
                logging.debug(log_text)

                # telegram
                if app.isTelegramEnabled():
                    telegram = Telegram(app.getTelegramToken(), app.getTelegramClientId())
                    telegram.send(app.getMarket() + ' (' + str(app.getGranularity()) + ') ' + log_text)

            if three_black_crows == True:
                log_text = '* Candlestick Detected: Three Black Crows ("Strong - Reversal - Bearish Pattern - Down")'
                print (log_text, "\n")
                logging.debug(log_text)

                # telegram
                if app.isTelegramEnabled():
                    telegram = Telegram(app.getTelegramToken(), app.getTelegramClientId())
                    telegram.send(app.getMarket() + ' (' + str(app.getGranularity()) + ') ' + log_text)

            if morning_star == True:
                log_text = '*** Candlestick Detected: Morning Star ("Strong - Reversal - Bullish Pattern - Up")'
                print (log_text, "\n")
                logging.debug(log_text)

                # telegram
                if app.isTelegramEnabled():
                    telegram = Telegram(app.getTelegramToken(), app.getTelegramClientId())
                    telegram.send(app.getMarket() + ' (' + str(app.getGranularity()) + ') ' + log_text)

            if evening_star == True:
                log_text = '*** Candlestick Detected: Evening Star ("Strong - Reversal - Bearish Pattern - Down")'
                print (log_text, "\n")
                logging.debug(log_text)

                # telegram
                if app.isTelegramEnabled():
                    telegram = Telegram(app.getTelegramToken(), app.getTelegramClientId())
                    telegram.send(app.getMarket() + ' (' + str(app.getGranularity()) + ') ' + log_text)

            if three_line_strike == True:
                log_text = '** Candlestick Detected: Three Line Strike ("Reliable - Reversal - Bullish Pattern - Up")'
                print (log_text, "\n")
                logging.debug(log_text)

                # telegram
                if app.isTelegramEnabled():
                    telegram = Telegram(app.getTelegramToken(), app.getTelegramClientId())
                    telegram.send(app.getMarket() + ' (' + str(app.getGranularity()) + ') ' + log_text)

            if abandoned_baby == True:
                log_text = '** Candlestick Detected: Abandoned Baby ("Reliable - Reversal - Bullish Pattern - Up")'
                print (log_text, "\n")
                logging.debug(log_text)

                # telegram
                if app.isTelegramEnabled():
                    telegram = Telegram(app.getTelegramToken(), app.getTelegramClientId())
                    telegram.send(app.getMarket() + ' (' + str(app.getGranularity()) + ') ' + log_text)

            if morning_doji_star == True:
                log_text = '** Candlestick Detected: Morning Doji Star ("Reliable - Reversal - Bullish Pattern - Up")'
                print (log_text, "\n")
                logging.debug(log_text)

                # telegram
                if app.isTelegramEnabled():
                    telegram = Telegram(app.getTelegramToken(), app.getTelegramClientId())
                    telegram.send(app.getMarket() + ' (' + str(app.getGranularity()) + ') ' + log_text)

            if evening_doji_star == True:
                log_text = '** Candlestick Detected: Evening Doji Star ("Reliable - Reversal - Bearish Pattern - Down")'
                print (log_text, "\n")
                logging.debug(log_text)

                # telegram
                if app.isTelegramEnabled():
                    telegram = Telegram(app.getTelegramToken(), app.getTelegramClientId())
                    telegram.send(app.getMarket() + ' (' + str(app.getGranularity()) + ') ' + log_text)

            if two_black_gapping == True:
                log_text = '*** Candlestick Detected: Two Black Gapping ("Reliable - Reversal - Bearish Pattern - Down")'
                print (log_text, "\n")
                logging.debug(log_text)

                # telegram
                if app.isTelegramEnabled():
                    telegram = Telegram(app.getTelegramToken(), app.getTelegramClientId())
                    telegram.send(app.getMarket() + ' (' + str(app.getGranularity()) + ') ' + log_text)

            ema_co_prefix = ''
            ema_co_suffix = ''
            if ema12gtema26co == True:
                ema_co_prefix = '*^ '
                ema_co_suffix = ' ^*'
            elif ema12ltema26co == True:
                ema_co_prefix = '*v '
                ema_co_suffix = ' v*'   
            elif ema12gtema26 == True:
                ema_co_prefix = '^ '
                ema_co_suffix = ' ^'
            elif ema12ltema26 == True:
                ema_co_prefix = 'v '
                ema_co_suffix = ' v'

            macd_co_prefix = ''
            macd_co_suffix = ''
            if macdgtsignalco == True:
                macd_co_prefix = '*^ '
                macd_co_suffix = ' ^*'
            elif macdltsignalco == True:
                macd_co_prefix = '*v '
                macd_co_suffix = ' v*'
            elif macdgtsignal == True:
                macd_co_prefix = '^ '
                macd_co_suffix = ' ^'
            elif macdltsignal == True:
                macd_co_prefix = 'v '
                macd_co_suffix = ' v'

            obv_prefix = ''
            obv_suffix = ''
            if float(obv_pc) > 0:
                obv_prefix = '^ '
                obv_suffix = ' ^'
            elif float(obv_pc) < 0:
                obv_prefix = 'v '
                obv_suffix = ' v'

            if app.isVerbose() == 0:
                if last_action != '':
                    output_text = current_df_index + ' | ' + app.getMarket() + bullbeartext + ' | ' + str(app.getGranularity()) + ' | ' + price_text + ' | ' + ema_co_prefix + ema_text + ema_co_suffix + ' | ' + macd_co_prefix + macd_text + macd_co_suffix + ' | ' + obv_prefix + obv_text + obv_suffix + ' | ' + eri_text + ' | ' + action + ' | Last Action: ' + last_action
                else:
                    output_text = current_df_index + ' | ' + app.getMarket() + bullbeartext + ' | ' + str(app.getGranularity()) + ' | ' + price_text + ' | ' + ema_co_prefix + ema_text + ema_co_suffix + ' | ' + macd_co_prefix + macd_text + macd_co_suffix + ' | ' + obv_prefix + obv_text + obv_suffix + ' | ' + eri_text + ' | ' + action + ' '

                if last_action == 'BUY':
                    if last_buy_minus_fees > 0:
                        margin = str(app.truncate((((price - last_buy_minus_fees) / price) * 100), 2)) + '%'
                    else:
                        margin = '0%'

                    output_text += ' | ' +  margin

                logging.debug(output_text)
                print (output_text)
            else:
                logging.debug('-- Iteration: ' + str(iterations) + ' --' + bullbeartext)

                if last_action == 'BUY':
                    margin = str(app.truncate((((price - last_buy) / price) * 100), 2)) + '%'
                    logging.debug('-- Margin: ' + margin + '% --')            
                
                logging.debug('price: ' + str(app.truncate(price, precision)))
                logging.debug('ema12: ' + str(app.truncate(float(df_last['ema12'].values[0]), precision)))
                logging.debug('ema26: ' + str(app.truncate(float(df_last['ema26'].values[0]), precision)))
                logging.debug('ema12gtema26co: ' + str(ema12gtema26co))
                logging.debug('ema12gtema26: ' + str(ema12gtema26))
                logging.debug('ema12ltema26co: ' + str(ema12ltema26co))
                logging.debug('ema12ltema26: ' + str(ema12ltema26))
                logging.debug('sma50: ' + str(app.truncate(float(df_last['sma50'].values[0]), precision)))
                logging.debug('sma200: ' + str(app.truncate(float(df_last['sma200'].values[0]), precision)))
                logging.debug('macd: ' + str(app.truncate(float(df_last['macd'].values[0]), precision)))
                logging.debug('signal: ' + str(app.truncate(float(df_last['signal'].values[0]), precision)))
                logging.debug('macdgtsignal: ' + str(macdgtsignal))
                logging.debug('macdltsignal: ' + str(macdltsignal))
                logging.debug('obv: ' + str(obv))
                logging.debug('obv_pc: ' + str(obv_pc))
                logging.debug('action: ' + action)

                # informational output on the most recent entry  
                print('')
                print('================================================================================')
                txt = '        Iteration : ' + str(iterations) + bullbeartext
                print('|', txt, (' ' * (75 - len(txt))), '|')
                txt = '        Timestamp : ' + str(df_last.index.format()[0])
                print('|', txt, (' ' * (75 - len(txt))), '|')
                print('--------------------------------------------------------------------------------')
                txt = '            Close : ' + str(app.truncate(price, precision))
                print('|', txt, (' ' * (75 - len(txt))), '|')
                txt = '            EMA12 : ' + str(app.truncate(float(df_last['ema12'].values[0]), precision))
                print('|', txt, (' ' * (75 - len(txt))), '|')
                txt = '            EMA26 : ' + str(app.truncate(float(df_last['ema26'].values[0]), precision))
                print('|', txt, (' ' * (75 - len(txt))), '|')               
                txt = '   Crossing Above : ' + str(ema12gtema26co)
                print('|', txt, (' ' * (75 - len(txt))), '|')
                txt = '  Currently Above : ' + str(ema12gtema26)
                print('|', txt, (' ' * (75 - len(txt))), '|')
                txt = '   Crossing Below : ' + str(ema12ltema26co)
                print('|', txt, (' ' * (75 - len(txt))), '|')
                txt = '  Currently Below : ' + str(ema12ltema26)
                print('|', txt, (' ' * (75 - len(txt))), '|')

                if (ema12gtema26 == True and ema12gtema26co == True):
                    txt = '        Condition : EMA12 is currently crossing above EMA26'
                elif (ema12gtema26 == True and ema12gtema26co == False):
                    txt = '        Condition : EMA12 is currently above EMA26 and has crossed over'
                elif (ema12ltema26 == True and ema12ltema26co == True):
                    txt = '        Condition : EMA12 is currently crossing below EMA26'
                elif (ema12ltema26 == True and ema12ltema26co == False):
                    txt = '        Condition : EMA12 is currently below EMA26 and has crossed over'
                else:
                    txt = '        Condition : -'
                print('|', txt, (' ' * (75 - len(txt))), '|')

                txt = '            SMA20 : ' + str(app.truncate(float(df_last['sma20'].values[0]), precision))
                print('|', txt, (' ' * (75 - len(txt))), '|')
                txt = '           SMA200 : ' + str(app.truncate(float(df_last['sma200'].values[0]), precision))
                print('|', txt, (' ' * (75 - len(txt))), '|')

                print('--------------------------------------------------------------------------------')
                txt = '             MACD : ' + str(app.truncate(float(df_last['macd'].values[0]), precision))
                print('|', txt, (' ' * (75 - len(txt))), '|')
                txt = '           Signal : ' + str(app.truncate(float(df_last['signal'].values[0]), precision))
                print('|', txt, (' ' * (75 - len(txt))), '|')
                txt = '  Currently Above : ' + str(macdgtsignal)
                print('|', txt, (' ' * (75 - len(txt))), '|')
                txt = '  Currently Below : ' + str(macdltsignal)
                print('|', txt, (' ' * (75 - len(txt))), '|')

                if (macdgtsignal == True and macdgtsignalco == True):
                    txt = '        Condition : MACD is currently crossing above Signal'
                elif (macdgtsignal == True and macdgtsignalco == False):
                    txt = '        Condition : MACD is currently above Signal and has crossed over'
                elif (macdltsignal == True and macdltsignalco == True):
                    txt = '        Condition : MACD is currently crossing below Signal'
                elif (macdltsignal == True and macdltsignalco == False):
                    txt = '        Condition : MACD is currently below Signal and has crossed over'
                else:
                    txt = '        Condition : -'
                print('|', txt, (' ' * (75 - len(txt))), '|')

                print('--------------------------------------------------------------------------------')
                txt = '           Action : ' + action
                print('|', txt, (' ' * (75 - len(txt))), '|')
                print('================================================================================')
                if last_action == 'BUY':
                    txt = '           Margin : ' + margin + '%'
                    print('|', txt, (' ' * (75 - len(txt))), '|')
                    print('================================================================================')

            # if a buy signal
            if action == 'BUY':
                last_buy = price
                buy_count = buy_count + 1
                fee = float(price) * 0.005
                price_incl_fees = float(price) + fee
                buy_sum = buy_sum + price_incl_fees

                # if live
                if app.isLive() == 1:
                    # telegram
                    if app.isTelegramEnabled():
                        telegram = Telegram(app.getTelegramToken(), app.getTelegramClientId())
                        telegram.send(app.getMarket() + ' (' + str(app.getGranularity()) + ') BUY at ' + price_text)

                    if app.isVerbose() == 0:
                        logging.info(current_df_index + ' | ' + app.getMarket() + ' ' + str(app.getGranularity()) + ' | ' + price_text + ' | BUY')
                        print ("\n", current_df_index, '|', app.getMarket(), str(app.getGranularity()), '|', price_text, '| BUY', "\n")                    
                    else:
                        print('--------------------------------------------------------------------------------')
                        print('|                      *** Executing LIVE Buy Order ***                        |')
                        print('--------------------------------------------------------------------------------')
                    
                    # display balances
                    print (app.getBaseCurrency(), 'balance before order:', account.getBalance(app.getBaseCurrency()))
                    print (app.getQuoteCurrency(), 'balance before order:', account.getBalance(app.getQuoteCurrency()))

                    # execute a live market buy
                    resp = app.marketBuy(app.getMarket(), float(account.getBalance(app.getQuoteCurrency())))
                    logging.info(resp)

                    # display balances
                    print (app.getBaseCurrency(), 'balance after order:', account.getBalance(app.getBaseCurrency()))
                    print (app.getQuoteCurrency(), 'balance after order:', account.getBalance(app.getQuoteCurrency()))

                # if not live
                else:
                    if app.isVerbose() == 0:
                        logging.info(current_df_index + ' | ' + app.getMarket() + ' ' + str(app.getGranularity()) + ' | ' + price_text + ' | BUY')
                        print ("\n", current_df_index, '|', app.getMarket(), str(app.getGranularity()), '|', price_text, '| BUY')

                        bands = ta.getFibonacciRetracementLevels(float(price))                      
                        print (' Fibonacci Retracement Levels:', str(bands))
                        ta.printSupportResistanceLevel(float(price))

                        if len(bands) >= 1 and len(bands) <= 2:
                            if len(bands) == 1:
                                first_key = list(bands.keys())[0]
                                if first_key == 'ratio1':
                                    fib_low = 0
                                    fib_high = bands[first_key]
                                if first_key == 'ratio1_618':
                                    fib_low = bands[first_key]
                                    fib_high = bands[first_key] * 2
                                else:
                                    fib_low = bands[first_key]

                            elif len(bands) == 2:
                                first_key = list(bands.keys())[0]
                                second_key = list(bands.keys())[1]
                                fib_low = bands[first_key] 
                                fib_high = bands[second_key]
                            
                    else:
                        print('--------------------------------------------------------------------------------')
                        print('|                      *** Executing TEST Buy Order ***                        |')
                        print('--------------------------------------------------------------------------------')

                if app.shouldSaveGraphs() == 1:
                    tradinggraphs = TradingGraphs(ta)
                    ts = datetime.now().timestamp()
                    filename = app.getMarket() + '_' + str(app.getGranularity()) + '_buy_' + str(ts) + '.png'
                    tradinggraphs.renderEMAandMACD(len(trading_data), 'graphs/' + filename, True)

            # if a sell signal
            elif action == 'SELL':
                sell_count = sell_count + 1
                fee = float(price) * 0.005
                price_incl_fees = float(price) - fee
                sell_sum = sell_sum + price_incl_fees

                # if live
                if app.isLive() == 1:
                    # telegram
                    if app.isTelegramEnabled():
                        telegram = Telegram(app.getTelegramToken(), app.getTelegramClientId())
                        telegram.send(app.getMarket() + ' (' + str(app.getGranularity()) + ') SELL at ' + price_text)

                    if app.isVerbose() == 0:
                        logging.info(current_df_index + ' | ' + app.getMarket() + ' ' + str(app.getGranularity()) + ' | ' + price_text + ' | SELL')
                        print ("\n", current_df_index, '|', app.getMarket(), str(app.getGranularity()), '|', price_text, '| SELL')

                        bands = ta.getFibonacciRetracementLevels(float(price))                      
                        print (' Fibonacci Retracement Levels:', str(bands), "\n")                    

                        if len(bands) >= 1 and len(bands) <= 2:
                            if len(bands) == 1:
                                first_key = list(bands.keys())[0]
                                if first_key == 'ratio1':
                                    fib_low = 0
                                    fib_high = bands[first_key]
                                if first_key == 'ratio1_618':
                                    fib_low = bands[first_key]
                                    fib_high = bands[first_key] * 2
                                else:
                                    fib_low = bands[first_key]

                            elif len(bands) == 2:
                                first_key = list(bands.keys())[0]
                                second_key = list(bands.keys())[1]
                                fib_low = bands[first_key] 
                                fib_high = bands[second_key]

                    else:
                        print('--------------------------------------------------------------------------------')
                        print('|                      *** Executing LIVE Sell Order ***                        |')
                        print('--------------------------------------------------------------------------------')

                    # display balances
                    print (app.getBaseCurrency(), 'balance before order:', account.getBalance(app.getBaseCurrency()))
                    print (app.getQuoteCurrency(), 'balance before order:', account.getBalance(app.getQuoteCurrency()))

                    # execute a live market sell
                    resp = app.marketSell(app.getMarket(), float(account.getBalance(app.getBaseCurrency())))
                    logging.info(resp)

                    # display balances
                    print (app.getBaseCurrency(), 'balance after order:', account.getBalance(app.getBaseCurrency()))
                    print (app.getQuoteCurrency(), 'balance after order:', account.getBalance(app.getQuoteCurrency()))

                # if not live
                else:
                    if app.isVerbose() == 0:
                        sell_price = float(str(app.truncate(price, precision)))
                        last_buy_price = float(str(app.truncate(float(last_buy), precision)))
                        buy_sell_diff = round(np.subtract(sell_price, last_buy_price), precision)

                        if (sell_price != 0):
                            buy_sell_margin_no_fees = str(app.truncate((((sell_price - last_buy_price) / sell_price) * 100), 2)) + '%'
                        else:
                            buy_sell_margin_no_fees = '0%'

                        # calculate last buy minus fees
                        buy_fee = last_buy_price * 0.005
                        last_buy_price_minus_fees = last_buy_price + buy_fee

                        if (sell_price != 0):
                            buy_sell_margin_fees = str(app.truncate((((sell_price - last_buy_price_minus_fees) / sell_price) * 100), 2)) + '%'
                        else:
                            buy_sell_margin_fees = '0%'

                        logging.info(current_df_index + ' | ' + app.getMarket() + ' ' + str(app.getGranularity()) + ' | SELL | ' + str(sell_price) + ' | BUY | ' + str(last_buy_price) + ' | DIFF | ' + str(buy_sell_diff) + ' | MARGIN NO FEES | ' + str(buy_sell_margin_no_fees) + ' | MARGIN FEES | ' + str(buy_sell_margin_fees))
                        print ("\n", current_df_index, '|', app.getMarket(), str(app.getGranularity()), '| SELL |', str(sell_price), '| BUY |', str(last_buy_price), '| DIFF |', str(buy_sell_diff) , '| MARGIN NO FEES |', str(buy_sell_margin_no_fees), '| MARGIN FEES |', str(buy_sell_margin_fees), "\n")                    
                    else:
                        print('--------------------------------------------------------------------------------')
                        print('|                      *** Executing TEST Sell Order ***                        |')
                        print('--------------------------------------------------------------------------------')

                if app.shouldSaveGraphs() == 1:
                    tradinggraphs = TradingGraphs(ta)
                    ts = datetime.now().timestamp()
                    filename = app.getMarket() + '_' + str(app.getGranularity()) + '_sell_' + str(ts) + '.png'
                    tradinggraphs.renderEMAandMACD(len(trading_data), 'graphs/' + filename, True)

            # last significant action
            if action in [ 'BUY', 'SELL' ]:
                last_action = action
            
            last_df_index = str(df_last.index.format()[0])

            if iterations == len(df):
                print ("\nSimulation Summary\n")

                if buy_count > sell_count:
                    fee = price * 0.005
                    last_price_minus_fees = price - fee
                    sell_sum = sell_sum + last_price_minus_fees
                    sell_count = sell_count + 1

                print ('   Buy Count :', buy_count)
                print ('  Sell Count :', sell_count, "\n")

                if sell_count > 0:
                    print ('      Margin :', str(app.truncate((((sell_sum - buy_sum) / sell_sum) * 100), 2)) + '%', "\n")

                    print ('  ** non-live simulation, assuming highest fees', "\n")

        else:
            print (str(app.getTime()), '|', app.getMarket() + bullbeartext, '|', str(app.getGranularity()), '| Current Price:', price)

            # decrement ignored iteration
            iterations = iterations - 1

        # if live
        if app.isLive() == 1:
            # update order tracker csv
            if app.getExchange() == 'binance':
                account.saveTrackerCSV(app.getMarket())
            elif app.getExchange() == 'coinbasepro':
                account.saveTrackerCSV()

        if app.isSimulation() == 1:
            if iterations < 300:
                if app.simuluationSpeed() in [ 'fast', 'fast-sample' ]:
                    # fast processing
                    executeJob(sc, app, trading_data)
                else:
                    # slow processing
                    list(map(s.cancel, s.queue))
                    s.enter(1, 1, executeJob, (sc, app, trading_data))

        else:
            # poll every 5 minute
            list(map(s.cancel, s.queue))
            s.enter(300, 1, executeJob, (sc, app))
Ejemplo n.º 7
0
from models.PyCryptoBot import PyCryptoBot
from models.Trading import TechnicalAnalysis

app = PyCryptoBot()
df = app.getHistoricalData(app.getMarket(), app.getGranularity())

model = TechnicalAnalysis(df)
model.addATR(14)
df = model.getDataFrame()
print(df)
Ejemplo n.º 8
0
    def technical_analysis(exchange: str, market: str, g1, g2, g3) -> str:
        if exchange == 'binance':
            if not isBinanceMarketValid(market):
                return f"""
                {header()}
                <h4>Invalid Market!</h4>

                <div class="d-grid gap-2 d-md-flex justify-content-md-end">
                <a class="text-dark" href='/{exchange}'><button class="btn btn-primary me-md-2" type="button">Go Back</button></a>
                </div>
                {footer()}
                """
        elif exchange == 'coinbasepro':
            if not isCoinbaseMarketValid(market):
                return f"""
                {header()}
                <h4>Invalid Market!</h4>

                <div class="d-grid gap-2 d-md-flex justify-content-md-end">
                <a class="text-dark" href='/{exchange}'><button class="btn btn-primary me-md-2" type="button">Go Back</button></a>
                </div>
                {footer()}
                """
        else:
            return "Invalid Exchange!"

        if exchange == 'binance':
            api = BPublicAPI()
        if exchange == 'coinbasepro':
            api = CPublicAPI()
        ticker = api.getTicker(market)

        ta = TechnicalAnalysis(api.getHistoricalData(market, g1, None))
        ta.addAll()
        df_15m = ta.getDataFrame()
        df_15m_last = df_15m.tail(1)

        ta = TechnicalAnalysis(api.getHistoricalData(market, g2, None))
        ta.addAll()
        df_1h = ta.getDataFrame()
        df_1h_last = df_1h.tail(1)

        ta = TechnicalAnalysis(api.getHistoricalData(market, g3, None))
        ta.addAll()
        df_6h = ta.getDataFrame()
        df_6h_last = df_6h.tail(1)

        if exchange == 'binance':
            exchange_name = 'Binance'
        elif exchange == 'coinbasepro':
            exchange_name = 'Coinbase Pro'

        rsi14_15m_class = 'table-normal'
        rsi14_15m_desc = 'Uneventful'
        if df_15m_last['rsi14'].values[0] > 70:
            rsi14_15m_class = 'table-danger'
            rsi14_15m_desc = 'Overbought (Sell)'
        elif df_15m_last['rsi14'].values[0] < 30:
            rsi14_15m_class = 'table-success'
            rsi14_15m_desc = 'Oversold (Buy)'

        rsi14_1h_class = 'table-normal'
        rsi14_1h_desc = 'Uneventful'
        if df_1h_last['rsi14'].values[0] > 70:
            rsi14_1h_class = 'table-danger'
            rsi14_1h_desc = 'Overbought (Sell)'
        elif df_1h_last['rsi14'].values[0] < 30:
            rsi14_1h_class = 'table-success'
            rsi14_1h_desc = 'Oversold (Buy)'

        rsi14_6h_class = 'table-normal'
        rsi14_6h_desc = 'Uneventful'
        if df_6h_last['rsi14'].values[0] > 70:
            rsi14_6h_class = 'table-danger'
            rsi14_6h_desc = 'Overbought (Sell)'
        elif df_6h_last['rsi14'].values[0] < 30:
            rsi14_6h_class = 'table-success'
            rsi14_6h_desc = 'Oversold (Buy)'

        stochrsi14_15m_class = 'table-normal'
        stochrsi14_15m_desc = 'Uneventful'
        if df_6h_last['stochrsi14'].values[0] > 0.8:
            stochrsi14_6h_class = 'table-danger'
            stochrsi14_6h_desc = 'Overbought (Sell)'
        elif df_6h_last['stochrsi14'].values[0] < 0.2:
            stochrsi14_6h_class = 'table-success'
            stochrsi14_6h_desc = 'Oversold (Buy)'

        stochrsi14_1h_class = 'table-normal'
        stochrsi14_1h_desc = 'Uneventful'
        if df_1h_last['stochrsi14'].values[0] > 0.8:
            stochrsi14_1h_class = 'table-danger'
            stochrsi14_1h_desc = 'Overbought (Sell)'
        elif df_1h_last['stochrsi14'].values[0] < 0.2:
            stochrsi14_1h_class = 'table-success'
            stochrsi14_1h_desc = 'Oversold (Buy)'

        stochrsi14_6h_class = 'table-normal'
        stochrsi14_6h_desc = 'Uneventful'
        if df_6h_last['stochrsi14'].values[0] > 0.8:
            stochrsi14_6h_class = 'table-danger'
            stochrsi14_6h_desc = 'Overbought (Sell)'
        elif df_6h_last['stochrsi14'].values[0] < 0.2:
            stochrsi14_6h_class = 'table-success'
            stochrsi14_6h_desc = 'Oversold (Buy)'

        williamsr14_15m_class = 'table-normal'
        williamsr14_15m_desc = 'Uneventful'
        if df_15m_last['williamsr14'].values[0] > -20:
            williamsr14_15m_class = 'table-danger'
            williamsr14_15m_desc = 'Overbought (Sell)'
        elif df_15m_last['williamsr14'].values[0] < -80:
            williamsr14_15m_class = 'table-success'
            williamsr14_15m_desc = 'Oversold (Buy)'

        williamsr14_1h_class = 'table-normal'
        williamsr14_1h_desc = 'Uneventful'
        if df_1h_last['williamsr14'].values[0] > -20:
            williamsr14_1h_class = 'table-danger'
            williamsr14_1h_desc = 'Overbought (Sell)'
        elif df_1h_last['williamsr14'].values[0] < -80:
            williamsr14_1h_class = 'table-success'
            williamsr14_1h_desc = 'Oversold (Buy)'

        williamsr14_6h_class = 'table-normal'
        williamsr14_6h_desc = 'Uneventful'
        if df_6h_last['williamsr14'].values[0] > -20:
            williamsr14_6h_class = 'table-danger'
            williamsr14_6h_desc = 'Overbought (Sell)'
        elif df_6h_last['williamsr14'].values[0] < -80:
            williamsr14_6h_class = 'table-success'
            williamsr14_6h_desc = 'Oversold (Buy)'

        adx14_15m_class = 'table-normal'
        adx14_15m_desc = 'Normal Trend'
        if df_15m_last['adx14'].values[0] > 25 and df_15m_last['ema12'].values[0] >= df_15m_last['ema26'].values[0]:
            adx14_15m_class = 'table-success'
            adx14_15m_desc = 'Strong Trend Up'
        elif df_15m_last['adx14'].values[0] > 25 and df_15m_last['ema12'].values[0] < df_15m_last['ema26'].values[0]:
            adx14_15m_class = 'table-danger'
            adx14_15m_desc = 'Strong Trend Down'
        elif df_15m_last['adx14'].values[0] < 20 and df_15m_last['ema12'].values[0] >= df_15m_last['ema26'].values[0]:
            adx14_15m_class = 'table-success'
            adx14_15m_desc = 'Weak Trend Up'
        elif df_15m_last['adx14'].values[0] < 20 and df_15m_last['ema12'].values[0] < df_15m_last['ema26'].values[0]:
            adx14_15m_class = 'table-danger'
            adx14_15m_desc = 'Weak Trend Up'

        adx14_1h_class = 'table-normal'
        adx14_1h_desc = 'Normal Trend'
        if df_1h_last['adx14'].values[0] > 25 and df_1h_last['ema12'].values[0] >= df_1h_last['ema26'].values[0]:
            adx14_1h_class = 'table-success'
            adx14_1h_desc = 'Strong Trend Up'
        elif df_1h_last['adx14'].values[0] > 25 and df_1h_last['ema12'].values[0] < df_1h_last['ema26'].values[0]:
            adx14_1h_class = 'table-danger'
            adx14_1h_desc = 'Strong Trend Down'
        elif df_1h_last['adx14'].values[0] < 20 and df_1h_last['ema12'].values[0] >= df_1h_last['ema26'].values[0]:
            adx14_1h_class = 'table-success'
            adx14_1h_desc = 'Weak Trend Up'
        elif df_1h_last['adx14'].values[0] < 20 and df_1h_last['ema12'].values[0] < df_1h_last['ema26'].values[0]:
            adx14_1h_class = 'table-danger'
            adx14_1h_desc = 'Weak Trend Up'

        adx14_6h_class = 'table-normal'
        adx14_6h_desc = 'Normal Trend'
        if df_6h_last['adx14'].values[0] > 25 and df_6h_last['ema12'].values[0] >= df_6h_last['ema26'].values[0]:
            adx14_6h_class = 'table-success'
            adx14_6h_desc = 'Strong Trend Up'
        elif df_6h_last['adx14'].values[0] > 25 and df_6h_last['ema12'].values[0] < df_6h_last['ema26'].values[0]:
            adx14_6h_class = 'table-danger'
            adx14_6h_desc = 'Strong Trend Down'
        elif df_6h_last['adx14'].values[0] < 20 and df_6h_last['ema12'].values[0] >= df_6h_last['ema26'].values[0]:
            adx14_6h_class = 'table-success'
            adx14_6h_desc = 'Weak Trend Up'
        elif df_6h_last['adx14'].values[0] < 20 and df_6h_last['ema12'].values[0] < df_6h_last['ema26'].values[0]:
            adx14_6h_class = 'table-danger'
            adx14_6h_desc = 'Weak Trend Up'

        def arima_predictions(even_rows: bool = True):
            results_ARIMA = ta.seasonalARIMAModel()
            start_date = df_1h.last_valid_index()
            end_date = start_date + datetime.timedelta(days=3)
            arima_pred = results_ARIMA.predict(
                start=str(start_date), end=str(end_date), dynamic=True
            )

            if even_rows:
                arima_pred_rows = arima_pred.iloc[::2]
            else:
                arima_pred_rows = arima_pred.iloc[1::2]

            html = ""
            for index, pred in arima_pred_rows.iteritems():
                html += f"""
                <tbody>
                    <tr class={'table-success' if pred >= ticker[1] else 'table-danger'}>
                        <td>{index}</td>
                        <td>{pred}</td>
                    </tr>
                </tbody>
                """

            return html

        return f"""
Ejemplo n.º 9
0
import pandas as pd
from models.Trading import TechnicalAnalysis
from models.CoinbasePro import PublicAPI

api = PublicAPI()
data = api.getHistoricalData('BCH-GBP', 3600)

ta = TechnicalAnalysis(data)
ta.addEMA(12)
ta.addEMA(26)
ta.addMACD()
ta.addOBV()
ta.addEMABuySignals()
ta.addMACDBuySignals()

df = ta.getDataFrame()
print(df.iloc[247:291][[
    'close', 'ema12', 'ema26', 'ema12gtema26', 'ema12gtema26co',
    'ema12ltema26', 'ema12ltema26co', 'macd', 'signal', 'macdgtsignal',
    'macdltsignal', 'obv_pc'
]])
Ejemplo n.º 10
0
def executeJob(sc, market, granularity, tradingData=pd.DataFrame()):
    """Trading bot job which runs at a scheduled interval"""
    global action, iterations, x_since_buy, x_since_sell, last_action, last_df_index

    # increment iterations
    iterations = iterations + 1

    if is_sim == 0:
        # retrieve the market data
        api = PublicAPI()
        tradingData = api.getHistoricalData(market, granularity)

    # analyse the market data
    tradingDataCopy = tradingData.copy()
    technicalAnalysis = TechnicalAnalysis(tradingDataCopy)
    technicalAnalysis.addAll()
    df = technicalAnalysis.getDataFrame()

    if len(df) != 300:
        # data frame should have 300 rows, if not retry
        print('error: data frame length is < 300 (' + str(len(df)) + ')')
        logging.error('error: data frame length is < 300 (' + str(len(df)) +
                      ')')
        s.enter(300, 1, executeJob, (sc, market, granularity))

    if is_sim == 1:
        # with a simulation df_last will iterate through data
        df_last = df.iloc[iterations - 1:iterations]
    else:
        # df_last contains the most recent entry
        df_last = df.tail(1)

    ema12gtema26 = bool(df_last['ema12gtema26'].values[0])
    ema12gtema26co = bool(df_last['ema12gtema26co'].values[0])
    macdgtsignal = bool(df_last['macdgtsignal'].values[0])
    macdgtsignalco = bool(df_last['macdgtsignalco'].values[0])
    ema12ltema26 = bool(df_last['ema12ltema26'].values[0])
    ema12ltema26co = bool(df_last['ema12ltema26co'].values[0])
    macdltsignal = bool(df_last['macdltsignal'].values[0])
    macdltsignalco = bool(df_last['macdltsignalco'].values[0])
    obv = float(df_last['obv'].values[0])
    obv_pc = float(df_last['obv_pc'].values[0])

    # criteria for a buy signal
    if ((ema12gtema26co == True and macdgtsignal == True and obv_pc > 0.1) or
        (ema12gtema26 == True and macdgtsignal == True and obv_pc > 0.1
         and x_since_buy > 0 and x_since_buy <= 2)) and last_action != 'BUY':
        action = 'BUY'
    # criteria for a sell signal
    elif (ema12ltema26co == True
          and macdltsignal == True) and last_action not in ['', 'SELL']:
        action = 'SELL'
    # anything other than a buy or sell, just wait
    else:
        action = 'WAIT'

    # polling is every 5 minutes (even for hourly intervals), but only process once per interval
    if (last_df_index != df_last.index.format()):
        ts_text = str(df_last.index.format()[0])
        price_text = 'Price: ' + str(
            truncate(float(df_last['close'].values[0]), 2))
        ema_text = compare(df_last['ema12'].values[0],
                           df_last['ema26'].values[0], 'EMA12/26')
        macd_text = compare(df_last['macd'].values[0],
                            df_last['signal'].values[0], 'MACD')
        obv_text = compare(df_last['obv_pc'].values[0], 0, 'OBV %')
        counter_text = '[I:' + str(iterations) + ',B:' + str(
            x_since_buy) + ',S:' + str(x_since_sell) + ']'

        ema_co_prefix = ''
        ema_co_suffix = ''
        if ema12gtema26co == True or ema12ltema26co == True:
            ema_co_prefix = '* '
            ema_co_suffix = ' *'

        macd_co_prefix = ''
        macd_co_suffix = ''
        if macdgtsignalco == True or macdltsignalco == True:
            macd_co_prefix = '* '
            macd_co_suffix = ' *'

        if is_verbose == 0:
            output_text = ts_text + ' | ' + price_text + ' | ' + ema_co_prefix + ema_text + ema_co_suffix + ' | ' + macd_co_prefix + macd_text + macd_co_suffix + ' | ' + obv_text + ' | ' + action + ' ' + counter_text
            logging.debug(output_text)
            print(output_text)
        else:
            logging.debug('-- Iteration: ' + str(iterations) + ' --')
            logging.debug('-- Since Last Buy: ' + str(x_since_buy) + ' --')
            logging.debug('-- Since Last Sell: ' + str(x_since_sell) + ' --')

            logging.debug('price: ' +
                          str(truncate(float(df_last['close'].values[0]), 2)))
            logging.debug('ema12: ' +
                          str(truncate(float(df_last['ema12'].values[0]), 2)))
            logging.debug('ema26: ' +
                          str(truncate(float(df_last['ema26'].values[0]), 2)))
            logging.debug('ema12gtema26co: ' + str(ema12gtema26co))
            logging.debug('ema12gtema26: ' + str(ema12gtema26))
            logging.debug('ema12ltema26co: ' + str(ema12ltema26co))
            logging.debug('ema12ltema26: ' + str(ema12ltema26))
            logging.debug('macd: ' +
                          str(truncate(float(df_last['macd'].values[0]), 2)))
            logging.debug('signal: ' +
                          str(truncate(float(df_last['signal'].values[0]), 2)))
            logging.debug('macdgtsignal: ' + str(macdgtsignal))
            logging.debug('macdltsignal: ' + str(macdltsignal))
            logging.debug('obv: ' + str(obv))
            logging.debug('obv_pc: ' + str(obv_pc) + '%')
            logging.debug('action: ' + action)

            # informational output on the most recent entry
            print('')
            print(
                '================================================================================'
            )
            txt = '        Iteration : ' + str(iterations)
            print('|', txt, (' ' * (75 - len(txt))), '|')
            txt = '   Since Last Buy : ' + str(x_since_buy)
            print('|', txt, (' ' * (75 - len(txt))), '|')
            txt = '  Since Last Sell : ' + str(x_since_sell)
            print('|', txt, (' ' * (75 - len(txt))), '|')
            txt = '        Timestamp : ' + str(df_last.index.format()[0])
            print('|', txt, (' ' * (75 - len(txt))), '|')
            print(
                '--------------------------------------------------------------------------------'
            )
            txt = '            EMA12 : ' + str(
                truncate(float(df_last['ema12'].values[0]), 2))
            print('|', txt, (' ' * (75 - len(txt))), '|')
            txt = '            EMA26 : ' + str(
                truncate(float(df_last['ema26'].values[0]), 2))
            print('|', txt, (' ' * (75 - len(txt))), '|')
            txt = '   Crossing Above : ' + str(ema12gtema26co)
            print('|', txt, (' ' * (75 - len(txt))), '|')
            txt = '  Currently Above : ' + str(ema12gtema26)
            print('|', txt, (' ' * (75 - len(txt))), '|')
            txt = '   Crossing Below : ' + str(ema12ltema26co)
            print('|', txt, (' ' * (75 - len(txt))), '|')
            txt = '  Currently Below : ' + str(ema12ltema26)
            print('|', txt, (' ' * (75 - len(txt))), '|')

            if (ema12gtema26 == True and ema12gtema26co == True):
                txt = '        Condition : EMA12 is currently crossing above EMA26'
            elif (ema12gtema26 == True and ema12gtema26co == False):
                txt = '        Condition : EMA12 is currently above EMA26 and has crossed over'
            elif (ema12ltema26 == True and ema12ltema26co == True):
                txt = '        Condition : EMA12 is currently crossing below EMA26'
            elif (ema12ltema26 == True and ema12ltema26co == False):
                txt = '        Condition : EMA12 is currently below EMA26 and has crossed over'
            else:
                txt = '        Condition : -'
            print('|', txt, (' ' * (75 - len(txt))), '|')

            print(
                '--------------------------------------------------------------------------------'
            )
            txt = '             MACD : ' + str(
                truncate(float(df_last['macd'].values[0]), 2))
            print('|', txt, (' ' * (75 - len(txt))), '|')
            txt = '           Signal : ' + str(
                truncate(float(df_last['signal'].values[0]), 2))
            print('|', txt, (' ' * (75 - len(txt))), '|')
            txt = '  Currently Above : ' + str(macdgtsignal)
            print('|', txt, (' ' * (75 - len(txt))), '|')
            txt = '  Currently Below : ' + str(macdltsignal)
            print('|', txt, (' ' * (75 - len(txt))), '|')

            if (macdgtsignal == True and macdgtsignalco == True):
                txt = '        Condition : MACD is currently crossing above Signal'
            elif (macdgtsignal == True and macdgtsignalco == False):
                txt = '        Condition : MACD is currently above Signal and has crossed over'
            elif (macdltsignal == True and macdltsignalco == True):
                txt = '        Condition : MACD is currently crossing below Signal'
            elif (macdltsignal == True and macdltsignalco == False):
                txt = '        Condition : MACD is currently below Signal and has crossed over'
            else:
                txt = '        Condition : -'
            print('|', txt, (' ' * (75 - len(txt))), '|')

            print(
                '--------------------------------------------------------------------------------'
            )
            txt = '              OBV : ' + str(truncate(obv, 4))
            print('|', txt, (' ' * (75 - len(txt))), '|')
            txt = '       OBV Change : ' + str(obv_pc) + '%'
            print('|', txt, (' ' * (75 - len(txt))), '|')

            if (obv_pc >= 2):
                txt = '        Condition : Large positive volume changes'
            elif (obv_pc < 2 and obv_pc >= 0):
                txt = '        Condition : Positive volume changes'
            else:
                txt = '        Condition : Negative volume changes'
            print('|', txt, (' ' * (75 - len(txt))), '|')

            print(
                '--------------------------------------------------------------------------------'
            )
            txt = '           Action : ' + action
            print('|', txt, (' ' * (75 - len(txt))), '|')
            print(
                '================================================================================'
            )

        if last_action == 'BUY':
            x_since_buy = x_since_buy + 1
        elif last_action == 'SELL':
            x_since_sell = x_since_sell + 1

        # if a buy signal
        if action == 'BUY':
            # increment x since buy
            x_since_buy = x_since_buy + 1

            # reset x since sell
            x_since_sell = 0

            # if live
            if is_live == 1:
                if is_verbose == 0:
                    logging.info(ts_text + ' | ' + market + ' ' +
                                 str(granularity) + ' | ' + price_text +
                                 ' | BUY')
                    print(ts_text, '|', market, granularity, '|', price_text,
                          '| BUY')
                else:
                    print(
                        '--------------------------------------------------------------------------------'
                    )
                    print(
                        '|                      *** Executing LIVE Buy Order ***                        |'
                    )
                    print(
                        '--------------------------------------------------------------------------------'
                    )
                # connect to coinbase pro api (authenticated)
                model = AuthAPI(config['api_key'], config['api_secret'],
                                config['api_pass'], config['api_url'])
                # execute a live market buy
                resp = model.marketBuy(market,
                                       float(account.getBalance(fiatMarket)))
                logging.info(resp)
                #logging.info('attempt to buy ' + resp['specified_funds'] + ' (' + resp['funds'] + ' after fees) of ' + resp['product_id'])
            # if not live
            else:
                if is_verbose == 0:
                    logging.info(ts_text + ' | ' + market + ' ' +
                                 str(granularity) + ' | ' + price_text +
                                 ' | BUY')
                    print(ts_text, '|', market, granularity, '|', price_text,
                          '| BUY')
                else:
                    print(
                        '--------------------------------------------------------------------------------'
                    )
                    print(
                        '|                      *** Executing TEST Buy Order ***                        |'
                    )
                    print(
                        '--------------------------------------------------------------------------------'
                    )
            #print(df_last[['close','ema12','ema26','ema12gtema26','ema12gtema26co','macd','signal','macdgtsignal','obv','obv_pc']])

        # if a sell signal
        elif action == 'SELL':
            # increment x since buy
            x_since_sell = x_since_sell + 1

            # reset x since buy
            x_since_buy = 0

            # if live
            if is_live == 1:
                if is_verbose == 0:
                    logging.info(ts_text + ' | ' + market + ' ' +
                                 str(granularity) + ' | ' + price_text +
                                 ' | SELL')
                    print(ts_text, '|', market, granularity, '|', price_text,
                          '| SELL')
                else:
                    print(
                        '--------------------------------------------------------------------------------'
                    )
                    print(
                        '|                      *** Executing LIVE Sell Order ***                        |'
                    )
                    print(
                        '--------------------------------------------------------------------------------'
                    )
                # connect to Coinbase Pro API live
                model = AuthAPI(config['api_key'], config['api_secret'],
                                config['api_pass'], config['api_url'])
                # execute a live market sell
                resp = model.marketSell(
                    market, float(account.getBalance(cryptoMarket)))
                logging.info(resp)
                #logging.info('attempt to sell ' + resp['size'] + ' of ' + resp['product_id'])
            # if not live
            else:
                if is_verbose == 0:
                    logging.info(ts_text + ' | ' + market + ' ' +
                                 str(granularity) + ' | ' + price_text +
                                 ' | SELL')
                    print(ts_text, '|', market, granularity, '|', price_text,
                          '| SELL')
                else:
                    print(
                        '--------------------------------------------------------------------------------'
                    )
                    print(
                        '|                      *** Executing TEST Sell Order ***                        |'
                    )
                    print(
                        '--------------------------------------------------------------------------------'
                    )
            #print(df_last[['close','ema12','ema26','ema12ltema26','ema12ltema26co','macd','signal','macdltsignal','obv','obv_pc']])

        # last significant action
        if action in ['BUY', 'SELL']:
            last_action = action

        last_df_index = df_last.index.format()

    # if live
    if is_live == 1:
        # save csv with orders for market that are 'done'
        orders = account.getOrders(market, '', 'done')
        orders.to_csv('orders.csv', index=False)

    if is_sim == 1:
        if iterations < 300:
            if sim_speed == 'fast':
                # fast processing
                executeJob(sc, market, granularity, tradingData)
            else:
                # slow processing
                s.enter(1, 1, executeJob,
                        (sc, market, granularity, tradingData))
    else:
        # poll every 5 minutes
        s.enter(300, 1, executeJob, (sc, market, granularity))
Ejemplo n.º 11
0
import sys
import pandas as pd

sys.path.append('.')
# pylint: disable=import-error
from models.Trading import TechnicalAnalysis
from models.CoinbasePro import PublicAPI

api = PublicAPI()
data = api.getHistoricalData('BCH-GBP', 3600)

ta = TechnicalAnalysis(data)
ta.addAll()

df = ta.getDataFrame()
df.to_csv('ml/data/BCH-GBP_3600.csv', index=False)
Ejemplo n.º 12
0
def test_should_calculate_addSMA_20():
    """
      Add the Simple Moving Average (SMA) to the DataFrame :
    """

    # GIVEN a series of values
    closes_list = [
        0.0003, 0.0004, 0.0010, 0.0020, 0.0009, 0.0008, 0.0009, 0.0010, 0.0012,
        0.0015, 0.0025, 0.0015, 0.0014, 0.0016, 0.0030, 0.0032, 0.0035, 0.0024,
        0.0023, 0.0022, 0.0021, 0.0020
    ]
    df = pd.DataFrame({
        'date': [
            '2021-10-10 14:30:00', '2021-10-10 14:31:00',
            '2021-10-10 14:32:00', '2021-10-10 14:33:00',
            '2021-10-10 14:34:00', '2021-10-10 14:35:00',
            '2021-10-10 14:36:00', '2021-10-10 14:37:00',
            '2021-10-10 14:38:00', '2021-10-10 14:39:00',
            '2021-10-10 14:40:00', '2021-10-10 14:41:00',
            '2021-10-10 14:42:00', '2021-10-10 14:43:00',
            '2021-10-10 14:44:00', '2021-10-10 14:45:00',
            '2021-10-10 14:46:00', '2021-10-10 14:47:00',
            '2021-10-10 14:48:00', '2021-10-10 14:49:00',
            '2021-10-10 14:50:00', '2021-10-10 14:51:00'
        ],
        'close':
        closes_list
    })
    df['date'] = pd.to_datetime(df['date'], format="%Y-%d-%m %H:%M:%S")
    df.set_index(['date'])

    ta = TechnicalAnalysis(df)

    # WHEN calculate the cumulative moving average 20
    ta.addSMA(20)

    # THEN
    actual = ta.getDataFrame()
    expected = pd.DataFrame({
        'date': [
            '2021-10-10 14:30:00', '2021-10-10 14:31:00',
            '2021-10-10 14:32:00', '2021-10-10 14:33:00',
            '2021-10-10 14:34:00', '2021-10-10 14:35:00',
            '2021-10-10 14:36:00', '2021-10-10 14:37:00',
            '2021-10-10 14:38:00', '2021-10-10 14:39:00',
            '2021-10-10 14:40:00', '2021-10-10 14:41:00',
            '2021-10-10 14:42:00', '2021-10-10 14:43:00',
            '2021-10-10 14:44:00', '2021-10-10 14:45:00',
            '2021-10-10 14:46:00', '2021-10-10 14:47:00',
            '2021-10-10 14:48:00', '2021-10-10 14:49:00',
            '2021-10-10 14:50:00', '2021-10-10 14:51:00'
        ],
        'close':
        closes_list,
        'sma20': [
            calculate_mean_on_range(0, 1, closes_list),
            calculate_mean_on_range(0, 2, closes_list),
            calculate_mean_on_range(0, 3, closes_list),
            calculate_mean_on_range(0, 4, closes_list),
            calculate_mean_on_range(0, 5, closes_list),
            calculate_mean_on_range(0, 6, closes_list),
            calculate_mean_on_range(0, 7, closes_list),
            calculate_mean_on_range(0, 8, closes_list),
            calculate_mean_on_range(0, 9, closes_list),
            calculate_mean_on_range(0, 10, closes_list),
            calculate_mean_on_range(0, 11, closes_list),
            calculate_mean_on_range(0, 12, closes_list),
            calculate_mean_on_range(0, 13, closes_list),
            calculate_mean_on_range(0, 14, closes_list),
            calculate_mean_on_range(0, 15, closes_list),
            calculate_mean_on_range(0, 16, closes_list),
            calculate_mean_on_range(0, 17, closes_list),
            calculate_mean_on_range(0, 18, closes_list),
            calculate_mean_on_range(0, 19, closes_list),
            calculate_mean_on_range(0, 20, closes_list),
            calculate_mean_on_range(1, 21, closes_list),
            calculate_mean_on_range(2, 22, closes_list)
        ]
    })
    expected['date'] = pd.to_datetime(df['date'], format="%Y-%d-%m %H:%M:%S")
    expected.set_index(['date'])

    assert_frame_equal(actual, expected)