def backtest(backtest_conf, backdata, mocker):
    trades = []
    exchange._API = Bittrex({'key': '', 'secret': ''})
    mocked_history = mocker.patch('freqtrade.analyze.get_ticker_history')
    mocker.patch.dict('freqtrade.main._CONF', backtest_conf)
    mocker.patch('arrow.utcnow', return_value=arrow.get('2017-08-20T14:50:00'))
    for pair, pair_data in backdata.items():
        mocked_history.return_value = pair_data
        ticker = analyze_ticker(pair)[['close', 'date', 'buy']].copy()
        # for each buy point
        for row in ticker[ticker.buy == 1].itertuples(index=True):
            trade = Trade(open_rate=row.close,
                          open_date=row.date,
                          amount=1,
                          fee=exchange.get_fee() * 2)
            # calculate win/lose forwards from buy point
            for row2 in ticker[row.Index:].itertuples(index=True):
                if should_sell(trade, row2.close, row2.date):
                    current_profit = trade.calc_profit(row2.close)

                    trades.append(
                        (pair, current_profit, row2.Index - row.Index))
                    break
    labels = ['currency', 'profit', 'duration']
    results = DataFrame.from_records(trades, columns=labels)
    return results
Exemple #2
0
def backtest(backtest_conf, processed, mocker):
    trades = []
    exchange._API = Bittrex({'key': '', 'secret': ''})
    mocker.patch.dict('freqtrade.main._CONF', backtest_conf)
    for pair, pair_data in processed.items():
        pair_data['buy'] = 0
        pair_data['sell'] = 0
        ticker = populate_sell_trend(populate_buy_trend(pair_data))
        # for each buy point
        for row in ticker[ticker.buy == 1].itertuples(index=True):
            trade = Trade(open_rate=row.close,
                          open_date=row.date,
                          amount=backtest_conf['stake_amount'],
                          fee=exchange.get_fee() * 2)
            # calculate win/lose forwards from buy point
            for row2 in ticker[row.Index:].itertuples(index=True):
                if min_roi_reached(trade, row2.close,
                                   row2.date) or row2.sell == 1:
                    current_profit = trade.calc_profit(row2.close)

                    trades.append(
                        (pair, current_profit, row2.Index - row.Index))
                    break
    labels = ['currency', 'profit', 'duration']
    return DataFrame.from_records(trades, columns=labels)
Exemple #3
0
def test_backtest(default_conf, mocker):
    mocker.patch.dict('freqtrade.main._CONF', default_conf)
    exchange._API = Bittrex({'key': '', 'secret': ''})

    data = optimize.load_data(None, ticker_interval=5, pairs=['BTC_ETH'])
    results = backtest(default_conf['stake_amount'], optimize.preprocess(data),
                       10, True)
    assert not results.empty
Exemple #4
0
def test_backtest_1min_ticker_interval(default_conf, mocker):
    mocker.patch.dict('freqtrade.main._CONF', default_conf)
    exchange._API = Bittrex({'key': '', 'secret': ''})

    # Run a backtesting for an exiting 5min ticker_interval
    data = optimize.load_data(None, ticker_interval=1, pairs=['BTC_UNITEST'])
    results = backtest(default_conf['stake_amount'], optimize.preprocess(data),
                       1, True)
    assert not results.empty
Exemple #5
0
 def _init(self) -> None:
     """
     Init objects required for backtesting
     :return: None
     """
     self.analyze = Analyze(self.config)
     self.ticker_interval = self.analyze.strategy.ticker_interval
     self.tickerdata_to_dataframe = self.analyze.tickerdata_to_dataframe
     self.populate_buy_trend = self.analyze.populate_buy_trend
     self.populate_sell_trend = self.analyze.populate_sell_trend
     exchange._API = Bittrex({'key': '', 'secret': ''})
Exemple #6
0
def test_backtest(backtest_conf, mocker):
    print('')
    exchange._API = Bittrex({'key': '', 'secret': ''})

    # Load configuration file based on env variable
    conf_path = os.environ.get('BACKTEST_CONFIG')
    if conf_path:
        print('Using config: {} ...'.format(conf_path))
        config = load_config(conf_path)
    else:
        config = backtest_conf

    # Parse ticker interval
    ticker_interval = int(os.environ.get('BACKTEST_TICKER_INTERVAL') or 5)
    print('Using ticker_interval: {} ...'.format(ticker_interval))

    data = {}
    if os.environ.get('BACKTEST_LIVE'):
        print('Downloading data for all pairs in whitelist ...')
        for pair in config['exchange']['pair_whitelist']:
            data[pair] = exchange.get_ticker_history(pair, ticker_interval)
    else:
        print(
            'Using local backtesting data (ignoring whitelist in given config)...'
        )
        data = load_backtesting_data(ticker_interval)

    print('Using stake_currency: {} ...\nUsing stake_amount: {} ...'.format(
        config['stake_currency'], config['stake_amount']))

    # Print timeframe
    min_date, max_date = get_timeframe(data)
    print('Measuring data from {} up to {} ...'.format(min_date.isoformat(),
                                                       max_date.isoformat()))

    # Execute backtest and print results
    results = backtest(config, preprocess(data), mocker)
    print(
        '====================== BACKTESTING REPORT ======================================\n\n'
        'NOTE: This Report doesn\'t respect the limits of max_open_trades, \n'
        '      so the projected values should be taken with a grain of salt.\n'
    )
    print(generate_text_table(data, results, config['stake_currency']))
Exemple #7
0
    ax1.plot(dataframe.index.values, dataframe['blower'], '-.', label='BB low')
    ax1.plot(dataframe.index.values, dataframe['buy_price'], 'bo', label='buy')
    ax1.legend()

    ax2.plot(dataframe.index.values, dataframe['adx'], label='ADX')
    ax2.plot(dataframe.index.values, dataframe['mfi'], label='MFI')
    # ax2.plot(dataframe.index.values, [25] * len(dataframe.index.values))
    ax2.legend()

    ax3.plot(dataframe.index.values, dataframe['fastk'], label='k')
    ax3.plot(dataframe.index.values, dataframe['fastd'], label='d')
    ax3.plot(dataframe.index.values, [20] * len(dataframe.index.values))
    ax3.legend()

    # Fine-tune figure; make subplots close to each other and hide x ticks for
    # all but bottom plot.
    fig.subplots_adjust(hspace=0)
    plt.setp([a.get_xticklabels() for a in fig.axes[:-1]], visible=False)
    plt.show()


if __name__ == '__main__':
    # Install PYQT5==5.9 manually if you want to test this helper function
    while True:
        exchange.EXCHANGE = Bittrex({'key': '', 'secret': ''})
        test_pair = 'BTC_ETH'
        # for pair in ['BTC_ANT', 'BTC_ETH', 'BTC_GNT', 'BTC_ETC']:
        #     get_buy_signal(pair)
        plot_dataframe(analyze_ticker(test_pair), test_pair)
        time.sleep(60)
Exemple #8
0
def test_hyperopt(backtest_conf, mocker):
    mocked_buy_trend = mocker.patch('freqtrade.tests.test_backtesting.populate_buy_trend')

    backdata = load_backtesting_data()
    processed = preprocess(backdata)
    exchange._API = Bittrex({'key': '', 'secret': ''})

    def optimizer(params):
        mocked_buy_trend.side_effect = buy_strategy_generator(params)

        results = backtest(backtest_conf, processed, mocker)

        result = format_results(results)

        total_profit = results.profit.sum() * 1000
        trade_count = len(results.index)

        trade_loss = 1 - 0.35 * exp(-(trade_count - TARGET_TRADES) ** 2 / 10 ** 5.2)
        profit_loss = max(0, 1 - total_profit / 10000)  # max profit 10000

        # pylint: disable=W0603
        global current_tries
        current_tries += 1
        print('{:5d}/{}: {}'.format(current_tries, TOTAL_TRIES, result))

        return {
            'loss': trade_loss + profit_loss,
            'status': STATUS_OK,
            'result': result
        }

    space = {
        'mfi': hp.choice('mfi', [
            {'enabled': False},
            {'enabled': True, 'value': hp.quniform('mfi-value', 5, 25, 1)}
        ]),
        'fastd': hp.choice('fastd', [
            {'enabled': False},
            {'enabled': True, 'value': hp.quniform('fastd-value', 10, 50, 1)}
        ]),
        'adx': hp.choice('adx', [
            {'enabled': False},
            {'enabled': True, 'value': hp.quniform('adx-value', 15, 50, 1)}
        ]),
        'rsi': hp.choice('rsi', [
            {'enabled': False},
            {'enabled': True, 'value': hp.quniform('rsi-value', 20, 40, 1)}
        ]),
        'uptrend_long_ema': hp.choice('uptrend_long_ema', [
            {'enabled': False},
            {'enabled': True}
        ]),
        'uptrend_short_ema': hp.choice('uptrend_short_ema', [
            {'enabled': False},
            {'enabled': True}
        ]),
        'over_sar': hp.choice('over_sar', [
            {'enabled': False},
            {'enabled': True}
        ]),
        'green_candle': hp.choice('green_candle', [
            {'enabled': False},
            {'enabled': True}
        ]),
        'uptrend_sma': hp.choice('uptrend_sma', [
            {'enabled': False},
            {'enabled': True}
        ]),
        'trigger': hp.choice('trigger', [
            {'type': 'lower_bb'},
            {'type': 'faststoch10'},
            {'type': 'ao_cross_zero'},
            {'type': 'ema5_cross_ema10'},
            {'type': 'macd_cross_signal'},
            {'type': 'sar_reversal'},
            {'type': 'stochf_cross'},
            {'type': 'ht_sine'},
        ]),
    }
    trials = Trials()
    best = fmin(fn=optimizer, space=space, algo=tpe.suggest, max_evals=TOTAL_TRIES, trials=trials)
    print('\n\n\n\n==================== HYPEROPT BACKTESTING REPORT ==============================')
    print('Best parameters {}'.format(best))
    newlist = sorted(trials.results, key=itemgetter('loss'))
    print('Result: {}'.format(newlist[0]['result']))
Exemple #9
0
#!/usr/bin/env python3
"""This script generate json data from bittrex"""
import json
from os import path

from freqtrade import exchange
from freqtrade.exchange import Bittrex

PAIRS = [
    'BTC_BCC', 'BTC_ETH', 'BTC_MER', 'BTC_POWR', 'BTC_ETC', 'BTC_OK',
    'BTC_NEO', 'BTC_EMC2', 'BTC_DASH', 'BTC_LSK', 'BTC_LTC', 'BTC_XZC',
    'BTC_OMG', 'BTC_STRAT', 'BTC_XRP', 'BTC_QTUM', 'BTC_WAVES', 'BTC_VTC',
    'BTC_XLM', 'BTC_MCO'
]
TICKER_INTERVAL = 5  # ticker interval in minutes (currently implemented: 1 and 5)
OUTPUT_DIR = path.dirname(path.realpath(__file__))

# Init Bittrex exchange
exchange._API = Bittrex({'key': '', 'secret': ''})

for pair in PAIRS:
    data = exchange.get_ticker_history(pair, TICKER_INTERVAL)
    filename = path.join(OUTPUT_DIR, '{}-{}.json'.format(
        pair,
        TICKER_INTERVAL,
    ))
    with open(filename, 'w') as fp:
        json.dump(data, fp)
Exemple #10
0
def start(args):
    global TOTAL_TRIES, PROCESSED, SPACE, TRIALS, _CURRENT_TRIES

    TOTAL_TRIES = args.epochs

    exchange._API = Bittrex({'key': '', 'secret': ''})

    # Initialize logger
    logging.basicConfig(
        level=args.loglevel,
        format='\n%(message)s',
    )

    logger.info('Using config: %s ...', args.config)
    config = load_config(args.config)
    pairs = config['exchange']['pair_whitelist']
    PROCESSED = optimize.preprocess(
        optimize.load_data(args.datadir,
                           pairs=pairs,
                           ticker_interval=args.ticker_interval))

    if args.mongodb:
        logger.info('Using mongodb ...')
        logger.info(
            'Start scripts/start-mongodb.sh and start-hyperopt-worker.sh manually!'
        )

        db_name = 'freqtrade_hyperopt'
        TRIALS = MongoTrials('mongo://127.0.0.1:1234/{}/jobs'.format(db_name),
                             exp_key='exp1')
    else:
        logger.info('Preparing Trials..')
        signal.signal(signal.SIGINT, signal_handler)
        # read trials file if we have one
        if os.path.exists(TRIALS_FILE):
            TRIALS = read_trials()

            _CURRENT_TRIES = len(TRIALS.results)
            TOTAL_TRIES = TOTAL_TRIES + _CURRENT_TRIES
            logger.info(
                'Continuing with trials. Current: {}, Total: {}'.format(
                    _CURRENT_TRIES, TOTAL_TRIES))

    try:
        best_parameters = fmin(fn=optimizer,
                               space=SPACE,
                               algo=tpe.suggest,
                               max_evals=TOTAL_TRIES,
                               trials=TRIALS)

        results = sorted(TRIALS.results, key=itemgetter('loss'))
        best_result = results[0]['result']

    except ValueError:
        best_parameters = {}
        best_result = 'Sorry, Hyperopt was not able to find good parameters. Please ' \
                      'try with more epochs (param: -e).'

    # Improve best parameter logging display
    if best_parameters:
        best_parameters = space_eval(SPACE, best_parameters)

    logger.info('Best parameters:\n%s', json.dumps(best_parameters, indent=4))
    logger.info('Best Result:\n%s', best_result)

    # Store trials result to file to resume next time
    save_trials(TRIALS)
Exemple #11
0
def backtest(stake_amount: float,
             processed: Dict[str, DataFrame],
             max_open_trades: int = 0,
             realistic: bool = True,
             sell_profit_only: bool = False,
             stoploss: int = -1.00,
             use_sell_signal: bool = False) -> DataFrame:
    """
    Implements backtesting functionality
    :param stake_amount: btc amount to use for each trade
    :param processed: a processed dictionary with format {pair, data}
    :param max_open_trades: maximum number of concurrent trades (default: 0, disabled)
    :param realistic: do we try to simulate realistic trades? (default: True)
    :return: DataFrame
    """
    trades = []
    trade_count_lock: dict = {}
    exchange._API = Bittrex({'key': '', 'secret': ''})
    for pair, pair_data in processed.items():
        pair_data['buy'], pair_data['sell'] = 0, 0
        ticker = populate_sell_trend(populate_buy_trend(pair_data))
        # for each buy point
        lock_pair_until = None
        buy_subset = ticker[ticker.buy == 1][[
            'buy', 'open', 'close', 'date', 'sell'
        ]]
        for row in buy_subset.itertuples(index=True):
            if realistic:
                if lock_pair_until is not None and row.Index <= lock_pair_until:
                    continue
            if max_open_trades > 0:
                # Check if max_open_trades has already been reached for the given date
                if not trade_count_lock.get(row.date, 0) < max_open_trades:
                    continue

            if max_open_trades > 0:
                # Increase lock
                trade_count_lock[row.date] = trade_count_lock.get(row.date,
                                                                  0) + 1

            trade = Trade(open_rate=row.close,
                          open_date=row.date,
                          stake_amount=stake_amount,
                          amount=stake_amount / row.open,
                          fee=exchange.get_fee())

            # calculate win/lose forwards from buy point
            sell_subset = ticker[row.Index + 1:][['close', 'date', 'sell']]
            for row2 in sell_subset.itertuples(index=True):
                if max_open_trades > 0:
                    # Increase trade_count_lock for every iteration
                    trade_count_lock[row2.date] = trade_count_lock.get(
                        row2.date, 0) + 1

                current_profit_percent = trade.calc_profit_percent(
                    rate=row2.close)
                if (sell_profit_only and current_profit_percent < 0):
                    continue
                if min_roi_reached(trade, row2.close, row2.date) or \
                    (row2.sell == 1 and use_sell_signal) or \
                        current_profit_percent <= stoploss:
                    current_profit_btc = trade.calc_profit(rate=row2.close)
                    lock_pair_until = row2.Index

                    trades.append(
                        (pair, current_profit_percent, current_profit_btc,
                         row2.Index - row.Index, current_profit_btc > 0,
                         current_profit_btc < 0))
                    break
    labels = [
        'currency', 'profit_percent', 'profit_BTC', 'duration', 'profit',
        'loss'
    ]
    return DataFrame.from_records(trades, columns=labels)
Exemple #12
0
def start(args):
    # Initialize logger
    logging.basicConfig(
        level=args.loglevel,
        format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
    )

    exchange._API = Bittrex({'key': '', 'secret': ''})

    logger.info('Using config: %s ...', args.config)
    config = misc.load_config(args.config)

    logger.info('Using ticker_interval: %s ...', args.ticker_interval)

    data = {}
    pairs = config['exchange']['pair_whitelist']
    if args.live:
        logger.info('Downloading data for all pairs in whitelist ...')
        for pair in pairs:
            data[pair] = exchange.get_ticker_history(pair,
                                                     args.ticker_interval)
    else:
        logger.info(
            'Using local backtesting data (using whitelist in given config) ...'
        )
        data = optimize.load_data(args.datadir,
                                  pairs=pairs,
                                  ticker_interval=args.ticker_interval,
                                  refresh_pairs=args.refresh_pairs)

        logger.info('Using stake_currency: %s ...', config['stake_currency'])
        logger.info('Using stake_amount: %s ...', config['stake_amount'])

    max_open_trades = 0
    if args.realistic_simulation:
        logger.info('Using max_open_trades: %s ...', config['max_open_trades'])
        max_open_trades = config['max_open_trades']

    # Monkey patch config
    from freqtrade import main
    main._CONF = config

    preprocessed = preprocess(data)
    # Print timeframe
    min_date, max_date = get_timeframe(preprocessed)
    logger.info('Measuring data from %s up to %s ...', min_date.isoformat(),
                max_date.isoformat())

    # Execute backtest and print results
    results = backtest(
        stake_amount=config['stake_amount'],
        processed=preprocessed,
        max_open_trades=max_open_trades,
        realistic=args.realistic_simulation,
        sell_profit_only=config.get('experimental',
                                    {}).get('sell_profit_only', False),
        stoploss=config.get('stoploss'),
        use_sell_signal=config.get('experimental',
                                   {}).get('use_sell_signal', False))
    logger.info(
        '\n==================================== BACKTESTING REPORT ====================================\n%s',  # noqa
        generate_text_table(data, results, config['stake_currency'],
                            args.ticker_interval))