Merge branch 'develop' into pr/mkavinkumar1/6545

This commit is contained in:
Matthias
2022-06-14 06:36:16 +02:00
52 changed files with 1053 additions and 1028 deletions

View File

@@ -325,7 +325,7 @@ def create_mock_trades_with_leverage(fee, use_db: bool = True):
Trade.query.session.flush()
def create_mock_trades_usdt(fee, use_db: bool = True):
def create_mock_trades_usdt(fee, is_short: Optional[bool] = False, use_db: bool = True):
"""
Create some fake trades ...
"""
@@ -335,26 +335,29 @@ def create_mock_trades_usdt(fee, use_db: bool = True):
else:
LocalTrade.add_bt_trade(trade)
is_short1 = is_short if is_short is not None else True
is_short2 = is_short if is_short is not None else False
# Simulate dry_run entries
trade = mock_trade_usdt_1(fee)
trade = mock_trade_usdt_1(fee, is_short1)
add_trade(trade)
trade = mock_trade_usdt_2(fee)
trade = mock_trade_usdt_2(fee, is_short1)
add_trade(trade)
trade = mock_trade_usdt_3(fee)
trade = mock_trade_usdt_3(fee, is_short1)
add_trade(trade)
trade = mock_trade_usdt_4(fee)
trade = mock_trade_usdt_4(fee, is_short2)
add_trade(trade)
trade = mock_trade_usdt_5(fee)
trade = mock_trade_usdt_5(fee, is_short2)
add_trade(trade)
trade = mock_trade_usdt_6(fee)
trade = mock_trade_usdt_6(fee, is_short1)
add_trade(trade)
trade = mock_trade_usdt_7(fee)
trade = mock_trade_usdt_7(fee, is_short1)
add_trade(trade)
if use_db:
Trade.commit()

View File

@@ -6,47 +6,84 @@ from freqtrade.persistence.models import Order, Trade
MOCK_TRADE_COUNT = 6
def mock_order_usdt_1():
def entry_side(is_short: bool):
return "sell" if is_short else "buy"
def exit_side(is_short: bool):
return "buy" if is_short else "sell"
def direc(is_short: bool):
return "short" if is_short else "long"
def mock_order_usdt_1(is_short: bool):
return {
'id': '1234',
'symbol': 'ADA/USDT',
'id': f'prod_entry_1_{direc(is_short)}',
'symbol': 'LTC/USDT',
'status': 'closed',
'side': 'buy',
'side': entry_side(is_short),
'type': 'limit',
'price': 2.0,
'amount': 10.0,
'filled': 10.0,
'price': 10.0,
'amount': 2.0,
'filled': 2.0,
'remaining': 0.0,
}
def mock_trade_usdt_1(fee):
def mock_order_usdt_1_exit(is_short: bool):
return {
'id': f'prod_exit_1_{direc(is_short)}',
'symbol': 'LTC/USDT',
'status': 'closed',
'side': exit_side(is_short),
'type': 'limit',
'price': 8.0,
'amount': 2.0,
'filled': 2.0,
'remaining': 0.0,
}
def mock_trade_usdt_1(fee, is_short: bool):
"""
Simulate prod entry with open sell order
"""
trade = Trade(
pair='ADA/USDT',
pair='LTC/USDT',
stake_amount=20.0,
amount=10.0,
amount_requested=10.0,
amount=2.0,
amount_requested=2.0,
open_date=datetime.now(tz=timezone.utc) - timedelta(days=2, minutes=20),
close_date=datetime.now(tz=timezone.utc) - timedelta(days=2, minutes=5),
fee_open=fee.return_value,
fee_close=fee.return_value,
is_open=True,
open_date=datetime.now(tz=timezone.utc) - timedelta(minutes=17),
open_rate=2.0,
is_open=False,
open_rate=10.0,
close_rate=8.0,
close_profit=-0.2,
close_profit_abs=-4.0,
exchange='binance',
open_order_id='dry_run_buy_12345',
strategy='StrategyTestV2',
strategy='SampleStrategy',
open_order_id=f'prod_exit_1_{direc(is_short)}',
timeframe=5,
is_short=is_short,
)
o = Order.parse_from_ccxt_object(mock_order_usdt_1(), 'ADA/USDT', 'buy')
o = Order.parse_from_ccxt_object(mock_order_usdt_1(is_short), 'LTC/USDT', entry_side(is_short))
trade.orders.append(o)
o = Order.parse_from_ccxt_object(mock_order_usdt_1_exit(is_short),
'LTC/USDT', exit_side(is_short))
trade.orders.append(o)
return trade
def mock_order_usdt_2():
def mock_order_usdt_2(is_short: bool):
return {
'id': '1235',
'id': f'1235_{direc(is_short)}',
'symbol': 'ETC/USDT',
'status': 'closed',
'side': 'buy',
'side': entry_side(is_short),
'type': 'limit',
'price': 2.0,
'amount': 100.0,
@@ -55,12 +92,12 @@ def mock_order_usdt_2():
}
def mock_order_usdt_2_sell():
def mock_order_usdt_2_exit(is_short: bool):
return {
'id': '12366',
'id': f'12366_{direc(is_short)}',
'symbol': 'ETC/USDT',
'status': 'closed',
'side': 'sell',
'side': exit_side(is_short),
'type': 'limit',
'price': 2.05,
'amount': 100.0,
@@ -69,7 +106,7 @@ def mock_order_usdt_2_sell():
}
def mock_trade_usdt_2(fee):
def mock_trade_usdt_2(fee, is_short: bool):
"""
Closed trade...
"""
@@ -82,30 +119,33 @@ def mock_trade_usdt_2(fee):
fee_close=fee.return_value,
open_rate=2.0,
close_rate=2.05,
close_profit=5.0,
close_profit=0.05,
close_profit_abs=3.9875,
exchange='binance',
is_open=False,
open_order_id='dry_run_sell_12345',
open_order_id=f'12366_{direc(is_short)}',
strategy='StrategyTestV2',
timeframe=5,
exit_reason='sell_signal',
enter_tag='TEST1',
exit_reason='exit_signal',
open_date=datetime.now(tz=timezone.utc) - timedelta(minutes=20),
close_date=datetime.now(tz=timezone.utc) - timedelta(minutes=2),
is_short=is_short,
)
o = Order.parse_from_ccxt_object(mock_order_usdt_2(), 'ETC/USDT', 'buy')
o = Order.parse_from_ccxt_object(mock_order_usdt_2(is_short), 'ETC/USDT', entry_side(is_short))
trade.orders.append(o)
o = Order.parse_from_ccxt_object(mock_order_usdt_2_sell(), 'ETC/USDT', 'sell')
o = Order.parse_from_ccxt_object(
mock_order_usdt_2_exit(is_short), 'ETC/USDT', exit_side(is_short))
trade.orders.append(o)
return trade
def mock_order_usdt_3():
def mock_order_usdt_3(is_short: bool):
return {
'id': '41231a12a',
'id': f'41231a12a_{direc(is_short)}',
'symbol': 'XRP/USDT',
'status': 'closed',
'side': 'buy',
'side': entry_side(is_short),
'type': 'limit',
'price': 1.0,
'amount': 30.0,
@@ -114,12 +154,12 @@ def mock_order_usdt_3():
}
def mock_order_usdt_3_sell():
def mock_order_usdt_3_exit(is_short: bool):
return {
'id': '41231a666a',
'id': f'41231a666a_{direc(is_short)}',
'symbol': 'XRP/USDT',
'status': 'closed',
'side': 'sell',
'side': exit_side(is_short),
'type': 'stop_loss_limit',
'price': 1.1,
'average': 1.1,
@@ -129,7 +169,7 @@ def mock_order_usdt_3_sell():
}
def mock_trade_usdt_3(fee):
def mock_trade_usdt_3(fee, is_short: bool):
"""
Closed trade
"""
@@ -142,29 +182,32 @@ def mock_trade_usdt_3(fee):
fee_close=fee.return_value,
open_rate=1.0,
close_rate=1.1,
close_profit=10.0,
close_profit=0.1,
close_profit_abs=9.8425,
exchange='binance',
is_open=False,
strategy='StrategyTestV2',
timeframe=5,
enter_tag='TEST3',
exit_reason='roi',
open_date=datetime.now(tz=timezone.utc) - timedelta(minutes=20),
close_date=datetime.now(tz=timezone.utc),
is_short=is_short,
)
o = Order.parse_from_ccxt_object(mock_order_usdt_3(), 'XRP/USDT', 'buy')
o = Order.parse_from_ccxt_object(mock_order_usdt_3(is_short), 'XRP/USDT', entry_side(is_short))
trade.orders.append(o)
o = Order.parse_from_ccxt_object(mock_order_usdt_3_sell(), 'XRP/USDT', 'sell')
o = Order.parse_from_ccxt_object(mock_order_usdt_3_exit(is_short),
'XRP/USDT', exit_side(is_short))
trade.orders.append(o)
return trade
def mock_order_usdt_4():
def mock_order_usdt_4(is_short: bool):
return {
'id': 'prod_buy_12345',
'id': f'prod_buy_12345_{direc(is_short)}',
'symbol': 'ETC/USDT',
'status': 'open',
'side': 'buy',
'side': entry_side(is_short),
'type': 'limit',
'price': 2.0,
'amount': 10.0,
@@ -173,7 +216,7 @@ def mock_order_usdt_4():
}
def mock_trade_usdt_4(fee):
def mock_trade_usdt_4(fee, is_short: bool):
"""
Simulate prod entry
"""
@@ -188,21 +231,22 @@ def mock_trade_usdt_4(fee):
is_open=True,
open_rate=2.0,
exchange='binance',
open_order_id='prod_buy_12345',
open_order_id=f'prod_buy_12345_{direc(is_short)}',
strategy='StrategyTestV2',
timeframe=5,
is_short=is_short,
)
o = Order.parse_from_ccxt_object(mock_order_usdt_4(), 'ETC/USDT', 'buy')
o = Order.parse_from_ccxt_object(mock_order_usdt_4(is_short), 'ETC/USDT', entry_side(is_short))
trade.orders.append(o)
return trade
def mock_order_usdt_5():
def mock_order_usdt_5(is_short: bool):
return {
'id': 'prod_buy_3455',
'id': f'prod_buy_3455_{direc(is_short)}',
'symbol': 'XRP/USDT',
'status': 'closed',
'side': 'buy',
'side': entry_side(is_short),
'type': 'limit',
'price': 2.0,
'amount': 10.0,
@@ -211,12 +255,12 @@ def mock_order_usdt_5():
}
def mock_order_usdt_5_stoploss():
def mock_order_usdt_5_stoploss(is_short: bool):
return {
'id': 'prod_stoploss_3455',
'id': f'prod_stoploss_3455_{direc(is_short)}',
'symbol': 'XRP/USDT',
'status': 'open',
'side': 'sell',
'side': exit_side(is_short),
'type': 'stop_loss_limit',
'price': 2.0,
'amount': 10.0,
@@ -225,7 +269,7 @@ def mock_order_usdt_5_stoploss():
}
def mock_trade_usdt_5(fee):
def mock_trade_usdt_5(fee, is_short: bool):
"""
Simulate prod entry with stoploss
"""
@@ -241,22 +285,23 @@ def mock_trade_usdt_5(fee):
open_rate=2.0,
exchange='binance',
strategy='SampleStrategy',
stoploss_order_id='prod_stoploss_3455',
stoploss_order_id=f'prod_stoploss_3455_{direc(is_short)}',
timeframe=5,
is_short=is_short,
)
o = Order.parse_from_ccxt_object(mock_order_usdt_5(), 'XRP/USDT', 'buy')
o = Order.parse_from_ccxt_object(mock_order_usdt_5(is_short), 'XRP/USDT', entry_side(is_short))
trade.orders.append(o)
o = Order.parse_from_ccxt_object(mock_order_usdt_5_stoploss(), 'XRP/USDT', 'stoploss')
o = Order.parse_from_ccxt_object(mock_order_usdt_5_stoploss(is_short), 'XRP/USDT', 'stoploss')
trade.orders.append(o)
return trade
def mock_order_usdt_6():
def mock_order_usdt_6(is_short: bool):
return {
'id': 'prod_buy_6',
'id': f'prod_entry_6_{direc(is_short)}',
'symbol': 'LTC/USDT',
'status': 'closed',
'side': 'buy',
'side': entry_side(is_short),
'type': 'limit',
'price': 10.0,
'amount': 2.0,
@@ -265,12 +310,12 @@ def mock_order_usdt_6():
}
def mock_order_usdt_6_sell():
def mock_order_usdt_6_exit(is_short: bool):
return {
'id': 'prod_sell_6',
'id': f'prod_exit_6_{direc(is_short)}',
'symbol': 'LTC/USDT',
'status': 'open',
'side': 'sell',
'side': exit_side(is_short),
'type': 'limit',
'price': 12.0,
'amount': 2.0,
@@ -279,7 +324,7 @@ def mock_order_usdt_6_sell():
}
def mock_trade_usdt_6(fee):
def mock_trade_usdt_6(fee, is_short: bool):
"""
Simulate prod entry with open sell order
"""
@@ -295,69 +340,49 @@ def mock_trade_usdt_6(fee):
open_rate=10.0,
exchange='binance',
strategy='SampleStrategy',
open_order_id="prod_sell_6",
open_order_id=f'prod_exit_6_{direc(is_short)}',
timeframe=5,
is_short=is_short,
)
o = Order.parse_from_ccxt_object(mock_order_usdt_6(), 'LTC/USDT', 'buy')
o = Order.parse_from_ccxt_object(mock_order_usdt_6(is_short), 'LTC/USDT', entry_side(is_short))
trade.orders.append(o)
o = Order.parse_from_ccxt_object(mock_order_usdt_6_sell(), 'LTC/USDT', 'sell')
o = Order.parse_from_ccxt_object(mock_order_usdt_6_exit(is_short),
'LTC/USDT', exit_side(is_short))
trade.orders.append(o)
return trade
def mock_order_usdt_7():
def mock_order_usdt_7(is_short: bool):
return {
'id': 'prod_buy_7',
'symbol': 'LTC/USDT',
'id': f'1234_{direc(is_short)}',
'symbol': 'ADA/USDT',
'status': 'closed',
'side': 'buy',
'side': entry_side(is_short),
'type': 'limit',
'price': 10.0,
'amount': 2.0,
'filled': 2.0,
'price': 2.0,
'amount': 10.0,
'filled': 10.0,
'remaining': 0.0,
}
def mock_order_usdt_7_sell():
return {
'id': 'prod_sell_7',
'symbol': 'LTC/USDT',
'status': 'closed',
'side': 'sell',
'type': 'limit',
'price': 8.0,
'amount': 2.0,
'filled': 2.0,
'remaining': 0.0,
}
def mock_trade_usdt_7(fee):
"""
Simulate prod entry with open sell order
"""
def mock_trade_usdt_7(fee, is_short: bool):
trade = Trade(
pair='LTC/USDT',
pair='ADA/USDT',
stake_amount=20.0,
amount=2.0,
amount_requested=2.0,
open_date=datetime.now(tz=timezone.utc) - timedelta(minutes=20),
close_date=datetime.now(tz=timezone.utc) - timedelta(minutes=5),
amount=10.0,
amount_requested=10.0,
fee_open=fee.return_value,
fee_close=fee.return_value,
is_open=False,
open_rate=10.0,
close_rate=8.0,
close_profit=-0.2,
close_profit_abs=-4.0,
is_open=True,
open_date=datetime.now(tz=timezone.utc) - timedelta(minutes=17),
open_rate=2.0,
exchange='binance',
strategy='SampleStrategy',
open_order_id="prod_sell_6",
open_order_id=f'1234_{direc(is_short)}',
strategy='StrategyTestV2',
timeframe=5,
is_short=is_short,
)
o = Order.parse_from_ccxt_object(mock_order_usdt_7(), 'LTC/USDT', 'buy')
trade.orders.append(o)
o = Order.parse_from_ccxt_object(mock_order_usdt_7_sell(), 'LTC/USDT', 'sell')
o = Order.parse_from_ccxt_object(mock_order_usdt_7(is_short), 'ADA/USDT', entry_side(is_short))
trade.orders.append(o)
return trade

View File

@@ -85,7 +85,7 @@ def test_load_backtest_data_new_format(testdatadir):
filename = testdatadir / "backtest_results/backtest-result_new.json"
bt_data = load_backtest_data(filename)
assert isinstance(bt_data, DataFrame)
assert set(bt_data.columns) == set(BT_DATA_COLUMNS + ['close_timestamp', 'open_timestamp'])
assert set(bt_data.columns) == set(BT_DATA_COLUMNS)
assert len(bt_data) == 179
# Test loading from string (must yield same result)
@@ -110,7 +110,7 @@ def test_load_backtest_data_multi(testdatadir):
bt_data = load_backtest_data(filename, strategy=strategy)
assert isinstance(bt_data, DataFrame)
assert set(bt_data.columns) == set(
BT_DATA_COLUMNS + ['close_timestamp', 'open_timestamp'])
BT_DATA_COLUMNS)
assert len(bt_data) == 179
# Test loading from string (must yield same result)

View File

@@ -154,6 +154,7 @@ def test_stoploss_adjust_binance(mocker, default_conf, sl1, sl2, sl3, side):
order = {
'type': 'stop_loss_limit',
'price': 1500,
'stopPrice': 1500,
'info': {'stopPrice': 1500},
}
assert exchange.stoploss_adjust(sl1, order, side=side)

View File

@@ -795,10 +795,27 @@ def test_backtest_one(default_conf, fee, mocker, testdatadir) -> None:
'is_open': [False, False],
'enter_tag': [None, None],
"is_short": [False, False],
'open_timestamp': [1517251200000, 1517283000000],
'close_timestamp': [1517265300000, 1517285400000],
'orders': [
[
{'amount': 0.00957442, 'safe_price': 0.104445, 'ft_order_side': 'buy',
'order_filled_timestamp': 1517251200000, 'ft_is_entry': True},
{'amount': 0.00957442, 'safe_price': 0.10496853383458644, 'ft_order_side': 'sell',
'order_filled_timestamp': 1517265300000, 'ft_is_entry': False}
], [
{'amount': 0.0097064, 'safe_price': 0.10302485, 'ft_order_side': 'buy',
'order_filled_timestamp': 1517283000000, 'ft_is_entry': True},
{'amount': 0.0097064, 'safe_price': 0.10354126528822055, 'ft_order_side': 'sell',
'order_filled_timestamp': 1517285400000, 'ft_is_entry': False}
]
]
})
pd.testing.assert_frame_equal(results, expected)
assert 'orders' in results.columns
data_pair = processed[pair]
for _, t in results.iterrows():
assert len(t['orders']) == 2
ln = data_pair.loc[data_pair["date"] == t["open_date"]]
# Check open trade rate alignes to open rate
assert ln is not None

View File

@@ -72,9 +72,14 @@ def test_backtest_position_adjustment(default_conf, fee, mocker, testdatadir) ->
'is_open': [False, False],
'enter_tag': [None, None],
'is_short': [False, False],
'open_timestamp': [1517251200000, 1517283000000],
'close_timestamp': [1517265300000, 1517285400000],
})
pd.testing.assert_frame_equal(results, expected)
pd.testing.assert_frame_equal(results.drop(columns=['orders']), expected)
data_pair = processed[pair]
assert len(results.iloc[0]['orders']) == 6
assert len(results.iloc[1]['orders']) == 2
for _, t in results.iterrows():
ln = data_pair.loc[data_pair["date"] == t["open_date"]]
# Check open trade rate alignes to open rate

View File

@@ -509,7 +509,6 @@ def test_generate_optimizer(mocker, hyperopt_conf) -> None:
hyperopt.min_date = Arrow(2017, 12, 10)
hyperopt.max_date = Arrow(2017, 12, 13)
hyperopt.init_spaces()
hyperopt.dimensions = hyperopt.dimensions
generate_optimizer_value = hyperopt.generate_optimizer(list(optimizer_param.values()))
assert generate_optimizer_value == response_expected

View File

@@ -762,8 +762,8 @@ def test_PerformanceFilter_keep_mid_order(mocker, default_conf_usdt, fee, caplog
with time_machine.travel("2021-09-01 05:00:00 +00:00") as t:
create_mock_trades_usdt(fee)
pm.refresh_pairlist()
assert pm.whitelist == ['XRP/USDT', 'ETC/USDT', 'ETH/USDT',
'NEO/USDT', 'TKN/USDT', 'ADA/USDT', 'LTC/USDT']
assert pm.whitelist == ['XRP/USDT', 'ETC/USDT', 'ETH/USDT', 'LTC/USDT',
'NEO/USDT', 'TKN/USDT', 'ADA/USDT', ]
# assert log_has_re(r'Removing pair .* since .* is below .*', caplog)
# Move to "outside" of lookback window, so original sorting is restored.

View File

@@ -11,11 +11,11 @@ from freqtrade.edge import PairInfo
from freqtrade.enums import SignalDirection, State, TradingMode
from freqtrade.exceptions import ExchangeError, InvalidOrderException, TemporaryError
from freqtrade.persistence import Trade
from freqtrade.persistence.models import Order
from freqtrade.persistence.pairlock_middleware import PairLocks
from freqtrade.rpc import RPC, RPCException
from freqtrade.rpc.fiat_convert import CryptoToFiatConverter
from tests.conftest import create_mock_trades, get_patched_freqtradebot, patch_get_signal
from tests.conftest import (create_mock_trades, create_mock_trades_usdt, get_patched_freqtradebot,
patch_get_signal)
# Functions for recurrent object patching
@@ -286,8 +286,8 @@ def test_rpc_status_table(default_conf, ticker, fee, mocker) -> None:
assert isnan(fiat_profit_sum)
def test_rpc_daily_profit(default_conf, update, ticker, fee,
limit_buy_order, limit_sell_order, markets, mocker) -> None:
def test__rpc_timeunit_profit(default_conf_usdt, ticker, fee,
limit_buy_order, limit_sell_order, markets, mocker) -> None:
mocker.patch('freqtrade.rpc.telegram.Telegram', MagicMock())
mocker.patch.multiple(
'freqtrade.exchange.Exchange',
@@ -296,45 +296,35 @@ def test_rpc_daily_profit(default_conf, update, ticker, fee,
markets=PropertyMock(return_value=markets)
)
freqtradebot = get_patched_freqtradebot(mocker, default_conf)
patch_get_signal(freqtradebot)
stake_currency = default_conf['stake_currency']
fiat_display_currency = default_conf['fiat_display_currency']
freqtradebot = get_patched_freqtradebot(mocker, default_conf_usdt)
create_mock_trades_usdt(fee)
stake_currency = default_conf_usdt['stake_currency']
fiat_display_currency = default_conf_usdt['fiat_display_currency']
rpc = RPC(freqtradebot)
rpc._fiat_converter = CryptoToFiatConverter()
# Create some test data
freqtradebot.enter_positions()
trade = Trade.query.first()
assert trade
# Simulate buy & sell
oobj = Order.parse_from_ccxt_object(limit_buy_order, limit_buy_order['symbol'], 'buy')
trade.update_trade(oobj)
oobj = Order.parse_from_ccxt_object(limit_sell_order, limit_sell_order['symbol'], 'sell')
trade.update_trade(oobj)
trade.close_date = datetime.utcnow()
trade.is_open = False
# Try valid data
update.message.text = '/daily 2'
days = rpc._rpc_daily_profit(7, stake_currency, fiat_display_currency)
days = rpc._rpc_timeunit_profit(7, stake_currency, fiat_display_currency)
assert len(days['data']) == 7
assert days['stake_currency'] == default_conf['stake_currency']
assert days['fiat_display_currency'] == default_conf['fiat_display_currency']
assert days['stake_currency'] == default_conf_usdt['stake_currency']
assert days['fiat_display_currency'] == default_conf_usdt['fiat_display_currency']
for day in days['data']:
# [datetime.date(2018, 1, 11), '0.00000000 BTC', '0.000 USD']
assert (day['abs_profit'] == 0.0 or
day['abs_profit'] == 0.00006217)
assert (day['fiat_value'] == 0.0 or
day['fiat_value'] == 0.76748865)
# {'date': datetime.date(2022, 6, 11), 'abs_profit': 13.8299999,
# 'starting_balance': 1055.37, 'rel_profit': 0.0131044,
# 'fiat_value': 0.0, 'trade_count': 2}
assert day['abs_profit'] in (0.0, pytest.approx(13.8299999), pytest.approx(-4.0))
assert day['rel_profit'] in (0.0, pytest.approx(0.01310441), pytest.approx(-0.00377583))
assert day['trade_count'] in (0, 1, 2)
assert day['starting_balance'] in (pytest.approx(1059.37), pytest.approx(1055.37))
assert day['fiat_value'] in (0.0, )
# ensure first day is current date
assert str(days['data'][0]['date']) == str(datetime.utcnow().date())
# Try invalid data
with pytest.raises(RPCException, match=r'.*must be an integer greater than 0*'):
rpc._rpc_daily_profit(0, stake_currency, fiat_display_currency)
rpc._rpc_timeunit_profit(0, stake_currency, fiat_display_currency)
@pytest.mark.parametrize('is_short', [True, False])
@@ -418,13 +408,8 @@ def test_rpc_delete_trade(mocker, default_conf, fee, markets, caplog, is_short):
assert stoploss_mock.call_count == 0
def test_rpc_trade_statistics(default_conf, ticker, ticker_sell_up, fee,
limit_buy_order, limit_sell_order, mocker) -> None:
mocker.patch.multiple(
'freqtrade.rpc.fiat_convert.CoinGeckoAPI',
get_price=MagicMock(return_value={'bitcoin': {'usd': 15000.0}}),
)
mocker.patch('freqtrade.rpc.rpc.CryptoToFiatConverter._find_price', return_value=15000.0)
def test_rpc_trade_statistics(default_conf_usdt, ticker, fee, mocker) -> None:
mocker.patch('freqtrade.rpc.rpc.CryptoToFiatConverter._find_price', return_value=1.1)
mocker.patch('freqtrade.rpc.telegram.Telegram', MagicMock())
mocker.patch.multiple(
'freqtrade.exchange.Exchange',
@@ -432,10 +417,9 @@ def test_rpc_trade_statistics(default_conf, ticker, ticker_sell_up, fee,
get_fee=fee,
)
freqtradebot = get_patched_freqtradebot(mocker, default_conf)
patch_get_signal(freqtradebot)
stake_currency = default_conf['stake_currency']
fiat_display_currency = default_conf['fiat_display_currency']
freqtradebot = get_patched_freqtradebot(mocker, default_conf_usdt)
stake_currency = default_conf_usdt['stake_currency']
fiat_display_currency = default_conf_usdt['fiat_display_currency']
rpc = RPC(freqtradebot)
rpc._fiat_converter = CryptoToFiatConverter()
@@ -448,75 +432,40 @@ def test_rpc_trade_statistics(default_conf, ticker, ticker_sell_up, fee,
assert res['latest_trade_timestamp'] == 0
# Create some test data
freqtradebot.enter_positions()
trade = Trade.query.first()
# Simulate fulfilled LIMIT_BUY order for trade
oobj = Order.parse_from_ccxt_object(limit_buy_order, limit_buy_order['symbol'], 'buy')
trade.update_trade(oobj)
# Update the ticker with a market going up
mocker.patch.multiple(
'freqtrade.exchange.Exchange',
fetch_ticker=ticker_sell_up
)
oobj = Order.parse_from_ccxt_object(limit_sell_order, limit_sell_order['symbol'], 'sell')
trade.update_trade(oobj)
trade.close_date = datetime.utcnow()
trade.is_open = False
freqtradebot.enter_positions()
trade = Trade.query.first()
# Simulate fulfilled LIMIT_BUY order for trade
oobj = Order.parse_from_ccxt_object(limit_buy_order, limit_buy_order['symbol'], 'buy')
trade.update_trade(oobj)
# Update the ticker with a market going up
mocker.patch.multiple(
'freqtrade.exchange.Exchange',
fetch_ticker=ticker_sell_up
)
oobj = Order.parse_from_ccxt_object(limit_sell_order, limit_sell_order['symbol'], 'sell')
trade.update_trade(oobj)
trade.close_date = datetime.utcnow()
trade.is_open = False
create_mock_trades_usdt(fee)
stats = rpc._rpc_trade_statistics(stake_currency, fiat_display_currency)
assert prec_satoshi(stats['profit_closed_coin'], 6.217e-05)
assert prec_satoshi(stats['profit_closed_percent_mean'], 6.2)
assert prec_satoshi(stats['profit_closed_fiat'], 0.93255)
assert prec_satoshi(stats['profit_all_coin'], 5.802e-05)
assert prec_satoshi(stats['profit_all_percent_mean'], 2.89)
assert prec_satoshi(stats['profit_all_fiat'], 0.8703)
assert stats['trade_count'] == 2
assert stats['first_trade_date'] == 'just now'
assert stats['latest_trade_date'] == 'just now'
assert stats['avg_duration'] in ('0:00:00', '0:00:01', '0:00:02')
assert stats['best_pair'] == 'ETH/BTC'
assert prec_satoshi(stats['best_rate'], 6.2)
assert pytest.approx(stats['profit_closed_coin']) == 9.83
assert pytest.approx(stats['profit_closed_percent_mean']) == -1.67
assert pytest.approx(stats['profit_closed_fiat']) == 10.813
assert pytest.approx(stats['profit_all_coin']) == -77.45964918
assert pytest.approx(stats['profit_all_percent_mean']) == -57.86
assert pytest.approx(stats['profit_all_fiat']) == -85.205614098
assert stats['trade_count'] == 7
assert stats['first_trade_date'] == '2 days ago'
assert stats['latest_trade_date'] == '17 minutes ago'
assert stats['avg_duration'] in ('0:17:40')
assert stats['best_pair'] == 'XRP/USDT'
assert stats['best_rate'] == 10.0
# Test non-available pair
mocker.patch('freqtrade.exchange.Exchange.get_rate',
MagicMock(side_effect=ExchangeError("Pair 'ETH/BTC' not available")))
MagicMock(side_effect=ExchangeError("Pair 'XRP/USDT' not available")))
stats = rpc._rpc_trade_statistics(stake_currency, fiat_display_currency)
assert stats['trade_count'] == 2
assert stats['first_trade_date'] == 'just now'
assert stats['latest_trade_date'] == 'just now'
assert stats['avg_duration'] in ('0:00:00', '0:00:01', '0:00:02')
assert stats['best_pair'] == 'ETH/BTC'
assert prec_satoshi(stats['best_rate'], 6.2)
assert stats['trade_count'] == 7
assert stats['first_trade_date'] == '2 days ago'
assert stats['latest_trade_date'] == '17 minutes ago'
assert stats['avg_duration'] in ('0:17:40')
assert stats['best_pair'] == 'XRP/USDT'
assert stats['best_rate'] == 10.0
assert isnan(stats['profit_all_coin'])
# Test that rpc_trade_statistics can handle trades that lacks
# trade.open_rate (it is set to None)
def test_rpc_trade_statistics_closed(mocker, default_conf, ticker, fee,
ticker_sell_up, limit_buy_order, limit_sell_order):
mocker.patch.multiple(
'freqtrade.rpc.fiat_convert.CoinGeckoAPI',
get_price=MagicMock(return_value={'bitcoin': {'usd': 15000.0}}),
)
def test_rpc_trade_statistics_closed(mocker, default_conf_usdt, ticker, fee):
mocker.patch('freqtrade.rpc.fiat_convert.CryptoToFiatConverter._find_price',
return_value=15000.0)
return_value=1.1)
mocker.patch('freqtrade.rpc.telegram.Telegram', MagicMock())
mocker.patch.multiple(
'freqtrade.exchange.Exchange',
@@ -524,46 +473,32 @@ def test_rpc_trade_statistics_closed(mocker, default_conf, ticker, fee,
get_fee=fee,
)
freqtradebot = get_patched_freqtradebot(mocker, default_conf)
freqtradebot = get_patched_freqtradebot(mocker, default_conf_usdt)
patch_get_signal(freqtradebot)
stake_currency = default_conf['stake_currency']
fiat_display_currency = default_conf['fiat_display_currency']
stake_currency = default_conf_usdt['stake_currency']
fiat_display_currency = default_conf_usdt['fiat_display_currency']
rpc = RPC(freqtradebot)
# Create some test data
freqtradebot.enter_positions()
trade = Trade.query.first()
# Simulate fulfilled LIMIT_BUY order for trade
oobj = Order.parse_from_ccxt_object(limit_buy_order, limit_buy_order['symbol'], 'buy')
trade.update_trade(oobj)
# Update the ticker with a market going up
mocker.patch.multiple(
'freqtrade.exchange.Exchange',
fetch_ticker=ticker_sell_up,
get_fee=fee
)
oobj = Order.parse_from_ccxt_object(limit_sell_order, limit_sell_order['symbol'], 'sell')
trade.update_trade(oobj)
trade.close_date = datetime.utcnow()
trade.is_open = False
create_mock_trades_usdt(fee)
for trade in Trade.query.order_by(Trade.id).all():
trade.open_rate = None
stats = rpc._rpc_trade_statistics(stake_currency, fiat_display_currency)
assert prec_satoshi(stats['profit_closed_coin'], 0)
assert prec_satoshi(stats['profit_closed_percent_mean'], 0)
assert prec_satoshi(stats['profit_closed_fiat'], 0)
assert prec_satoshi(stats['profit_all_coin'], 0)
assert prec_satoshi(stats['profit_all_percent_mean'], 0)
assert prec_satoshi(stats['profit_all_fiat'], 0)
assert stats['trade_count'] == 1
assert stats['first_trade_date'] == 'just now'
assert stats['latest_trade_date'] == 'just now'
assert stats['profit_closed_coin'] == 0
assert stats['profit_closed_percent_mean'] == 0
assert stats['profit_closed_fiat'] == 0
assert stats['profit_all_coin'] == 0
assert stats['profit_all_percent_mean'] == 0
assert stats['profit_all_fiat'] == 0
assert stats['trade_count'] == 7
assert stats['first_trade_date'] == '2 days ago'
assert stats['latest_trade_date'] == '17 minutes ago'
assert stats['avg_duration'] == '0:00:00'
assert stats['best_pair'] == 'ETH/BTC'
assert prec_satoshi(stats['best_rate'], 6.2)
assert stats['best_pair'] == 'XRP/USDT'
assert stats['best_rate'] == 10.0
def test_rpc_balance_handle_error(default_conf, mocker):
@@ -916,8 +851,7 @@ def test_rpc_force_exit(default_conf, ticker, fee, mocker) -> None:
assert cancel_order_mock.call_count == 3
def test_performance_handle(default_conf, ticker, limit_buy_order, fee,
limit_sell_order, mocker) -> None:
def test_performance_handle(default_conf_usdt, ticker, fee, mocker) -> None:
mocker.patch('freqtrade.rpc.telegram.Telegram', MagicMock())
mocker.patch.multiple(
'freqtrade.exchange.Exchange',
@@ -926,34 +860,21 @@ def test_performance_handle(default_conf, ticker, limit_buy_order, fee,
get_fee=fee,
)
freqtradebot = get_patched_freqtradebot(mocker, default_conf)
freqtradebot = get_patched_freqtradebot(mocker, default_conf_usdt)
patch_get_signal(freqtradebot)
rpc = RPC(freqtradebot)
# Create some test data
freqtradebot.enter_positions()
trade = Trade.query.first()
assert trade
create_mock_trades_usdt(fee)
# Simulate fulfilled LIMIT_BUY order for trade
oobj = Order.parse_from_ccxt_object(limit_buy_order, limit_buy_order['symbol'], 'buy')
trade.update_trade(oobj)
# Simulate fulfilled LIMIT_SELL order for trade
oobj = Order.parse_from_ccxt_object(limit_sell_order, limit_sell_order['symbol'], 'sell')
trade.update_trade(oobj)
trade.close_date = datetime.utcnow()
trade.is_open = False
res = rpc._rpc_performance()
assert len(res) == 1
assert res[0]['pair'] == 'ETH/BTC'
assert len(res) == 3
assert res[0]['pair'] == 'XRP/USDT'
assert res[0]['count'] == 1
assert prec_satoshi(res[0]['profit_pct'], 6.2)
assert res[0]['profit_pct'] == 10.0
def test_enter_tag_performance_handle(default_conf, ticker, limit_buy_order, fee,
limit_sell_order, mocker) -> None:
def test_enter_tag_performance_handle(default_conf, ticker, fee, mocker) -> None:
mocker.patch('freqtrade.rpc.telegram.Telegram', MagicMock())
mocker.patch.multiple(
'freqtrade.exchange.Exchange',
@@ -967,34 +888,22 @@ def test_enter_tag_performance_handle(default_conf, ticker, limit_buy_order, fee
rpc = RPC(freqtradebot)
# Create some test data
create_mock_trades_usdt(fee)
freqtradebot.enter_positions()
trade = Trade.query.first()
assert trade
# Simulate fulfilled LIMIT_BUY order for trade
oobj = Order.parse_from_ccxt_object(limit_buy_order, limit_buy_order['symbol'], 'buy')
trade.update_trade(oobj)
# Simulate fulfilled LIMIT_SELL order for trade
oobj = Order.parse_from_ccxt_object(limit_sell_order, limit_sell_order['symbol'], 'sell')
trade.update_trade(oobj)
trade.close_date = datetime.utcnow()
trade.is_open = False
res = rpc._rpc_enter_tag_performance(None)
assert len(res) == 1
assert res[0]['enter_tag'] == 'Other'
assert len(res) == 3
assert res[0]['enter_tag'] == 'TEST3'
assert res[0]['count'] == 1
assert prec_satoshi(res[0]['profit_pct'], 6.2)
assert res[0]['profit_pct'] == 10.0
trade.enter_tag = "TEST_TAG"
res = rpc._rpc_enter_tag_performance(None)
assert len(res) == 1
assert res[0]['enter_tag'] == 'TEST_TAG'
assert len(res) == 3
assert res[0]['enter_tag'] == 'TEST3'
assert res[0]['count'] == 1
assert prec_satoshi(res[0]['profit_pct'], 6.2)
assert res[0]['profit_pct'] == 10.0
def test_enter_tag_performance_handle_2(mocker, default_conf, markets, fee):
@@ -1026,8 +935,7 @@ def test_enter_tag_performance_handle_2(mocker, default_conf, markets, fee):
assert prec_satoshi(res[0]['profit_pct'], 0.5)
def test_exit_reason_performance_handle(default_conf, ticker, limit_buy_order, fee,
limit_sell_order, mocker) -> None:
def test_exit_reason_performance_handle(default_conf_usdt, ticker, fee, mocker) -> None:
mocker.patch('freqtrade.rpc.telegram.Telegram', MagicMock())
mocker.patch.multiple(
'freqtrade.exchange.Exchange',
@@ -1036,39 +944,22 @@ def test_exit_reason_performance_handle(default_conf, ticker, limit_buy_order, f
get_fee=fee,
)
freqtradebot = get_patched_freqtradebot(mocker, default_conf)
freqtradebot = get_patched_freqtradebot(mocker, default_conf_usdt)
patch_get_signal(freqtradebot)
rpc = RPC(freqtradebot)
# Create some test data
freqtradebot.enter_positions()
trade = Trade.query.first()
assert trade
create_mock_trades_usdt(fee)
# Simulate fulfilled LIMIT_BUY order for trade
oobj = Order.parse_from_ccxt_object(limit_buy_order, limit_buy_order['symbol'], 'buy')
trade.update_trade(oobj)
# Simulate fulfilled LIMIT_SELL order for trade
oobj = Order.parse_from_ccxt_object(limit_sell_order, limit_sell_order['symbol'], 'sell')
trade.update_trade(oobj)
trade.close_date = datetime.utcnow()
trade.is_open = False
res = rpc._rpc_exit_reason_performance(None)
assert len(res) == 1
assert res[0]['exit_reason'] == 'Other'
assert len(res) == 3
assert res[0]['exit_reason'] == 'roi'
assert res[0]['count'] == 1
assert prec_satoshi(res[0]['profit_pct'], 6.2)
assert res[0]['profit_pct'] == 10.0
trade.exit_reason = "TEST1"
res = rpc._rpc_exit_reason_performance(None)
assert len(res) == 1
assert res[0]['exit_reason'] == 'TEST1'
assert res[0]['count'] == 1
assert prec_satoshi(res[0]['profit_pct'], 6.2)
assert res[1]['exit_reason'] == 'exit_signal'
assert res[2]['exit_reason'] == 'Other'
def test_exit_reason_performance_handle_2(mocker, default_conf, markets, fee):
@@ -1100,8 +991,7 @@ def test_exit_reason_performance_handle_2(mocker, default_conf, markets, fee):
assert prec_satoshi(res[0]['profit_pct'], 0.5)
def test_mix_tag_performance_handle(default_conf, ticker, limit_buy_order, fee,
limit_sell_order, mocker) -> None:
def test_mix_tag_performance_handle(default_conf, ticker, fee, mocker) -> None:
mocker.patch('freqtrade.rpc.telegram.Telegram', MagicMock())
mocker.patch.multiple(
'freqtrade.exchange.Exchange',
@@ -1115,35 +1005,14 @@ def test_mix_tag_performance_handle(default_conf, ticker, limit_buy_order, fee,
rpc = RPC(freqtradebot)
# Create some test data
freqtradebot.enter_positions()
trade = Trade.query.first()
assert trade
create_mock_trades_usdt(fee)
# Simulate fulfilled LIMIT_BUY order for trade
oobj = Order.parse_from_ccxt_object(limit_buy_order, limit_buy_order['symbol'], 'buy')
trade.update_trade(oobj)
# Simulate fulfilled LIMIT_SELL order for trade
oobj = Order.parse_from_ccxt_object(limit_sell_order, limit_sell_order['symbol'], 'sell')
trade.update_trade(oobj)
trade.close_date = datetime.utcnow()
trade.is_open = False
res = rpc._rpc_mix_tag_performance(None)
assert len(res) == 1
assert res[0]['mix_tag'] == 'Other Other'
assert len(res) == 3
assert res[0]['mix_tag'] == 'TEST3 roi'
assert res[0]['count'] == 1
assert prec_satoshi(res[0]['profit_pct'], 6.2)
trade.enter_tag = "TESTBUY"
trade.exit_reason = "TESTSELL"
res = rpc._rpc_mix_tag_performance(None)
assert len(res) == 1
assert res[0]['mix_tag'] == 'TESTBUY TESTSELL'
assert res[0]['count'] == 1
assert prec_satoshi(res[0]['profit_pct'], 6.2)
assert res[0]['profit_pct'] == 10.0
def test_mix_tag_performance_handle_2(mocker, default_conf, markets, fee):

View File

@@ -27,8 +27,9 @@ from freqtrade.persistence.models import Order
from freqtrade.rpc import RPC
from freqtrade.rpc.rpc import RPCException
from freqtrade.rpc.telegram import Telegram, authorized_only
from tests.conftest import (CURRENT_TEST_STRATEGY, create_mock_trades, get_patched_freqtradebot,
log_has, log_has_re, patch_exchange, patch_get_signal, patch_whitelist)
from tests.conftest import (CURRENT_TEST_STRATEGY, create_mock_trades, create_mock_trades_usdt,
get_patched_freqtradebot, log_has, log_has_re, patch_exchange,
patch_get_signal, patch_whitelist)
class DummyCls(Telegram):
@@ -404,12 +405,10 @@ def test_status_table_handle(default_conf, update, ticker, fee, mocker) -> None:
assert msg_mock.call_count == 1
def test_daily_handle(default_conf, update, ticker, limit_buy_order, fee,
limit_sell_order, mocker) -> None:
default_conf['max_open_trades'] = 1
def test_daily_handle(default_conf_usdt, update, ticker, fee, mocker, time_machine) -> None:
mocker.patch(
'freqtrade.rpc.rpc.CryptoToFiatConverter._find_price',
return_value=15000.0
return_value=1.1
)
mocker.patch.multiple(
'freqtrade.exchange.Exchange',
@@ -417,27 +416,12 @@ def test_daily_handle(default_conf, update, ticker, limit_buy_order, fee,
get_fee=fee,
)
telegram, freqtradebot, msg_mock = get_telegram_testobject(mocker, default_conf)
patch_get_signal(freqtradebot)
telegram, freqtradebot, msg_mock = get_telegram_testobject(mocker, default_conf_usdt)
# Move date to within day
time_machine.move_to('2022-06-11 08:00:00+00:00')
# Create some test data
freqtradebot.enter_positions()
trade = Trade.query.first()
assert trade
# Simulate fulfilled LIMIT_BUY order for trade
limit_buy_order['id'] = trade.orders[0].order_id
oobj = Order.parse_from_ccxt_object(limit_buy_order, limit_buy_order['symbol'], 'buy')
trade.update_order(limit_buy_order)
trade.update_trade(oobj)
# Simulate fulfilled LIMIT_SELL order for trade
oobjs = Order.parse_from_ccxt_object(limit_sell_order, limit_sell_order['symbol'], 'sell')
trade.update_trade(oobjs)
trade.close_date = datetime.utcnow()
trade.is_open = False
create_mock_trades_usdt(fee)
# Try valid data
# /daily 2
@@ -448,10 +432,11 @@ def test_daily_handle(default_conf, update, ticker, limit_buy_order, fee,
assert "Daily Profit over the last 2 days</b>:" in msg_mock.call_args_list[0][0][0]
assert 'Day ' in msg_mock.call_args_list[0][0][0]
assert str(datetime.utcnow().date()) in msg_mock.call_args_list[0][0][0]
assert str(' 0.00006217 BTC') in msg_mock.call_args_list[0][0][0]
assert str(' 0.933 USD') in msg_mock.call_args_list[0][0][0]
assert str(' 1 trade') in msg_mock.call_args_list[0][0][0]
assert str(' 0 trade') in msg_mock.call_args_list[0][0][0]
assert ' 13.83 USDT' in msg_mock.call_args_list[0][0][0]
assert ' 15.21 USD' in msg_mock.call_args_list[0][0][0]
assert '(2)' in msg_mock.call_args_list[0][0][0]
assert '(2) 13.83 USDT 15.21 USD 1.31%' in msg_mock.call_args_list[0][0][0]
assert '(0)' in msg_mock.call_args_list[0][0][0]
# Reset msg_mock
msg_mock.reset_mock()
@@ -460,32 +445,23 @@ def test_daily_handle(default_conf, update, ticker, limit_buy_order, fee,
assert msg_mock.call_count == 1
assert "Daily Profit over the last 7 days</b>:" in msg_mock.call_args_list[0][0][0]
assert str(datetime.utcnow().date()) in msg_mock.call_args_list[0][0][0]
assert str(' 0.00006217 BTC') in msg_mock.call_args_list[0][0][0]
assert str(' 0.933 USD') in msg_mock.call_args_list[0][0][0]
assert str(' 1 trade') in msg_mock.call_args_list[0][0][0]
assert str(' 0 trade') in msg_mock.call_args_list[0][0][0]
assert str((datetime.utcnow() - timedelta(days=5)).date()) in msg_mock.call_args_list[0][0][0]
assert ' 13.83 USDT' in msg_mock.call_args_list[0][0][0]
assert ' 15.21 USD' in msg_mock.call_args_list[0][0][0]
assert '(2)' in msg_mock.call_args_list[0][0][0]
assert '(1)' in msg_mock.call_args_list[0][0][0]
assert '(0)' in msg_mock.call_args_list[0][0][0]
# Reset msg_mock
msg_mock.reset_mock()
freqtradebot.config['max_open_trades'] = 2
# Add two other trades
n = freqtradebot.enter_positions()
assert n == 2
trades = Trade.query.all()
for trade in trades:
trade.update_trade(oobj)
trade.update_trade(oobjs)
trade.close_date = datetime.utcnow()
trade.is_open = False
# /daily 1
context = MagicMock()
context.args = ["1"]
telegram._daily(update=update, context=context)
assert str(' 0.00018651 BTC') in msg_mock.call_args_list[0][0][0]
assert str(' 2.798 USD') in msg_mock.call_args_list[0][0][0]
assert str(' 3 trades') in msg_mock.call_args_list[0][0][0]
assert ' 13.83 USDT' in msg_mock.call_args_list[0][0][0]
assert ' 15.21 USD' in msg_mock.call_args_list[0][0][0]
assert '(2)' in msg_mock.call_args_list[0][0][0]
def test_daily_wrong_input(default_conf, update, ticker, mocker) -> None:
@@ -514,15 +490,14 @@ def test_daily_wrong_input(default_conf, update, ticker, mocker) -> None:
context = MagicMock()
context.args = ["today"]
telegram._daily(update=update, context=context)
assert str('Daily Profit over the last 7 days</b>:') in msg_mock.call_args_list[0][0][0]
assert 'Daily Profit over the last 7 days</b>:' in msg_mock.call_args_list[0][0][0]
def test_weekly_handle(default_conf, update, ticker, limit_buy_order, fee,
limit_sell_order, mocker) -> None:
default_conf['max_open_trades'] = 1
def test_weekly_handle(default_conf_usdt, update, ticker, fee, mocker, time_machine) -> None:
default_conf_usdt['max_open_trades'] = 1
mocker.patch(
'freqtrade.rpc.rpc.CryptoToFiatConverter._find_price',
return_value=15000.0
return_value=1.1
)
mocker.patch.multiple(
'freqtrade.exchange.Exchange',
@@ -530,27 +505,10 @@ def test_weekly_handle(default_conf, update, ticker, limit_buy_order, fee,
get_fee=fee,
)
telegram, freqtradebot, msg_mock = get_telegram_testobject(mocker, default_conf)
patch_get_signal(freqtradebot)
# Create some test data
freqtradebot.enter_positions()
trade = Trade.query.first()
assert trade
# Simulate fulfilled LIMIT_BUY order for trade
limit_buy_order['id'] = trade.orders[0].order_id
oobj = Order.parse_from_ccxt_object(limit_buy_order, limit_buy_order['symbol'], 'buy')
trade.update_order(limit_buy_order)
trade.update_trade(oobj)
# Simulate fulfilled LIMIT_SELL order for trade
oobjs = Order.parse_from_ccxt_object(limit_sell_order, limit_sell_order['symbol'], 'sell')
trade.update_trade(oobjs)
trade.close_date = datetime.utcnow()
trade.is_open = False
telegram, freqtradebot, msg_mock = get_telegram_testobject(mocker, default_conf_usdt)
# Move to saturday - so all trades are within that week
time_machine.move_to('2022-06-11')
create_mock_trades_usdt(fee)
# Try valid data
# /weekly 2
@@ -564,10 +522,10 @@ def test_weekly_handle(default_conf, update, ticker, limit_buy_order, fee,
today = datetime.utcnow().date()
first_iso_day_of_current_week = today - timedelta(days=today.weekday())
assert str(first_iso_day_of_current_week) in msg_mock.call_args_list[0][0][0]
assert str(' 0.00006217 BTC') in msg_mock.call_args_list[0][0][0]
assert str(' 0.933 USD') in msg_mock.call_args_list[0][0][0]
assert str(' 1 trade') in msg_mock.call_args_list[0][0][0]
assert str(' 0 trade') in msg_mock.call_args_list[0][0][0]
assert ' 9.83 USDT' in msg_mock.call_args_list[0][0][0]
assert ' 10.81 USD' in msg_mock.call_args_list[0][0][0]
assert '(3)' in msg_mock.call_args_list[0][0][0]
assert '(0)' in msg_mock.call_args_list[0][0][0]
# Reset msg_mock
msg_mock.reset_mock()
@@ -577,44 +535,10 @@ def test_weekly_handle(default_conf, update, ticker, limit_buy_order, fee,
assert "Weekly Profit over the last 8 weeks (starting from Monday)</b>:" \
in msg_mock.call_args_list[0][0][0]
assert 'Weekly' in msg_mock.call_args_list[0][0][0]
assert str(' 0.00006217 BTC') in msg_mock.call_args_list[0][0][0]
assert str(' 0.933 USD') in msg_mock.call_args_list[0][0][0]
assert str(' 1 trade') in msg_mock.call_args_list[0][0][0]
assert str(' 0 trade') in msg_mock.call_args_list[0][0][0]
# Reset msg_mock
msg_mock.reset_mock()
freqtradebot.config['max_open_trades'] = 2
# Add two other trades
n = freqtradebot.enter_positions()
assert n == 2
trades = Trade.query.all()
for trade in trades:
trade.update_trade(oobj)
trade.update_trade(oobjs)
trade.close_date = datetime.utcnow()
trade.is_open = False
# /weekly 1
# By default, the 8 previous weeks are shown
# So the previous modified trade should be excluded from the stats
context = MagicMock()
context.args = ["1"]
telegram._weekly(update=update, context=context)
assert str(' 0.00018651 BTC') in msg_mock.call_args_list[0][0][0]
assert str(' 2.798 USD') in msg_mock.call_args_list[0][0][0]
assert str(' 3 trades') in msg_mock.call_args_list[0][0][0]
def test_weekly_wrong_input(default_conf, update, ticker, mocker) -> None:
mocker.patch.multiple(
'freqtrade.exchange.Exchange',
fetch_ticker=ticker
)
telegram, freqtradebot, msg_mock = get_telegram_testobject(mocker, default_conf)
patch_get_signal(freqtradebot)
assert ' 9.83 USDT' in msg_mock.call_args_list[0][0][0]
assert ' 10.81 USD' in msg_mock.call_args_list[0][0][0]
assert '(3)' in msg_mock.call_args_list[0][0][0]
assert '(0)' in msg_mock.call_args_list[0][0][0]
# Try invalid data
msg_mock.reset_mock()
@@ -633,16 +557,17 @@ def test_weekly_wrong_input(default_conf, update, ticker, mocker) -> None:
context = MagicMock()
context.args = ["this week"]
telegram._weekly(update=update, context=context)
assert str('Weekly Profit over the last 8 weeks (starting from Monday)</b>:') \
assert (
'Weekly Profit over the last 8 weeks (starting from Monday)</b>:'
in msg_mock.call_args_list[0][0][0]
)
def test_monthly_handle(default_conf, update, ticker, limit_buy_order, fee,
limit_sell_order, mocker) -> None:
default_conf['max_open_trades'] = 1
def test_monthly_handle(default_conf_usdt, update, ticker, fee, mocker, time_machine) -> None:
default_conf_usdt['max_open_trades'] = 1
mocker.patch(
'freqtrade.rpc.rpc.CryptoToFiatConverter._find_price',
return_value=15000.0
return_value=1.1
)
mocker.patch.multiple(
'freqtrade.exchange.Exchange',
@@ -650,27 +575,10 @@ def test_monthly_handle(default_conf, update, ticker, limit_buy_order, fee,
get_fee=fee,
)
telegram, freqtradebot, msg_mock = get_telegram_testobject(mocker, default_conf)
patch_get_signal(freqtradebot)
# Create some test data
freqtradebot.enter_positions()
trade = Trade.query.first()
assert trade
# Simulate fulfilled LIMIT_BUY order for trade
limit_buy_order['id'] = trade.orders[0].order_id
oobj = Order.parse_from_ccxt_object(limit_buy_order, limit_buy_order['symbol'], 'buy')
trade.update_order(limit_buy_order)
trade.update_trade(oobj)
# Simulate fulfilled LIMIT_SELL order for trade
oobjs = Order.parse_from_ccxt_object(limit_sell_order, limit_sell_order['symbol'], 'sell')
trade.update_trade(oobjs)
trade.close_date = datetime.utcnow()
trade.is_open = False
telegram, freqtradebot, msg_mock = get_telegram_testobject(mocker, default_conf_usdt)
# Move to day within the month so all mock trades fall into this week.
time_machine.move_to('2022-06-11')
create_mock_trades_usdt(fee)
# Try valid data
# /monthly 2
@@ -683,10 +591,10 @@ def test_monthly_handle(default_conf, update, ticker, limit_buy_order, fee,
today = datetime.utcnow().date()
current_month = f"{today.year}-{today.month:02} "
assert current_month in msg_mock.call_args_list[0][0][0]
assert str(' 0.00006217 BTC') in msg_mock.call_args_list[0][0][0]
assert str(' 0.933 USD') in msg_mock.call_args_list[0][0][0]
assert str(' 1 trade') in msg_mock.call_args_list[0][0][0]
assert str(' 0 trade') in msg_mock.call_args_list[0][0][0]
assert ' 9.83 USDT' in msg_mock.call_args_list[0][0][0]
assert ' 10.81 USD' in msg_mock.call_args_list[0][0][0]
assert '(3)' in msg_mock.call_args_list[0][0][0]
assert '(0)' in msg_mock.call_args_list[0][0][0]
# Reset msg_mock
msg_mock.reset_mock()
@@ -697,24 +605,13 @@ def test_monthly_handle(default_conf, update, ticker, limit_buy_order, fee,
assert 'Monthly Profit over the last 6 months</b>:' in msg_mock.call_args_list[0][0][0]
assert 'Month ' in msg_mock.call_args_list[0][0][0]
assert current_month in msg_mock.call_args_list[0][0][0]
assert str(' 0.00006217 BTC') in msg_mock.call_args_list[0][0][0]
assert str(' 0.933 USD') in msg_mock.call_args_list[0][0][0]
assert str(' 1 trade') in msg_mock.call_args_list[0][0][0]
assert str(' 0 trade') in msg_mock.call_args_list[0][0][0]
assert ' 9.83 USDT' in msg_mock.call_args_list[0][0][0]
assert ' 10.81 USD' in msg_mock.call_args_list[0][0][0]
assert '(3)' in msg_mock.call_args_list[0][0][0]
assert '(0)' in msg_mock.call_args_list[0][0][0]
# Reset msg_mock
msg_mock.reset_mock()
freqtradebot.config['max_open_trades'] = 2
# Add two other trades
n = freqtradebot.enter_positions()
assert n == 2
trades = Trade.query.all()
for trade in trades:
trade.update_trade(oobj)
trade.update_trade(oobjs)
trade.close_date = datetime.utcnow()
trade.is_open = False
# /monthly 12
context = MagicMock()
@@ -722,24 +619,14 @@ def test_monthly_handle(default_conf, update, ticker, limit_buy_order, fee,
telegram._monthly(update=update, context=context)
assert msg_mock.call_count == 1
assert 'Monthly Profit over the last 12 months</b>:' in msg_mock.call_args_list[0][0][0]
assert str(' 0.00018651 BTC') in msg_mock.call_args_list[0][0][0]
assert str(' 2.798 USD') in msg_mock.call_args_list[0][0][0]
assert str(' 3 trades') in msg_mock.call_args_list[0][0][0]
assert ' 9.83 USDT' in msg_mock.call_args_list[0][0][0]
assert ' 10.81 USD' in msg_mock.call_args_list[0][0][0]
assert '(3)' in msg_mock.call_args_list[0][0][0]
# The one-digit months should contain a zero, Eg: September 2021 = "2021-09"
# Since we loaded the last 12 months, any month should appear
assert str('-09') in msg_mock.call_args_list[0][0][0]
def test_monthly_wrong_input(default_conf, update, ticker, mocker) -> None:
mocker.patch.multiple(
'freqtrade.exchange.Exchange',
fetch_ticker=ticker
)
telegram, freqtradebot, msg_mock = get_telegram_testobject(mocker, default_conf)
patch_get_signal(freqtradebot)
# Try invalid data
msg_mock.reset_mock()
freqtradebot.state = State.RUNNING
@@ -760,16 +647,16 @@ def test_monthly_wrong_input(default_conf, update, ticker, mocker) -> None:
assert str('Monthly Profit over the last 6 months</b>:') in msg_mock.call_args_list[0][0][0]
def test_profit_handle(default_conf, update, ticker, ticker_sell_up, fee,
limit_buy_order, limit_sell_order, mocker) -> None:
mocker.patch('freqtrade.rpc.rpc.CryptoToFiatConverter._find_price', return_value=15000.0)
def test_profit_handle(default_conf_usdt, update, ticker_usdt, ticker_sell_up, fee,
limit_sell_order_usdt, mocker) -> None:
mocker.patch('freqtrade.rpc.rpc.CryptoToFiatConverter._find_price', return_value=1.1)
mocker.patch.multiple(
'freqtrade.exchange.Exchange',
fetch_ticker=ticker,
fetch_ticker=ticker_usdt,
get_fee=fee,
)
telegram, freqtradebot, msg_mock = get_telegram_testobject(mocker, default_conf)
telegram, freqtradebot, msg_mock = get_telegram_testobject(mocker, default_conf_usdt)
patch_get_signal(freqtradebot)
telegram._profit(update=update, context=MagicMock())
@@ -781,13 +668,6 @@ def test_profit_handle(default_conf, update, ticker, ticker_sell_up, fee,
freqtradebot.enter_positions()
trade = Trade.query.first()
# Simulate fulfilled LIMIT_BUY order for trade
limit_buy_order['id'] = trade.orders[0].order_id
oobj = Order.parse_from_ccxt_object(limit_buy_order, limit_buy_order['symbol'], 'buy')
trade.update_order(limit_buy_order)
trade.update_trade(oobj)
Trade.commit()
context = MagicMock()
# Test with invalid 2nd argument (should silently pass)
context.args = ["aaa"]
@@ -795,15 +675,16 @@ def test_profit_handle(default_conf, update, ticker, ticker_sell_up, fee,
assert msg_mock.call_count == 1
assert 'No closed trade' in msg_mock.call_args_list[-1][0][0]
assert '*ROI:* All trades' in msg_mock.call_args_list[-1][0][0]
mocker.patch('freqtrade.wallets.Wallets.get_starting_balance', return_value=0.01)
assert ('∙ `-0.000005 BTC (-0.50%) (-0.0 \N{GREEK CAPITAL LETTER SIGMA}%)`'
mocker.patch('freqtrade.wallets.Wallets.get_starting_balance', return_value=1000)
assert ('∙ `0.298 USDT (0.50%) (0.03 \N{GREEK CAPITAL LETTER SIGMA}%)`'
in msg_mock.call_args_list[-1][0][0])
msg_mock.reset_mock()
# Update the ticker with a market going up
mocker.patch('freqtrade.exchange.Exchange.fetch_ticker', ticker_sell_up)
# Simulate fulfilled LIMIT_SELL order for trade
oobj = Order.parse_from_ccxt_object(limit_sell_order, limit_sell_order['symbol'], 'sell')
oobj = Order.parse_from_ccxt_object(
limit_sell_order_usdt, limit_sell_order_usdt['symbol'], 'sell')
trade.update_trade(oobj)
trade.close_date = datetime.now(timezone.utc)
@@ -814,15 +695,15 @@ def test_profit_handle(default_conf, update, ticker, ticker_sell_up, fee,
telegram._profit(update=update, context=context)
assert msg_mock.call_count == 1
assert '*ROI:* Closed trades' in msg_mock.call_args_list[-1][0][0]
assert ('∙ `0.00006217 BTC (6.20%) (0.62 \N{GREEK CAPITAL LETTER SIGMA}%)`'
assert ('∙ `5.685 USDT (9.45%) (0.57 \N{GREEK CAPITAL LETTER SIGMA}%)`'
in msg_mock.call_args_list[-1][0][0])
assert '∙ `0.933 USD`' in msg_mock.call_args_list[-1][0][0]
assert '∙ `6.253 USD`' in msg_mock.call_args_list[-1][0][0]
assert '*ROI:* All trades' in msg_mock.call_args_list[-1][0][0]
assert ('∙ `0.00006217 BTC (6.20%) (0.62 \N{GREEK CAPITAL LETTER SIGMA}%)`'
assert ('∙ `5.685 USDT (9.45%) (0.57 \N{GREEK CAPITAL LETTER SIGMA}%)`'
in msg_mock.call_args_list[-1][0][0])
assert '∙ `0.933 USD`' in msg_mock.call_args_list[-1][0][0]
assert '∙ `6.253 USD`' in msg_mock.call_args_list[-1][0][0]
assert '*Best Performing:* `ETH/BTC: 6.20%`' in msg_mock.call_args_list[-1][0][0]
assert '*Best Performing:* `ETH/USDT: 9.45%`' in msg_mock.call_args_list[-1][0][0]
@pytest.mark.parametrize('is_short', [True, False])
@@ -1365,75 +1246,43 @@ def test_force_enter_no_pair(default_conf, update, mocker) -> None:
assert fbuy_mock.call_count == 1
def test_telegram_performance_handle(default_conf, update, ticker, fee,
limit_buy_order, limit_sell_order, mocker) -> None:
def test_telegram_performance_handle(default_conf_usdt, update, ticker, fee, mocker) -> None:
mocker.patch.multiple(
'freqtrade.exchange.Exchange',
fetch_ticker=ticker,
get_fee=fee,
)
telegram, freqtradebot, msg_mock = get_telegram_testobject(mocker, default_conf)
patch_get_signal(freqtradebot)
telegram, freqtradebot, msg_mock = get_telegram_testobject(mocker, default_conf_usdt)
# Create some test data
freqtradebot.enter_positions()
trade = Trade.query.first()
assert trade
create_mock_trades_usdt(fee)
# Simulate fulfilled LIMIT_BUY order for trade
limit_buy_order['id'] = trade.orders[0].order_id
oobj = Order.parse_from_ccxt_object(limit_buy_order, limit_buy_order['symbol'], 'buy')
trade.update_order(limit_buy_order)
trade.update_trade(oobj)
# Simulate fulfilled LIMIT_SELL order for trade
oobj = Order.parse_from_ccxt_object(limit_sell_order, limit_sell_order['symbol'], 'sell')
trade.update_trade(oobj)
trade.close_date = datetime.utcnow()
trade.is_open = False
telegram._performance(update=update, context=MagicMock())
assert msg_mock.call_count == 1
assert 'Performance' in msg_mock.call_args_list[0][0][0]
assert '<code>ETH/BTC\t0.00006217 BTC (6.20%) (1)</code>' in msg_mock.call_args_list[0][0][0]
assert '<code>XRP/USDT\t9.842 USDT (10.00%) (1)</code>' in msg_mock.call_args_list[0][0][0]
def test_telegram_entry_tag_performance_handle(
default_conf, update, ticker, fee, limit_buy_order, limit_sell_order, mocker) -> None:
default_conf_usdt, update, ticker, fee, mocker) -> None:
mocker.patch.multiple(
'freqtrade.exchange.Exchange',
fetch_ticker=ticker,
get_fee=fee,
)
telegram, freqtradebot, msg_mock = get_telegram_testobject(mocker, default_conf)
telegram, freqtradebot, msg_mock = get_telegram_testobject(mocker, default_conf_usdt)
patch_get_signal(freqtradebot)
# Create some test data
freqtradebot.enter_positions()
trade = Trade.query.first()
assert trade
create_mock_trades_usdt(fee)
# Simulate fulfilled LIMIT_BUY order for trade
limit_buy_order['id'] = trade.orders[0].order_id
oobj = Order.parse_from_ccxt_object(limit_buy_order, limit_buy_order['symbol'], 'buy')
trade.update_order(limit_buy_order)
trade.update_trade(oobj)
trade.enter_tag = "TESTBUY"
# Simulate fulfilled LIMIT_SELL order for trade
oobj = Order.parse_from_ccxt_object(limit_sell_order, limit_sell_order['symbol'], 'sell')
trade.update_trade(oobj)
trade.close_date = datetime.utcnow()
trade.is_open = False
context = MagicMock()
telegram._enter_tag_performance(update=update, context=context)
assert msg_mock.call_count == 1
assert 'Entry Tag Performance' in msg_mock.call_args_list[0][0][0]
assert '<code>TESTBUY\t0.00006217 BTC (6.20%) (1)</code>' in msg_mock.call_args_list[0][0][0]
assert '<code>TEST1\t3.987 USDT (5.00%) (1)</code>' in msg_mock.call_args_list[0][0][0]
context.args = [trade.pair]
context.args = ['XRP/USDT']
telegram._enter_tag_performance(update=update, context=context)
assert msg_mock.call_count == 2
@@ -1446,39 +1295,24 @@ def test_telegram_entry_tag_performance_handle(
assert "Error" in msg_mock.call_args_list[0][0][0]
def test_telegram_exit_reason_performance_handle(default_conf, update, ticker, fee,
limit_buy_order, limit_sell_order, mocker) -> None:
def test_telegram_exit_reason_performance_handle(default_conf_usdt, update, ticker, fee,
mocker) -> None:
mocker.patch.multiple(
'freqtrade.exchange.Exchange',
fetch_ticker=ticker,
get_fee=fee,
)
telegram, freqtradebot, msg_mock = get_telegram_testobject(mocker, default_conf)
telegram, freqtradebot, msg_mock = get_telegram_testobject(mocker, default_conf_usdt)
patch_get_signal(freqtradebot)
# Create some test data
freqtradebot.enter_positions()
trade = Trade.query.first()
assert trade
trade.exit_reason = 'TESTSELL'
# Simulate fulfilled LIMIT_BUY order for trade
limit_buy_order['id'] = trade.orders[0].order_id
oobj = Order.parse_from_ccxt_object(limit_buy_order, limit_buy_order['symbol'], 'buy')
trade.update_order(limit_buy_order)
trade.update_trade(oobj)
create_mock_trades_usdt(fee)
# Simulate fulfilled LIMIT_SELL order for trade
oobj = Order.parse_from_ccxt_object(limit_sell_order, limit_sell_order['symbol'], 'sell')
trade.update_trade(oobj)
trade.close_date = datetime.utcnow()
trade.is_open = False
context = MagicMock()
telegram._exit_reason_performance(update=update, context=context)
assert msg_mock.call_count == 1
assert 'Exit Reason Performance' in msg_mock.call_args_list[0][0][0]
assert '<code>TESTSELL\t0.00006217 BTC (6.20%) (1)</code>' in msg_mock.call_args_list[0][0][0]
context.args = [trade.pair]
assert '<code>roi\t9.842 USDT (10.00%) (1)</code>' in msg_mock.call_args_list[0][0][0]
context.args = ['XRP/USDT']
telegram._exit_reason_performance(update=update, context=context)
assert msg_mock.call_count == 2
@@ -1492,45 +1326,27 @@ def test_telegram_exit_reason_performance_handle(default_conf, update, ticker, f
assert "Error" in msg_mock.call_args_list[0][0][0]
def test_telegram_mix_tag_performance_handle(default_conf, update, ticker, fee,
limit_buy_order, limit_sell_order, mocker) -> None:
def test_telegram_mix_tag_performance_handle(default_conf_usdt, update, ticker, fee,
mocker) -> None:
mocker.patch.multiple(
'freqtrade.exchange.Exchange',
fetch_ticker=ticker,
get_fee=fee,
)
telegram, freqtradebot, msg_mock = get_telegram_testobject(mocker, default_conf)
telegram, freqtradebot, msg_mock = get_telegram_testobject(mocker, default_conf_usdt)
patch_get_signal(freqtradebot)
# Create some test data
freqtradebot.enter_positions()
trade = Trade.query.first()
assert trade
trade.enter_tag = "TESTBUY"
trade.exit_reason = "TESTSELL"
# Simulate fulfilled LIMIT_BUY order for trade
limit_buy_order['id'] = trade.orders[0].order_id
oobj = Order.parse_from_ccxt_object(limit_buy_order, limit_buy_order['symbol'], 'buy')
trade.update_order(limit_buy_order)
trade.update_trade(oobj)
# Simulate fulfilled LIMIT_SELL order for trade
oobj = Order.parse_from_ccxt_object(limit_sell_order, limit_sell_order['symbol'], 'sell')
trade.update_trade(oobj)
trade.close_date = datetime.utcnow()
trade.is_open = False
create_mock_trades_usdt(fee)
context = MagicMock()
telegram._mix_tag_performance(update=update, context=context)
assert msg_mock.call_count == 1
assert 'Mix Tag Performance' in msg_mock.call_args_list[0][0][0]
assert ('<code>TESTBUY TESTSELL\t0.00006217 BTC (6.20%) (1)</code>'
assert ('<code>TEST3 roi\t9.842 USDT (10.00%) (1)</code>'
in msg_mock.call_args_list[0][0][0])
context.args = [trade.pair]
context.args = ['XRP/USDT']
telegram._mix_tag_performance(update=update, context=context)
assert msg_mock.call_count == 2

View File

@@ -1,5 +1,6 @@
# pragma pylint: disable=missing-docstring, C0103, protected-access
from datetime import datetime, timedelta
from unittest.mock import MagicMock
import pytest
@@ -7,6 +8,7 @@ from requests import RequestException
from freqtrade.enums import ExitType, RPCMessageType
from freqtrade.rpc import RPC
from freqtrade.rpc.discord import Discord
from freqtrade.rpc.webhook import Webhook
from tests.conftest import get_patched_freqtradebot, log_has
@@ -406,3 +408,42 @@ def test__send_msg_with_raw_format(default_conf, mocker, caplog):
webhook._send_msg(msg)
assert post.call_args[1] == {'data': msg['data'], 'headers': {'Content-Type': 'text/plain'}}
def test_send_msg_discord(default_conf, mocker):
default_conf["discord"] = {
'enabled': True,
'webhook_url': "https://webhookurl..."
}
msg_mock = MagicMock()
mocker.patch("freqtrade.rpc.webhook.Webhook._send_msg", msg_mock)
discord = Discord(RPC(get_patched_freqtradebot(mocker, default_conf)), default_conf)
msg = {
'type': RPCMessageType.EXIT_FILL,
'trade_id': 1,
'exchange': 'Binance',
'pair': 'ETH/BTC',
'direction': 'Long',
'gain': "profit",
'close_rate': 0.005,
'amount': 0.8,
'order_type': 'limit',
'open_date': datetime.now() - timedelta(days=1),
'close_date': datetime.now(),
'open_rate': 0.004,
'current_rate': 0.005,
'profit_amount': 0.001,
'profit_ratio': 0.20,
'stake_currency': 'BTC',
'enter_tag': 'enter_tagggg',
'exit_reason': ExitType.STOP_LOSS.value,
}
discord.send_msg(msg=msg)
assert msg_mock.call_count == 1
assert 'embeds' in msg_mock.call_args_list[0][0][0]
assert 'title' in msg_mock.call_args_list[0][0][0]['embeds'][0]
assert 'color' in msg_mock.call_args_list[0][0][0]['embeds'][0]
assert 'fields' in msg_mock.call_args_list[0][0][0]['embeds'][0]

View File

@@ -27,7 +27,6 @@ class HyperoptableStrategy(StrategyTestV2):
'sell_minusdi': 0.4
}
buy_rsi = IntParameter([0, 50], default=30, space='buy')
buy_plusdi = RealParameter(low=0, high=1, default=0.5, space='buy')
sell_rsi = IntParameter(low=50, high=100, default=70, space='sell')
sell_minusdi = DecimalParameter(low=0, high=1, default=0.5001, decimals=3, space='sell',
@@ -45,6 +44,12 @@ class HyperoptableStrategy(StrategyTestV2):
})
return prot
def bot_start(self, **kwargs) -> None:
"""
Parameters can also be defined here ...
"""
self.buy_rsi = IntParameter([0, 50], default=30, space='buy')
def informative_pairs(self):
"""
Define additional, informative pair/interval combinations to be cached from the exchange.

View File

@@ -178,8 +178,8 @@ class StrategyTestV3(IStrategy):
return dataframe
def leverage(self, pair: str, current_time: datetime, current_rate: float,
proposed_leverage: float, max_leverage: float, side: str,
**kwargs) -> float:
proposed_leverage: float, max_leverage: float, entry_tag: Optional[str],
side: str, **kwargs) -> float:
# Return 3.0 in all cases.
# Bot-logic must make sure it's an allowed leverage and eventually adjust accordingly.

View File

@@ -16,10 +16,12 @@ from freqtrade.exceptions import OperationalException, StrategyError
from freqtrade.optimize.space import SKDecimal
from freqtrade.persistence import PairLocks, Trade
from freqtrade.resolvers import StrategyResolver
from freqtrade.strategy.hyper import detect_parameters
from freqtrade.strategy.parameters import (BaseParameter, BooleanParameter, CategoricalParameter,
DecimalParameter, IntParameter, RealParameter)
from freqtrade.strategy.strategy_wrapper import strategy_safe_wrapper
from tests.conftest import CURRENT_TEST_STRATEGY, TRADE_SIDES, log_has, log_has_re
from tests.conftest import (CURRENT_TEST_STRATEGY, TRADE_SIDES, create_mock_trades, log_has,
log_has_re)
from .strats.strategy_test_v3 import StrategyTestV3
@@ -614,6 +616,7 @@ def test_leverage_callback(default_conf, side) -> None:
proposed_leverage=1.0,
max_leverage=5.0,
side=side,
entry_tag=None,
) == 1
default_conf['strategy'] = CURRENT_TEST_STRATEGY
@@ -625,6 +628,7 @@ def test_leverage_callback(default_conf, side) -> None:
proposed_leverage=1.0,
max_leverage=5.0,
side=side,
entry_tag='entry_tag_test',
) == 3
@@ -809,6 +813,28 @@ def test_strategy_safe_wrapper(value):
assert ret == value
@pytest.mark.usefixtures("init_persistence")
def test_strategy_safe_wrapper_trade_copy(fee):
create_mock_trades(fee)
def working_method(trade):
assert len(trade.orders) > 0
assert trade.orders
trade.orders = []
assert len(trade.orders) == 0
return trade
trade = Trade.get_open_trades()[0]
# Don't assert anything before strategy_wrapper.
# This ensures that relationship loading works correctly.
ret = strategy_safe_wrapper(working_method, message='DeadBeef')(trade=trade)
assert isinstance(ret, Trade)
assert id(trade) != id(ret)
# Did not modify the original order
assert len(trade.orders) > 0
assert len(ret.orders) == 0
def test_hyperopt_parameters():
from skopt.space import Categorical, Integer, Real
with pytest.raises(OperationalException, match=r"Name is determined.*"):
@@ -893,7 +919,7 @@ def test_auto_hyperopt_interface(default_conf):
default_conf.update({'strategy': 'HyperoptableStrategy'})
PairLocks.timeframe = default_conf['timeframe']
strategy = StrategyResolver.load_strategy(default_conf)
strategy.ft_bot_start()
with pytest.raises(OperationalException):
next(strategy.enumerate_parameters('deadBeef'))
@@ -908,15 +934,18 @@ def test_auto_hyperopt_interface(default_conf):
assert strategy.sell_minusdi.value == 0.5
all_params = strategy.detect_all_parameters()
assert isinstance(all_params, dict)
assert len(all_params['buy']) == 2
# Only one buy param at class level
assert len(all_params['buy']) == 1
# Running detect params at instance level reveals both parameters.
assert len(list(detect_parameters(strategy, 'buy'))) == 2
assert len(all_params['sell']) == 2
# Number of Hyperoptable parameters
assert all_params['count'] == 6
assert all_params['count'] == 5
strategy.__class__.sell_rsi = IntParameter([0, 10], default=5, space='buy')
with pytest.raises(OperationalException, match=r"Inconclusive parameter.*"):
[x for x in strategy.detect_parameters('sell')]
[x for x in detect_parameters(strategy, 'sell')]
def test_auto_hyperopt_interface_loadparams(default_conf, mocker, caplog):

View File

@@ -209,13 +209,14 @@ def test_edge_overrides_stoploss(limit_order, fee, caplog, mocker,
#
# mocking the ticker: price is falling ...
enter_price = limit_order['buy']['price']
ticker_val = {
'bid': enter_price,
'ask': enter_price,
'last': enter_price,
}
mocker.patch.multiple(
'freqtrade.exchange.Exchange',
fetch_ticker=MagicMock(return_value={
'bid': enter_price * buy_price_mult,
'ask': enter_price * buy_price_mult,
'last': enter_price * buy_price_mult,
}),
fetch_ticker=MagicMock(return_value=ticker_val),
get_fee=fee,
)
#############################################
@@ -228,11 +229,12 @@ def test_edge_overrides_stoploss(limit_order, fee, caplog, mocker,
freqtrade.enter_positions()
trade = Trade.query.first()
caplog.clear()
limit_order['buy']['id'] = trade.orders[0].order_id
oobj = Order.parse_from_ccxt_object(limit_order['buy'], 'NEO/BTC', 'buy')
trade.update_order(limit_order['buy'])
trade.update_trade(oobj)
#############################################
ticker_val.update({
'bid': enter_price * buy_price_mult,
'ask': enter_price * buy_price_mult,
'last': enter_price * buy_price_mult,
})
# stoploss shoud be hit
assert freqtrade.handle_trade(trade) is not ignore_strat_sl
@@ -1776,9 +1778,7 @@ def test_tsl_on_exchange_compatible_with_edge(mocker, edge_conf, fee, caplog,
'type': 'stop_loss_limit',
'price': 3,
'average': 2,
'info': {
'stopPrice': '2.178'
}
'stopPrice': '2.178'
})
mocker.patch('freqtrade.exchange.Exchange.fetch_stoploss_order', stoploss_order_hanging)
@@ -2577,6 +2577,7 @@ def test_check_handle_cancelled_buy(
get_fee=fee
)
freqtrade = FreqtradeBot(default_conf_usdt)
open_trade.orders = []
open_trade.is_short = is_short
Trade.query.session.add(open_trade)
@@ -2961,6 +2962,7 @@ def test_handle_cancel_enter(mocker, caplog, default_conf_usdt, limit_order, is_
freqtrade = FreqtradeBot(default_conf_usdt)
freqtrade._notify_enter_cancel = MagicMock()
# TODO: Convert to real trade
trade = MagicMock()
trade.pair = 'LTC/USDT'
trade.open_rate = 200
@@ -2968,6 +2970,7 @@ def test_handle_cancel_enter(mocker, caplog, default_conf_usdt, limit_order, is_
trade.entry_side = "buy"
l_order['filled'] = 0.0
l_order['status'] = 'open'
trade.nr_of_successful_entries = 0
reason = CANCEL_REASON['TIMEOUT']
assert freqtrade.handle_cancel_enter(trade, l_order, reason)
assert cancel_order_mock.call_count == 1
@@ -3010,7 +3013,9 @@ def test_handle_cancel_enter_exchanges(mocker, caplog, default_conf_usdt, is_sho
freqtrade = FreqtradeBot(default_conf_usdt)
reason = CANCEL_REASON['TIMEOUT']
# TODO: Convert to real trade
trade = MagicMock()
trade.nr_of_successful_entries = 0
trade.pair = 'LTC/ETH'
trade.entry_side = "sell" if is_short else "buy"
assert freqtrade.handle_cancel_enter(trade, limit_buy_order_canceled_empty, reason)
@@ -3043,13 +3048,14 @@ def test_handle_cancel_enter_corder_empty(mocker, default_conf_usdt, limit_order
freqtrade = FreqtradeBot(default_conf_usdt)
freqtrade._notify_enter_cancel = MagicMock()
# TODO: Convert to real trade
trade = MagicMock()
trade.pair = 'LTC/USDT'
trade.entry_side = "buy"
trade.open_rate = 200
trade.entry_side = "buy"
trade.open_order_id = "open_order_noop"
trade.nr_of_successful_entries = 0
l_order['filled'] = 0.0
l_order['status'] = 'open'
reason = CANCEL_REASON['TIMEOUT']
@@ -3783,6 +3789,7 @@ def test_exit_profit_only(
trade = Trade.query.first()
assert trade.is_short == is_short
oobj = Order.parse_from_ccxt_object(limit_order[eside], limit_order[eside]['symbol'], eside)
trade.update_order(limit_order[eside])
trade.update_trade(oobj)
freqtrade.wallets.update()
if profit_only:
@@ -4071,6 +4078,7 @@ def test_trailing_stop_loss_positive(
trade = Trade.query.first()
assert trade.is_short == is_short
oobj = Order.parse_from_ccxt_object(limit_order[eside], limit_order[eside]['symbol'], eside)
trade.update_order(limit_order[eside])
trade.update_trade(oobj)
caplog.set_level(logging.DEBUG)
# stop-loss not reached
@@ -4816,10 +4824,19 @@ def test_startup_update_open_orders(mocker, default_conf_usdt, fee, caplog, is_s
assert len(Order.get_open_orders()) == 2
caplog.clear()
mocker.patch('freqtrade.exchange.Exchange.fetch_order', side_effect=InvalidOrderException)
mocker.patch('freqtrade.exchange.Exchange.fetch_order', side_effect=ExchangeError)
freqtrade.startup_update_open_orders()
assert log_has_re(r"Error updating Order .*", caplog)
mocker.patch('freqtrade.exchange.Exchange.fetch_order', side_effect=InvalidOrderException)
hto_mock = mocker.patch('freqtrade.freqtradebot.FreqtradeBot.handle_timedout_order')
# Orders which are no longer found after X days should be assumed as canceled.
freqtrade.startup_update_open_orders()
assert log_has_re(r"Order is older than \d days.*", caplog)
assert hto_mock.call_count == 2
assert hto_mock.call_args_list[0][0][0]['status'] == 'canceled'
assert hto_mock.call_args_list[1][0][0]['status'] == 'canceled'
@pytest.mark.usefixtures("init_persistence")
@pytest.mark.parametrize("is_short", [False, True])