Merge branch 'develop' into plugins/protections_backtest
This commit is contained in:
@@ -1588,16 +1588,7 @@ def fetch_trades_result():
|
||||
|
||||
@pytest.fixture(scope="function")
|
||||
def trades_for_order2():
|
||||
return [{'info': {'id': 34567,
|
||||
'orderId': 123456,
|
||||
'price': '0.24544100',
|
||||
'qty': '8.00000000',
|
||||
'commission': '0.00800000',
|
||||
'commissionAsset': 'LTC',
|
||||
'time': 1521663363189,
|
||||
'isBuyer': True,
|
||||
'isMaker': False,
|
||||
'isBestMatch': True},
|
||||
return [{'info': {},
|
||||
'timestamp': 1521663363189,
|
||||
'datetime': '2018-03-21T20:16:03.189Z',
|
||||
'symbol': 'LTC/ETH',
|
||||
@@ -1609,16 +1600,7 @@ def trades_for_order2():
|
||||
'cost': 1.963528,
|
||||
'amount': 4.0,
|
||||
'fee': {'cost': 0.004, 'currency': 'LTC'}},
|
||||
{'info': {'id': 34567,
|
||||
'orderId': 123456,
|
||||
'price': '0.24544100',
|
||||
'qty': '8.00000000',
|
||||
'commission': '0.00800000',
|
||||
'commissionAsset': 'LTC',
|
||||
'time': 1521663363189,
|
||||
'isBuyer': True,
|
||||
'isMaker': False,
|
||||
'isBestMatch': True},
|
||||
{'info': {},
|
||||
'timestamp': 1521663363189,
|
||||
'datetime': '2018-03-21T20:16:03.189Z',
|
||||
'symbol': 'LTC/ETH',
|
||||
@@ -1632,6 +1614,14 @@ def trades_for_order2():
|
||||
'fee': {'cost': 0.004, 'currency': 'LTC'}}]
|
||||
|
||||
|
||||
@pytest.fixture(scope="function")
|
||||
def trades_for_order3(trades_for_order2):
|
||||
# Different fee currencies for each trade
|
||||
trades_for_order = deepcopy(trades_for_order2)
|
||||
trades_for_order[0]['fee'] = {'cost': 0.02, 'currency': 'BNB'}
|
||||
return trades_for_order
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def buy_order_fee():
|
||||
return {
|
||||
|
@@ -1,3 +1,5 @@
|
||||
from datetime import datetime, timedelta, timezone
|
||||
|
||||
from freqtrade.persistence.models import Order, Trade
|
||||
|
||||
|
||||
@@ -82,6 +84,9 @@ def mock_trade_2(fee):
|
||||
is_open=False,
|
||||
open_order_id='dry_run_sell_12345',
|
||||
strategy='DefaultStrategy',
|
||||
sell_reason='sell_signal',
|
||||
open_date=datetime.now(tz=timezone.utc) - timedelta(minutes=20),
|
||||
close_date=datetime.now(tz=timezone.utc),
|
||||
)
|
||||
o = Order.parse_from_ccxt_object(mock_order_2(), 'ETC/BTC', 'buy')
|
||||
trade.orders.append(o)
|
||||
@@ -134,6 +139,9 @@ def mock_trade_3(fee):
|
||||
close_profit=0.01,
|
||||
exchange='bittrex',
|
||||
is_open=False,
|
||||
sell_reason='roi',
|
||||
open_date=datetime.now(tz=timezone.utc) - timedelta(minutes=20),
|
||||
close_date=datetime.now(tz=timezone.utc),
|
||||
)
|
||||
o = Order.parse_from_ccxt_object(mock_order_3(), 'XRP/BTC', 'buy')
|
||||
trade.orders.append(o)
|
||||
|
@@ -62,7 +62,7 @@ def test_rpc_trade_status(default_conf, ticker, fee, mocker) -> None:
|
||||
'fee_close_cost': ANY,
|
||||
'fee_close_currency': ANY,
|
||||
'open_rate_requested': ANY,
|
||||
'open_trade_price': 0.0010025,
|
||||
'open_trade_value': 0.0010025,
|
||||
'close_rate_requested': ANY,
|
||||
'sell_reason': ANY,
|
||||
'sell_order_status': ANY,
|
||||
@@ -127,7 +127,7 @@ def test_rpc_trade_status(default_conf, ticker, fee, mocker) -> None:
|
||||
'fee_close_cost': ANY,
|
||||
'fee_close_currency': ANY,
|
||||
'open_rate_requested': ANY,
|
||||
'open_trade_price': ANY,
|
||||
'open_trade_value': ANY,
|
||||
'close_rate_requested': ANY,
|
||||
'sell_reason': ANY,
|
||||
'sell_order_status': ANY,
|
||||
|
@@ -559,6 +559,35 @@ def test_api_profit(botclient, mocker, ticker, fee, markets, limit_buy_order, li
|
||||
}
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("init_persistence")
|
||||
def test_api_stats(botclient, mocker, ticker, fee, markets,):
|
||||
ftbot, client = botclient
|
||||
patch_get_signal(ftbot, (True, False))
|
||||
mocker.patch.multiple(
|
||||
'freqtrade.exchange.Exchange',
|
||||
get_balances=MagicMock(return_value=ticker),
|
||||
fetch_ticker=ticker,
|
||||
get_fee=fee,
|
||||
markets=PropertyMock(return_value=markets)
|
||||
)
|
||||
|
||||
rc = client_get(client, f"{BASE_URI}/stats")
|
||||
assert_response(rc, 200)
|
||||
assert 'durations' in rc.json
|
||||
assert 'sell_reasons' in rc.json
|
||||
|
||||
create_mock_trades(fee)
|
||||
|
||||
rc = client_get(client, f"{BASE_URI}/stats")
|
||||
assert_response(rc, 200)
|
||||
assert 'durations' in rc.json
|
||||
assert 'sell_reasons' in rc.json
|
||||
|
||||
assert 'wins' in rc.json['durations']
|
||||
assert 'losses' in rc.json['durations']
|
||||
assert 'draws' in rc.json['durations']
|
||||
|
||||
|
||||
def test_api_performance(botclient, mocker, ticker, fee):
|
||||
ftbot, client = botclient
|
||||
patch_get_signal(ftbot, (True, False))
|
||||
@@ -678,7 +707,7 @@ def test_api_status(botclient, mocker, ticker, fee, markets):
|
||||
'min_rate': 1.098e-05,
|
||||
'open_order_id': None,
|
||||
'open_rate_requested': 1.098e-05,
|
||||
'open_trade_price': 0.0010025,
|
||||
'open_trade_value': 0.0010025,
|
||||
'sell_reason': None,
|
||||
'sell_order_status': None,
|
||||
'strategy': 'DefaultStrategy',
|
||||
@@ -805,7 +834,7 @@ def test_api_forcebuy(botclient, mocker, fee):
|
||||
'min_rate': None,
|
||||
'open_order_id': '123456',
|
||||
'open_rate_requested': None,
|
||||
'open_trade_price': 0.24605460,
|
||||
'open_trade_value': 0.24605460,
|
||||
'sell_reason': None,
|
||||
'sell_order_status': None,
|
||||
'strategy': None,
|
||||
|
@@ -74,9 +74,10 @@ def test_telegram_init(default_conf, mocker, caplog) -> None:
|
||||
|
||||
message_str = ("rpc.telegram is listening for following commands: [['status'], ['profit'], "
|
||||
"['balance'], ['start'], ['stop'], ['forcesell'], ['forcebuy'], ['trades'], "
|
||||
"['delete'], ['performance'], ['daily'], ['count'], ['locks'], "
|
||||
"['delete'], ['performance'], ['stats'], ['daily'], ['count'], ['locks'], "
|
||||
"['reload_config', 'reload_conf'], ['show_config', 'show_conf'], ['stopbuy'], "
|
||||
"['whitelist'], ['blacklist'], ['logs'], ['edge'], ['help'], ['version']]")
|
||||
"['whitelist'], ['blacklist'], ['logs'], ['edge'], ['help'], ['version']"
|
||||
"]")
|
||||
|
||||
assert log_has(message_str, caplog)
|
||||
|
||||
@@ -468,6 +469,41 @@ def test_profit_handle(default_conf, update, ticker, ticker_sell_up, fee,
|
||||
assert '*Best Performing:* `ETH/BTC: 6.20%`' in msg_mock.call_args_list[-1][0][0]
|
||||
|
||||
|
||||
def test_telegram_stats(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)
|
||||
mocker.patch.multiple(
|
||||
'freqtrade.exchange.Exchange',
|
||||
fetch_ticker=ticker,
|
||||
get_fee=fee,
|
||||
)
|
||||
msg_mock = MagicMock()
|
||||
mocker.patch.multiple(
|
||||
'freqtrade.rpc.telegram.Telegram',
|
||||
_init=MagicMock(),
|
||||
_send_msg=msg_mock
|
||||
)
|
||||
|
||||
freqtradebot = get_patched_freqtradebot(mocker, default_conf)
|
||||
patch_get_signal(freqtradebot, (True, False))
|
||||
telegram = Telegram(freqtradebot)
|
||||
|
||||
telegram._stats(update=update, context=MagicMock())
|
||||
assert msg_mock.call_count == 1
|
||||
# assert 'No trades yet.' in msg_mock.call_args_list[0][0][0]
|
||||
msg_mock.reset_mock()
|
||||
|
||||
# Create some test data
|
||||
create_mock_trades(fee)
|
||||
|
||||
telegram._stats(update=update, context=MagicMock())
|
||||
assert msg_mock.call_count == 1
|
||||
assert 'Sell Reason' in msg_mock.call_args_list[-1][0][0]
|
||||
assert 'ROI' in msg_mock.call_args_list[-1][0][0]
|
||||
assert 'Avg. Duration' in msg_mock.call_args_list[-1][0][0]
|
||||
msg_mock.reset_mock()
|
||||
|
||||
|
||||
def test_telegram_balance_handle(default_conf, update, mocker, rpc_balance, tickers) -> None:
|
||||
default_conf['dry_run'] = False
|
||||
mocker.patch('freqtrade.exchange.Exchange.get_balances', return_value=rpc_balance)
|
||||
|
@@ -3744,6 +3744,48 @@ def test_get_real_amount_multi(default_conf, trades_for_order2, buy_order_fee, c
|
||||
'open_rate=0.24544100, open_since=closed) (from 8.0 to 7.992).',
|
||||
caplog)
|
||||
|
||||
assert trade.fee_open == 0.001
|
||||
assert trade.fee_close == 0.001
|
||||
assert trade.fee_open_cost is not None
|
||||
assert trade.fee_open_currency is not None
|
||||
assert trade.fee_close_cost is None
|
||||
assert trade.fee_close_currency is None
|
||||
|
||||
|
||||
def test_get_real_amount_multi2(default_conf, trades_for_order3, buy_order_fee, caplog, fee,
|
||||
mocker, markets):
|
||||
# Different fee currency on both trades
|
||||
mocker.patch('freqtrade.exchange.Exchange.get_trades_for_order', return_value=trades_for_order3)
|
||||
amount = float(sum(x['amount'] for x in trades_for_order3))
|
||||
default_conf['stake_currency'] = 'ETH'
|
||||
trade = Trade(
|
||||
pair='LTC/ETH',
|
||||
amount=amount,
|
||||
exchange='binance',
|
||||
fee_open=fee.return_value,
|
||||
fee_close=fee.return_value,
|
||||
open_rate=0.245441,
|
||||
open_order_id="123456"
|
||||
)
|
||||
# Fake markets entry to enable fee parsing
|
||||
markets['BNB/ETH'] = markets['ETH/BTC']
|
||||
freqtrade = get_patched_freqtradebot(mocker, default_conf)
|
||||
mocker.patch('freqtrade.exchange.Exchange.markets', PropertyMock(return_value=markets))
|
||||
mocker.patch('freqtrade.exchange.Exchange.fetch_ticker',
|
||||
return_value={'ask': 0.19, 'last': 0.2})
|
||||
|
||||
# Amount is reduced by "fee"
|
||||
assert freqtrade.get_real_amount(trade, buy_order_fee) == amount - (amount * 0.0005)
|
||||
assert log_has('Applying fee on amount for Trade(id=None, pair=LTC/ETH, amount=8.00000000, '
|
||||
'open_rate=0.24544100, open_since=closed) (from 8.0 to 7.996).',
|
||||
caplog)
|
||||
# Overall fee is average of both trade's fee
|
||||
assert trade.fee_open == 0.001518575
|
||||
assert trade.fee_open_cost is not None
|
||||
assert trade.fee_open_currency is not None
|
||||
assert trade.fee_close_cost is None
|
||||
assert trade.fee_close_currency is None
|
||||
|
||||
|
||||
def test_get_real_amount_fromorder(default_conf, trades_for_order, buy_order_fee, fee,
|
||||
caplog, mocker):
|
||||
@@ -4290,7 +4332,7 @@ def test_update_closed_trades_without_assigned_fees(mocker, default_conf, fee):
|
||||
freqtrade = get_patched_freqtradebot(mocker, default_conf)
|
||||
|
||||
def patch_with_fee(order):
|
||||
order.update({'fee': {'cost': 0.1, 'rate': 0.2,
|
||||
order.update({'fee': {'cost': 0.1, 'rate': 0.01,
|
||||
'currency': order['symbol'].split('/')[0]}})
|
||||
return order
|
||||
|
||||
|
@@ -177,10 +177,10 @@ def test_calc_open_close_trade_price(limit_buy_order, limit_sell_order, fee):
|
||||
|
||||
trade.open_order_id = 'something'
|
||||
trade.update(limit_buy_order)
|
||||
assert trade._calc_open_trade_price() == 0.0010024999999225068
|
||||
assert trade._calc_open_trade_value() == 0.0010024999999225068
|
||||
|
||||
trade.update(limit_sell_order)
|
||||
assert trade.calc_close_trade_price() == 0.0010646656050132426
|
||||
assert trade.calc_close_trade_value() == 0.0010646656050132426
|
||||
|
||||
# Profit in BTC
|
||||
assert trade.calc_profit() == 0.00006217
|
||||
@@ -233,7 +233,7 @@ def test_calc_close_trade_price_exception(limit_buy_order, fee):
|
||||
|
||||
trade.open_order_id = 'something'
|
||||
trade.update(limit_buy_order)
|
||||
assert trade.calc_close_trade_price() == 0.0
|
||||
assert trade.calc_close_trade_value() == 0.0
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("init_persistence")
|
||||
@@ -277,7 +277,7 @@ def test_update_invalid_order(limit_buy_order):
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("init_persistence")
|
||||
def test_calc_open_trade_price(limit_buy_order, fee):
|
||||
def test_calc_open_trade_value(limit_buy_order, fee):
|
||||
trade = Trade(
|
||||
pair='ETH/BTC',
|
||||
stake_amount=0.001,
|
||||
@@ -291,10 +291,10 @@ def test_calc_open_trade_price(limit_buy_order, fee):
|
||||
trade.update(limit_buy_order) # Buy @ 0.00001099
|
||||
|
||||
# Get the open rate price with the standard fee rate
|
||||
assert trade._calc_open_trade_price() == 0.0010024999999225068
|
||||
assert trade._calc_open_trade_value() == 0.0010024999999225068
|
||||
trade.fee_open = 0.003
|
||||
# Get the open rate price with a custom fee rate
|
||||
assert trade._calc_open_trade_price() == 0.001002999999922468
|
||||
assert trade._calc_open_trade_value() == 0.001002999999922468
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("init_persistence")
|
||||
@@ -312,14 +312,14 @@ def test_calc_close_trade_price(limit_buy_order, limit_sell_order, fee):
|
||||
trade.update(limit_buy_order) # Buy @ 0.00001099
|
||||
|
||||
# Get the close rate price with a custom close rate and a regular fee rate
|
||||
assert trade.calc_close_trade_price(rate=0.00001234) == 0.0011200318470471794
|
||||
assert trade.calc_close_trade_value(rate=0.00001234) == 0.0011200318470471794
|
||||
|
||||
# Get the close rate price with a custom close rate and a custom fee rate
|
||||
assert trade.calc_close_trade_price(rate=0.00001234, fee=0.003) == 0.0011194704275749754
|
||||
assert trade.calc_close_trade_value(rate=0.00001234, fee=0.003) == 0.0011194704275749754
|
||||
|
||||
# Test when we apply a Sell order, and ask price with a custom fee rate
|
||||
trade.update(limit_sell_order)
|
||||
assert trade.calc_close_trade_price(fee=0.005) == 0.0010619972701635854
|
||||
assert trade.calc_close_trade_value(fee=0.005) == 0.0010619972701635854
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("init_persistence")
|
||||
@@ -499,7 +499,7 @@ def test_migrate_old(mocker, default_conf, fee):
|
||||
assert trade.max_rate == 0.0
|
||||
assert trade.stop_loss == 0.0
|
||||
assert trade.initial_stop_loss == 0.0
|
||||
assert trade.open_trade_price == trade._calc_open_trade_price()
|
||||
assert trade.open_trade_value == trade._calc_open_trade_value()
|
||||
assert trade.close_profit_abs is None
|
||||
assert trade.fee_open_cost is None
|
||||
assert trade.fee_open_currency is None
|
||||
@@ -607,7 +607,7 @@ def test_migrate_new(mocker, default_conf, fee, caplog):
|
||||
assert log_has("trying trades_bak1", caplog)
|
||||
assert log_has("trying trades_bak2", caplog)
|
||||
assert log_has("Running database migration for trades - backup: trades_bak2", caplog)
|
||||
assert trade.open_trade_price == trade._calc_open_trade_price()
|
||||
assert trade.open_trade_value == trade._calc_open_trade_value()
|
||||
assert trade.close_profit_abs is None
|
||||
|
||||
assert log_has("Moving open orders to Orders table.", caplog)
|
||||
@@ -677,7 +677,7 @@ def test_migrate_mid_state(mocker, default_conf, fee, caplog):
|
||||
assert trade.max_rate == 0.0
|
||||
assert trade.stop_loss == 0.0
|
||||
assert trade.initial_stop_loss == 0.0
|
||||
assert trade.open_trade_price == trade._calc_open_trade_price()
|
||||
assert trade.open_trade_value == trade._calc_open_trade_value()
|
||||
assert log_has("trying trades_bak0", caplog)
|
||||
assert log_has("Running database migration for trades - backup: trades_bak0", caplog)
|
||||
|
||||
@@ -803,7 +803,7 @@ def test_to_json(default_conf, fee):
|
||||
'close_timestamp': None,
|
||||
'open_rate': 0.123,
|
||||
'open_rate_requested': None,
|
||||
'open_trade_price': 15.1668225,
|
||||
'open_trade_value': 15.1668225,
|
||||
'fee_close': 0.0025,
|
||||
'fee_close_cost': None,
|
||||
'fee_close_currency': None,
|
||||
@@ -896,7 +896,7 @@ def test_to_json(default_conf, fee):
|
||||
'min_rate': None,
|
||||
'open_order_id': None,
|
||||
'open_rate_requested': None,
|
||||
'open_trade_price': 12.33075,
|
||||
'open_trade_value': 12.33075,
|
||||
'sell_reason': None,
|
||||
'sell_order_status': None,
|
||||
'strategy': None,
|
||||
|
Reference in New Issue
Block a user