Merge branch 'develop' into feature_keyval_storage

This commit is contained in:
eSeR1805
2022-06-13 20:05:45 +03:00
31 changed files with 732 additions and 841 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

@@ -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
@@ -284,8 +284,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',
@@ -294,45 +294,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])
@@ -416,13 +406,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',
@@ -430,10 +415,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()
@@ -446,75 +430,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'], 'sell')
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',
@@ -522,46 +471,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):
@@ -913,8 +848,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',
@@ -923,34 +857,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',
@@ -964,34 +885,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):
@@ -1023,8 +932,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',
@@ -1033,39 +941,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):
@@ -1097,8 +988,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',
@@ -1112,35 +1002,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,25 +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
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
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
@@ -446,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()
@@ -458,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:
@@ -512,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',
@@ -528,25 +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
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
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
@@ -560,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()
@@ -573,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()
@@ -629,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',
@@ -646,25 +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
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
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
@@ -677,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()
@@ -691,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()
@@ -716,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
@@ -754,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())
@@ -775,10 +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
oobj = Order.parse_from_ccxt_object(limit_buy_order, limit_buy_order['symbol'], 'buy')
trade.update_trade(oobj)
context = MagicMock()
# Test with invalid 2nd argument (should silently pass)
context.args = ["aaa"]
@@ -786,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)
@@ -805,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])
@@ -1350,71 +1240,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
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
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
oobj = Order.parse_from_ccxt_object(limit_buy_order, limit_buy_order['symbol'], 'buy')
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
@@ -1427,37 +1289,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
oobj = Order.parse_from_ccxt_object(limit_buy_order, limit_buy_order['symbol'], 'buy')
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
@@ -1471,43 +1320,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
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
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

@@ -20,7 +20,8 @@ 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
@@ -812,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.*"):

View File

@@ -210,13 +210,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,
)
#############################################
@@ -229,9 +230,12 @@ def test_edge_overrides_stoploss(limit_order, fee, caplog, mocker,
freqtrade.enter_positions()
trade = Trade.query.first()
caplog.clear()
oobj = Order.parse_from_ccxt_object(limit_order['buy'], 'ADA/USDT', '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
@@ -3771,6 +3775,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:
@@ -4059,6 +4064,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