Merge branch 'develop' into stoploss_restart
This commit is contained in:
@@ -11,7 +11,7 @@ import arrow
|
||||
import pytest
|
||||
from telegram import Chat, Message, Update
|
||||
|
||||
from freqtrade import constants
|
||||
from freqtrade import constants, persistence
|
||||
from freqtrade.data.converter import parse_ticker_dataframe
|
||||
from freqtrade.edge import Edge, PairInfo
|
||||
from freqtrade.exchange import Exchange
|
||||
@@ -97,7 +97,7 @@ def patch_freqtradebot(mocker, config) -> None:
|
||||
:return: None
|
||||
"""
|
||||
mocker.patch('freqtrade.freqtradebot.RPCManager', MagicMock())
|
||||
mocker.patch('freqtrade.freqtradebot.persistence.init', MagicMock())
|
||||
persistence.init(config['db_url'])
|
||||
patch_exchange(mocker, None)
|
||||
mocker.patch('freqtrade.freqtradebot.RPCManager._init', MagicMock())
|
||||
mocker.patch('freqtrade.freqtradebot.RPCManager.send_msg', MagicMock())
|
||||
@@ -113,6 +113,16 @@ def get_patched_worker(mocker, config) -> Worker:
|
||||
return Worker(args=None, config=config)
|
||||
|
||||
|
||||
def patch_get_signal(freqtrade: FreqtradeBot, value=(True, False)) -> None:
|
||||
"""
|
||||
:param mocker: mocker to patch IStrategy class
|
||||
:param value: which value IStrategy.get_signal() must return
|
||||
:return: None
|
||||
"""
|
||||
freqtrade.strategy.get_signal = lambda e, s, t: value
|
||||
freqtrade.exchange.refresh_latest_ohlcv = lambda p: None
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def patch_coinmarketcap(mocker) -> None:
|
||||
"""
|
||||
@@ -963,3 +973,39 @@ def edge_conf(default_conf):
|
||||
}
|
||||
|
||||
return conf
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def rpc_balance():
|
||||
return {
|
||||
'BTC': {
|
||||
'total': 12.0,
|
||||
'free': 12.0,
|
||||
'used': 0.0
|
||||
},
|
||||
'ETH': {
|
||||
'total': 0.0,
|
||||
'free': 0.0,
|
||||
'used': 0.0
|
||||
},
|
||||
'USDT': {
|
||||
'total': 10000.0,
|
||||
'free': 10000.0,
|
||||
'used': 0.0
|
||||
},
|
||||
'LTC': {
|
||||
'total': 10.0,
|
||||
'free': 10.0,
|
||||
'used': 0.0
|
||||
},
|
||||
'XRP': {
|
||||
'total': 1.0,
|
||||
'free': 1.0,
|
||||
'used': 0.0
|
||||
},
|
||||
'EUR': {
|
||||
'total': 10.0,
|
||||
'free': 10.0,
|
||||
'used': 0.0
|
||||
},
|
||||
}
|
||||
|
@@ -2,8 +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
|
||||
from freqtrade.optimize import validate_backtest_data, get_timeframe
|
||||
from freqtrade.data.history import load_pair_history, validate_backtest_data, get_timeframe
|
||||
from freqtrade.tests.conftest import log_has
|
||||
|
||||
|
||||
|
@@ -2,24 +2,27 @@
|
||||
|
||||
import json
|
||||
import os
|
||||
from pathlib import Path
|
||||
import uuid
|
||||
from pathlib import Path
|
||||
from shutil import copyfile
|
||||
from unittest.mock import MagicMock
|
||||
|
||||
import arrow
|
||||
from pandas import DataFrame
|
||||
import pytest
|
||||
from pandas import DataFrame
|
||||
|
||||
from freqtrade import OperationalException
|
||||
from freqtrade.arguments import TimeRange
|
||||
from freqtrade.data import history
|
||||
from freqtrade.data.history import (download_pair_history,
|
||||
load_cached_data_for_updating,
|
||||
load_tickerdata_file,
|
||||
make_testdata_path,
|
||||
load_tickerdata_file, make_testdata_path,
|
||||
trim_tickerlist)
|
||||
from freqtrade.exchange import timeframe_to_minutes
|
||||
from freqtrade.misc import file_dump_json
|
||||
from freqtrade.tests.conftest import get_patched_exchange, log_has
|
||||
from freqtrade.strategy.default_strategy import DefaultStrategy
|
||||
from freqtrade.tests.conftest import (get_patched_exchange, log_has,
|
||||
patch_exchange)
|
||||
|
||||
# Change this if modifying UNITTEST/BTC testdatafile
|
||||
_BTC_UNITTEST_LENGTH = 13681
|
||||
@@ -135,6 +138,31 @@ def test_load_data_with_new_pair_1min(ticker_history_list, mocker, caplog, defau
|
||||
_clean_test_file(file)
|
||||
|
||||
|
||||
def test_load_data_live(default_conf, mocker, caplog) -> None:
|
||||
refresh_mock = MagicMock()
|
||||
mocker.patch("freqtrade.exchange.Exchange.refresh_latest_ohlcv", refresh_mock)
|
||||
exchange = get_patched_exchange(mocker, default_conf)
|
||||
|
||||
history.load_data(datadir=None, ticker_interval='5m',
|
||||
pairs=['UNITTEST/BTC', 'UNITTEST2/BTC'],
|
||||
live=True,
|
||||
exchange=exchange)
|
||||
assert refresh_mock.call_count == 1
|
||||
assert len(refresh_mock.call_args_list[0][0][0]) == 2
|
||||
assert log_has('Live: Downloading data for all defined pairs ...', caplog.record_tuples)
|
||||
|
||||
|
||||
def test_load_data_live_noexchange(default_conf, mocker, caplog) -> None:
|
||||
|
||||
with pytest.raises(OperationalException,
|
||||
match=r'Exchange needs to be initialized when using live data.'):
|
||||
history.load_data(datadir=None, ticker_interval='5m',
|
||||
pairs=['UNITTEST/BTC', 'UNITTEST2/BTC'],
|
||||
exchange=None,
|
||||
live=True,
|
||||
)
|
||||
|
||||
|
||||
def test_testdata_path() -> None:
|
||||
assert str(Path('freqtrade') / 'tests' / 'testdata') in str(make_testdata_path(None))
|
||||
|
||||
@@ -321,7 +349,8 @@ def test_download_backtesting_data_exception(ticker_history, mocker, caplog, def
|
||||
_clean_test_file(file1_1)
|
||||
_clean_test_file(file1_5)
|
||||
assert log_has(
|
||||
'Failed to download history data for pair: "MEME/BTC", interval: 1m.',
|
||||
'Failed to download history data for pair: "MEME/BTC", interval: 1m. '
|
||||
'Error: File Error',
|
||||
caplog.record_tuples
|
||||
)
|
||||
|
||||
@@ -494,3 +523,62 @@ def test_file_dump_json_tofile() -> None:
|
||||
|
||||
# Remove the file
|
||||
_clean_test_file(file)
|
||||
|
||||
|
||||
def test_get_timeframe(default_conf, mocker) -> None:
|
||||
patch_exchange(mocker)
|
||||
strategy = DefaultStrategy(default_conf)
|
||||
|
||||
data = strategy.tickerdata_to_dataframe(
|
||||
history.load_data(
|
||||
datadir=None,
|
||||
ticker_interval='1m',
|
||||
pairs=['UNITTEST/BTC']
|
||||
)
|
||||
)
|
||||
min_date, max_date = history.get_timeframe(data)
|
||||
assert min_date.isoformat() == '2017-11-04T23:02:00+00:00'
|
||||
assert max_date.isoformat() == '2017-11-14T22:58:00+00:00'
|
||||
|
||||
|
||||
def test_validate_backtest_data_warn(default_conf, mocker, caplog) -> None:
|
||||
patch_exchange(mocker)
|
||||
strategy = DefaultStrategy(default_conf)
|
||||
|
||||
data = strategy.tickerdata_to_dataframe(
|
||||
history.load_data(
|
||||
datadir=None,
|
||||
ticker_interval='1m',
|
||||
pairs=['UNITTEST/BTC'],
|
||||
fill_up_missing=False
|
||||
)
|
||||
)
|
||||
min_date, max_date = history.get_timeframe(data)
|
||||
caplog.clear()
|
||||
assert history.validate_backtest_data(data, 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",
|
||||
caplog.record_tuples)
|
||||
|
||||
|
||||
def test_validate_backtest_data(default_conf, mocker, caplog) -> None:
|
||||
patch_exchange(mocker)
|
||||
strategy = DefaultStrategy(default_conf)
|
||||
|
||||
timerange = TimeRange('index', 'index', 200, 250)
|
||||
data = strategy.tickerdata_to_dataframe(
|
||||
history.load_data(
|
||||
datadir=None,
|
||||
ticker_interval='5m',
|
||||
pairs=['UNITTEST/BTC'],
|
||||
timerange=timerange
|
||||
)
|
||||
)
|
||||
|
||||
min_date, max_date = history.get_timeframe(data)
|
||||
caplog.clear()
|
||||
assert not history.validate_backtest_data(data, min_date, max_date,
|
||||
timeframe_to_minutes('5m'))
|
||||
assert len(caplog.record_tuples) == 0
|
||||
|
@@ -10,10 +10,11 @@ import numpy as np
|
||||
import pytest
|
||||
from pandas import DataFrame, to_datetime
|
||||
|
||||
from freqtrade import OperationalException
|
||||
from freqtrade.data.converter import parse_ticker_dataframe
|
||||
from freqtrade.edge import Edge, PairInfo
|
||||
from freqtrade.strategy.interface import SellType
|
||||
from freqtrade.tests.conftest import get_patched_freqtradebot
|
||||
from freqtrade.tests.conftest import get_patched_freqtradebot, log_has
|
||||
from freqtrade.tests.optimize import (BTContainer, BTrade,
|
||||
_build_backtest_dataframe,
|
||||
_get_frame_time_from_offset)
|
||||
@@ -30,7 +31,50 @@ ticker_start_time = arrow.get(2018, 10, 3)
|
||||
ticker_interval_in_minute = 60
|
||||
_ohlc = {'date': 0, 'buy': 1, 'open': 2, 'high': 3, 'low': 4, 'close': 5, 'sell': 6, 'volume': 7}
|
||||
|
||||
# Helpers for this test file
|
||||
|
||||
|
||||
def _validate_ohlc(buy_ohlc_sell_matrice):
|
||||
for index, ohlc in enumerate(buy_ohlc_sell_matrice):
|
||||
# if not high < open < low or not high < close < low
|
||||
if not ohlc[3] >= ohlc[2] >= ohlc[4] or not ohlc[3] >= ohlc[5] >= ohlc[4]:
|
||||
raise Exception('Line ' + str(index + 1) + ' of ohlc has invalid values!')
|
||||
return True
|
||||
|
||||
|
||||
def _build_dataframe(buy_ohlc_sell_matrice):
|
||||
_validate_ohlc(buy_ohlc_sell_matrice)
|
||||
tickers = []
|
||||
for ohlc in buy_ohlc_sell_matrice:
|
||||
ticker = {
|
||||
'date': ticker_start_time.shift(
|
||||
minutes=(
|
||||
ohlc[0] *
|
||||
ticker_interval_in_minute)).timestamp *
|
||||
1000,
|
||||
'buy': ohlc[1],
|
||||
'open': ohlc[2],
|
||||
'high': ohlc[3],
|
||||
'low': ohlc[4],
|
||||
'close': ohlc[5],
|
||||
'sell': ohlc[6]}
|
||||
tickers.append(ticker)
|
||||
|
||||
frame = DataFrame(tickers)
|
||||
frame['date'] = to_datetime(frame['date'],
|
||||
unit='ms',
|
||||
utc=True,
|
||||
infer_datetime_format=True)
|
||||
|
||||
return frame
|
||||
|
||||
|
||||
def _time_on_candle(number):
|
||||
return np.datetime64(ticker_start_time.shift(
|
||||
minutes=(number * ticker_interval_in_minute)).timestamp * 1000, 'ms')
|
||||
|
||||
|
||||
# End helper functions
|
||||
# Open trade should be removed from the end
|
||||
tc0 = BTContainer(data=[
|
||||
# D O H L C V B S
|
||||
@@ -203,46 +247,6 @@ def test_nonexisting_stake_amount(mocker, edge_conf):
|
||||
assert edge.stake_amount('N/O', 1, 2, 1) == 0.15
|
||||
|
||||
|
||||
def _validate_ohlc(buy_ohlc_sell_matrice):
|
||||
for index, ohlc in enumerate(buy_ohlc_sell_matrice):
|
||||
# if not high < open < low or not high < close < low
|
||||
if not ohlc[3] >= ohlc[2] >= ohlc[4] or not ohlc[3] >= ohlc[5] >= ohlc[4]:
|
||||
raise Exception('Line ' + str(index + 1) + ' of ohlc has invalid values!')
|
||||
return True
|
||||
|
||||
|
||||
def _build_dataframe(buy_ohlc_sell_matrice):
|
||||
_validate_ohlc(buy_ohlc_sell_matrice)
|
||||
tickers = []
|
||||
for ohlc in buy_ohlc_sell_matrice:
|
||||
ticker = {
|
||||
'date': ticker_start_time.shift(
|
||||
minutes=(
|
||||
ohlc[0] *
|
||||
ticker_interval_in_minute)).timestamp *
|
||||
1000,
|
||||
'buy': ohlc[1],
|
||||
'open': ohlc[2],
|
||||
'high': ohlc[3],
|
||||
'low': ohlc[4],
|
||||
'close': ohlc[5],
|
||||
'sell': ohlc[6]}
|
||||
tickers.append(ticker)
|
||||
|
||||
frame = DataFrame(tickers)
|
||||
frame['date'] = to_datetime(frame['date'],
|
||||
unit='ms',
|
||||
utc=True,
|
||||
infer_datetime_format=True)
|
||||
|
||||
return frame
|
||||
|
||||
|
||||
def _time_on_candle(number):
|
||||
return np.datetime64(ticker_start_time.shift(
|
||||
minutes=(number * ticker_interval_in_minute)).timestamp * 1000, 'ms')
|
||||
|
||||
|
||||
def test_edge_heartbeat_calculate(mocker, edge_conf):
|
||||
freqtrade = get_patched_freqtradebot(mocker, edge_conf)
|
||||
edge = Edge(edge_conf, freqtrade.exchange, freqtrade.strategy)
|
||||
@@ -298,6 +302,40 @@ def test_edge_process_downloaded_data(mocker, edge_conf):
|
||||
assert edge._last_updated <= arrow.utcnow().timestamp + 2
|
||||
|
||||
|
||||
def test_edge_process_no_data(mocker, edge_conf, caplog):
|
||||
edge_conf['datadir'] = None
|
||||
freqtrade = get_patched_freqtradebot(mocker, edge_conf)
|
||||
mocker.patch('freqtrade.exchange.Exchange.get_fee', MagicMock(return_value=0.001))
|
||||
mocker.patch('freqtrade.data.history.load_data', MagicMock(return_value={}))
|
||||
edge = Edge(edge_conf, freqtrade.exchange, freqtrade.strategy)
|
||||
|
||||
assert not edge.calculate()
|
||||
assert len(edge._cached_pairs) == 0
|
||||
assert log_has("No data found. Edge is stopped ...", caplog.record_tuples)
|
||||
assert edge._last_updated == 0
|
||||
|
||||
|
||||
def test_edge_process_no_trades(mocker, edge_conf, caplog):
|
||||
edge_conf['datadir'] = None
|
||||
freqtrade = get_patched_freqtradebot(mocker, edge_conf)
|
||||
mocker.patch('freqtrade.exchange.Exchange.get_fee', MagicMock(return_value=0.001))
|
||||
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=[]))
|
||||
edge = Edge(edge_conf, freqtrade.exchange, freqtrade.strategy)
|
||||
|
||||
assert not edge.calculate()
|
||||
assert len(edge._cached_pairs) == 0
|
||||
assert log_has("No trades found.", caplog.record_tuples)
|
||||
|
||||
|
||||
def test_edge_init_error(mocker, edge_conf,):
|
||||
edge_conf['stake_amount'] = 0.5
|
||||
mocker.patch('freqtrade.exchange.Exchange.get_fee', MagicMock(return_value=0.001))
|
||||
with pytest.raises(OperationalException, match='Edge works only with unlimited stake amount'):
|
||||
get_patched_freqtradebot(mocker, edge_conf)
|
||||
|
||||
|
||||
def test_process_expectancy(mocker, edge_conf):
|
||||
edge_conf['edge']['min_trade_number'] = 2
|
||||
freqtrade = get_patched_freqtradebot(mocker, edge_conf)
|
||||
@@ -360,3 +398,11 @@ def test_process_expectancy(mocker, edge_conf):
|
||||
assert round(final['TEST/BTC'].risk_reward_ratio, 10) == 306.5384615384
|
||||
assert round(final['TEST/BTC'].required_risk_reward, 10) == 2.0
|
||||
assert round(final['TEST/BTC'].expectancy, 10) == 101.5128205128
|
||||
|
||||
# Pop last item so no trade is profitable
|
||||
trades.pop()
|
||||
trades_df = DataFrame(trades)
|
||||
trades_df = edge._fill_calculable_fields(trades_df)
|
||||
final = edge._process_expectancy(trades_df)
|
||||
assert len(final) == 0
|
||||
assert isinstance(final, dict)
|
||||
|
@@ -1016,7 +1016,7 @@ def test_refresh_latest_ohlcv(mocker, default_conf, caplog) -> None:
|
||||
exchange.refresh_latest_ohlcv([('IOTA/ETH', '5m'), ('XRP/ETH', '5m')])
|
||||
|
||||
assert exchange._api_async.fetch_ohlcv.call_count == 2
|
||||
assert log_has(f"Using cached ohlcv data for {pairs[0][0]}, {pairs[0][1]} ...",
|
||||
assert log_has(f"Using cached ohlcv data for pair {pairs[0][0]}, interval {pairs[0][1]} ...",
|
||||
caplog.record_tuples)
|
||||
|
||||
|
||||
|
@@ -2,17 +2,17 @@
|
||||
import logging
|
||||
from unittest.mock import MagicMock
|
||||
|
||||
from pandas import DataFrame
|
||||
import pytest
|
||||
from pandas import DataFrame
|
||||
|
||||
|
||||
from freqtrade.optimize import get_timeframe
|
||||
from freqtrade.data.history import get_timeframe
|
||||
from freqtrade.optimize.backtesting import Backtesting
|
||||
from freqtrade.strategy.interface import SellType
|
||||
from freqtrade.tests.optimize import (BTrade, BTContainer, _build_backtest_dataframe,
|
||||
_get_frame_time_from_offset, tests_ticker_interval)
|
||||
from freqtrade.tests.conftest import patch_exchange
|
||||
|
||||
from freqtrade.tests.optimize import (BTContainer, BTrade,
|
||||
_build_backtest_dataframe,
|
||||
_get_frame_time_from_offset,
|
||||
tests_ticker_interval)
|
||||
|
||||
# Test 1 Minus 8% Close
|
||||
# Test with Stop-loss at 1%
|
||||
|
@@ -17,9 +17,9 @@ 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.optimize import get_timeframe
|
||||
from freqtrade.optimize.backtesting import (Backtesting, setup_configuration,
|
||||
start)
|
||||
from freqtrade.data.history import get_timeframe
|
||||
from freqtrade.optimize import setup_configuration, start_backtesting
|
||||
from freqtrade.optimize.backtesting import Backtesting
|
||||
from freqtrade.state import RunMode
|
||||
from freqtrade.strategy.default_strategy import DefaultStrategy
|
||||
from freqtrade.strategy.interface import SellType
|
||||
@@ -105,7 +105,7 @@ def simple_backtest(config, contour, num_results, mocker) -> None:
|
||||
|
||||
|
||||
def mocked_load_data(datadir, pairs=[], ticker_interval='0m', refresh_pairs=False,
|
||||
timerange=None, exchange=None):
|
||||
timerange=None, exchange=None, live=False):
|
||||
tickerdata = history.load_tickerdata_file(datadir, 'UNITTEST/BTC', '1m', timerange=timerange)
|
||||
pairdata = {'UNITTEST/BTC': parse_ticker_dataframe(tickerdata, '1m', fill_missing=True)}
|
||||
return pairdata
|
||||
@@ -178,7 +178,7 @@ def test_setup_configuration_without_arguments(mocker, default_conf, caplog) ->
|
||||
'backtesting'
|
||||
]
|
||||
|
||||
config = setup_configuration(get_args(args))
|
||||
config = setup_configuration(get_args(args), RunMode.BACKTEST)
|
||||
assert 'max_open_trades' in config
|
||||
assert 'stake_currency' in config
|
||||
assert 'stake_amount' in config
|
||||
@@ -228,7 +228,7 @@ def test_setup_bt_configuration_with_arguments(mocker, default_conf, caplog) ->
|
||||
'--export-filename', 'foo_bar.json'
|
||||
]
|
||||
|
||||
config = setup_configuration(get_args(args))
|
||||
config = setup_configuration(get_args(args), RunMode.BACKTEST)
|
||||
assert 'max_open_trades' in config
|
||||
assert 'stake_currency' in config
|
||||
assert 'stake_amount' in config
|
||||
@@ -290,7 +290,7 @@ def test_setup_configuration_unlimited_stake_amount(mocker, default_conf, caplog
|
||||
]
|
||||
|
||||
with pytest.raises(DependencyException, match=r'.*stake amount.*'):
|
||||
setup_configuration(get_args(args))
|
||||
setup_configuration(get_args(args), RunMode.BACKTEST)
|
||||
|
||||
|
||||
def test_start(mocker, fee, default_conf, caplog) -> None:
|
||||
@@ -307,7 +307,7 @@ def test_start(mocker, fee, default_conf, caplog) -> None:
|
||||
'backtesting'
|
||||
]
|
||||
args = get_args(args)
|
||||
start(args)
|
||||
start_backtesting(args)
|
||||
assert log_has(
|
||||
'Starting freqtrade in Backtesting mode',
|
||||
caplog.record_tuples
|
||||
@@ -472,7 +472,7 @@ def test_backtesting_start(default_conf, mocker, caplog) -> None:
|
||||
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.optimize.get_timeframe', get_timeframe)
|
||||
mocker.patch('freqtrade.data.history.get_timeframe', get_timeframe)
|
||||
mocker.patch('freqtrade.exchange.Exchange.refresh_latest_ohlcv', MagicMock())
|
||||
patch_exchange(mocker)
|
||||
mocker.patch.multiple(
|
||||
@@ -492,7 +492,6 @@ def test_backtesting_start(default_conf, mocker, caplog) -> None:
|
||||
backtesting.start()
|
||||
# check the logs, that will contain the backtest result
|
||||
exists = [
|
||||
'Using local backtesting data (using whitelist in given config) ...',
|
||||
'Using stake_currency: BTC ...',
|
||||
'Using stake_amount: 0.001 ...',
|
||||
'Backtesting with data from 2017-11-14T21:17:00+00:00 '
|
||||
@@ -507,7 +506,7 @@ def test_backtesting_start_no_data(default_conf, mocker, caplog) -> None:
|
||||
return Arrow(2017, 11, 14, 21, 17), Arrow(2017, 11, 14, 22, 59)
|
||||
|
||||
mocker.patch('freqtrade.data.history.load_data', MagicMock(return_value={}))
|
||||
mocker.patch('freqtrade.optimize.get_timeframe', get_timeframe)
|
||||
mocker.patch('freqtrade.data.history.get_timeframe', get_timeframe)
|
||||
mocker.patch('freqtrade.exchange.Exchange.refresh_latest_ohlcv', MagicMock())
|
||||
patch_exchange(mocker)
|
||||
mocker.patch.multiple(
|
||||
@@ -847,7 +846,7 @@ def test_backtest_start_live(default_conf, mocker, caplog):
|
||||
'--disable-max-market-positions'
|
||||
]
|
||||
args = get_args(args)
|
||||
start(args)
|
||||
start_backtesting(args)
|
||||
# check the logs, that will contain the backtest result
|
||||
exists = [
|
||||
'Parameter -i/--ticker-interval detected ... Using ticker_interval: 1m ...',
|
||||
@@ -857,7 +856,7 @@ def test_backtest_start_live(default_conf, mocker, caplog):
|
||||
'Using data folder: freqtrade/tests/testdata ...',
|
||||
'Using stake_currency: BTC ...',
|
||||
'Using stake_amount: 0.001 ...',
|
||||
'Downloading data for all pairs in whitelist ...',
|
||||
'Live: Downloading data for all defined pairs ...',
|
||||
'Backtesting with data from 2017-11-14T19:31:00+00:00 '
|
||||
'up to 2017-11-14T22:58:00+00:00 (0 days)..',
|
||||
'Parameter --enable-position-stacking detected ...'
|
||||
@@ -901,7 +900,7 @@ def test_backtest_start_multi_strat(default_conf, mocker, caplog):
|
||||
'TestStrategy',
|
||||
]
|
||||
args = get_args(args)
|
||||
start(args)
|
||||
start_backtesting(args)
|
||||
# 2 backtests, 4 tables
|
||||
assert backtestmock.call_count == 2
|
||||
assert gen_table_mock.call_count == 4
|
||||
@@ -916,7 +915,7 @@ def test_backtest_start_multi_strat(default_conf, mocker, caplog):
|
||||
'Using data folder: freqtrade/tests/testdata ...',
|
||||
'Using stake_currency: BTC ...',
|
||||
'Using stake_amount: 0.001 ...',
|
||||
'Downloading data for all pairs in whitelist ...',
|
||||
'Live: Downloading data for all defined pairs ...',
|
||||
'Backtesting with data from 2017-11-14T19:31:00+00:00 '
|
||||
'up to 2017-11-14T22:58:00+00:00 (0 days)..',
|
||||
'Parameter --enable-position-stacking detected ...',
|
||||
|
@@ -7,7 +7,8 @@ from unittest.mock import MagicMock
|
||||
|
||||
from freqtrade.arguments import Arguments
|
||||
from freqtrade.edge import PairInfo
|
||||
from freqtrade.optimize.edge_cli import EdgeCli, setup_configuration, start
|
||||
from freqtrade.optimize import start_edge, setup_configuration
|
||||
from freqtrade.optimize.edge_cli import EdgeCli
|
||||
from freqtrade.state import RunMode
|
||||
from freqtrade.tests.conftest import log_has, log_has_re, patch_exchange
|
||||
|
||||
@@ -27,8 +28,8 @@ def test_setup_configuration_without_arguments(mocker, default_conf, caplog) ->
|
||||
'edge'
|
||||
]
|
||||
|
||||
config = setup_configuration(get_args(args))
|
||||
assert config['runmode'] == RunMode.EDGECLI
|
||||
config = setup_configuration(get_args(args), RunMode.EDGE)
|
||||
assert config['runmode'] == RunMode.EDGE
|
||||
|
||||
assert 'max_open_trades' in config
|
||||
assert 'stake_currency' in config
|
||||
@@ -67,14 +68,14 @@ def test_setup_edge_configuration_with_arguments(mocker, edge_conf, caplog) -> N
|
||||
'--stoplosses=-0.01,-0.10,-0.001'
|
||||
]
|
||||
|
||||
config = setup_configuration(get_args(args))
|
||||
config = setup_configuration(get_args(args), RunMode.EDGE)
|
||||
assert 'max_open_trades' in config
|
||||
assert 'stake_currency' in config
|
||||
assert 'stake_amount' in config
|
||||
assert 'exchange' in config
|
||||
assert 'pair_whitelist' in config['exchange']
|
||||
assert 'datadir' in config
|
||||
assert config['runmode'] == RunMode.EDGECLI
|
||||
assert config['runmode'] == RunMode.EDGE
|
||||
assert log_has(
|
||||
'Using data folder: {} ...'.format(config['datadir']),
|
||||
caplog.record_tuples
|
||||
@@ -106,7 +107,7 @@ def test_start(mocker, fee, edge_conf, caplog) -> None:
|
||||
'edge'
|
||||
]
|
||||
args = get_args(args)
|
||||
start(args)
|
||||
start_edge(args)
|
||||
assert log_has(
|
||||
'Starting freqtrade in Edge mode',
|
||||
caplog.record_tuples
|
||||
|
@@ -3,6 +3,7 @@ import json
|
||||
import os
|
||||
from datetime import datetime
|
||||
from unittest.mock import MagicMock
|
||||
from filelock import Timeout
|
||||
|
||||
import pandas as pd
|
||||
import pytest
|
||||
@@ -11,8 +12,9 @@ from freqtrade import DependencyException
|
||||
from freqtrade.data.converter import parse_ticker_dataframe
|
||||
from freqtrade.data.history import load_tickerdata_file
|
||||
from freqtrade.optimize.default_hyperopt import DefaultHyperOpts
|
||||
from freqtrade.optimize.hyperopt import Hyperopt, setup_configuration, start
|
||||
from freqtrade.resolvers import HyperOptResolver
|
||||
from freqtrade.optimize.hyperopt import Hyperopt, HYPEROPT_LOCKFILE
|
||||
from freqtrade.optimize import setup_configuration, start_hyperopt
|
||||
from freqtrade.resolvers.hyperopt_resolver import HyperOptResolver
|
||||
from freqtrade.state import RunMode
|
||||
from freqtrade.tests.conftest import log_has, log_has_re, patch_exchange
|
||||
from freqtrade.tests.optimize.test_backtesting import get_args
|
||||
@@ -52,7 +54,7 @@ def test_setup_hyperopt_configuration_without_arguments(mocker, default_conf, ca
|
||||
'hyperopt'
|
||||
]
|
||||
|
||||
config = setup_configuration(get_args(args))
|
||||
config = setup_configuration(get_args(args), RunMode.HYPEROPT)
|
||||
assert 'max_open_trades' in config
|
||||
assert 'stake_currency' in config
|
||||
assert 'stake_amount' in config
|
||||
@@ -100,7 +102,7 @@ def test_setup_hyperopt_configuration_with_arguments(mocker, default_conf, caplo
|
||||
'--print-all'
|
||||
]
|
||||
|
||||
config = setup_configuration(get_args(args))
|
||||
config = setup_configuration(get_args(args), RunMode.HYPEROPT)
|
||||
assert 'max_open_trades' in config
|
||||
assert 'stake_currency' in config
|
||||
assert 'stake_amount' in config
|
||||
@@ -183,7 +185,7 @@ def test_start(mocker, default_conf, caplog) -> None:
|
||||
'--epochs', '5'
|
||||
]
|
||||
args = get_args(args)
|
||||
start(args)
|
||||
start_hyperopt(args)
|
||||
|
||||
import pprint
|
||||
pprint.pprint(caplog.record_tuples)
|
||||
@@ -214,7 +216,7 @@ def test_start_no_data(mocker, default_conf, caplog) -> None:
|
||||
'--epochs', '5'
|
||||
]
|
||||
args = get_args(args)
|
||||
start(args)
|
||||
start_hyperopt(args)
|
||||
|
||||
import pprint
|
||||
pprint.pprint(caplog.record_tuples)
|
||||
@@ -239,13 +241,35 @@ def test_start_failure(mocker, default_conf, caplog) -> None:
|
||||
]
|
||||
args = get_args(args)
|
||||
with pytest.raises(DependencyException):
|
||||
start(args)
|
||||
start_hyperopt(args)
|
||||
assert log_has(
|
||||
"Please don't use --strategy for hyperopt.",
|
||||
caplog.record_tuples
|
||||
)
|
||||
|
||||
|
||||
def test_start_filelock(mocker, default_conf, caplog) -> None:
|
||||
start_mock = MagicMock(side_effect=Timeout(HYPEROPT_LOCKFILE))
|
||||
mocker.patch(
|
||||
'freqtrade.configuration.Configuration._load_config_file',
|
||||
lambda *args, **kwargs: default_conf
|
||||
)
|
||||
mocker.patch('freqtrade.optimize.hyperopt.Hyperopt.start', start_mock)
|
||||
patch_exchange(mocker)
|
||||
|
||||
args = [
|
||||
'--config', 'config.json',
|
||||
'hyperopt',
|
||||
'--epochs', '5'
|
||||
]
|
||||
args = get_args(args)
|
||||
start_hyperopt(args)
|
||||
assert log_has(
|
||||
"Another running instance of freqtrade Hyperopt detected.",
|
||||
caplog.record_tuples
|
||||
)
|
||||
|
||||
|
||||
def test_loss_calculation_prefer_correct_trade_count(hyperopt) -> None:
|
||||
|
||||
correct = hyperopt.calculate_loss(1, hyperopt.target_trades, 20)
|
||||
@@ -348,20 +372,21 @@ def test_start_calls_optimizer(mocker, default_conf, caplog) -> None:
|
||||
)
|
||||
patch_exchange(mocker)
|
||||
|
||||
default_conf.update({'config': 'config.json.example'})
|
||||
default_conf.update({'epochs': 1})
|
||||
default_conf.update({'timerange': None})
|
||||
default_conf.update({'spaces': 'all'})
|
||||
default_conf.update({'hyperopt_jobs': 1})
|
||||
default_conf.update({'config': 'config.json.example',
|
||||
'epochs': 1,
|
||||
'timerange': None,
|
||||
'spaces': 'all',
|
||||
'hyperopt_jobs': 1, })
|
||||
|
||||
hyperopt = Hyperopt(default_conf)
|
||||
hyperopt.strategy.tickerdata_to_dataframe = MagicMock()
|
||||
|
||||
hyperopt.start()
|
||||
parallel.assert_called_once()
|
||||
|
||||
assert 'Best result:\nfoo result\nwith values:\n\n' in caplog.text
|
||||
assert log_has('Best result:\nfoo result\nwith values:\n', caplog.record_tuples)
|
||||
assert dumper.called
|
||||
# Should be called twice, once for tickerdata, once to save evaluations
|
||||
assert dumper.call_count == 2
|
||||
|
||||
|
||||
def test_format_results(hyperopt):
|
||||
|
@@ -1,66 +0,0 @@
|
||||
# pragma pylint: disable=missing-docstring, protected-access, C0103
|
||||
from freqtrade import optimize
|
||||
from freqtrade.arguments import TimeRange
|
||||
from freqtrade.data import history
|
||||
from freqtrade.exchange import timeframe_to_minutes
|
||||
from freqtrade.strategy.default_strategy import DefaultStrategy
|
||||
from freqtrade.tests.conftest import log_has, patch_exchange
|
||||
|
||||
|
||||
def test_get_timeframe(default_conf, mocker) -> None:
|
||||
patch_exchange(mocker)
|
||||
strategy = DefaultStrategy(default_conf)
|
||||
|
||||
data = strategy.tickerdata_to_dataframe(
|
||||
history.load_data(
|
||||
datadir=None,
|
||||
ticker_interval='1m',
|
||||
pairs=['UNITTEST/BTC']
|
||||
)
|
||||
)
|
||||
min_date, max_date = optimize.get_timeframe(data)
|
||||
assert min_date.isoformat() == '2017-11-04T23:02:00+00:00'
|
||||
assert max_date.isoformat() == '2017-11-14T22:58:00+00:00'
|
||||
|
||||
|
||||
def test_validate_backtest_data_warn(default_conf, mocker, caplog) -> None:
|
||||
patch_exchange(mocker)
|
||||
strategy = DefaultStrategy(default_conf)
|
||||
|
||||
data = strategy.tickerdata_to_dataframe(
|
||||
history.load_data(
|
||||
datadir=None,
|
||||
ticker_interval='1m',
|
||||
pairs=['UNITTEST/BTC'],
|
||||
fill_up_missing=False
|
||||
)
|
||||
)
|
||||
min_date, max_date = optimize.get_timeframe(data)
|
||||
caplog.clear()
|
||||
assert optimize.validate_backtest_data(data, 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",
|
||||
caplog.record_tuples)
|
||||
|
||||
|
||||
def test_validate_backtest_data(default_conf, mocker, caplog) -> None:
|
||||
patch_exchange(mocker)
|
||||
strategy = DefaultStrategy(default_conf)
|
||||
|
||||
timerange = TimeRange('index', 'index', 200, 250)
|
||||
data = strategy.tickerdata_to_dataframe(
|
||||
history.load_data(
|
||||
datadir=None,
|
||||
ticker_interval='5m',
|
||||
pairs=['UNITTEST/BTC'],
|
||||
timerange=timerange
|
||||
)
|
||||
)
|
||||
|
||||
min_date, max_date = optimize.get_timeframe(data)
|
||||
caplog.clear()
|
||||
assert not optimize.validate_backtest_data(data, min_date, max_date,
|
||||
timeframe_to_minutes('5m'))
|
||||
assert len(caplog.record_tuples) == 0
|
@@ -14,8 +14,7 @@ from freqtrade.persistence import Trade
|
||||
from freqtrade.rpc import RPC, RPCException
|
||||
from freqtrade.rpc.fiat_convert import CryptoToFiatConverter
|
||||
from freqtrade.state import State
|
||||
from freqtrade.tests.conftest import patch_exchange
|
||||
from freqtrade.tests.test_freqtradebot import patch_get_signal
|
||||
from freqtrade.tests.conftest import patch_exchange, patch_get_signal
|
||||
|
||||
|
||||
# Functions for recurrent object patching
|
||||
|
556
freqtrade/tests/rpc/test_rpc_apiserver.py
Normal file
556
freqtrade/tests/rpc/test_rpc_apiserver.py
Normal file
@@ -0,0 +1,556 @@
|
||||
"""
|
||||
Unit test file for rpc/api_server.py
|
||||
"""
|
||||
|
||||
from datetime import datetime
|
||||
from unittest.mock import ANY, MagicMock, PropertyMock
|
||||
|
||||
import pytest
|
||||
from flask import Flask
|
||||
from requests.auth import _basic_auth_str
|
||||
|
||||
from freqtrade.__init__ import __version__
|
||||
from freqtrade.persistence import Trade
|
||||
from freqtrade.rpc.api_server import BASE_URI, ApiServer
|
||||
from freqtrade.state import State
|
||||
from freqtrade.tests.conftest import (get_patched_freqtradebot, log_has,
|
||||
patch_get_signal)
|
||||
|
||||
|
||||
_TEST_USER = "FreqTrader"
|
||||
_TEST_PASS = "SuperSecurePassword1!"
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def botclient(default_conf, mocker):
|
||||
default_conf.update({"api_server": {"enabled": True,
|
||||
"listen_ip_address": "127.0.0.1",
|
||||
"listen_port": "8080",
|
||||
"username": _TEST_USER,
|
||||
"password": _TEST_PASS,
|
||||
}})
|
||||
|
||||
ftbot = get_patched_freqtradebot(mocker, default_conf)
|
||||
mocker.patch('freqtrade.rpc.api_server.ApiServer.run', MagicMock())
|
||||
apiserver = ApiServer(ftbot)
|
||||
yield ftbot, apiserver.app.test_client()
|
||||
# Cleanup ... ?
|
||||
|
||||
|
||||
def client_post(client, url, data={}):
|
||||
return client.post(url,
|
||||
content_type="application/json",
|
||||
data=data,
|
||||
headers={'Authorization': _basic_auth_str(_TEST_USER, _TEST_PASS)})
|
||||
|
||||
|
||||
def client_get(client, url):
|
||||
return client.get(url, headers={'Authorization': _basic_auth_str(_TEST_USER, _TEST_PASS)})
|
||||
|
||||
|
||||
def assert_response(response, expected_code=200):
|
||||
assert response.status_code == expected_code
|
||||
assert response.content_type == "application/json"
|
||||
|
||||
|
||||
def test_api_not_found(botclient):
|
||||
ftbot, client = botclient
|
||||
|
||||
rc = client_post(client, f"{BASE_URI}/invalid_url")
|
||||
assert_response(rc, 404)
|
||||
assert rc.json == {"status": "error",
|
||||
"reason": f"There's no API call for http://localhost{BASE_URI}/invalid_url.",
|
||||
"code": 404
|
||||
}
|
||||
|
||||
|
||||
def test_api_unauthorized(botclient):
|
||||
ftbot, client = botclient
|
||||
# Don't send user/pass information
|
||||
rc = client.get(f"{BASE_URI}/version")
|
||||
assert_response(rc, 401)
|
||||
assert rc.json == {'error': 'Unauthorized'}
|
||||
|
||||
# Change only username
|
||||
ftbot.config['api_server']['username'] = "Ftrader"
|
||||
rc = client_get(client, f"{BASE_URI}/version")
|
||||
assert_response(rc, 401)
|
||||
assert rc.json == {'error': 'Unauthorized'}
|
||||
|
||||
# Change only password
|
||||
ftbot.config['api_server']['username'] = _TEST_USER
|
||||
ftbot.config['api_server']['password'] = "WrongPassword"
|
||||
rc = client_get(client, f"{BASE_URI}/version")
|
||||
assert_response(rc, 401)
|
||||
assert rc.json == {'error': 'Unauthorized'}
|
||||
|
||||
ftbot.config['api_server']['username'] = "Ftrader"
|
||||
ftbot.config['api_server']['password'] = "WrongPassword"
|
||||
|
||||
rc = client_get(client, f"{BASE_URI}/version")
|
||||
assert_response(rc, 401)
|
||||
assert rc.json == {'error': 'Unauthorized'}
|
||||
|
||||
|
||||
def test_api_stop_workflow(botclient):
|
||||
ftbot, client = botclient
|
||||
assert ftbot.state == State.RUNNING
|
||||
rc = client_post(client, f"{BASE_URI}/stop")
|
||||
assert_response(rc)
|
||||
assert rc.json == {'status': 'stopping trader ...'}
|
||||
assert ftbot.state == State.STOPPED
|
||||
|
||||
# Stop bot again
|
||||
rc = client_post(client, f"{BASE_URI}/stop")
|
||||
assert_response(rc)
|
||||
assert rc.json == {'status': 'already stopped'}
|
||||
|
||||
# Start bot
|
||||
rc = client_post(client, f"{BASE_URI}/start")
|
||||
assert_response(rc)
|
||||
assert rc.json == {'status': 'starting trader ...'}
|
||||
assert ftbot.state == State.RUNNING
|
||||
|
||||
# Call start again
|
||||
rc = client_post(client, f"{BASE_URI}/start")
|
||||
assert_response(rc)
|
||||
assert rc.json == {'status': 'already running'}
|
||||
|
||||
|
||||
def test_api__init__(default_conf, mocker):
|
||||
"""
|
||||
Test __init__() method
|
||||
"""
|
||||
mocker.patch('freqtrade.rpc.telegram.Updater', MagicMock())
|
||||
mocker.patch('freqtrade.rpc.api_server.ApiServer.run', MagicMock())
|
||||
|
||||
apiserver = ApiServer(get_patched_freqtradebot(mocker, default_conf))
|
||||
assert apiserver._config == default_conf
|
||||
|
||||
|
||||
def test_api_run(default_conf, mocker, caplog):
|
||||
default_conf.update({"api_server": {"enabled": True,
|
||||
"listen_ip_address": "127.0.0.1",
|
||||
"listen_port": "8080"}})
|
||||
mocker.patch('freqtrade.rpc.telegram.Updater', MagicMock())
|
||||
mocker.patch('freqtrade.rpc.api_server.threading.Thread', MagicMock())
|
||||
|
||||
server_mock = MagicMock()
|
||||
mocker.patch('freqtrade.rpc.api_server.make_server', server_mock)
|
||||
|
||||
apiserver = ApiServer(get_patched_freqtradebot(mocker, default_conf))
|
||||
|
||||
assert apiserver._config == default_conf
|
||||
apiserver.run()
|
||||
assert server_mock.call_count == 1
|
||||
assert server_mock.call_args_list[0][0][0] == "127.0.0.1"
|
||||
assert server_mock.call_args_list[0][0][1] == "8080"
|
||||
assert isinstance(server_mock.call_args_list[0][0][2], Flask)
|
||||
assert hasattr(apiserver, "srv")
|
||||
|
||||
assert log_has("Starting HTTP Server at 127.0.0.1:8080", caplog.record_tuples)
|
||||
assert log_has("Starting Local Rest Server.", caplog.record_tuples)
|
||||
|
||||
# Test binding to public
|
||||
caplog.clear()
|
||||
server_mock.reset_mock()
|
||||
apiserver._config.update({"api_server": {"enabled": True,
|
||||
"listen_ip_address": "0.0.0.0",
|
||||
"listen_port": "8089",
|
||||
"password": "",
|
||||
}})
|
||||
apiserver.run()
|
||||
|
||||
assert server_mock.call_count == 1
|
||||
assert server_mock.call_args_list[0][0][0] == "0.0.0.0"
|
||||
assert server_mock.call_args_list[0][0][1] == "8089"
|
||||
assert isinstance(server_mock.call_args_list[0][0][2], Flask)
|
||||
assert log_has("Starting HTTP Server at 0.0.0.0:8089", caplog.record_tuples)
|
||||
assert log_has("Starting Local Rest Server.", caplog.record_tuples)
|
||||
assert log_has("SECURITY WARNING - Local Rest Server listening to external connections",
|
||||
caplog.record_tuples)
|
||||
assert log_has("SECURITY WARNING - This is insecure please set to your loopback,"
|
||||
"e.g 127.0.0.1 in config.json",
|
||||
caplog.record_tuples)
|
||||
assert log_has("SECURITY WARNING - No password for local REST Server defined. "
|
||||
"Please make sure that this is intentional!",
|
||||
caplog.record_tuples)
|
||||
|
||||
# Test crashing flask
|
||||
caplog.clear()
|
||||
mocker.patch('freqtrade.rpc.api_server.make_server', MagicMock(side_effect=Exception))
|
||||
apiserver.run()
|
||||
assert log_has("Api server failed to start.", caplog.record_tuples)
|
||||
|
||||
|
||||
def test_api_cleanup(default_conf, mocker, caplog):
|
||||
default_conf.update({"api_server": {"enabled": True,
|
||||
"listen_ip_address": "127.0.0.1",
|
||||
"listen_port": "8080"}})
|
||||
mocker.patch('freqtrade.rpc.telegram.Updater', MagicMock())
|
||||
mocker.patch('freqtrade.rpc.api_server.threading.Thread', MagicMock())
|
||||
mocker.patch('freqtrade.rpc.api_server.make_server', MagicMock())
|
||||
|
||||
apiserver = ApiServer(get_patched_freqtradebot(mocker, default_conf))
|
||||
apiserver.run()
|
||||
stop_mock = MagicMock()
|
||||
stop_mock.shutdown = MagicMock()
|
||||
apiserver.srv = stop_mock
|
||||
|
||||
apiserver.cleanup()
|
||||
assert stop_mock.shutdown.call_count == 1
|
||||
assert log_has("Stopping API Server", caplog.record_tuples)
|
||||
|
||||
|
||||
def test_api_reloadconf(botclient):
|
||||
ftbot, client = botclient
|
||||
|
||||
rc = client_post(client, f"{BASE_URI}/reload_conf")
|
||||
assert_response(rc)
|
||||
assert rc.json == {'status': 'reloading config ...'}
|
||||
assert ftbot.state == State.RELOAD_CONF
|
||||
|
||||
|
||||
def test_api_stopbuy(botclient):
|
||||
ftbot, client = botclient
|
||||
assert ftbot.config['max_open_trades'] != 0
|
||||
|
||||
rc = client_post(client, f"{BASE_URI}/stopbuy")
|
||||
assert_response(rc)
|
||||
assert rc.json == {'status': 'No more buy will occur from now. Run /reload_conf to reset.'}
|
||||
assert ftbot.config['max_open_trades'] == 0
|
||||
|
||||
|
||||
def test_api_balance(botclient, mocker, rpc_balance):
|
||||
ftbot, client = botclient
|
||||
|
||||
def mock_ticker(symbol, refresh):
|
||||
if symbol == 'BTC/USDT':
|
||||
return {
|
||||
'bid': 10000.00,
|
||||
'ask': 10000.00,
|
||||
'last': 10000.00,
|
||||
}
|
||||
elif symbol == 'XRP/BTC':
|
||||
return {
|
||||
'bid': 0.00001,
|
||||
'ask': 0.00001,
|
||||
'last': 0.00001,
|
||||
}
|
||||
return {
|
||||
'bid': 0.1,
|
||||
'ask': 0.1,
|
||||
'last': 0.1,
|
||||
}
|
||||
mocker.patch('freqtrade.exchange.Exchange.get_balances', return_value=rpc_balance)
|
||||
mocker.patch('freqtrade.exchange.Exchange.get_ticker', side_effect=mock_ticker)
|
||||
|
||||
rc = client_get(client, f"{BASE_URI}/balance")
|
||||
assert_response(rc)
|
||||
assert "currencies" in rc.json
|
||||
assert len(rc.json["currencies"]) == 5
|
||||
assert rc.json['currencies'][0] == {
|
||||
'currency': 'BTC',
|
||||
'available': 12.0,
|
||||
'balance': 12.0,
|
||||
'pending': 0.0,
|
||||
'est_btc': 12.0,
|
||||
}
|
||||
|
||||
|
||||
def test_api_count(botclient, mocker, ticker, fee, markets):
|
||||
ftbot, client = botclient
|
||||
patch_get_signal(ftbot, (True, False))
|
||||
mocker.patch.multiple(
|
||||
'freqtrade.exchange.Exchange',
|
||||
get_balances=MagicMock(return_value=ticker),
|
||||
get_ticker=ticker,
|
||||
get_fee=fee,
|
||||
markets=PropertyMock(return_value=markets)
|
||||
)
|
||||
rc = client_get(client, f"{BASE_URI}/count")
|
||||
assert_response(rc)
|
||||
|
||||
assert rc.json["current"] == 0
|
||||
assert rc.json["max"] == 1.0
|
||||
|
||||
# Create some test data
|
||||
ftbot.create_trade()
|
||||
rc = client_get(client, f"{BASE_URI}/count")
|
||||
assert_response(rc)
|
||||
assert rc.json["current"] == 1.0
|
||||
assert rc.json["max"] == 1.0
|
||||
|
||||
|
||||
def test_api_daily(botclient, mocker, ticker, fee, markets):
|
||||
ftbot, client = botclient
|
||||
patch_get_signal(ftbot, (True, False))
|
||||
mocker.patch.multiple(
|
||||
'freqtrade.exchange.Exchange',
|
||||
get_balances=MagicMock(return_value=ticker),
|
||||
get_ticker=ticker,
|
||||
get_fee=fee,
|
||||
markets=PropertyMock(return_value=markets)
|
||||
)
|
||||
rc = client_get(client, f"{BASE_URI}/daily")
|
||||
assert_response(rc)
|
||||
assert len(rc.json) == 7
|
||||
assert rc.json[0][0] == str(datetime.utcnow().date())
|
||||
|
||||
|
||||
def test_api_edge_disabled(botclient, mocker, ticker, fee, markets):
|
||||
ftbot, client = botclient
|
||||
patch_get_signal(ftbot, (True, False))
|
||||
mocker.patch.multiple(
|
||||
'freqtrade.exchange.Exchange',
|
||||
get_balances=MagicMock(return_value=ticker),
|
||||
get_ticker=ticker,
|
||||
get_fee=fee,
|
||||
markets=PropertyMock(return_value=markets)
|
||||
)
|
||||
rc = client_get(client, f"{BASE_URI}/edge")
|
||||
assert_response(rc, 502)
|
||||
assert rc.json == {"error": "Error querying _edge: Edge is not enabled."}
|
||||
|
||||
|
||||
def test_api_profit(botclient, mocker, ticker, fee, markets, limit_buy_order, limit_sell_order):
|
||||
ftbot, client = botclient
|
||||
patch_get_signal(ftbot, (True, False))
|
||||
mocker.patch.multiple(
|
||||
'freqtrade.exchange.Exchange',
|
||||
get_balances=MagicMock(return_value=ticker),
|
||||
get_ticker=ticker,
|
||||
get_fee=fee,
|
||||
markets=PropertyMock(return_value=markets)
|
||||
)
|
||||
|
||||
rc = client_get(client, f"{BASE_URI}/profit")
|
||||
assert_response(rc, 502)
|
||||
assert len(rc.json) == 1
|
||||
assert rc.json == {"error": "Error querying _profit: no closed trade"}
|
||||
|
||||
ftbot.create_trade()
|
||||
trade = Trade.query.first()
|
||||
|
||||
# Simulate fulfilled LIMIT_BUY order for trade
|
||||
trade.update(limit_buy_order)
|
||||
rc = client_get(client, f"{BASE_URI}/profit")
|
||||
assert_response(rc, 502)
|
||||
assert rc.json == {"error": "Error querying _profit: no closed trade"}
|
||||
|
||||
trade.update(limit_sell_order)
|
||||
|
||||
trade.close_date = datetime.utcnow()
|
||||
trade.is_open = False
|
||||
|
||||
rc = client_get(client, f"{BASE_URI}/profit")
|
||||
assert_response(rc)
|
||||
assert rc.json == {'avg_duration': '0:00:00',
|
||||
'best_pair': 'ETH/BTC',
|
||||
'best_rate': 6.2,
|
||||
'first_trade_date': 'just now',
|
||||
'latest_trade_date': 'just now',
|
||||
'profit_all_coin': 6.217e-05,
|
||||
'profit_all_fiat': 0,
|
||||
'profit_all_percent': 6.2,
|
||||
'profit_closed_coin': 6.217e-05,
|
||||
'profit_closed_fiat': 0,
|
||||
'profit_closed_percent': 6.2,
|
||||
'trade_count': 1
|
||||
}
|
||||
|
||||
|
||||
def test_api_performance(botclient, mocker, ticker, fee):
|
||||
ftbot, client = botclient
|
||||
patch_get_signal(ftbot, (True, False))
|
||||
|
||||
trade = Trade(
|
||||
pair='LTC/ETH',
|
||||
amount=1,
|
||||
exchange='binance',
|
||||
stake_amount=1,
|
||||
open_rate=0.245441,
|
||||
open_order_id="123456",
|
||||
is_open=False,
|
||||
fee_close=fee.return_value,
|
||||
fee_open=fee.return_value,
|
||||
close_rate=0.265441,
|
||||
|
||||
)
|
||||
trade.close_profit = trade.calc_profit_percent()
|
||||
Trade.session.add(trade)
|
||||
|
||||
trade = Trade(
|
||||
pair='XRP/ETH',
|
||||
amount=5,
|
||||
stake_amount=1,
|
||||
exchange='binance',
|
||||
open_rate=0.412,
|
||||
open_order_id="123456",
|
||||
is_open=False,
|
||||
fee_close=fee.return_value,
|
||||
fee_open=fee.return_value,
|
||||
close_rate=0.391
|
||||
)
|
||||
trade.close_profit = trade.calc_profit_percent()
|
||||
Trade.session.add(trade)
|
||||
Trade.session.flush()
|
||||
|
||||
rc = client_get(client, f"{BASE_URI}/performance")
|
||||
assert_response(rc)
|
||||
assert len(rc.json) == 2
|
||||
assert rc.json == [{'count': 1, 'pair': 'LTC/ETH', 'profit': 7.61},
|
||||
{'count': 1, 'pair': 'XRP/ETH', 'profit': -5.57}]
|
||||
|
||||
|
||||
def test_api_status(botclient, mocker, ticker, fee, markets):
|
||||
ftbot, client = botclient
|
||||
patch_get_signal(ftbot, (True, False))
|
||||
mocker.patch.multiple(
|
||||
'freqtrade.exchange.Exchange',
|
||||
get_balances=MagicMock(return_value=ticker),
|
||||
get_ticker=ticker,
|
||||
get_fee=fee,
|
||||
markets=PropertyMock(return_value=markets)
|
||||
)
|
||||
|
||||
rc = client_get(client, f"{BASE_URI}/status")
|
||||
assert_response(rc, 502)
|
||||
assert rc.json == {'error': 'Error querying _status: no active trade'}
|
||||
|
||||
ftbot.create_trade()
|
||||
rc = client_get(client, f"{BASE_URI}/status")
|
||||
assert_response(rc)
|
||||
assert len(rc.json) == 1
|
||||
assert rc.json == [{'amount': 90.99181074,
|
||||
'base_currency': 'BTC',
|
||||
'close_date': None,
|
||||
'close_date_hum': None,
|
||||
'close_profit': None,
|
||||
'close_rate': None,
|
||||
'current_profit': -0.59,
|
||||
'current_rate': 1.098e-05,
|
||||
'initial_stop_loss': 0.0,
|
||||
'initial_stop_loss_pct': None,
|
||||
'open_date': ANY,
|
||||
'open_date_hum': 'just now',
|
||||
'open_order': '(limit buy rem=0.00000000)',
|
||||
'open_rate': 1.099e-05,
|
||||
'pair': 'ETH/BTC',
|
||||
'stake_amount': 0.001,
|
||||
'stop_loss': 0.0,
|
||||
'stop_loss_pct': None,
|
||||
'trade_id': 1}]
|
||||
|
||||
|
||||
def test_api_version(botclient):
|
||||
ftbot, client = botclient
|
||||
|
||||
rc = client_get(client, f"{BASE_URI}/version")
|
||||
assert_response(rc)
|
||||
assert rc.json == {"version": __version__}
|
||||
|
||||
|
||||
def test_api_blacklist(botclient, mocker):
|
||||
ftbot, client = botclient
|
||||
|
||||
rc = client_get(client, f"{BASE_URI}/blacklist")
|
||||
assert_response(rc)
|
||||
assert rc.json == {"blacklist": ["DOGE/BTC", "HOT/BTC"],
|
||||
"length": 2,
|
||||
"method": "StaticPairList"}
|
||||
|
||||
# Add ETH/BTC to blacklist
|
||||
rc = client_post(client, f"{BASE_URI}/blacklist",
|
||||
data='{"blacklist": ["ETH/BTC"]}')
|
||||
assert_response(rc)
|
||||
assert rc.json == {"blacklist": ["DOGE/BTC", "HOT/BTC", "ETH/BTC"],
|
||||
"length": 3,
|
||||
"method": "StaticPairList"}
|
||||
|
||||
|
||||
def test_api_whitelist(botclient):
|
||||
ftbot, client = botclient
|
||||
|
||||
rc = client_get(client, f"{BASE_URI}/whitelist")
|
||||
assert_response(rc)
|
||||
assert rc.json == {"whitelist": ['ETH/BTC', 'LTC/BTC', 'XRP/BTC', 'NEO/BTC'],
|
||||
"length": 4,
|
||||
"method": "StaticPairList"}
|
||||
|
||||
|
||||
def test_api_forcebuy(botclient, mocker, fee):
|
||||
ftbot, client = botclient
|
||||
|
||||
rc = client_post(client, f"{BASE_URI}/forcebuy",
|
||||
data='{"pair": "ETH/BTC"}')
|
||||
assert_response(rc, 502)
|
||||
assert rc.json == {"error": "Error querying _forcebuy: Forcebuy not enabled."}
|
||||
|
||||
# enable forcebuy
|
||||
ftbot.config["forcebuy_enable"] = True
|
||||
|
||||
fbuy_mock = MagicMock(return_value=None)
|
||||
mocker.patch("freqtrade.rpc.RPC._rpc_forcebuy", fbuy_mock)
|
||||
rc = client_post(client, f"{BASE_URI}/forcebuy",
|
||||
data='{"pair": "ETH/BTC"}')
|
||||
assert_response(rc)
|
||||
assert rc.json == {"status": "Error buying pair ETH/BTC."}
|
||||
|
||||
# Test creating trae
|
||||
fbuy_mock = MagicMock(return_value=Trade(
|
||||
pair='ETH/ETH',
|
||||
amount=1,
|
||||
exchange='bittrex',
|
||||
stake_amount=1,
|
||||
open_rate=0.245441,
|
||||
open_order_id="123456",
|
||||
open_date=datetime.utcnow(),
|
||||
is_open=False,
|
||||
fee_close=fee.return_value,
|
||||
fee_open=fee.return_value,
|
||||
close_rate=0.265441,
|
||||
))
|
||||
mocker.patch("freqtrade.rpc.RPC._rpc_forcebuy", fbuy_mock)
|
||||
|
||||
rc = client_post(client, f"{BASE_URI}/forcebuy",
|
||||
data='{"pair": "ETH/BTC"}')
|
||||
assert_response(rc)
|
||||
assert rc.json == {'amount': 1,
|
||||
'close_date': None,
|
||||
'close_date_hum': None,
|
||||
'close_rate': 0.265441,
|
||||
'initial_stop_loss': None,
|
||||
'initial_stop_loss_pct': None,
|
||||
'open_date': ANY,
|
||||
'open_date_hum': 'just now',
|
||||
'open_rate': 0.245441,
|
||||
'pair': 'ETH/ETH',
|
||||
'stake_amount': 1,
|
||||
'stop_loss': None,
|
||||
'stop_loss_pct': None,
|
||||
'trade_id': None}
|
||||
|
||||
|
||||
def test_api_forcesell(botclient, mocker, ticker, fee, markets):
|
||||
ftbot, client = botclient
|
||||
mocker.patch.multiple(
|
||||
'freqtrade.exchange.Exchange',
|
||||
get_balances=MagicMock(return_value=ticker),
|
||||
get_ticker=ticker,
|
||||
get_fee=fee,
|
||||
markets=PropertyMock(return_value=markets)
|
||||
)
|
||||
patch_get_signal(ftbot, (True, False))
|
||||
|
||||
rc = client_post(client, f"{BASE_URI}/forcesell",
|
||||
data='{"tradeid": "1"}')
|
||||
assert_response(rc, 502)
|
||||
assert rc.json == {"error": "Error querying _forcesell: invalid argument"}
|
||||
|
||||
ftbot.create_trade()
|
||||
|
||||
rc = client_post(client, f"{BASE_URI}/forcesell",
|
||||
data='{"tradeid": "1"}')
|
||||
assert_response(rc)
|
||||
assert rc.json == {'result': 'Created sell order for trade 1.'}
|
@@ -135,3 +135,32 @@ def test_startupmessages_telegram_enabled(mocker, default_conf, caplog) -> None:
|
||||
rpc_manager.startup_messages(default_conf, freqtradebot.pairlists)
|
||||
assert telegram_mock.call_count == 3
|
||||
assert "Dry run is enabled." in telegram_mock.call_args_list[0][0][0]['status']
|
||||
|
||||
|
||||
def test_init_apiserver_disabled(mocker, default_conf, caplog) -> None:
|
||||
caplog.set_level(logging.DEBUG)
|
||||
run_mock = MagicMock()
|
||||
mocker.patch('freqtrade.rpc.api_server.ApiServer.run', run_mock)
|
||||
default_conf['telegram']['enabled'] = False
|
||||
rpc_manager = RPCManager(get_patched_freqtradebot(mocker, default_conf))
|
||||
|
||||
assert not log_has('Enabling rpc.api_server', caplog.record_tuples)
|
||||
assert rpc_manager.registered_modules == []
|
||||
assert run_mock.call_count == 0
|
||||
|
||||
|
||||
def test_init_apiserver_enabled(mocker, default_conf, caplog) -> None:
|
||||
caplog.set_level(logging.DEBUG)
|
||||
run_mock = MagicMock()
|
||||
mocker.patch('freqtrade.rpc.api_server.ApiServer.run', run_mock)
|
||||
|
||||
default_conf["telegram"]["enabled"] = False
|
||||
default_conf["api_server"] = {"enabled": True,
|
||||
"listen_ip_address": "127.0.0.1",
|
||||
"listen_port": "8080"}
|
||||
rpc_manager = RPCManager(get_patched_freqtradebot(mocker, default_conf))
|
||||
|
||||
assert log_has('Enabling rpc.api_server', caplog.record_tuples)
|
||||
assert len(rpc_manager.registered_modules) == 1
|
||||
assert 'apiserver' in [mod.name for mod in rpc_manager.registered_modules]
|
||||
assert run_mock.call_count == 1
|
||||
|
@@ -22,8 +22,7 @@ from freqtrade.rpc.telegram import Telegram, authorized_only
|
||||
from freqtrade.state import State
|
||||
from freqtrade.strategy.interface import SellType
|
||||
from freqtrade.tests.conftest import (get_patched_freqtradebot, log_has,
|
||||
patch_exchange)
|
||||
from freqtrade.tests.test_freqtradebot import patch_get_signal
|
||||
patch_exchange, patch_get_signal)
|
||||
|
||||
|
||||
class DummyCls(Telegram):
|
||||
@@ -496,39 +495,7 @@ def test_profit_handle(default_conf, update, ticker, ticker_sell_up, fee,
|
||||
assert '*Best Performing:* `ETH/BTC: 6.20%`' in msg_mock.call_args_list[-1][0][0]
|
||||
|
||||
|
||||
def test_telegram_balance_handle(default_conf, update, mocker) -> None:
|
||||
mock_balance = {
|
||||
'BTC': {
|
||||
'total': 12.0,
|
||||
'free': 12.0,
|
||||
'used': 0.0
|
||||
},
|
||||
'ETH': {
|
||||
'total': 0.0,
|
||||
'free': 0.0,
|
||||
'used': 0.0
|
||||
},
|
||||
'USDT': {
|
||||
'total': 10000.0,
|
||||
'free': 10000.0,
|
||||
'used': 0.0
|
||||
},
|
||||
'LTC': {
|
||||
'total': 10.0,
|
||||
'free': 10.0,
|
||||
'used': 0.0
|
||||
},
|
||||
'XRP': {
|
||||
'total': 1.0,
|
||||
'free': 1.0,
|
||||
'used': 0.0
|
||||
},
|
||||
'EUR': {
|
||||
'total': 10.0,
|
||||
'free': 10.0,
|
||||
'used': 0.0
|
||||
}
|
||||
}
|
||||
def test_telegram_balance_handle(default_conf, update, mocker, rpc_balance) -> None:
|
||||
|
||||
def mock_ticker(symbol, refresh):
|
||||
if symbol == 'BTC/USDT':
|
||||
@@ -549,7 +516,7 @@ def test_telegram_balance_handle(default_conf, update, mocker) -> None:
|
||||
'last': 0.1,
|
||||
}
|
||||
|
||||
mocker.patch('freqtrade.exchange.Exchange.get_balances', return_value=mock_balance)
|
||||
mocker.patch('freqtrade.exchange.Exchange.get_balances', return_value=rpc_balance)
|
||||
mocker.patch('freqtrade.exchange.Exchange.get_ticker', side_effect=mock_ticker)
|
||||
|
||||
msg_mock = MagicMock()
|
||||
|
@@ -1,5 +1,4 @@
|
||||
# pragma pylint: disable=missing-docstring, C0103
|
||||
|
||||
import argparse
|
||||
|
||||
import pytest
|
||||
@@ -185,3 +184,22 @@ def test_testdata_dl_options() -> None:
|
||||
assert args.export == 'export/folder'
|
||||
assert args.days == 30
|
||||
assert args.exchange == 'binance'
|
||||
|
||||
|
||||
def test_check_int_positive() -> None:
|
||||
|
||||
assert Arguments.check_int_positive("3") == 3
|
||||
assert Arguments.check_int_positive("1") == 1
|
||||
assert Arguments.check_int_positive("100") == 100
|
||||
|
||||
with pytest.raises(argparse.ArgumentTypeError):
|
||||
Arguments.check_int_positive("-2")
|
||||
|
||||
with pytest.raises(argparse.ArgumentTypeError):
|
||||
Arguments.check_int_positive("0")
|
||||
|
||||
with pytest.raises(argparse.ArgumentTypeError):
|
||||
Arguments.check_int_positive("3.5")
|
||||
|
||||
with pytest.raises(argparse.ArgumentTypeError):
|
||||
Arguments.check_int_positive("DeadBeef")
|
||||
|
@@ -11,8 +11,8 @@ import arrow
|
||||
import pytest
|
||||
import requests
|
||||
|
||||
from freqtrade import (DependencyException, OperationalException,
|
||||
TemporaryError, InvalidOrderException, constants)
|
||||
from freqtrade import (DependencyException, InvalidOrderException,
|
||||
OperationalException, TemporaryError, constants)
|
||||
from freqtrade.data.dataprovider import DataProvider
|
||||
from freqtrade.freqtradebot import FreqtradeBot
|
||||
from freqtrade.persistence import Trade
|
||||
@@ -20,7 +20,8 @@ from freqtrade.rpc import RPCMessageType
|
||||
from freqtrade.state import State
|
||||
from freqtrade.strategy.interface import SellCheckTuple, SellType
|
||||
from freqtrade.tests.conftest import (log_has, log_has_re, patch_edge,
|
||||
patch_exchange, patch_wallet)
|
||||
patch_exchange, patch_get_signal,
|
||||
patch_wallet)
|
||||
from freqtrade.worker import Worker
|
||||
|
||||
|
||||
@@ -59,16 +60,6 @@ def get_patched_worker(mocker, config) -> Worker:
|
||||
return Worker(args=None, config=config)
|
||||
|
||||
|
||||
def patch_get_signal(freqtrade: FreqtradeBot, value=(True, False)) -> None:
|
||||
"""
|
||||
:param mocker: mocker to patch IStrategy class
|
||||
:param value: which value IStrategy.get_signal() must return
|
||||
:return: None
|
||||
"""
|
||||
freqtrade.strategy.get_signal = lambda e, s, t: value
|
||||
freqtrade.exchange.refresh_latest_ohlcv = lambda p: None
|
||||
|
||||
|
||||
def patch_RPCManager(mocker) -> MagicMock:
|
||||
"""
|
||||
This function mock RPC manager to avoid repeating this code in almost every tests
|
||||
|
@@ -19,8 +19,10 @@ def test_parse_args_backtesting(mocker) -> None:
|
||||
Test that main() can start backtesting and also ensure we can pass some specific arguments
|
||||
further argument parsing is done in test_arguments.py
|
||||
"""
|
||||
backtesting_mock = mocker.patch('freqtrade.optimize.backtesting.start', MagicMock())
|
||||
main(['backtesting'])
|
||||
backtesting_mock = mocker.patch('freqtrade.optimize.start_backtesting', MagicMock())
|
||||
# it's sys.exit(0) at the end of backtesting
|
||||
with pytest.raises(SystemExit):
|
||||
main(['backtesting'])
|
||||
assert backtesting_mock.call_count == 1
|
||||
call_args = backtesting_mock.call_args[0][0]
|
||||
assert call_args.config == ['config.json']
|
||||
@@ -32,8 +34,10 @@ def test_parse_args_backtesting(mocker) -> None:
|
||||
|
||||
|
||||
def test_main_start_hyperopt(mocker) -> None:
|
||||
hyperopt_mock = mocker.patch('freqtrade.optimize.hyperopt.start', MagicMock())
|
||||
main(['hyperopt'])
|
||||
hyperopt_mock = mocker.patch('freqtrade.optimize.start_hyperopt', MagicMock())
|
||||
# it's sys.exit(0) at the end of hyperopt
|
||||
with pytest.raises(SystemExit):
|
||||
main(['hyperopt'])
|
||||
assert hyperopt_mock.call_count == 1
|
||||
call_args = hyperopt_mock.call_args[0][0]
|
||||
assert call_args.config == ['config.json']
|
||||
|
@@ -6,7 +6,7 @@ from unittest.mock import MagicMock
|
||||
from freqtrade.data.converter import parse_ticker_dataframe
|
||||
from freqtrade.misc import (common_datearray, datesarray_to_datetimearray,
|
||||
file_dump_json, file_load_json, format_ms_time, shorten_date)
|
||||
from freqtrade.data.history import load_tickerdata_file, make_testdata_path
|
||||
from freqtrade.data.history import load_tickerdata_file, pair_data_filename
|
||||
from freqtrade.strategy.default_strategy import DefaultStrategy
|
||||
|
||||
|
||||
@@ -60,13 +60,13 @@ def test_file_dump_json(mocker) -> None:
|
||||
def test_file_load_json(mocker) -> None:
|
||||
|
||||
# 7m .json does not exist
|
||||
ret = file_load_json(make_testdata_path(None).joinpath('UNITTEST_BTC-7m.json'))
|
||||
ret = file_load_json(pair_data_filename(None, 'UNITTEST/BTC', '7m'))
|
||||
assert not ret
|
||||
# 1m json exists (but no .gz exists)
|
||||
ret = file_load_json(make_testdata_path(None).joinpath('UNITTEST_BTC-1m.json'))
|
||||
ret = file_load_json(pair_data_filename(None, 'UNITTEST/BTC', '1m'))
|
||||
assert ret
|
||||
# 8 .json is empty and will fail if it's loaded. .json.gz is a copy of 1.json
|
||||
ret = file_load_json(make_testdata_path(None).joinpath('UNITTEST_BTC-8m.json'))
|
||||
ret = file_load_json(pair_data_filename(None, 'UNITTEST/BTC', '8m'))
|
||||
assert ret
|
||||
|
||||
|
||||
|
@@ -13,12 +13,12 @@ from freqtrade.tests.conftest import log_has
|
||||
|
||||
@pytest.fixture(scope='function')
|
||||
def init_persistence(default_conf):
|
||||
init(default_conf)
|
||||
init(default_conf['db_url'], default_conf['dry_run'])
|
||||
|
||||
|
||||
def test_init_create_session(default_conf):
|
||||
# Check if init create a session
|
||||
init(default_conf)
|
||||
init(default_conf['db_url'], default_conf['dry_run'])
|
||||
assert hasattr(Trade, 'session')
|
||||
assert 'Session' in type(Trade.session).__name__
|
||||
|
||||
@@ -28,7 +28,7 @@ def test_init_custom_db_url(default_conf, mocker):
|
||||
default_conf.update({'db_url': 'sqlite:///tmp/freqtrade2_test.sqlite'})
|
||||
create_engine_mock = mocker.patch('freqtrade.persistence.create_engine', MagicMock())
|
||||
|
||||
init(default_conf)
|
||||
init(default_conf['db_url'], default_conf['dry_run'])
|
||||
assert create_engine_mock.call_count == 1
|
||||
assert create_engine_mock.mock_calls[0][1][0] == 'sqlite:///tmp/freqtrade2_test.sqlite'
|
||||
|
||||
@@ -37,7 +37,7 @@ def test_init_invalid_db_url(default_conf):
|
||||
# Update path to a value other than default, but still in-memory
|
||||
default_conf.update({'db_url': 'unknown:///some.url'})
|
||||
with pytest.raises(OperationalException, match=r'.*no valid database URL*'):
|
||||
init(default_conf)
|
||||
init(default_conf['db_url'], default_conf['dry_run'])
|
||||
|
||||
|
||||
def test_init_prod_db(default_conf, mocker):
|
||||
@@ -46,7 +46,7 @@ def test_init_prod_db(default_conf, mocker):
|
||||
|
||||
create_engine_mock = mocker.patch('freqtrade.persistence.create_engine', MagicMock())
|
||||
|
||||
init(default_conf)
|
||||
init(default_conf['db_url'], default_conf['dry_run'])
|
||||
assert create_engine_mock.call_count == 1
|
||||
assert create_engine_mock.mock_calls[0][1][0] == 'sqlite:///tradesv3.sqlite'
|
||||
|
||||
@@ -57,7 +57,7 @@ def test_init_dryrun_db(default_conf, mocker):
|
||||
|
||||
create_engine_mock = mocker.patch('freqtrade.persistence.create_engine', MagicMock())
|
||||
|
||||
init(default_conf)
|
||||
init(default_conf['db_url'], default_conf['dry_run'])
|
||||
assert create_engine_mock.call_count == 1
|
||||
assert create_engine_mock.mock_calls[0][1][0] == 'sqlite://'
|
||||
|
||||
@@ -336,8 +336,8 @@ def test_calc_profit_percent(limit_buy_order, limit_sell_order, fee):
|
||||
assert trade.calc_profit_percent(fee=0.003) == 0.06147824
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("init_persistence")
|
||||
def test_clean_dry_run_db(default_conf, fee):
|
||||
init(default_conf)
|
||||
|
||||
# Simulate dry_run entries
|
||||
trade = Trade(
|
||||
@@ -424,7 +424,7 @@ def test_migrate_old(mocker, default_conf, fee):
|
||||
engine.execute(create_table_old)
|
||||
engine.execute(insert_table_old)
|
||||
# Run init to test migration
|
||||
init(default_conf)
|
||||
init(default_conf['db_url'], default_conf['dry_run'])
|
||||
|
||||
assert len(Trade.query.filter(Trade.id == 1).all()) == 1
|
||||
trade = Trade.query.filter(Trade.id == 1).first()
|
||||
@@ -497,7 +497,7 @@ def test_migrate_new(mocker, default_conf, fee, caplog):
|
||||
|
||||
engine.execute("create table trades_bak1 as select * from trades")
|
||||
# Run init to test migration
|
||||
init(default_conf)
|
||||
init(default_conf['db_url'], default_conf['dry_run'])
|
||||
|
||||
assert len(Trade.query.filter(Trade.id == 1).all()) == 1
|
||||
trade = Trade.query.filter(Trade.id == 1).first()
|
||||
@@ -566,7 +566,7 @@ def test_migrate_mid_state(mocker, default_conf, fee, caplog):
|
||||
engine.execute(insert_table_old)
|
||||
|
||||
# Run init to test migration
|
||||
init(default_conf)
|
||||
init(default_conf['db_url'], default_conf['dry_run'])
|
||||
|
||||
assert len(Trade.query.filter(Trade.id == 1).all()) == 1
|
||||
trade = Trade.query.filter(Trade.id == 1).first()
|
||||
@@ -668,8 +668,8 @@ def test_adjust_min_max_rates(fee):
|
||||
assert trade.min_rate == 0.96
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("init_persistence")
|
||||
def test_get_open(default_conf, fee):
|
||||
init(default_conf)
|
||||
|
||||
# Simulate dry_run entries
|
||||
trade = Trade(
|
||||
@@ -713,8 +713,8 @@ def test_get_open(default_conf, fee):
|
||||
assert len(Trade.get_open_trades()) == 2
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("init_persistence")
|
||||
def test_to_json(default_conf, fee):
|
||||
init(default_conf)
|
||||
|
||||
# Simulate dry_run entries
|
||||
trade = Trade(
|
||||
|
Reference in New Issue
Block a user