Merge branch 'develop' into margin-db

This commit is contained in:
Sam Germain
2021-08-02 23:58:44 -06:00
50 changed files with 827 additions and 587 deletions

View File

@@ -182,7 +182,7 @@ def get_patched_worker(mocker, config) -> Worker:
return Worker(args=None, config=config)
def patch_get_signal(freqtrade: FreqtradeBot, value=(True, False)) -> None:
def patch_get_signal(freqtrade: FreqtradeBot, value=(True, False, None)) -> None:
"""
:param mocker: mocker to patch IStrategy class
:param value: which value IStrategy.get_signal() must return

View File

@@ -29,7 +29,6 @@ from tests.optimize import (BTContainer, BTrade, _build_backtest_dataframe,
tests_start_time = arrow.get(2018, 10, 3)
timeframe_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

View File

@@ -673,7 +673,7 @@ def test_validate_pairs_restricted(default_conf, mocker, caplog):
api_mock = MagicMock()
type(api_mock).load_markets = MagicMock(return_value={
'ETH/BTC': {'quote': 'BTC'}, 'LTC/BTC': {'quote': 'BTC'},
'XRP/BTC': {'quote': 'BTC', 'info': {'IsRestricted': True}},
'XRP/BTC': {'quote': 'BTC', 'info': {'prohibitedIn': ['US']}},
'NEO/BTC': {'quote': 'BTC', 'info': 'TestString'}, # info can also be a string ...
})
mocker.patch('freqtrade.exchange.Exchange._init_ccxt', MagicMock(return_value=api_mock))
@@ -1056,8 +1056,8 @@ def test_buy_dry_run(default_conf, mocker):
default_conf['dry_run'] = True
exchange = get_patched_exchange(mocker, default_conf)
order = exchange.buy(pair='ETH/BTC', ordertype='limit',
amount=1, rate=200, time_in_force='gtc')
order = exchange.create_order(pair='ETH/BTC', ordertype='limit', side="buy",
amount=1, rate=200, time_in_force='gtc')
assert 'id' in order
assert 'dry_run_buy_' in order['id']
@@ -1080,8 +1080,8 @@ def test_buy_prod(default_conf, mocker, exchange_name):
mocker.patch('freqtrade.exchange.Exchange.price_to_precision', lambda s, x, y: y)
exchange = get_patched_exchange(mocker, default_conf, api_mock, id=exchange_name)
order = exchange.buy(pair='ETH/BTC', ordertype=order_type,
amount=1, rate=200, time_in_force=time_in_force)
order = exchange.create_order(pair='ETH/BTC', ordertype=order_type, side="buy",
amount=1, rate=200, time_in_force=time_in_force)
assert 'id' in order
assert 'info' in order
@@ -1094,9 +1094,10 @@ def test_buy_prod(default_conf, mocker, exchange_name):
api_mock.create_order.reset_mock()
order_type = 'limit'
order = exchange.buy(
order = exchange.create_order(
pair='ETH/BTC',
ordertype=order_type,
side="buy",
amount=1,
rate=200,
time_in_force=time_in_force)
@@ -1110,32 +1111,32 @@ def test_buy_prod(default_conf, mocker, exchange_name):
with pytest.raises(DependencyException):
api_mock.create_order = MagicMock(side_effect=ccxt.InsufficientFunds("Not enough funds"))
exchange = get_patched_exchange(mocker, default_conf, api_mock, id=exchange_name)
exchange.buy(pair='ETH/BTC', ordertype=order_type,
amount=1, rate=200, time_in_force=time_in_force)
exchange.create_order(pair='ETH/BTC', ordertype=order_type, side="buy",
amount=1, rate=200, time_in_force=time_in_force)
with pytest.raises(DependencyException):
api_mock.create_order = MagicMock(side_effect=ccxt.InvalidOrder("Order not found"))
exchange = get_patched_exchange(mocker, default_conf, api_mock, id=exchange_name)
exchange.buy(pair='ETH/BTC', ordertype='limit',
amount=1, rate=200, time_in_force=time_in_force)
exchange.create_order(pair='ETH/BTC', ordertype='limit', side="buy",
amount=1, rate=200, time_in_force=time_in_force)
with pytest.raises(DependencyException):
api_mock.create_order = MagicMock(side_effect=ccxt.InvalidOrder("Order not found"))
exchange = get_patched_exchange(mocker, default_conf, api_mock, id=exchange_name)
exchange.buy(pair='ETH/BTC', ordertype='market',
amount=1, rate=200, time_in_force=time_in_force)
exchange.create_order(pair='ETH/BTC', ordertype='market', side="buy",
amount=1, rate=200, time_in_force=time_in_force)
with pytest.raises(TemporaryError):
api_mock.create_order = MagicMock(side_effect=ccxt.NetworkError("Network disconnect"))
exchange = get_patched_exchange(mocker, default_conf, api_mock, id=exchange_name)
exchange.buy(pair='ETH/BTC', ordertype=order_type,
amount=1, rate=200, time_in_force=time_in_force)
exchange.create_order(pair='ETH/BTC', ordertype=order_type, side="buy",
amount=1, rate=200, time_in_force=time_in_force)
with pytest.raises(OperationalException):
api_mock.create_order = MagicMock(side_effect=ccxt.BaseError("Unknown error"))
exchange = get_patched_exchange(mocker, default_conf, api_mock, id=exchange_name)
exchange.buy(pair='ETH/BTC', ordertype=order_type,
amount=1, rate=200, time_in_force=time_in_force)
exchange.create_order(pair='ETH/BTC', ordertype=order_type, side="buy",
amount=1, rate=200, time_in_force=time_in_force)
@pytest.mark.parametrize("exchange_name", EXCHANGES)
@@ -1157,8 +1158,8 @@ def test_buy_considers_time_in_force(default_conf, mocker, exchange_name):
order_type = 'limit'
time_in_force = 'ioc'
order = exchange.buy(pair='ETH/BTC', ordertype=order_type,
amount=1, rate=200, time_in_force=time_in_force)
order = exchange.create_order(pair='ETH/BTC', ordertype=order_type, side="buy",
amount=1, rate=200, time_in_force=time_in_force)
assert 'id' in order
assert 'info' in order
@@ -1174,8 +1175,8 @@ def test_buy_considers_time_in_force(default_conf, mocker, exchange_name):
order_type = 'market'
time_in_force = 'ioc'
order = exchange.buy(pair='ETH/BTC', ordertype=order_type,
amount=1, rate=200, time_in_force=time_in_force)
order = exchange.create_order(pair='ETH/BTC', ordertype=order_type, side="buy",
amount=1, rate=200, time_in_force=time_in_force)
assert 'id' in order
assert 'info' in order
@@ -1193,7 +1194,8 @@ def test_sell_dry_run(default_conf, mocker):
default_conf['dry_run'] = True
exchange = get_patched_exchange(mocker, default_conf)
order = exchange.sell(pair='ETH/BTC', ordertype='limit', amount=1, rate=200)
order = exchange.create_order(pair='ETH/BTC', ordertype='limit',
side="sell", amount=1, rate=200)
assert 'id' in order
assert 'dry_run_sell_' in order['id']
@@ -1216,7 +1218,8 @@ def test_sell_prod(default_conf, mocker, exchange_name):
mocker.patch('freqtrade.exchange.Exchange.price_to_precision', lambda s, x, y: y)
exchange = get_patched_exchange(mocker, default_conf, api_mock, id=exchange_name)
order = exchange.sell(pair='ETH/BTC', ordertype=order_type, amount=1, rate=200)
order = exchange.create_order(pair='ETH/BTC', ordertype=order_type,
side="sell", amount=1, rate=200)
assert 'id' in order
assert 'info' in order
@@ -1229,7 +1232,8 @@ def test_sell_prod(default_conf, mocker, exchange_name):
api_mock.create_order.reset_mock()
order_type = 'limit'
order = exchange.sell(pair='ETH/BTC', ordertype=order_type, amount=1, rate=200)
order = exchange.create_order(pair='ETH/BTC', ordertype=order_type,
side="sell", amount=1, rate=200)
assert api_mock.create_order.call_args[0][0] == 'ETH/BTC'
assert api_mock.create_order.call_args[0][1] == order_type
assert api_mock.create_order.call_args[0][2] == 'sell'
@@ -1240,28 +1244,28 @@ def test_sell_prod(default_conf, mocker, exchange_name):
with pytest.raises(DependencyException):
api_mock.create_order = MagicMock(side_effect=ccxt.InsufficientFunds("0 balance"))
exchange = get_patched_exchange(mocker, default_conf, api_mock, id=exchange_name)
exchange.sell(pair='ETH/BTC', ordertype=order_type, amount=1, rate=200)
exchange.create_order(pair='ETH/BTC', ordertype=order_type, side="sell", amount=1, rate=200)
with pytest.raises(DependencyException):
api_mock.create_order = MagicMock(side_effect=ccxt.InvalidOrder("Order not found"))
exchange = get_patched_exchange(mocker, default_conf, api_mock, id=exchange_name)
exchange.sell(pair='ETH/BTC', ordertype='limit', amount=1, rate=200)
exchange.create_order(pair='ETH/BTC', ordertype='limit', side="sell", amount=1, rate=200)
# Market orders don't require price, so the behaviour is slightly different
with pytest.raises(DependencyException):
api_mock.create_order = MagicMock(side_effect=ccxt.InvalidOrder("Order not found"))
exchange = get_patched_exchange(mocker, default_conf, api_mock, id=exchange_name)
exchange.sell(pair='ETH/BTC', ordertype='market', amount=1, rate=200)
exchange.create_order(pair='ETH/BTC', ordertype='market', side="sell", amount=1, rate=200)
with pytest.raises(TemporaryError):
api_mock.create_order = MagicMock(side_effect=ccxt.NetworkError("No Connection"))
exchange = get_patched_exchange(mocker, default_conf, api_mock, id=exchange_name)
exchange.sell(pair='ETH/BTC', ordertype=order_type, amount=1, rate=200)
exchange.create_order(pair='ETH/BTC', ordertype=order_type, side="sell", amount=1, rate=200)
with pytest.raises(OperationalException):
api_mock.create_order = MagicMock(side_effect=ccxt.BaseError("DeadBeef"))
exchange = get_patched_exchange(mocker, default_conf, api_mock, id=exchange_name)
exchange.sell(pair='ETH/BTC', ordertype=order_type, amount=1, rate=200)
exchange.create_order(pair='ETH/BTC', ordertype=order_type, side="sell", amount=1, rate=200)
@pytest.mark.parametrize("exchange_name", EXCHANGES)
@@ -1283,8 +1287,8 @@ def test_sell_considers_time_in_force(default_conf, mocker, exchange_name):
order_type = 'limit'
time_in_force = 'ioc'
order = exchange.sell(pair='ETH/BTC', ordertype=order_type,
amount=1, rate=200, time_in_force=time_in_force)
order = exchange.create_order(pair='ETH/BTC', ordertype=order_type, side="sell",
amount=1, rate=200, time_in_force=time_in_force)
assert 'id' in order
assert 'info' in order
@@ -1299,8 +1303,8 @@ def test_sell_considers_time_in_force(default_conf, mocker, exchange_name):
order_type = 'market'
time_in_force = 'ioc'
order = exchange.sell(pair='ETH/BTC', ordertype=order_type,
amount=1, rate=200, time_in_force=time_in_force)
order = exchange.create_order(pair='ETH/BTC', ordertype=order_type, side="sell",
amount=1, rate=200, time_in_force=time_in_force)
assert 'id' in order
assert 'info' in order
@@ -2186,7 +2190,7 @@ def test_cancel_order_dry_run(default_conf, mocker, exchange_name):
assert exchange.cancel_order(order_id='123', pair='TKN/BTC') == {}
assert exchange.cancel_stoploss_order(order_id='123', pair='TKN/BTC') == {}
order = exchange.buy('ETH/BTC', 'limit', 5, 0.55, 'gtc')
order = exchange.create_order('ETH/BTC', 'limit', "buy", 5, 0.55, 'gtc')
cancel_order = exchange.cancel_order(order_id=order['id'], pair='ETH/BTC')
assert order['id'] == cancel_order['id']

View File

@@ -31,8 +31,8 @@ def test_buy_kraken_trading_agreement(default_conf, mocker):
mocker.patch('freqtrade.exchange.Exchange.price_to_precision', lambda s, x, y: y)
exchange = get_patched_exchange(mocker, default_conf, api_mock, id="kraken")
order = exchange.buy(pair='ETH/BTC', ordertype=order_type,
amount=1, rate=200, time_in_force=time_in_force)
order = exchange.create_order(pair='ETH/BTC', ordertype=order_type, side="buy",
amount=1, rate=200, time_in_force=time_in_force)
assert 'id' in order
assert 'info' in order
@@ -63,7 +63,8 @@ def test_sell_kraken_trading_agreement(default_conf, mocker):
mocker.patch('freqtrade.exchange.Exchange.price_to_precision', lambda s, x, y: y)
exchange = get_patched_exchange(mocker, default_conf, api_mock, id="kraken")
order = exchange.sell(pair='ETH/BTC', ordertype=order_type, amount=1, rate=200)
order = exchange.create_order(pair='ETH/BTC', ordertype=order_type,
side="sell", amount=1, rate=200)
assert 'id' in order
assert 'info' in order

View File

@@ -18,6 +18,7 @@ class BTrade(NamedTuple):
sell_reason: SellType
open_tick: int
close_tick: int
buy_tag: Optional[str] = None
class BTContainer(NamedTuple):
@@ -44,6 +45,7 @@ def _get_frame_time_from_offset(offset):
def _build_backtest_dataframe(data):
columns = ['date', 'open', 'high', 'low', 'close', 'volume', 'buy', 'sell']
columns = columns + ['buy_tag'] if len(data[0]) == 9 else columns
frame = DataFrame.from_records(data, columns=columns)
frame['date'] = frame['date'].apply(_get_frame_time_from_offset)

View File

@@ -516,6 +516,26 @@ tc32 = BTContainer(data=[
trades=[BTrade(sell_reason=SellType.TRAILING_STOP_LOSS, open_tick=1, close_tick=1)]
)
# Test 33: trailing_stop should be triggered immediately on trade open candle.
# stop-loss: 1%, ROI: 10% (should not apply)
tc33 = BTContainer(data=[
# D O H L C V B S BT
[0, 5000, 5050, 4950, 5000, 6172, 1, 0, 'buy_signal_01'],
[1, 5000, 5500, 5000, 4900, 6172, 0, 0, None], # enter trade (signal on last candle) and stop
[2, 4900, 5250, 4500, 5100, 6172, 0, 0, None],
[3, 5100, 5100, 4650, 4750, 6172, 0, 0, None],
[4, 4750, 4950, 4350, 4750, 6172, 0, 0, None]],
stop_loss=-0.01, roi={"0": 0.10}, profit_perc=-0.01, trailing_stop=True,
trailing_only_offset_is_reached=True, trailing_stop_positive_offset=0.02,
trailing_stop_positive=0.01, use_custom_stoploss=True,
trades=[BTrade(
sell_reason=SellType.TRAILING_STOP_LOSS,
open_tick=1,
close_tick=1,
buy_tag='buy_signal_01'
)]
)
TESTS = [
tc0,
tc1,
@@ -550,6 +570,7 @@ TESTS = [
tc30,
tc31,
tc32,
tc33,
]
@@ -575,6 +596,7 @@ def test_backtest_results(default_conf, fee, mocker, caplog, data) -> None:
frame = _build_backtest_dataframe(data.data)
backtesting = Backtesting(default_conf)
backtesting._set_strategy(backtesting.strategylist[0])
backtesting.required_startup = 0
backtesting.strategy.advise_buy = lambda a, m: frame
backtesting.strategy.advise_sell = lambda a, m: frame
backtesting.strategy.use_custom_stoploss = data.use_custom_stoploss
@@ -598,5 +620,6 @@ def test_backtest_results(default_conf, fee, mocker, caplog, data) -> None:
for c, trade in enumerate(data.trades):
res = results.iloc[c]
assert res.sell_reason == trade.sell_reason.value
assert res.buy_tag == trade.buy_tag
assert res.open_date == _get_frame_time_from_offset(trade.open_tick)
assert res.close_date == _get_frame_time_from_offset(trade.close_tick)

View File

@@ -496,6 +496,7 @@ def test_backtest__enter_trade(default_conf, fee, mocker) -> None:
0, # Sell
0.00099, # Low
0.0012, # High
'', # Buy Signal Name
]
trade = backtesting._enter_trade(pair, row=row)
assert isinstance(trade, LocalTrade)
@@ -583,6 +584,7 @@ def test_backtest_one(default_conf, fee, mocker, testdatadir) -> None:
'min_rate': [0.1038, 0.10302485],
'max_rate': [0.10501, 0.1038888],
'is_open': [False, False],
'buy_tag': [None, None],
})
pd.testing.assert_frame_equal(results, expected)
data_pair = processed[pair]
@@ -727,6 +729,7 @@ def test_backtest_alternate_buy_sell(default_conf, fee, mocker, testdatadir):
pair='UNITTEST/BTC', datadir=testdatadir)
default_conf['timeframe'] = '1m'
backtesting = Backtesting(default_conf)
backtesting.required_startup = 0
backtesting._set_strategy(backtesting.strategylist[0])
backtesting.strategy.advise_buy = _trend_alternate # Override
backtesting.strategy.advise_sell = _trend_alternate # Override
@@ -736,6 +739,9 @@ def test_backtest_alternate_buy_sell(default_conf, fee, mocker, testdatadir):
# 100 buys signals
results = result['results']
assert len(results) == 100
# Cached data should be 200 (no change since required_startup is 0)
assert len(backtesting.dataprovider.get_analyzed_dataframe('UNITTEST/BTC', '1m')[0]) == 200
# One trade was force-closed at the end
assert len(results.loc[results['is_open']]) == 0
@@ -791,6 +797,10 @@ def test_backtest_multi_pair(default_conf, fee, mocker, tres, pair, testdatadir)
# make sure we don't have trades with more than configured max_open_trades
assert len(evaluate_result_multi(results['results'], '5m', 3)) == 0
# Cached data correctly removed amounts
removed_candles = len(data[pair]) - 1 - backtesting.strategy.startup_candle_count
assert len(backtesting.dataprovider.get_analyzed_dataframe(pair, '5m')[0]) == removed_candles
backtest_conf = {
'processed': processed,
'start_date': min_date,
@@ -857,7 +867,7 @@ def test_backtest_start_multi_strat(default_conf, mocker, caplog, testdatadir):
'locks': [],
'rejected_signals': 20,
'final_balance': 1000,
})
})
mocker.patch('freqtrade.plugins.pairlistmanager.PairListManager.whitelist',
PropertyMock(return_value=['UNITTEST/BTC']))
mocker.patch('freqtrade.optimize.backtesting.Backtesting.backtest', backtestmock)

View File

@@ -427,6 +427,10 @@ def test_VolumePairList_refresh_empty(mocker, markets_empty, whitelist_conf):
{"method": "RangeStabilityFilter", "lookback_days": 10,
"min_rate_of_change": 0.01, "refresh_period": 1440}],
"BTC", ['ETH/BTC', 'TKN/BTC', 'HOT/BTC']),
([{"method": "StaticPairList"},
{"method": "RangeStabilityFilter", "lookback_days": 10,
"max_rate_of_change": 0.01, "refresh_period": 1440}],
"BTC", []), # All removed because of max_rate_of_change being 0.017
([{"method": "StaticPairList"},
{"method": "VolatilityFilter", "lookback_days": 3,
"min_volatility": 0.002, "max_volatility": 0.004, "refresh_period": 1440}],
@@ -874,15 +878,16 @@ def test_rangestabilityfilter_checks(mocker, default_conf, markets, tickers):
get_patched_freqtradebot(mocker, default_conf)
@pytest.mark.parametrize('min_rate_of_change,expected_length', [
(0.01, 5),
(0.05, 0), # Setting rate_of_change to 5% removes all pairs from the whitelist.
@pytest.mark.parametrize('min_rate_of_change,max_rate_of_change,expected_length', [
(0.01, 0.99, 5),
(0.05, 0.0, 0), # Setting min rate_of_change to 5% removes all pairs from the whitelist.
])
def test_rangestabilityfilter_caching(mocker, markets, default_conf, tickers, ohlcv_history,
min_rate_of_change, expected_length):
min_rate_of_change, max_rate_of_change, expected_length):
default_conf['pairlists'] = [{'method': 'VolumePairList', 'number_assets': 10},
{'method': 'RangeStabilityFilter', 'lookback_days': 2,
'min_rate_of_change': min_rate_of_change}]
'min_rate_of_change': min_rate_of_change,
"max_rate_of_change": max_rate_of_change}]
mocker.patch.multiple('freqtrade.exchange.Exchange',
markets=PropertyMock(return_value=markets),
@@ -984,11 +989,18 @@ def test_spreadfilter_invalid_data(mocker, default_conf, markets, tickers, caplo
None,
"PriceFilter requires max_value to be >= 0"
), # OperationalException expected
({"method": "RangeStabilityFilter", "lookback_days": 10, "min_rate_of_change": 0.01},
({"method": "RangeStabilityFilter", "lookback_days": 10,
"min_rate_of_change": 0.01},
"[{'RangeStabilityFilter': 'RangeStabilityFilter - Filtering pairs with rate of change below "
"0.01 over the last days.'}]",
None
),
({"method": "RangeStabilityFilter", "lookback_days": 10,
"min_rate_of_change": 0.01, "max_rate_of_change": 0.99},
"[{'RangeStabilityFilter': 'RangeStabilityFilter - Filtering pairs with rate of change below "
"0.01 and above 0.99 over the last days.'}]",
None
),
])
def test_pricefilter_desc(mocker, whitelist_conf, markets, pairlistconfig,
desc_expected, exception_expected):

View File

@@ -35,7 +35,7 @@ def test_rpc_trade_status(default_conf, ticker, fee, mocker) -> None:
)
freqtradebot = get_patched_freqtradebot(mocker, default_conf)
patch_get_signal(freqtradebot, (True, False))
patch_get_signal(freqtradebot, (True, False, None))
rpc = RPC(freqtradebot)
freqtradebot.state = State.RUNNING
@@ -69,6 +69,7 @@ def test_rpc_trade_status(default_conf, ticker, fee, mocker) -> None:
'min_rate': ANY,
'max_rate': ANY,
'strategy': ANY,
'buy_tag': ANY,
'timeframe': 5,
'open_order_id': ANY,
'close_date': None,
@@ -139,6 +140,7 @@ def test_rpc_trade_status(default_conf, ticker, fee, mocker) -> None:
'min_rate': ANY,
'max_rate': ANY,
'strategy': ANY,
'buy_tag': ANY,
'timeframe': ANY,
'open_order_id': ANY,
'close_date': None,
@@ -198,7 +200,7 @@ def test_rpc_status_table(default_conf, ticker, fee, mocker) -> None:
)
del default_conf['fiat_display_currency']
freqtradebot = get_patched_freqtradebot(mocker, default_conf)
patch_get_signal(freqtradebot, (True, False))
patch_get_signal(freqtradebot, (True, False, None))
rpc = RPC(freqtradebot)
freqtradebot.state = State.RUNNING
@@ -245,7 +247,7 @@ def test_rpc_daily_profit(default_conf, update, ticker, fee,
)
freqtradebot = get_patched_freqtradebot(mocker, default_conf)
patch_get_signal(freqtradebot, (True, False))
patch_get_signal(freqtradebot, (True, False, None))
stake_currency = default_conf['stake_currency']
fiat_display_currency = default_conf['fiat_display_currency']
@@ -377,7 +379,7 @@ def test_rpc_trade_statistics(default_conf, ticker, ticker_sell_up, fee,
)
freqtradebot = get_patched_freqtradebot(mocker, default_conf)
patch_get_signal(freqtradebot, (True, False))
patch_get_signal(freqtradebot, (True, False, None))
stake_currency = default_conf['stake_currency']
fiat_display_currency = default_conf['fiat_display_currency']
@@ -465,7 +467,7 @@ def test_rpc_trade_statistics_closed(mocker, default_conf, ticker, fee,
)
freqtradebot = get_patched_freqtradebot(mocker, default_conf)
patch_get_signal(freqtradebot, (True, False))
patch_get_signal(freqtradebot, (True, False, None))
stake_currency = default_conf['stake_currency']
fiat_display_currency = default_conf['fiat_display_currency']
@@ -532,7 +534,7 @@ def test_rpc_balance_handle_error(default_conf, mocker):
)
freqtradebot = get_patched_freqtradebot(mocker, default_conf)
patch_get_signal(freqtradebot, (True, False))
patch_get_signal(freqtradebot, (True, False, None))
rpc = RPC(freqtradebot)
rpc._fiat_converter = CryptoToFiatConverter()
with pytest.raises(RPCException, match="Error getting current tickers."):
@@ -573,7 +575,7 @@ def test_rpc_balance_handle(default_conf, mocker, tickers):
)
default_conf['dry_run'] = False
freqtradebot = get_patched_freqtradebot(mocker, default_conf)
patch_get_signal(freqtradebot, (True, False))
patch_get_signal(freqtradebot, (True, False, None))
rpc = RPC(freqtradebot)
rpc._fiat_converter = CryptoToFiatConverter()
@@ -618,7 +620,7 @@ def test_rpc_start(mocker, default_conf) -> None:
)
freqtradebot = get_patched_freqtradebot(mocker, default_conf)
patch_get_signal(freqtradebot, (True, False))
patch_get_signal(freqtradebot, (True, False, None))
rpc = RPC(freqtradebot)
freqtradebot.state = State.STOPPED
@@ -639,7 +641,7 @@ def test_rpc_stop(mocker, default_conf) -> None:
)
freqtradebot = get_patched_freqtradebot(mocker, default_conf)
patch_get_signal(freqtradebot, (True, False))
patch_get_signal(freqtradebot, (True, False, None))
rpc = RPC(freqtradebot)
freqtradebot.state = State.RUNNING
@@ -661,7 +663,7 @@ def test_rpc_stopbuy(mocker, default_conf) -> None:
)
freqtradebot = get_patched_freqtradebot(mocker, default_conf)
patch_get_signal(freqtradebot, (True, False))
patch_get_signal(freqtradebot, (True, False, None))
rpc = RPC(freqtradebot)
freqtradebot.state = State.RUNNING
@@ -693,7 +695,7 @@ def test_rpc_forcesell(default_conf, ticker, fee, mocker) -> None:
mocker.patch('freqtrade.wallets.Wallets.get_free', return_value=1000)
freqtradebot = get_patched_freqtradebot(mocker, default_conf)
patch_get_signal(freqtradebot, (True, False))
patch_get_signal(freqtradebot, (True, False, None))
rpc = RPC(freqtradebot)
freqtradebot.state = State.STOPPED
@@ -811,7 +813,7 @@ def test_performance_handle(default_conf, ticker, limit_buy_order, fee,
)
freqtradebot = get_patched_freqtradebot(mocker, default_conf)
patch_get_signal(freqtradebot, (True, False))
patch_get_signal(freqtradebot, (True, False, None))
rpc = RPC(freqtradebot)
# Create some test data
@@ -844,7 +846,7 @@ def test_rpc_count(mocker, default_conf, ticker, fee) -> None:
)
freqtradebot = get_patched_freqtradebot(mocker, default_conf)
patch_get_signal(freqtradebot, (True, False))
patch_get_signal(freqtradebot, (True, False, None))
rpc = RPC(freqtradebot)
counts = rpc._rpc_count()
@@ -865,11 +867,11 @@ def test_rpcforcebuy(mocker, default_conf, ticker, fee, limit_buy_order_open) ->
get_balances=MagicMock(return_value=ticker),
fetch_ticker=ticker,
get_fee=fee,
buy=buy_mm
create_order=buy_mm
)
freqtradebot = get_patched_freqtradebot(mocker, default_conf)
patch_get_signal(freqtradebot, (True, False))
patch_get_signal(freqtradebot, (True, False, None))
rpc = RPC(freqtradebot)
pair = 'ETH/BTC'
trade = rpc._rpc_forcebuy(pair, None)
@@ -895,7 +897,7 @@ def test_rpcforcebuy(mocker, default_conf, ticker, fee, limit_buy_order_open) ->
# Test not buying
freqtradebot = get_patched_freqtradebot(mocker, default_conf)
freqtradebot.config['stake_amount'] = 0
patch_get_signal(freqtradebot, (True, False))
patch_get_signal(freqtradebot, (True, False, None))
rpc = RPC(freqtradebot)
pair = 'TKN/BTC'
trade = rpc._rpc_forcebuy(pair, None)
@@ -908,7 +910,7 @@ def test_rpcforcebuy_stopped(mocker, default_conf) -> None:
mocker.patch('freqtrade.rpc.telegram.Telegram', MagicMock())
freqtradebot = get_patched_freqtradebot(mocker, default_conf)
patch_get_signal(freqtradebot, (True, False))
patch_get_signal(freqtradebot, (True, False, None))
rpc = RPC(freqtradebot)
pair = 'ETH/BTC'
with pytest.raises(RPCException, match=r'trader is not running'):
@@ -919,7 +921,7 @@ def test_rpcforcebuy_disabled(mocker, default_conf) -> None:
mocker.patch('freqtrade.rpc.telegram.Telegram', MagicMock())
freqtradebot = get_patched_freqtradebot(mocker, default_conf)
patch_get_signal(freqtradebot, (True, False))
patch_get_signal(freqtradebot, (True, False, None))
rpc = RPC(freqtradebot)
pair = 'ETH/BTC'
with pytest.raises(RPCException, match=r'Forcebuy not enabled.'):

View File

@@ -442,7 +442,7 @@ def test_api_balance(botclient, mocker, rpc_balance):
def test_api_count(botclient, mocker, ticker, fee, markets):
ftbot, client = botclient
patch_get_signal(ftbot, (True, False))
patch_get_signal(ftbot, (True, False, None))
mocker.patch.multiple(
'freqtrade.exchange.Exchange',
get_balances=MagicMock(return_value=ticker),
@@ -504,7 +504,7 @@ def test_api_locks(botclient):
def test_api_show_config(botclient, mocker):
ftbot, client = botclient
patch_get_signal(ftbot, (True, False))
patch_get_signal(ftbot, (True, False, None))
rc = client_get(client, f"{BASE_URI}/show_config")
assert_response(rc)
@@ -522,7 +522,7 @@ def test_api_show_config(botclient, mocker):
def test_api_daily(botclient, mocker, ticker, fee, markets):
ftbot, client = botclient
patch_get_signal(ftbot, (True, False))
patch_get_signal(ftbot, (True, False, None))
mocker.patch.multiple(
'freqtrade.exchange.Exchange',
get_balances=MagicMock(return_value=ticker),
@@ -540,7 +540,7 @@ def test_api_daily(botclient, mocker, ticker, fee, markets):
def test_api_trades(botclient, mocker, fee, markets):
ftbot, client = botclient
patch_get_signal(ftbot, (True, False))
patch_get_signal(ftbot, (True, False, None))
mocker.patch.multiple(
'freqtrade.exchange.Exchange',
markets=PropertyMock(return_value=markets)
@@ -568,7 +568,7 @@ def test_api_trades(botclient, mocker, fee, markets):
def test_api_trade_single(botclient, mocker, fee, ticker, markets):
ftbot, client = botclient
patch_get_signal(ftbot, (True, False))
patch_get_signal(ftbot, (True, False, None))
mocker.patch.multiple(
'freqtrade.exchange.Exchange',
markets=PropertyMock(return_value=markets),
@@ -588,7 +588,7 @@ def test_api_trade_single(botclient, mocker, fee, ticker, markets):
def test_api_delete_trade(botclient, mocker, fee, markets):
ftbot, client = botclient
patch_get_signal(ftbot, (True, False))
patch_get_signal(ftbot, (True, False, None))
stoploss_mock = MagicMock()
cancel_mock = MagicMock()
mocker.patch.multiple(
@@ -656,13 +656,13 @@ def test_api_logs(botclient):
# Help debugging random test failure
print(f"rc={rc.json()}")
print(f"rc1={rc1.json()}")
assert rc1.json()['log_count'] == 5
assert rc1.json()['log_count'] > 2
assert len(rc1.json()['logs']) == rc1.json()['log_count']
def test_api_edge_disabled(botclient, mocker, ticker, fee, markets):
ftbot, client = botclient
patch_get_signal(ftbot, (True, False))
patch_get_signal(ftbot, (True, False, None))
mocker.patch.multiple(
'freqtrade.exchange.Exchange',
get_balances=MagicMock(return_value=ticker),
@@ -678,7 +678,7 @@ def test_api_edge_disabled(botclient, mocker, ticker, fee, markets):
@pytest.mark.usefixtures("init_persistence")
def test_api_profit(botclient, mocker, ticker, fee, markets):
ftbot, client = botclient
patch_get_signal(ftbot, (True, False))
patch_get_signal(ftbot, (True, False, None))
mocker.patch.multiple(
'freqtrade.exchange.Exchange',
get_balances=MagicMock(return_value=ticker),
@@ -729,7 +729,7 @@ def test_api_profit(botclient, mocker, ticker, fee, markets):
@pytest.mark.usefixtures("init_persistence")
def test_api_stats(botclient, mocker, ticker, fee, markets,):
ftbot, client = botclient
patch_get_signal(ftbot, (True, False))
patch_get_signal(ftbot, (True, False, None))
mocker.patch.multiple(
'freqtrade.exchange.Exchange',
get_balances=MagicMock(return_value=ticker),
@@ -757,7 +757,7 @@ def test_api_stats(botclient, mocker, ticker, fee, markets,):
def test_api_performance(botclient, fee):
ftbot, client = botclient
patch_get_signal(ftbot, (True, False))
patch_get_signal(ftbot, (True, False, None))
trade = Trade(
pair='LTC/ETH',
@@ -803,7 +803,7 @@ def test_api_performance(botclient, fee):
def test_api_status(botclient, mocker, ticker, fee, markets):
ftbot, client = botclient
patch_get_signal(ftbot, (True, False))
patch_get_signal(ftbot, (True, False, None))
mocker.patch.multiple(
'freqtrade.exchange.Exchange',
get_balances=MagicMock(return_value=ticker),
@@ -875,6 +875,7 @@ def test_api_status(botclient, mocker, ticker, fee, markets):
'sell_reason': None,
'sell_order_status': None,
'strategy': 'DefaultStrategy',
'buy_tag': None,
'timeframe': 5,
'exchange': 'binance',
}
@@ -1029,6 +1030,7 @@ def test_api_forcebuy(botclient, mocker, fee):
'sell_reason': None,
'sell_order_status': None,
'strategy': 'DefaultStrategy',
'buy_tag': None,
'timeframe': 5,
'exchange': 'binance',
}
@@ -1044,7 +1046,7 @@ def test_api_forcesell(botclient, mocker, ticker, fee, markets):
markets=PropertyMock(return_value=markets),
_is_dry_limit_order_filled=MagicMock(return_value=False),
)
patch_get_signal(ftbot, (True, False))
patch_get_signal(ftbot, (True, False, None))
rc = client_post(client, f"{BASE_URI}/forcesell",
data='{"tradeid": "1"}')
@@ -1185,8 +1187,10 @@ def test_api_plot_config(botclient):
assert_response(rc)
assert rc.json() == {}
ftbot.strategy.plot_config = {'main_plot': {'sma': {}},
'subplots': {'RSI': {'rsi': {'color': 'red'}}}}
ftbot.strategy.plot_config = {
'main_plot': {'sma': {}},
'subplots': {'RSI': {'rsi': {'color': 'red'}}}
}
rc = client_get(client, f"{BASE_URI}/plot_config")
assert_response(rc)
assert rc.json() == ftbot.strategy.plot_config

View File

@@ -119,7 +119,7 @@ def test_authorized_only(default_conf, mocker, caplog, update) -> None:
rpc = RPC(bot)
dummy = DummyCls(rpc, default_conf)
patch_get_signal(bot, (True, False))
patch_get_signal(bot, (True, False, None))
dummy.dummy_handler(update=update, context=MagicMock())
assert dummy.state['called'] is True
assert log_has('Executing handler: dummy_handler for chat_id: 0', caplog)
@@ -139,7 +139,7 @@ def test_authorized_only_unauthorized(default_conf, mocker, caplog) -> None:
rpc = RPC(bot)
dummy = DummyCls(rpc, default_conf)
patch_get_signal(bot, (True, False))
patch_get_signal(bot, (True, False, None))
dummy.dummy_handler(update=update, context=MagicMock())
assert dummy.state['called'] is False
assert not log_has('Executing handler: dummy_handler for chat_id: 3735928559', caplog)
@@ -155,7 +155,7 @@ def test_authorized_only_exception(default_conf, mocker, caplog, update) -> None
bot = FreqtradeBot(default_conf)
rpc = RPC(bot)
dummy = DummyCls(rpc, default_conf)
patch_get_signal(bot, (True, False))
patch_get_signal(bot, (True, False, None))
dummy.dummy_exception(update=update, context=MagicMock())
assert dummy.state['called'] is False
@@ -185,6 +185,7 @@ def test_telegram_status(default_conf, update, mocker) -> None:
'current_rate': 1.098e-05,
'amount': 90.99181074,
'stake_amount': 90.99181074,
'buy_tag': None,
'close_profit_pct': None,
'profit': -0.0059,
'profit_pct': -0.59,
@@ -228,7 +229,7 @@ def test_status_handle(default_conf, update, ticker, fee, mocker) -> None:
telegram, freqtradebot, msg_mock = get_telegram_testobject(mocker, default_conf)
patch_get_signal(freqtradebot, (True, False))
patch_get_signal(freqtradebot, (True, False, None))
freqtradebot.state = State.STOPPED
# Status is also enabled when stopped
@@ -285,7 +286,7 @@ def test_status_table_handle(default_conf, update, ticker, fee, mocker) -> None:
telegram, freqtradebot, msg_mock = get_telegram_testobject(mocker, default_conf)
patch_get_signal(freqtradebot, (True, False))
patch_get_signal(freqtradebot, (True, False, None))
freqtradebot.state = State.STOPPED
# Status table is also enabled when stopped
@@ -329,7 +330,7 @@ def test_daily_handle(default_conf, update, ticker, limit_buy_order, fee,
telegram, freqtradebot, msg_mock = get_telegram_testobject(mocker, default_conf)
patch_get_signal(freqtradebot, (True, False))
patch_get_signal(freqtradebot, (True, False, None))
# Create some test data
freqtradebot.enter_positions()
@@ -400,7 +401,7 @@ def test_daily_wrong_input(default_conf, update, ticker, mocker) -> None:
)
telegram, freqtradebot, msg_mock = get_telegram_testobject(mocker, default_conf)
patch_get_signal(freqtradebot, (True, False))
patch_get_signal(freqtradebot, (True, False, None))
# Try invalid data
msg_mock.reset_mock()
@@ -432,7 +433,7 @@ def test_profit_handle(default_conf, update, ticker, ticker_sell_up, fee,
)
telegram, freqtradebot, msg_mock = get_telegram_testobject(mocker, default_conf)
patch_get_signal(freqtradebot, (True, False))
patch_get_signal(freqtradebot, (True, False, None))
telegram._profit(update=update, context=MagicMock())
assert msg_mock.call_count == 1
@@ -487,7 +488,7 @@ def test_telegram_stats(default_conf, update, ticker, ticker_sell_up, fee,
get_fee=fee,
)
telegram, freqtradebot, msg_mock = get_telegram_testobject(mocker, default_conf)
patch_get_signal(freqtradebot, (True, False))
patch_get_signal(freqtradebot, (True, False, None))
telegram._stats(update=update, context=MagicMock())
assert msg_mock.call_count == 1
@@ -513,7 +514,7 @@ def test_telegram_balance_handle(default_conf, update, mocker, rpc_balance, tick
side_effect=lambda a, b: f"{a}/{b}")
telegram, freqtradebot, msg_mock = get_telegram_testobject(mocker, default_conf)
patch_get_signal(freqtradebot, (True, False))
patch_get_signal(freqtradebot, (True, False, None))
telegram._balance(update=update, context=MagicMock())
result = msg_mock.call_args_list[0][0][0]
@@ -536,7 +537,7 @@ def test_balance_handle_empty_response(default_conf, update, mocker) -> None:
mocker.patch('freqtrade.exchange.Exchange.get_balances', return_value={})
telegram, freqtradebot, msg_mock = get_telegram_testobject(mocker, default_conf)
patch_get_signal(freqtradebot, (True, False))
patch_get_signal(freqtradebot, (True, False, None))
freqtradebot.config['dry_run'] = False
telegram._balance(update=update, context=MagicMock())
@@ -549,7 +550,7 @@ def test_balance_handle_empty_response_dry(default_conf, update, mocker) -> None
mocker.patch('freqtrade.exchange.Exchange.get_balances', return_value={})
telegram, freqtradebot, msg_mock = get_telegram_testobject(mocker, default_conf)
patch_get_signal(freqtradebot, (True, False))
patch_get_signal(freqtradebot, (True, False, None))
telegram._balance(update=update, context=MagicMock())
result = msg_mock.call_args_list[0][0][0]
@@ -578,7 +579,7 @@ def test_balance_handle_too_large_response(default_conf, update, mocker) -> None
})
telegram, freqtradebot, msg_mock = get_telegram_testobject(mocker, default_conf)
patch_get_signal(freqtradebot, (True, False))
patch_get_signal(freqtradebot, (True, False, None))
telegram._balance(update=update, context=MagicMock())
assert msg_mock.call_count > 1
@@ -677,7 +678,7 @@ def test_telegram_forcesell_handle(default_conf, update, ticker, fee,
freqtradebot = FreqtradeBot(default_conf)
rpc = RPC(freqtradebot)
telegram = Telegram(rpc, default_conf)
patch_get_signal(freqtradebot, (True, False))
patch_get_signal(freqtradebot, (True, False, None))
# Create some test data
freqtradebot.enter_positions()
@@ -736,7 +737,7 @@ def test_telegram_forcesell_down_handle(default_conf, update, ticker, fee,
freqtradebot = FreqtradeBot(default_conf)
rpc = RPC(freqtradebot)
telegram = Telegram(rpc, default_conf)
patch_get_signal(freqtradebot, (True, False))
patch_get_signal(freqtradebot, (True, False, None))
# Create some test data
freqtradebot.enter_positions()
@@ -797,7 +798,7 @@ def test_forcesell_all_handle(default_conf, update, ticker, fee, mocker) -> None
freqtradebot = FreqtradeBot(default_conf)
rpc = RPC(freqtradebot)
telegram = Telegram(rpc, default_conf)
patch_get_signal(freqtradebot, (True, False))
patch_get_signal(freqtradebot, (True, False, None))
# Create some test data
freqtradebot.enter_positions()
@@ -838,7 +839,7 @@ def test_forcesell_handle_invalid(default_conf, update, mocker) -> None:
return_value=15000.0)
telegram, freqtradebot, msg_mock = get_telegram_testobject(mocker, default_conf)
patch_get_signal(freqtradebot, (True, False))
patch_get_signal(freqtradebot, (True, False, None))
# Trader is not running
freqtradebot.state = State.STOPPED
@@ -876,7 +877,7 @@ def test_forcebuy_handle(default_conf, update, mocker) -> None:
mocker.patch('freqtrade.rpc.RPC._rpc_forcebuy', fbuy_mock)
telegram, freqtradebot, _ = get_telegram_testobject(mocker, default_conf)
patch_get_signal(freqtradebot, (True, False))
patch_get_signal(freqtradebot, (True, False, None))
# /forcebuy ETH/BTC
context = MagicMock()
@@ -905,7 +906,7 @@ def test_forcebuy_handle_exception(default_conf, update, mocker) -> None:
mocker.patch('freqtrade.rpc.rpc.CryptoToFiatConverter._find_price', return_value=15000.0)
telegram, freqtradebot, msg_mock = get_telegram_testobject(mocker, default_conf)
patch_get_signal(freqtradebot, (True, False))
patch_get_signal(freqtradebot, (True, False, None))
update.message.text = '/forcebuy ETH/Nonepair'
telegram._forcebuy(update=update, context=MagicMock())
@@ -922,7 +923,7 @@ def test_forcebuy_no_pair(default_conf, update, mocker) -> None:
telegram, freqtradebot, msg_mock = get_telegram_testobject(mocker, default_conf)
patch_get_signal(freqtradebot, (True, False))
patch_get_signal(freqtradebot, (True, False, None))
context = MagicMock()
context.args = []
@@ -950,7 +951,7 @@ def test_performance_handle(default_conf, update, ticker, fee,
get_fee=fee,
)
telegram, freqtradebot, msg_mock = get_telegram_testobject(mocker, default_conf)
patch_get_signal(freqtradebot, (True, False))
patch_get_signal(freqtradebot, (True, False, None))
# Create some test data
freqtradebot.enter_positions()
@@ -978,7 +979,7 @@ def test_count_handle(default_conf, update, ticker, fee, mocker) -> None:
get_fee=fee,
)
telegram, freqtradebot, msg_mock = get_telegram_testobject(mocker, default_conf)
patch_get_signal(freqtradebot, (True, False))
patch_get_signal(freqtradebot, (True, False, None))
freqtradebot.state = State.STOPPED
telegram._count(update=update, context=MagicMock())
@@ -1007,7 +1008,7 @@ def test_telegram_lock_handle(default_conf, update, ticker, fee, mocker) -> None
get_fee=fee,
)
telegram, freqtradebot, msg_mock = get_telegram_testobject(mocker, default_conf)
patch_get_signal(freqtradebot, (True, False))
patch_get_signal(freqtradebot, (True, False, None))
telegram._locks(update=update, context=MagicMock())
assert msg_mock.call_count == 1
assert 'No active locks.' in msg_mock.call_args_list[0][0][0]
@@ -1253,6 +1254,7 @@ def test_send_msg_buy_notification(default_conf, mocker, caplog) -> None:
msg = {
'type': RPCMessageType.BUY,
'trade_id': 1,
'buy_tag': 'buy_signal_01',
'exchange': 'Binance',
'pair': 'ETH/BTC',
'limit': 1.099e-05,
@@ -1270,6 +1272,7 @@ def test_send_msg_buy_notification(default_conf, mocker, caplog) -> None:
telegram.send_msg(msg)
assert msg_mock.call_args[0][0] \
== '\N{LARGE BLUE CIRCLE} *Binance:* Buying ETH/BTC (#1)\n' \
'*Buy Tag:* `buy_signal_01`\n' \
'*Amount:* `1333.33333333`\n' \
'*Open Rate:* `0.00001099`\n' \
'*Current Rate:* `0.00001099`\n' \
@@ -1297,6 +1300,7 @@ def test_send_msg_buy_cancel_notification(default_conf, mocker) -> None:
telegram.send_msg({
'type': RPCMessageType.BUY_CANCEL,
'buy_tag': 'buy_signal_01',
'trade_id': 1,
'exchange': 'Binance',
'pair': 'ETH/BTC',
@@ -1314,6 +1318,7 @@ def test_send_msg_buy_fill_notification(default_conf, mocker) -> None:
telegram.send_msg({
'type': RPCMessageType.BUY_FILL,
'buy_tag': 'buy_signal_01',
'trade_id': 1,
'exchange': 'Binance',
'pair': 'ETH/USDT',
@@ -1498,6 +1503,7 @@ def test_send_msg_buy_notification_no_fiat(default_conf, mocker) -> None:
telegram.send_msg({
'type': RPCMessageType.BUY,
'buy_tag': 'buy_signal_01',
'trade_id': 1,
'exchange': 'Binance',
'pair': 'ETH/BTC',
@@ -1512,6 +1518,7 @@ def test_send_msg_buy_notification_no_fiat(default_conf, mocker) -> None:
'open_date': arrow.utcnow().shift(hours=-1)
})
assert msg_mock.call_args[0][0] == ('\N{LARGE BLUE CIRCLE} *Binance:* Buying ETH/BTC (#1)\n'
'*Buy Tag:* `buy_signal_01`\n'
'*Amount:* `1333.33333333`\n'
'*Open Rate:* `0.00001099`\n'
'*Current Rate:* `0.00001099`\n'

View File

@@ -38,15 +38,20 @@ def test_returns_latest_signal(mocker, default_conf, ohlcv_history):
mocked_history['buy'] = 0
mocked_history.loc[1, 'sell'] = 1
assert _STRATEGY.get_signal('ETH/BTC', '5m', mocked_history) == (False, True)
assert _STRATEGY.get_signal('ETH/BTC', '5m', mocked_history) == (False, True, None)
mocked_history.loc[1, 'sell'] = 0
mocked_history.loc[1, 'buy'] = 1
assert _STRATEGY.get_signal('ETH/BTC', '5m', mocked_history) == (True, False)
assert _STRATEGY.get_signal('ETH/BTC', '5m', mocked_history) == (True, False, None)
mocked_history.loc[1, 'sell'] = 0
mocked_history.loc[1, 'buy'] = 0
assert _STRATEGY.get_signal('ETH/BTC', '5m', mocked_history) == (False, False)
assert _STRATEGY.get_signal('ETH/BTC', '5m', mocked_history) == (False, False, None)
mocked_history.loc[1, 'sell'] = 0
mocked_history.loc[1, 'buy'] = 1
mocked_history.loc[1, 'buy_tag'] = 'buy_signal_01'
assert _STRATEGY.get_signal('ETH/BTC', '5m', mocked_history) == (True, False, 'buy_signal_01')
def test_analyze_pair_empty(default_conf, mocker, caplog, ohlcv_history):
@@ -63,15 +68,21 @@ def test_analyze_pair_empty(default_conf, mocker, caplog, ohlcv_history):
def test_get_signal_empty(default_conf, mocker, caplog):
assert (False, False) == _STRATEGY.get_signal('foo', default_conf['timeframe'], DataFrame())
assert (False, False, None) == _STRATEGY.get_signal(
'foo', default_conf['timeframe'], DataFrame()
)
assert log_has('Empty candle (OHLCV) data for pair foo', caplog)
caplog.clear()
assert (False, False) == _STRATEGY.get_signal('bar', default_conf['timeframe'], None)
assert (False, False, None) == _STRATEGY.get_signal('bar', default_conf['timeframe'], None)
assert log_has('Empty candle (OHLCV) data for pair bar', caplog)
caplog.clear()
assert (False, False) == _STRATEGY.get_signal('baz', default_conf['timeframe'], DataFrame([]))
assert (False, False, None) == _STRATEGY.get_signal(
'baz',
default_conf['timeframe'],
DataFrame([])
)
assert log_has('Empty candle (OHLCV) data for pair baz', caplog)
@@ -107,10 +118,35 @@ def test_get_signal_old_dataframe(default_conf, mocker, caplog, ohlcv_history):
caplog.set_level(logging.INFO)
mocker.patch.object(_STRATEGY, 'assert_df')
assert (False, False) == _STRATEGY.get_signal('xyz', default_conf['timeframe'], mocked_history)
assert (False, False, None) == _STRATEGY.get_signal(
'xyz',
default_conf['timeframe'],
mocked_history
)
assert log_has('Outdated history for pair xyz. Last tick is 16 minutes old', caplog)
def test_get_signal_no_sell_column(default_conf, mocker, caplog, ohlcv_history):
# default_conf defines a 5m interval. we check interval * 2 + 5m
# this is necessary as the last candle is removed (partial candles) by default
ohlcv_history.loc[1, 'date'] = arrow.utcnow()
# Take a copy to correctly modify the call
mocked_history = ohlcv_history.copy()
# Intentionally don't set sell column
# mocked_history['sell'] = 0
mocked_history['buy'] = 0
mocked_history.loc[1, 'buy'] = 1
caplog.set_level(logging.INFO)
mocker.patch.object(_STRATEGY, 'assert_df')
assert (True, False, None) == _STRATEGY.get_signal(
'xyz',
default_conf['timeframe'],
mocked_history
)
def test_ignore_expired_candle(default_conf):
default_conf.update({'strategy': 'DefaultStrategy'})
strategy = StrategyResolver.load_strategy(default_conf)
@@ -182,10 +218,6 @@ def test_assert_df(ohlcv_history, caplog):
match="Buy column not set"):
_STRATEGY.assert_df(ohlcv_history.drop('buy', axis=1), len(ohlcv_history),
ohlcv_history.loc[df_len, 'close'], ohlcv_history.loc[0, 'date'])
with pytest.raises(StrategyError,
match="Sell column not set"):
_STRATEGY.assert_df(ohlcv_history.drop('sell', axis=1), len(ohlcv_history),
ohlcv_history.loc[df_len, 'close'], ohlcv_history.loc[0, 'date'])
_STRATEGY.disable_dataframe_checks = True
caplog.clear()

View File

@@ -18,8 +18,9 @@ from freqtrade.configuration.deprecated_settings import (check_conflicting_setti
process_deprecated_setting,
process_removed_setting,
process_temporary_deprecated_settings)
from freqtrade.configuration.environment_vars import flat_vars_to_nested_dict
from freqtrade.configuration.load_config import load_config_file, load_file, log_config_error_range
from freqtrade.constants import DEFAULT_DB_DRYRUN_URL, DEFAULT_DB_PROD_URL
from freqtrade.constants import DEFAULT_DB_DRYRUN_URL, DEFAULT_DB_PROD_URL, ENV_VAR_PREFIX
from freqtrade.enums import RunMode
from freqtrade.exceptions import OperationalException
from freqtrade.loggers import _set_loggers, setup_logging, setup_logging_pre
@@ -1349,3 +1350,35 @@ def test_process_deprecated_ticker_interval(mocker, default_conf, caplog):
with pytest.raises(OperationalException,
match=r"Both 'timeframe' and 'ticker_interval' detected."):
process_temporary_deprecated_settings(config)
def test_flat_vars_to_nested_dict(caplog):
test_args = {
'FREQTRADE__EXCHANGE__SOME_SETTING': 'true',
'FREQTRADE__EXCHANGE__SOME_FALSE_SETTING': 'false',
'FREQTRADE__EXCHANGE__CONFIG__whatever': 'sometime',
'FREQTRADE__ASK_STRATEGY__PRICE_SIDE': 'bid',
'FREQTRADE__ASK_STRATEGY__cccc': '500',
'FREQTRADE__STAKE_AMOUNT': '200.05',
'NOT_RELEVANT': '200.0', # Will be ignored
}
expected = {
'stake_amount': 200.05,
'ask_strategy': {
'price_side': 'bid',
'cccc': 500,
},
'exchange': {
'config': {
'whatever': 'sometime',
},
'some_setting': True,
'some_false_setting': False,
}
}
res = flat_vars_to_nested_dict(test_args, ENV_VAR_PREFIX)
assert res == expected
assert log_has("Loading variable 'FREQTRADE__EXCHANGE__SOME_SETTING'", caplog)
assert not log_has("Loading variable 'NOT_RELEVANT'", caplog)

View File

@@ -169,7 +169,7 @@ def test_check_available_stake_amount(default_conf, ticker, mocker, fee, limit_b
mocker.patch.multiple(
'freqtrade.exchange.Exchange',
fetch_ticker=ticker,
buy=MagicMock(return_value=limit_buy_order_open),
create_order=MagicMock(return_value=limit_buy_order_open),
get_fee=fee
)
default_conf['dry_run_wallet'] = wallet
@@ -384,7 +384,7 @@ def test_create_trade_minimal_amount(default_conf, ticker, limit_buy_order_open,
mocker.patch.multiple(
'freqtrade.exchange.Exchange',
fetch_ticker=ticker,
buy=buy_mock,
create_order=buy_mock,
get_fee=fee,
)
default_conf['stake_amount'] = 0.0005
@@ -404,7 +404,7 @@ def test_create_trade_too_small_stake_amount(default_conf, ticker, limit_buy_ord
mocker.patch.multiple(
'freqtrade.exchange.Exchange',
fetch_ticker=ticker,
buy=buy_mock,
create_order=buy_mock,
get_fee=fee,
)
@@ -425,7 +425,7 @@ def test_create_trade_zero_stake_amount(default_conf, ticker, limit_buy_order_op
mocker.patch.multiple(
'freqtrade.exchange.Exchange',
fetch_ticker=ticker,
buy=buy_mock,
create_order=buy_mock,
get_fee=fee,
)
@@ -444,7 +444,7 @@ def test_create_trade_limit_reached(default_conf, ticker, limit_buy_order_open,
mocker.patch.multiple(
'freqtrade.exchange.Exchange',
fetch_ticker=ticker,
buy=MagicMock(return_value=limit_buy_order_open),
create_order=MagicMock(return_value=limit_buy_order_open),
get_fee=fee,
)
default_conf['max_open_trades'] = 0
@@ -464,7 +464,7 @@ def test_enter_positions_no_pairs_left(default_conf, ticker, limit_buy_order_ope
mocker.patch.multiple(
'freqtrade.exchange.Exchange',
fetch_ticker=ticker,
buy=MagicMock(return_value=limit_buy_order_open),
create_order=MagicMock(return_value=limit_buy_order_open),
get_fee=fee,
)
@@ -487,7 +487,7 @@ def test_enter_positions_no_pairs_in_whitelist(default_conf, ticker, limit_buy_o
mocker.patch.multiple(
'freqtrade.exchange.Exchange',
fetch_ticker=ticker,
buy=MagicMock(return_value={'id': limit_buy_order['id']}),
create_order=MagicMock(return_value={'id': limit_buy_order['id']}),
get_fee=fee,
)
default_conf['exchange']['pair_whitelist'] = []
@@ -507,7 +507,7 @@ def test_enter_positions_global_pairlock(default_conf, ticker, limit_buy_order,
mocker.patch.multiple(
'freqtrade.exchange.Exchange',
fetch_ticker=ticker,
buy=MagicMock(return_value={'id': limit_buy_order['id']}),
create_order=MagicMock(return_value={'id': limit_buy_order['id']}),
get_fee=fee,
)
freqtrade = FreqtradeBot(default_conf)
@@ -536,7 +536,7 @@ def test_create_trade_no_signal(default_conf, fee, mocker) -> None:
)
default_conf['stake_amount'] = 10
freqtrade = FreqtradeBot(default_conf)
patch_get_signal(freqtrade, value=(False, False))
patch_get_signal(freqtrade, value=(False, False, None))
Trade.query = MagicMock()
Trade.query.filter = MagicMock()
@@ -556,7 +556,7 @@ def test_create_trades_multiple_trades(default_conf, ticker, fee, mocker, limit_
mocker.patch.multiple(
'freqtrade.exchange.Exchange',
fetch_ticker=ticker,
buy=MagicMock(return_value=limit_buy_order_open),
create_order=MagicMock(return_value=limit_buy_order_open),
get_fee=fee,
)
freqtrade = FreqtradeBot(default_conf)
@@ -577,7 +577,7 @@ def test_create_trades_preopen(default_conf, ticker, fee, mocker, limit_buy_orde
mocker.patch.multiple(
'freqtrade.exchange.Exchange',
fetch_ticker=ticker,
buy=MagicMock(return_value=limit_buy_order_open),
create_order=MagicMock(return_value=limit_buy_order_open),
get_fee=fee,
)
freqtrade = FreqtradeBot(default_conf)
@@ -606,7 +606,7 @@ def test_process_trade_creation(default_conf, ticker, limit_buy_order, limit_buy
mocker.patch.multiple(
'freqtrade.exchange.Exchange',
fetch_ticker=ticker,
buy=MagicMock(return_value=limit_buy_order_open),
create_order=MagicMock(return_value=limit_buy_order_open),
fetch_order=MagicMock(return_value=limit_buy_order),
get_fee=fee,
)
@@ -641,7 +641,7 @@ def test_process_exchange_failures(default_conf, ticker, mocker) -> None:
mocker.patch.multiple(
'freqtrade.exchange.Exchange',
fetch_ticker=ticker,
buy=MagicMock(side_effect=TemporaryError)
create_order=MagicMock(side_effect=TemporaryError)
)
sleep_mock = mocker.patch('time.sleep', side_effect=lambda _: None)
@@ -658,7 +658,7 @@ def test_process_operational_exception(default_conf, ticker, mocker) -> None:
mocker.patch.multiple(
'freqtrade.exchange.Exchange',
fetch_ticker=ticker,
buy=MagicMock(side_effect=OperationalException)
create_order=MagicMock(side_effect=OperationalException)
)
worker = Worker(args=None, config=default_conf)
patch_get_signal(worker.freqtrade)
@@ -676,7 +676,7 @@ def test_process_trade_handling(default_conf, ticker, limit_buy_order_open, fee,
mocker.patch.multiple(
'freqtrade.exchange.Exchange',
fetch_ticker=ticker,
buy=MagicMock(return_value=limit_buy_order_open),
create_order=MagicMock(return_value=limit_buy_order_open),
fetch_order=MagicMock(return_value=limit_buy_order_open),
get_fee=fee,
)
@@ -703,7 +703,7 @@ def test_process_trade_no_whitelist_pair(default_conf, ticker, limit_buy_order,
mocker.patch.multiple(
'freqtrade.exchange.Exchange',
fetch_ticker=ticker,
buy=MagicMock(return_value={'id': limit_buy_order['id']}),
create_order=MagicMock(return_value={'id': limit_buy_order['id']}),
fetch_order=MagicMock(return_value=limit_buy_order),
get_fee=fee,
)
@@ -753,11 +753,14 @@ def test_process_informative_pairs_added(default_conf, ticker, mocker) -> None:
mocker.patch.multiple(
'freqtrade.exchange.Exchange',
fetch_ticker=ticker,
buy=MagicMock(side_effect=TemporaryError),
create_order=MagicMock(side_effect=TemporaryError),
refresh_latest_ohlcv=refresh_mock,
)
inf_pairs = MagicMock(return_value=[("BTC/ETH", '1m'), ("ETH/USDT", "1h")])
mocker.patch('freqtrade.strategy.interface.IStrategy.get_signal', return_value=(False, False))
mocker.patch(
'freqtrade.strategy.interface.IStrategy.get_signal',
return_value=(False, False, '')
)
mocker.patch('time.sleep', return_value=None)
freqtrade = FreqtradeBot(default_conf)
@@ -790,7 +793,7 @@ def test_execute_buy(mocker, default_conf, fee, limit_buy_order, limit_buy_order
'ask': 0.00001173,
'last': 0.00001172
}),
buy=buy_mm,
create_order=buy_mm,
get_min_pair_stake_amount=MagicMock(return_value=1),
get_fee=fee,
)
@@ -839,7 +842,8 @@ def test_execute_buy(mocker, default_conf, fee, limit_buy_order, limit_buy_order
limit_buy_order['cost'] = 100
limit_buy_order['id'] = '444'
mocker.patch('freqtrade.exchange.Exchange.buy', MagicMock(return_value=limit_buy_order))
mocker.patch('freqtrade.exchange.Exchange.create_order',
MagicMock(return_value=limit_buy_order))
assert freqtrade.execute_buy(pair, stake_amount)
trade = Trade.query.all()[2]
assert trade
@@ -855,7 +859,8 @@ def test_execute_buy(mocker, default_conf, fee, limit_buy_order, limit_buy_order
limit_buy_order['price'] = 0.5
limit_buy_order['cost'] = 40.495905365
limit_buy_order['id'] = '555'
mocker.patch('freqtrade.exchange.Exchange.buy', MagicMock(return_value=limit_buy_order))
mocker.patch('freqtrade.exchange.Exchange.create_order',
MagicMock(return_value=limit_buy_order))
assert freqtrade.execute_buy(pair, stake_amount)
trade = Trade.query.all()[3]
assert trade
@@ -889,7 +894,8 @@ def test_execute_buy(mocker, default_conf, fee, limit_buy_order, limit_buy_order
limit_buy_order['price'] = 0.5
limit_buy_order['cost'] = 0.0
limit_buy_order['id'] = '66'
mocker.patch('freqtrade.exchange.Exchange.buy', MagicMock(return_value=limit_buy_order))
mocker.patch('freqtrade.exchange.Exchange.create_order',
MagicMock(return_value=limit_buy_order))
assert not freqtrade.execute_buy(pair, stake_amount)
# Fail to get price...
@@ -908,7 +914,7 @@ def test_execute_buy_confirm_error(mocker, default_conf, fee, limit_buy_order) -
'ask': 0.00001173,
'last': 0.00001172
}),
buy=MagicMock(return_value=limit_buy_order),
create_order=MagicMock(return_value=limit_buy_order),
get_rate=MagicMock(return_value=0.11),
get_min_pair_stake_amount=MagicMock(return_value=1),
get_fee=fee,
@@ -970,8 +976,10 @@ def test_handle_stoploss_on_exchange(mocker, default_conf, fee, caplog,
'ask': 0.00001173,
'last': 0.00001172
}),
buy=MagicMock(return_value={'id': limit_buy_order['id']}),
sell=MagicMock(return_value={'id': limit_sell_order['id']}),
create_order=MagicMock(side_effect=[
{'id': limit_buy_order['id']},
{'id': limit_sell_order['id']},
]),
get_fee=fee,
)
mocker.patch.multiple(
@@ -1087,8 +1095,10 @@ def test_handle_sle_cancel_cant_recreate(mocker, default_conf, fee, caplog,
'ask': 0.00001173,
'last': 0.00001172
}),
buy=MagicMock(return_value={'id': limit_buy_order['id']}),
sell=MagicMock(return_value={'id': limit_sell_order['id']}),
create_order=MagicMock(side_effect=[
{'id': limit_buy_order['id']},
{'id': limit_sell_order['id']},
]),
get_fee=fee,
)
mocker.patch.multiple(
@@ -1116,7 +1126,10 @@ def test_create_stoploss_order_invalid_order(mocker, default_conf, caplog, fee,
limit_buy_order_open, limit_sell_order):
rpc_mock = patch_RPCManager(mocker)
patch_exchange(mocker)
sell_mock = MagicMock(return_value={'id': limit_sell_order['id']})
create_order_mock = MagicMock(side_effect=[
limit_buy_order_open,
{'id': limit_sell_order['id']}
])
mocker.patch.multiple(
'freqtrade.exchange.Exchange',
fetch_ticker=MagicMock(return_value={
@@ -1124,8 +1137,7 @@ def test_create_stoploss_order_invalid_order(mocker, default_conf, caplog, fee,
'ask': 0.00001173,
'last': 0.00001172
}),
buy=MagicMock(return_value=limit_buy_order_open),
sell=sell_mock,
create_order=create_order_mock,
get_fee=fee,
)
mocker.patch.multiple(
@@ -1147,10 +1159,10 @@ def test_create_stoploss_order_invalid_order(mocker, default_conf, caplog, fee,
assert log_has("Selling the trade forcefully", caplog)
# Should call a market sell
assert sell_mock.call_count == 1
assert sell_mock.call_args[1]['ordertype'] == 'market'
assert sell_mock.call_args[1]['pair'] == trade.pair
assert sell_mock.call_args[1]['amount'] == trade.amount
assert create_order_mock.call_count == 2
assert create_order_mock.call_args[1]['ordertype'] == 'market'
assert create_order_mock.call_args[1]['pair'] == trade.pair
assert create_order_mock.call_args[1]['amount'] == trade.amount
# Rpc is sending first buy, then sell
assert rpc_mock.call_count == 2
@@ -1171,8 +1183,10 @@ def test_create_stoploss_order_insufficient_funds(mocker, default_conf, caplog,
'ask': 0.00001173,
'last': 0.00001172
}),
buy=MagicMock(return_value=limit_buy_order_open),
sell=sell_mock,
create_order=MagicMock(side_effect=[
limit_buy_order_open,
sell_mock,
]),
get_fee=fee,
fetch_order=MagicMock(return_value={'status': 'canceled'}),
)
@@ -1212,8 +1226,10 @@ def test_handle_stoploss_on_exchange_trailing(mocker, default_conf, fee,
'ask': 0.00001173,
'last': 0.00001172
}),
buy=MagicMock(return_value={'id': limit_buy_order['id']}),
sell=MagicMock(return_value={'id': limit_sell_order['id']}),
create_order=MagicMock(side_effect=[
{'id': limit_buy_order['id']},
{'id': limit_sell_order['id']},
]),
get_fee=fee,
)
mocker.patch.multiple(
@@ -1318,8 +1334,10 @@ def test_handle_stoploss_on_exchange_trailing_error(mocker, default_conf, fee, c
'ask': 0.00001173,
'last': 0.00001172
}),
buy=MagicMock(return_value={'id': limit_buy_order['id']}),
sell=MagicMock(return_value={'id': limit_sell_order['id']}),
create_order=MagicMock(side_effect=[
{'id': limit_buy_order['id']},
{'id': limit_sell_order['id']},
]),
get_fee=fee,
)
mocker.patch.multiple(
@@ -1391,8 +1409,10 @@ def test_handle_stoploss_on_exchange_custom_stop(mocker, default_conf, fee,
'ask': 0.00001173,
'last': 0.00001172
}),
buy=MagicMock(return_value={'id': limit_buy_order['id']}),
sell=MagicMock(return_value={'id': limit_sell_order['id']}),
create_order=MagicMock(side_effect=[
{'id': limit_buy_order['id']},
{'id': limit_sell_order['id']},
]),
get_fee=fee,
)
mocker.patch.multiple(
@@ -1502,8 +1522,10 @@ def test_tsl_on_exchange_compatible_with_edge(mocker, edge_conf, fee, caplog,
'ask': 0.00001173,
'last': 0.00001172
}),
buy=MagicMock(return_value={'id': limit_buy_order['id']}),
sell=MagicMock(return_value={'id': limit_sell_order['id']}),
create_order=MagicMock(side_effect=[
{'id': limit_buy_order['id']},
{'id': limit_sell_order['id']},
]),
get_fee=fee,
stoploss=stoploss,
)
@@ -1840,8 +1862,10 @@ def test_handle_trade(default_conf, limit_buy_order, limit_sell_order_open, limi
'ask': 0.00001173,
'last': 0.00001172
}),
buy=MagicMock(return_value=limit_buy_order),
sell=MagicMock(return_value=limit_sell_order_open),
create_order=MagicMock(side_effect=[
limit_buy_order,
limit_sell_order_open,
]),
get_fee=fee,
)
freqtrade = FreqtradeBot(default_conf)
@@ -1857,7 +1881,7 @@ def test_handle_trade(default_conf, limit_buy_order, limit_sell_order_open, limi
assert trade.is_open is True
freqtrade.wallets.update()
patch_get_signal(freqtrade, value=(False, True))
patch_get_signal(freqtrade, value=(False, True, None))
assert freqtrade.handle_trade(trade) is True
assert trade.open_order_id == limit_sell_order['id']
@@ -1877,12 +1901,15 @@ def test_handle_overlapping_signals(default_conf, ticker, limit_buy_order_open,
mocker.patch.multiple(
'freqtrade.exchange.Exchange',
fetch_ticker=ticker,
buy=MagicMock(return_value=limit_buy_order_open),
create_order=MagicMock(side_effect=[
limit_buy_order_open,
{'id': 1234553382},
]),
get_fee=fee,
)
freqtrade = FreqtradeBot(default_conf)
patch_get_signal(freqtrade, value=(True, True))
patch_get_signal(freqtrade, value=(True, True, None))
freqtrade.strategy.min_roi_reached = MagicMock(return_value=False)
freqtrade.enter_positions()
@@ -1893,7 +1920,7 @@ def test_handle_overlapping_signals(default_conf, ticker, limit_buy_order_open,
assert nb_trades == 0
# Buy is triggering, so buying ...
patch_get_signal(freqtrade, value=(True, False))
patch_get_signal(freqtrade, value=(True, False, None))
freqtrade.enter_positions()
trades = Trade.query.all()
nb_trades = len(trades)
@@ -1901,7 +1928,7 @@ def test_handle_overlapping_signals(default_conf, ticker, limit_buy_order_open,
assert trades[0].is_open is True
# Buy and Sell are not triggering, so doing nothing ...
patch_get_signal(freqtrade, value=(False, False))
patch_get_signal(freqtrade, value=(False, False, None))
assert freqtrade.handle_trade(trades[0]) is False
trades = Trade.query.all()
nb_trades = len(trades)
@@ -1909,7 +1936,7 @@ def test_handle_overlapping_signals(default_conf, ticker, limit_buy_order_open,
assert trades[0].is_open is True
# Buy and Sell are triggering, so doing nothing ...
patch_get_signal(freqtrade, value=(True, True))
patch_get_signal(freqtrade, value=(True, True, None))
assert freqtrade.handle_trade(trades[0]) is False
trades = Trade.query.all()
nb_trades = len(trades)
@@ -1917,7 +1944,7 @@ def test_handle_overlapping_signals(default_conf, ticker, limit_buy_order_open,
assert trades[0].is_open is True
# Sell is triggering, guess what : we are Selling!
patch_get_signal(freqtrade, value=(False, True))
patch_get_signal(freqtrade, value=(False, True, None))
trades = Trade.query.all()
assert freqtrade.handle_trade(trades[0]) is True
@@ -1930,12 +1957,15 @@ def test_handle_trade_roi(default_conf, ticker, limit_buy_order_open,
mocker.patch.multiple(
'freqtrade.exchange.Exchange',
fetch_ticker=ticker,
buy=MagicMock(return_value=limit_buy_order_open),
create_order=MagicMock(side_effect=[
limit_buy_order_open,
{'id': 1234553382},
]),
get_fee=fee,
)
freqtrade = get_patched_freqtradebot(mocker, default_conf)
patch_get_signal(freqtrade, value=(True, False))
patch_get_signal(freqtrade, value=(True, False, None))
freqtrade.strategy.min_roi_reached = MagicMock(return_value=True)
freqtrade.enter_positions()
@@ -1948,21 +1978,24 @@ def test_handle_trade_roi(default_conf, ticker, limit_buy_order_open,
# we might just want to check if we are in a sell condition without
# executing
# if ROI is reached we must sell
patch_get_signal(freqtrade, value=(False, True))
patch_get_signal(freqtrade, value=(False, True, None))
assert freqtrade.handle_trade(trade)
assert log_has("ETH/BTC - Required profit reached. sell_type=SellType.ROI",
caplog)
def test_handle_trade_use_sell_signal(
default_conf, ticker, limit_buy_order_open, fee, mocker, caplog) -> None:
def test_handle_trade_use_sell_signal(default_conf, ticker, limit_buy_order_open,
limit_sell_order_open, fee, mocker, caplog) -> None:
# use_sell_signal is True buy default
caplog.set_level(logging.DEBUG)
patch_RPCManager(mocker)
mocker.patch.multiple(
'freqtrade.exchange.Exchange',
fetch_ticker=ticker,
buy=MagicMock(return_value=limit_buy_order_open),
create_order=MagicMock(side_effect=[
limit_buy_order_open,
limit_sell_order_open,
]),
get_fee=fee,
)
@@ -1974,10 +2007,10 @@ def test_handle_trade_use_sell_signal(
trade = Trade.query.first()
trade.is_open = True
patch_get_signal(freqtrade, value=(False, False))
patch_get_signal(freqtrade, value=(False, False, None))
assert not freqtrade.handle_trade(trade)
patch_get_signal(freqtrade, value=(False, True))
patch_get_signal(freqtrade, value=(False, True, None))
assert freqtrade.handle_trade(trade)
assert log_has("ETH/BTC - Sell signal received. sell_type=SellType.SELL_SIGNAL",
caplog)
@@ -1990,7 +2023,7 @@ def test_close_trade(default_conf, ticker, limit_buy_order, limit_buy_order_open
mocker.patch.multiple(
'freqtrade.exchange.Exchange',
fetch_ticker=ticker,
buy=MagicMock(return_value=limit_buy_order_open),
create_order=MagicMock(return_value=limit_buy_order_open),
get_fee=fee,
)
freqtrade = FreqtradeBot(default_conf)
@@ -2747,13 +2780,16 @@ def test_execute_sell_sloe_cancel_exception(mocker, default_conf, ticker, fee, c
mocker.patch('freqtrade.exchange.Exchange.cancel_stoploss_order',
side_effect=InvalidOrderException())
mocker.patch('freqtrade.wallets.Wallets.get_free', MagicMock(return_value=300))
sellmock = MagicMock(return_value={'id': '12345555'})
create_order_mock = MagicMock(side_effect=[
{'id': '12345554'},
{'id': '12345555'},
])
patch_exchange(mocker)
mocker.patch.multiple(
'freqtrade.exchange.Exchange',
fetch_ticker=ticker,
get_fee=fee,
sell=sellmock
create_order=create_order_mock,
)
freqtrade.strategy.order_types['stoploss_on_exchange'] = True
@@ -2768,7 +2804,7 @@ def test_execute_sell_sloe_cancel_exception(mocker, default_conf, ticker, fee, c
freqtrade.execute_sell(trade=trade, limit=1234,
sell_reason=SellCheckTuple(sell_type=SellType.STOP_LOSS))
assert sellmock.call_count == 1
assert create_order_mock.call_count == 2
assert log_has('Could not cancel stoploss order abcd', caplog)
@@ -2964,7 +3000,10 @@ def test_execute_sell_insufficient_funds_error(default_conf, ticker, fee,
'freqtrade.exchange.Exchange',
fetch_ticker=ticker,
get_fee=fee,
sell=MagicMock(side_effect=InsufficientFundsError())
create_order=MagicMock(side_effect=[
{'id': 1234553382},
InsufficientFundsError(),
]),
)
patch_get_signal(freqtrade)
@@ -2997,7 +3036,10 @@ def test_sell_profit_only_enable_profit(default_conf, limit_buy_order, limit_buy
'ask': 0.00001173,
'last': 0.00001172
}),
buy=MagicMock(return_value=limit_buy_order_open),
create_order=MagicMock(side_effect=[
limit_buy_order_open,
{'id': 1234553382},
]),
get_fee=fee,
)
default_conf.update({
@@ -3014,7 +3056,7 @@ def test_sell_profit_only_enable_profit(default_conf, limit_buy_order, limit_buy
trade = Trade.query.first()
trade.update(limit_buy_order)
freqtrade.wallets.update()
patch_get_signal(freqtrade, value=(False, True))
patch_get_signal(freqtrade, value=(False, True, None))
assert freqtrade.handle_trade(trade) is False
freqtrade.strategy.sell_profit_offset = 0.0
@@ -3034,7 +3076,10 @@ def test_sell_profit_only_disable_profit(default_conf, limit_buy_order, limit_bu
'ask': 0.00002173,
'last': 0.00002172
}),
buy=MagicMock(return_value=limit_buy_order_open),
create_order=MagicMock(side_effect=[
limit_buy_order_open,
{'id': 1234553382},
]),
get_fee=fee,
)
default_conf.update({
@@ -3049,7 +3094,7 @@ def test_sell_profit_only_disable_profit(default_conf, limit_buy_order, limit_bu
trade = Trade.query.first()
trade.update(limit_buy_order)
freqtrade.wallets.update()
patch_get_signal(freqtrade, value=(False, True))
patch_get_signal(freqtrade, value=(False, True, None))
assert freqtrade.handle_trade(trade) is True
assert trade.sell_reason == SellType.SELL_SIGNAL.value
@@ -3065,7 +3110,10 @@ def test_sell_profit_only_enable_loss(default_conf, limit_buy_order, limit_buy_o
'ask': 0.00000173,
'last': 0.00000172
}),
buy=MagicMock(return_value=limit_buy_order_open),
create_order=MagicMock(side_effect=[
limit_buy_order_open,
{'id': 1234553382},
]),
get_fee=fee,
)
default_conf.update({
@@ -3080,7 +3128,7 @@ def test_sell_profit_only_enable_loss(default_conf, limit_buy_order, limit_buy_o
trade = Trade.query.first()
trade.update(limit_buy_order)
patch_get_signal(freqtrade, value=(False, True))
patch_get_signal(freqtrade, value=(False, True, None))
assert freqtrade.handle_trade(trade) is False
@@ -3095,7 +3143,10 @@ def test_sell_profit_only_disable_loss(default_conf, limit_buy_order, limit_buy_
'ask': 0.0000173,
'last': 0.0000172
}),
buy=MagicMock(return_value=limit_buy_order_open),
create_order=MagicMock(side_effect=[
limit_buy_order_open,
{'id': 1234553382},
]),
get_fee=fee,
)
default_conf.update({
@@ -3112,7 +3163,7 @@ def test_sell_profit_only_disable_loss(default_conf, limit_buy_order, limit_buy_
trade = Trade.query.first()
trade.update(limit_buy_order)
freqtrade.wallets.update()
patch_get_signal(freqtrade, value=(False, True))
patch_get_signal(freqtrade, value=(False, True, None))
assert freqtrade.handle_trade(trade) is True
assert trade.sell_reason == SellType.SELL_SIGNAL.value
@@ -3128,7 +3179,10 @@ def test_sell_not_enough_balance(default_conf, limit_buy_order, limit_buy_order_
'ask': 0.00002173,
'last': 0.00002172
}),
buy=MagicMock(return_value=limit_buy_order_open),
create_order=MagicMock(side_effect=[
limit_buy_order_open,
{'id': 1234553382},
]),
get_fee=fee,
)
@@ -3141,7 +3195,7 @@ def test_sell_not_enough_balance(default_conf, limit_buy_order, limit_buy_order_
trade = Trade.query.first()
amnt = trade.amount
trade.update(limit_buy_order)
patch_get_signal(freqtrade, value=(False, True))
patch_get_signal(freqtrade, value=(False, True, None))
mocker.patch('freqtrade.wallets.Wallets.get_free', MagicMock(return_value=trade.amount * 0.985))
assert freqtrade.handle_trade(trade) is True
@@ -3246,7 +3300,10 @@ def test_ignore_roi_if_buy_signal(default_conf, limit_buy_order, limit_buy_order
'ask': 0.0000173,
'last': 0.0000172
}),
buy=MagicMock(return_value=limit_buy_order_open),
create_order=MagicMock(side_effect=[
limit_buy_order_open,
{'id': 1234553382},
]),
get_fee=fee,
)
default_conf['ignore_roi_if_buy_signal'] = True
@@ -3260,11 +3317,11 @@ def test_ignore_roi_if_buy_signal(default_conf, limit_buy_order, limit_buy_order
trade = Trade.query.first()
trade.update(limit_buy_order)
freqtrade.wallets.update()
patch_get_signal(freqtrade, value=(True, True))
patch_get_signal(freqtrade, value=(True, True, None))
assert freqtrade.handle_trade(trade) is False
# Test if buy-signal is absent (should sell due to roi = true)
patch_get_signal(freqtrade, value=(False, True))
patch_get_signal(freqtrade, value=(False, True, None))
assert freqtrade.handle_trade(trade) is True
assert trade.sell_reason == SellType.ROI.value
@@ -3280,7 +3337,10 @@ def test_trailing_stop_loss(default_conf, limit_buy_order_open, limit_buy_order,
'ask': 0.00001099,
'last': 0.00001099
}),
buy=MagicMock(return_value=limit_buy_order_open),
create_order=MagicMock(side_effect=[
limit_buy_order_open,
{'id': 1234553382},
]),
get_fee=fee,
)
default_conf['trailing_stop'] = True
@@ -3332,7 +3392,10 @@ def test_trailing_stop_loss_positive(default_conf, limit_buy_order, limit_buy_or
'ask': buy_price - 0.000001,
'last': buy_price - 0.000001
}),
buy=MagicMock(return_value=limit_buy_order_open),
create_order=MagicMock(side_effect=[
limit_buy_order_open,
{'id': 1234553382},
]),
get_fee=fee,
)
default_conf['trailing_stop'] = True
@@ -3389,7 +3452,10 @@ def test_trailing_stop_loss_offset(default_conf, limit_buy_order, limit_buy_orde
'ask': buy_price - 0.000001,
'last': buy_price - 0.000001
}),
buy=MagicMock(return_value=limit_buy_order_open),
create_order=MagicMock(side_effect=[
limit_buy_order_open,
{'id': 1234553382},
]),
get_fee=fee,
)
patch_whitelist(mocker, default_conf)
@@ -3449,7 +3515,7 @@ def test_tsl_only_offset_reached(default_conf, limit_buy_order, limit_buy_order_
'ask': buy_price,
'last': buy_price
}),
buy=MagicMock(return_value=limit_buy_order_open),
create_order=MagicMock(return_value=limit_buy_order_open),
get_fee=fee,
)
patch_whitelist(mocker, default_conf)
@@ -3509,7 +3575,11 @@ def test_disable_ignore_roi_if_buy_signal(default_conf, limit_buy_order, limit_b
'ask': 0.00000173,
'last': 0.00000172
}),
buy=MagicMock(return_value=limit_buy_order_open),
create_order=MagicMock(side_effect=[
limit_buy_order_open,
{'id': 1234553382},
{'id': 1234553383}
]),
get_fee=fee,
_is_dry_limit_order_filled=MagicMock(return_value=False),
)
@@ -3525,11 +3595,11 @@ def test_disable_ignore_roi_if_buy_signal(default_conf, limit_buy_order, limit_b
trade = Trade.query.first()
trade.update(limit_buy_order)
# Sell due to min_roi_reached
patch_get_signal(freqtrade, value=(True, True))
patch_get_signal(freqtrade, value=(True, True, None))
assert freqtrade.handle_trade(trade) is True
# Test if buy-signal is absent
patch_get_signal(freqtrade, value=(False, True))
patch_get_signal(freqtrade, value=(False, True, None))
assert freqtrade.handle_trade(trade) is True
assert trade.sell_reason == SellType.SELL_SIGNAL.value
@@ -3917,7 +3987,7 @@ def test_order_book_depth_of_market(default_conf, ticker, limit_buy_order_open,
mocker.patch.multiple(
'freqtrade.exchange.Exchange',
fetch_ticker=ticker,
buy=MagicMock(return_value=limit_buy_order_open),
create_order=MagicMock(return_value=limit_buy_order_open),
get_fee=fee,
)
@@ -3954,7 +4024,7 @@ def test_order_book_depth_of_market_high_delta(default_conf, ticker, limit_buy_o
mocker.patch.multiple(
'freqtrade.exchange.Exchange',
fetch_ticker=ticker,
buy=MagicMock(return_value={'id': limit_buy_order['id']}),
create_order=MagicMock(return_value={'id': limit_buy_order['id']}),
get_fee=fee,
)
# Save state of current whitelist
@@ -4051,8 +4121,10 @@ def test_order_book_ask_strategy(default_conf, limit_buy_order_open, limit_buy_o
'ask': 0.00001173,
'last': 0.00001172
}),
buy=MagicMock(return_value=limit_buy_order_open),
sell=MagicMock(return_value=limit_sell_order_open),
create_order=MagicMock(side_effect=[
limit_buy_order_open,
limit_sell_order_open,
]),
get_fee=fee,
)
freqtrade = FreqtradeBot(default_conf)
@@ -4068,7 +4140,7 @@ def test_order_book_ask_strategy(default_conf, limit_buy_order_open, limit_buy_o
freqtrade.wallets.update()
assert trade.is_open is True
patch_get_signal(freqtrade, value=(False, True))
patch_get_signal(freqtrade, value=(False, True, None))
assert freqtrade.handle_trade(trade) is True
assert trade.close_rate_requested == order_book_l2.return_value['asks'][0][0]
@@ -4117,7 +4189,7 @@ def test_sync_wallet_dry_run(mocker, default_conf, ticker, fee, limit_buy_order_
mocker.patch.multiple(
'freqtrade.exchange.Exchange',
fetch_ticker=ticker,
buy=MagicMock(return_value=limit_buy_order_open),
create_order=MagicMock(return_value=limit_buy_order_open),
get_fee=fee,
)

View File

@@ -69,7 +69,7 @@ def test_init_dryrun_db(default_conf, tmpdir):
def test_enter_exit_side(fee):
trade = Trade(
id=2,
pair='ETH/BTC',
pair='ADA/USDT',
stake_amount=0.001,
open_rate=0.01,
amount=5,
@@ -94,10 +94,10 @@ def test_enter_exit_side(fee):
def test__set_stop_loss_isolated_liq(fee):
trade = Trade(
id=2,
pair='ETH/BTC',
stake_amount=0.001,
open_rate=0.01,
amount=5,
pair='ADA/USDT',
stake_amount=60.0,
open_rate=2.0,
amount=30.0,
is_open=True,
open_date=arrow.utcnow().datetime,
fee_open=fee.return_value,
@@ -227,7 +227,7 @@ def test_interest(market_buy_order_usdt, fee):
"""
trade = Trade(
pair='ETH/BTC',
pair='ADA/USDT',
stake_amount=20.0,
amount=30.0,
open_rate=2.0,
@@ -404,7 +404,7 @@ def test_borrowed(limit_buy_order_usdt, limit_sell_order_usdt, fee, caplog):
trade = Trade(
id=2,
pair='ETH/BTC',
pair='ADA/USDT',
stake_amount=60.0,
open_rate=2.0,
amount=30.0,
@@ -498,7 +498,7 @@ def test_update_limit_order(limit_buy_order_usdt, limit_sell_order_usdt, fee, ca
trade = Trade(
id=2,
pair='ETH/BTC',
pair='ADA/USDT',
stake_amount=60.0,
open_rate=2.0,
amount=30.0,
@@ -519,7 +519,7 @@ def test_update_limit_order(limit_buy_order_usdt, limit_sell_order_usdt, fee, ca
assert trade.close_profit is None
assert trade.close_date is None
assert log_has_re(r"LIMIT_BUY has been fulfilled for Trade\(id=2, "
r'pair=ETH/BTC, amount=30.00000000, '
r'pair=ADA/USDT, amount=30.00000000, '
r"is_short=False, leverage=1.0, open_rate=2.00000000, open_since=.*\).",
caplog)
@@ -531,14 +531,14 @@ def test_update_limit_order(limit_buy_order_usdt, limit_sell_order_usdt, fee, ca
assert trade.close_profit == round(0.0945137157107232, 8)
assert trade.close_date is not None
assert log_has_re(r"LIMIT_SELL has been fulfilled for Trade\(id=2, "
r"pair=ETH/BTC, amount=30.00000000, "
r"pair=ADA/USDT, amount=30.00000000, "
r"is_short=False, leverage=1.0, open_rate=2.00000000, open_since=.*\).",
caplog)
caplog.clear()
trade = Trade(
id=226531,
pair='ETH/BTC',
pair='ADA/USDT',
stake_amount=20.0,
open_rate=2.0,
amount=30.0,
@@ -561,7 +561,7 @@ def test_update_limit_order(limit_buy_order_usdt, limit_sell_order_usdt, fee, ca
assert trade.close_date is None
assert log_has_re(r"LIMIT_SELL has been fulfilled for Trade\(id=226531, "
r"pair=ETH/BTC, amount=30.00000000, "
r"pair=ADA/USDT, amount=30.00000000, "
r"is_short=True, leverage=3.0, open_rate=2.20000000, open_since=.*\).",
caplog)
caplog.clear()
@@ -573,7 +573,7 @@ def test_update_limit_order(limit_buy_order_usdt, limit_sell_order_usdt, fee, ca
assert trade.close_profit == round(0.2589996297562085, 8)
assert trade.close_date is not None
assert log_has_re(r"LIMIT_BUY has been fulfilled for Trade\(id=226531, "
r"pair=ETH/BTC, amount=30.00000000, "
r"pair=ADA/USDT, amount=30.00000000, "
r"is_short=True, leverage=3.0, open_rate=2.20000000, open_since=.*\).",
caplog)
caplog.clear()
@@ -583,7 +583,7 @@ def test_update_limit_order(limit_buy_order_usdt, limit_sell_order_usdt, fee, ca
def test_update_market_order(market_buy_order_usdt, market_sell_order_usdt, fee, caplog):
trade = Trade(
id=1,
pair='ETH/BTC',
pair='ADA/USDT',
stake_amount=60.0,
open_rate=2.0,
amount=30.0,
@@ -601,7 +601,7 @@ def test_update_market_order(market_buy_order_usdt, market_sell_order_usdt, fee,
assert trade.close_profit is None
assert trade.close_date is None
assert log_has_re(r"MARKET_BUY has been fulfilled for Trade\(id=1, "
r"pair=ETH/BTC, amount=30.00000000, is_short=False, leverage=1.0, "
r"pair=ADA/USDT, amount=30.00000000, is_short=False, leverage=1.0, "
r"open_rate=2.00000000, open_since=.*\).",
caplog)
@@ -614,7 +614,7 @@ def test_update_market_order(market_buy_order_usdt, market_sell_order_usdt, fee,
assert trade.close_profit == round(0.0945137157107232, 8)
assert trade.close_date is not None
assert log_has_re(r"MARKET_SELL has been fulfilled for Trade\(id=1, "
r"pair=ETH/BTC, amount=30.00000000, is_short=False, leverage=1.0, "
r"pair=ADA/USDT, amount=30.00000000, is_short=False, leverage=1.0, "
r"open_rate=2.00000000, open_since=.*\).",
caplog)
@@ -622,7 +622,7 @@ def test_update_market_order(market_buy_order_usdt, market_sell_order_usdt, fee,
@pytest.mark.usefixtures("init_persistence")
def test_calc_open_close_trade_price(limit_buy_order_usdt, limit_sell_order_usdt, fee):
trade = Trade(
pair='ETH/BTC',
pair='ADA/USDT',
stake_amount=60.0,
open_rate=2.0,
amount=30.0,
@@ -685,7 +685,7 @@ def test_calc_open_close_trade_price(limit_buy_order_usdt, limit_sell_order_usdt
@pytest.mark.usefixtures("init_persistence")
def test_trade_close(limit_buy_order_usdt, limit_sell_order_usdt, fee):
trade = Trade(
pair='ETH/BTC',
pair='ADA/USDT',
stake_amount=60.0,
open_rate=2.0,
amount=30.0,
@@ -710,14 +710,14 @@ def test_trade_close(limit_buy_order_usdt, limit_sell_order_usdt, fee):
# Close should NOT update close_date if the trade has been closed already
assert trade.is_open is False
trade.close_date = new_date
trade.close(0.02)
trade.close(2.2)
assert trade.close_date == new_date
@pytest.mark.usefixtures("init_persistence")
def test_calc_close_trade_price_exception(limit_buy_order_usdt, fee):
trade = Trade(
pair='ETH/BTC',
pair='ADA/USDT',
stake_amount=60.0,
open_rate=2.0,
amount=30.0,
@@ -734,7 +734,7 @@ def test_calc_close_trade_price_exception(limit_buy_order_usdt, fee):
@pytest.mark.usefixtures("init_persistence")
def test_update_open_order(limit_buy_order_usdt):
trade = Trade(
pair='ETH/BTC',
pair='ADA/USDT',
stake_amount=60.0,
open_rate=2.0,
amount=30.0,
@@ -758,7 +758,7 @@ def test_update_open_order(limit_buy_order_usdt):
@pytest.mark.usefixtures("init_persistence")
def test_update_invalid_order(limit_buy_order_usdt):
trade = Trade(
pair='ETH/BTC',
pair='ADA/USDT',
stake_amount=60.0,
amount=30.0,
open_rate=2.0,
@@ -788,7 +788,7 @@ def test_calc_open_trade_value(limit_buy_order_usdt, fee):
# 1x, 3x: 30 * 2 + 30 * 2 * 0.003 = 60.18 quote
# -1x,-3x: 30 * 2 - 30 * 2 * 0.003 = 59.82 quote
trade = Trade(
pair='ETH/BTC',
pair='ADA/USDT',
stake_amount=60.0,
amount=30.0,
open_rate=2.0,
@@ -823,7 +823,7 @@ def test_calc_open_trade_value(limit_buy_order_usdt, fee):
@pytest.mark.usefixtures("init_persistence")
def test_calc_close_trade_price(limit_buy_order_usdt, limit_sell_order_usdt, fee):
trade = Trade(
pair='ETH/BTC',
pair='ADA/USDT',
stake_amount=60.0,
amount=30.0,
open_rate=2.0,
@@ -1007,7 +1007,7 @@ def test_calc_profit(limit_buy_order_usdt, limit_sell_order_usdt, fee):
2.2 quote: (65.802 / 60.15) - 1 = 0.09396508728179565
"""
trade = Trade(
pair='ETH/BTC',
pair='ADA/USDT',
stake_amount=60.0,
amount=30.0,
open_rate=2.0,
@@ -1109,7 +1109,7 @@ def test_calc_profit(limit_buy_order_usdt, limit_sell_order_usdt, fee):
@pytest.mark.usefixtures("init_persistence")
def test_calc_profit_ratio(limit_buy_order_usdt, limit_sell_order_usdt, fee):
trade = Trade(
pair='ETH/BTC',
pair='ADA/USDT',
stake_amount=60.0,
amount=30.0,
open_rate=2.0,
@@ -1214,7 +1214,7 @@ def test_clean_dry_run_db(default_conf, fee):
# Simulate dry_run entries
trade = Trade(
pair='ETH/BTC',
pair='ADA/USDT',
stake_amount=0.001,
amount=123.0,
fee_open=fee.return_value,
@@ -1259,96 +1259,6 @@ 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(mocker, default_conf, fee):
"""
Test Database migration(starting with old pairformat)
"""
amount = 103.223
create_table_old = """CREATE TABLE IF NOT EXISTS "trades" (
id INTEGER NOT NULL,
exchange VARCHAR NOT NULL,
pair VARCHAR NOT NULL,
is_open BOOLEAN NOT NULL,
fee FLOAT NOT NULL,
open_rate FLOAT,
close_rate FLOAT,
close_profit FLOAT,
stake_amount FLOAT NOT NULL,
amount FLOAT,
open_date DATETIME NOT NULL,
close_date DATETIME,
open_order_id VARCHAR,
PRIMARY KEY (id),
CHECK (is_open IN (0, 1))
);"""
insert_table_old = """INSERT INTO trades (exchange, pair, is_open, open_order_id, fee,
open_rate, stake_amount, amount, open_date)
VALUES ('binance', 'BTC_ETC', 1, '123123', {fee},
0.00258580, {stake}, {amount},
'2017-11-28 12:44:24.000000')
""".format(fee=fee.return_value,
stake=default_conf.get("stake_amount"),
amount=amount
)
insert_table_old2 = """INSERT INTO trades (exchange, pair, is_open, fee,
open_rate, close_rate, stake_amount, amount, open_date)
VALUES ('binance', 'BTC_ETC', 0, {fee},
0.00258580, 0.00268580, {stake}, {amount},
'2017-11-28 12:44:24.000000')
""".format(fee=fee.return_value,
stake=default_conf.get("stake_amount"),
amount=amount
)
engine = create_engine('sqlite://')
mocker.patch('freqtrade.persistence.models.create_engine', lambda *args, **kwargs: engine)
# Create table using the old format
with engine.begin() as connection:
connection.execute(text(create_table_old))
connection.execute(text(insert_table_old))
connection.execute(text(insert_table_old2))
# Run init to test migration
init_db(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()
assert trade.fee_open == fee.return_value
assert trade.fee_close == fee.return_value
assert trade.open_rate_requested is None
assert trade.close_rate_requested is None
assert trade.is_open == 1
assert trade.amount == amount
assert trade.amount_requested == amount
assert trade.stake_amount == default_conf.get("stake_amount")
assert trade.pair == "ETC/BTC"
assert trade.exchange == "binance"
assert trade.max_rate == 0.0
assert trade.stop_loss == 0.0
assert trade.initial_stop_loss == 0.0
assert trade.open_trade_value == trade._calc_open_trade_value()
assert trade.close_profit_abs is None
assert trade.fee_open_cost is None
assert trade.fee_open_currency is None
assert trade.fee_close_cost is None
assert trade.fee_close_currency is None
assert trade.timeframe is None
trade = Trade.query.filter(Trade.id == 2).first()
assert trade.close_rate is not None
assert trade.is_open == 0
assert trade.open_rate_requested is None
assert trade.close_rate_requested is None
assert trade.close_rate is not None
assert pytest.approx(trade.close_profit_abs) == trade.calc_profit()
assert trade.sell_order_status is None
# Should've created one order
assert len(Order.query.all()) == 1
order = Order.query.first()
assert order.order_id == '123123'
assert order.ft_order_side == 'buy'
def test_migrate_new(mocker, default_conf, fee, caplog):
"""
Test Database migration (starting with new pairformat)
@@ -1571,9 +1481,9 @@ def test_migrate_mid_state(mocker, default_conf, fee, caplog):
def test_adjust_stop_loss(fee):
trade = Trade(
pair='ETH/BTC',
stake_amount=0.001,
amount=5,
pair='ADA/USDT',
stake_amount=30.0,
amount=30,
fee_open=fee.return_value,
fee_close=fee.return_value,
exchange='binance',
@@ -1623,7 +1533,7 @@ def test_adjust_stop_loss(fee):
def test_adjust_stop_loss_short(fee):
trade = Trade(
pair='ETH/BTC',
pair='ADA/USDT',
stake_amount=0.001,
amount=5,
fee_open=fee.return_value,
@@ -1677,9 +1587,9 @@ def test_adjust_stop_loss_short(fee):
def test_adjust_min_max_rates(fee):
trade = Trade(
pair='ETH/BTC',
stake_amount=0.001,
amount=5,
pair='ADA/USDT',
stake_amount=30.0,
amount=30.0,
fee_open=fee.return_value,
fee_close=fee.return_value,
exchange='binance',
@@ -1735,7 +1645,7 @@ def test_to_json(default_conf, fee):
# Simulate dry_run entries
trade = Trade(
pair='ETH/BTC',
pair='ADA/USDT',
stake_amount=0.001,
amount=123.0,
amount_requested=123.0,
@@ -1744,13 +1654,14 @@ def test_to_json(default_conf, fee):
open_date=arrow.utcnow().shift(hours=-2).datetime,
open_rate=0.123,
exchange='binance',
buy_tag=None,
open_order_id='dry_run_buy_12345'
)
result = trade.to_json()
assert isinstance(result, dict)
assert result == {'trade_id': None,
'pair': 'ETH/BTC',
'pair': 'ADA/USDT',
'is_open': None,
'open_date': trade.open_date.strftime("%Y-%m-%d %H:%M:%S"),
'open_timestamp': int(trade.open_date.timestamp() * 1000),
@@ -1793,6 +1704,7 @@ def test_to_json(default_conf, fee):
'min_rate': None,
'max_rate': None,
'strategy': None,
'buy_tag': None,
'timeframe': None,
'exchange': 'binance',
'leverage': None,
@@ -1813,6 +1725,7 @@ def test_to_json(default_conf, fee):
close_date=arrow.utcnow().shift(hours=-1).datetime,
open_rate=0.123,
close_rate=0.125,
buy_tag='buys_signal_001',
exchange='binance',
)
result = trade.to_json()
@@ -1862,6 +1775,7 @@ def test_to_json(default_conf, fee):
'sell_reason': None,
'sell_order_status': None,
'strategy': None,
'buy_tag': 'buys_signal_001',
'timeframe': None,
'exchange': 'binance',
'leverage': None,
@@ -1874,11 +1788,11 @@ def test_to_json(default_conf, fee):
def test_stoploss_reinitialization(default_conf, fee):
init_db(default_conf['db_url'])
trade = Trade(
pair='ETH/BTC',
stake_amount=0.001,
pair='ADA/USDT',
stake_amount=30.0,
fee_open=fee.return_value,
open_date=arrow.utcnow().shift(hours=-2).datetime,
amount=10,
amount=30.0,
fee_close=fee.return_value,
exchange='binance',
open_rate=1,
@@ -1934,7 +1848,7 @@ def test_stoploss_reinitialization(default_conf, fee):
def test_stoploss_reinitialization_short(default_conf, fee):
init_db(default_conf['db_url'])
trade = Trade(
pair='ETH/BTC',
pair='ADA/USDT',
stake_amount=0.001,
fee_open=fee.return_value,
open_date=arrow.utcnow().shift(hours=-2).datetime,
@@ -1993,11 +1907,11 @@ def test_stoploss_reinitialization_short(default_conf, fee):
def test_update_fee(fee):
trade = Trade(
pair='ETH/BTC',
stake_amount=0.001,
pair='ADA/USDT',
stake_amount=30.0,
fee_open=fee.return_value,
open_date=arrow.utcnow().shift(hours=-2).datetime,
amount=10,
amount=30.0,
fee_close=fee.return_value,
exchange='binance',
open_rate=1,
@@ -2032,11 +1946,11 @@ def test_update_fee(fee):
def test_fee_updated(fee):
trade = Trade(
pair='ETH/BTC',
stake_amount=0.001,
pair='ADA/USDT',
stake_amount=30.0,
fee_open=fee.return_value,
open_date=arrow.utcnow().shift(hours=-2).datetime,
amount=10,
amount=30.0,
fee_close=fee.return_value,
exchange='binance',
open_rate=1,
@@ -2164,16 +2078,16 @@ def test_get_best_pair_lev(fee):
@pytest.mark.usefixtures("init_persistence")
def test_update_order_from_ccxt(caplog):
# Most basic order return (only has orderid)
o = Order.parse_from_ccxt_object({'id': '1234'}, 'ETH/BTC', 'buy')
o = Order.parse_from_ccxt_object({'id': '1234'}, 'ADA/USDT', 'buy')
assert isinstance(o, Order)
assert o.ft_pair == 'ETH/BTC'
assert o.ft_pair == 'ADA/USDT'
assert o.ft_order_side == 'buy'
assert o.order_id == '1234'
assert o.ft_is_open
ccxt_order = {
'id': '1234',
'side': 'buy',
'symbol': 'ETH/BTC',
'symbol': 'ADA/USDT',
'type': 'limit',
'price': 1234.5,
'amount': 20.0,
@@ -2182,9 +2096,9 @@ def test_update_order_from_ccxt(caplog):
'status': 'open',
'timestamp': 1599394315123
}
o = Order.parse_from_ccxt_object(ccxt_order, 'ETH/BTC', 'buy')
o = Order.parse_from_ccxt_object(ccxt_order, 'ADA/USDT', 'buy')
assert isinstance(o, Order)
assert o.ft_pair == 'ETH/BTC'
assert o.ft_pair == 'ADA/USDT'
assert o.ft_order_side == 'buy'
assert o.order_id == '1234'
assert o.order_type == 'limit'

View File

@@ -125,7 +125,7 @@ def test_get_trade_stake_amount_no_stake_amount(default_conf, mocker) -> None:
(1, None, 50, 66.66666),
(0.99, None, 49.5, 66.0),
(0.50, None, 25, 33.3333),
# Tests with capital ignore balance_ratio
# Tests with capital ignore balance_ratio
(1, 100, 50, 0.0),
(0.99, 200, 50, 66.66666),
(0.99, 150, 50, 50),
@@ -138,7 +138,7 @@ def test_get_trade_stake_amount_unlimited_amount(default_conf, ticker, balance_r
mocker.patch.multiple(
'freqtrade.exchange.Exchange',
fetch_ticker=ticker,
buy=MagicMock(return_value=limit_buy_order_open),
create_order=MagicMock(return_value=limit_buy_order_open),
get_fee=fee
)