Merge with develop
This commit is contained in:
@@ -9,7 +9,6 @@ from unittest.mock import MagicMock
|
||||
import arrow
|
||||
import pytest
|
||||
from jsonschema import validate
|
||||
from sqlalchemy import create_engine
|
||||
from telegram import Chat, Message, Update
|
||||
|
||||
from freqtrade.analyze import Analyze
|
||||
@@ -45,7 +44,7 @@ def get_patched_freqtradebot(mocker, config) -> FreqtradeBot:
|
||||
mocker.patch('freqtrade.freqtradebot.RPCManager.send_msg', MagicMock())
|
||||
mocker.patch('freqtrade.freqtradebot.Analyze.get_signal', MagicMock())
|
||||
|
||||
return FreqtradeBot(config, create_engine('sqlite://'))
|
||||
return FreqtradeBot(config)
|
||||
|
||||
|
||||
def patch_coinmarketcap(mocker, value: Optional[Dict[str, float]] = None) -> None:
|
||||
@@ -108,7 +107,8 @@ def default_conf():
|
||||
"chat_id": "0"
|
||||
},
|
||||
"initial_state": "running",
|
||||
"loglevel": logging.DEBUG
|
||||
"db_url": "sqlite://",
|
||||
"loglevel": logging.DEBUG,
|
||||
}
|
||||
validate(configuration, constants.CONF_SCHEMA)
|
||||
return configuration
|
||||
|
@@ -310,9 +310,19 @@ def test_get_ticker(default_conf, mocker):
|
||||
# if not fetching a new result we should get the cached ticker
|
||||
ticker = get_ticker(pair='ETH/BTC')
|
||||
|
||||
assert api_mock.fetch_ticker.call_count == 1
|
||||
assert ticker['bid'] == 0.5
|
||||
assert ticker['ask'] == 1
|
||||
|
||||
assert 'ETH/BTC' in exchange._CACHED_TICKER
|
||||
assert exchange._CACHED_TICKER['ETH/BTC']['bid'] == 0.5
|
||||
assert exchange._CACHED_TICKER['ETH/BTC']['ask'] == 1
|
||||
|
||||
# Test caching
|
||||
api_mock.fetch_ticker = MagicMock()
|
||||
get_ticker(pair='ETH/BTC', refresh=False)
|
||||
assert api_mock.fetch_ticker.call_count == 0
|
||||
|
||||
with pytest.raises(TemporaryError): # test retrier
|
||||
api_mock.fetch_ticker = MagicMock(side_effect=ccxt.NetworkError)
|
||||
mocker.patch('freqtrade.exchange._API', api_mock)
|
||||
@@ -323,6 +333,10 @@ def test_get_ticker(default_conf, mocker):
|
||||
mocker.patch('freqtrade.exchange._API', api_mock)
|
||||
get_ticker(pair='ETH/BTC', refresh=True)
|
||||
|
||||
api_mock.fetch_ticker = MagicMock(return_value={})
|
||||
mocker.patch('freqtrade.exchange._API', api_mock)
|
||||
get_ticker(pair='ETH/BTC', refresh=True)
|
||||
|
||||
|
||||
def make_fetch_ohlcv_mock(data):
|
||||
def fetch_ohlcv_mock(pair, timeframe, since):
|
||||
|
@@ -14,7 +14,7 @@ from arrow import Arrow
|
||||
|
||||
from freqtrade import optimize, constants, DependencyException
|
||||
from freqtrade.analyze import Analyze
|
||||
from freqtrade.arguments import Arguments
|
||||
from freqtrade.arguments import Arguments, TimeRange
|
||||
from freqtrade.optimize.backtesting import Backtesting, start, setup_configuration
|
||||
from freqtrade.tests.conftest import log_has
|
||||
|
||||
@@ -31,7 +31,7 @@ def trim_dictlist(dict_list, num):
|
||||
|
||||
|
||||
def load_data_test(what):
|
||||
timerange = ((None, 'line'), None, -100)
|
||||
timerange = TimeRange(None, 'line', 0, -101)
|
||||
data = optimize.load_data(None, ticker_interval='1m',
|
||||
pairs=['UNITTEST/BTC'], timerange=timerange)
|
||||
pair = data['UNITTEST/BTC']
|
||||
@@ -111,14 +111,14 @@ def mocked_load_data(datadir, pairs=[], ticker_interval='0m', refresh_pairs=Fals
|
||||
# use for mock freqtrade.exchange.get_ticker_history'
|
||||
def _load_pair_as_ticks(pair, tickfreq):
|
||||
ticks = optimize.load_data(None, ticker_interval=tickfreq, pairs=[pair])
|
||||
ticks = trim_dictlist(ticks, -200)
|
||||
ticks = trim_dictlist(ticks, -201)
|
||||
return ticks[pair]
|
||||
|
||||
|
||||
# FIX: fixturize this?
|
||||
def _make_backtest_conf(mocker, conf=None, pair='UNITTEST/BTC', record=None):
|
||||
data = optimize.load_data(None, ticker_interval='8m', pairs=[pair])
|
||||
data = trim_dictlist(data, -200)
|
||||
data = trim_dictlist(data, -201)
|
||||
mocker.patch('freqtrade.exchange.validate_pairs', MagicMock(return_value=True))
|
||||
backtesting = Backtesting(conf)
|
||||
return {
|
||||
@@ -219,7 +219,8 @@ def test_setup_configuration_with_arguments(mocker, default_conf, caplog) -> Non
|
||||
'--realistic-simulation',
|
||||
'--refresh-pairs-cached',
|
||||
'--timerange', ':100',
|
||||
'--export', '/bar/foo'
|
||||
'--export', '/bar/foo',
|
||||
'--export-filename', 'foo_bar.json'
|
||||
]
|
||||
|
||||
config = setup_configuration(get_args(args))
|
||||
@@ -260,6 +261,11 @@ def test_setup_configuration_with_arguments(mocker, default_conf, caplog) -> Non
|
||||
'Parameter --export detected: {} ...'.format(config['export']),
|
||||
caplog.record_tuples
|
||||
)
|
||||
assert 'exportfilename' in config
|
||||
assert log_has(
|
||||
'Storing backtest results to {} ...'.format(config['exportfilename']),
|
||||
caplog.record_tuples
|
||||
)
|
||||
|
||||
|
||||
def test_setup_configuration_unlimited_stake_amount(mocker, default_conf, caplog) -> None:
|
||||
@@ -328,7 +334,7 @@ def test_tickerdata_to_dataframe(default_conf, mocker) -> None:
|
||||
Test Backtesting.tickerdata_to_dataframe() method
|
||||
"""
|
||||
mocker.patch('freqtrade.exchange.validate_pairs', MagicMock(return_value=True))
|
||||
timerange = ((None, 'line'), None, -100)
|
||||
timerange = TimeRange(None, 'line', 0, -100)
|
||||
tick = optimize.load_tickerdata_file(None, 'UNITTEST/BTC', '1m', timerange=timerange)
|
||||
tickerlist = {'UNITTEST/BTC': tick}
|
||||
|
||||
|
@@ -11,6 +11,7 @@ from freqtrade.misc import file_dump_json
|
||||
from freqtrade.optimize.__init__ import make_testdata_path, download_pairs, \
|
||||
download_backtesting_testdata, load_tickerdata_file, trim_tickerlist, \
|
||||
load_cached_data_for_updating
|
||||
from freqtrade.arguments import TimeRange
|
||||
from freqtrade.tests.conftest import log_has
|
||||
|
||||
# Change this if modifying UNITTEST/BTC testdatafile
|
||||
@@ -176,7 +177,7 @@ def test_load_cached_data_for_updating(mocker) -> None:
|
||||
|
||||
# timeframe starts earlier than the cached data
|
||||
# should fully update data
|
||||
timerange = (('date', None), test_data[0][0] / 1000 - 1, None)
|
||||
timerange = TimeRange('date', None, test_data[0][0] / 1000 - 1, 0)
|
||||
data, start_ts = load_cached_data_for_updating(test_filename,
|
||||
'1m',
|
||||
timerange)
|
||||
@@ -187,13 +188,13 @@ def test_load_cached_data_for_updating(mocker) -> None:
|
||||
num_lines = (test_data[-1][0] - test_data[1][0]) / 1000 / 60 + 120
|
||||
data, start_ts = load_cached_data_for_updating(test_filename,
|
||||
'1m',
|
||||
((None, 'line'), None, -num_lines))
|
||||
TimeRange(None, 'line', 0, -num_lines))
|
||||
assert data == []
|
||||
assert start_ts < test_data[0][0] - 1
|
||||
|
||||
# timeframe starts in the center of the cached data
|
||||
# should return the chached data w/o the last item
|
||||
timerange = (('date', None), test_data[0][0] / 1000 + 1, None)
|
||||
timerange = TimeRange('date', None, test_data[0][0] / 1000 + 1, 0)
|
||||
data, start_ts = load_cached_data_for_updating(test_filename,
|
||||
'1m',
|
||||
timerange)
|
||||
@@ -202,7 +203,7 @@ def test_load_cached_data_for_updating(mocker) -> None:
|
||||
|
||||
# same with 'line' timeframe
|
||||
num_lines = (test_data[-1][0] - test_data[1][0]) / 1000 / 60 + 30
|
||||
timerange = ((None, 'line'), None, -num_lines)
|
||||
timerange = TimeRange(None, 'line', 0, -num_lines)
|
||||
data, start_ts = load_cached_data_for_updating(test_filename,
|
||||
'1m',
|
||||
timerange)
|
||||
@@ -211,7 +212,7 @@ def test_load_cached_data_for_updating(mocker) -> None:
|
||||
|
||||
# timeframe starts after the chached data
|
||||
# should return the chached data w/o the last item
|
||||
timerange = (('date', None), test_data[-1][0] / 1000 + 1, None)
|
||||
timerange = TimeRange('date', None, test_data[-1][0] / 1000 + 1, 0)
|
||||
data, start_ts = load_cached_data_for_updating(test_filename,
|
||||
'1m',
|
||||
timerange)
|
||||
@@ -220,7 +221,7 @@ def test_load_cached_data_for_updating(mocker) -> None:
|
||||
|
||||
# same with 'line' timeframe
|
||||
num_lines = 30
|
||||
timerange = ((None, 'line'), None, -num_lines)
|
||||
timerange = TimeRange(None, 'line', 0, -num_lines)
|
||||
data, start_ts = load_cached_data_for_updating(test_filename,
|
||||
'1m',
|
||||
timerange)
|
||||
@@ -230,7 +231,7 @@ def test_load_cached_data_for_updating(mocker) -> None:
|
||||
# no timeframe is set
|
||||
# should return the chached data w/o the last item
|
||||
num_lines = 30
|
||||
timerange = ((None, 'line'), None, -num_lines)
|
||||
timerange = TimeRange(None, 'line', 0, -num_lines)
|
||||
data, start_ts = load_cached_data_for_updating(test_filename,
|
||||
'1m',
|
||||
timerange)
|
||||
@@ -239,7 +240,7 @@ def test_load_cached_data_for_updating(mocker) -> None:
|
||||
|
||||
# no datafile exist
|
||||
# should return timestamp start time
|
||||
timerange = (('date', None), now_ts - 10000, None)
|
||||
timerange = TimeRange('date', None, now_ts - 10000, 0)
|
||||
data, start_ts = load_cached_data_for_updating(test_filename + 'unexist',
|
||||
'1m',
|
||||
timerange)
|
||||
@@ -248,7 +249,7 @@ def test_load_cached_data_for_updating(mocker) -> None:
|
||||
|
||||
# same with 'line' timeframe
|
||||
num_lines = 30
|
||||
timerange = ((None, 'line'), None, -num_lines)
|
||||
timerange = TimeRange(None, 'line', 0, -num_lines)
|
||||
data, start_ts = load_cached_data_for_updating(test_filename + 'unexist',
|
||||
'1m',
|
||||
timerange)
|
||||
@@ -343,7 +344,7 @@ def test_trim_tickerlist() -> None:
|
||||
|
||||
# Test the pattern ^(-\d+)$
|
||||
# This pattern uses the latest N elements
|
||||
timerange = ((None, 'line'), None, -5)
|
||||
timerange = TimeRange(None, 'line', 0, -5)
|
||||
ticker = trim_tickerlist(ticker_list, timerange)
|
||||
ticker_len = len(ticker)
|
||||
|
||||
@@ -353,7 +354,7 @@ def test_trim_tickerlist() -> None:
|
||||
|
||||
# Test the pattern ^(\d+)-$
|
||||
# This pattern keep X element from the end
|
||||
timerange = (('line', None), 5, None)
|
||||
timerange = TimeRange('line', None, 5, 0)
|
||||
ticker = trim_tickerlist(ticker_list, timerange)
|
||||
ticker_len = len(ticker)
|
||||
|
||||
@@ -363,7 +364,7 @@ def test_trim_tickerlist() -> None:
|
||||
|
||||
# Test the pattern ^(\d+)-(\d+)$
|
||||
# This pattern extract a window
|
||||
timerange = (('index', 'index'), 5, 10)
|
||||
timerange = TimeRange('index', 'index', 5, 10)
|
||||
ticker = trim_tickerlist(ticker_list, timerange)
|
||||
ticker_len = len(ticker)
|
||||
|
||||
@@ -374,7 +375,7 @@ def test_trim_tickerlist() -> None:
|
||||
|
||||
# Test the pattern ^(\d{8})-(\d{8})$
|
||||
# This pattern extract a window between the dates
|
||||
timerange = (('date', 'date'), ticker_list[5][0] / 1000, ticker_list[10][0] / 1000 - 1)
|
||||
timerange = TimeRange('date', 'date', ticker_list[5][0] / 1000, ticker_list[10][0] / 1000 - 1)
|
||||
ticker = trim_tickerlist(ticker_list, timerange)
|
||||
ticker_len = len(ticker)
|
||||
|
||||
@@ -385,7 +386,7 @@ def test_trim_tickerlist() -> None:
|
||||
|
||||
# Test the pattern ^-(\d{8})$
|
||||
# This pattern extracts elements from the start to the date
|
||||
timerange = ((None, 'date'), None, ticker_list[10][0] / 1000 - 1)
|
||||
timerange = TimeRange(None, 'date', 0, ticker_list[10][0] / 1000 - 1)
|
||||
ticker = trim_tickerlist(ticker_list, timerange)
|
||||
ticker_len = len(ticker)
|
||||
|
||||
@@ -395,7 +396,7 @@ def test_trim_tickerlist() -> None:
|
||||
|
||||
# Test the pattern ^(\d{8})-$
|
||||
# This pattern extracts elements from the date to now
|
||||
timerange = (('date', None), ticker_list[10][0] / 1000 - 1, None)
|
||||
timerange = TimeRange('date', None, ticker_list[10][0] / 1000 - 1, None)
|
||||
ticker = trim_tickerlist(ticker_list, timerange)
|
||||
ticker_len = len(ticker)
|
||||
|
||||
@@ -405,7 +406,7 @@ def test_trim_tickerlist() -> None:
|
||||
|
||||
# Test a wrong pattern
|
||||
# This pattern must return the list unchanged
|
||||
timerange = ((None, None), None, 5)
|
||||
timerange = TimeRange(None, None, None, 5)
|
||||
ticker = trim_tickerlist(ticker_list, timerange)
|
||||
ticker_len = len(ticker)
|
||||
|
||||
|
@@ -7,8 +7,6 @@ Unit test file for rpc/rpc.py
|
||||
from datetime import datetime
|
||||
from unittest.mock import MagicMock
|
||||
|
||||
from sqlalchemy import create_engine
|
||||
|
||||
from freqtrade.freqtradebot import FreqtradeBot
|
||||
from freqtrade.persistence import Trade
|
||||
from freqtrade.rpc.rpc import RPC
|
||||
@@ -39,7 +37,7 @@ def test_rpc_trade_status(default_conf, ticker, fee, mocker) -> None:
|
||||
get_fee=fee
|
||||
)
|
||||
|
||||
freqtradebot = FreqtradeBot(default_conf, create_engine('sqlite://'))
|
||||
freqtradebot = FreqtradeBot(default_conf)
|
||||
rpc = RPC(freqtradebot)
|
||||
|
||||
freqtradebot.state = State.STOPPED
|
||||
@@ -88,7 +86,7 @@ def test_rpc_status_table(default_conf, ticker, fee, mocker) -> None:
|
||||
get_fee=fee
|
||||
)
|
||||
|
||||
freqtradebot = FreqtradeBot(default_conf, create_engine('sqlite://'))
|
||||
freqtradebot = FreqtradeBot(default_conf)
|
||||
rpc = RPC(freqtradebot)
|
||||
|
||||
freqtradebot.state = State.STOPPED
|
||||
@@ -123,7 +121,7 @@ def test_rpc_daily_profit(default_conf, update, ticker, fee,
|
||||
get_fee=fee
|
||||
)
|
||||
|
||||
freqtradebot = FreqtradeBot(default_conf, create_engine('sqlite://'))
|
||||
freqtradebot = FreqtradeBot(default_conf)
|
||||
stake_currency = default_conf['stake_currency']
|
||||
fiat_display_currency = default_conf['fiat_display_currency']
|
||||
|
||||
@@ -180,7 +178,7 @@ def test_rpc_trade_statistics(default_conf, ticker, ticker_sell_up, fee,
|
||||
get_fee=fee
|
||||
)
|
||||
|
||||
freqtradebot = FreqtradeBot(default_conf, create_engine('sqlite://'))
|
||||
freqtradebot = FreqtradeBot(default_conf)
|
||||
stake_currency = default_conf['stake_currency']
|
||||
fiat_display_currency = default_conf['fiat_display_currency']
|
||||
|
||||
@@ -206,15 +204,30 @@ def test_rpc_trade_statistics(default_conf, ticker, ticker_sell_up, fee,
|
||||
trade.close_date = datetime.utcnow()
|
||||
trade.is_open = False
|
||||
|
||||
freqtradebot.create_trade()
|
||||
trade = Trade.query.first()
|
||||
# Simulate fulfilled LIMIT_BUY order for trade
|
||||
trade.update(limit_buy_order)
|
||||
|
||||
# Update the ticker with a market going up
|
||||
mocker.patch.multiple(
|
||||
'freqtrade.freqtradebot.exchange',
|
||||
validate_pairs=MagicMock(),
|
||||
get_ticker=ticker_sell_up
|
||||
)
|
||||
trade.update(limit_sell_order)
|
||||
trade.close_date = datetime.utcnow()
|
||||
trade.is_open = False
|
||||
|
||||
(error, stats) = rpc.rpc_trade_statistics(stake_currency, fiat_display_currency)
|
||||
assert not error
|
||||
assert prec_satoshi(stats['profit_closed_coin'], 6.217e-05)
|
||||
assert prec_satoshi(stats['profit_closed_percent'], 6.2)
|
||||
assert prec_satoshi(stats['profit_closed_fiat'], 0.93255)
|
||||
assert prec_satoshi(stats['profit_all_coin'], 6.217e-05)
|
||||
assert prec_satoshi(stats['profit_all_percent'], 6.2)
|
||||
assert prec_satoshi(stats['profit_all_fiat'], 0.93255)
|
||||
assert stats['trade_count'] == 1
|
||||
assert prec_satoshi(stats['profit_all_coin'], 5.632e-05)
|
||||
assert prec_satoshi(stats['profit_all_percent'], 2.81)
|
||||
assert prec_satoshi(stats['profit_all_fiat'], 0.8448)
|
||||
assert stats['trade_count'] == 2
|
||||
assert stats['first_trade_date'] == 'just now'
|
||||
assert stats['latest_trade_date'] == 'just now'
|
||||
assert stats['avg_duration'] == '0:00:00'
|
||||
@@ -243,7 +256,7 @@ def test_rpc_trade_statistics_closed(mocker, default_conf, ticker, fee,
|
||||
get_fee=fee
|
||||
)
|
||||
|
||||
freqtradebot = FreqtradeBot(default_conf, create_engine('sqlite://'))
|
||||
freqtradebot = FreqtradeBot(default_conf)
|
||||
stake_currency = default_conf['stake_currency']
|
||||
fiat_display_currency = default_conf['fiat_display_currency']
|
||||
|
||||
@@ -314,7 +327,7 @@ def test_rpc_balance_handle(default_conf, mocker):
|
||||
get_balances=MagicMock(return_value=mock_balance)
|
||||
)
|
||||
|
||||
freqtradebot = FreqtradeBot(default_conf, create_engine('sqlite://'))
|
||||
freqtradebot = FreqtradeBot(default_conf)
|
||||
rpc = RPC(freqtradebot)
|
||||
|
||||
(error, res) = rpc.rpc_balance(default_conf['fiat_display_currency'])
|
||||
@@ -344,7 +357,7 @@ def test_rpc_start(mocker, default_conf) -> None:
|
||||
get_ticker=MagicMock()
|
||||
)
|
||||
|
||||
freqtradebot = FreqtradeBot(default_conf, create_engine('sqlite://'))
|
||||
freqtradebot = FreqtradeBot(default_conf)
|
||||
rpc = RPC(freqtradebot)
|
||||
freqtradebot.state = State.STOPPED
|
||||
|
||||
@@ -372,7 +385,7 @@ def test_rpc_stop(mocker, default_conf) -> None:
|
||||
get_ticker=MagicMock()
|
||||
)
|
||||
|
||||
freqtradebot = FreqtradeBot(default_conf, create_engine('sqlite://'))
|
||||
freqtradebot = FreqtradeBot(default_conf)
|
||||
rpc = RPC(freqtradebot)
|
||||
freqtradebot.state = State.RUNNING
|
||||
|
||||
@@ -411,7 +424,7 @@ def test_rpc_forcesell(default_conf, ticker, fee, mocker) -> None:
|
||||
get_fee=fee,
|
||||
)
|
||||
|
||||
freqtradebot = FreqtradeBot(default_conf, create_engine('sqlite://'))
|
||||
freqtradebot = FreqtradeBot(default_conf)
|
||||
rpc = RPC(freqtradebot)
|
||||
|
||||
freqtradebot.state = State.STOPPED
|
||||
@@ -521,7 +534,7 @@ def test_performance_handle(default_conf, ticker, limit_buy_order, fee,
|
||||
get_fee=fee
|
||||
)
|
||||
|
||||
freqtradebot = FreqtradeBot(default_conf, create_engine('sqlite://'))
|
||||
freqtradebot = FreqtradeBot(default_conf)
|
||||
rpc = RPC(freqtradebot)
|
||||
|
||||
# Create some test data
|
||||
@@ -560,7 +573,7 @@ def test_rpc_count(mocker, default_conf, ticker, fee) -> None:
|
||||
get_fee=fee,
|
||||
)
|
||||
|
||||
freqtradebot = FreqtradeBot(default_conf, create_engine('sqlite://'))
|
||||
freqtradebot = FreqtradeBot(default_conf)
|
||||
rpc = RPC(freqtradebot)
|
||||
|
||||
(error, trades) = rpc.rpc_count()
|
||||
|
@@ -11,7 +11,6 @@ from datetime import datetime
|
||||
from random import randint
|
||||
from unittest.mock import MagicMock
|
||||
|
||||
from sqlalchemy import create_engine
|
||||
from telegram import Update, Message, Chat
|
||||
from telegram.error import NetworkError
|
||||
|
||||
@@ -156,7 +155,7 @@ def test_authorized_only(default_conf, mocker, caplog) -> None:
|
||||
|
||||
conf = deepcopy(default_conf)
|
||||
conf['telegram']['enabled'] = False
|
||||
dummy = DummyCls(FreqtradeBot(conf, create_engine('sqlite://')))
|
||||
dummy = DummyCls(FreqtradeBot(conf))
|
||||
dummy.dummy_handler(bot=MagicMock(), update=update)
|
||||
assert dummy.state['called'] is True
|
||||
assert log_has(
|
||||
@@ -187,7 +186,7 @@ def test_authorized_only_unauthorized(default_conf, mocker, caplog) -> None:
|
||||
|
||||
conf = deepcopy(default_conf)
|
||||
conf['telegram']['enabled'] = False
|
||||
dummy = DummyCls(FreqtradeBot(conf, create_engine('sqlite://')))
|
||||
dummy = DummyCls(FreqtradeBot(conf))
|
||||
dummy.dummy_handler(bot=MagicMock(), update=update)
|
||||
assert dummy.state['called'] is False
|
||||
assert not log_has(
|
||||
@@ -217,7 +216,7 @@ def test_authorized_only_exception(default_conf, mocker, caplog) -> None:
|
||||
|
||||
conf = deepcopy(default_conf)
|
||||
conf['telegram']['enabled'] = False
|
||||
dummy = DummyCls(FreqtradeBot(conf, create_engine('sqlite://')))
|
||||
dummy = DummyCls(FreqtradeBot(conf))
|
||||
dummy.dummy_exception(bot=MagicMock(), update=update)
|
||||
assert dummy.state['called'] is False
|
||||
assert not log_has(
|
||||
@@ -263,7 +262,7 @@ def test_status(default_conf, update, mocker, fee, ticker) -> None:
|
||||
)
|
||||
mocker.patch('freqtrade.freqtradebot.RPCManager', MagicMock())
|
||||
|
||||
freqtradebot = FreqtradeBot(conf, create_engine('sqlite://'))
|
||||
freqtradebot = FreqtradeBot(conf)
|
||||
telegram = Telegram(freqtradebot)
|
||||
|
||||
# Create some test data
|
||||
@@ -301,7 +300,7 @@ def test_status_handle(default_conf, update, ticker, fee, mocker) -> None:
|
||||
)
|
||||
mocker.patch('freqtrade.freqtradebot.RPCManager', MagicMock())
|
||||
|
||||
freqtradebot = FreqtradeBot(default_conf, create_engine('sqlite://'))
|
||||
freqtradebot = FreqtradeBot(default_conf)
|
||||
telegram = Telegram(freqtradebot)
|
||||
|
||||
freqtradebot.state = State.STOPPED
|
||||
@@ -348,7 +347,7 @@ def test_status_table_handle(default_conf, update, ticker, fee, mocker) -> None:
|
||||
|
||||
conf = deepcopy(default_conf)
|
||||
conf['stake_amount'] = 15.0
|
||||
freqtradebot = FreqtradeBot(conf, create_engine('sqlite://'))
|
||||
freqtradebot = FreqtradeBot(conf)
|
||||
telegram = Telegram(freqtradebot)
|
||||
|
||||
freqtradebot.state = State.STOPPED
|
||||
@@ -402,7 +401,7 @@ def test_daily_handle(default_conf, update, ticker, limit_buy_order, fee,
|
||||
)
|
||||
mocker.patch('freqtrade.freqtradebot.RPCManager', MagicMock())
|
||||
|
||||
freqtradebot = FreqtradeBot(default_conf, create_engine('sqlite://'))
|
||||
freqtradebot = FreqtradeBot(default_conf)
|
||||
telegram = Telegram(freqtradebot)
|
||||
|
||||
# Create some test data
|
||||
@@ -470,7 +469,7 @@ def test_daily_wrong_input(default_conf, update, ticker, mocker) -> None:
|
||||
)
|
||||
mocker.patch('freqtrade.freqtradebot.RPCManager', MagicMock())
|
||||
|
||||
freqtradebot = FreqtradeBot(default_conf, create_engine('sqlite://'))
|
||||
freqtradebot = FreqtradeBot(default_conf)
|
||||
telegram = Telegram(freqtradebot)
|
||||
|
||||
# Try invalid data
|
||||
@@ -511,7 +510,7 @@ def test_profit_handle(default_conf, update, ticker, ticker_sell_up, fee,
|
||||
)
|
||||
mocker.patch('freqtrade.freqtradebot.RPCManager', MagicMock())
|
||||
|
||||
freqtradebot = FreqtradeBot(default_conf, create_engine('sqlite://'))
|
||||
freqtradebot = FreqtradeBot(default_conf)
|
||||
telegram = Telegram(freqtradebot)
|
||||
|
||||
telegram._profit(bot=MagicMock(), update=update)
|
||||
@@ -608,7 +607,7 @@ def test_telegram_balance_handle(default_conf, update, mocker) -> None:
|
||||
send_msg=msg_mock
|
||||
)
|
||||
|
||||
freqtradebot = FreqtradeBot(default_conf, create_engine('sqlite://'))
|
||||
freqtradebot = FreqtradeBot(default_conf)
|
||||
telegram = Telegram(freqtradebot)
|
||||
|
||||
telegram._balance(bot=MagicMock(), update=update)
|
||||
@@ -638,7 +637,7 @@ def test_zero_balance_handle(default_conf, update, mocker) -> None:
|
||||
send_msg=msg_mock
|
||||
)
|
||||
|
||||
freqtradebot = FreqtradeBot(default_conf, create_engine('sqlite://'))
|
||||
freqtradebot = FreqtradeBot(default_conf)
|
||||
telegram = Telegram(freqtradebot)
|
||||
|
||||
telegram._balance(bot=MagicMock(), update=update)
|
||||
@@ -661,7 +660,7 @@ def test_start_handle(default_conf, update, mocker) -> None:
|
||||
)
|
||||
mocker.patch('freqtrade.freqtradebot.RPCManager', MagicMock())
|
||||
|
||||
freqtradebot = FreqtradeBot(default_conf, create_engine('sqlite://'))
|
||||
freqtradebot = FreqtradeBot(default_conf)
|
||||
telegram = Telegram(freqtradebot)
|
||||
|
||||
freqtradebot.state = State.STOPPED
|
||||
@@ -685,7 +684,7 @@ def test_start_handle_already_running(default_conf, update, mocker) -> None:
|
||||
)
|
||||
mocker.patch('freqtrade.freqtradebot.RPCManager', MagicMock())
|
||||
|
||||
freqtradebot = FreqtradeBot(default_conf, create_engine('sqlite://'))
|
||||
freqtradebot = FreqtradeBot(default_conf)
|
||||
telegram = Telegram(freqtradebot)
|
||||
|
||||
freqtradebot.state = State.RUNNING
|
||||
@@ -710,7 +709,7 @@ def test_stop_handle(default_conf, update, mocker) -> None:
|
||||
)
|
||||
mocker.patch('freqtrade.freqtradebot.RPCManager', MagicMock())
|
||||
|
||||
freqtradebot = FreqtradeBot(default_conf, create_engine('sqlite://'))
|
||||
freqtradebot = FreqtradeBot(default_conf)
|
||||
telegram = Telegram(freqtradebot)
|
||||
|
||||
freqtradebot.state = State.RUNNING
|
||||
@@ -735,7 +734,7 @@ def test_stop_handle_already_stopped(default_conf, update, mocker) -> None:
|
||||
)
|
||||
mocker.patch('freqtrade.freqtradebot.RPCManager', MagicMock())
|
||||
|
||||
freqtradebot = FreqtradeBot(default_conf, create_engine('sqlite://'))
|
||||
freqtradebot = FreqtradeBot(default_conf)
|
||||
telegram = Telegram(freqtradebot)
|
||||
|
||||
freqtradebot.state = State.STOPPED
|
||||
@@ -762,7 +761,7 @@ def test_forcesell_handle(default_conf, update, ticker, fee, ticker_sell_up, moc
|
||||
get_fee=fee
|
||||
)
|
||||
|
||||
freqtradebot = FreqtradeBot(default_conf, create_engine('sqlite://'))
|
||||
freqtradebot = FreqtradeBot(default_conf)
|
||||
telegram = Telegram(freqtradebot)
|
||||
|
||||
# Create some test data
|
||||
@@ -802,7 +801,7 @@ def test_forcesell_down_handle(default_conf, update, ticker, fee, ticker_sell_do
|
||||
get_fee=fee
|
||||
)
|
||||
|
||||
freqtradebot = FreqtradeBot(default_conf, create_engine('sqlite://'))
|
||||
freqtradebot = FreqtradeBot(default_conf)
|
||||
telegram = Telegram(freqtradebot)
|
||||
|
||||
# Create some test data
|
||||
@@ -847,7 +846,7 @@ def test_forcesell_all_handle(default_conf, update, ticker, fee, mocker) -> None
|
||||
get_fee=fee
|
||||
)
|
||||
|
||||
freqtradebot = FreqtradeBot(default_conf, create_engine('sqlite://'))
|
||||
freqtradebot = FreqtradeBot(default_conf)
|
||||
telegram = Telegram(freqtradebot)
|
||||
|
||||
# Create some test data
|
||||
@@ -880,7 +879,7 @@ def test_forcesell_handle_invalid(default_conf, update, mocker) -> None:
|
||||
)
|
||||
mocker.patch('freqtrade.freqtradebot.exchange.validate_pairs', MagicMock())
|
||||
|
||||
freqtradebot = FreqtradeBot(default_conf, create_engine('sqlite://'))
|
||||
freqtradebot = FreqtradeBot(default_conf)
|
||||
telegram = Telegram(freqtradebot)
|
||||
|
||||
# Trader is not running
|
||||
@@ -927,7 +926,7 @@ def test_performance_handle(default_conf, update, ticker, fee,
|
||||
get_fee=fee
|
||||
)
|
||||
mocker.patch('freqtrade.freqtradebot.RPCManager', MagicMock())
|
||||
freqtradebot = FreqtradeBot(default_conf, create_engine('sqlite://'))
|
||||
freqtradebot = FreqtradeBot(default_conf)
|
||||
telegram = Telegram(freqtradebot)
|
||||
|
||||
# Create some test data
|
||||
@@ -962,7 +961,7 @@ def test_performance_handle_invalid(default_conf, update, mocker) -> None:
|
||||
send_msg=msg_mock
|
||||
)
|
||||
mocker.patch('freqtrade.freqtradebot.exchange.validate_pairs', MagicMock())
|
||||
freqtradebot = FreqtradeBot(default_conf, create_engine('sqlite://'))
|
||||
freqtradebot = FreqtradeBot(default_conf)
|
||||
telegram = Telegram(freqtradebot)
|
||||
|
||||
# Trader is not running
|
||||
@@ -991,7 +990,7 @@ def test_count_handle(default_conf, update, ticker, fee, mocker) -> None:
|
||||
buy=MagicMock(return_value={'id': 'mocked_order_id'})
|
||||
)
|
||||
mocker.patch('freqtrade.optimize.backtesting.exchange.get_fee', fee)
|
||||
freqtradebot = FreqtradeBot(default_conf, create_engine('sqlite://'))
|
||||
freqtradebot = FreqtradeBot(default_conf)
|
||||
telegram = Telegram(freqtradebot)
|
||||
|
||||
freqtradebot.state = State.STOPPED
|
||||
@@ -1027,7 +1026,7 @@ def test_help_handle(default_conf, update, mocker) -> None:
|
||||
_init=MagicMock(),
|
||||
send_msg=msg_mock
|
||||
)
|
||||
freqtradebot = FreqtradeBot(default_conf, create_engine('sqlite://'))
|
||||
freqtradebot = FreqtradeBot(default_conf)
|
||||
telegram = Telegram(freqtradebot)
|
||||
|
||||
telegram._help(bot=MagicMock(), update=update)
|
||||
@@ -1047,7 +1046,7 @@ def test_version_handle(default_conf, update, mocker) -> None:
|
||||
_init=MagicMock(),
|
||||
send_msg=msg_mock
|
||||
)
|
||||
freqtradebot = FreqtradeBot(default_conf, create_engine('sqlite://'))
|
||||
freqtradebot = FreqtradeBot(default_conf)
|
||||
telegram = Telegram(freqtradebot)
|
||||
|
||||
telegram._version(bot=MagicMock(), update=update)
|
||||
@@ -1064,7 +1063,7 @@ def test_send_msg(default_conf, mocker) -> None:
|
||||
mocker.patch('freqtrade.rpc.telegram.Telegram._init', MagicMock())
|
||||
conf = deepcopy(default_conf)
|
||||
bot = MagicMock()
|
||||
freqtradebot = FreqtradeBot(conf, create_engine('sqlite://'))
|
||||
freqtradebot = FreqtradeBot(conf)
|
||||
telegram = Telegram(freqtradebot)
|
||||
|
||||
telegram._config['telegram']['enabled'] = False
|
||||
@@ -1087,7 +1086,7 @@ def test_send_msg_network_error(default_conf, mocker, caplog) -> None:
|
||||
conf = deepcopy(default_conf)
|
||||
bot = MagicMock()
|
||||
bot.send_message = MagicMock(side_effect=NetworkError('Oh snap'))
|
||||
freqtradebot = FreqtradeBot(conf, create_engine('sqlite://'))
|
||||
freqtradebot = FreqtradeBot(conf)
|
||||
telegram = Telegram(freqtradebot)
|
||||
|
||||
telegram._config['telegram']['enabled'] = True
|
||||
|
@@ -13,6 +13,7 @@ from pandas import DataFrame
|
||||
|
||||
from freqtrade.analyze import Analyze, SignalType
|
||||
from freqtrade.optimize.__init__ import load_tickerdata_file
|
||||
from freqtrade.arguments import TimeRange
|
||||
from freqtrade.tests.conftest import log_has
|
||||
|
||||
# Avoid to reinit the same object again and again
|
||||
@@ -183,7 +184,7 @@ def test_tickerdata_to_dataframe(default_conf) -> None:
|
||||
"""
|
||||
analyze = Analyze(default_conf)
|
||||
|
||||
timerange = ((None, 'line'), None, -100)
|
||||
timerange = TimeRange(None, 'line', 0, -100)
|
||||
tick = load_tickerdata_file(None, 'UNITTEST/BTC', '1m', timerange=timerange)
|
||||
tickerlist = {'UNITTEST/BTC': tick}
|
||||
data = analyze.tickerdata_to_dataframe(tickerlist)
|
||||
|
@@ -9,7 +9,7 @@ import logging
|
||||
|
||||
import pytest
|
||||
|
||||
from freqtrade.arguments import Arguments
|
||||
from freqtrade.arguments import Arguments, TimeRange
|
||||
|
||||
|
||||
def test_arguments_object() -> None:
|
||||
@@ -46,6 +46,11 @@ def test_parse_args_config() -> None:
|
||||
assert args.config == '/dev/null'
|
||||
|
||||
|
||||
def test_parse_args_db_url() -> None:
|
||||
args = Arguments(['--db-url', 'sqlite:///test.sqlite'], '').get_parsed_arg()
|
||||
assert args.db_url == 'sqlite:///test.sqlite'
|
||||
|
||||
|
||||
def test_parse_args_verbose() -> None:
|
||||
args = Arguments(['-v'], '').get_parsed_arg()
|
||||
assert args.loglevel == logging.DEBUG
|
||||
@@ -107,20 +112,24 @@ def test_parse_args_dynamic_whitelist_invalid_values() -> None:
|
||||
|
||||
|
||||
def test_parse_timerange_incorrect() -> None:
|
||||
assert ((None, 'line'), None, -200) == Arguments.parse_timerange('-200')
|
||||
assert (('line', None), 200, None) == Arguments.parse_timerange('200-')
|
||||
assert (('index', 'index'), 200, 500) == Arguments.parse_timerange('200-500')
|
||||
assert TimeRange(None, 'line', 0, -200) == Arguments.parse_timerange('-200')
|
||||
assert TimeRange('line', None, 200, 0) == Arguments.parse_timerange('200-')
|
||||
assert TimeRange('index', 'index', 200, 500) == Arguments.parse_timerange('200-500')
|
||||
|
||||
assert (('date', None), 1274486400, None) == Arguments.parse_timerange('20100522-')
|
||||
assert ((None, 'date'), None, 1274486400) == Arguments.parse_timerange('-20100522')
|
||||
assert TimeRange('date', None, 1274486400, 0) == Arguments.parse_timerange('20100522-')
|
||||
assert TimeRange(None, 'date', 0, 1274486400) == Arguments.parse_timerange('-20100522')
|
||||
timerange = Arguments.parse_timerange('20100522-20150730')
|
||||
assert timerange == (('date', 'date'), 1274486400, 1438214400)
|
||||
assert timerange == TimeRange('date', 'date', 1274486400, 1438214400)
|
||||
|
||||
# Added test for unix timestamp - BTC genesis date
|
||||
assert (('date', None), 1231006505, None) == Arguments.parse_timerange('1231006505-')
|
||||
assert ((None, 'date'), None, 1233360000) == Arguments.parse_timerange('-1233360000')
|
||||
assert TimeRange('date', None, 1231006505, 0) == Arguments.parse_timerange('1231006505-')
|
||||
assert TimeRange(None, 'date', 0, 1233360000) == Arguments.parse_timerange('-1233360000')
|
||||
timerange = Arguments.parse_timerange('1231006505-1233360000')
|
||||
assert timerange == (('date', 'date'), 1231006505, 1233360000)
|
||||
assert TimeRange('date', 'date', 1231006505, 1233360000) == timerange
|
||||
|
||||
# TODO: Find solution for the following case (passing timestamp in ms)
|
||||
timerange = Arguments.parse_timerange('1231006505000-1233360000000')
|
||||
assert TimeRange('date', 'date', 1231006505, 1233360000) != timerange
|
||||
|
||||
with pytest.raises(Exception, match=r'Incorrect syntax.*'):
|
||||
Arguments.parse_timerange('-')
|
||||
|
@@ -130,7 +130,6 @@ def test_load_config(default_conf, mocker) -> None:
|
||||
assert validated_conf.get('strategy') == 'DefaultStrategy'
|
||||
assert validated_conf.get('strategy_path') is None
|
||||
assert 'dynamic_whitelist' not in validated_conf
|
||||
assert 'dry_run_db' not in validated_conf
|
||||
|
||||
|
||||
def test_load_config_with_params(default_conf, mocker) -> None:
|
||||
@@ -145,7 +144,7 @@ def test_load_config_with_params(default_conf, mocker) -> None:
|
||||
'--dynamic-whitelist', '10',
|
||||
'--strategy', 'TestStrategy',
|
||||
'--strategy-path', '/some/path',
|
||||
'--dry-run-db',
|
||||
'--db-url', 'sqlite:///someurl',
|
||||
]
|
||||
args = Arguments(arglist, '').get_parsed_arg()
|
||||
|
||||
@@ -155,7 +154,7 @@ def test_load_config_with_params(default_conf, mocker) -> None:
|
||||
assert validated_conf.get('dynamic_whitelist') == 10
|
||||
assert validated_conf.get('strategy') == 'TestStrategy'
|
||||
assert validated_conf.get('strategy_path') == '/some/path'
|
||||
assert validated_conf.get('dry_run_db') is True
|
||||
assert validated_conf.get('db_url') == 'sqlite:///someurl'
|
||||
|
||||
|
||||
def test_load_custom_strategy(default_conf, mocker) -> None:
|
||||
@@ -190,7 +189,7 @@ def test_show_info(default_conf, mocker, caplog) -> None:
|
||||
arglist = [
|
||||
'--dynamic-whitelist', '10',
|
||||
'--strategy', 'TestStrategy',
|
||||
'--dry-run-db'
|
||||
'--db-url', 'sqlite:///tmp/testdb',
|
||||
]
|
||||
args = Arguments(arglist, '').get_parsed_arg()
|
||||
|
||||
@@ -204,23 +203,8 @@ def test_show_info(default_conf, mocker, caplog) -> None:
|
||||
caplog.record_tuples
|
||||
)
|
||||
|
||||
assert log_has(
|
||||
'Parameter --dry-run-db detected ...',
|
||||
caplog.record_tuples
|
||||
)
|
||||
|
||||
assert log_has(
|
||||
'Dry_run will use the DB file: "tradesv3.dry_run.sqlite"',
|
||||
caplog.record_tuples
|
||||
)
|
||||
|
||||
# Test the Dry run condition
|
||||
configuration.config.update({'dry_run': False}) # type: ignore
|
||||
configuration._load_common_config(configuration.config) # type: ignore
|
||||
assert log_has(
|
||||
'Dry run is disabled. (--dry_run_db ignored)',
|
||||
caplog.record_tuples
|
||||
)
|
||||
assert log_has('Using DB: "sqlite:///tmp/testdb"', caplog.record_tuples)
|
||||
assert log_has('Dry run is enabled', caplog.record_tuples)
|
||||
|
||||
|
||||
def test_setup_configuration_without_arguments(mocker, default_conf, caplog) -> None:
|
||||
|
@@ -13,7 +13,6 @@ from unittest.mock import MagicMock
|
||||
import arrow
|
||||
import pytest
|
||||
import requests
|
||||
from sqlalchemy import create_engine
|
||||
|
||||
from freqtrade import constants, DependencyException, OperationalException, TemporaryError
|
||||
from freqtrade.freqtradebot import FreqtradeBot
|
||||
@@ -36,7 +35,7 @@ def get_patched_freqtradebot(mocker, config) -> FreqtradeBot:
|
||||
mocker.patch('freqtrade.freqtradebot.exchange.init', MagicMock())
|
||||
patch_coinmarketcap(mocker)
|
||||
|
||||
return FreqtradeBot(config, create_engine('sqlite://'))
|
||||
return FreqtradeBot(config)
|
||||
|
||||
|
||||
def patch_get_signal(mocker, value=(True, False)) -> None:
|
||||
@@ -346,7 +345,7 @@ def test_create_trade(default_conf, ticker, limit_buy_order, fee, mocker) -> Non
|
||||
|
||||
# Save state of current whitelist
|
||||
whitelist = deepcopy(default_conf['exchange']['pair_whitelist'])
|
||||
freqtrade = FreqtradeBot(default_conf, create_engine('sqlite://'))
|
||||
freqtrade = FreqtradeBot(default_conf)
|
||||
freqtrade.create_trade()
|
||||
|
||||
trade = Trade.query.first()
|
||||
@@ -383,13 +382,34 @@ def test_create_trade_minimal_amount(default_conf, ticker, limit_buy_order, fee,
|
||||
|
||||
conf = deepcopy(default_conf)
|
||||
conf['stake_amount'] = 0.0005
|
||||
freqtrade = FreqtradeBot(conf, create_engine('sqlite://'))
|
||||
freqtrade = FreqtradeBot(conf)
|
||||
|
||||
freqtrade.create_trade()
|
||||
rate, amount = buy_mock.call_args[0][1], buy_mock.call_args[0][2]
|
||||
assert rate * amount >= conf['stake_amount']
|
||||
|
||||
|
||||
def test_create_trade_no_stake_amount(default_conf, ticker, limit_buy_order, fee, mocker) -> None:
|
||||
"""
|
||||
Test create_trade() method
|
||||
"""
|
||||
patch_get_signal(mocker)
|
||||
patch_RPCManager(mocker)
|
||||
patch_coinmarketcap(mocker)
|
||||
mocker.patch.multiple(
|
||||
'freqtrade.freqtradebot.exchange',
|
||||
validate_pairs=MagicMock(),
|
||||
get_ticker=ticker,
|
||||
buy=MagicMock(return_value={'id': limit_buy_order['id']}),
|
||||
get_balance=MagicMock(return_value=default_conf['stake_amount'] * 0.5),
|
||||
get_fee=fee,
|
||||
)
|
||||
freqtrade = FreqtradeBot(default_conf)
|
||||
|
||||
with pytest.raises(DependencyException, match=r'.*stake amount.*'):
|
||||
freqtrade.create_trade()
|
||||
|
||||
|
||||
def test_create_trade_no_pairs(default_conf, ticker, limit_buy_order, fee, mocker) -> None:
|
||||
"""
|
||||
Test create_trade() method
|
||||
@@ -408,7 +428,7 @@ def test_create_trade_no_pairs(default_conf, ticker, limit_buy_order, fee, mocke
|
||||
conf = deepcopy(default_conf)
|
||||
conf['exchange']['pair_whitelist'] = ["ETH/BTC"]
|
||||
conf['exchange']['pair_blacklist'] = ["ETH/BTC"]
|
||||
freqtrade = FreqtradeBot(conf, create_engine('sqlite://'))
|
||||
freqtrade = FreqtradeBot(conf)
|
||||
|
||||
freqtrade.create_trade()
|
||||
|
||||
@@ -435,7 +455,7 @@ def test_create_trade_no_pairs_after_blacklist(default_conf, ticker,
|
||||
conf = deepcopy(default_conf)
|
||||
conf['exchange']['pair_whitelist'] = ["ETH/BTC"]
|
||||
conf['exchange']['pair_blacklist'] = ["ETH/BTC"]
|
||||
freqtrade = FreqtradeBot(conf, create_engine('sqlite://'))
|
||||
freqtrade = FreqtradeBot(conf)
|
||||
|
||||
freqtrade.create_trade()
|
||||
|
||||
@@ -463,7 +483,7 @@ def test_create_trade_no_signal(default_conf, fee, mocker) -> None:
|
||||
|
||||
conf = deepcopy(default_conf)
|
||||
conf['stake_amount'] = 10
|
||||
freqtrade = FreqtradeBot(conf, create_engine('sqlite://'))
|
||||
freqtrade = FreqtradeBot(conf)
|
||||
|
||||
Trade.query = MagicMock()
|
||||
Trade.query.filter = MagicMock()
|
||||
@@ -487,7 +507,7 @@ def test_process_trade_creation(default_conf, ticker, limit_buy_order,
|
||||
get_order=MagicMock(return_value=limit_buy_order),
|
||||
get_fee=fee,
|
||||
)
|
||||
freqtrade = FreqtradeBot(default_conf, create_engine('sqlite://'))
|
||||
freqtrade = FreqtradeBot(default_conf)
|
||||
|
||||
trades = Trade.query.filter(Trade.is_open.is_(True)).all()
|
||||
assert not trades
|
||||
@@ -528,7 +548,7 @@ def test_process_exchange_failures(default_conf, ticker, markets, mocker) -> Non
|
||||
)
|
||||
sleep_mock = mocker.patch('time.sleep', side_effect=lambda _: None)
|
||||
|
||||
freqtrade = FreqtradeBot(default_conf, create_engine('sqlite://'))
|
||||
freqtrade = FreqtradeBot(default_conf)
|
||||
result = freqtrade._process()
|
||||
assert result is False
|
||||
assert sleep_mock.has_calls()
|
||||
@@ -548,7 +568,7 @@ def test_process_operational_exception(default_conf, ticker, markets, mocker) ->
|
||||
get_markets=markets,
|
||||
buy=MagicMock(side_effect=OperationalException)
|
||||
)
|
||||
freqtrade = FreqtradeBot(default_conf, create_engine('sqlite://'))
|
||||
freqtrade = FreqtradeBot(default_conf)
|
||||
assert freqtrade.state == State.RUNNING
|
||||
|
||||
result = freqtrade._process()
|
||||
@@ -574,7 +594,7 @@ def test_process_trade_handling(
|
||||
get_order=MagicMock(return_value=limit_buy_order),
|
||||
get_fee=fee,
|
||||
)
|
||||
freqtrade = FreqtradeBot(default_conf, create_engine('sqlite://'))
|
||||
freqtrade = FreqtradeBot(default_conf)
|
||||
|
||||
trades = Trade.query.filter(Trade.is_open.is_(True)).all()
|
||||
assert not trades
|
||||
@@ -691,7 +711,7 @@ def test_handle_trade(default_conf, limit_buy_order, limit_sell_order, fee, mock
|
||||
)
|
||||
patch_coinmarketcap(mocker, value={'price_usd': 15000.0})
|
||||
|
||||
freqtrade = FreqtradeBot(default_conf, create_engine('sqlite://'))
|
||||
freqtrade = FreqtradeBot(default_conf)
|
||||
|
||||
freqtrade.create_trade()
|
||||
|
||||
@@ -734,7 +754,7 @@ def test_handle_overlpapping_signals(default_conf, ticker, limit_buy_order, fee,
|
||||
get_fee=fee,
|
||||
)
|
||||
|
||||
freqtrade = FreqtradeBot(conf, create_engine('sqlite://'))
|
||||
freqtrade = FreqtradeBot(conf)
|
||||
|
||||
freqtrade.create_trade()
|
||||
|
||||
@@ -793,7 +813,7 @@ def test_handle_trade_roi(default_conf, ticker, limit_buy_order, fee, mocker, ca
|
||||
)
|
||||
|
||||
mocker.patch('freqtrade.freqtradebot.Analyze.min_roi_reached', return_value=True)
|
||||
freqtrade = FreqtradeBot(conf, create_engine('sqlite://'))
|
||||
freqtrade = FreqtradeBot(conf)
|
||||
freqtrade.create_trade()
|
||||
|
||||
trade = Trade.query.first()
|
||||
@@ -830,7 +850,7 @@ def test_handle_trade_experimental(
|
||||
)
|
||||
mocker.patch('freqtrade.freqtradebot.Analyze.min_roi_reached', return_value=False)
|
||||
|
||||
freqtrade = FreqtradeBot(conf, create_engine('sqlite://'))
|
||||
freqtrade = FreqtradeBot(conf)
|
||||
freqtrade.create_trade()
|
||||
|
||||
trade = Trade.query.first()
|
||||
@@ -858,7 +878,7 @@ def test_close_trade(default_conf, ticker, limit_buy_order, limit_sell_order, fe
|
||||
buy=MagicMock(return_value={'id': limit_buy_order['id']}),
|
||||
get_fee=fee,
|
||||
)
|
||||
freqtrade = FreqtradeBot(default_conf, create_engine('sqlite://'))
|
||||
freqtrade = FreqtradeBot(default_conf)
|
||||
|
||||
# Create trade and sell it
|
||||
freqtrade.create_trade()
|
||||
@@ -889,7 +909,7 @@ def test_check_handle_timedout_buy(default_conf, ticker, limit_buy_order_old, fe
|
||||
cancel_order=cancel_order_mock,
|
||||
get_fee=fee
|
||||
)
|
||||
freqtrade = FreqtradeBot(default_conf, create_engine('sqlite://'))
|
||||
freqtrade = FreqtradeBot(default_conf)
|
||||
|
||||
trade_buy = Trade(
|
||||
pair='ETH/BTC',
|
||||
@@ -929,7 +949,7 @@ def test_check_handle_timedout_sell(default_conf, ticker, limit_sell_order_old,
|
||||
get_order=MagicMock(return_value=limit_sell_order_old),
|
||||
cancel_order=cancel_order_mock
|
||||
)
|
||||
freqtrade = FreqtradeBot(default_conf, create_engine('sqlite://'))
|
||||
freqtrade = FreqtradeBot(default_conf)
|
||||
|
||||
trade_sell = Trade(
|
||||
pair='ETH/BTC',
|
||||
@@ -969,7 +989,7 @@ def test_check_handle_timedout_partial(default_conf, ticker, limit_buy_order_old
|
||||
get_order=MagicMock(return_value=limit_buy_order_old_partial),
|
||||
cancel_order=cancel_order_mock
|
||||
)
|
||||
freqtrade = FreqtradeBot(default_conf, create_engine('sqlite://'))
|
||||
freqtrade = FreqtradeBot(default_conf)
|
||||
|
||||
trade_buy = Trade(
|
||||
pair='ETH/BTC',
|
||||
@@ -1017,7 +1037,7 @@ def test_check_handle_timedout_exception(default_conf, ticker, mocker, caplog) -
|
||||
get_order=MagicMock(side_effect=requests.exceptions.RequestException('Oh snap')),
|
||||
cancel_order=cancel_order_mock
|
||||
)
|
||||
freqtrade = FreqtradeBot(default_conf, create_engine('sqlite://'))
|
||||
freqtrade = FreqtradeBot(default_conf)
|
||||
|
||||
trade_buy = Trade(
|
||||
pair='ETH/BTC',
|
||||
@@ -1056,7 +1076,7 @@ def test_handle_timedout_limit_buy(mocker, default_conf) -> None:
|
||||
cancel_order=cancel_order_mock
|
||||
)
|
||||
|
||||
freqtrade = FreqtradeBot(default_conf, create_engine('sqlite://'))
|
||||
freqtrade = FreqtradeBot(default_conf)
|
||||
|
||||
Trade.session = MagicMock()
|
||||
trade = MagicMock()
|
||||
@@ -1082,7 +1102,7 @@ def test_handle_timedout_limit_sell(mocker, default_conf) -> None:
|
||||
cancel_order=cancel_order_mock
|
||||
)
|
||||
|
||||
freqtrade = FreqtradeBot(default_conf, create_engine('sqlite://'))
|
||||
freqtrade = FreqtradeBot(default_conf)
|
||||
|
||||
trade = MagicMock()
|
||||
order = {'remaining': 1,
|
||||
@@ -1109,7 +1129,7 @@ def test_execute_sell_up(default_conf, ticker, fee, ticker_sell_up, mocker) -> N
|
||||
get_fee=fee
|
||||
)
|
||||
mocker.patch('freqtrade.fiat_convert.CryptoToFiatConverter._find_price', return_value=15000.0)
|
||||
freqtrade = FreqtradeBot(default_conf, create_engine('sqlite://'))
|
||||
freqtrade = FreqtradeBot(default_conf)
|
||||
|
||||
# Create some test data
|
||||
freqtrade.create_trade()
|
||||
@@ -1150,7 +1170,7 @@ def test_execute_sell_down(default_conf, ticker, fee, ticker_sell_down, mocker)
|
||||
get_ticker=ticker,
|
||||
get_fee=fee
|
||||
)
|
||||
freqtrade = FreqtradeBot(default_conf, create_engine('sqlite://'))
|
||||
freqtrade = FreqtradeBot(default_conf)
|
||||
|
||||
# Create some test data
|
||||
freqtrade.create_trade()
|
||||
@@ -1190,7 +1210,7 @@ def test_execute_sell_without_conf_sell_up(default_conf, ticker, fee,
|
||||
get_ticker=ticker,
|
||||
get_fee=fee
|
||||
)
|
||||
freqtrade = FreqtradeBot(default_conf, create_engine('sqlite://'))
|
||||
freqtrade = FreqtradeBot(default_conf)
|
||||
|
||||
# Create some test data
|
||||
freqtrade.create_trade()
|
||||
@@ -1231,7 +1251,7 @@ def test_execute_sell_without_conf_sell_down(default_conf, ticker, fee,
|
||||
get_ticker=ticker,
|
||||
get_fee=fee
|
||||
)
|
||||
freqtrade = FreqtradeBot(default_conf, create_engine('sqlite://'))
|
||||
freqtrade = FreqtradeBot(default_conf)
|
||||
|
||||
# Create some test data
|
||||
freqtrade.create_trade()
|
||||
@@ -1280,7 +1300,7 @@ def test_sell_profit_only_enable_profit(default_conf, limit_buy_order, fee, mock
|
||||
'use_sell_signal': True,
|
||||
'sell_profit_only': True,
|
||||
}
|
||||
freqtrade = FreqtradeBot(conf, create_engine('sqlite://'))
|
||||
freqtrade = FreqtradeBot(conf)
|
||||
freqtrade.create_trade()
|
||||
|
||||
trade = Trade.query.first()
|
||||
@@ -1313,7 +1333,7 @@ def test_sell_profit_only_disable_profit(default_conf, limit_buy_order, fee, moc
|
||||
'use_sell_signal': True,
|
||||
'sell_profit_only': False,
|
||||
}
|
||||
freqtrade = FreqtradeBot(conf, create_engine('sqlite://'))
|
||||
freqtrade = FreqtradeBot(conf)
|
||||
freqtrade.create_trade()
|
||||
|
||||
trade = Trade.query.first()
|
||||
@@ -1346,7 +1366,7 @@ def test_sell_profit_only_enable_loss(default_conf, limit_buy_order, fee, mocker
|
||||
'use_sell_signal': True,
|
||||
'sell_profit_only': True,
|
||||
}
|
||||
freqtrade = FreqtradeBot(conf, create_engine('sqlite://'))
|
||||
freqtrade = FreqtradeBot(conf)
|
||||
freqtrade.create_trade()
|
||||
|
||||
trade = Trade.query.first()
|
||||
@@ -1381,7 +1401,7 @@ def test_sell_profit_only_disable_loss(default_conf, limit_buy_order, fee, mocke
|
||||
'sell_profit_only': False,
|
||||
}
|
||||
|
||||
freqtrade = FreqtradeBot(conf, create_engine('sqlite://'))
|
||||
freqtrade = FreqtradeBot(conf)
|
||||
freqtrade.create_trade()
|
||||
|
||||
trade = Trade.query.first()
|
||||
@@ -1409,7 +1429,7 @@ def test_get_real_amount_quote(default_conf, trades_for_order, buy_order_fee, ca
|
||||
open_rate=0.245441,
|
||||
open_order_id="123456"
|
||||
)
|
||||
freqtrade = FreqtradeBot(default_conf, create_engine('sqlite://'))
|
||||
freqtrade = FreqtradeBot(default_conf)
|
||||
# Amount is reduced by "fee"
|
||||
assert freqtrade.get_real_amount(trade, buy_order_fee) == amount - (amount * 0.001)
|
||||
assert log_has('Applying fee on amount for Trade(id=None, pair=LTC/ETH, amount=8.00000000, '
|
||||
@@ -1436,7 +1456,7 @@ def test_get_real_amount_no_trade(default_conf, buy_order_fee, caplog, mocker):
|
||||
open_rate=0.245441,
|
||||
open_order_id="123456"
|
||||
)
|
||||
freqtrade = FreqtradeBot(default_conf, create_engine('sqlite://'))
|
||||
freqtrade = FreqtradeBot(default_conf)
|
||||
# Amount is reduced by "fee"
|
||||
assert freqtrade.get_real_amount(trade, buy_order_fee) == amount
|
||||
assert log_has('Applying fee on amount for Trade(id=None, pair=LTC/ETH, amount=8.00000000, '
|
||||
@@ -1463,7 +1483,7 @@ def test_get_real_amount_stake(default_conf, trades_for_order, buy_order_fee, ca
|
||||
open_rate=0.245441,
|
||||
open_order_id="123456"
|
||||
)
|
||||
freqtrade = FreqtradeBot(default_conf, create_engine('sqlite://'))
|
||||
freqtrade = FreqtradeBot(default_conf)
|
||||
# Amount does not change
|
||||
assert freqtrade.get_real_amount(trade, buy_order_fee) == amount
|
||||
|
||||
@@ -1489,7 +1509,7 @@ def test_get_real_amount_BNB(default_conf, trades_for_order, buy_order_fee, mock
|
||||
open_rate=0.245441,
|
||||
open_order_id="123456"
|
||||
)
|
||||
freqtrade = FreqtradeBot(default_conf, create_engine('sqlite://'))
|
||||
freqtrade = FreqtradeBot(default_conf)
|
||||
# Amount does not change
|
||||
assert freqtrade.get_real_amount(trade, buy_order_fee) == amount
|
||||
|
||||
@@ -1512,7 +1532,7 @@ def test_get_real_amount_multi(default_conf, trades_for_order2, buy_order_fee, c
|
||||
open_rate=0.245441,
|
||||
open_order_id="123456"
|
||||
)
|
||||
freqtrade = FreqtradeBot(default_conf, create_engine('sqlite://'))
|
||||
freqtrade = FreqtradeBot(default_conf)
|
||||
# Amount is reduced by "fee"
|
||||
assert freqtrade.get_real_amount(trade, buy_order_fee) == amount - (amount * 0.001)
|
||||
assert log_has('Applying fee on amount for Trade(id=None, pair=LTC/ETH, amount=8.00000000, '
|
||||
@@ -1540,7 +1560,7 @@ def test_get_real_amount_fromorder(default_conf, trades_for_order, buy_order_fee
|
||||
open_rate=0.245441,
|
||||
open_order_id="123456"
|
||||
)
|
||||
freqtrade = FreqtradeBot(default_conf, create_engine('sqlite://'))
|
||||
freqtrade = FreqtradeBot(default_conf)
|
||||
# Amount is reduced by "fee"
|
||||
assert freqtrade.get_real_amount(trade, limit_buy_order) == amount - 0.004
|
||||
assert log_has('Applying fee on amount for Trade(id=None, pair=LTC/ETH, amount=8.00000000, '
|
||||
@@ -1568,7 +1588,7 @@ def test_get_real_amount_invalid_order(default_conf, trades_for_order, buy_order
|
||||
open_rate=0.245441,
|
||||
open_order_id="123456"
|
||||
)
|
||||
freqtrade = FreqtradeBot(default_conf, create_engine('sqlite://'))
|
||||
freqtrade = FreqtradeBot(default_conf)
|
||||
# Amount does not change
|
||||
assert freqtrade.get_real_amount(trade, limit_buy_order) == amount
|
||||
|
||||
@@ -1593,6 +1613,6 @@ def test_get_real_amount_invalid(default_conf, trades_for_order, buy_order_fee,
|
||||
open_rate=0.245441,
|
||||
open_order_id="123456"
|
||||
)
|
||||
freqtrade = FreqtradeBot(default_conf, create_engine('sqlite://'))
|
||||
freqtrade = FreqtradeBot(default_conf)
|
||||
# Amount does not change
|
||||
assert freqtrade.get_real_amount(trade, buy_order_fee) == amount
|
||||
|
@@ -1,9 +1,11 @@
|
||||
# pragma pylint: disable=missing-docstring, C0103
|
||||
import os
|
||||
from copy import deepcopy
|
||||
from unittest.mock import MagicMock
|
||||
|
||||
import pytest
|
||||
from sqlalchemy import create_engine
|
||||
|
||||
from freqtrade import constants, OperationalException
|
||||
from freqtrade.persistence import Trade, init, clean_dry_run_db
|
||||
|
||||
|
||||
@@ -21,77 +23,54 @@ def test_init_create_session(default_conf, mocker):
|
||||
assert 'Session' in type(Trade.session).__name__
|
||||
|
||||
|
||||
def test_init_dry_run_db(default_conf, mocker):
|
||||
default_conf.update({'dry_run_db': True})
|
||||
mocker.patch.dict('freqtrade.persistence._CONF', default_conf)
|
||||
def test_init_custom_db_url(default_conf, mocker):
|
||||
conf = deepcopy(default_conf)
|
||||
|
||||
# First, protect the existing 'tradesv3.dry_run.sqlite' (Do not delete user data)
|
||||
dry_run_db = 'tradesv3.dry_run.sqlite'
|
||||
dry_run_db_swp = dry_run_db + '.swp'
|
||||
# Update path to a value other than default, but still in-memory
|
||||
conf.update({'db_url': 'sqlite:///tmp/freqtrade2_test.sqlite'})
|
||||
create_engine_mock = mocker.patch('freqtrade.persistence.create_engine', MagicMock())
|
||||
mocker.patch.dict('freqtrade.persistence._CONF', conf)
|
||||
|
||||
if os.path.isfile(dry_run_db):
|
||||
os.rename(dry_run_db, dry_run_db_swp)
|
||||
|
||||
# Check if the new tradesv3.dry_run.sqlite was created
|
||||
init(default_conf)
|
||||
assert os.path.isfile(dry_run_db) is True
|
||||
|
||||
# Delete the file made for this unitest and rollback to the previous
|
||||
# tradesv3.dry_run.sqlite file
|
||||
|
||||
# 1. Delete file from the test
|
||||
if os.path.isfile(dry_run_db):
|
||||
os.remove(dry_run_db)
|
||||
|
||||
# 2. Rollback to the initial file
|
||||
if os.path.isfile(dry_run_db_swp):
|
||||
os.rename(dry_run_db_swp, dry_run_db)
|
||||
init(conf)
|
||||
assert create_engine_mock.call_count == 1
|
||||
assert create_engine_mock.mock_calls[0][1][0] == 'sqlite:///tmp/freqtrade2_test.sqlite'
|
||||
|
||||
|
||||
def test_init_dry_run_without_db(default_conf, mocker):
|
||||
default_conf.update({'dry_run_db': False})
|
||||
mocker.patch.dict('freqtrade.persistence._CONF', default_conf)
|
||||
def test_init_invalid_db_url(default_conf, mocker):
|
||||
conf = deepcopy(default_conf)
|
||||
|
||||
# First, protect the existing 'tradesv3.dry_run.sqlite' (Do not delete user data)
|
||||
dry_run_db = 'tradesv3.dry_run.sqlite'
|
||||
dry_run_db_swp = dry_run_db + '.swp'
|
||||
# Update path to a value other than default, but still in-memory
|
||||
conf.update({'db_url': 'unknown:///some.url'})
|
||||
mocker.patch.dict('freqtrade.persistence._CONF', conf)
|
||||
|
||||
if os.path.isfile(dry_run_db):
|
||||
os.rename(dry_run_db, dry_run_db_swp)
|
||||
|
||||
# Check if the new tradesv3.dry_run.sqlite was created
|
||||
init(default_conf)
|
||||
assert os.path.isfile(dry_run_db) is False
|
||||
|
||||
# Rollback to the initial 'tradesv3.dry_run.sqlite' file
|
||||
if os.path.isfile(dry_run_db_swp):
|
||||
os.rename(dry_run_db_swp, dry_run_db)
|
||||
with pytest.raises(OperationalException, match=r'.*no valid database URL*'):
|
||||
init(conf)
|
||||
|
||||
|
||||
def test_init_prod_db(default_conf, mocker):
|
||||
default_conf.update({'dry_run': False})
|
||||
mocker.patch.dict('freqtrade.persistence._CONF', default_conf)
|
||||
conf = deepcopy(default_conf)
|
||||
conf.update({'dry_run': False})
|
||||
conf.update({'db_url': constants.DEFAULT_DB_PROD_URL})
|
||||
|
||||
# First, protect the existing 'tradesv3.sqlite' (Do not delete user data)
|
||||
prod_db = 'tradesv3.sqlite'
|
||||
prod_db_swp = prod_db + '.swp'
|
||||
create_engine_mock = mocker.patch('freqtrade.persistence.create_engine', MagicMock())
|
||||
mocker.patch.dict('freqtrade.persistence._CONF', conf)
|
||||
|
||||
if os.path.isfile(prod_db):
|
||||
os.rename(prod_db, prod_db_swp)
|
||||
init(conf)
|
||||
assert create_engine_mock.call_count == 1
|
||||
assert create_engine_mock.mock_calls[0][1][0] == 'sqlite:///tradesv3.sqlite'
|
||||
|
||||
# Check if the new tradesv3.sqlite was created
|
||||
init(default_conf)
|
||||
assert os.path.isfile(prod_db) is True
|
||||
|
||||
# Delete the file made for this unitest and rollback to the previous tradesv3.sqlite file
|
||||
def test_init_dryrun_db(default_conf, mocker):
|
||||
conf = deepcopy(default_conf)
|
||||
conf.update({'dry_run': True})
|
||||
conf.update({'db_url': constants.DEFAULT_DB_DRYRUN_URL})
|
||||
|
||||
# 1. Delete file from the test
|
||||
if os.path.isfile(prod_db):
|
||||
os.remove(prod_db)
|
||||
create_engine_mock = mocker.patch('freqtrade.persistence.create_engine', MagicMock())
|
||||
mocker.patch.dict('freqtrade.persistence._CONF', conf)
|
||||
|
||||
# Rollback to the initial 'tradesv3.sqlite' file
|
||||
if os.path.isfile(prod_db_swp):
|
||||
os.rename(prod_db_swp, prod_db)
|
||||
init(conf)
|
||||
assert create_engine_mock.call_count == 1
|
||||
assert create_engine_mock.mock_calls[0][1][0] == 'sqlite://'
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("init_persistence")
|
||||
@@ -328,7 +307,7 @@ def test_calc_profit_percent(limit_buy_order, limit_sell_order, fee):
|
||||
|
||||
|
||||
def test_clean_dry_run_db(default_conf, fee):
|
||||
init(default_conf, create_engine('sqlite://'))
|
||||
init(default_conf)
|
||||
|
||||
# Simulate dry_run entries
|
||||
trade = Trade(
|
||||
@@ -377,7 +356,7 @@ def test_clean_dry_run_db(default_conf, fee):
|
||||
assert len(Trade.query.filter(Trade.open_order_id.isnot(None)).all()) == 1
|
||||
|
||||
|
||||
def test_migrate_old(default_conf, fee):
|
||||
def test_migrate_old(mocker, default_conf, fee):
|
||||
"""
|
||||
Test Database migration(starting with old pairformat)
|
||||
"""
|
||||
@@ -409,11 +388,13 @@ def test_migrate_old(default_conf, fee):
|
||||
amount=amount
|
||||
)
|
||||
engine = create_engine('sqlite://')
|
||||
mocker.patch('freqtrade.persistence.create_engine', lambda *args, **kwargs: engine)
|
||||
|
||||
# Create table using the old format
|
||||
engine.execute(create_table_old)
|
||||
engine.execute(insert_table_old)
|
||||
# Run init to test migration
|
||||
init(default_conf, engine)
|
||||
init(default_conf)
|
||||
|
||||
assert len(Trade.query.filter(Trade.id == 1).all()) == 1
|
||||
trade = Trade.query.filter(Trade.id == 1).first()
|
||||
@@ -428,7 +409,7 @@ def test_migrate_old(default_conf, fee):
|
||||
assert trade.exchange == "bittrex"
|
||||
|
||||
|
||||
def test_migrate_new(default_conf, fee):
|
||||
def test_migrate_new(mocker, default_conf, fee):
|
||||
"""
|
||||
Test Database migration (starting with new pairformat)
|
||||
"""
|
||||
@@ -460,11 +441,13 @@ def test_migrate_new(default_conf, fee):
|
||||
amount=amount
|
||||
)
|
||||
engine = create_engine('sqlite://')
|
||||
mocker.patch('freqtrade.persistence.create_engine', lambda *args, **kwargs: engine)
|
||||
|
||||
# Create table using the old format
|
||||
engine.execute(create_table_old)
|
||||
engine.execute(insert_table_old)
|
||||
# Run init to test migration
|
||||
init(default_conf, engine)
|
||||
init(default_conf)
|
||||
|
||||
assert len(Trade.query.filter(Trade.id == 1).all()) == 1
|
||||
trade = Trade.query.filter(Trade.id == 1).first()
|
||||
|
Reference in New Issue
Block a user