Merge branch 'develop' into add-inlier-metric
This commit is contained in:
@@ -1,4 +1,3 @@
|
||||
from math import isclose
|
||||
from pathlib import Path
|
||||
from unittest.mock import MagicMock
|
||||
|
||||
@@ -269,7 +268,7 @@ def test_create_cum_profit(testdatadir):
|
||||
"cum_profits", timeframe="5m")
|
||||
assert "cum_profits" in cum_profits.columns
|
||||
assert cum_profits.iloc[0]['cum_profits'] == 0
|
||||
assert isclose(cum_profits.iloc[-1]['cum_profits'], 8.723007518796964e-06)
|
||||
assert pytest.approx(cum_profits.iloc[-1]['cum_profits']) == 8.723007518796964e-06
|
||||
|
||||
|
||||
def test_create_cum_profit1(testdatadir):
|
||||
@@ -287,7 +286,7 @@ def test_create_cum_profit1(testdatadir):
|
||||
"cum_profits", timeframe="5m")
|
||||
assert "cum_profits" in cum_profits.columns
|
||||
assert cum_profits.iloc[0]['cum_profits'] == 0
|
||||
assert isclose(cum_profits.iloc[-1]['cum_profits'], 8.723007518796964e-06)
|
||||
assert pytest.approx(cum_profits.iloc[-1]['cum_profits']) == 8.723007518796964e-06
|
||||
|
||||
with pytest.raises(ValueError, match='Trade dataframe empty.'):
|
||||
create_cum_profit(df.set_index('date'), bt_data[bt_data["pair"] == 'NOTAPAIR'],
|
||||
|
@@ -2,7 +2,6 @@ import copy
|
||||
import logging
|
||||
from copy import deepcopy
|
||||
from datetime import datetime, timedelta, timezone
|
||||
from math import isclose
|
||||
from random import randint
|
||||
from unittest.mock import MagicMock, Mock, PropertyMock, patch
|
||||
|
||||
@@ -407,10 +406,10 @@ def test__get_stake_amount_limit(mocker, default_conf) -> None:
|
||||
# min
|
||||
result = exchange.get_min_pair_stake_amount('ETH/BTC', 1, stoploss)
|
||||
expected_result = 2 * (1 + 0.05) / (1 - abs(stoploss))
|
||||
assert isclose(result, expected_result)
|
||||
assert pytest.approx(result) == expected_result
|
||||
# With Leverage
|
||||
result = exchange.get_min_pair_stake_amount('ETH/BTC', 1, stoploss, 3.0)
|
||||
assert isclose(result, expected_result / 3)
|
||||
assert pytest.approx(result) == expected_result / 3
|
||||
# max
|
||||
result = exchange.get_max_pair_stake_amount('ETH/BTC', 2)
|
||||
assert result == 10000
|
||||
@@ -426,10 +425,10 @@ def test__get_stake_amount_limit(mocker, default_conf) -> None:
|
||||
)
|
||||
result = exchange.get_min_pair_stake_amount('ETH/BTC', 2, stoploss)
|
||||
expected_result = 2 * 2 * (1 + 0.05) / (1 - abs(stoploss))
|
||||
assert isclose(result, expected_result)
|
||||
assert pytest.approx(result) == expected_result
|
||||
# With Leverage
|
||||
result = exchange.get_min_pair_stake_amount('ETH/BTC', 2, stoploss, 5.0)
|
||||
assert isclose(result, expected_result / 5)
|
||||
assert pytest.approx(result) == expected_result / 5
|
||||
# max
|
||||
result = exchange.get_max_pair_stake_amount('ETH/BTC', 2)
|
||||
assert result == 20000
|
||||
@@ -445,10 +444,10 @@ def test__get_stake_amount_limit(mocker, default_conf) -> None:
|
||||
)
|
||||
result = exchange.get_min_pair_stake_amount('ETH/BTC', 2, stoploss)
|
||||
expected_result = max(2, 2 * 2) * (1 + 0.05) / (1 - abs(stoploss))
|
||||
assert isclose(result, expected_result)
|
||||
assert pytest.approx(result) == expected_result
|
||||
# With Leverage
|
||||
result = exchange.get_min_pair_stake_amount('ETH/BTC', 2, stoploss, 10)
|
||||
assert isclose(result, expected_result / 10)
|
||||
assert pytest.approx(result) == expected_result / 10
|
||||
|
||||
# min amount and cost are set (amount is minial)
|
||||
markets["ETH/BTC"]["limits"] = {
|
||||
@@ -461,20 +460,20 @@ def test__get_stake_amount_limit(mocker, default_conf) -> None:
|
||||
)
|
||||
result = exchange.get_min_pair_stake_amount('ETH/BTC', 2, stoploss)
|
||||
expected_result = max(8, 2 * 2) * (1 + 0.05) / (1 - abs(stoploss))
|
||||
assert isclose(result, expected_result)
|
||||
assert pytest.approx(result) == expected_result
|
||||
# With Leverage
|
||||
result = exchange.get_min_pair_stake_amount('ETH/BTC', 2, stoploss, 7.0)
|
||||
assert isclose(result, expected_result / 7.0)
|
||||
assert pytest.approx(result) == expected_result / 7.0
|
||||
# Max
|
||||
result = exchange.get_max_pair_stake_amount('ETH/BTC', 2)
|
||||
assert result == 1000
|
||||
|
||||
result = exchange.get_min_pair_stake_amount('ETH/BTC', 2, -0.4)
|
||||
expected_result = max(8, 2 * 2) * 1.5
|
||||
assert isclose(result, expected_result)
|
||||
assert pytest.approx(result) == expected_result
|
||||
# With Leverage
|
||||
result = exchange.get_min_pair_stake_amount('ETH/BTC', 2, -0.4, 8.0)
|
||||
assert isclose(result, expected_result / 8.0)
|
||||
assert pytest.approx(result) == expected_result / 8.0
|
||||
# Max
|
||||
result = exchange.get_max_pair_stake_amount('ETH/BTC', 2)
|
||||
assert result == 1000
|
||||
@@ -482,10 +481,10 @@ def test__get_stake_amount_limit(mocker, default_conf) -> None:
|
||||
# Really big stoploss
|
||||
result = exchange.get_min_pair_stake_amount('ETH/BTC', 2, -1)
|
||||
expected_result = max(8, 2 * 2) * 1.5
|
||||
assert isclose(result, expected_result)
|
||||
assert pytest.approx(result) == expected_result
|
||||
# With Leverage
|
||||
result = exchange.get_min_pair_stake_amount('ETH/BTC', 2, -1, 12.0)
|
||||
assert isclose(result, expected_result / 12)
|
||||
assert pytest.approx(result) == expected_result / 12
|
||||
# Max
|
||||
result = exchange.get_max_pair_stake_amount('ETH/BTC', 2)
|
||||
assert result == 1000
|
||||
@@ -501,7 +500,7 @@ def test__get_stake_amount_limit(mocker, default_conf) -> None:
|
||||
|
||||
# Contract size 0.01
|
||||
result = exchange.get_min_pair_stake_amount('ETH/BTC', 2, -1)
|
||||
assert isclose(result, expected_result * 0.01)
|
||||
assert pytest.approx(result) == expected_result * 0.01
|
||||
# Max
|
||||
result = exchange.get_max_pair_stake_amount('ETH/BTC', 2)
|
||||
assert result == 10
|
||||
@@ -513,7 +512,7 @@ def test__get_stake_amount_limit(mocker, default_conf) -> None:
|
||||
)
|
||||
# With Leverage, Contract size 10
|
||||
result = exchange.get_min_pair_stake_amount('ETH/BTC', 2, -1, 12.0)
|
||||
assert isclose(result, (expected_result / 12) * 10.0)
|
||||
assert pytest.approx(result) == (expected_result / 12) * 10.0
|
||||
# Max
|
||||
result = exchange.get_max_pair_stake_amount('ETH/BTC', 2)
|
||||
assert result == 10000
|
||||
@@ -3239,7 +3238,7 @@ def test_get_trades_for_order(default_conf, mocker, exchange_name, trading_mode,
|
||||
orders = exchange.get_trades_for_order(order_id, 'ETH/USDT:USDT', since)
|
||||
assert len(orders) == 1
|
||||
assert orders[0]['price'] == 165
|
||||
assert isclose(orders[0]['amount'], amount)
|
||||
assert pytest.approx(orders[0]['amount']) == amount
|
||||
assert api_mock.fetch_my_trades.call_count == 1
|
||||
# since argument should be
|
||||
assert isinstance(api_mock.fetch_my_trades.call_args[0][1], int)
|
||||
@@ -3776,8 +3775,8 @@ def test__get_funding_fees_from_exchange(default_conf, mocker, exchange_name):
|
||||
since=unix_time
|
||||
)
|
||||
|
||||
assert (isclose(expected_fees, fees_from_datetime))
|
||||
assert (isclose(expected_fees, fees_from_unix_time))
|
||||
assert pytest.approx(expected_fees) == fees_from_datetime
|
||||
assert pytest.approx(expected_fees) == fees_from_unix_time
|
||||
|
||||
ccxt_exceptionhandlers(
|
||||
mocker,
|
||||
@@ -4514,7 +4513,7 @@ def test_liquidation_price(
|
||||
default_conf['liquidation_buffer'] = 0.0
|
||||
exchange = get_patched_exchange(mocker, default_conf, id=exchange_name)
|
||||
exchange.get_maintenance_ratio_and_amt = MagicMock(return_value=(mm_ratio, maintenance_amt))
|
||||
assert isclose(round(exchange.get_liquidation_price(
|
||||
assert pytest.approx(round(exchange.get_liquidation_price(
|
||||
pair='DOGE/USDT',
|
||||
open_rate=open_rate,
|
||||
is_short=is_short,
|
||||
@@ -4523,7 +4522,7 @@ def test_liquidation_price(
|
||||
upnl_ex_1=upnl_ex_1,
|
||||
amount=amount,
|
||||
stake_amount=open_rate * amount,
|
||||
), 2), expected)
|
||||
), 2)) == expected
|
||||
|
||||
|
||||
def test_get_max_pair_stake_amount(
|
||||
@@ -4868,8 +4867,8 @@ def test_get_max_leverage_futures(default_conf, mocker, leverage_tiers):
|
||||
assert exchange.get_max_leverage("BNB/BUSD", 1.0) == 20.0
|
||||
assert exchange.get_max_leverage("BNB/USDT", 100.0) == 75.0
|
||||
assert exchange.get_max_leverage("BTC/USDT", 170.30) == 125.0
|
||||
assert isclose(exchange.get_max_leverage("BNB/BUSD", 99999.9), 5.000005)
|
||||
assert isclose(exchange.get_max_leverage("BNB/USDT", 1500), 33.333333333333333)
|
||||
assert pytest.approx(exchange.get_max_leverage("BNB/BUSD", 99999.9)) == 5.000005
|
||||
assert pytest.approx(exchange.get_max_leverage("BNB/USDT", 1500)) == 33.333333333333333
|
||||
assert exchange.get_max_leverage("BTC/USDT", 300000000) == 2.0
|
||||
assert exchange.get_max_leverage("BTC/USDT", 600000000) == 1.0 # Last tier
|
||||
|
||||
@@ -4986,6 +4985,7 @@ def test_get_liquidation_price1(mocker, default_conf):
|
||||
is_short=False,
|
||||
amount=0.8,
|
||||
stake_amount=18.884 * 0.8,
|
||||
wallet_balance=18.884 * 0.8,
|
||||
)
|
||||
assert liq_price == 17.47
|
||||
|
||||
@@ -4997,6 +4997,7 @@ def test_get_liquidation_price1(mocker, default_conf):
|
||||
is_short=False,
|
||||
amount=0.8,
|
||||
stake_amount=18.884 * 0.8,
|
||||
wallet_balance=18.884 * 0.8,
|
||||
)
|
||||
assert liq_price == 17.540699999999998
|
||||
|
||||
@@ -5008,6 +5009,7 @@ def test_get_liquidation_price1(mocker, default_conf):
|
||||
is_short=False,
|
||||
amount=0.8,
|
||||
stake_amount=18.884 * 0.8,
|
||||
wallet_balance=18.884 * 0.8,
|
||||
)
|
||||
assert liq_price is None
|
||||
default_conf['trading_mode'] = 'margin'
|
||||
@@ -5020,6 +5022,7 @@ def test_get_liquidation_price1(mocker, default_conf):
|
||||
is_short=False,
|
||||
amount=0.8,
|
||||
stake_amount=18.884 * 0.8,
|
||||
wallet_balance=18.884 * 0.8,
|
||||
)
|
||||
|
||||
|
||||
@@ -5145,7 +5148,7 @@ def test_get_liquidation_price(
|
||||
else:
|
||||
buffer_amount = liquidation_buffer * abs(open_rate - expected_liq)
|
||||
expected_liq = expected_liq - buffer_amount if is_short else expected_liq + buffer_amount
|
||||
assert isclose(expected_liq, liq)
|
||||
assert pytest.approx(expected_liq) == liq
|
||||
|
||||
|
||||
@pytest.mark.parametrize('contract_size,order_amount', [
|
||||
|
@@ -45,7 +45,6 @@ def freqai_conf(default_conf, tmpdir):
|
||||
"principal_component_analysis": False,
|
||||
"use_SVM_to_remove_outliers": True,
|
||||
"stratify_training_data": 0,
|
||||
"indicator_max_period_candles": 10,
|
||||
"indicator_periods_candles": [10],
|
||||
},
|
||||
"data_split_parameters": {"test_size": 0.33, "random_state": 1},
|
||||
|
@@ -48,10 +48,4 @@ def test_freqai_backtest_load_data(freqai_conf, mocker, caplog):
|
||||
|
||||
assert log_has_re('Increasing startup_candle_count for freqai to.*', caplog)
|
||||
|
||||
del freqai_conf['freqai']['startup_candles']
|
||||
backtesting = Backtesting(freqai_conf)
|
||||
with pytest.raises(OperationalException,
|
||||
match=r'FreqAI backtesting module.*startup_candles in config.'):
|
||||
backtesting.load_bt_data()
|
||||
|
||||
Backtesting.cleanup()
|
||||
|
@@ -1,5 +1,5 @@
|
||||
import datetime
|
||||
import shutil
|
||||
from datetime import datetime, timedelta, timezone
|
||||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
@@ -57,16 +57,13 @@ def test_split_timerange(
|
||||
shutil.rmtree(Path(dk.full_path))
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"timestamp, expected",
|
||||
[
|
||||
(datetime.datetime.now(tz=datetime.timezone.utc).timestamp() - 7200, True),
|
||||
(datetime.datetime.now(tz=datetime.timezone.utc).timestamp(), False),
|
||||
],
|
||||
)
|
||||
def test_check_if_model_expired(mocker, freqai_conf, timestamp, expected):
|
||||
def test_check_if_model_expired(mocker, freqai_conf):
|
||||
|
||||
dk = get_patched_data_kitchen(mocker, freqai_conf)
|
||||
assert dk.check_if_model_expired(timestamp) == expected
|
||||
now = datetime.now(tz=timezone.utc).timestamp()
|
||||
assert dk.check_if_model_expired(now) is False
|
||||
now = (datetime.now(tz=timezone.utc) - timedelta(hours=2)).timestamp()
|
||||
assert dk.check_if_model_expired(now) is True
|
||||
shutil.rmtree(Path(dk.full_path))
|
||||
|
||||
|
||||
@@ -75,7 +72,7 @@ def test_use_DBSCAN_to_remove_outliers(mocker, freqai_conf, caplog):
|
||||
# freqai_conf['freqai']['feature_parameters'].update({"outlier_protection_percentage": 1})
|
||||
freqai.dk.use_DBSCAN_to_remove_outliers(predict=False)
|
||||
assert log_has_re(
|
||||
"DBSCAN found eps of 2.42.",
|
||||
"DBSCAN found eps of 2.36.",
|
||||
caplog,
|
||||
)
|
||||
|
||||
@@ -84,7 +81,7 @@ def test_compute_distances(mocker, freqai_conf):
|
||||
freqai = make_data_dictionary(mocker, freqai_conf)
|
||||
freqai_conf['freqai']['feature_parameters'].update({"DI_threshold": 1})
|
||||
avg_mean_dist = freqai.dk.compute_distances()
|
||||
assert round(avg_mean_dist, 2) == 2.56
|
||||
assert round(avg_mean_dist, 2) == 2.54
|
||||
|
||||
|
||||
def test_use_SVM_to_remove_outliers_and_outlier_protection(mocker, freqai_conf, caplog):
|
||||
@@ -92,7 +89,7 @@ def test_use_SVM_to_remove_outliers_and_outlier_protection(mocker, freqai_conf,
|
||||
freqai_conf['freqai']['feature_parameters'].update({"outlier_protection_percentage": 0.1})
|
||||
freqai.dk.use_SVM_to_remove_outliers(predict=False)
|
||||
assert log_has_re(
|
||||
"SVM detected 8.46%",
|
||||
"SVM detected 8.09%",
|
||||
caplog,
|
||||
)
|
||||
|
||||
|
@@ -176,6 +176,7 @@ def test_extract_data_and_train_model_LightGBMClassifier(mocker, freqai_conf):
|
||||
|
||||
def test_start_backtesting(mocker, freqai_conf):
|
||||
freqai_conf.update({"timerange": "20180120-20180130"})
|
||||
freqai_conf.get("freqai", {}).update({"save_backtest_models": True})
|
||||
strategy = get_patched_freqai_strategy(mocker, freqai_conf)
|
||||
exchange = get_patched_exchange(mocker, freqai_conf)
|
||||
strategy.dp = DataProvider(freqai_conf, exchange)
|
||||
@@ -194,7 +195,7 @@ def test_start_backtesting(mocker, freqai_conf):
|
||||
freqai.start_backtesting(df, metadata, freqai.dk)
|
||||
model_folders = [x for x in freqai.dd.full_path.iterdir() if x.is_dir()]
|
||||
|
||||
assert len(model_folders) == 5
|
||||
assert len(model_folders) == 6
|
||||
|
||||
shutil.rmtree(Path(freqai.dk.full_path))
|
||||
|
||||
@@ -202,6 +203,7 @@ def test_start_backtesting(mocker, freqai_conf):
|
||||
def test_start_backtesting_subdaily_backtest_period(mocker, freqai_conf):
|
||||
freqai_conf.update({"timerange": "20180120-20180124"})
|
||||
freqai_conf.get("freqai", {}).update({"backtest_period_days": 0.5})
|
||||
freqai_conf.get("freqai", {}).update({"save_backtest_models": True})
|
||||
strategy = get_patched_freqai_strategy(mocker, freqai_conf)
|
||||
exchange = get_patched_exchange(mocker, freqai_conf)
|
||||
strategy.dp = DataProvider(freqai_conf, exchange)
|
||||
@@ -219,13 +221,14 @@ def test_start_backtesting_subdaily_backtest_period(mocker, freqai_conf):
|
||||
metadata = {"pair": "LTC/BTC"}
|
||||
freqai.start_backtesting(df, metadata, freqai.dk)
|
||||
model_folders = [x for x in freqai.dd.full_path.iterdir() if x.is_dir()]
|
||||
assert len(model_folders) == 8
|
||||
assert len(model_folders) == 9
|
||||
|
||||
shutil.rmtree(Path(freqai.dk.full_path))
|
||||
|
||||
|
||||
def test_start_backtesting_from_existing_folder(mocker, freqai_conf, caplog):
|
||||
freqai_conf.update({"timerange": "20180120-20180130"})
|
||||
freqai_conf.get("freqai", {}).update({"save_backtest_models": True})
|
||||
strategy = get_patched_freqai_strategy(mocker, freqai_conf)
|
||||
exchange = get_patched_exchange(mocker, freqai_conf)
|
||||
strategy.dp = DataProvider(freqai_conf, exchange)
|
||||
@@ -244,7 +247,7 @@ def test_start_backtesting_from_existing_folder(mocker, freqai_conf, caplog):
|
||||
freqai.start_backtesting(df, metadata, freqai.dk)
|
||||
model_folders = [x for x in freqai.dd.full_path.iterdir() if x.is_dir()]
|
||||
|
||||
assert len(model_folders) == 5
|
||||
assert len(model_folders) == 6
|
||||
|
||||
# without deleting the exiting folder structure, re-run
|
||||
|
||||
@@ -265,10 +268,14 @@ def test_start_backtesting_from_existing_folder(mocker, freqai_conf, caplog):
|
||||
freqai.start_backtesting(df, metadata, freqai.dk)
|
||||
|
||||
assert log_has_re(
|
||||
"Found model at ",
|
||||
"Found backtesting prediction file ",
|
||||
caplog,
|
||||
)
|
||||
|
||||
path = (freqai.dd.full_path / freqai.dk.backtest_predictions_folder)
|
||||
prediction_files = [x for x in path.iterdir() if x.is_file()]
|
||||
assert len(prediction_files) == 5
|
||||
|
||||
shutil.rmtree(Path(freqai.dk.full_path))
|
||||
|
||||
|
||||
|
@@ -1,5 +1,3 @@
|
||||
from math import isclose
|
||||
|
||||
import pytest
|
||||
|
||||
from freqtrade.leverage import interest
|
||||
@@ -30,9 +28,9 @@ twentyfive_hours = FtPrecise(25.0)
|
||||
def test_interest(exchange, interest_rate, hours, expected):
|
||||
borrowed = FtPrecise(60.0)
|
||||
|
||||
assert isclose(interest(
|
||||
assert pytest.approx(float(interest(
|
||||
exchange_name=exchange,
|
||||
borrowed=borrowed,
|
||||
rate=FtPrecise(interest_rate),
|
||||
hours=hours
|
||||
), expected)
|
||||
))) == expected
|
||||
|
@@ -37,6 +37,7 @@ def generate_mock_trade(pair: str, fee: float, is_open: bool,
|
||||
trade.orders.append(Order(
|
||||
ft_order_side=trade.entry_side,
|
||||
order_id=f'{pair}-{trade.entry_side}-{trade.open_date}',
|
||||
ft_is_open=False,
|
||||
ft_pair=pair,
|
||||
amount=trade.amount,
|
||||
filled=trade.amount,
|
||||
@@ -51,6 +52,7 @@ def generate_mock_trade(pair: str, fee: float, is_open: bool,
|
||||
trade.orders.append(Order(
|
||||
ft_order_side=trade.exit_side,
|
||||
order_id=f'{pair}-{trade.exit_side}-{trade.close_date}',
|
||||
ft_is_open=False,
|
||||
ft_pair=pair,
|
||||
amount=trade.amount,
|
||||
filled=trade.amount,
|
||||
|
@@ -2138,11 +2138,11 @@ def test_send_msg_strategy_msg_notification(default_conf, mocker) -> None:
|
||||
|
||||
|
||||
def test_send_msg_unknown_type(default_conf, mocker) -> None:
|
||||
telegram, _, _ = get_telegram_testobject(mocker, default_conf)
|
||||
with pytest.raises(NotImplementedError, match=r'Unknown message type: None'):
|
||||
telegram.send_msg({
|
||||
'type': None,
|
||||
})
|
||||
telegram, _, msg_mock = get_telegram_testobject(mocker, default_conf)
|
||||
telegram.send_msg({
|
||||
'type': None,
|
||||
})
|
||||
msg_mock.call_count == 0
|
||||
|
||||
|
||||
@pytest.mark.parametrize('message_type,enter,enter_signal,leverage', [
|
||||
|
@@ -1,5 +1,3 @@
|
||||
from math import isclose
|
||||
|
||||
import numpy as np
|
||||
import pandas as pd
|
||||
import pytest
|
||||
@@ -165,7 +163,7 @@ def test_stoploss_from_open():
|
||||
or (side == 'short' and expected_stop_price < current_price)):
|
||||
assert stoploss == 0
|
||||
else:
|
||||
assert isclose(stop_price, expected_stop_price, rel_tol=0.00001)
|
||||
assert pytest.approx(stop_price) == expected_stop_price
|
||||
|
||||
|
||||
def test_stoploss_from_absolute():
|
||||
|
@@ -1051,8 +1051,6 @@ def test_add_stoploss_on_exchange(mocker, default_conf_usdt, limit_order, is_sho
|
||||
mocker.patch('freqtrade.freqtradebot.FreqtradeBot.handle_trade', MagicMock(return_value=True))
|
||||
mocker.patch('freqtrade.exchange.Exchange.fetch_order', return_value=order)
|
||||
mocker.patch('freqtrade.exchange.Exchange.get_trades_for_order', return_value=[])
|
||||
mocker.patch('freqtrade.freqtradebot.FreqtradeBot.get_real_amount',
|
||||
return_value=order['amount'])
|
||||
|
||||
stoploss = MagicMock(return_value={'id': 13434334})
|
||||
mocker.patch('freqtrade.exchange.Binance.stoploss', stoploss)
|
||||
@@ -1875,8 +1873,6 @@ def test_exit_positions(mocker, default_conf_usdt, limit_order, is_short, caplog
|
||||
mocker.patch('freqtrade.exchange.Exchange.fetch_order',
|
||||
return_value=limit_order[entry_side(is_short)])
|
||||
mocker.patch('freqtrade.exchange.Exchange.get_trades_for_order', return_value=[])
|
||||
mocker.patch('freqtrade.freqtradebot.FreqtradeBot.get_real_amount',
|
||||
return_value=limit_order[entry_side(is_short)]['amount'])
|
||||
|
||||
trade = MagicMock()
|
||||
trade.is_short = is_short
|
||||
@@ -1886,14 +1882,13 @@ def test_exit_positions(mocker, default_conf_usdt, limit_order, is_short, caplog
|
||||
n = freqtrade.exit_positions(trades)
|
||||
assert n == 0
|
||||
# Test amount not modified by fee-logic
|
||||
assert not log_has(
|
||||
'Applying fee to amount for Trade {} from 30.0 to 90.81'.format(trade), caplog
|
||||
)
|
||||
assert not log_has_re(r'Applying fee to amount for Trade .*', caplog)
|
||||
|
||||
mocker.patch('freqtrade.freqtradebot.FreqtradeBot.get_real_amount', return_value=90.81)
|
||||
gra = mocker.patch('freqtrade.freqtradebot.FreqtradeBot.get_real_amount', return_value=0.0)
|
||||
# test amount modified by fee-logic
|
||||
n = freqtrade.exit_positions(trades)
|
||||
assert n == 0
|
||||
assert gra.call_count == 0
|
||||
|
||||
|
||||
@pytest.mark.parametrize("is_short", [False, True])
|
||||
@@ -1927,8 +1922,7 @@ def test_update_trade_state(mocker, default_conf_usdt, limit_order, is_short, ca
|
||||
mocker.patch('freqtrade.freqtradebot.FreqtradeBot.handle_trade', MagicMock(return_value=True))
|
||||
mocker.patch('freqtrade.exchange.Exchange.fetch_order', return_value=order)
|
||||
mocker.patch('freqtrade.exchange.Exchange.get_trades_for_order', return_value=[])
|
||||
mocker.patch('freqtrade.freqtradebot.FreqtradeBot.get_real_amount',
|
||||
return_value=order['amount'])
|
||||
mocker.patch('freqtrade.freqtradebot.FreqtradeBot.get_real_amount', return_value=0.0)
|
||||
order_id = order['id']
|
||||
|
||||
trade = Trade(
|
||||
@@ -1960,11 +1954,11 @@ def test_update_trade_state(mocker, default_conf_usdt, limit_order, is_short, ca
|
||||
assert trade.amount == order['amount']
|
||||
|
||||
trade.open_order_id = order_id
|
||||
mocker.patch('freqtrade.freqtradebot.FreqtradeBot.get_real_amount', return_value=90.81)
|
||||
assert trade.amount != 90.81
|
||||
mocker.patch('freqtrade.freqtradebot.FreqtradeBot.get_real_amount', return_value=0.01)
|
||||
assert trade.amount == 30.0
|
||||
# test amount modified by fee-logic
|
||||
freqtrade.update_trade_state(trade, order_id)
|
||||
assert trade.amount == 90.81
|
||||
assert trade.amount == 29.99
|
||||
assert trade.open_order_id is None
|
||||
|
||||
trade.is_open = True
|
||||
@@ -4268,10 +4262,10 @@ def test_get_real_amount_quote(default_conf_usdt, trades_for_order, buy_order_fe
|
||||
caplog.clear()
|
||||
order_obj = Order.parse_from_ccxt_object(buy_order_fee, 'LTC/ETH', 'buy')
|
||||
# Amount is reduced by "fee"
|
||||
assert freqtrade.get_real_amount(trade, buy_order_fee, order_obj) == amount - (amount * 0.001)
|
||||
assert freqtrade.get_real_amount(trade, buy_order_fee, order_obj) == (amount * 0.001)
|
||||
assert log_has(
|
||||
'Applying fee on amount for Trade(id=None, pair=LTC/ETH, amount=8.00000000, is_short=False,'
|
||||
' leverage=1.0, open_rate=0.24544100, open_since=closed) (from 8.0 to 7.992).',
|
||||
' leverage=1.0, open_rate=0.24544100, open_since=closed), fee=0.008.',
|
||||
caplog
|
||||
)
|
||||
|
||||
@@ -4296,7 +4290,7 @@ def test_get_real_amount_quote_dust(default_conf_usdt, trades_for_order, buy_ord
|
||||
walletmock.reset_mock()
|
||||
order_obj = Order.parse_from_ccxt_object(buy_order_fee, 'LTC/ETH', 'buy')
|
||||
# Amount is kept as is
|
||||
assert freqtrade.get_real_amount(trade, buy_order_fee, order_obj) == amount
|
||||
assert freqtrade.get_real_amount(trade, buy_order_fee, order_obj) is None
|
||||
assert walletmock.call_count == 1
|
||||
assert log_has_re(r'Fee amount for Trade.* was in base currency '
|
||||
'- Eating Fee 0.008 into dust', caplog)
|
||||
@@ -4319,7 +4313,7 @@ def test_get_real_amount_no_trade(default_conf_usdt, buy_order_fee, caplog, mock
|
||||
|
||||
order_obj = Order.parse_from_ccxt_object(buy_order_fee, 'LTC/ETH', 'buy')
|
||||
# Amount is reduced by "fee"
|
||||
assert freqtrade.get_real_amount(trade, buy_order_fee, order_obj) == amount
|
||||
assert freqtrade.get_real_amount(trade, buy_order_fee, order_obj) is None
|
||||
assert log_has(
|
||||
'Applying fee on amount for Trade(id=None, pair=LTC/ETH, amount=8.00000000, '
|
||||
'is_short=False, leverage=1.0, open_rate=0.24544100, open_since=closed) failed: '
|
||||
@@ -4343,8 +4337,7 @@ def test_get_real_amount_no_trade(default_conf_usdt, buy_order_fee, caplog, mock
|
||||
# from order
|
||||
({'cost': 0.004, 'currency': 'LTC'}, 0.004, False, (
|
||||
'Applying fee on amount for Trade(id=None, pair=LTC/ETH, amount=8.00000000, '
|
||||
'is_short=False, leverage=1.0, open_rate=0.24544100, open_since=closed) (from'
|
||||
' 8.0 to 7.996).'
|
||||
'is_short=False, leverage=1.0, open_rate=0.24544100, open_since=closed), fee=0.004.'
|
||||
)),
|
||||
# invalid, no currency in from fee dict
|
||||
({'cost': 0.008, 'currency': None}, 0, True, None),
|
||||
@@ -4376,7 +4369,11 @@ def test_get_real_amount(
|
||||
|
||||
caplog.clear()
|
||||
order_obj = Order.parse_from_ccxt_object(buy_order_fee, 'LTC/ETH', 'buy')
|
||||
assert freqtrade.get_real_amount(trade, buy_order, order_obj) == amount - fee_reduction_amount
|
||||
res = freqtrade.get_real_amount(trade, buy_order, order_obj)
|
||||
if fee_reduction_amount == 0:
|
||||
assert res is None
|
||||
else:
|
||||
assert res == fee_reduction_amount
|
||||
|
||||
if expected_log:
|
||||
assert log_has(expected_log, caplog)
|
||||
@@ -4422,14 +4419,14 @@ def test_get_real_amount_multi(
|
||||
return_value={'ask': 0.19, 'last': 0.2})
|
||||
|
||||
# Amount is reduced by "fee"
|
||||
expected_amount = amount - (amount * fee_reduction_amount)
|
||||
expected_amount = amount * fee_reduction_amount
|
||||
order_obj = Order.parse_from_ccxt_object(buy_order_fee, 'LTC/ETH', 'buy')
|
||||
assert freqtrade.get_real_amount(trade, buy_order_fee, order_obj) == expected_amount
|
||||
assert log_has(
|
||||
(
|
||||
'Applying fee on amount for Trade(id=None, pair=LTC/ETH, amount=8.00000000, '
|
||||
'is_short=False, leverage=1.0, open_rate=0.24544100, open_since=closed) '
|
||||
f'(from 8.0 to {expected_log_amount}).'
|
||||
'is_short=False, leverage=1.0, open_rate=0.24544100, open_since=closed), '
|
||||
f'fee={expected_amount}.'
|
||||
),
|
||||
caplog
|
||||
)
|
||||
@@ -4462,7 +4459,7 @@ def test_get_real_amount_invalid_order(default_conf_usdt, trades_for_order, buy_
|
||||
|
||||
order_obj = Order.parse_from_ccxt_object(buy_order_fee, 'LTC/ETH', 'buy')
|
||||
# Amount does not change
|
||||
assert freqtrade.get_real_amount(trade, limit_buy_order_usdt, order_obj) == amount
|
||||
assert freqtrade.get_real_amount(trade, limit_buy_order_usdt, order_obj) is None
|
||||
|
||||
|
||||
def test_get_real_amount_fees_order(default_conf_usdt, market_buy_order_usdt_doublefee,
|
||||
@@ -4485,7 +4482,7 @@ def test_get_real_amount_fees_order(default_conf_usdt, market_buy_order_usdt_dou
|
||||
# Amount does not change
|
||||
assert trade.fee_open == 0.0025
|
||||
order_obj = Order.parse_from_ccxt_object(market_buy_order_usdt_doublefee, 'LTC/ETH', 'buy')
|
||||
assert freqtrade.get_real_amount(trade, market_buy_order_usdt_doublefee, order_obj) == 30.0
|
||||
assert freqtrade.get_real_amount(trade, market_buy_order_usdt_doublefee, order_obj) is None
|
||||
assert tfo_mock.call_count == 0
|
||||
# Fetch fees from trades dict if available to get "proper" values
|
||||
assert round(trade.fee_open, 4) == 0.001
|
||||
@@ -4537,7 +4534,7 @@ def test_get_real_amount_wrong_amount_rounding(default_conf_usdt, trades_for_ord
|
||||
order_obj = Order.parse_from_ccxt_object(buy_order_fee, 'LTC/ETH', 'buy')
|
||||
# Amount changes by fee amount.
|
||||
assert pytest.approx(freqtrade.get_real_amount(
|
||||
trade, limit_buy_order_usdt, order_obj)) == amount - (amount * 0.001)
|
||||
trade, limit_buy_order_usdt, order_obj)) == (amount * 0.001)
|
||||
|
||||
|
||||
def test_get_real_amount_open_trade_usdt(default_conf_usdt, fee, mocker):
|
||||
@@ -4559,7 +4556,7 @@ def test_get_real_amount_open_trade_usdt(default_conf_usdt, fee, mocker):
|
||||
}
|
||||
freqtrade = get_patched_freqtradebot(mocker, default_conf_usdt)
|
||||
order_obj = Order.parse_from_ccxt_object(order, 'LTC/ETH', 'buy')
|
||||
assert freqtrade.get_real_amount(trade, order, order_obj) == amount
|
||||
assert freqtrade.get_real_amount(trade, order, order_obj) is None
|
||||
|
||||
|
||||
def test_get_real_amount_in_point(default_conf_usdt, buy_order_fee, fee, mocker, caplog):
|
||||
@@ -4616,7 +4613,7 @@ def test_get_real_amount_in_point(default_conf_usdt, buy_order_fee, fee, mocker,
|
||||
|
||||
order_obj = Order.parse_from_ccxt_object(buy_order_fee, 'LTC/ETH', 'buy')
|
||||
res = freqtrade.get_real_amount(trade, limit_buy_order_usdt, order_obj)
|
||||
assert res == amount
|
||||
assert res is None
|
||||
assert trade.fee_open_currency is None
|
||||
assert trade.fee_open_cost is None
|
||||
message = "Not updating buy-fee - rate: None, POINT."
|
||||
@@ -4624,7 +4621,7 @@ def test_get_real_amount_in_point(default_conf_usdt, buy_order_fee, fee, mocker,
|
||||
caplog.clear()
|
||||
freqtrade.config['exchange']['unknown_fee_rate'] = 1
|
||||
res = freqtrade.get_real_amount(trade, limit_buy_order_usdt, order_obj)
|
||||
assert res == amount
|
||||
assert res is None
|
||||
assert trade.fee_open_currency == 'POINT'
|
||||
assert pytest.approx(trade.fee_open_cost) == 0.3046651026
|
||||
assert trade.fee_open == 0.002
|
||||
@@ -4633,12 +4630,12 @@ def test_get_real_amount_in_point(default_conf_usdt, buy_order_fee, fee, mocker,
|
||||
|
||||
|
||||
@pytest.mark.parametrize('amount,fee_abs,wallet,amount_exp', [
|
||||
(8.0, 0.0, 10, 8),
|
||||
(8.0, 0.0, 0, 8),
|
||||
(8.0, 0.1, 0, 7.9),
|
||||
(8.0, 0.1, 10, 8),
|
||||
(8.0, 0.1, 8.0, 8.0),
|
||||
(8.0, 0.1, 7.9, 7.9),
|
||||
(8.0, 0.0, 10, None),
|
||||
(8.0, 0.0, 0, None),
|
||||
(8.0, 0.1, 0, 0.1),
|
||||
(8.0, 0.1, 10, None),
|
||||
(8.0, 0.1, 8.0, None),
|
||||
(8.0, 0.1, 7.9, 0.1),
|
||||
])
|
||||
def test_apply_fee_conditional(default_conf_usdt, fee, mocker,
|
||||
amount, fee_abs, wallet, amount_exp):
|
||||
@@ -4653,11 +4650,17 @@ def test_apply_fee_conditional(default_conf_usdt, fee, mocker,
|
||||
fee_close=fee.return_value,
|
||||
open_order_id="123456"
|
||||
)
|
||||
order = Order(
|
||||
ft_order_side='buy',
|
||||
order_id='100',
|
||||
ft_pair=trade.pair,
|
||||
ft_is_open=True,
|
||||
)
|
||||
freqtrade = get_patched_freqtradebot(mocker, default_conf_usdt)
|
||||
|
||||
walletmock.reset_mock()
|
||||
# Amount is kept as is
|
||||
assert freqtrade.apply_fee_conditional(trade, 'LTC', amount, fee_abs) == amount_exp
|
||||
assert freqtrade.apply_fee_conditional(trade, 'LTC', amount, fee_abs, order) == amount_exp
|
||||
assert walletmock.call_count == 1
|
||||
|
||||
|
||||
|
@@ -1,7 +1,6 @@
|
||||
# pragma pylint: disable=missing-docstring, C0103
|
||||
import logging
|
||||
from datetime import datetime, timedelta, timezone
|
||||
from math import isclose
|
||||
from pathlib import Path
|
||||
from types import FunctionType
|
||||
from unittest.mock import MagicMock
|
||||
@@ -582,25 +581,25 @@ def test_update_market_order(market_buy_order_usdt, market_sell_order_usdt, fee,
|
||||
@pytest.mark.parametrize(
|
||||
'exchange,is_short,lev,open_value,close_value,profit,profit_ratio,trading_mode,funding_fees', [
|
||||
("binance", False, 1, 60.15, 65.835, 5.685, 0.09451371, spot, 0.0),
|
||||
("binance", True, 1, 59.850, 66.1663784375, -6.3163784375, -0.1055368, margin, 0.0),
|
||||
("binance", True, 1, 65.835, 60.151253125, 5.68374687, 0.08633321, margin, 0.0),
|
||||
("binance", False, 3, 60.15, 65.83416667, 5.68416667, 0.28349958, margin, 0.0),
|
||||
("binance", True, 3, 59.85, 66.1663784375, -6.3163784375, -0.31661044, margin, 0.0),
|
||||
("binance", True, 3, 65.835, 60.151253125, 5.68374687, 0.25899963, margin, 0.0),
|
||||
|
||||
("kraken", False, 1, 60.15, 65.835, 5.685, 0.09451371, spot, 0.0),
|
||||
("kraken", True, 1, 59.850, 66.231165, -6.381165, -0.1066192, margin, 0.0),
|
||||
("kraken", True, 1, 65.835, 60.21015, 5.62485, 0.0854386, margin, 0.0),
|
||||
("kraken", False, 3, 60.15, 65.795, 5.645, 0.28154613, margin, 0.0),
|
||||
("kraken", True, 3, 59.850, 66.231165, -6.381165, -0.3198578, margin, 0.0),
|
||||
("kraken", True, 3, 65.835, 60.21015, 5.62485, 0.25631579, margin, 0.0),
|
||||
|
||||
("binance", False, 1, 60.15, 65.835, 5.685, 0.09451371, futures, 0.0),
|
||||
("binance", False, 1, 60.15, 66.835, 6.685, 0.11113881, futures, 1.0),
|
||||
("binance", True, 1, 59.85, 66.165, -6.315, -0.10551378, futures, 0.0),
|
||||
("binance", True, 1, 59.85, 67.165, -7.315, -0.12222222, futures, -1.0),
|
||||
("binance", True, 1, 65.835, 60.15, 5.685, 0.08635224, futures, 0.0),
|
||||
("binance", True, 1, 65.835, 61.15, 4.685, 0.07116276, futures, -1.0),
|
||||
("binance", True, 3, 65.835, 59.15, 6.685, 0.3046252, futures, 1.0),
|
||||
("binance", False, 3, 60.15, 64.835, 4.685, 0.23366583, futures, -1.0),
|
||||
("binance", True, 3, 59.85, 65.165, -5.315, -0.26641604, futures, 1.0),
|
||||
])
|
||||
@pytest.mark.usefixtures("init_persistence")
|
||||
def test_calc_open_close_trade_price(
|
||||
limit_buy_order_usdt, limit_sell_order_usdt, fee, exchange, is_short, lev,
|
||||
limit_order, fee, exchange, is_short, lev,
|
||||
open_value, close_value, profit, profit_ratio, trading_mode, funding_fees
|
||||
):
|
||||
trade: Trade = Trade(
|
||||
@@ -616,24 +615,30 @@ def test_calc_open_close_trade_price(
|
||||
is_short=is_short,
|
||||
leverage=lev,
|
||||
trading_mode=trading_mode,
|
||||
funding_fees=funding_fees
|
||||
)
|
||||
|
||||
entry_order = limit_order[trade.entry_side]
|
||||
exit_order = limit_order[trade.exit_side]
|
||||
trade.open_order_id = f'something-{is_short}-{lev}-{exchange}'
|
||||
|
||||
oobj = Order.parse_from_ccxt_object(limit_buy_order_usdt, 'ADA/USDT', 'buy')
|
||||
oobj = Order.parse_from_ccxt_object(entry_order, 'ADA/USDT', trade.entry_side)
|
||||
oobj.trade = trade
|
||||
oobj.update_from_ccxt_object(entry_order)
|
||||
trade.update_trade(oobj)
|
||||
|
||||
oobj = Order.parse_from_ccxt_object(limit_sell_order_usdt, 'ADA/USDT', 'sell')
|
||||
trade.funding_fees = funding_fees
|
||||
|
||||
oobj = Order.parse_from_ccxt_object(exit_order, 'ADA/USDT', trade.exit_side)
|
||||
oobj.trade = trade
|
||||
oobj.update_from_ccxt_object(exit_order)
|
||||
trade.update_trade(oobj)
|
||||
|
||||
trade.open_rate = 2.0
|
||||
trade.close_rate = 2.2
|
||||
trade.recalc_open_trade_value()
|
||||
assert isclose(trade._calc_open_trade_value(trade.amount, trade.open_rate), open_value)
|
||||
assert isclose(trade.calc_close_trade_value(trade.close_rate), close_value)
|
||||
assert isclose(trade.calc_profit(trade.close_rate), round(profit, 8))
|
||||
assert pytest.approx(trade.calc_profit_ratio(trade.close_rate)) == profit_ratio
|
||||
assert trade.is_open is False
|
||||
assert trade.funding_fees == funding_fees
|
||||
|
||||
assert pytest.approx(trade._calc_open_trade_value(trade.amount, trade.open_rate)) == open_value
|
||||
assert pytest.approx(trade.calc_close_trade_value(trade.close_rate)) == close_value
|
||||
assert pytest.approx(trade.close_profit_abs) == profit
|
||||
assert pytest.approx(trade.close_profit) == profit_ratio
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("init_persistence")
|
||||
@@ -655,6 +660,7 @@ def test_trade_close(fee):
|
||||
trade.orders.append(Order(
|
||||
ft_order_side=trade.entry_side,
|
||||
order_id=f'{trade.pair}-{trade.entry_side}-{trade.open_date}',
|
||||
ft_is_open=False,
|
||||
ft_pair=trade.pair,
|
||||
amount=trade.amount,
|
||||
filled=trade.amount,
|
||||
@@ -668,6 +674,7 @@ def test_trade_close(fee):
|
||||
trade.orders.append(Order(
|
||||
ft_order_side=trade.exit_side,
|
||||
order_id=f'{trade.pair}-{trade.exit_side}-{trade.open_date}',
|
||||
ft_is_open=False,
|
||||
ft_pair=trade.pair,
|
||||
amount=trade.amount,
|
||||
filled=trade.amount,
|
||||
|
Reference in New Issue
Block a user