@@ -3,14 +3,14 @@ import json
|
||||
import pytest
|
||||
from pandas import DataFrame
|
||||
|
||||
from freqtrade.analyze import Analyze
|
||||
from freqtrade.exchange.exchange_helpers import parse_ticker_dataframe
|
||||
from freqtrade.strategy.default_strategy import DefaultStrategy
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def result():
|
||||
with open('freqtrade/tests/testdata/ETH_BTC-1m.json') as data_file:
|
||||
return Analyze.parse_ticker_dataframe(json.load(data_file))
|
||||
return parse_ticker_dataframe(json.load(data_file))
|
||||
|
||||
|
||||
def test_default_strategy_structure():
|
||||
@@ -23,7 +23,7 @@ def test_default_strategy_structure():
|
||||
|
||||
|
||||
def test_default_strategy(result):
|
||||
strategy = DefaultStrategy()
|
||||
strategy = DefaultStrategy({})
|
||||
|
||||
assert type(strategy.minimal_roi) is dict
|
||||
assert type(strategy.stoploss) is float
|
||||
|
126
freqtrade/tests/strategy/test_interface.py
Normal file
126
freqtrade/tests/strategy/test_interface.py
Normal file
@@ -0,0 +1,126 @@
|
||||
# pragma pylint: disable=missing-docstring, C0103
|
||||
|
||||
"""
|
||||
Unit test file for analyse.py
|
||||
"""
|
||||
|
||||
import logging
|
||||
from unittest.mock import MagicMock
|
||||
|
||||
import arrow
|
||||
from pandas import DataFrame
|
||||
|
||||
from freqtrade.arguments import TimeRange
|
||||
from freqtrade.optimize.__init__ import load_tickerdata_file
|
||||
from freqtrade.tests.conftest import get_patched_exchange, log_has
|
||||
from freqtrade.strategy.default_strategy import DefaultStrategy
|
||||
|
||||
# Avoid to reinit the same object again and again
|
||||
_STRATEGY = DefaultStrategy(config={})
|
||||
|
||||
|
||||
def test_returns_latest_buy_signal(mocker, default_conf):
|
||||
mocker.patch('freqtrade.exchange.Exchange.get_ticker_history', return_value=MagicMock())
|
||||
exchange = get_patched_exchange(mocker, default_conf)
|
||||
mocker.patch.object(
|
||||
_STRATEGY, 'analyze_ticker',
|
||||
return_value=DataFrame([{'buy': 1, 'sell': 0, 'date': arrow.utcnow()}])
|
||||
)
|
||||
assert _STRATEGY.get_signal(exchange, 'ETH/BTC', '5m') == (True, False)
|
||||
|
||||
mocker.patch.object(
|
||||
_STRATEGY, 'analyze_ticker',
|
||||
return_value=DataFrame([{'buy': 0, 'sell': 1, 'date': arrow.utcnow()}])
|
||||
)
|
||||
assert _STRATEGY.get_signal(exchange, 'ETH/BTC', '5m') == (False, True)
|
||||
|
||||
|
||||
def test_returns_latest_sell_signal(mocker, default_conf):
|
||||
mocker.patch('freqtrade.exchange.Exchange.get_ticker_history', return_value=MagicMock())
|
||||
exchange = get_patched_exchange(mocker, default_conf)
|
||||
mocker.patch.object(
|
||||
_STRATEGY, 'analyze_ticker',
|
||||
return_value=DataFrame([{'sell': 1, 'buy': 0, 'date': arrow.utcnow()}])
|
||||
)
|
||||
|
||||
assert _STRATEGY.get_signal(exchange, 'ETH/BTC', '5m') == (False, True)
|
||||
|
||||
mocker.patch.object(
|
||||
_STRATEGY, 'analyze_ticker',
|
||||
return_value=DataFrame([{'sell': 0, 'buy': 1, 'date': arrow.utcnow()}])
|
||||
)
|
||||
assert _STRATEGY.get_signal(exchange, 'ETH/BTC', '5m') == (True, False)
|
||||
|
||||
|
||||
def test_get_signal_empty(default_conf, mocker, caplog):
|
||||
caplog.set_level(logging.INFO)
|
||||
mocker.patch('freqtrade.exchange.Exchange.get_ticker_history', return_value=None)
|
||||
exchange = get_patched_exchange(mocker, default_conf)
|
||||
assert (False, False) == _STRATEGY.get_signal(exchange, 'foo', default_conf['ticker_interval'])
|
||||
assert log_has('Empty ticker history for pair foo', caplog.record_tuples)
|
||||
|
||||
|
||||
def test_get_signal_exception_valueerror(default_conf, mocker, caplog):
|
||||
caplog.set_level(logging.INFO)
|
||||
mocker.patch('freqtrade.exchange.Exchange.get_ticker_history', return_value=1)
|
||||
exchange = get_patched_exchange(mocker, default_conf)
|
||||
mocker.patch.object(
|
||||
_STRATEGY, 'analyze_ticker',
|
||||
side_effect=ValueError('xyz')
|
||||
)
|
||||
assert (False, False) == _STRATEGY.get_signal(exchange, 'foo', default_conf['ticker_interval'])
|
||||
assert log_has('Unable to analyze ticker for pair foo: xyz', caplog.record_tuples)
|
||||
|
||||
|
||||
def test_get_signal_empty_dataframe(default_conf, mocker, caplog):
|
||||
caplog.set_level(logging.INFO)
|
||||
mocker.patch('freqtrade.exchange.Exchange.get_ticker_history', return_value=1)
|
||||
exchange = get_patched_exchange(mocker, default_conf)
|
||||
mocker.patch.object(
|
||||
_STRATEGY, 'analyze_ticker',
|
||||
return_value=DataFrame([])
|
||||
)
|
||||
assert (False, False) == _STRATEGY.get_signal(exchange, 'xyz', default_conf['ticker_interval'])
|
||||
assert log_has('Empty dataframe for pair xyz', caplog.record_tuples)
|
||||
|
||||
|
||||
def test_get_signal_old_dataframe(default_conf, mocker, caplog):
|
||||
caplog.set_level(logging.INFO)
|
||||
mocker.patch('freqtrade.exchange.Exchange.get_ticker_history', return_value=1)
|
||||
exchange = get_patched_exchange(mocker, default_conf)
|
||||
# default_conf defines a 5m interval. we check interval * 2 + 5m
|
||||
# this is necessary as the last candle is removed (partial candles) by default
|
||||
oldtime = arrow.utcnow().shift(minutes=-16)
|
||||
ticks = DataFrame([{'buy': 1, 'date': oldtime}])
|
||||
mocker.patch.object(
|
||||
_STRATEGY, 'analyze_ticker',
|
||||
return_value=DataFrame(ticks)
|
||||
)
|
||||
assert (False, False) == _STRATEGY.get_signal(exchange, 'xyz', default_conf['ticker_interval'])
|
||||
assert log_has(
|
||||
'Outdated history for pair xyz. Last tick is 16 minutes old',
|
||||
caplog.record_tuples
|
||||
)
|
||||
|
||||
|
||||
def test_get_signal_handles_exceptions(mocker, default_conf):
|
||||
mocker.patch('freqtrade.exchange.Exchange.get_ticker_history', return_value=MagicMock())
|
||||
exchange = get_patched_exchange(mocker, default_conf)
|
||||
mocker.patch.object(
|
||||
_STRATEGY, 'analyze_ticker',
|
||||
side_effect=Exception('invalid ticker history ')
|
||||
)
|
||||
assert _STRATEGY.get_signal(exchange, 'ETH/BTC', '5m') == (False, False)
|
||||
|
||||
|
||||
def test_tickerdata_to_dataframe(default_conf) -> None:
|
||||
"""
|
||||
Test Analyze.tickerdata_to_dataframe() method
|
||||
"""
|
||||
strategy = DefaultStrategy(default_conf)
|
||||
|
||||
timerange = TimeRange(None, 'line', 0, -100)
|
||||
tick = load_tickerdata_file(None, 'UNITTEST/BTC', '1m', timerange=timerange)
|
||||
tickerlist = {'UNITTEST/BTC': tick}
|
||||
data = strategy.tickerdata_to_dataframe(tickerlist)
|
||||
assert len(data['UNITTEST/BTC']) == 99 # partial candle was removed
|
@@ -12,14 +12,15 @@ from freqtrade.strategy.resolver import StrategyResolver
|
||||
|
||||
def test_import_strategy(caplog):
|
||||
caplog.set_level(logging.DEBUG)
|
||||
default_config = {}
|
||||
|
||||
strategy = DefaultStrategy()
|
||||
strategy = DefaultStrategy(default_config)
|
||||
strategy.some_method = lambda *args, **kwargs: 42
|
||||
|
||||
assert strategy.__module__ == 'freqtrade.strategy.default_strategy'
|
||||
assert strategy.some_method() == 42
|
||||
|
||||
imported_strategy = import_strategy(strategy)
|
||||
imported_strategy = import_strategy(strategy, default_config)
|
||||
|
||||
assert dir(strategy) == dir(imported_strategy)
|
||||
|
||||
@@ -35,13 +36,23 @@ def test_import_strategy(caplog):
|
||||
|
||||
|
||||
def test_search_strategy():
|
||||
default_config = {}
|
||||
default_location = os.path.join(os.path.dirname(
|
||||
os.path.realpath(__file__)), '..', '..', 'strategy'
|
||||
)
|
||||
assert isinstance(
|
||||
StrategyResolver._search_strategy(default_location, 'DefaultStrategy'), IStrategy
|
||||
StrategyResolver._search_strategy(
|
||||
default_location,
|
||||
config=default_config,
|
||||
strategy_name='DefaultStrategy'
|
||||
),
|
||||
IStrategy
|
||||
)
|
||||
assert StrategyResolver._search_strategy(default_location, 'NotFoundStrategy') is None
|
||||
assert StrategyResolver._search_strategy(
|
||||
default_location,
|
||||
config=default_config,
|
||||
strategy_name='NotFoundStrategy'
|
||||
) is None
|
||||
|
||||
|
||||
def test_load_strategy(result):
|
||||
@@ -53,7 +64,7 @@ def test_load_strategy(result):
|
||||
def test_load_strategy_invalid_directory(result, caplog):
|
||||
resolver = StrategyResolver()
|
||||
extra_dir = os.path.join('some', 'path')
|
||||
resolver._load_strategy('TestStrategy', extra_dir)
|
||||
resolver._load_strategy('TestStrategy', config={}, extra_dir=extra_dir)
|
||||
|
||||
assert (
|
||||
'freqtrade.strategy.resolver',
|
||||
@@ -70,7 +81,7 @@ def test_load_not_found_strategy():
|
||||
with pytest.raises(ImportError,
|
||||
match=r'Impossible to load Strategy \'NotFoundStrategy\'.'
|
||||
r' This class does not exist or contains Python code errors'):
|
||||
strategy._load_strategy('NotFoundStrategy')
|
||||
strategy._load_strategy(strategy_name='NotFoundStrategy', config={})
|
||||
|
||||
|
||||
def test_strategy(result):
|
||||
|
Reference in New Issue
Block a user