Merge pull request #591 from gcarq/feature/remove-duplicate-ticks

Aggregate ticks in parse_ticker_dataframe
This commit is contained in:
Janne Sinivirta 2018-03-30 10:55:51 +03:00 committed by GitHub
commit 2efc0113fe
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 40 additions and 36 deletions

View File

@ -46,12 +46,20 @@ class Analyze(object):
:return: DataFrame :return: DataFrame
""" """
columns = {'C': 'close', 'V': 'volume', 'O': 'open', 'H': 'high', 'L': 'low', 'T': 'date'} columns = {'C': 'close', 'V': 'volume', 'O': 'open', 'H': 'high', 'L': 'low', 'T': 'date'}
frame = DataFrame(ticker) \ frame = DataFrame(ticker).rename(columns=columns)
.rename(columns=columns)
if 'BV' in frame: if 'BV' in frame:
frame.drop('BV', 1, inplace=True) frame.drop('BV', axis=1, inplace=True)
frame['date'] = to_datetime(frame['date'], utc=True, infer_datetime_format=True) frame['date'] = to_datetime(frame['date'], utc=True, infer_datetime_format=True)
frame.sort_values('date', inplace=True)
# group by index and aggregate results to eliminate duplicate ticks
frame = frame.groupby(by='date', as_index=False, sort=True).agg({
'close': 'last',
'high': 'max',
'low': 'min',
'open': 'first',
'volume': 'max',
})
return frame return frame
def populate_indicators(self, dataframe: DataFrame) -> DataFrame: def populate_indicators(self, dataframe: DataFrame) -> DataFrame:

View File

@ -111,45 +111,38 @@ def download_pairs(datadir, pairs: List[str], ticker_interval: int) -> bool:
# FIX: 20180110, suggest rename interval to tick_interval # FIX: 20180110, suggest rename interval to tick_interval
def download_backtesting_testdata(datadir: str, pair: str, interval: int = 5) -> bool: def download_backtesting_testdata(datadir: str, pair: str, interval: int = 5) -> None:
""" """
Download the latest 1 and 5 ticker intervals from Bittrex for the pairs passed in parameters Download the latest 1 and 5 ticker intervals from Bittrex for the pairs passed in parameters
Based on @Rybolov work: https://github.com/rybolov/freqtrade-data Based on @Rybolov work: https://github.com/rybolov/freqtrade-data
:param pairs: list of pairs to download
:return: bool
""" """
path = make_testdata_path(datadir) path = make_testdata_path(datadir)
logger.info( logger.info(
'Download the pair: "%s", Interval: %s min', 'Download the pair: "%s", Interval: %s min', pair, interval
pair,
interval
) )
filepair = pair.replace("-", "_")
filename = os.path.join(path, '{pair}-{interval}.json'.format( filename = os.path.join(path, '{pair}-{interval}.json'.format(
pair=filepair, pair=pair.replace("-", "_"),
interval=interval, interval=interval,
)) ))
if os.path.isfile(filename): if os.path.isfile(filename):
with open(filename, "rt") as file: with open(filename, "rt") as file:
data = json.load(file) data = json.load(file)
logger.debug("Current Start: %s", data[1]['T'])
logger.debug("Current End: %s", data[-1:][0]['T'])
else: else:
data = [] data = []
logger.debug("Current Start: None")
logger.debug("Current End: None")
new_data = get_ticker_history(pair=pair, tick_interval=int(interval)) logger.debug('Current Start: %s', data[1]['T'] if data else None)
for row in new_data: logger.debug('Current End: %s', data[-1:][0]['T'] if data else None)
if row not in data:
data.append(row)
logger.debug("New Start: %s", data[1]['T'])
logger.debug("New End: %s", data[-1:][0]['T'])
data = sorted(data, key=lambda data: data['T'])
# Extend data with new ticker history
data.extend([
row for row in get_ticker_history(pair=pair, tick_interval=int(interval))
if row not in data
])
data = sorted(data, key=lambda _data: _data['T'])
logger.debug('New Start: %s', data[1]['T'])
logger.debug('New End: %s', data[-1:][0]['T'])
misc.file_dump_json(filename, data) misc.file_dump_json(filename, data)
return True

View File

@ -4,11 +4,12 @@
This module contains the backtesting logic This module contains the backtesting logic
""" """
import logging import logging
import operator
from argparse import Namespace from argparse import Namespace
from typing import Dict, Tuple, Any, List, Optional from typing import Dict, Tuple, Any, List, Optional
import arrow import arrow
from pandas import DataFrame, Series from pandas import DataFrame
from tabulate import tabulate from tabulate import tabulate
import freqtrade.optimize as optimize import freqtrade.optimize as optimize
@ -60,11 +61,12 @@ class Backtesting(object):
:param data: dictionary with preprocessed backtesting data :param data: dictionary with preprocessed backtesting data
:return: tuple containing min_date, max_date :return: tuple containing min_date, max_date
""" """
all_dates = Series([]) timeframe = [
for pair_data in data.values(): (arrow.get(min(frame.date)), arrow.get(max(frame.date)))
all_dates = all_dates.append(pair_data['date']) for frame in data.values()
all_dates.sort_values(inplace=True) ]
return arrow.get(all_dates.iloc[0]), arrow.get(all_dates.iloc[-1]) return min(timeframe, key=operator.itemgetter(0))[0], \
max(timeframe, key=operator.itemgetter(1))[1]
def _generate_text_table(self, data: Dict[str, Dict], results: DataFrame) -> str: def _generate_text_table(self, data: Dict[str, Dict], results: DataFrame) -> str:
""" """

View File

@ -182,10 +182,11 @@ def test_download_backtesting_testdata(ticker_history, mocker) -> None:
def test_download_backtesting_testdata2(mocker) -> None: def test_download_backtesting_testdata2(mocker) -> None:
tick = [{'T': 'bar'}, {'T': 'foo'}] tick = [{'T': 'bar'}, {'T': 'foo'}]
mocker.patch('freqtrade.misc.file_dump_json', return_value=None) json_dump_mock = mocker.patch('freqtrade.misc.file_dump_json', return_value=None)
mocker.patch('freqtrade.optimize.__init__.get_ticker_history', return_value=tick) mocker.patch('freqtrade.optimize.__init__.get_ticker_history', return_value=tick)
assert download_backtesting_testdata(None, pair="BTC-UNITEST", interval=1) download_backtesting_testdata(None, pair="BTC-UNITEST", interval=1)
assert download_backtesting_testdata(None, pair="BTC-UNITEST", interval=3) download_backtesting_testdata(None, pair="BTC-UNITEST", interval=3)
assert json_dump_mock.call_count == 2
def test_load_tickerdata_file() -> None: def test_load_tickerdata_file() -> None:

View File

@ -50,7 +50,7 @@ def test_dataframe_correct_length(result):
def test_dataframe_correct_columns(result): def test_dataframe_correct_columns(result):
assert result.columns.tolist() == \ assert result.columns.tolist() == \
['close', 'high', 'low', 'open', 'date', 'volume'] ['date', 'close', 'high', 'low', 'open', 'volume']
def test_populates_buy_trend(result): def test_populates_buy_trend(result):
@ -170,7 +170,7 @@ def test_get_signal_handles_exceptions(mocker):
def test_parse_ticker_dataframe(ticker_history, ticker_history_without_bv): def test_parse_ticker_dataframe(ticker_history, ticker_history_without_bv):
columns = ['close', 'high', 'low', 'open', 'date', 'volume'] columns = ['date', 'close', 'high', 'low', 'open', 'volume']
# Test file with BV data # Test file with BV data
dataframe = Analyze.parse_ticker_dataframe(ticker_history) dataframe = Analyze.parse_ticker_dataframe(ticker_history)