Merge branch 'develop' into feat/short
This commit is contained in:
@@ -8,12 +8,12 @@ from zipfile import ZipFile
|
||||
import arrow
|
||||
import pytest
|
||||
|
||||
from freqtrade.commands import (start_convert_data, start_create_userdir, start_download_data,
|
||||
start_hyperopt_list, start_hyperopt_show, start_install_ui,
|
||||
start_list_data, start_list_exchanges, start_list_markets,
|
||||
start_list_strategies, start_list_timeframes, start_new_strategy,
|
||||
start_show_trades, start_test_pairlist, start_trading,
|
||||
start_webserver)
|
||||
from freqtrade.commands import (start_convert_data, start_convert_trades, start_create_userdir,
|
||||
start_download_data, start_hyperopt_list, start_hyperopt_show,
|
||||
start_install_ui, start_list_data, start_list_exchanges,
|
||||
start_list_markets, start_list_strategies, start_list_timeframes,
|
||||
start_new_strategy, start_show_trades, start_test_pairlist,
|
||||
start_trading, start_webserver)
|
||||
from freqtrade.commands.deploy_commands import (clean_ui_subdir, download_and_install_ui,
|
||||
get_ui_download_url, read_ui_version)
|
||||
from freqtrade.configuration import setup_utils_configuration
|
||||
@@ -208,11 +208,10 @@ def test_list_timeframes(mocker, capsys):
|
||||
assert re.search(r"^1d$", captured.out, re.MULTILINE)
|
||||
|
||||
|
||||
def test_list_markets(mocker, markets, capsys):
|
||||
def test_list_markets(mocker, markets_static, capsys):
|
||||
|
||||
api_mock = MagicMock()
|
||||
api_mock.markets = markets
|
||||
patch_exchange(mocker, api_mock=api_mock, id='bittrex')
|
||||
patch_exchange(mocker, api_mock=api_mock, id='bittrex', mock_markets=markets_static)
|
||||
|
||||
# Test with no --config
|
||||
args = [
|
||||
@@ -237,7 +236,7 @@ def test_list_markets(mocker, markets, capsys):
|
||||
"TKN/BTC, XLTCUSDT, XRP/BTC.\n"
|
||||
in captured.out)
|
||||
|
||||
patch_exchange(mocker, api_mock=api_mock, id="binance")
|
||||
patch_exchange(mocker, api_mock=api_mock, id="binance", mock_markets=markets_static)
|
||||
# Test with --exchange
|
||||
args = [
|
||||
"list-markets",
|
||||
@@ -250,7 +249,7 @@ def test_list_markets(mocker, markets, capsys):
|
||||
assert re.match("\nExchange Binance has 10 active markets:\n",
|
||||
captured.out)
|
||||
|
||||
patch_exchange(mocker, api_mock=api_mock, id="bittrex")
|
||||
patch_exchange(mocker, api_mock=api_mock, id="bittrex", mock_markets=markets_static)
|
||||
# Test with --all: all markets
|
||||
args = [
|
||||
"list-markets", "--all",
|
||||
@@ -760,6 +759,22 @@ def test_download_data_trades(mocker, caplog):
|
||||
assert convert_mock.call_count == 1
|
||||
|
||||
|
||||
def test_start_convert_trades(mocker, caplog):
|
||||
convert_mock = mocker.patch('freqtrade.commands.data_commands.convert_trades_to_ohlcv',
|
||||
MagicMock(return_value=[]))
|
||||
patch_exchange(mocker)
|
||||
mocker.patch(
|
||||
'freqtrade.exchange.Exchange.markets', PropertyMock(return_value={})
|
||||
)
|
||||
args = [
|
||||
"trades-to-ohlcv",
|
||||
"--exchange", "kraken",
|
||||
"--pairs", "ETH/BTC", "XRP/BTC",
|
||||
]
|
||||
start_convert_trades(get_args(args))
|
||||
assert convert_mock.call_count == 1
|
||||
|
||||
|
||||
def test_start_list_strategies(mocker, caplog, capsys):
|
||||
|
||||
args = [
|
||||
|
@@ -102,8 +102,10 @@ def patch_exchange(
|
||||
mocker.patch('freqtrade.exchange.Exchange.precisionMode', PropertyMock(return_value=2))
|
||||
|
||||
if mock_markets:
|
||||
if isinstance(mock_markets, bool):
|
||||
mock_markets = get_markets()
|
||||
mocker.patch('freqtrade.exchange.Exchange.markets',
|
||||
PropertyMock(return_value=get_markets()))
|
||||
PropertyMock(return_value=mock_markets))
|
||||
|
||||
if mock_supported_modes:
|
||||
mocker.patch(
|
||||
@@ -462,6 +464,8 @@ def markets():
|
||||
|
||||
|
||||
def get_markets():
|
||||
# See get_markets_static() for immutable markets and do not modify them unless absolutely
|
||||
# necessary!
|
||||
return {
|
||||
'ETH/BTC': {
|
||||
'id': 'ethbtc',
|
||||
@@ -778,11 +782,22 @@ def get_markets():
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def shitcoinmarkets(markets):
|
||||
def markets_static():
|
||||
# These markets are used in some tests that would need adaptation should anything change in
|
||||
# market list. Do not modify this list without a good reason! Do not modify market parameters
|
||||
# of listed pairs in get_markets() without a good reason either!
|
||||
static_markets = ['BLK/BTC', 'BTT/BTC', 'ETH/BTC', 'ETH/USDT', 'LTC/BTC', 'LTC/ETH', 'LTC/USD',
|
||||
'LTC/USDT', 'NEO/BTC', 'TKN/BTC', 'XLTCUSDT', 'XRP/BTC']
|
||||
all_markets = get_markets()
|
||||
return {m: all_markets[m] for m in static_markets}
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def shitcoinmarkets(markets_static):
|
||||
"""
|
||||
Fixture with shitcoin markets - used to test filters in pairlists
|
||||
"""
|
||||
shitmarkets = deepcopy(markets)
|
||||
shitmarkets = deepcopy(markets_static)
|
||||
shitmarkets.update({
|
||||
'HOT/BTC': {
|
||||
'id': 'HOTBTC',
|
||||
@@ -1788,14 +1803,6 @@ def trades_for_order2():
|
||||
'fee': {'cost': 0.004, 'currency': 'LTC'}}]
|
||||
|
||||
|
||||
@pytest.fixture(scope="function")
|
||||
def trades_for_order3(trades_for_order2):
|
||||
# Different fee currencies for each trade
|
||||
trades_for_order = deepcopy(trades_for_order2)
|
||||
trades_for_order[0]['fee'] = {'cost': 0.02, 'currency': 'BNB'}
|
||||
return trades_for_order
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def buy_order_fee():
|
||||
return {
|
||||
|
@@ -2806,7 +2806,7 @@ def test_get_valid_pair_combination(default_conf, mocker, markets):
|
||||
(['LTC'], ['NONEXISTENT'], False, False,
|
||||
[]),
|
||||
])
|
||||
def test_get_markets(default_conf, mocker, markets,
|
||||
def test_get_markets(default_conf, mocker, markets_static,
|
||||
base_currencies, quote_currencies, pairs_only, active_only,
|
||||
expected_keys):
|
||||
mocker.patch.multiple('freqtrade.exchange.Exchange',
|
||||
@@ -2814,7 +2814,7 @@ def test_get_markets(default_conf, mocker, markets,
|
||||
_load_async_markets=MagicMock(),
|
||||
validate_pairs=MagicMock(),
|
||||
validate_timeframes=MagicMock(),
|
||||
markets=PropertyMock(return_value=markets))
|
||||
markets=PropertyMock(return_value=markets_static))
|
||||
ex = Exchange(default_conf)
|
||||
pairs = ex.get_markets(base_currencies, quote_currencies, pairs_only, active_only)
|
||||
assert sorted(pairs.keys()) == sorted(expected_keys)
|
||||
|
@@ -131,9 +131,9 @@ def test_load_pairlist_noexist(mocker, markets, default_conf):
|
||||
default_conf, {}, 1)
|
||||
|
||||
|
||||
def test_load_pairlist_verify_multi(mocker, markets, default_conf):
|
||||
def test_load_pairlist_verify_multi(mocker, markets_static, default_conf):
|
||||
freqtrade = get_patched_freqtradebot(mocker, default_conf)
|
||||
mocker.patch('freqtrade.exchange.Exchange.markets', PropertyMock(return_value=markets))
|
||||
mocker.patch('freqtrade.exchange.Exchange.markets', PropertyMock(return_value=markets_static))
|
||||
plm = PairListManager(freqtrade.exchange, default_conf)
|
||||
# Call different versions one after the other, should always consider what was passed in
|
||||
# and have no side-effects (therefore the same check multiple times)
|
||||
|
@@ -125,7 +125,7 @@ def test_stoploss_guard(mocker, default_conf, fee, caplog):
|
||||
# Test 5m after lock-period - this should try and relock the pair, but end-time
|
||||
# should be the previous end-time
|
||||
end_time = PairLocks.get_pair_longest_lock('*').lock_end_time + timedelta(minutes=5)
|
||||
assert freqtrade.protections.global_stop(end_time)
|
||||
freqtrade.protections.global_stop(end_time)
|
||||
assert not PairLocks.is_global_lock(end_time)
|
||||
|
||||
|
||||
@@ -182,7 +182,7 @@ def test_stoploss_guard_perpair(mocker, default_conf, fee, caplog, only_per_pair
|
||||
min_ago_open=180, min_ago_close=30, profit_rate=0.9,
|
||||
))
|
||||
|
||||
assert freqtrade.protections.stop_per_pair(pair)
|
||||
freqtrade.protections.stop_per_pair(pair)
|
||||
assert freqtrade.protections.global_stop() != only_per_pair
|
||||
assert PairLocks.is_pair_locked(pair)
|
||||
assert PairLocks.is_global_lock() != only_per_pair
|
||||
|
@@ -1313,6 +1313,34 @@ def test_send_msg_buy_cancel_notification(default_conf, mocker) -> None:
|
||||
'Reason: cancelled due to timeout.')
|
||||
|
||||
|
||||
def test_send_msg_protection_notification(default_conf, mocker, time_machine) -> None:
|
||||
|
||||
default_conf['telegram']['notification_settings']['protection_trigger'] = 'on'
|
||||
|
||||
telegram, _, msg_mock = get_telegram_testobject(mocker, default_conf)
|
||||
time_machine.move_to("2021-09-01 05:00:00 +00:00")
|
||||
lock = PairLocks.lock_pair('ETH/BTC', arrow.utcnow().shift(minutes=6).datetime, 'randreason')
|
||||
msg = {
|
||||
'type': RPCMessageType.PROTECTION_TRIGGER,
|
||||
}
|
||||
msg.update(lock.to_json())
|
||||
telegram.send_msg(msg)
|
||||
assert (msg_mock.call_args[0][0] == "*Protection* triggered due to randreason. "
|
||||
"`ETH/BTC` will be locked until `2021-09-01 05:10:00`.")
|
||||
|
||||
msg_mock.reset_mock()
|
||||
# Test global protection
|
||||
|
||||
msg = {
|
||||
'type': RPCMessageType.PROTECTION_TRIGGER_GLOBAL,
|
||||
}
|
||||
lock = PairLocks.lock_pair('*', arrow.utcnow().shift(minutes=100).datetime, 'randreason')
|
||||
msg.update(lock.to_json())
|
||||
telegram.send_msg(msg)
|
||||
assert (msg_mock.call_args[0][0] == "*Protection* triggered due to randreason. "
|
||||
"*All pairs* will be locked until `2021-09-01 06:45:00`.")
|
||||
|
||||
|
||||
def test_send_msg_buy_fill_notification(default_conf, mocker) -> None:
|
||||
|
||||
default_conf['telegram']['notification_settings']['buy_fill'] = 'on'
|
||||
|
@@ -416,6 +416,29 @@ def test_enter_positions_global_pairlock(default_conf, ticker, limit_buy_order,
|
||||
assert log_has_re(message, caplog)
|
||||
|
||||
|
||||
def test_handle_protections(mocker, default_conf, fee):
|
||||
default_conf['protections'] = [
|
||||
{"method": "CooldownPeriod", "stop_duration": 60},
|
||||
{
|
||||
"method": "StoplossGuard",
|
||||
"lookback_period_candles": 24,
|
||||
"trade_limit": 4,
|
||||
"stop_duration_candles": 4,
|
||||
"only_per_pair": False
|
||||
}
|
||||
]
|
||||
|
||||
freqtrade = get_patched_freqtradebot(mocker, default_conf)
|
||||
freqtrade.protections._protection_handlers[1].global_stop = MagicMock(
|
||||
return_value=(True, arrow.utcnow().shift(hours=1).datetime, "asdf"))
|
||||
create_mock_trades(fee)
|
||||
freqtrade.handle_protections('ETC/BTC')
|
||||
send_msg_mock = freqtrade.rpc.send_msg
|
||||
assert send_msg_mock.call_count == 2
|
||||
assert send_msg_mock.call_args_list[0][0][0]['type'] == RPCMessageType.PROTECTION_TRIGGER
|
||||
assert send_msg_mock.call_args_list[1][0][0]['type'] == RPCMessageType.PROTECTION_TRIGGER_GLOBAL
|
||||
|
||||
|
||||
def test_create_trade_no_signal(default_conf, fee, mocker) -> None:
|
||||
default_conf['dry_run'] = True
|
||||
|
||||
@@ -3508,6 +3531,7 @@ def test_get_real_amount_quote(default_conf, trades_for_order, buy_order_fee, fe
|
||||
)
|
||||
freqtrade = get_patched_freqtradebot(mocker, default_conf)
|
||||
|
||||
caplog.clear()
|
||||
# Amount is reduced by "fee"
|
||||
assert freqtrade.get_real_amount(trade, buy_order_fee) == amount - (amount * 0.001)
|
||||
assert log_has(
|
||||
@@ -3567,8 +3591,35 @@ def test_get_real_amount_no_trade(default_conf, buy_order_fee, caplog, mocker, f
|
||||
)
|
||||
|
||||
|
||||
def test_get_real_amount_stake(default_conf, trades_for_order, buy_order_fee, fee, mocker):
|
||||
trades_for_order[0]['fee']['currency'] = 'ETH'
|
||||
@pytest.mark.parametrize(
|
||||
'fee_par,fee_reduction_amount,use_ticker_rate,expected_log', [
|
||||
# basic, amount does not change
|
||||
({'cost': 0.008, 'currency': 'ETH'}, 0, False, None),
|
||||
# no currency in fee
|
||||
({'cost': 0.004, 'currency': None}, 0, True, None),
|
||||
# BNB no rate
|
||||
({'cost': 0.00094518, 'currency': 'BNB'}, 0, True, (
|
||||
'Fee for Trade Trade(id=None, pair=LTC/ETH, amount=8.00000000, is_short=False, '
|
||||
'leverage=1.0, open_rate=0.24544100, open_since=closed) [buy]: 0.00094518 BNB -'
|
||||
' rate: None'
|
||||
)),
|
||||
# from order
|
||||
({'cost': 0.004, 'currency': 'LTC'}, 0.004, False, (
|
||||
'Applying fee on amount for Trade(id=None, pair=LTC/ETH, amount=8.00000000, '
|
||||
'is_short=False, leverage=1.0, open_rate=0.24544100, open_since=closed) (from'
|
||||
' 8.0 to 7.996).'
|
||||
)),
|
||||
# invalid, no currency in from fee dict
|
||||
({'cost': 0.008, 'currency': None}, 0, True, None),
|
||||
])
|
||||
def test_get_real_amount(
|
||||
default_conf, trades_for_order, buy_order_fee, fee, mocker, caplog,
|
||||
fee_par, fee_reduction_amount, use_ticker_rate, expected_log
|
||||
):
|
||||
|
||||
buy_order = deepcopy(buy_order_fee)
|
||||
buy_order['fee'] = fee_par
|
||||
trades_for_order[0]['fee'] = fee_par
|
||||
|
||||
mocker.patch('freqtrade.exchange.Exchange.get_trades_for_order', return_value=trades_for_order)
|
||||
amount = sum(x['amount'] for x in trades_for_order)
|
||||
@@ -3583,19 +3634,38 @@ def test_get_real_amount_stake(default_conf, trades_for_order, buy_order_fee, fe
|
||||
)
|
||||
freqtrade = get_patched_freqtradebot(mocker, default_conf)
|
||||
|
||||
# Amount does not change
|
||||
assert freqtrade.get_real_amount(trade, buy_order_fee) == amount
|
||||
if not use_ticker_rate:
|
||||
mocker.patch('freqtrade.exchange.Exchange.fetch_ticker', side_effect=ExchangeError)
|
||||
|
||||
caplog.clear()
|
||||
assert freqtrade.get_real_amount(trade, buy_order) == amount - fee_reduction_amount
|
||||
|
||||
if expected_log:
|
||||
assert log_has(expected_log, caplog)
|
||||
|
||||
|
||||
def test_get_real_amount_no_currency_in_fee(default_conf, trades_for_order, buy_order_fee,
|
||||
fee, mocker):
|
||||
@pytest.mark.parametrize(
|
||||
'fee_cost, fee_currency, fee_reduction_amount, expected_fee, expected_log_amount', [
|
||||
# basic, amount is reduced by fee
|
||||
(None, None, 0.001, 0.001, 7.992),
|
||||
# different fee currency on both trades, fee is average of both trade's fee
|
||||
(0.02, 'BNB', 0.0005, 0.001518575, 7.996),
|
||||
])
|
||||
def test_get_real_amount_multi(
|
||||
default_conf, trades_for_order2, buy_order_fee, caplog, fee, mocker, markets,
|
||||
fee_cost, fee_currency, fee_reduction_amount, expected_fee, expected_log_amount,
|
||||
):
|
||||
|
||||
limit_buy_order = deepcopy(buy_order_fee)
|
||||
limit_buy_order['fee'] = {'cost': 0.004, 'currency': None}
|
||||
trades_for_order[0]['fee']['currency'] = None
|
||||
trades_for_order = deepcopy(trades_for_order2)
|
||||
if fee_cost:
|
||||
trades_for_order[0]['fee']['cost'] = fee_cost
|
||||
if fee_currency:
|
||||
trades_for_order[0]['fee']['currency'] = fee_currency
|
||||
|
||||
mocker.patch('freqtrade.exchange.Exchange.get_trades_for_order', return_value=trades_for_order)
|
||||
amount = sum(x['amount'] for x in trades_for_order)
|
||||
amount = float(sum(x['amount'] for x in trades_for_order))
|
||||
default_conf['stake_currency'] = "ETH"
|
||||
|
||||
trade = Trade(
|
||||
pair='LTC/ETH',
|
||||
amount=amount,
|
||||
@@ -3605,78 +3675,7 @@ def test_get_real_amount_no_currency_in_fee(default_conf, trades_for_order, buy_
|
||||
open_rate=0.245441,
|
||||
open_order_id="123456"
|
||||
)
|
||||
freqtrade = get_patched_freqtradebot(mocker, default_conf)
|
||||
|
||||
# Amount does not change
|
||||
assert freqtrade.get_real_amount(trade, limit_buy_order) == amount
|
||||
|
||||
|
||||
def test_get_real_amount_BNB(default_conf, trades_for_order, buy_order_fee, fee, mocker):
|
||||
trades_for_order[0]['fee']['currency'] = 'BNB'
|
||||
trades_for_order[0]['fee']['cost'] = 0.00094518
|
||||
|
||||
mocker.patch('freqtrade.exchange.Exchange.get_trades_for_order', return_value=trades_for_order)
|
||||
amount = sum(x['amount'] for x in trades_for_order)
|
||||
trade = Trade(
|
||||
pair='LTC/ETH',
|
||||
amount=amount,
|
||||
exchange='binance',
|
||||
fee_open=fee.return_value,
|
||||
fee_close=fee.return_value,
|
||||
open_rate=0.245441,
|
||||
open_order_id="123456"
|
||||
)
|
||||
freqtrade = get_patched_freqtradebot(mocker, default_conf)
|
||||
|
||||
# Amount does not change
|
||||
assert freqtrade.get_real_amount(trade, buy_order_fee) == amount
|
||||
|
||||
|
||||
def test_get_real_amount_multi(default_conf, trades_for_order2, buy_order_fee, caplog, fee, mocker):
|
||||
mocker.patch('freqtrade.exchange.Exchange.get_trades_for_order', return_value=trades_for_order2)
|
||||
amount = float(sum(x['amount'] for x in trades_for_order2))
|
||||
trade = Trade(
|
||||
pair='LTC/ETH',
|
||||
amount=amount,
|
||||
exchange='binance',
|
||||
fee_open=fee.return_value,
|
||||
fee_close=fee.return_value,
|
||||
open_rate=0.245441,
|
||||
open_order_id="123456"
|
||||
)
|
||||
freqtrade = get_patched_freqtradebot(mocker, 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, is_short=False,'
|
||||
' leverage=1.0, open_rate=0.24544100, open_since=closed) (from 8.0 to 7.992).',
|
||||
caplog
|
||||
)
|
||||
|
||||
assert trade.fee_open == 0.001
|
||||
assert trade.fee_close == 0.001
|
||||
assert trade.fee_open_cost is not None
|
||||
assert trade.fee_open_currency is not None
|
||||
assert trade.fee_close_cost is None
|
||||
assert trade.fee_close_currency is None
|
||||
|
||||
|
||||
def test_get_real_amount_multi2(default_conf, trades_for_order3, buy_order_fee, caplog, fee,
|
||||
mocker, markets):
|
||||
# Different fee currency on both trades
|
||||
mocker.patch('freqtrade.exchange.Exchange.get_trades_for_order', return_value=trades_for_order3)
|
||||
amount = float(sum(x['amount'] for x in trades_for_order3))
|
||||
default_conf['stake_currency'] = 'ETH'
|
||||
trade = Trade(
|
||||
pair='LTC/ETH',
|
||||
amount=amount,
|
||||
exchange='binance',
|
||||
fee_open=fee.return_value,
|
||||
fee_close=fee.return_value,
|
||||
open_rate=0.245441,
|
||||
open_order_id="123456"
|
||||
)
|
||||
# Fake markets entry to enable fee parsing
|
||||
markets['BNB/ETH'] = markets['ETH/BTC']
|
||||
freqtrade = get_patched_freqtradebot(mocker, default_conf)
|
||||
@@ -3685,50 +3684,25 @@ def test_get_real_amount_multi2(default_conf, trades_for_order3, buy_order_fee,
|
||||
return_value={'ask': 0.19, 'last': 0.2})
|
||||
|
||||
# Amount is reduced by "fee"
|
||||
assert freqtrade.get_real_amount(trade, buy_order_fee) == amount - (amount * 0.0005)
|
||||
expected_amount = amount - (amount * fee_reduction_amount)
|
||||
assert freqtrade.get_real_amount(trade, buy_order_fee) == expected_amount
|
||||
assert log_has(
|
||||
'Applying fee on amount for Trade(id=None, pair=LTC/ETH, amount=8.00000000, is_short=False,'
|
||||
' leverage=1.0, open_rate=0.24544100, open_since=closed) (from 8.0 to 7.996).',
|
||||
(
|
||||
'Applying fee on amount for Trade(id=None, pair=LTC/ETH, amount=8.00000000, '
|
||||
'is_short=False, leverage=1.0, open_rate=0.24544100, open_since=closed) '
|
||||
f'(from 8.0 to {expected_log_amount}).'
|
||||
),
|
||||
caplog
|
||||
)
|
||||
# Overall fee is average of both trade's fee
|
||||
assert trade.fee_open == 0.001518575
|
||||
|
||||
assert trade.fee_open == expected_fee
|
||||
assert trade.fee_close == expected_fee
|
||||
assert trade.fee_open_cost is not None
|
||||
assert trade.fee_open_currency is not None
|
||||
assert trade.fee_close_cost is None
|
||||
assert trade.fee_close_currency is None
|
||||
|
||||
|
||||
def test_get_real_amount_fromorder(default_conf, trades_for_order, buy_order_fee, fee,
|
||||
caplog, mocker):
|
||||
limit_buy_order = deepcopy(buy_order_fee)
|
||||
limit_buy_order['fee'] = {'cost': 0.004, 'currency': 'LTC'}
|
||||
|
||||
mocker.patch('freqtrade.exchange.Exchange.get_trades_for_order',
|
||||
return_value=[trades_for_order])
|
||||
amount = float(sum(x['amount'] for x in trades_for_order))
|
||||
trade = Trade(
|
||||
pair='LTC/ETH',
|
||||
amount=amount,
|
||||
exchange='binance',
|
||||
fee_open=fee.return_value,
|
||||
fee_close=fee.return_value,
|
||||
open_rate=0.245441,
|
||||
open_order_id="123456"
|
||||
)
|
||||
freqtrade = get_patched_freqtradebot(mocker, default_conf)
|
||||
# Ticker rate cannot be found for this to work.
|
||||
mocker.patch('freqtrade.exchange.Exchange.fetch_ticker', side_effect=ExchangeError)
|
||||
|
||||
# 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, is_short=False,'
|
||||
' leverage=1.0, open_rate=0.24544100, open_since=closed) (from 8.0 to 7.996).',
|
||||
caplog
|
||||
)
|
||||
|
||||
|
||||
def test_get_real_amount_invalid_order(default_conf, trades_for_order, buy_order_fee, fee, mocker):
|
||||
limit_buy_order = deepcopy(buy_order_fee)
|
||||
limit_buy_order['fee'] = {'cost': 0.004}
|
||||
@@ -3796,27 +3770,6 @@ def test_get_real_amount_wrong_amount_rounding(default_conf, trades_for_order, b
|
||||
abs_tol=MATH_CLOSE_PREC,)
|
||||
|
||||
|
||||
def test_get_real_amount_invalid(default_conf, trades_for_order, buy_order_fee, fee, mocker):
|
||||
# Remove "Currency" from fee dict
|
||||
trades_for_order[0]['fee'] = {'cost': 0.008}
|
||||
|
||||
mocker.patch('freqtrade.exchange.Exchange.get_trades_for_order', return_value=trades_for_order)
|
||||
amount = sum(x['amount'] for x in trades_for_order)
|
||||
trade = Trade(
|
||||
pair='LTC/ETH',
|
||||
amount=amount,
|
||||
exchange='binance',
|
||||
open_rate=0.245441,
|
||||
fee_open=fee.return_value,
|
||||
fee_close=fee.return_value,
|
||||
|
||||
open_order_id="123456"
|
||||
)
|
||||
freqtrade = get_patched_freqtradebot(mocker, default_conf)
|
||||
# Amount does not change
|
||||
assert freqtrade.get_real_amount(trade, buy_order_fee) == amount
|
||||
|
||||
|
||||
def test_get_real_amount_open_trade(default_conf, fee, mocker):
|
||||
amount = 12345
|
||||
trade = Trade(
|
||||
@@ -3867,10 +3820,14 @@ def test_apply_fee_conditional(default_conf, fee, caplog, mocker,
|
||||
assert walletmock.call_count == 1
|
||||
|
||||
|
||||
@pytest.mark.parametrize("delta, is_high_delta", [
|
||||
(0.1, False),
|
||||
(100, True),
|
||||
])
|
||||
def test_order_book_depth_of_market(default_conf, ticker, limit_buy_order_open, limit_buy_order,
|
||||
fee, mocker, order_book_l2):
|
||||
fee, mocker, order_book_l2, delta, is_high_delta):
|
||||
default_conf['bid_strategy']['check_depth_of_market']['enabled'] = True
|
||||
default_conf['bid_strategy']['check_depth_of_market']['bids_to_ask_delta'] = 0.1
|
||||
default_conf['bid_strategy']['check_depth_of_market']['bids_to_ask_delta'] = delta
|
||||
patch_RPCManager(mocker)
|
||||
patch_exchange(mocker)
|
||||
mocker.patch('freqtrade.exchange.Exchange.fetch_l2_order_book', order_book_l2)
|
||||
@@ -3888,42 +3845,22 @@ def test_order_book_depth_of_market(default_conf, ticker, limit_buy_order_open,
|
||||
freqtrade.enter_positions()
|
||||
|
||||
trade = Trade.query.first()
|
||||
assert trade is not None
|
||||
assert trade.stake_amount == 0.001
|
||||
assert trade.is_open
|
||||
assert trade.open_date is not None
|
||||
assert trade.exchange == 'binance'
|
||||
if is_high_delta:
|
||||
assert trade is None
|
||||
else:
|
||||
assert trade is not None
|
||||
assert trade.stake_amount == 0.001
|
||||
assert trade.is_open
|
||||
assert trade.open_date is not None
|
||||
assert trade.exchange == 'binance'
|
||||
|
||||
assert len(Trade.query.all()) == 1
|
||||
assert len(Trade.query.all()) == 1
|
||||
|
||||
# Simulate fulfilled LIMIT_BUY order for trade
|
||||
trade.update(limit_buy_order)
|
||||
# Simulate fulfilled LIMIT_BUY order for trade
|
||||
trade.update(limit_buy_order)
|
||||
|
||||
assert trade.open_rate == 0.00001099
|
||||
assert whitelist == default_conf['exchange']['pair_whitelist']
|
||||
|
||||
|
||||
def test_order_book_depth_of_market_high_delta(default_conf, ticker, limit_buy_order,
|
||||
fee, mocker, order_book_l2):
|
||||
default_conf['bid_strategy']['check_depth_of_market']['enabled'] = True
|
||||
# delta is 100 which is impossible to reach. hence check_depth_of_market will return false
|
||||
default_conf['bid_strategy']['check_depth_of_market']['bids_to_ask_delta'] = 100
|
||||
patch_RPCManager(mocker)
|
||||
patch_exchange(mocker)
|
||||
mocker.patch('freqtrade.exchange.Exchange.fetch_l2_order_book', order_book_l2)
|
||||
mocker.patch.multiple(
|
||||
'freqtrade.exchange.Exchange',
|
||||
fetch_ticker=ticker,
|
||||
create_order=MagicMock(return_value={'id': limit_buy_order['id']}),
|
||||
get_fee=fee,
|
||||
)
|
||||
# Save state of current whitelist
|
||||
freqtrade = FreqtradeBot(default_conf)
|
||||
patch_get_signal(freqtrade)
|
||||
freqtrade.enter_positions()
|
||||
|
||||
trade = Trade.query.first()
|
||||
assert trade is None
|
||||
assert trade.open_rate == 0.00001099
|
||||
assert whitelist == default_conf['exchange']['pair_whitelist']
|
||||
|
||||
|
||||
@pytest.mark.parametrize('exception_thrown,ask,last,order_book_top,order_book', [
|
||||
@@ -4122,16 +4059,16 @@ def test_check_for_open_trades(mocker, default_conf, fee):
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("init_persistence")
|
||||
def test_update_open_orders(mocker, default_conf, fee, caplog):
|
||||
def test_startup_update_open_orders(mocker, default_conf, fee, caplog):
|
||||
freqtrade = get_patched_freqtradebot(mocker, default_conf)
|
||||
create_mock_trades(fee)
|
||||
|
||||
freqtrade.update_open_orders()
|
||||
freqtrade.startup_update_open_orders()
|
||||
assert not log_has_re(r"Error updating Order .*", caplog)
|
||||
caplog.clear()
|
||||
|
||||
freqtrade.config['dry_run'] = False
|
||||
freqtrade.update_open_orders()
|
||||
freqtrade.startup_update_open_orders()
|
||||
|
||||
assert log_has_re(r"Error updating Order .*", caplog)
|
||||
caplog.clear()
|
||||
@@ -4142,7 +4079,7 @@ def test_update_open_orders(mocker, default_conf, fee, caplog):
|
||||
'status': 'closed',
|
||||
})
|
||||
mocker.patch('freqtrade.exchange.Exchange.fetch_order', return_value=matching_buy_order)
|
||||
freqtrade.update_open_orders()
|
||||
freqtrade.startup_update_open_orders()
|
||||
# Only stoploss and sell orders are kept open
|
||||
assert len(Order.get_open_orders()) == 2
|
||||
|
||||
|
Reference in New Issue
Block a user