Example #1
0
def run(start_date: str,
        finish_date: str,
        candles=None,
        chart=False,
        tradingview=False):
    # clear the screen
    if not jh.should_execute_silently():
        click.clear()

    # validate routes
    validate_routes(router)

    # initiate candle store
    store.candles.init_storage(5000)

    # load historical candles
    if candles is None:
        print('loading candles...')
        candles = _load_candles(start_date, finish_date)
        click.clear()

    if not jh.should_execute_silently():
        # print candles table
        key = '{}-{}'.format(config['app']['trading_exchanges'][0],
                             config['app']['trading_symbols'][0])
        table.key_value(stats.candles(candles[key]['candles']),
                        'candles',
                        alignments=('left', 'right'))
        print('\n')

        # print routes table
        table.multi_value(stats.routes(router.routes))
        print('\n')

        # print guidance for debugging candles
        if jh.is_debuggable('trading_candles') or jh.is_debuggable(
                'shorter_period_candles'):
            print(
                '     Symbol  |     timestamp    | open | close | high | low | volume'
            )

    # run backtest simulation
    simulator(candles)

    if not jh.should_execute_silently():
        # print trades statistics
        if store.completed_trades.count > 0:
            print('\n')
            table.key_value(report.portfolio_metrics(),
                            'Metrics',
                            alignments=('left', 'right'))
            print('\n')

            # save logs
            store_logs(tradingview)

            if chart:
                charts.portfolio_vs_asset_returns()
        else:
            print(jh.color('No trades were made.', 'yellow'))
Example #2
0
    def _terminate(self) -> None:
        """
        Optional for executing code after completion of a backTest.
        This block will not execute in live use as a live
        Jesse is never ending.
        """
        if not jh.should_execute_silently() or jh.is_debugging():
            logger.info("Terminating strategy...")

        self.terminate()

        self._detect_and_handle_entry_and_exit_modifications()

        # fake execution of market orders in backtest simulation
        if not jh.is_live():
            store.orders.execute_pending_market_orders()

        if jh.is_live():
            return

        if self.position.is_open:
            store.app.total_open_trades += 1
            store.app.total_open_pl += self.position.pnl
            logger.info(
                f"Closed open {self.exchange}-{self.symbol} position at {self.position.current_price} with PNL: {round(self.position.pnl, 4)}({round(self.position.pnl_percentage, 2)}%) because we reached the end of the backtest session."
            )
            # fake a closing (market) order so that the calculations would be correct
            self.broker.reduce_position_at(self.position.qty, self.position.current_price, order_roles.CLOSE_POSITION)
            return

        if self._open_position_orders:
            self._execute_cancel()
            logger.info('Canceled open-position orders because we reached the end of the backtest session.')
Example #3
0
def print_candle(candle, is_partial, symbol):
    """

    :param candle:
    :param is_partial:
    :param symbol:
    :return:
    """
    if jh.should_execute_silently():
        return

    if is_bullish(candle) and is_partial is True:
        candle_form = click.style('  ==', fg='green')
    elif is_bullish(candle) and is_partial is False:
        candle_form = click.style('====', bg='green')
    elif is_bearish(candle) and is_partial is True:
        candle_form = click.style('  ==', fg='red')
    else:
        candle_form = click.style('====', bg='red')

    if is_bullish(candle):
        candle_info = click.style(' {} | {} | {} | {} | {} | {} | {}'.format(
            symbol,
            str(arrow.get(candle[0] / 1000))[:-9], candle[1], candle[2],
            candle[3], candle[4], round(candle[5], 2)),
                                  fg='green')
    else:
        candle_info = click.style(' {} | {} | {} | {} | {} | {} | {}'.format(
            symbol,
            str(arrow.get(candle[0] / 1000))[:-9], candle[1], candle[2],
            candle[3], candle[4], round(candle[5], 2)),
                                  fg='red')

    print(candle_form + candle_info)
Example #4
0
    def _on_stop_loss(self, order: Order) -> None:
        if not jh.should_execute_silently() or jh.is_debugging():
            logger.info('Stop-loss has been executed.')

        self._broadcast('route-stop-loss')
        self._execute_cancel()
        self.on_stop_loss(order)

        self._detect_and_handle_entry_and_exit_modifications()
Example #5
0
    def _on_take_profit(self, order: Order) -> None:
        if not jh.should_execute_silently() or jh.is_debugging():
            logger.info("Take-profit order has been executed.")

        self._broadcast('route-take-profit')
        self._execute_cancel()
        self.on_take_profit(order)

        self._detect_and_handle_entry_and_exit_modifications()
Example #6
0
    def _on_increased_position(self):
        if not jh.should_execute_silently() or jh.is_debugging():
            logger.info("Position size increased.")

        self._broadcast('route-increased-position')

        self.on_increased_position()

        self._detect_and_handle_entry_and_exit_modifications()
Example #7
0
    def _on_close_position(self, order: Order):
        if not jh.should_execute_silently() or jh.is_debugging():
            logger.info("A closing order has been executed")

        self._broadcast('route-close-position')
        self._execute_cancel()
        self.on_close_position(order)

        self._detect_and_handle_entry_and_exit_modifications()
Example #8
0
    def _on_reduced_position(self):
        """
        prepares for on_reduced_position() is implemented by user
        """
        if not jh.should_execute_silently() or jh.is_debugging():
            logger.info("Position size reduced.")

        self._broadcast('route-reduced-position')

        self.on_reduced_position()

        self._detect_and_handle_entry_and_exit_modifications()
Example #9
0
    def _on_take_profit(self, order: Order) -> None:
        if not jh.should_execute_silently() or jh.is_debugging():
            logger.info("Take-profit order has been executed.")

        self._broadcast('route-take-profit')
        self._execute_cancel()

        # set metrics only after a trade happens and they actually change
        self.metrics = metrics.trades(store.completed_trades.trades,
                                      store.app.daily_balance)

        self.on_take_profit(order)

        self._detect_and_handle_entry_and_exit_modifications()
Example #10
0
def print_candle(candle: np.ndarray, is_partial: bool, symbol: str) -> None:
    """
    Ever since the new GUI dashboard, this function should log instead of actually printing

    :param candle: np.ndarray
    :param is_partial: bool
    :param symbol: str
    """
    if jh.should_execute_silently():
        return

    candle_form = '  ==' if is_partial else '===='
    candle_info = f' {symbol} | {str(arrow.get(candle[0] / 1000))[:-9]} | {candle[1]} | {candle[2]} | {candle[3]} | {candle[4]} | {round(candle[5], 2)}'
    msg = candle_form + candle_info

    # store it in the log file
    logger.info(msg)
Example #11
0
def run(debug_mode, user_config: dict, routes: List[Dict[str, str]],
        extra_routes: List[Dict[str, str]], start_date: str, finish_date: str,
        optimal_total: int, csv: bool, json: bool) -> None:
    from jesse.config import config, set_config
    config['app']['trading_mode'] = 'optimize'

    # debug flag
    config['app']['debug_mode'] = debug_mode

    cpu_cores = int(user_config['cpu_cores'])

    # inject config
    set_config(user_config)

    # set routes
    router.initiate(routes, extra_routes)

    store.app.set_session_id()

    register_custom_exception_handler()

    # clear the screen
    if not jh.should_execute_silently():
        click.clear()

    # validate routes
    validate_routes(router)

    print('loading candles...')

    # load historical candles and divide them into training
    # and testing periods (15% for test, 85% for training)
    training_candles, testing_candles = _get_training_and_testing_candles(
        start_date, finish_date)

    # clear the screen
    click.clear()

    optimizer = Optimizer(training_candles, testing_candles, optimal_total,
                          cpu_cores, csv, json, start_date, finish_date)

    # start the process
    optimizer.run()
Example #12
0
def print_candle(candle: np.ndarray, is_partial: bool, symbol: str) -> None:
    if jh.should_execute_silently():
        return

    if is_bullish(candle) and is_partial:
        candle_form = click.style('  ==', fg='green')
    elif is_bullish(candle) and not is_partial:
        candle_form = click.style('====', bg='green')
    elif is_bearish(candle) and is_partial:
        candle_form = click.style('  ==', fg='red')
    else:
        candle_form = click.style('====', bg='red')

    if is_bullish(candle):
        candle_info = click.style(
            f' {symbol} | {str(arrow.get(candle[0] / 1000))[:-9]} | {candle[1]} | {candle[2]} | {candle[3]} | {candle[4]} | {round(candle[5], 2)}',
            fg='green')
    else:
        candle_info = click.style(
            f' {symbol} | {str(arrow.get(candle[0] / 1000))[:-9]} | {candle[1]} | {candle[2]} | {candle[3]} | {candle[4]} | {round(candle[5], 2)}',
            fg='red')

    print(candle_form + candle_info)
Example #13
0
    def _terminate(self):
        """
        Optional for executing code after completion of a backTest.
        This block will not execute in live use as a live
        Jesse is never ending.
        """
        if not jh.should_execute_silently() or jh.is_debugging():
            logger.info("Terminating strategy...")

        self.terminate()

        self._detect_and_handle_entry_and_exit_modifications()

        # fake execution of market orders in backtest simulation
        if not jh.is_live():
            store.orders.execute_pending_market_orders()

        if jh.is_live():
            return

        if self.position.is_open:
            store.app.total_open_trades += 1
            store.app.total_open_pl += self.position.pnl
            logger.info(
                "Closed open {}-{} position at {} with PNL: {}({}%) because we reached the end of the backtest session."
                .format(self.exchange, self.symbol,
                        self.position.current_price, self.position.pnl,
                        self.position.pnl_percentage))
            self.position._close(self.position.current_price)
            self._execute_cancel()
            return

        if self._open_position_orders:
            self._execute_cancel()
            logger.info(
                'Canceled open-position orders because we reached the end of the backtest session.'
            )
Example #14
0
def run(
        debug_mode,
        user_config: dict,
        routes: List[Dict[str, str]],
        extra_routes: List[Dict[str, str]],
        start_date: str,
        finish_date: str,
        candles: dict = None,
        chart: bool = False,
        tradingview: bool = False,
        full_reports: bool = False,
        csv: bool = False,
        json: bool = False
) -> None:
    if not jh.is_unit_testing():
        # at every second, we check to see if it's time to execute stuff
        status_checker = Timeloop()
        @status_checker.job(interval=timedelta(seconds=1))
        def handle_time():
            if process_status() != 'started':
                raise exceptions.Termination
        status_checker.start()

    from jesse.config import config, set_config
    config['app']['trading_mode'] = 'backtest'

    # debug flag
    config['app']['debug_mode'] = debug_mode

    # inject config
    if not jh.is_unit_testing():
        set_config(user_config)

    # set routes
    router.initiate(routes, extra_routes)

    store.app.set_session_id()

    register_custom_exception_handler()

    # clear the screen
    if not jh.should_execute_silently():
        click.clear()

    # validate routes
    validate_routes(router)

    # initiate candle store
    store.candles.init_storage(5000)

    # load historical candles
    if candles is None:
        candles = load_candles(start_date, finish_date)
        click.clear()

    if not jh.should_execute_silently():
        sync_publish('general_info', {
            'session_id': jh.get_session_id(),
            'debug_mode': str(config['app']['debug_mode']),
        })

        # candles info
        key = f"{config['app']['considering_candles'][0][0]}-{config['app']['considering_candles'][0][1]}"
        sync_publish('candles_info', stats.candles_info(candles[key]['candles']))

        # routes info
        sync_publish('routes_info', stats.routes(router.routes))

    # run backtest simulation
    simulator(candles, run_silently=jh.should_execute_silently())

    # hyperparameters (if any)
    if not jh.should_execute_silently():
        sync_publish('hyperparameters', stats.hyperparameters(router.routes))

    if not jh.should_execute_silently():
        if store.completed_trades.count > 0:
            sync_publish('metrics', report.portfolio_metrics())

            routes_count = len(router.routes)
            more = f"-and-{routes_count - 1}-more" if routes_count > 1 else ""
            study_name = f"{router.routes[0].strategy_name}-{router.routes[0].exchange}-{router.routes[0].symbol}-{router.routes[0].timeframe}{more}-{start_date}-{finish_date}"
            store_logs(study_name, json, tradingview, csv)

            if chart:
                charts.portfolio_vs_asset_returns(study_name)

            sync_publish('equity_curve', charts.equity_curve())

            # QuantStats' report
            if full_reports:
                price_data = []
                # load close candles for Buy and hold and calculate pct_change
                for index, c in enumerate(config['app']['considering_candles']):
                    exchange, symbol = c[0], c[1]
                    if exchange in config['app']['trading_exchanges'] and symbol in config['app']['trading_symbols']:
                        # fetch from database
                        candles_tuple = Candle.select(
                            Candle.timestamp, Candle.close
                        ).where(
                            Candle.timestamp.between(jh.date_to_timestamp(start_date),
                                                     jh.date_to_timestamp(finish_date) - 60000),
                            Candle.exchange == exchange,
                            Candle.symbol == symbol
                        ).order_by(Candle.timestamp.asc()).tuples()

                        candles = np.array(candles_tuple)

                        timestamps = candles[:, 0]
                        price_data.append(candles[:, 1])

                price_data = np.transpose(price_data)
                price_df = pd.DataFrame(price_data, index=pd.to_datetime(timestamps, unit="ms"), dtype=float).resample(
                    'D').mean()
                price_pct_change = price_df.pct_change(1).fillna(0)
                bh_daily_returns_all_routes = price_pct_change.mean(1)
                quantstats.quantstats_tearsheet(bh_daily_returns_all_routes, study_name)
        else:
            sync_publish('equity_curve', None)
            sync_publish('metrics', None)

    # close database connection
    from jesse.services.db import database
    database.close_connection()
Example #15
0
def test_should_execute_silently():
    assert jh.should_execute_silently() is True
Example #16
0
def generate_signal(start_date: str,
                    finish_date: str,
                    candles=None,
                    chart=False,
                    tradingview=False,
                    csv=False,
                    json=False):
    # clear the screen
    if not jh.should_execute_silently():
        click.clear()

    # validate routes
    validate_routes(router)

    # initiate candle store
    store.candles.init_storage(5000)

    # load historical candles
    if candles is None:
        print('loading candles...')
        candles = load_candles(start_date, finish_date)
        click.clear()

    if not jh.should_execute_silently():
        # print candles table
        key = '{}-{}'.format(config['app']['considering_candles'][0][0],
                             config['app']['considering_candles'][0][1])
        table.key_value(stats.candles(candles[key]['candles']),
                        'candles',
                        alignments=('left', 'right'))
        print('\n')

        # print routes table
        table.multi_value(stats.routes(router.routes))
        print('\n')

        # print guidance for debugging candles
        if jh.is_debuggable('trading_candles') or jh.is_debuggable(
                'shorter_period_candles'):
            print(
                '     Symbol  |     timestamp    | open | close | high | low | volume'
            )

    # run backtest simulation
    signal_simulator(candles)

    if not jh.should_execute_silently():
        # print trades statistics
        if store.completed_trades.count > 0:
            print('\n')
            table.key_value(report.portfolio_metrics(),
                            'Metrics',
                            alignments=('left', 'right'))
            print('\n')

            # save logs
            store_logs(json, tradingview, csv)

            if chart:
                charts.portfolio_vs_asset_returns()

            # # clone the trades so that the original is not mutated
            # completed_trades = copy.deepcopy(store.completed_trades.trades)
            #
            # for trade in completed_trades:
            #     print(trade.to_dict())
            #
            # # filter trades which were generated for current day
            # completed_trades = filter(lambda x: x.opened_at == jh.get_current_time_in_epoch(), completed_trades)
            #
            # # TODO: add a slack notification here instead of print to notify the user
            # print("Trades to execute today: ")
            # for trade in completed_trades:
            #     print(trade.to_dict())
        else:
            print(jh.color('No trades were completed/closed.', 'yellow'))

        open_positions = store.positions.get_open_positions()
        open_orders = store.orders.get_all_active_orders()

        current_report = jh.generate_signals_report(open_positions,
                                                    open_orders)

        return current_report
Example #17
0
def simulator(candles: Dict[str, Dict[str, Union[str, np.ndarray]]],
              hyperparameters=None) -> None:
    begin_time_track = time.time()
    key = '{}-{}'.format(config['app']['considering_candles'][0][0],
                         config['app']['considering_candles'][0][1])
    first_candles_set = candles[key]['candles']
    length = len(first_candles_set)
    # to preset the array size for performance
    store.app.starting_time = first_candles_set[0][0]
    store.app.time = first_candles_set[0][0]

    # initiate strategies
    for r in router.routes:
        StrategyClass = jh.get_strategy_class(r.strategy_name)

        try:
            r.strategy = StrategyClass()
        except TypeError:
            raise exceptions.InvalidStrategy(
                "Looks like the structure of your strategy directory is incorrect. Make sure to include the strategy INSIDE the __init__.py file."
                "\nIf you need working examples, check out: https://github.com/jesse-ai/example-strategies"
            )
        except:
            raise

        r.strategy.name = r.strategy_name
        r.strategy.exchange = r.exchange
        r.strategy.symbol = r.symbol
        r.strategy.timeframe = r.timeframe

        # inject hyper parameters (used for optimize_mode)
        # convert DNS string into hyperparameters
        if r.dna and hyperparameters is None:
            hyperparameters = jh.dna_to_hp(r.strategy.hyperparameters(), r.dna)

        # inject hyperparameters sent within the optimize mode
        if hyperparameters is not None:
            r.strategy.hp = hyperparameters

        # init few objects that couldn't be initiated in Strategy __init__
        # it also injects hyperparameters into self.hp in case the route does not uses any DNAs
        r.strategy._init_objects()

        selectors.get_position(r.exchange, r.symbol).strategy = r.strategy

    # add initial balance
    save_daily_portfolio_balance()

    with click.progressbar(length=length,
                           label='Executing simulation...') as progressbar:
        for i in range(length):
            # update time
            store.app.time = first_candles_set[i][0] + 60_000

            # add candles
            for j in candles:
                short_candle = candles[j]['candles'][i]
                if i != 0:
                    previous_short_candle = candles[j]['candles'][i - 1]
                    short_candle = _get_fixed_jumped_candle(
                        previous_short_candle, short_candle)
                exchange = candles[j]['exchange']
                symbol = candles[j]['symbol']

                store.candles.add_candle(short_candle,
                                         exchange,
                                         symbol,
                                         '1m',
                                         with_execution=False,
                                         with_generation=False)

                # print short candle
                if jh.is_debuggable('shorter_period_candles'):
                    print_candle(short_candle, True, symbol)

                _simulate_price_change_effect(short_candle, exchange, symbol)

                # generate and add candles for bigger timeframes
                for timeframe in config['app']['considering_timeframes']:
                    # for 1m, no work is needed
                    if timeframe == '1m':
                        continue

                    count = jh.timeframe_to_one_minutes(timeframe)
                    until = count - ((i + 1) % count)

                    if (i + 1) % count == 0:
                        generated_candle = generate_candle_from_one_minutes(
                            timeframe,
                            candles[j]['candles'][(i - (count - 1)):(i + 1)])
                        store.candles.add_candle(generated_candle,
                                                 exchange,
                                                 symbol,
                                                 timeframe,
                                                 with_execution=False,
                                                 with_generation=False)

            # update progressbar
            if not jh.is_debugging() and not jh.should_execute_silently(
            ) and i % 60 == 0:
                progressbar.update(60)

            # now that all new generated candles are ready, execute
            for r in router.routes:
                count = jh.timeframe_to_one_minutes(r.timeframe)
                # 1m timeframe
                if r.timeframe == timeframes.MINUTE_1:
                    r.strategy._execute()
                elif (i + 1) % count == 0:
                    # print candle
                    if jh.is_debuggable('trading_candles'):
                        print_candle(
                            store.candles.get_current_candle(
                                r.exchange, r.symbol, r.timeframe), False,
                            r.symbol)
                    r.strategy._execute()

            # now check to see if there's any MARKET orders waiting to be executed
            store.orders.execute_pending_market_orders()

            if i != 0 and i % 1440 == 0:
                save_daily_portfolio_balance()

    if not jh.should_execute_silently():
        if jh.is_debuggable('trading_candles') or jh.is_debuggable(
                'shorter_period_candles'):
            print('\n')

        # print executed time for the backtest session
        finish_time_track = time.time()
        print(
            'Executed backtest simulation in: ',
            '{} seconds'.format(round(finish_time_track - begin_time_track,
                                      2)))

    for r in router.routes:
        r.strategy._terminate()
        store.orders.execute_pending_market_orders()

    # now that backtest is finished, add finishing balance
    save_daily_portfolio_balance()
Example #18
0
def simulator(candles, hyper_parameters=None):
    begin_time_track = time.time()
    key = '{}-{}'.format(config['app']['trading_exchanges'][0],
                         config['app']['trading_symbols'][0])
    first_candles_set = candles[key]['candles']
    length = len(first_candles_set)
    # to preset the array size for performance
    store.app.starting_time = first_candles_set[0][0]

    # initiate strategies
    for r in router.routes:
        StrategyClass = jh.get_strategy_class(r.strategy_name)

        # convert DNS string into hyper_parameters
        if r.dna and hyper_parameters is None:
            hyper_parameters = jh.dna_to_hp(StrategyClass.hyper_parameters(),
                                            r.dna)

        r.strategy = StrategyClass()
        r.strategy.name = r.strategy_name
        r.strategy.exchange = r.exchange
        r.strategy.symbol = r.symbol
        r.strategy.timeframe = r.timeframe

        # init few objects that couldn't be initiated in Strategy __init__
        r.strategy._init_objects()

        # inject hyper parameters (used for optimize_mode)
        if hyper_parameters is not None:
            r.strategy.hp = hyper_parameters

        selectors.get_position(r.exchange, r.symbol).strategy = r.strategy

    # add initial balance
    _save_daily_portfolio_balance()

    with click.progressbar(length=length,
                           label='Executing simulation...') as progressbar:
        for i in range(length):
            # update time
            store.app.time = first_candles_set[i][0] + 60_000

            # add candles
            for j in candles:
                short_candle = candles[j]['candles'][i]
                exchange = candles[j]['exchange']
                symbol = candles[j]['symbol']

                store.candles.add_candle(short_candle,
                                         exchange,
                                         symbol,
                                         '1m',
                                         with_execution=False,
                                         with_generation=False)

                # print short candle
                if jh.is_debuggable('shorter_period_candles'):
                    print_candle(short_candle, True, symbol)

                _simulate_price_change_effect(short_candle, exchange, symbol)

                # generate and add candles for bigger timeframes
                for timeframe in config['app']['considering_timeframes']:
                    # for 1m, no work is needed
                    if timeframe == '1m':
                        continue

                    count = jh.timeframe_to_one_minutes(timeframe)
                    until = count - ((i + 1) % count)

                    if (i + 1) % count == 0:
                        generated_candle = generate_candle_from_one_minutes(
                            timeframe,
                            candles[j]['candles'][(i - (count - 1)):(i + 1)])
                        store.candles.add_candle(generated_candle,
                                                 exchange,
                                                 symbol,
                                                 timeframe,
                                                 with_execution=False,
                                                 with_generation=False)

            # update progressbar
            if not jh.is_debugging() and not jh.should_execute_silently(
            ) and i % 60 == 0:
                progressbar.update(60)

            # now that all new generated candles are ready, execute
            for r in router.routes:
                count = jh.timeframe_to_one_minutes(r.timeframe)
                # 1m timeframe
                if r.timeframe == timeframes.MINUTE_1:
                    r.strategy._execute()
                elif (i + 1) % count == 0:
                    # print candle
                    if jh.is_debuggable('trading_candles'):
                        print_candle(
                            store.candles.get_current_candle(
                                r.exchange, r.symbol, r.timeframe), False,
                            r.symbol)
                    r.strategy._execute()

            # now check to see if there's any MARKET orders waiting to be executed
            store.orders.execute_pending_market_orders()

            if i != 0 and i % 1440 == 0:
                _save_daily_portfolio_balance()

    if not jh.should_execute_silently():
        if jh.is_debuggable('trading_candles') or jh.is_debuggable(
                'shorter_period_candles'):
            print('\n')

        # print executed time for the backtest session
        finish_time_track = time.time()
        print(
            'Executed backtest simulation in: ',
            '{} seconds'.format(round(finish_time_track - begin_time_track,
                                      2)))

    for r in router.routes:
        r.strategy._terminate()

    # now that backtest is finished, add finishing balance
    _save_daily_portfolio_balance()
Example #19
0
def run(start_date: str,
        finish_date: str,
        candles: Dict[str, Dict[str, Union[str, np.ndarray]]] = None,
        chart: bool = False,
        tradingview: bool = False,
        full_reports: bool = False,
        csv: bool = False,
        json: bool = False) -> None:
    # clear the screen
    if not jh.should_execute_silently():
        click.clear()

    # validate routes
    validate_routes(router)

    # initiate candle store
    store.candles.init_storage(5000)

    # load historical candles
    if candles is None:
        print('loading candles...')
        candles = load_candles(start_date, finish_date)
        click.clear()

    if not jh.should_execute_silently():
        # print candles table
        key = '{}-{}'.format(config['app']['considering_candles'][0][0],
                             config['app']['considering_candles'][0][1])
        table.key_value(stats.candles(candles[key]['candles']),
                        'candles',
                        alignments=('left', 'right'))
        print('\n')

        # print routes table
        table.multi_value(stats.routes(router.routes))
        print('\n')

        # print guidance for debugging candles
        if jh.is_debuggable('trading_candles') or jh.is_debuggable(
                'shorter_period_candles'):
            print(
                '     Symbol  |     timestamp    | open | close | high | low | volume'
            )

    # run backtest simulation
    simulator(candles)

    if not jh.should_execute_silently():
        # print trades metrics
        if store.completed_trades.count > 0:

            change = []
            # calcualte market change
            for e in router.routes:
                if e.strategy is None:
                    return

                first = Candle.select(Candle.close).where(
                    Candle.timestamp == jh.date_to_timestamp(start_date),
                    Candle.exchange == e.exchange,
                    Candle.symbol == e.symbol).first()
                last = Candle.select(Candle.close).where(
                    Candle.timestamp == jh.date_to_timestamp(finish_date) -
                    60000, Candle.exchange == e.exchange,
                    Candle.symbol == e.symbol).first()

                change.append(
                    ((last.close - first.close) / first.close) * 100.0)

            data = report.portfolio_metrics()
            data.append(
                ['Market Change',
                 str(round(np.average(change), 2)) + "%"])
            print('\n')
            table.key_value(data, 'Metrics', alignments=('left', 'right'))
            print('\n')

            # save logs
            store_logs(json, tradingview, csv)

            if chart:
                charts.portfolio_vs_asset_returns()

            # QuantStats' report
            if full_reports:
                quantstats.quantstats_tearsheet()
        else:
            print(jh.color('No trades were made.', 'yellow'))
Example #20
0
def run(start_date: str,
        finish_date: str,
        candles: Dict[str, Dict[str, Union[str, np.ndarray]]] = None,
        chart: bool = False,
        tradingview: bool = False,
        full_reports: bool = False,
        csv: bool = False,
        json: bool = False) -> None:
    # clear the screen
    if not jh.should_execute_silently():
        click.clear()

    # validate routes
    validate_routes(router)

    # initiate candle store
    store.candles.init_storage(5000)

    # load historical candles
    if candles is None:
        print('loading candles...')
        candles = load_candles(start_date, finish_date)
        click.clear()

    if not jh.should_execute_silently():
        # print candles table
        key = f"{config['app']['considering_candles'][0][0]}-{config['app']['considering_candles'][0][1]}"
        table.key_value(stats.candles(candles[key]['candles']),
                        'candles',
                        alignments=('left', 'right'))
        print('\n')

        # print routes table
        table.multi_value(stats.routes(router.routes))
        print('\n')

        # print guidance for debugging candles
        if jh.is_debuggable('trading_candles') or jh.is_debuggable(
                'shorter_period_candles'):
            print(
                '     Symbol  |     timestamp    | open | close | high | low | volume'
            )

    # run backtest simulation
    simulator(candles)

    if not jh.should_execute_silently():
        # print trades metrics
        if store.completed_trades.count > 0:

            change = []
            # calcualte market change
            for e in router.routes:
                if e.strategy is None:
                    return

                first = Candle.select(Candle.close).where(
                    Candle.timestamp == jh.date_to_timestamp(start_date),
                    Candle.exchange == e.exchange,
                    Candle.symbol == e.symbol).first()
                last = Candle.select(Candle.close).where(
                    Candle.timestamp == jh.date_to_timestamp(finish_date) -
                    60000, Candle.exchange == e.exchange,
                    Candle.symbol == e.symbol).first()

                change.append(
                    ((last.close - first.close) / first.close) * 100.0)

            data = report.portfolio_metrics()
            data.append(
                ['Market Change', f"{str(round(np.average(change), 2))}%"])
            print('\n')
            table.key_value(data, 'Metrics', alignments=('left', 'right'))
            print('\n')

            # save logs
            more = ""
            routes_count = len(router.routes)
            if routes_count > 1:
                more = f"-and-{routes_count-1}-more"

            study_name = f"{router.routes[0].strategy_name}-{router.routes[0].exchange}-{router.routes[0].symbol}-{router.routes[0].timeframe}{more}-{start_date}-{finish_date}"
            store_logs(study_name, json, tradingview, csv)

            if chart:
                charts.portfolio_vs_asset_returns(study_name)

            # QuantStats' report
            if full_reports:

                price_data = []

                # load close candles for Buy and hold and calculate pct_change
                for index, c in enumerate(
                        config['app']['considering_candles']):
                    exchange, symbol = c[0], c[1]
                    if exchange in config['app'][
                            'trading_exchanges'] and symbol in config['app'][
                                'trading_symbols']:
                        # fetch from database
                        candles_tuple = Candle.select(
                            Candle.timestamp, Candle.close).where(
                                Candle.timestamp.between(
                                    jh.date_to_timestamp(start_date),
                                    jh.date_to_timestamp(finish_date) - 60000),
                                Candle.exchange == exchange,
                                Candle.symbol == symbol).order_by(
                                    Candle.timestamp.asc()).tuples()

                        candles = np.array(candles_tuple)

                        timestamps = candles[:, 0]
                        price_data.append(candles[:, 1])

                price_data = np.transpose(price_data)
                price_df = pd.DataFrame(price_data,
                                        index=pd.to_datetime(timestamps,
                                                             unit="ms"),
                                        dtype=float).resample('D').mean()
                price_pct_change = price_df.pct_change(1).fillna(0)
                bh_daily_returns_all_routes = price_pct_change.mean(1)
                quantstats.quantstats_tearsheet(bh_daily_returns_all_routes,
                                                study_name)
        else:
            print(jh.color('No trades were made.', 'yellow'))