Merge pull request #291 from gcarq/backtesting_speed_opt

Backtesting speed optimizations
This commit is contained in:
Gérald LONLAS 2018-01-02 23:35:47 -08:00 committed by GitHub
commit 9b09b5aa29
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 20 additions and 19 deletions

View File

@ -5,7 +5,7 @@ import logging
from typing import Tuple, Dict from typing import Tuple, Dict
import arrow import arrow
from pandas import DataFrame from pandas import DataFrame, Series
from tabulate import tabulate from tabulate import tabulate
from freqtrade import exchange from freqtrade import exchange
@ -19,20 +19,17 @@ from freqtrade.persistence import Trade
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
def get_timeframe(data: Dict[str, Dict]) -> Tuple[arrow.Arrow, arrow.Arrow]: def get_timeframe(data: Dict[str, DataFrame]) -> Tuple[arrow.Arrow, arrow.Arrow]:
""" """
Get the maximum timeframe for the given backtest data Get the maximum timeframe for the given backtest data
:param data: dictionary with backtesting data :param data: dictionary with preprocessed backtesting data
:return: tuple containing min_date, max_date :return: tuple containing min_date, max_date
""" """
min_date, max_date = None, None all_dates = Series([])
for values in data.values(): for pair, pair_data in data.items():
sorted_values = sorted(values, key=lambda d: arrow.get(d['T'])) all_dates = all_dates.append(pair_data['date'])
if not min_date or sorted_values[0]['T'] < min_date: all_dates.sort_values(inplace=True)
min_date = sorted_values[0]['T'] return arrow.get(all_dates.iloc[0]), arrow.get(all_dates.iloc[-1])
if not max_date or sorted_values[-1]['T'] > max_date:
max_date = sorted_values[-1]['T']
return arrow.get(min_date), arrow.get(max_date)
def generate_text_table( def generate_text_table(
@ -84,7 +81,8 @@ def backtest(stake_amount: float, processed: Dict[str, DataFrame],
ticker = populate_sell_trend(populate_buy_trend(pair_data)) ticker = populate_sell_trend(populate_buy_trend(pair_data))
# for each buy point # for each buy point
lock_pair_until = None lock_pair_until = None
for row in ticker[ticker.buy == 1].itertuples(index=True): buy_subset = ticker[ticker.buy == 1][['buy', 'open', 'close', 'date', 'sell']]
for row in buy_subset.itertuples(index=True):
if realistic: if realistic:
if lock_pair_until is not None and row.Index <= lock_pair_until: if lock_pair_until is not None and row.Index <= lock_pair_until:
continue continue
@ -106,7 +104,8 @@ def backtest(stake_amount: float, processed: Dict[str, DataFrame],
) )
# calculate win/lose forwards from buy point # calculate win/lose forwards from buy point
for row2 in ticker[row.Index + 1:].itertuples(index=True): sell_subset = ticker[row.Index + 1:][['close', 'date', 'sell']]
for row2 in sell_subset.itertuples(index=True):
if max_open_trades > 0: if max_open_trades > 0:
# Increase trade_count_lock for every iteration # Increase trade_count_lock for every iteration
trade_count_lock[row2.date] = trade_count_lock.get(row2.date, 0) + 1 trade_count_lock[row2.date] = trade_count_lock.get(row2.date, 0) + 1
@ -157,10 +156,6 @@ def start(args):
logger.info('Using stake_currency: %s ...', config['stake_currency']) logger.info('Using stake_currency: %s ...', config['stake_currency'])
logger.info('Using stake_amount: %s ...', config['stake_amount']) logger.info('Using stake_amount: %s ...', config['stake_amount'])
# Print timeframe
min_date, max_date = get_timeframe(data)
logger.info('Measuring data from %s up to %s ...', min_date.isoformat(), max_date.isoformat())
max_open_trades = 0 max_open_trades = 0
if args.realistic_simulation: if args.realistic_simulation:
logger.info('Using max_open_trades: %s ...', config['max_open_trades']) logger.info('Using max_open_trades: %s ...', config['max_open_trades'])
@ -170,9 +165,14 @@ def start(args):
from freqtrade import main from freqtrade import main
main._CONF = config 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 # Execute backtest and print results
results = backtest( results = backtest(
config['stake_amount'], preprocess(data), max_open_trades, args.realistic_simulation config['stake_amount'], preprocessed, max_open_trades, args.realistic_simulation
) )
logger.info( logger.info(
'\n====================== BACKTESTING REPORT ================================\n%s', '\n====================== BACKTESTING REPORT ================================\n%s',

View File

@ -5,6 +5,7 @@ import pandas as pd
# from unittest.mock import MagicMock # from unittest.mock import MagicMock
from freqtrade import exchange, optimize from freqtrade import exchange, optimize
from freqtrade.exchange import Bittrex from freqtrade.exchange import Bittrex
from freqtrade.optimize import preprocess
from freqtrade.optimize.backtesting import backtest, generate_text_table, get_timeframe from freqtrade.optimize.backtesting import backtest, generate_text_table, get_timeframe
# import freqtrade.optimize.backtesting as backtesting # import freqtrade.optimize.backtesting as backtesting
@ -27,7 +28,7 @@ def test_generate_text_table():
def test_get_timeframe(): def test_get_timeframe():
data = optimize.load_data(ticker_interval=1, pairs=['BTC_UNITEST']) data = preprocess(optimize.load_data(ticker_interval=1, pairs=['BTC_UNITEST']))
min_date, max_date = get_timeframe(data) min_date, max_date = get_timeframe(data)
assert min_date.isoformat() == '2017-11-04T23:02:00+00:00' assert min_date.isoformat() == '2017-11-04T23:02:00+00:00'
assert max_date.isoformat() == '2017-11-14T22:59:00+00:00' assert max_date.isoformat() == '2017-11-14T22:59:00+00:00'