Merge branch 'develop' into safe_sell_amount

This commit is contained in:
Matthias
2019-12-18 19:45:31 +01:00
45 changed files with 812 additions and 363 deletions

File diff suppressed because one or more lines are too long

View File

@@ -2,7 +2,7 @@
import logging
from freqtrade.data.converter import parse_ticker_dataframe, ohlcv_fill_up_missing_data
from freqtrade.data.history import load_pair_history, validate_backtest_data, get_timeframe
from freqtrade.data.history import load_pair_history, validate_backtest_data, get_timerange
from tests.conftest import log_has
@@ -36,7 +36,7 @@ def test_ohlcv_fill_up_missing_data(testdatadir, caplog):
f"{len(data)} - after: {len(data2)}", caplog)
# Test fillup actually fixes invalid backtest data
min_date, max_date = get_timeframe({'UNITTEST/BTC': data})
min_date, max_date = get_timerange({'UNITTEST/BTC': data})
assert validate_backtest_data(data, 'UNITTEST/BTC', min_date, max_date, 1)
assert not validate_backtest_data(data2, 'UNITTEST/BTC', min_date, max_date, 1)

View File

@@ -7,21 +7,21 @@ from shutil import copyfile
from unittest.mock import MagicMock, PropertyMock
import arrow
import pytest
from pandas import DataFrame
from freqtrade import OperationalException
from freqtrade.configuration import TimeRange
from freqtrade.data import history
from freqtrade.data.history import (_load_cached_data_for_updating,
convert_trades_to_ohlcv,
download_pair_history,
download_trades_history,
from freqtrade.data.history import (_download_pair_history,
_download_trades_history,
_load_cached_data_for_updating,
convert_trades_to_ohlcv, get_timerange,
load_data, load_pair_history,
load_tickerdata_file, pair_data_filename,
pair_trades_filename,
refresh_backtest_ohlcv_data,
refresh_backtest_trades_data,
trim_tickerlist)
refresh_data,
trim_dataframe, trim_tickerlist,
validate_backtest_data)
from freqtrade.exchange import timeframe_to_minutes
from freqtrade.misc import file_dump_json
from freqtrade.strategy.default_strategy import DefaultStrategy
@@ -64,7 +64,7 @@ def _clean_test_file(file: Path) -> None:
def test_load_data_30min_ticker(mocker, caplog, default_conf, testdatadir) -> None:
ld = history.load_pair_history(pair='UNITTEST/BTC', timeframe='30m', datadir=testdatadir)
ld = load_pair_history(pair='UNITTEST/BTC', timeframe='30m', datadir=testdatadir)
assert isinstance(ld, DataFrame)
assert not log_has(
'Download history data for pair: "UNITTEST/BTC", timeframe: 30m '
@@ -73,7 +73,7 @@ def test_load_data_30min_ticker(mocker, caplog, default_conf, testdatadir) -> No
def test_load_data_7min_ticker(mocker, caplog, default_conf, testdatadir) -> None:
ld = history.load_pair_history(pair='UNITTEST/BTC', timeframe='7m', datadir=testdatadir)
ld = load_pair_history(pair='UNITTEST/BTC', timeframe='7m', datadir=testdatadir)
assert isinstance(ld, DataFrame)
assert ld.empty
assert log_has(
@@ -86,7 +86,7 @@ def test_load_data_1min_ticker(ticker_history, mocker, caplog, testdatadir) -> N
mocker.patch('freqtrade.exchange.Exchange.get_historic_ohlcv', return_value=ticker_history)
file = testdatadir / 'UNITTEST_BTC-1m.json'
_backup_file(file, copy_file=True)
history.load_data(datadir=testdatadir, timeframe='1m', pairs=['UNITTEST/BTC'])
load_data(datadir=testdatadir, timeframe='1m', pairs=['UNITTEST/BTC'])
assert file.is_file()
assert not log_has(
'Download history data for pair: "UNITTEST/BTC", interval: 1m '
@@ -99,10 +99,9 @@ def test_load_data_startup_candles(mocker, caplog, default_conf, testdatadir) ->
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,
)
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
@@ -121,9 +120,7 @@ def test_load_data_with_new_pair_1min(ticker_history_list, mocker, caplog,
_backup_file(file)
# do not download a new pair if refresh_pairs isn't set
history.load_pair_history(datadir=testdatadir,
timeframe='1m',
pair='MEME/BTC')
load_pair_history(datadir=testdatadir, timeframe='1m', pair='MEME/BTC')
assert not file.is_file()
assert log_has(
'No history data for pair: "MEME/BTC", timeframe: 1m. '
@@ -131,22 +128,14 @@ def test_load_data_with_new_pair_1min(ticker_history_list, mocker, caplog,
)
# download a new pair if refresh_pairs is set
history.load_pair_history(datadir=testdatadir,
timeframe='1m',
refresh_pairs=True,
exchange=exchange,
pair='MEME/BTC')
refresh_data(datadir=testdatadir, timeframe='1m', pairs=['MEME/BTC'],
exchange=exchange)
load_pair_history(datadir=testdatadir, timeframe='1m', pair='MEME/BTC')
assert file.is_file()
assert log_has_re(
'Download history data for pair: "MEME/BTC", timeframe: 1m '
'and store in .*', caplog
)
with pytest.raises(OperationalException, match=r'Exchange needs to be initialized when.*'):
history.load_pair_history(datadir=testdatadir,
timeframe='1m',
refresh_pairs=True,
exchange=None,
pair='MEME/BTC')
_clean_test_file(file)
@@ -267,12 +256,12 @@ def test_download_pair_history(ticker_history_list, mocker, default_conf, testda
assert not file1_1.is_file()
assert not file2_1.is_file()
assert download_pair_history(datadir=testdatadir, exchange=exchange,
pair='MEME/BTC',
timeframe='1m')
assert download_pair_history(datadir=testdatadir, exchange=exchange,
pair='CFI/BTC',
timeframe='1m')
assert _download_pair_history(datadir=testdatadir, exchange=exchange,
pair='MEME/BTC',
timeframe='1m')
assert _download_pair_history(datadir=testdatadir, exchange=exchange,
pair='CFI/BTC',
timeframe='1m')
assert not exchange._pairs_last_refresh_time
assert file1_1.is_file()
assert file2_1.is_file()
@@ -284,12 +273,12 @@ def test_download_pair_history(ticker_history_list, mocker, default_conf, testda
assert not file1_5.is_file()
assert not file2_5.is_file()
assert download_pair_history(datadir=testdatadir, exchange=exchange,
pair='MEME/BTC',
timeframe='5m')
assert download_pair_history(datadir=testdatadir, exchange=exchange,
pair='CFI/BTC',
timeframe='5m')
assert _download_pair_history(datadir=testdatadir, exchange=exchange,
pair='MEME/BTC',
timeframe='5m')
assert _download_pair_history(datadir=testdatadir, exchange=exchange,
pair='CFI/BTC',
timeframe='5m')
assert not exchange._pairs_last_refresh_time
assert file1_5.is_file()
assert file2_5.is_file()
@@ -307,8 +296,8 @@ def test_download_pair_history2(mocker, default_conf, testdatadir) -> None:
json_dump_mock = mocker.patch('freqtrade.misc.file_dump_json', return_value=None)
mocker.patch('freqtrade.exchange.Exchange.get_historic_ohlcv', return_value=tick)
exchange = get_patched_exchange(mocker, default_conf)
download_pair_history(testdatadir, exchange, pair="UNITTEST/BTC", timeframe='1m')
download_pair_history(testdatadir, exchange, pair="UNITTEST/BTC", timeframe='3m')
_download_pair_history(testdatadir, exchange, pair="UNITTEST/BTC", timeframe='1m')
_download_pair_history(testdatadir, exchange, pair="UNITTEST/BTC", timeframe='3m')
assert json_dump_mock.call_count == 2
@@ -324,9 +313,9 @@ def test_download_backtesting_data_exception(ticker_history, mocker, caplog,
_backup_file(file1_1)
_backup_file(file1_5)
assert not download_pair_history(datadir=testdatadir, exchange=exchange,
pair='MEME/BTC',
timeframe='1m')
assert not _download_pair_history(datadir=testdatadir, exchange=exchange,
pair='MEME/BTC',
timeframe='1m')
# clean files freshly downloaded
_clean_test_file(file1_1)
_clean_test_file(file1_5)
@@ -351,10 +340,8 @@ 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))
tickerdata = 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
)
@@ -369,10 +356,8 @@ def test_load_partial_missing(testdatadir, caplog) -> None:
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))
tickerdata = 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'])
@@ -384,12 +369,24 @@ def test_load_partial_missing(testdatadir, caplog) -> None:
def test_init(default_conf, mocker) -> None:
exchange = get_patched_exchange(mocker, default_conf)
assert {} == history.load_data(
assert {} == load_data(
datadir='',
pairs=[],
timeframe=default_conf['ticker_interval']
)
def test_init_with_refresh(default_conf, mocker) -> None:
exchange = get_patched_exchange(mocker, default_conf)
refresh_data(
datadir='',
pairs=[],
timeframe=default_conf['ticker_interval'],
exchange=exchange
)
assert {} == load_data(
datadir='',
exchange=exchange,
pairs=[],
refresh_pairs=True,
timeframe=default_conf['ticker_interval']
)
@@ -447,7 +444,7 @@ def test_trim_tickerlist(testdatadir) -> None:
def test_trim_dataframe(testdatadir) -> None:
data = history.load_data(
data = load_data(
datadir=testdatadir,
timeframe='1m',
pairs=['UNITTEST/BTC']
@@ -458,7 +455,7 @@ def test_trim_dataframe(testdatadir) -> None:
# Remove first 30 minutes (1800 s)
tr = TimeRange('date', None, min_date + 1800, 0)
data_modify = history.trim_dataframe(data_modify, tr)
data_modify = trim_dataframe(data_modify, tr)
assert not data_modify.equals(data)
assert len(data_modify) < len(data)
assert len(data_modify) == len(data) - 30
@@ -468,7 +465,7 @@ def test_trim_dataframe(testdatadir) -> None:
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)
data_modify = trim_dataframe(data_modify, tr)
assert not data_modify.equals(data)
assert len(data_modify) < len(data)
assert len(data_modify) == len(data) - 30
@@ -478,7 +475,7 @@ def test_trim_dataframe(testdatadir) -> None:
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)
data_modify = trim_dataframe(data_modify, tr)
assert not data_modify.equals(data)
assert len(data_modify) < len(data)
assert len(data_modify) == len(data) - 55
@@ -510,18 +507,18 @@ def test_file_dump_json_tofile(testdatadir) -> None:
_clean_test_file(file)
def test_get_timeframe(default_conf, mocker, testdatadir) -> None:
def test_get_timerange(default_conf, mocker, testdatadir) -> None:
patch_exchange(mocker)
strategy = DefaultStrategy(default_conf)
data = strategy.tickerdata_to_dataframe(
history.load_data(
load_data(
datadir=testdatadir,
timeframe='1m',
pairs=['UNITTEST/BTC']
)
)
min_date, max_date = history.get_timeframe(data)
min_date, max_date = get_timerange(data)
assert min_date.isoformat() == '2017-11-04T23:02:00+00:00'
assert max_date.isoformat() == '2017-11-14T22:58:00+00:00'
@@ -531,17 +528,17 @@ def test_validate_backtest_data_warn(default_conf, mocker, caplog, testdatadir)
strategy = DefaultStrategy(default_conf)
data = strategy.tickerdata_to_dataframe(
history.load_data(
load_data(
datadir=testdatadir,
timeframe='1m',
pairs=['UNITTEST/BTC'],
fill_up_missing=False
)
)
min_date, max_date = history.get_timeframe(data)
min_date, max_date = get_timerange(data)
caplog.clear()
assert history.validate_backtest_data(data['UNITTEST/BTC'], 'UNITTEST/BTC',
min_date, max_date, timeframe_to_minutes('1m'))
assert validate_backtest_data(data['UNITTEST/BTC'], 'UNITTEST/BTC',
min_date, max_date, timeframe_to_minutes('1m'))
assert len(caplog.record_tuples) == 1
assert log_has(
"UNITTEST/BTC has missing frames: expected 14396, got 13680, that's 716 missing values",
@@ -554,7 +551,7 @@ def test_validate_backtest_data(default_conf, mocker, caplog, testdatadir) -> No
timerange = TimeRange('index', 'index', 200, 250)
data = strategy.tickerdata_to_dataframe(
history.load_data(
load_data(
datadir=testdatadir,
timeframe='5m',
pairs=['UNITTEST/BTC'],
@@ -562,15 +559,15 @@ def test_validate_backtest_data(default_conf, mocker, caplog, testdatadir) -> No
)
)
min_date, max_date = history.get_timeframe(data)
min_date, max_date = get_timerange(data)
caplog.clear()
assert not history.validate_backtest_data(data['UNITTEST/BTC'], 'UNITTEST/BTC',
min_date, max_date, timeframe_to_minutes('5m'))
assert not validate_backtest_data(data['UNITTEST/BTC'], 'UNITTEST/BTC',
min_date, max_date, timeframe_to_minutes('5m'))
assert len(caplog.record_tuples) == 0
def test_refresh_backtest_ohlcv_data(mocker, default_conf, markets, caplog, testdatadir):
dl_mock = mocker.patch('freqtrade.data.history.download_pair_history', MagicMock())
dl_mock = mocker.patch('freqtrade.data.history._download_pair_history', MagicMock())
mocker.patch(
'freqtrade.exchange.Exchange.markets', PropertyMock(return_value=markets)
)
@@ -580,7 +577,7 @@ def test_refresh_backtest_ohlcv_data(mocker, default_conf, markets, caplog, test
ex = get_patched_exchange(mocker, default_conf)
timerange = TimeRange.parse_timerange("20190101-20190102")
refresh_backtest_ohlcv_data(exchange=ex, pairs=["ETH/BTC", "XRP/BTC"],
timeframes=["1m", "5m"], dl_path=testdatadir,
timeframes=["1m", "5m"], datadir=testdatadir,
timerange=timerange, erase=True
)
@@ -591,7 +588,7 @@ def test_refresh_backtest_ohlcv_data(mocker, default_conf, markets, caplog, test
def test_download_data_no_markets(mocker, default_conf, caplog, testdatadir):
dl_mock = mocker.patch('freqtrade.data.history.download_pair_history', MagicMock())
dl_mock = mocker.patch('freqtrade.data.history._download_pair_history', MagicMock())
ex = get_patched_exchange(mocker, default_conf)
mocker.patch(
@@ -600,7 +597,7 @@ def test_download_data_no_markets(mocker, default_conf, caplog, testdatadir):
timerange = TimeRange.parse_timerange("20190101-20190102")
unav_pairs = refresh_backtest_ohlcv_data(exchange=ex, pairs=["BTT/BTC", "LTC/USDT"],
timeframes=["1m", "5m"],
dl_path=testdatadir,
datadir=testdatadir,
timerange=timerange, erase=False
)
@@ -611,7 +608,7 @@ def test_download_data_no_markets(mocker, default_conf, caplog, testdatadir):
def test_refresh_backtest_trades_data(mocker, default_conf, markets, caplog, testdatadir):
dl_mock = mocker.patch('freqtrade.data.history.download_trades_history', MagicMock())
dl_mock = mocker.patch('freqtrade.data.history._download_trades_history', MagicMock())
mocker.patch(
'freqtrade.exchange.Exchange.markets', PropertyMock(return_value=markets)
)
@@ -646,8 +643,8 @@ def test_download_trades_history(trades_history, mocker, default_conf, testdatad
assert not file1.is_file()
assert download_trades_history(datadir=testdatadir, exchange=exchange,
pair='ETH/BTC')
assert _download_trades_history(datadir=testdatadir, exchange=exchange,
pair='ETH/BTC')
assert log_has("New Amount of trades: 5", caplog)
assert file1.is_file()
@@ -657,8 +654,8 @@ def test_download_trades_history(trades_history, mocker, default_conf, testdatad
mocker.patch('freqtrade.exchange.Exchange.get_historic_trades',
MagicMock(side_effect=ValueError))
assert not download_trades_history(datadir=testdatadir, exchange=exchange,
pair='ETH/BTC')
assert not _download_trades_history(datadir=testdatadir, exchange=exchange,
pair='ETH/BTC')
assert log_has_re('Failed to download historic trades for pair: "ETH/BTC".*', caplog)
@@ -668,12 +665,8 @@ def test_convert_trades_to_ohlcv(mocker, default_conf, testdatadir, caplog):
file1 = testdatadir / 'XRP_ETH-1m.json'
file5 = testdatadir / 'XRP_ETH-5m.json'
# Compare downloaded dataset with converted dataset
dfbak_1m = history.load_pair_history(datadir=testdatadir,
timeframe="1m",
pair=pair)
dfbak_5m = history.load_pair_history(datadir=testdatadir,
timeframe="5m",
pair=pair)
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)
@@ -685,12 +678,8 @@ def test_convert_trades_to_ohlcv(mocker, default_conf, testdatadir, caplog):
assert log_has("Deleting existing data for pair XRP/ETH, interval 1m.", caplog)
# Load new data
df_1m = history.load_pair_history(datadir=testdatadir,
timeframe="1m",
pair=pair)
df_5m = history.load_pair_history(datadir=testdatadir,
timeframe="5m",
pair=pair)
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)

View File

@@ -255,8 +255,8 @@ def test_edge_heartbeat_calculate(mocker, edge_conf):
assert edge.calculate() is False
def mocked_load_data(datadir, pairs=[], timeframe='0m', refresh_pairs=False,
timerange=None, exchange=None, *args, **kwargs):
def mocked_load_data(datadir, pairs=[], timeframe='0m',
timerange=None, *args, **kwargs):
hz = 0.1
base = 0.001
@@ -290,6 +290,7 @@ def mocked_load_data(datadir, pairs=[], timeframe='0m', refresh_pairs=False,
def test_edge_process_downloaded_data(mocker, edge_conf):
freqtrade = get_patched_freqtradebot(mocker, edge_conf)
mocker.patch('freqtrade.exchange.Exchange.get_fee', MagicMock(return_value=0.001))
mocker.patch('freqtrade.data.history.refresh_data', MagicMock())
mocker.patch('freqtrade.data.history.load_data', mocked_load_data)
edge = Edge(edge_conf, freqtrade.exchange, freqtrade.strategy)
@@ -301,6 +302,7 @@ def test_edge_process_downloaded_data(mocker, edge_conf):
def test_edge_process_no_data(mocker, edge_conf, caplog):
freqtrade = get_patched_freqtradebot(mocker, edge_conf)
mocker.patch('freqtrade.exchange.Exchange.get_fee', MagicMock(return_value=0.001))
mocker.patch('freqtrade.data.history.refresh_data', MagicMock())
mocker.patch('freqtrade.data.history.load_data', MagicMock(return_value={}))
edge = Edge(edge_conf, freqtrade.exchange, freqtrade.strategy)
@@ -313,6 +315,7 @@ def test_edge_process_no_data(mocker, edge_conf, caplog):
def test_edge_process_no_trades(mocker, edge_conf, caplog):
freqtrade = get_patched_freqtradebot(mocker, edge_conf)
mocker.patch('freqtrade.exchange.Exchange.get_fee', MagicMock(return_value=0.001))
mocker.patch('freqtrade.data.history.refresh_data', MagicMock())
mocker.patch('freqtrade.data.history.load_data', mocked_load_data)
# Return empty
mocker.patch('freqtrade.edge.Edge._find_trades_for_stoploss_range', MagicMock(return_value=[]))
@@ -334,7 +337,7 @@ def test_process_expectancy(mocker, edge_conf):
edge_conf['edge']['min_trade_number'] = 2
freqtrade = get_patched_freqtradebot(mocker, edge_conf)
def get_fee():
def get_fee(*args, **kwargs):
return 0.001
freqtrade.exchange.get_fee = get_fee

View File

@@ -876,6 +876,7 @@ def test_sell_considers_time_in_force(default_conf, mocker, exchange_name):
def test_get_balance_dry_run(default_conf, mocker):
default_conf['dry_run'] = True
default_conf['dry_run_wallet'] = 999.9
exchange = get_patched_exchange(mocker, default_conf)
assert exchange.get_balance(currency='BTC') == 999.9
@@ -1646,10 +1647,10 @@ def test_get_fee(default_conf, mocker, exchange_name):
})
exchange = get_patched_exchange(mocker, default_conf, api_mock, id=exchange_name)
assert exchange.get_fee() == 0.025
assert exchange.get_fee('ETH/BTC') == 0.025
ccxt_exceptionhandlers(mocker, default_conf, api_mock, exchange_name,
'get_fee', 'calculate_fee')
'get_fee', 'calculate_fee', symbol="ETH/BTC")
def test_stoploss_limit_order_unsupported_exchange(default_conf, mocker):

View File

@@ -4,7 +4,7 @@ from unittest.mock import MagicMock
import pytest
from freqtrade.data.history import get_timeframe
from freqtrade.data.history import get_timerange
from freqtrade.optimize.backtesting import Backtesting
from freqtrade.strategy.interface import SellType
from tests.conftest import patch_exchange
@@ -250,7 +250,7 @@ tc15 = BTContainer(data=[
BTrade(sell_reason=SellType.STOP_LOSS, open_tick=2, close_tick=2)]
)
# Test 16: Buy, hold for 65 mins, then forcesell using roi=-1
# Test 16: Buy, hold for 65 min, then forcesell using roi=-1
# Causes negative profit even though sell-reason is ROI.
# stop-loss: 10%, ROI: 10% (should not apply), -100% after 65 minutes (limits trade duration)
tc16 = BTContainer(data=[
@@ -265,6 +265,69 @@ tc16 = BTContainer(data=[
trades=[BTrade(sell_reason=SellType.ROI, open_tick=1, close_tick=3)]
)
# Test 17: Buy, hold for 120 mins, then forcesell using roi=-1
# Causes negative profit even though sell-reason is ROI.
# stop-loss: 10%, ROI: 10% (should not apply), -100% after 100 minutes (limits trade duration)
# Uses open as sell-rate (special case) - since the roi-time is a multiple of the ticker interval.
tc17 = BTContainer(data=[
# D O H L C V B S
[0, 5000, 5025, 4975, 4987, 6172, 1, 0],
[1, 5000, 5025, 4975, 4987, 6172, 0, 0],
[2, 4987, 5300, 4950, 5050, 6172, 0, 0],
[3, 4980, 5000, 4940, 4962, 6172, 0, 0], # ForceSell on ROI (roi=-1)
[4, 4962, 4987, 4972, 4950, 6172, 0, 0],
[5, 4950, 4975, 4925, 4950, 6172, 0, 0]],
stop_loss=-0.10, roi={"0": 0.10, "120": -1}, profit_perc=-0.004,
trades=[BTrade(sell_reason=SellType.ROI, open_tick=1, close_tick=3)]
)
# Test 18: Buy, hold for 120 mins, then drop ROI to 1%, causing a sell in candle 3.
# stop-loss: 10%, ROI: 10% (should not apply), -100% after 100 minutes (limits trade duration)
# uses open_rate as sell-price
tc18 = BTContainer(data=[
# D O H L C V B S
[0, 5000, 5025, 4975, 4987, 6172, 1, 0],
[1, 5000, 5025, 4975, 4987, 6172, 0, 0],
[2, 4987, 5300, 4950, 5200, 6172, 0, 0],
[3, 5200, 5220, 4940, 4962, 6172, 0, 0], # Sell on ROI (sells on open)
[4, 4962, 4987, 4972, 4950, 6172, 0, 0],
[5, 4950, 4975, 4925, 4950, 6172, 0, 0]],
stop_loss=-0.10, roi={"0": 0.10, "120": 0.01}, profit_perc=0.04,
trades=[BTrade(sell_reason=SellType.ROI, open_tick=1, close_tick=3)]
)
# Test 19: Buy, hold for 119 mins, then drop ROI to 1%, causing a sell in candle 3.
# stop-loss: 10%, ROI: 10% (should not apply), -100% after 100 minutes (limits trade duration)
# uses calculated ROI (1%) as sell rate, otherwise identical to tc18
tc19 = BTContainer(data=[
# D O H L C V B S
[0, 5000, 5025, 4975, 4987, 6172, 1, 0],
[1, 5000, 5025, 4975, 4987, 6172, 0, 0],
[2, 4987, 5300, 4950, 5200, 6172, 0, 0],
[3, 5000, 5300, 4940, 4962, 6172, 0, 0], # Sell on ROI
[4, 4962, 4987, 4972, 4950, 6172, 0, 0],
[5, 4550, 4975, 4925, 4950, 6172, 0, 0]],
stop_loss=-0.10, roi={"0": 0.10, "120": 0.01}, profit_perc=0.01,
trades=[BTrade(sell_reason=SellType.ROI, open_tick=1, close_tick=3)]
)
# Test 20: Buy, hold for 119 mins, then drop ROI to 1%, causing a sell in candle 3.
# stop-loss: 10%, ROI: 10% (should not apply), -100% after 100 minutes (limits trade duration)
# uses calculated ROI (1%) as sell rate, otherwise identical to tc18
tc20 = BTContainer(data=[
# D O H L C V B S
[0, 5000, 5025, 4975, 4987, 6172, 1, 0],
[1, 5000, 5025, 4975, 4987, 6172, 0, 0],
[2, 4987, 5300, 4950, 5200, 6172, 0, 0],
[3, 5200, 5300, 4940, 4962, 6172, 0, 0], # Sell on ROI
[4, 4962, 4987, 4972, 4950, 6172, 0, 0],
[5, 4550, 4975, 4925, 4950, 6172, 0, 0]],
stop_loss=-0.10, roi={"0": 0.10, "119": 0.01}, profit_perc=0.01,
trades=[BTrade(sell_reason=SellType.ROI, open_tick=1, close_tick=3)]
)
TESTS = [
tc0,
tc1,
@@ -283,6 +346,10 @@ TESTS = [
tc14,
tc15,
tc16,
tc17,
tc18,
tc19,
tc20,
]
@@ -313,7 +380,7 @@ def test_backtest_results(default_conf, fee, mocker, caplog, data) -> None:
pair = "UNITTEST/BTC"
# Dummy data as we mock the analyze functions
data_processed = {pair: frame.copy()}
min_date, max_date = get_timeframe({pair: frame})
min_date, max_date = get_timerange({pair: frame})
results = backtesting.backtest(
{
'stake_amount': default_conf['stake_amount'],

View File

@@ -16,7 +16,7 @@ from freqtrade.data import history
from freqtrade.data.btanalysis import evaluate_result_multi
from freqtrade.data.converter import parse_ticker_dataframe
from freqtrade.data.dataprovider import DataProvider
from freqtrade.data.history import get_timeframe
from freqtrade.data.history import get_timerange
from freqtrade.optimize import setup_configuration, start_backtesting
from freqtrade.optimize.backtesting import Backtesting
from freqtrade.state import RunMode
@@ -100,7 +100,7 @@ def simple_backtest(config, contour, num_results, mocker, testdatadir) -> None:
data = load_data_test(contour, testdatadir)
processed = backtesting.strategy.tickerdata_to_dataframe(data)
min_date, max_date = get_timeframe(processed)
min_date, max_date = get_timerange(processed)
assert isinstance(processed, dict)
results = backtesting.backtest(
{
@@ -116,8 +116,8 @@ def simple_backtest(config, contour, num_results, mocker, testdatadir) -> None:
assert len(results) == num_results
def mocked_load_data(datadir, pairs=[], timeframe='0m', refresh_pairs=False,
timerange=None, exchange=None, live=False, *args, **kwargs):
def mocked_load_data(datadir, pairs=[], timeframe='0m',
timerange=None, *args, **kwargs):
tickerdata = history.load_tickerdata_file(datadir, 'UNITTEST/BTC', '1m', timerange=timerange)
pairdata = {'UNITTEST/BTC': parse_ticker_dataframe(tickerdata, '1m', pair="UNITTEST/BTC",
fill_missing=True)}
@@ -138,7 +138,7 @@ def _make_backtest_conf(mocker, datadir, conf=None, pair='UNITTEST/BTC', record=
patch_exchange(mocker)
backtesting = Backtesting(conf)
processed = backtesting.strategy.tickerdata_to_dataframe(data)
min_date, max_date = get_timeframe(processed)
min_date, max_date = get_timerange(processed)
return {
'stake_amount': conf['stake_amount'],
'processed': processed,
@@ -458,11 +458,11 @@ def test_generate_text_table_strategyn(default_conf, mocker):
def test_backtesting_start(default_conf, mocker, testdatadir, caplog) -> None:
def get_timeframe(input1):
def get_timerange(input1):
return Arrow(2017, 11, 14, 21, 17), Arrow(2017, 11, 14, 22, 59)
mocker.patch('freqtrade.data.history.load_data', mocked_load_data)
mocker.patch('freqtrade.data.history.get_timeframe', get_timeframe)
mocker.patch('freqtrade.data.history.get_timerange', get_timerange)
mocker.patch('freqtrade.exchange.Exchange.refresh_latest_ohlcv', MagicMock())
patch_exchange(mocker)
mocker.patch.multiple(
@@ -491,11 +491,11 @@ def test_backtesting_start(default_conf, mocker, testdatadir, caplog) -> None:
def test_backtesting_start_no_data(default_conf, mocker, caplog, testdatadir) -> None:
def get_timeframe(input1):
def get_timerange(input1):
return Arrow(2017, 11, 14, 21, 17), Arrow(2017, 11, 14, 22, 59)
mocker.patch('freqtrade.data.history.load_pair_history', MagicMock(return_value=pd.DataFrame()))
mocker.patch('freqtrade.data.history.get_timeframe', get_timeframe)
mocker.patch('freqtrade.data.history.get_timerange', get_timerange)
mocker.patch('freqtrade.exchange.Exchange.refresh_latest_ohlcv', MagicMock())
patch_exchange(mocker)
mocker.patch.multiple(
@@ -525,7 +525,7 @@ def test_backtest(default_conf, fee, mocker, testdatadir) -> None:
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)
min_date, max_date = get_timerange(data_processed)
results = backtesting.backtest(
{
'stake_amount': default_conf['stake_amount'],
@@ -581,7 +581,7 @@ def test_backtest_1min_ticker_interval(default_conf, fee, mocker, testdatadir) -
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)
min_date, max_date = get_timerange(processed)
results = backtesting.backtest(
{
'stake_amount': default_conf['stake_amount'],
@@ -701,7 +701,7 @@ def test_backtest_multi_pair(default_conf, fee, mocker, tres, pair, testdatadir)
backtesting.strategy.advise_sell = _trend_alternate_hold # Override
data_processed = backtesting.strategy.tickerdata_to_dataframe(data)
min_date, max_date = get_timeframe(data_processed)
min_date, max_date = get_timerange(data_processed)
backtest_conf = {
'stake_amount': default_conf['stake_amount'],
'processed': data_processed,

View File

@@ -251,7 +251,7 @@ def test_start_no_data(mocker, default_conf, caplog) -> None:
patched_configuration_load_config_file(mocker, default_conf)
mocker.patch('freqtrade.data.history.load_pair_history', MagicMock(return_value=pd.DataFrame))
mocker.patch(
'freqtrade.optimize.hyperopt.get_timeframe',
'freqtrade.optimize.hyperopt.get_timerange',
MagicMock(return_value=(datetime(2017, 12, 10), datetime(2017, 12, 13)))
)
@@ -427,7 +427,7 @@ def test_start_calls_optimizer(mocker, default_conf, caplog, capsys) -> None:
mocker.patch('freqtrade.optimize.backtesting.Backtesting.load_bt_data',
MagicMock(return_value=(MagicMock(), None)))
mocker.patch(
'freqtrade.optimize.hyperopt.get_timeframe',
'freqtrade.optimize.hyperopt.get_timerange',
MagicMock(return_value=(datetime(2017, 12, 10), datetime(2017, 12, 13)))
)
@@ -602,7 +602,7 @@ def test_generate_optimizer(mocker, default_conf) -> None:
MagicMock(return_value=backtest_result)
)
mocker.patch(
'freqtrade.optimize.hyperopt.get_timeframe',
'freqtrade.optimize.hyperopt.get_timerange',
MagicMock(return_value=(Arrow(2017, 12, 10), Arrow(2017, 12, 13)))
)
patch_exchange(mocker)
@@ -642,7 +642,7 @@ def test_generate_optimizer(mocker, default_conf) -> None:
response_expected = {
'loss': 1.9840569076926293,
'results_explanation': (' 1 trades. Avg profit 2.31%. Total profit 0.00023300 BTC '
'( 2.31\N{GREEK CAPITAL LETTER SIGMA}%). Avg duration 100.0 mins.'
'( 2.31\N{GREEK CAPITAL LETTER SIGMA}%). Avg duration 100.0 min.'
).encode(locale.getpreferredencoding(), 'replace').decode('utf-8'),
'params_details': {'buy': {'adx-enabled': False,
'adx-value': 0,
@@ -726,7 +726,7 @@ def test_print_json_spaces_all(mocker, default_conf, caplog, capsys) -> None:
mocker.patch('freqtrade.optimize.backtesting.Backtesting.load_bt_data',
MagicMock(return_value=(MagicMock(), None)))
mocker.patch(
'freqtrade.optimize.hyperopt.get_timeframe',
'freqtrade.optimize.hyperopt.get_timerange',
MagicMock(return_value=(datetime(2017, 12, 10), datetime(2017, 12, 13)))
)
@@ -769,7 +769,7 @@ def test_print_json_spaces_default(mocker, default_conf, caplog, capsys) -> None
mocker.patch('freqtrade.optimize.backtesting.Backtesting.load_bt_data',
MagicMock(return_value=(MagicMock(), None)))
mocker.patch(
'freqtrade.optimize.hyperopt.get_timeframe',
'freqtrade.optimize.hyperopt.get_timerange',
MagicMock(return_value=(datetime(2017, 12, 10), datetime(2017, 12, 13)))
)
@@ -811,7 +811,7 @@ def test_print_json_spaces_roi_stoploss(mocker, default_conf, caplog, capsys) ->
mocker.patch('freqtrade.optimize.backtesting.Backtesting.load_bt_data',
MagicMock(return_value=(MagicMock(), None)))
mocker.patch(
'freqtrade.optimize.hyperopt.get_timeframe',
'freqtrade.optimize.hyperopt.get_timerange',
MagicMock(return_value=(datetime(2017, 12, 10), datetime(2017, 12, 13)))
)
@@ -851,7 +851,7 @@ def test_simplified_interface_roi_stoploss(mocker, default_conf, caplog, capsys)
mocker.patch('freqtrade.optimize.backtesting.Backtesting.load_bt_data',
MagicMock(return_value=(MagicMock(), None)))
mocker.patch(
'freqtrade.optimize.hyperopt.get_timeframe',
'freqtrade.optimize.hyperopt.get_timerange',
MagicMock(return_value=(datetime(2017, 12, 10), datetime(2017, 12, 13)))
)
@@ -899,7 +899,7 @@ def test_simplified_interface_all_failed(mocker, default_conf, caplog, capsys) -
mocker.patch('freqtrade.optimize.backtesting.Backtesting.load_bt_data',
MagicMock(return_value=(MagicMock(), None)))
mocker.patch(
'freqtrade.optimize.hyperopt.get_timeframe',
'freqtrade.optimize.hyperopt.get_timerange',
MagicMock(return_value=(datetime(2017, 12, 10), datetime(2017, 12, 13)))
)
@@ -930,7 +930,7 @@ def test_simplified_interface_buy(mocker, default_conf, caplog, capsys) -> None:
mocker.patch('freqtrade.optimize.backtesting.Backtesting.load_bt_data',
MagicMock(return_value=(MagicMock(), None)))
mocker.patch(
'freqtrade.optimize.hyperopt.get_timeframe',
'freqtrade.optimize.hyperopt.get_timerange',
MagicMock(return_value=(datetime(2017, 12, 10), datetime(2017, 12, 13)))
)
@@ -977,7 +977,7 @@ def test_simplified_interface_sell(mocker, default_conf, caplog, capsys) -> None
mocker.patch('freqtrade.optimize.backtesting.Backtesting.load_bt_data',
MagicMock(return_value=(MagicMock(), None)))
mocker.patch(
'freqtrade.optimize.hyperopt.get_timeframe',
'freqtrade.optimize.hyperopt.get_timerange',
MagicMock(return_value=(datetime(2017, 12, 10), datetime(2017, 12, 13)))
)
@@ -1030,7 +1030,7 @@ def test_simplified_interface_failed(mocker, default_conf, caplog, capsys, metho
mocker.patch('freqtrade.optimize.backtesting.Backtesting.load_bt_data',
MagicMock(return_value=(MagicMock(), None)))
mocker.patch(
'freqtrade.optimize.hyperopt.get_timeframe',
'freqtrade.optimize.hyperopt.get_timerange',
MagicMock(return_value=(datetime(2017, 12, 10), datetime(2017, 12, 13)))
)

View File

@@ -398,7 +398,7 @@ def test_rpc_balance_handle(default_conf, mocker, tickers):
get_valid_pair_combination=MagicMock(
side_effect=lambda a, b: f"{b}/{a}" if a == "USDT" else f"{a}/{b}")
)
default_conf['dry_run'] = False
freqtradebot = get_patched_freqtradebot(mocker, default_conf)
patch_get_signal(freqtradebot, (True, False))
rpc = RPC(freqtradebot)

View File

@@ -230,6 +230,7 @@ def test_api_stopbuy(botclient):
def test_api_balance(botclient, mocker, rpc_balance):
ftbot, client = botclient
ftbot.config['dry_run'] = False
mocker.patch('freqtrade.exchange.Exchange.get_balances', return_value=rpc_balance)
mocker.patch('freqtrade.exchange.Exchange.get_valid_pair_combination',
side_effect=lambda a, b: f"{a}/{b}")
@@ -380,7 +381,7 @@ def test_api_performance(botclient, mocker, ticker, fee):
close_rate=0.265441,
)
trade.close_profit = trade.calc_profit_percent()
trade.close_profit = trade.calc_profit_ratio()
Trade.session.add(trade)
trade = Trade(
@@ -395,7 +396,7 @@ def test_api_performance(botclient, mocker, ticker, fee):
fee_open=fee.return_value,
close_rate=0.391
)
trade.close_profit = trade.calc_profit_percent()
trade.close_profit = trade.calc_profit_ratio()
Trade.session.add(trade)
Trade.session.flush()

View File

@@ -462,7 +462,7 @@ def test_profit_handle(default_conf, update, ticker, ticker_sell_up, fee,
def test_telegram_balance_handle(default_conf, update, mocker, rpc_balance, tickers) -> None:
default_conf['dry_run'] = False
mocker.patch('freqtrade.exchange.Exchange.get_balances', return_value=rpc_balance)
mocker.patch('freqtrade.exchange.Exchange.get_tickers', tickers)
mocker.patch('freqtrade.exchange.Exchange.get_valid_pair_combination',
@@ -494,6 +494,7 @@ def test_telegram_balance_handle(default_conf, update, mocker, rpc_balance, tick
def test_balance_handle_empty_response(default_conf, update, mocker) -> None:
default_conf['dry_run'] = False
mocker.patch('freqtrade.exchange.Exchange.get_balances', return_value={})
msg_mock = MagicMock()
@@ -533,7 +534,8 @@ def test_balance_handle_empty_response_dry(default_conf, update, mocker) -> None
telegram._balance(update=update, context=MagicMock())
result = msg_mock.call_args_list[0][0][0]
assert msg_mock.call_count == 1
assert "Running in Dry Run, balances are not available." in result
assert "*Warning:*Simulated balances in Dry Mode." in result
assert "Starting capital: `1000` BTC" in result
def test_balance_handle_too_large_response(default_conf, update, mocker) -> None:
@@ -1177,6 +1179,16 @@ def test_show_config_handle(default_conf, update, mocker) -> None:
assert '*Mode:* `{}`'.format('Dry-run') in msg_mock.call_args_list[0][0][0]
assert '*Exchange:* `bittrex`' in msg_mock.call_args_list[0][0][0]
assert '*Strategy:* `DefaultStrategy`' in msg_mock.call_args_list[0][0][0]
assert '*Stoploss:* `-0.1`' in msg_mock.call_args_list[0][0][0]
msg_mock.reset_mock()
freqtradebot.config['trailing_stop'] = True
telegram._show_config(update=update, context=MagicMock())
assert msg_mock.call_count == 1
assert '*Mode:* `{}`'.format('Dry-run') in msg_mock.call_args_list[0][0][0]
assert '*Exchange:* `bittrex`' in msg_mock.call_args_list[0][0][0]
assert '*Strategy:* `DefaultStrategy`' in msg_mock.call_args_list[0][0][0]
assert '*Initial Stoploss:* `-0.1`' in msg_mock.call_args_list[0][0][0]
def test_send_msg_buy_notification(default_conf, mocker) -> None:

View File

@@ -125,6 +125,7 @@ def test_min_roi_reached(default_conf, fee) -> None:
trade = Trade(
pair='ETH/BTC',
stake_amount=0.001,
amount=5,
open_date=arrow.utcnow().shift(hours=-1).datetime,
fee_open=fee.return_value,
fee_close=fee.return_value,
@@ -162,6 +163,7 @@ def test_min_roi_reached2(default_conf, fee) -> None:
trade = Trade(
pair='ETH/BTC',
stake_amount=0.001,
amount=5,
open_date=arrow.utcnow().shift(hours=-1).datetime,
fee_open=fee.return_value,
fee_close=fee.return_value,
@@ -195,6 +197,7 @@ def test_min_roi_reached3(default_conf, fee) -> None:
trade = Trade(
pair='ETH/BTC',
stake_amount=0.001,
amount=5,
open_date=arrow.utcnow().shift(hours=-1).datetime,
fee_open=fee.return_value,
fee_close=fee.return_value,

View File

@@ -8,9 +8,9 @@ from pathlib import Path
from unittest.mock import MagicMock
import pytest
from jsonschema import Draft4Validator, ValidationError, validate
from jsonschema import ValidationError
from freqtrade import OperationalException, constants
from freqtrade import OperationalException
from freqtrade.configuration import (Arguments, Configuration, check_exchange,
remove_credentials,
validate_config_consistency)
@@ -718,7 +718,8 @@ def test_load_config_warn_forcebuy(default_conf, mocker, caplog) -> None:
def test_validate_default_conf(default_conf) -> None:
validate(default_conf, constants.CONF_SCHEMA, Draft4Validator)
# Validate via our validator - we allow setting defaults!
validate_config_schema(default_conf)
def test_validate_tsl(default_conf):

View File

@@ -211,6 +211,7 @@ def test_edge_overrides_stake_amount(mocker, edge_conf) -> None:
patch_RPCManager(mocker)
patch_exchange(mocker)
patch_edge(mocker)
edge_conf['dry_run_wallet'] = 999.9
freqtrade = FreqtradeBot(edge_conf)
assert freqtrade._get_trade_stake_amount('NEO/BTC') == (999.9 * 0.5 * 0.01) / 0.20
@@ -786,7 +787,10 @@ def test_process_trade_no_whitelist_pair(default_conf, ticker, limit_buy_order,
)
freqtrade = FreqtradeBot(default_conf)
patch_get_signal(freqtrade)
pair = 'NOCLUE/BTC'
pair = 'BLK/BTC'
# Ensure the pair is not in the whitelist!
assert pair not in default_conf['exchange']['pair_whitelist']
# create open trade not in whitelist
Trade.session.add(Trade(
pair=pair,
@@ -1335,6 +1339,7 @@ def test_tsl_on_exchange_compatible_with_edge(mocker, edge_conf, fee, caplog,
patch_exchange(mocker)
patch_edge(mocker)
edge_conf['max_open_trades'] = float('inf')
edge_conf['dry_run_wallet'] = 999.9
mocker.patch.multiple(
'freqtrade.exchange.Exchange',
get_ticker=MagicMock(return_value={
@@ -1507,13 +1512,15 @@ def test_update_trade_state(mocker, default_conf, limit_buy_order, caplog) -> No
mocker.patch('freqtrade.freqtradebot.FreqtradeBot.get_real_amount',
return_value=limit_buy_order['amount'])
trade = Trade()
# Mock session away
Trade.session = MagicMock()
trade.open_order_id = '123'
trade.open_fee = 0.001
trade = Trade(
open_order_id=123,
fee_open=0.001,
fee_close=0.001,
open_rate=0.01,
open_date=arrow.utcnow().datetime,
amount=11,
)
# Add datetime explicitly since sqlalchemy defaults apply only once written to database
trade.open_date = arrow.utcnow().datetime
freqtrade.update_trade_state(trade)
# Test amount not modified by fee-logic
assert not log_has_re(r'Applying fee to .*', caplog)
@@ -1536,7 +1543,8 @@ def test_update_trade_state(mocker, default_conf, limit_buy_order, caplog) -> No
assert log_has_re('Found open order for.*', caplog)
def test_update_trade_state_withorderdict(default_conf, trades_for_order, limit_buy_order, mocker):
def test_update_trade_state_withorderdict(default_conf, trades_for_order, limit_buy_order, fee,
mocker):
mocker.patch('freqtrade.exchange.Exchange.get_trades_for_order', return_value=trades_for_order)
# get_order should not be called!!
mocker.patch('freqtrade.exchange.Exchange.get_order', MagicMock(side_effect=ValueError))
@@ -1549,6 +1557,8 @@ def test_update_trade_state_withorderdict(default_conf, trades_for_order, limit_
amount=amount,
exchange='binance',
open_rate=0.245441,
fee_open=fee.return_value,
fee_close=fee.return_value,
open_order_id="123456",
is_open=True,
)
@@ -1557,7 +1567,7 @@ def test_update_trade_state_withorderdict(default_conf, trades_for_order, limit_
assert trade.amount == limit_buy_order['amount']
def test_update_trade_state_withorderdict_rounding_fee(default_conf, trades_for_order,
def test_update_trade_state_withorderdict_rounding_fee(default_conf, trades_for_order, fee,
limit_buy_order, mocker, caplog):
trades_for_order[0]['amount'] = limit_buy_order['amount'] + 1e-14
mocker.patch('freqtrade.exchange.Exchange.get_trades_for_order', return_value=trades_for_order)
@@ -1572,6 +1582,8 @@ def test_update_trade_state_withorderdict_rounding_fee(default_conf, trades_for_
amount=amount,
exchange='binance',
open_rate=0.245441,
fee_open=fee.return_value,
fee_close=fee.return_value,
open_order_id="123456",
is_open=True,
open_date=arrow.utcnow().datetime,
@@ -3039,7 +3051,7 @@ def test_disable_ignore_roi_if_buy_signal(default_conf, limit_buy_order,
assert trade.sell_reason == SellType.STOP_LOSS.value
def test_get_real_amount_quote(default_conf, trades_for_order, buy_order_fee, caplog, mocker):
def test_get_real_amount_quote(default_conf, trades_for_order, buy_order_fee, fee, caplog, mocker):
mocker.patch('freqtrade.exchange.Exchange.get_trades_for_order', return_value=trades_for_order)
patch_RPCManager(mocker)
patch_exchange(mocker)
@@ -3049,6 +3061,8 @@ def test_get_real_amount_quote(default_conf, trades_for_order, buy_order_fee, ca
amount=amount,
exchange='binance',
open_rate=0.245441,
fee_open=fee.return_value,
fee_close=fee.return_value,
open_order_id="123456"
)
freqtrade = FreqtradeBot(default_conf)
@@ -3061,7 +3075,7 @@ def test_get_real_amount_quote(default_conf, trades_for_order, buy_order_fee, ca
caplog)
def test_get_real_amount_no_trade(default_conf, buy_order_fee, caplog, mocker):
def test_get_real_amount_no_trade(default_conf, buy_order_fee, caplog, mocker, fee):
mocker.patch('freqtrade.exchange.Exchange.get_trades_for_order', return_value=[])
patch_RPCManager(mocker)
@@ -3072,6 +3086,8 @@ def test_get_real_amount_no_trade(default_conf, buy_order_fee, caplog, mocker):
amount=amount,
exchange='binance',
open_rate=0.245441,
fee_open=fee.return_value,
fee_close=fee.return_value,
open_order_id="123456"
)
freqtrade = FreqtradeBot(default_conf)
@@ -3084,7 +3100,7 @@ def test_get_real_amount_no_trade(default_conf, buy_order_fee, caplog, mocker):
caplog)
def test_get_real_amount_stake(default_conf, trades_for_order, buy_order_fee, mocker):
def test_get_real_amount_stake(default_conf, trades_for_order, buy_order_fee, fee, mocker):
trades_for_order[0]['fee']['currency'] = 'ETH'
patch_RPCManager(mocker)
@@ -3095,6 +3111,8 @@ def test_get_real_amount_stake(default_conf, trades_for_order, buy_order_fee, mo
pair='LTC/ETH',
amount=amount,
exchange='binance',
fee_open=fee.return_value,
fee_close=fee.return_value,
open_rate=0.245441,
open_order_id="123456"
)
@@ -3105,7 +3123,8 @@ def test_get_real_amount_stake(default_conf, trades_for_order, buy_order_fee, mo
assert freqtrade.get_real_amount(trade, buy_order_fee) == amount
def test_get_real_amount_no_currency_in_fee(default_conf, trades_for_order, buy_order_fee, mocker):
def test_get_real_amount_no_currency_in_fee(default_conf, trades_for_order, buy_order_fee,
fee, mocker):
limit_buy_order = deepcopy(buy_order_fee)
limit_buy_order['fee'] = {'cost': 0.004, 'currency': None}
@@ -3119,6 +3138,8 @@ def test_get_real_amount_no_currency_in_fee(default_conf, trades_for_order, buy_
pair='LTC/ETH',
amount=amount,
exchange='binance',
fee_open=fee.return_value,
fee_close=fee.return_value,
open_rate=0.245441,
open_order_id="123456"
)
@@ -3129,7 +3150,7 @@ def test_get_real_amount_no_currency_in_fee(default_conf, trades_for_order, buy_
assert freqtrade.get_real_amount(trade, limit_buy_order) == amount
def test_get_real_amount_BNB(default_conf, trades_for_order, buy_order_fee, mocker):
def test_get_real_amount_BNB(default_conf, trades_for_order, buy_order_fee, fee, mocker):
trades_for_order[0]['fee']['currency'] = 'BNB'
trades_for_order[0]['fee']['cost'] = 0.00094518
@@ -3141,6 +3162,8 @@ def test_get_real_amount_BNB(default_conf, trades_for_order, buy_order_fee, mock
pair='LTC/ETH',
amount=amount,
exchange='binance',
fee_open=fee.return_value,
fee_close=fee.return_value,
open_rate=0.245441,
open_order_id="123456"
)
@@ -3151,7 +3174,7 @@ def test_get_real_amount_BNB(default_conf, trades_for_order, buy_order_fee, mock
assert freqtrade.get_real_amount(trade, buy_order_fee) == amount
def test_get_real_amount_multi(default_conf, trades_for_order2, buy_order_fee, caplog, mocker):
def test_get_real_amount_multi(default_conf, trades_for_order2, buy_order_fee, caplog, fee, mocker):
patch_RPCManager(mocker)
patch_exchange(mocker)
mocker.patch('freqtrade.exchange.Exchange.get_trades_for_order', return_value=trades_for_order2)
@@ -3160,6 +3183,8 @@ def test_get_real_amount_multi(default_conf, trades_for_order2, buy_order_fee, c
pair='LTC/ETH',
amount=amount,
exchange='binance',
fee_open=fee.return_value,
fee_close=fee.return_value,
open_rate=0.245441,
open_order_id="123456"
)
@@ -3173,7 +3198,8 @@ def test_get_real_amount_multi(default_conf, trades_for_order2, buy_order_fee, c
caplog)
def test_get_real_amount_fromorder(default_conf, trades_for_order, buy_order_fee, caplog, mocker):
def test_get_real_amount_fromorder(default_conf, trades_for_order, buy_order_fee, fee,
caplog, mocker):
limit_buy_order = deepcopy(buy_order_fee)
limit_buy_order['fee'] = {'cost': 0.004, 'currency': 'LTC'}
@@ -3186,6 +3212,8 @@ def test_get_real_amount_fromorder(default_conf, trades_for_order, buy_order_fee
pair='LTC/ETH',
amount=amount,
exchange='binance',
fee_open=fee.return_value,
fee_close=fee.return_value,
open_rate=0.245441,
open_order_id="123456"
)
@@ -3199,7 +3227,7 @@ def test_get_real_amount_fromorder(default_conf, trades_for_order, buy_order_fee
caplog)
def test_get_real_amount_invalid_order(default_conf, trades_for_order, buy_order_fee, mocker):
def test_get_real_amount_invalid_order(default_conf, trades_for_order, buy_order_fee, fee, mocker):
limit_buy_order = deepcopy(buy_order_fee)
limit_buy_order['fee'] = {'cost': 0.004}
@@ -3211,6 +3239,8 @@ def test_get_real_amount_invalid_order(default_conf, trades_for_order, buy_order
pair='LTC/ETH',
amount=amount,
exchange='binance',
fee_open=fee.return_value,
fee_close=fee.return_value,
open_rate=0.245441,
open_order_id="123456"
)
@@ -3221,7 +3251,7 @@ def test_get_real_amount_invalid_order(default_conf, trades_for_order, buy_order
assert freqtrade.get_real_amount(trade, limit_buy_order) == amount
def test_get_real_amount_wrong_amount(default_conf, trades_for_order, buy_order_fee, mocker):
def test_get_real_amount_wrong_amount(default_conf, trades_for_order, buy_order_fee, fee, mocker):
limit_buy_order = deepcopy(buy_order_fee)
limit_buy_order['amount'] = limit_buy_order['amount'] - 0.001
@@ -3234,6 +3264,8 @@ def test_get_real_amount_wrong_amount(default_conf, trades_for_order, buy_order_
amount=amount,
exchange='binance',
open_rate=0.245441,
fee_open=fee.return_value,
fee_close=fee.return_value,
open_order_id="123456"
)
freqtrade = FreqtradeBot(default_conf)
@@ -3244,7 +3276,7 @@ def test_get_real_amount_wrong_amount(default_conf, trades_for_order, buy_order_
freqtrade.get_real_amount(trade, limit_buy_order)
def test_get_real_amount_wrong_amount_rounding(default_conf, trades_for_order, buy_order_fee,
def test_get_real_amount_wrong_amount_rounding(default_conf, trades_for_order, buy_order_fee, fee,
mocker):
# Floats should not be compared directly.
limit_buy_order = deepcopy(buy_order_fee)
@@ -3258,6 +3290,8 @@ def test_get_real_amount_wrong_amount_rounding(default_conf, trades_for_order, b
pair='LTC/ETH',
amount=amount,
exchange='binance',
fee_open=fee.return_value,
fee_close=fee.return_value,
open_rate=0.245441,
open_order_id="123456"
)
@@ -3269,7 +3303,7 @@ def test_get_real_amount_wrong_amount_rounding(default_conf, trades_for_order, b
abs_tol=MATH_CLOSE_PREC,)
def test_get_real_amount_invalid(default_conf, trades_for_order, buy_order_fee, mocker):
def test_get_real_amount_invalid(default_conf, trades_for_order, buy_order_fee, fee, mocker):
# Remove "Currency" from fee dict
trades_for_order[0]['fee'] = {'cost': 0.008}
@@ -3282,6 +3316,9 @@ def test_get_real_amount_invalid(default_conf, trades_for_order, buy_order_fee,
amount=amount,
exchange='binance',
open_rate=0.245441,
fee_open=fee.return_value,
fee_close=fee.return_value,
open_order_id="123456"
)
freqtrade = FreqtradeBot(default_conf)
@@ -3290,7 +3327,7 @@ def test_get_real_amount_invalid(default_conf, trades_for_order, buy_order_fee,
assert freqtrade.get_real_amount(trade, buy_order_fee) == amount
def test_get_real_amount_open_trade(default_conf, mocker):
def test_get_real_amount_open_trade(default_conf, fee, mocker):
patch_RPCManager(mocker)
patch_exchange(mocker)
amount = 12345
@@ -3299,6 +3336,8 @@ def test_get_real_amount_open_trade(default_conf, mocker):
amount=amount,
exchange='binance',
open_rate=0.245441,
fee_open=fee.return_value,
fee_close=fee.return_value,
open_order_id="123456"
)
order = {
@@ -3552,3 +3591,32 @@ def test_process_i_am_alive(default_conf, mocker, caplog):
ftbot.process()
assert log_has_re(message, caplog)
@pytest.mark.usefixtures("init_persistence")
def test_sync_wallet_dry_run(mocker, default_conf, ticker, fee, limit_buy_order):
default_conf['dry_run'] = True
# Initialize to 2 times stake amount
default_conf['dry_run_wallet'] = 0.002
default_conf['max_open_trades'] = 2
patch_exchange(mocker)
mocker.patch.multiple(
'freqtrade.exchange.Exchange',
get_ticker=ticker,
buy=MagicMock(return_value={'id': limit_buy_order['id']}),
get_fee=fee,
)
bot = get_patched_freqtradebot(mocker, default_conf)
patch_get_signal(bot)
assert bot.wallets.get_free('BTC') == 0.002
bot.create_trades()
trades = Trade.query.all()
assert len(trades) == 2
bot.config['max_open_trades'] = 3
with pytest.raises(
DependencyException,
match=r"Available balance \(0 BTC\) is lower than stake amount \(0.001 BTC\)"):
bot.create_trades()

View File

@@ -71,6 +71,7 @@ def test_may_execute_sell_stoploss_on_exchange_multi(default_conf, ticker, fee,
)
mocker.patch("freqtrade.strategy.interface.IStrategy.should_sell", should_sell_mock)
wallets_mock = mocker.patch("freqtrade.wallets.Wallets.update", MagicMock())
mocker.patch("freqtrade.wallets.Wallets.get_free", MagicMock(return_value=1))
freqtrade = get_patched_freqtradebot(mocker, default_conf)
freqtrade.strategy.order_types['stoploss_on_exchange'] = True

View File

@@ -79,6 +79,7 @@ def test_main_keyboard_interrupt(mocker, default_conf, caplog) -> None:
mocker.patch('freqtrade.worker.Worker._worker', MagicMock(side_effect=KeyboardInterrupt))
patched_configuration_load_config_file(mocker, default_conf)
mocker.patch('freqtrade.freqtradebot.RPCManager', MagicMock())
mocker.patch('freqtrade.wallets.Wallets.update', MagicMock())
mocker.patch('freqtrade.freqtradebot.persistence.init', MagicMock())
args = ['trade', '-c', 'config.json.example']
@@ -98,6 +99,7 @@ def test_main_operational_exception(mocker, default_conf, caplog) -> None:
MagicMock(side_effect=OperationalException('Oh snap!'))
)
patched_configuration_load_config_file(mocker, default_conf)
mocker.patch('freqtrade.wallets.Wallets.update', MagicMock())
mocker.patch('freqtrade.freqtradebot.RPCManager', MagicMock())
mocker.patch('freqtrade.freqtradebot.persistence.init', MagicMock())
@@ -120,6 +122,7 @@ def test_main_reload_conf(mocker, default_conf, caplog) -> None:
OperationalException("Oh snap!")])
mocker.patch('freqtrade.worker.Worker._worker', worker_mock)
patched_configuration_load_config_file(mocker, default_conf)
mocker.patch('freqtrade.wallets.Wallets.update', MagicMock())
reconfigure_mock = mocker.patch('freqtrade.worker.Worker._reconfigure', MagicMock())
mocker.patch('freqtrade.freqtradebot.RPCManager', MagicMock())
@@ -143,6 +146,7 @@ def test_reconfigure(mocker, default_conf) -> None:
'freqtrade.worker.Worker._worker',
MagicMock(side_effect=OperationalException('Oh snap!'))
)
mocker.patch('freqtrade.wallets.Wallets.update', MagicMock())
patched_configuration_load_config_file(mocker, default_conf)
mocker.patch('freqtrade.freqtradebot.RPCManager', MagicMock())
mocker.patch('freqtrade.freqtradebot.persistence.init', MagicMock())

View File

@@ -136,12 +136,13 @@ def test_update_with_bittrex(limit_buy_order, limit_sell_order, fee, caplog):
id=2,
pair='ETH/BTC',
stake_amount=0.001,
open_rate=0.01,
amount=5,
fee_open=fee.return_value,
fee_close=fee.return_value,
exchange='bittrex',
)
assert trade.open_order_id is None
assert trade.open_rate is None
assert trade.close_profit is None
assert trade.close_date is None
@@ -173,6 +174,8 @@ def test_update_market_order(market_buy_order, market_sell_order, fee, caplog):
id=1,
pair='ETH/BTC',
stake_amount=0.001,
amount=5,
open_rate=0.01,
fee_open=fee.return_value,
fee_close=fee.return_value,
exchange='bittrex',
@@ -205,6 +208,8 @@ def test_calc_open_close_trade_price(limit_buy_order, limit_sell_order, fee):
trade = Trade(
pair='ETH/BTC',
stake_amount=0.001,
open_rate=0.01,
amount=5,
fee_open=fee.return_value,
fee_close=fee.return_value,
exchange='bittrex',
@@ -212,7 +217,7 @@ def test_calc_open_close_trade_price(limit_buy_order, limit_sell_order, fee):
trade.open_order_id = 'something'
trade.update(limit_buy_order)
assert trade.calc_open_trade_price() == 0.0010024999999225068
assert trade._calc_open_trade_price() == 0.0010024999999225068
trade.update(limit_sell_order)
assert trade.calc_close_trade_price() == 0.0010646656050132426
@@ -221,7 +226,7 @@ def test_calc_open_close_trade_price(limit_buy_order, limit_sell_order, fee):
assert trade.calc_profit() == 0.00006217
# Profit in percent
assert trade.calc_profit_percent() == 0.06201058
assert trade.calc_profit_ratio() == 0.06201058
@pytest.mark.usefixtures("init_persistence")
@@ -229,6 +234,8 @@ def test_calc_close_trade_price_exception(limit_buy_order, fee):
trade = Trade(
pair='ETH/BTC',
stake_amount=0.001,
open_rate=0.1,
amount=5,
fee_open=fee.return_value,
fee_close=fee.return_value,
exchange='bittrex',
@@ -244,13 +251,14 @@ def test_update_open_order(limit_buy_order):
trade = Trade(
pair='ETH/BTC',
stake_amount=1.00,
open_rate=0.01,
amount=5,
fee_open=0.1,
fee_close=0.1,
exchange='bittrex',
)
assert trade.open_order_id is None
assert trade.open_rate is None
assert trade.close_profit is None
assert trade.close_date is None
@@ -258,7 +266,6 @@ def test_update_open_order(limit_buy_order):
trade.update(limit_buy_order)
assert trade.open_order_id is None
assert trade.open_rate is None
assert trade.close_profit is None
assert trade.close_date is None
@@ -268,6 +275,8 @@ def test_update_invalid_order(limit_buy_order):
trade = Trade(
pair='ETH/BTC',
stake_amount=1.00,
amount=5,
open_rate=0.001,
fee_open=0.1,
fee_close=0.1,
exchange='bittrex',
@@ -282,6 +291,8 @@ def test_calc_open_trade_price(limit_buy_order, fee):
trade = Trade(
pair='ETH/BTC',
stake_amount=0.001,
amount=5,
open_rate=0.00001099,
fee_open=fee.return_value,
fee_close=fee.return_value,
exchange='bittrex',
@@ -290,10 +301,10 @@ def test_calc_open_trade_price(limit_buy_order, fee):
trade.update(limit_buy_order) # Buy @ 0.00001099
# Get the open rate price with the standard fee rate
assert trade.calc_open_trade_price() == 0.0010024999999225068
assert trade._calc_open_trade_price() == 0.0010024999999225068
trade.fee_open = 0.003
# Get the open rate price with a custom fee rate
assert trade.calc_open_trade_price(fee=0.003) == 0.001002999999922468
assert trade._calc_open_trade_price() == 0.001002999999922468
@pytest.mark.usefixtures("init_persistence")
@@ -301,6 +312,8 @@ def test_calc_close_trade_price(limit_buy_order, limit_sell_order, fee):
trade = Trade(
pair='ETH/BTC',
stake_amount=0.001,
amount=5,
open_rate=0.00001099,
fee_open=fee.return_value,
fee_close=fee.return_value,
exchange='bittrex',
@@ -324,6 +337,8 @@ def test_calc_profit(limit_buy_order, limit_sell_order, fee):
trade = Trade(
pair='ETH/BTC',
stake_amount=0.001,
amount=5,
open_rate=0.00001099,
fee_open=fee.return_value,
fee_close=fee.return_value,
exchange='bittrex',
@@ -352,10 +367,12 @@ def test_calc_profit(limit_buy_order, limit_sell_order, fee):
@pytest.mark.usefixtures("init_persistence")
def test_calc_profit_percent(limit_buy_order, limit_sell_order, fee):
def test_calc_profit_ratio(limit_buy_order, limit_sell_order, fee):
trade = Trade(
pair='ETH/BTC',
stake_amount=0.001,
amount=5,
open_rate=0.00001099,
fee_open=fee.return_value,
fee_close=fee.return_value,
exchange='bittrex',
@@ -364,17 +381,17 @@ def test_calc_profit_percent(limit_buy_order, limit_sell_order, fee):
trade.update(limit_buy_order) # Buy @ 0.00001099
# Get percent of profit with a custom rate (Higher than open rate)
assert trade.calc_profit_percent(rate=0.00001234) == 0.11723875
assert trade.calc_profit_ratio(rate=0.00001234) == 0.11723875
# Get percent of profit with a custom rate (Lower than open rate)
assert trade.calc_profit_percent(rate=0.00000123) == -0.88863828
assert trade.calc_profit_ratio(rate=0.00000123) == -0.88863828
# Test when we apply a Sell order. Sell higher than open rate @ 0.00001173
trade.update(limit_sell_order)
assert trade.calc_profit_percent() == 0.06201058
assert trade.calc_profit_ratio() == 0.06201058
# Test with a custom fee rate on the close trade
assert trade.calc_profit_percent(fee=0.003) == 0.06147824
assert trade.calc_profit_ratio(fee=0.003) == 0.06147824
@pytest.mark.usefixtures("init_persistence")
@@ -481,6 +498,7 @@ def test_migrate_old(mocker, default_conf, fee):
assert trade.max_rate == 0.0
assert trade.stop_loss == 0.0
assert trade.initial_stop_loss == 0.0
assert trade.open_trade_price == trade._calc_open_trade_price()
def test_migrate_new(mocker, default_conf, fee, caplog):
@@ -563,6 +581,7 @@ def test_migrate_new(mocker, default_conf, fee, caplog):
assert log_has("trying trades_bak1", caplog)
assert log_has("trying trades_bak2", caplog)
assert log_has("Running database migration - backup available as trades_bak2", caplog)
assert trade.open_trade_price == trade._calc_open_trade_price()
def test_migrate_mid_state(mocker, default_conf, fee, caplog):
@@ -622,6 +641,7 @@ def test_migrate_mid_state(mocker, default_conf, fee, caplog):
assert trade.max_rate == 0.0
assert trade.stop_loss == 0.0
assert trade.initial_stop_loss == 0.0
assert trade.open_trade_price == trade._calc_open_trade_price()
assert log_has("trying trades_bak0", caplog)
assert log_has("Running database migration - backup available as trades_bak0", caplog)
@@ -630,6 +650,7 @@ def test_adjust_stop_loss(fee):
trade = Trade(
pair='ETH/BTC',
stake_amount=0.001,
amount=5,
fee_open=fee.return_value,
fee_close=fee.return_value,
exchange='bittrex',
@@ -681,6 +702,7 @@ def test_adjust_min_max_rates(fee):
trade = Trade(
pair='ETH/BTC',
stake_amount=0.001,
amount=5,
fee_open=fee.return_value,
fee_close=fee.return_value,
exchange='bittrex',

View File

@@ -444,6 +444,9 @@ def test_create_datadir_failed(caplog):
def test_create_datadir(caplog, mocker):
# Ensure that caplog is empty before starting ...
# Should prevent random failures.
caplog.clear()
cud = mocker.patch("freqtrade.utils.create_userdata_dir", MagicMock())
csf = mocker.patch("freqtrade.utils.copy_sample_files", MagicMock())
args = [

View File

@@ -1,7 +1,8 @@
# pragma pylint: disable=missing-docstring
from tests.conftest import get_patched_freqtradebot
from unittest.mock import MagicMock
from tests.conftest import get_patched_freqtradebot
def test_sync_wallet_at_boot(mocker, default_conf):
default_conf['dry_run'] = False