Ejemplo n.º 1
0
def test_backtest(default_conf, fee, mocker, testdatadir) -> None:
    default_conf['ask_strategy']['use_sell_signal'] = False
    mocker.patch('freqtrade.exchange.Exchange.get_fee', fee)
    patch_exchange(mocker)
    backtesting = Backtesting(default_conf)
    pair = 'UNITTEST/BTC'
    timerange = TimeRange('date', None, 1517227800, 0)
    data = history.load_data(datadir=testdatadir,
                             timeframe='5m',
                             pairs=['UNITTEST/BTC'],
                             timerange=timerange)
    data_processed = backtesting.strategy.tickerdata_to_dataframe(data)
    min_date, max_date = get_timeframe(data_processed)
    results = backtesting.backtest({
        'stake_amount': default_conf['stake_amount'],
        'processed': data_processed,
        'max_open_trades': 10,
        'position_stacking': False,
        'start_date': min_date,
        'end_date': max_date,
    })
    assert not results.empty
    assert len(results) == 2

    expected = pd.DataFrame({
        'pair': [pair, pair],
        'profit_percent': [0.0, 0.0],
        'profit_abs': [0.0, 0.0],
        'open_time':
        pd.to_datetime([
            Arrow(2018, 1, 29, 18, 40, 0).datetime,
            Arrow(2018, 1, 30, 3, 30, 0).datetime
        ],
                       utc=True),
        'close_time':
        pd.to_datetime([
            Arrow(2018, 1, 29, 22, 35, 0).datetime,
            Arrow(2018, 1, 30, 4, 10, 0).datetime
        ],
                       utc=True),
        'open_index': [78, 184],
        'close_index': [125, 192],
        'trade_duration': [235, 40],
        'open_at_end': [False, False],
        'open_rate': [0.104445, 0.10302485],
        'close_rate': [0.104969, 0.103541],
        'sell_reason': [SellType.ROI, SellType.ROI]
    })
    pd.testing.assert_frame_equal(results, expected)
    data_pair = data_processed[pair]
    for _, t in results.iterrows():
        ln = data_pair.loc[data_pair["date"] == t["open_time"]]
        # Check open trade rate alignes to open rate
        assert ln is not None
        assert round(ln.iloc[0]["open"], 6) == round(t["open_rate"], 6)
        # check close trade rate alignes to close rate or is between high and low
        ln = data_pair.loc[data_pair["date"] == t["close_time"]]
        assert (round(ln.iloc[0]["open"], 6) == round(t["close_rate"], 6)
                or round(ln.iloc[0]["low"], 6) < round(
                    t["close_rate"], 6) < round(ln.iloc[0]["high"], 6))
Ejemplo n.º 2
0
    def load_bt_data(self) -> Tuple[Dict[str, DataFrame], TimeRange]:
        """
        Loads backtest data and returns the data combined with the timerange
        as tuple.
        """
        timerange = TimeRange.parse_timerange(None if self.config.get(
            'timerange') is None else str(self.config.get('timerange')))

        data = history.load_data(
            datadir=self.config['datadir'],
            pairs=self.pairlists.whitelist,
            timeframe=self.timeframe,
            timerange=timerange,
            startup_candles=self.required_startup,
            fail_without_data=True,
            data_format=self.config.get('dataformat_ohlcv', 'json'),
        )

        min_date, max_date = history.get_timerange(data)

        logger.info(f'Loading data from {min_date.strftime(DATETIME_PRINT_FORMAT)} '
                    f'up to {max_date.strftime(DATETIME_PRINT_FORMAT)} '
                    f'({(max_date - min_date).days} days).')

        # Adjust startts forward if not enough data is available
        timerange.adjust_start_if_necessary(timeframe_to_seconds(self.timeframe),
                                            self.required_startup, min_date)

        return data, timerange
Ejemplo n.º 3
0
def test_generate_profit_graph():
    filename = history.make_testdata_path(None) / "backtest-result_test.json"
    trades = load_backtest_data(filename)
    timerange = TimeRange.parse_timerange("20180110-20180112")
    pairs = ["POWR/BTC", "XLM/BTC"]

    tickers = history.load_data(datadir=None,
                                pairs=pairs,
                                ticker_interval='5m',
                                timerange=timerange
                                )
    trades = trades[trades['pair'].isin(pairs)]

    fig = generate_profit_graph(pairs, tickers, trades)
    assert isinstance(fig, go.Figure)

    assert fig.layout.title.text == "Profit plot"
    figure = fig.layout.figure
    assert len(figure.data) == 4

    avgclose = find_trace_in_fig_data(figure.data, "Avg close price")
    assert isinstance(avgclose, go.Scattergl)

    profit = find_trace_in_fig_data(figure.data, "Profit")
    assert isinstance(profit, go.Scattergl)

    for pair in pairs:
        profit_pair = find_trace_in_fig_data(figure.data, f"Profit {pair}")
        assert isinstance(profit_pair, go.Scattergl)
Ejemplo n.º 4
0
def init_plotscript(config):
    """
    Initialize objects needed for plotting
    :return: Dict with tickers, trades and pairs
    """

    if "pairs" in config:
        pairs = config["pairs"]
    else:
        pairs = config["exchange"]["pair_whitelist"]

    # Set timerange to use
    timerange = TimeRange.parse_timerange(config.get("timerange"))

    tickers = load_data(
        datadir=config.get("datadir"),
        pairs=pairs,
        timeframe=config.get('ticker_interval', '5m'),
        timerange=timerange,
        data_format=config.get('dataformat_ohlcv', 'json'),
    )

    trades = load_trades(
        config['trade_source'],
        db_url=config.get('db_url'),
        exportfilename=config.get('exportfilename'),
    )
    trades = trim_dataframe(trades, timerange, 'open_time')
    return {
        "tickers": tickers,
        "trades": trades,
        "pairs": pairs,
    }
Ejemplo n.º 5
0
def test_add_indicators(default_conf, caplog):
    pair = "UNITTEST/BTC"
    timerange = TimeRange(None, 'line', 0, -1000)

    data = history.load_pair_history(pair=pair, ticker_interval='1m',
                                     datadir=None, timerange=timerange)
    indicators1 = ["ema10"]
    indicators2 = ["macd"]

    # Generate buy/sell signals and indicators
    strat = DefaultStrategy(default_conf)
    data = strat.analyze_ticker(data, {'pair': pair})
    fig = generage_empty_figure()

    # Row 1
    fig1 = add_indicators(fig=deepcopy(fig), row=1, indicators=indicators1, data=data)
    figure = fig1.layout.figure
    ema10 = find_trace_in_fig_data(figure.data, "ema10")
    assert isinstance(ema10, go.Scatter)
    assert ema10.yaxis == "y"

    fig2 = add_indicators(fig=deepcopy(fig), row=3, indicators=indicators2, data=data)
    figure = fig2.layout.figure
    macd = find_trace_in_fig_data(figure.data, "macd")
    assert isinstance(macd, go.Scatter)
    assert macd.yaxis == "y3"

    # No indicator found
    fig3 = add_indicators(fig=deepcopy(fig), row=3, indicators=['no_indicator'], data=data)
    assert fig == fig3
    assert log_has_re(r'Indicator "no_indicator" ignored\..*', caplog)
Ejemplo n.º 6
0
def test_hdf5datahandler_ohlcv_load_and_resave(testdatadir):
    dh = HDF5DataHandler(testdatadir)
    ohlcv = dh.ohlcv_load('UNITTEST/BTC', '5m')
    assert isinstance(ohlcv, DataFrame)
    assert len(ohlcv) > 0

    file = testdatadir / 'UNITTEST_NEW-5m.h5'
    assert not file.is_file()

    dh.ohlcv_store('UNITTEST/NEW', '5m', ohlcv)
    assert file.is_file()

    assert not ohlcv[ohlcv['date'] < '2018-01-15'].empty

    # Data gores from 2018-01-10 - 2018-01-30
    timerange = TimeRange.parse_timerange('20180115-20180119')

    # Call private function to ensure timerange is filtered in hdf5
    ohlcv = dh._ohlcv_load('UNITTEST/BTC', '5m', timerange)
    ohlcv1 = dh._ohlcv_load('UNITTEST/NEW', '5m', timerange)
    assert len(ohlcv) == len(ohlcv1)
    assert ohlcv.equals(ohlcv1)
    assert ohlcv[ohlcv['date'] < '2018-01-15'].empty
    assert ohlcv[ohlcv['date'] > '2018-01-19'].empty

    _clean_test_file(file)

    # Try loading inexisting file
    ohlcv = dh.ohlcv_load('UNITTEST/NONEXIST', '5m')
    assert ohlcv.empty
Ejemplo n.º 7
0
def test_generate_candlestick_graph_no_signals_no_trades(default_conf, mocker, caplog):
    row_mock = mocker.patch('freqtrade.plot.plotting.add_indicators',
                            MagicMock(side_effect=fig_generating_mock))
    trades_mock = mocker.patch('freqtrade.plot.plotting.plot_trades',
                               MagicMock(side_effect=fig_generating_mock))

    pair = "UNITTEST/BTC"
    timerange = TimeRange(None, 'line', 0, -1000)
    data = history.load_pair_history(pair=pair, ticker_interval='1m',
                                     datadir=None, timerange=timerange)
    data['buy'] = 0
    data['sell'] = 0

    indicators1 = []
    indicators2 = []
    fig = generate_candlestick_graph(pair=pair, data=data, trades=None,
                                     indicators1=indicators1, indicators2=indicators2)
    assert isinstance(fig, go.Figure)
    assert fig.layout.title.text == pair
    figure = fig.layout.figure

    assert len(figure.data) == 2
    # Candlesticks are plotted first
    candles = find_trace_in_fig_data(figure.data, "Price")
    assert isinstance(candles, go.Candlestick)

    volume = find_trace_in_fig_data(figure.data, "Volume")
    assert isinstance(volume, go.Bar)

    assert row_mock.call_count == 2
    assert trades_mock.call_count == 1

    assert log_has("No buy-signals found.", caplog)
    assert log_has("No sell-signals found.", caplog)
Ejemplo n.º 8
0
def test_convert_trades_to_ohlcv(mocker, default_conf, testdatadir, caplog):

    pair = 'XRP/ETH'
    file1 = testdatadir / 'XRP_ETH-1m.json'
    file5 = testdatadir / 'XRP_ETH-5m.json'
    # Compare downloaded dataset with converted dataset
    dfbak_1m = load_pair_history(datadir=testdatadir, timeframe="1m", pair=pair)
    dfbak_5m = load_pair_history(datadir=testdatadir, timeframe="5m", pair=pair)

    _backup_file(file1, copy_file=True)
    _backup_file(file5)

    tr = TimeRange.parse_timerange('20191011-20191012')

    convert_trades_to_ohlcv([pair], timeframes=['1m', '5m'],
                            datadir=testdatadir, timerange=tr, erase=True)

    assert log_has("Deleting existing data for pair XRP/ETH, interval 1m.", caplog)
    # Load new data
    df_1m = load_pair_history(datadir=testdatadir, timeframe="1m", pair=pair)
    df_5m = load_pair_history(datadir=testdatadir, timeframe="5m", pair=pair)

    assert df_1m.equals(dfbak_1m)
    assert df_5m.equals(dfbak_5m)

    _clean_test_file(file1)
    _clean_test_file(file5)

    assert not log_has('Could not convert NoDatapair to OHLCV.', caplog)

    convert_trades_to_ohlcv(['NoDatapair'], timeframes=['1m', '5m'],
                            datadir=testdatadir, timerange=tr, erase=True)
    assert log_has('Could not convert NoDatapair to OHLCV.', caplog)
Ejemplo n.º 9
0
    def load_bt_data(self) -> Tuple[Dict[str, DataFrame], TimeRange]:
        timerange = TimeRange.parse_timerange(None if self.config.get(
            'timerange') is None else str(self.config.get('timerange')))

        data = history.load_data(
            datadir=self.config['datadir'],
            pairs=self.config['exchange']['pair_whitelist'],
            timeframe=self.timeframe,
            timerange=timerange,
            startup_candles=self.required_startup,
            fail_without_data=True,
            data_format=self.config.get('dataformat_ohlcv', 'json'),
        )

        min_date, max_date = history.get_timerange(data)

        logger.info('Loading data from %s up to %s (%s days)..',
                    min_date.isoformat(), max_date.isoformat(),
                    (max_date - min_date).days)
        # Adjust startts forward if not enough data is available
        timerange.adjust_start_if_necessary(
            timeframe_to_seconds(self.timeframe), self.required_startup,
            min_date)

        return data, timerange
Ejemplo n.º 10
0
def test_backtest_1min_ticker_interval(default_conf, fee, mocker,
                                       testdatadir) -> None:
    default_conf['ask_strategy']['use_sell_signal'] = False
    mocker.patch('freqtrade.exchange.Exchange.get_fee', fee)
    patch_exchange(mocker)
    backtesting = Backtesting(default_conf)

    # Run a backtesting for an exiting 1min timeframe
    timerange = TimeRange.parse_timerange('1510688220-1510700340')
    data = history.load_data(datadir=testdatadir,
                             timeframe='1m',
                             pairs=['UNITTEST/BTC'],
                             timerange=timerange)
    processed = backtesting.strategy.tickerdata_to_dataframe(data)
    min_date, max_date = get_timeframe(processed)
    results = backtesting.backtest({
        'stake_amount': default_conf['stake_amount'],
        'processed': processed,
        'max_open_trades': 1,
        'position_stacking': False,
        'start_date': min_date,
        'end_date': max_date,
    })
    assert not results.empty
    assert len(results) == 1
Ejemplo n.º 11
0
def test_create_cum_profit1(testdatadir):
    filename = testdatadir / "backtest-result_test.json"
    bt_data = load_backtest_data(filename)
    # Move close-time to "off" the candle, to make sure the logic still works
    bt_data.loc[:, 'close_date'] = bt_data.loc[:, 'close_date'] + DateOffset(
        seconds=20)
    timerange = TimeRange.parse_timerange("20180110-20180112")

    df = load_pair_history(pair="TRX/BTC",
                           timeframe='5m',
                           datadir=testdatadir,
                           timerange=timerange)

    cum_profits = create_cum_profit(df.set_index('date'),
                                    bt_data[bt_data["pair"] == 'TRX/BTC'],
                                    "cum_profits",
                                    timeframe="5m")
    assert "cum_profits" in cum_profits.columns
    assert cum_profits.iloc[0]['cum_profits'] == 0
    assert cum_profits.iloc[-1]['cum_profits'] == 0.0798005

    with pytest.raises(ValueError, match='Trade dataframe empty.'):
        create_cum_profit(df.set_index('date'),
                          bt_data[bt_data["pair"] == 'NOTAPAIR'],
                          "cum_profits",
                          timeframe="5m")
Ejemplo n.º 12
0
def test_add_areas(default_conf, testdatadir, caplog):
    pair = "UNITTEST/BTC"
    timerange = TimeRange(None, 'line', 0, -1000)

    data = history.load_pair_history(pair=pair,
                                     timeframe='1m',
                                     datadir=testdatadir,
                                     timerange=timerange)
    indicators = {
        "macd": {
            "color": "red",
            "fill_color": "black",
            "fill_to": "macdhist",
            "fill_label": "MACD Fill"
        }
    }

    ind_no_label = {"macd": {"fill_color": "red", "fill_to": "macdhist"}}

    ind_plain = {"macd": {"fill_to": "macdhist"}}
    default_conf.update({'strategy': 'DefaultStrategy'})
    strategy = StrategyResolver.load_strategy(default_conf)

    # Generate buy/sell signals and indicators
    data = strategy.analyze_ticker(data, {'pair': pair})
    fig = generate_empty_figure()

    # indicator mentioned in fill_to does not exist
    fig1 = add_areas(fig, 1, data, {'ema10': {'fill_to': 'no_fill_indicator'}})
    assert fig == fig1
    assert log_has_re(r'fill_to: "no_fill_indicator" ignored\..*', caplog)

    # indicator does not exist
    fig2 = add_areas(fig, 1, data, {'no_indicator': {'fill_to': 'ema10'}})
    assert fig == fig2
    assert log_has_re(r'Indicator "no_indicator" ignored\..*', caplog)

    # everythin given in plot config, row 3
    fig3 = add_areas(fig, 3, data, indicators)
    figure = fig3.layout.figure
    fill_macd = find_trace_in_fig_data(figure.data, "MACD Fill")
    assert isinstance(fill_macd, go.Scatter)
    assert fill_macd.yaxis == "y3"
    assert fill_macd.fillcolor == "black"

    # label missing, row 1
    fig4 = add_areas(fig, 1, data, ind_no_label)
    figure = fig4.layout.figure
    fill_macd = find_trace_in_fig_data(figure.data, "macd<>macdhist")
    assert isinstance(fill_macd, go.Scatter)
    assert fill_macd.yaxis == "y"
    assert fill_macd.fillcolor == "red"

    # fit_to only
    fig5 = add_areas(fig, 1, data, ind_plain)
    figure = fig5.layout.figure
    fill_macd = find_trace_in_fig_data(figure.data, "macd<>macdhist")
    assert isinstance(fill_macd, go.Scatter)
    assert fill_macd.yaxis == "y"
Ejemplo n.º 13
0
def load_pair_history(pair: str,
                      ticker_interval: str,
                      datadir: Optional[Path],
                      timerange: TimeRange = TimeRange(None, None, 0, 0),
                      refresh_pairs: bool = False,
                      exchange: Optional[Exchange] = None,
                      fill_up_missing: bool = True,
                      drop_incomplete: bool = True) -> DataFrame:
    """
    Loads cached ticker history for the given pair.
    :param pair: Pair to load data for
    :param ticker_interval: Ticker-interval (e.g. "5m")
    :param datadir: Path to the data storage location.
    :param timerange: Limit data to be loaded to this timerange
    :param refresh_pairs: Refresh pairs from exchange.
        (Note: Requires exchange to be passed as well.)
    :param exchange: Exchange object (needed when using "refresh_pairs")
    :param fill_up_missing: Fill missing values with "No action"-candles
    :param drop_incomplete: Drop last candle assuming it may be incomplete.
    :return: DataFrame with ohlcv data
    """

    # The user forced the refresh of pairs
    if refresh_pairs:
        download_pair_history(datadir=datadir,
                              exchange=exchange,
                              pair=pair,
                              ticker_interval=ticker_interval,
                              timerange=timerange)

    pairdata = load_tickerdata_file(datadir,
                                    pair,
                                    ticker_interval,
                                    timerange=timerange)

    if pairdata:
        if timerange.starttype == 'date' and pairdata[0][
                0] > timerange.startts * 1000:
            logger.warning(
                'Missing data at start for pair %s, data starts at %s', pair,
                arrow.get(pairdata[0][0] //
                          1000).strftime('%Y-%m-%d %H:%M:%S'))
        if timerange.stoptype == 'date' and pairdata[-1][
                0] < timerange.stopts * 1000:
            logger.warning(
                'Missing data at end for pair %s, data ends at %s', pair,
                arrow.get(pairdata[-1][0] //
                          1000).strftime('%Y-%m-%d %H:%M:%S'))
        return parse_ticker_dataframe(pairdata,
                                      ticker_interval,
                                      pair=pair,
                                      fill_missing=fill_up_missing,
                                      drop_incomplete=drop_incomplete)
    else:
        logger.warning(
            f'No history data for pair: "{pair}", interval: {ticker_interval}. '
            'Use --refresh-pairs-cached option or download_backtest_data.py '
            'script to download the data')
        return None
Ejemplo n.º 14
0
def start_download_data(args: Dict[str, Any]) -> None:
    """
    Download data (former download_backtest_data.py script)
    """
    config = setup_utils_configuration(args, RunMode.UTIL_EXCHANGE)

    timerange = TimeRange()
    if 'days' in config:
        time_since = arrow.utcnow().shift(days=-config['days']).strftime("%Y%m%d")
        timerange = TimeRange.parse_timerange(f'{time_since}-')

    if 'pairs' not in config:
        raise OperationalException(
            "Downloading data requires a list of pairs. "
            "Please check the documentation on how to configure this.")

    logger.info(f'About to download pairs: {config["pairs"]}, '
                f'intervals: {config["timeframes"]} to {config["datadir"]}')

    pairs_not_available: List[str] = []

    # Init exchange
    exchange = ExchangeResolver.load_exchange(config['exchange']['name'], config)
    try:

        if config.get('download_trades'):
            pairs_not_available = refresh_backtest_trades_data(
                exchange, pairs=config["pairs"], datadir=config['datadir'],
                timerange=timerange, erase=config.get("erase"))

            # Convert downloaded trade data to different timeframes
            convert_trades_to_ohlcv(
                pairs=config["pairs"], timeframes=config["timeframes"],
                datadir=config['datadir'], timerange=timerange, erase=config.get("erase"))
        else:
            pairs_not_available = refresh_backtest_ohlcv_data(
                exchange, pairs=config["pairs"], timeframes=config["timeframes"],
                datadir=config['datadir'], timerange=timerange, erase=config.get("erase"))

    except KeyboardInterrupt:
        sys.exit("SIGINT received, aborting ...")

    finally:
        if pairs_not_available:
            logger.info(f"Pairs [{','.join(pairs_not_available)}] not available "
                        f"on exchange {exchange.name}.")
Ejemplo n.º 15
0
def test_ohlcvdata_to_dataframe(default_conf, testdatadir) -> None:
    default_conf.update({'strategy': 'DefaultStrategy'})
    strategy = StrategyResolver.load_strategy(default_conf)

    timerange = TimeRange.parse_timerange('1510694220-1510700340')
    data = load_data(testdatadir, '1m', ['UNITTEST/BTC'], timerange=timerange,
                     fill_up_missing=True)
    processed = strategy.ohlcvdata_to_dataframe(data)
    assert len(processed['UNITTEST/BTC']) == 102  # partial candle was removed
Ejemplo n.º 16
0
def init_plotscript(config, markets: List, startup_candles: int = 0):
    """
    Initialize objects needed for plotting
    :return: Dict with candle (OHLCV) data, trades and pairs
    """

    if "pairs" in config:
        pairs = expand_pairlist(config['pairs'], markets)
    else:
        pairs = expand_pairlist(config['exchange']['pair_whitelist'], markets)

    # Set timerange to use
    timerange = TimeRange.parse_timerange(config.get('timerange'))

    data = load_data(
        datadir=config.get('datadir'),
        pairs=pairs,
        timeframe=config['timeframe'],
        timerange=timerange,
        startup_candles=startup_candles,
        data_format=config.get('dataformat_ohlcv', 'json'),
    )

    if startup_candles and data:
        min_date, max_date = get_timerange(data)
        logger.info(f"Loading data from {min_date} to {max_date}")
        timerange.adjust_start_if_necessary(
            timeframe_to_seconds(config['timeframe']), startup_candles,
            min_date)

    no_trades = False
    filename = config.get('exportfilename')
    if config.get('no_trades', False):
        no_trades = True
    elif config['trade_source'] == 'file':
        if not filename.is_dir() and not filename.is_file():
            logger.warning("Backtest file is missing skipping trades.")
            no_trades = True
    try:
        trades = load_trades(
            config['trade_source'],
            db_url=config.get('db_url'),
            exportfilename=filename,
            no_trades=no_trades,
            strategy=config.get('strategy'),
        )
    except ValueError as e:
        raise OperationalException(e) from e
    if not trades.empty:
        trades = trim_dataframe(trades, timerange, 'open_date')

    return {
        "ohlcv": data,
        "trades": trades,
        "pairs": pairs,
        "timerange": timerange,
    }
Ejemplo n.º 17
0
def test_tickerdata_to_dataframe(default_conf, testdatadir) -> None:
    strategy = DefaultStrategy(default_conf)

    timerange = TimeRange.parse_timerange('1510694220-1510700340')
    tick = load_tickerdata_file(testdatadir, 'UNITTEST/BTC', '1m', timerange=timerange)
    tickerlist = {'UNITTEST/BTC': parse_ticker_dataframe(tick, '1m', pair="UNITTEST/BTC",
                                                         fill_missing=True)}
    data = strategy.tickerdata_to_dataframe(tickerlist)
    assert len(data['UNITTEST/BTC']) == 102       # partial candle was removed
Ejemplo n.º 18
0
def test_advise_all_indicators(default_conf, testdatadir) -> None:
    strategy = StrategyResolver.load_strategy(default_conf)

    timerange = TimeRange.parse_timerange('1510694220-1510700340')
    data = load_data(testdatadir,
                     '1m', ['UNITTEST/BTC'],
                     timerange=timerange,
                     fill_up_missing=True)
    processed = strategy.advise_all_indicators(data)
    assert len(processed['UNITTEST/BTC']) == 102  # partial candle was removed
Ejemplo n.º 19
0
def test_generate_profit_graph(testdatadir):
    filename = testdatadir / "backtest_results/backtest-result_new.json"
    trades = load_backtest_data(filename)
    timerange = TimeRange.parse_timerange("20180110-20180112")
    pairs = ["TRX/BTC", "XLM/BTC"]
    trades = trades[
        trades['close_date'] < pd.Timestamp('2018-01-12', tz='UTC')]

    data = history.load_data(datadir=testdatadir,
                             pairs=pairs,
                             timeframe='5m',
                             timerange=timerange)

    trades = trades[trades['pair'].isin(pairs)]

    fig = generate_profit_graph(pairs,
                                data,
                                trades,
                                timeframe="5m",
                                stake_currency='BTC')
    assert isinstance(fig, go.Figure)

    assert fig.layout.title.text == "Freqtrade Profit plot"
    assert fig.layout.yaxis.title.text == "Price"
    assert fig.layout.yaxis2.title.text == "Profit BTC"
    assert fig.layout.yaxis3.title.text == "Profit BTC"

    figure = fig.layout.figure
    assert len(figure.data) == 7

    avgclose = find_trace_in_fig_data(figure.data, "Avg close price")
    assert isinstance(avgclose, go.Scatter)

    profit = find_trace_in_fig_data(figure.data, "Profit")
    assert isinstance(profit, go.Scatter)
    drawdown = find_trace_in_fig_data(figure.data, "Max drawdown 35.69%")
    assert isinstance(drawdown, go.Scatter)
    parallel = find_trace_in_fig_data(figure.data, "Parallel trades")
    assert isinstance(parallel, go.Scatter)

    underwater = find_trace_in_fig_data(figure.data, "Underwater Plot")
    assert isinstance(underwater, go.Scatter)

    for pair in pairs:
        profit_pair = find_trace_in_fig_data(figure.data, f"Profit {pair}")
        assert isinstance(profit_pair, go.Scatter)

    with pytest.raises(OperationalException, match=r"No trades found.*"):
        # Pair cannot be empty - so it's an empty dataframe.
        generate_profit_graph(pairs,
                              data,
                              trades.loc[trades['pair'].isnull()],
                              timeframe="5m",
                              stake_currency='BTC')
Ejemplo n.º 20
0
def test_ohlcvdata_to_dataframe_copy(mocker, default_conf, testdatadir) -> None:
    default_conf.update({'strategy': 'DefaultStrategy'})
    strategy = StrategyResolver.load_strategy(default_conf)
    aimock = mocker.patch('freqtrade.strategy.interface.IStrategy.advise_indicators')
    timerange = TimeRange.parse_timerange('1510694220-1510700340')
    data = load_data(testdatadir, '1m', ['UNITTEST/BTC'], timerange=timerange,
                     fill_up_missing=True)
    strategy.ohlcvdata_to_dataframe(data)
    assert aimock.call_count == 1
    # Ensure that a copy of the dataframe is passed to advice_indicators
    assert aimock.call_args_list[0][0][0] is not data
Ejemplo n.º 21
0
def test_generate_candlestick_graph_no_trades(default_conf, mocker,
                                              testdatadir):
    row_mock = mocker.patch('freqtrade.plot.plotting.add_indicators',
                            MagicMock(side_effect=fig_generating_mock))
    trades_mock = mocker.patch('freqtrade.plot.plotting.plot_trades',
                               MagicMock(side_effect=fig_generating_mock))
    pair = 'UNITTEST/BTC'
    timerange = TimeRange(None, 'line', 0, -1000)
    data = history.load_pair_history(pair=pair,
                                     timeframe='1m',
                                     datadir=testdatadir,
                                     timerange=timerange)

    default_conf.update({'strategy': 'DefaultStrategy'})
    strategy = StrategyResolver.load_strategy(default_conf)

    # Generate buy/sell signals and indicators
    data = strategy.analyze_ticker(data, {'pair': pair})

    indicators1 = []
    indicators2 = []
    fig = generate_candlestick_graph(pair=pair,
                                     data=data,
                                     trades=None,
                                     indicators1=indicators1,
                                     indicators2=indicators2)
    assert isinstance(fig, go.Figure)
    assert fig.layout.title.text == pair
    figure = fig.layout.figure

    assert len(figure.data) == 6
    # Candlesticks are plotted first
    candles = find_trace_in_fig_data(figure.data, "Price")
    assert isinstance(candles, go.Candlestick)

    volume = find_trace_in_fig_data(figure.data, "Volume")
    assert isinstance(volume, go.Bar)

    buy = find_trace_in_fig_data(figure.data, "buy")
    assert isinstance(buy, go.Scatter)
    # All buy-signals should be plotted
    assert int(data.buy.sum()) == len(buy.x)

    sell = find_trace_in_fig_data(figure.data, "sell")
    assert isinstance(sell, go.Scatter)
    # All buy-signals should be plotted
    assert int(data.sell.sum()) == len(sell.x)

    assert find_trace_in_fig_data(figure.data, "Bollinger Band")

    assert row_mock.call_count == 2
    assert trades_mock.call_count == 1
Ejemplo n.º 22
0
def test_load_data_startup_candles(mocker, caplog, default_conf, testdatadir) -> None:
    ltfmock = mocker.patch('freqtrade.data.history.load_tickerdata_file',
                           MagicMock(return_value=None))
    timerange = TimeRange('date', None, 1510639620, 0)
    history.load_pair_history(pair='UNITTEST/BTC', timeframe='1m',
                              datadir=testdatadir, timerange=timerange,
                              startup_candles=20,
                              )

    assert ltfmock.call_count == 1
    assert ltfmock.call_args_list[0][1]['timerange'] != timerange
    # startts is 20 minutes earlier
    assert ltfmock.call_args_list[0][1]['timerange'].startts == timerange.startts - 20 * 60
Ejemplo n.º 23
0
def test_load_partial_missing(testdatadir, caplog) -> None:
    # Make sure we start fresh - test missing data at start
    start = arrow.get('2018-01-01T00:00:00')
    end = arrow.get('2018-01-11T00:00:00')
    tickerdata = history.load_data(testdatadir,
                                   '5m', ['UNITTEST/BTC'],
                                   startup_candles=20,
                                   timerange=TimeRange('date', 'date',
                                                       start.timestamp,
                                                       end.timestamp))
    assert log_has('Using indicator startup period: 20 ...', caplog)
    # timedifference in 5 minutes
    td = ((end - start).total_seconds() // 60 // 5) + 1
    assert td != len(tickerdata['UNITTEST/BTC'])
    start_real = tickerdata['UNITTEST/BTC'].iloc[0, 0]
    assert log_has(
        f'Missing data at start for pair '
        f'UNITTEST/BTC, data starts at {start_real.strftime("%Y-%m-%d %H:%M:%S")}',
        caplog)
    # Make sure we start fresh - test missing data at end
    caplog.clear()
    start = arrow.get('2018-01-10T00:00:00')
    end = arrow.get('2018-02-20T00:00:00')
    tickerdata = history.load_data(datadir=testdatadir,
                                   timeframe='5m',
                                   pairs=['UNITTEST/BTC'],
                                   timerange=TimeRange('date', 'date',
                                                       start.timestamp,
                                                       end.timestamp))
    # timedifference in 5 minutes
    td = ((end - start).total_seconds() // 60 // 5) + 1
    assert td != len(tickerdata['UNITTEST/BTC'])
    # Shift endtime with +5 - as last candle is dropped (partial candle)
    end_real = arrow.get(tickerdata['UNITTEST/BTC'].iloc[-1,
                                                         0]).shift(minutes=5)
    assert log_has(
        f'Missing data at end for pair '
        f'UNITTEST/BTC, data ends at {end_real.strftime("%Y-%m-%d %H:%M:%S")}',
        caplog)
Ejemplo n.º 24
0
def start_download_data(args: Namespace) -> None:
    """
    Download data (former download_backtest_data.py script)
    """
    config = setup_utils_configuration(args, RunMode.OTHER)

    timerange = TimeRange()
    if 'days' in config:
        time_since = arrow.utcnow().shift(
            days=-config['days']).strftime("%Y%m%d")
        timerange = TimeRange.parse_timerange(f'{time_since}-')

    dl_path = Path(config['datadir'])
    logger.info(f'About to download pairs: {config["pairs"]}, '
                f'intervals: {config["timeframes"]} to {dl_path}')

    pairs_not_available: List[str] = []

    try:
        # Init exchange
        exchange = ExchangeResolver(config['exchange']['name'],
                                    config).exchange

        pairs_not_available = refresh_backtest_ohlcv_data(
            exchange,
            pairs=config["pairs"],
            timeframes=config["timeframes"],
            dl_path=Path(config['datadir']),
            timerange=timerange,
            erase=config.get("erase"))

    except KeyboardInterrupt:
        sys.exit("SIGINT received, aborting ...")

    finally:
        if pairs_not_available:
            logger.info(
                f"Pairs [{','.join(pairs_not_available)}] not available "
                f"on exchange {config['exchange']['name']}.")
Ejemplo n.º 25
0
def test_trim_dataframe(testdatadir) -> None:
    data = history.load_data(
        datadir=testdatadir,
        timeframe='1m',
        pairs=['UNITTEST/BTC']
    )['UNITTEST/BTC']
    min_date = int(data.iloc[0]['date'].timestamp())
    max_date = int(data.iloc[-1]['date'].timestamp())
    data_modify = data.copy()

    # Remove first 30 minutes (1800 s)
    tr = TimeRange('date', None, min_date + 1800, 0)
    data_modify = history.trim_dataframe(data_modify, tr)
    assert not data_modify.equals(data)
    assert len(data_modify) < len(data)
    assert len(data_modify) == len(data) - 30
    assert all(data_modify.iloc[-1] == data.iloc[-1])
    assert all(data_modify.iloc[0] == data.iloc[30])

    data_modify = data.copy()
    # Remove last 30 minutes (1800 s)
    tr = TimeRange(None, 'date', 0, max_date - 1800)
    data_modify = history.trim_dataframe(data_modify, tr)
    assert not data_modify.equals(data)
    assert len(data_modify) < len(data)
    assert len(data_modify) == len(data) - 30
    assert all(data_modify.iloc[0] == data.iloc[0])
    assert all(data_modify.iloc[-1] == data.iloc[-31])

    data_modify = data.copy()
    # Remove first 25 and last 30 minutes (1800 s)
    tr = TimeRange('date', 'date', min_date + 1500, max_date - 1800)
    data_modify = history.trim_dataframe(data_modify, tr)
    assert not data_modify.equals(data)
    assert len(data_modify) < len(data)
    assert len(data_modify) == len(data) - 55
    # first row matches 25th original row
    assert all(data_modify.iloc[0] == data.iloc[25])
Ejemplo n.º 26
0
def load_data_test(what):
    timerange = TimeRange(None, 'line', 0, -101)
    pair = history.load_tickerdata_file(None,
                                        ticker_interval='1m',
                                        pair='UNITTEST/BTC',
                                        timerange=timerange)
    datalen = len(pair)

    base = 0.001
    if what == 'raise':
        data = [
            [
                pair[x][0],  # Keep old dates
                x * base,  # But replace O,H,L,C
                x * base + 0.0001,
                x * base - 0.0001,
                x * base,
                pair[x][5],  # Keep old volume
            ] for x in range(0, datalen)
        ]
    if what == 'lower':
        data = [
            [
                pair[x][0],  # Keep old dates
                1 - x * base,  # But replace O,H,L,C
                1 - x * base + 0.0001,
                1 - x * base - 0.0001,
                1 - x * base,
                pair[x][5]  # Keep old volume
            ] for x in range(0, datalen)
        ]
    if what == 'sine':
        hz = 0.1  # frequency
        data = [
            [
                pair[x][0],  # Keep old dates
                math.sin(x * hz) / 1000 + base,  # But replace O,H,L,C
                math.sin(x * hz) / 1000 + base + 0.0001,
                math.sin(x * hz) / 1000 + base - 0.0001,
                math.sin(x * hz) / 1000 + base,
                pair[x][5]  # Keep old volume
            ] for x in range(0, datalen)
        ]
    return {
        'UNITTEST/BTC':
        parse_ticker_dataframe(data,
                               '1m',
                               pair="UNITTEST/BTC",
                               fill_missing=True)
    }
Ejemplo n.º 27
0
def test_create_cum_profit():
    filename = make_testdata_path(None) / "backtest-result_test.json"
    bt_data = load_backtest_data(filename)
    timerange = TimeRange.parse_timerange("20180110-20180112")

    df = load_pair_history(pair="POWR/BTC", ticker_interval='5m',
                           datadir=None, timerange=timerange)

    cum_profits = create_cum_profit(df.set_index('date'),
                                    bt_data[bt_data["pair"] == 'POWR/BTC'],
                                    "cum_profits")
    assert "cum_profits" in cum_profits.columns
    assert cum_profits.iloc[0]['cum_profits'] == 0
    assert cum_profits.iloc[-1]['cum_profits'] == 0.0798005
Ejemplo n.º 28
0
    def __init__(self, config: Dict[str, Any], exchange, strategy) -> None:

        self.config = config
        self.exchange = exchange
        self.strategy: IStrategy = strategy

        self.edge_config = self.config.get('edge', {})
        self._cached_pairs: Dict[str, Any] = {}  # Keeps a list of pairs
        self._final_pairs: list = []

        # checking max_open_trades. it should be -1 as with Edge
        # the number of trades is determined by position size
        if self.config['max_open_trades'] != float('inf'):
            logger.critical('max_open_trades should be -1 in config !')

        if self.config['stake_amount'] != UNLIMITED_STAKE_AMOUNT:
            raise OperationalException(
                'Edge works only with unlimited stake amount')

        self._capital_ratio: float = self.config['tradable_balance_ratio']
        self._allowed_risk: float = self.edge_config.get('allowed_risk')
        self._since_number_of_days: int = self.edge_config.get(
            'calculate_since_number_of_days', 14)
        self._last_updated: int = 0  # Timestamp of pairs last updated time
        self._refresh_pairs = True

        self._stoploss_range_min = float(
            self.edge_config.get('stoploss_range_min', -0.01))
        self._stoploss_range_max = float(
            self.edge_config.get('stoploss_range_max', -0.05))
        self._stoploss_range_step = float(
            self.edge_config.get('stoploss_range_step', -0.001))

        # calculating stoploss range
        self._stoploss_range = np.arange(self._stoploss_range_min,
                                         self._stoploss_range_max,
                                         self._stoploss_range_step)

        self._timerange: TimeRange = TimeRange.parse_timerange(
            "%s-" % arrow.now().shift(
                days=-1 * self._since_number_of_days).format('YYYYMMDD'))
        if config.get('fee'):
            self.fee = config['fee']
        else:
            try:
                self.fee = self.exchange.get_fee(symbol=expand_pairlist(
                    self.config['exchange']['pair_whitelist'],
                    list(self.exchange.markets))[0])
            except IndexError:
                self.fee = None
Ejemplo n.º 29
0
def test_data_to_dataframe_bt(default_conf, mocker, testdatadir) -> None:
    patch_exchange(mocker)
    timerange = TimeRange.parse_timerange('1510694220-1510700340')
    data = history.load_data(testdatadir, '1m', ['UNITTEST/BTC'], timerange=timerange,
                             fill_up_missing=True)
    backtesting = Backtesting(default_conf)
    processed = backtesting.strategy.ohlcvdata_to_dataframe(data)
    assert len(processed['UNITTEST/BTC']) == 102

    # Load strategy to compare the result between Backtesting function and strategy are the same
    default_conf.update({'strategy': 'DefaultStrategy'})
    strategy = StrategyResolver.load_strategy(default_conf)

    processed2 = strategy.ohlcvdata_to_dataframe(data)
    assert processed['UNITTEST/BTC'].equals(processed2['UNITTEST/BTC'])
Ejemplo n.º 30
0
def test_create_cum_profit(testdatadir):
    filename = testdatadir / "backtest-result_test.json"
    bt_data = load_backtest_data(filename)
    timerange = TimeRange.parse_timerange("20180110-20180112")

    df = load_pair_history(pair="TRX/BTC",
                           timeframe='5m',
                           datadir=testdatadir,
                           timerange=timerange)

    cum_profits = create_cum_profit(df.set_index('date'),
                                    bt_data[bt_data["pair"] == 'TRX/BTC'],
                                    "cum_profits",
                                    timeframe="5m")
    assert "cum_profits" in cum_profits.columns
    assert cum_profits.iloc[0]['cum_profits'] == 0
    assert cum_profits.iloc[-1]['cum_profits'] == 0.0798005