Merge branch 'develop' into feat/externalsignals
This commit is contained in:
@@ -11,8 +11,9 @@ import pytest
|
||||
from pandas import DataFrame
|
||||
|
||||
from freqtrade.enums import CandleType, MarginMode, TradingMode
|
||||
from freqtrade.exceptions import (DDosProtection, DependencyException, InvalidOrderException,
|
||||
OperationalException, PricingError, TemporaryError)
|
||||
from freqtrade.exceptions import (DDosProtection, DependencyException, ExchangeError,
|
||||
InvalidOrderException, OperationalException, PricingError,
|
||||
TemporaryError)
|
||||
from freqtrade.exchange import (Binance, Bittrex, Exchange, Kraken, amount_to_precision,
|
||||
date_minus_candles, market_is_active, price_to_precision,
|
||||
timeframe_to_minutes, timeframe_to_msecs, timeframe_to_next_date,
|
||||
@@ -4179,17 +4180,24 @@ def test__fetch_and_calculate_funding_fees(
|
||||
type(api_mock).has = PropertyMock(return_value={'fetchOHLCV': True})
|
||||
type(api_mock).has = PropertyMock(return_value={'fetchFundingRateHistory': True})
|
||||
|
||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, id=exchange)
|
||||
ex = get_patched_exchange(mocker, default_conf, api_mock, id=exchange)
|
||||
mocker.patch('freqtrade.exchange.Exchange.timeframes', PropertyMock(
|
||||
return_value=['1h', '4h', '8h']))
|
||||
funding_fees = exchange._fetch_and_calculate_funding_fees(
|
||||
funding_fees = ex._fetch_and_calculate_funding_fees(
|
||||
pair='ADA/USDT', amount=amount, is_short=True, open_date=d1, close_date=d2)
|
||||
assert pytest.approx(funding_fees) == expected_fees
|
||||
# Fees for Longs are inverted
|
||||
funding_fees = exchange._fetch_and_calculate_funding_fees(
|
||||
funding_fees = ex._fetch_and_calculate_funding_fees(
|
||||
pair='ADA/USDT', amount=amount, is_short=False, open_date=d1, close_date=d2)
|
||||
assert pytest.approx(funding_fees) == -expected_fees
|
||||
|
||||
# Return empty "refresh_latest"
|
||||
mocker.patch("freqtrade.exchange.Exchange.refresh_latest_ohlcv", return_value={})
|
||||
ex = get_patched_exchange(mocker, default_conf, api_mock, id=exchange)
|
||||
with pytest.raises(ExchangeError, match="Could not find funding rates."):
|
||||
ex._fetch_and_calculate_funding_fees(
|
||||
pair='ADA/USDT', amount=amount, is_short=False, open_date=d1, close_date=d2)
|
||||
|
||||
|
||||
@pytest.mark.parametrize('exchange,expected_fees', [
|
||||
('binance', -0.0009140999999999999),
|
||||
@@ -4456,6 +4464,39 @@ def test__amount_to_contracts(
|
||||
assert result_amount == param_amount
|
||||
|
||||
|
||||
@pytest.mark.parametrize('pair,amount,expected_spot,expected_fut', [
|
||||
# Contract size of 0.01
|
||||
('ADA/USDT:USDT', 40, 40, 40),
|
||||
('ADA/USDT:USDT', 10.4445555, 10.4, 10.444),
|
||||
('LTC/ETH', 30, 30, 30),
|
||||
('LTC/USD', 30, 30, 30),
|
||||
# contract size of 10
|
||||
('ETH/USDT:USDT', 10.111, 10.1, 10),
|
||||
('ETH/USDT:USDT', 10.188, 10.1, 10),
|
||||
('ETH/USDT:USDT', 10.988, 10.9, 10),
|
||||
])
|
||||
def test_amount_to_contract_precision(
|
||||
mocker,
|
||||
default_conf,
|
||||
pair,
|
||||
amount,
|
||||
expected_spot,
|
||||
expected_fut,
|
||||
):
|
||||
api_mock = MagicMock()
|
||||
default_conf['trading_mode'] = 'spot'
|
||||
default_conf['margin_mode'] = 'isolated'
|
||||
exchange = get_patched_exchange(mocker, default_conf, api_mock)
|
||||
|
||||
result_size = exchange.amount_to_contract_precision(pair, amount)
|
||||
assert result_size == expected_spot
|
||||
|
||||
default_conf['trading_mode'] = 'futures'
|
||||
exchange = get_patched_exchange(mocker, default_conf, api_mock)
|
||||
result_size = exchange.amount_to_contract_precision(pair, amount)
|
||||
assert result_size == expected_fut
|
||||
|
||||
|
||||
@pytest.mark.parametrize('exchange_name,open_rate,is_short,trading_mode,margin_mode', [
|
||||
# Bittrex
|
||||
('bittrex', 2.0, False, 'spot', None),
|
||||
|
@@ -81,6 +81,37 @@ def get_patched_freqaimodel(mocker, freqaiconf):
|
||||
return freqaimodel
|
||||
|
||||
|
||||
def make_unfiltered_dataframe(mocker, freqai_conf):
|
||||
freqai_conf.update({"timerange": "20180110-20180130"})
|
||||
|
||||
strategy = get_patched_freqai_strategy(mocker, freqai_conf)
|
||||
exchange = get_patched_exchange(mocker, freqai_conf)
|
||||
strategy.dp = DataProvider(freqai_conf, exchange)
|
||||
strategy.freqai_info = freqai_conf.get("freqai", {})
|
||||
freqai = strategy.freqai
|
||||
freqai.live = True
|
||||
freqai.dk = FreqaiDataKitchen(freqai_conf)
|
||||
freqai.dk.pair = "ADA/BTC"
|
||||
data_load_timerange = TimeRange.parse_timerange("20180110-20180130")
|
||||
freqai.dd.load_all_pair_histories(data_load_timerange, freqai.dk)
|
||||
|
||||
freqai.dd.pair_dict = MagicMock()
|
||||
|
||||
new_timerange = TimeRange.parse_timerange("20180120-20180130")
|
||||
|
||||
corr_dataframes, base_dataframes = freqai.dd.get_base_and_corr_dataframes(
|
||||
data_load_timerange, freqai.dk.pair, freqai.dk
|
||||
)
|
||||
|
||||
unfiltered_dataframe = freqai.dk.use_strategy_to_populate_indicators(
|
||||
strategy, corr_dataframes, base_dataframes, freqai.dk.pair
|
||||
)
|
||||
|
||||
unfiltered_dataframe = freqai.dk.slice_dataframe(new_timerange, unfiltered_dataframe)
|
||||
|
||||
return freqai, unfiltered_dataframe
|
||||
|
||||
|
||||
def make_data_dictionary(mocker, freqai_conf):
|
||||
freqai_conf.update({"timerange": "20180110-20180130"})
|
||||
|
||||
@@ -92,12 +123,11 @@ def make_data_dictionary(mocker, freqai_conf):
|
||||
freqai.live = True
|
||||
freqai.dk = FreqaiDataKitchen(freqai_conf)
|
||||
freqai.dk.pair = "ADA/BTC"
|
||||
timerange = TimeRange.parse_timerange("20180110-20180130")
|
||||
freqai.dd.load_all_pair_histories(timerange, freqai.dk)
|
||||
data_load_timerange = TimeRange.parse_timerange("20180110-20180130")
|
||||
freqai.dd.load_all_pair_histories(data_load_timerange, freqai.dk)
|
||||
|
||||
freqai.dd.pair_dict = MagicMock()
|
||||
|
||||
data_load_timerange = TimeRange.parse_timerange("20180110-20180130")
|
||||
new_timerange = TimeRange.parse_timerange("20180120-20180130")
|
||||
|
||||
corr_dataframes, base_dataframes = freqai.dd.get_base_and_corr_dataframes(
|
||||
|
@@ -6,7 +6,8 @@ import pytest
|
||||
|
||||
from freqtrade.exceptions import OperationalException
|
||||
from tests.conftest import log_has_re
|
||||
from tests.freqai.conftest import get_patched_data_kitchen, make_data_dictionary
|
||||
from tests.freqai.conftest import (get_patched_data_kitchen, make_data_dictionary,
|
||||
make_unfiltered_dataframe)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
@@ -91,3 +92,72 @@ def test_use_SVM_to_remove_outliers_and_outlier_protection(mocker, freqai_conf,
|
||||
"SVM detected 8.09%",
|
||||
caplog,
|
||||
)
|
||||
|
||||
|
||||
def test_compute_inlier_metric(mocker, freqai_conf, caplog):
|
||||
freqai = make_data_dictionary(mocker, freqai_conf)
|
||||
freqai_conf['freqai']['feature_parameters'].update({"inlier_metric_window": 10})
|
||||
freqai.dk.compute_inlier_metric(set_='train')
|
||||
assert log_has_re(
|
||||
"Inlier metric computed and added to features.",
|
||||
caplog,
|
||||
)
|
||||
|
||||
|
||||
def test_add_noise_to_training_features(mocker, freqai_conf):
|
||||
freqai = make_data_dictionary(mocker, freqai_conf)
|
||||
freqai_conf['freqai']['feature_parameters'].update({"noise_standard_deviation": 0.1})
|
||||
freqai.dk.add_noise_to_training_features()
|
||||
|
||||
|
||||
def test_remove_beginning_points_from_data_dict(mocker, freqai_conf):
|
||||
freqai = make_data_dictionary(mocker, freqai_conf)
|
||||
freqai.dk.remove_beginning_points_from_data_dict(set_='train')
|
||||
|
||||
|
||||
def test_principal_component_analysis(mocker, freqai_conf, caplog):
|
||||
freqai = make_data_dictionary(mocker, freqai_conf)
|
||||
freqai.dk.principal_component_analysis()
|
||||
assert log_has_re(
|
||||
"reduced feature dimension by",
|
||||
caplog,
|
||||
)
|
||||
|
||||
|
||||
def test_normalize_data(mocker, freqai_conf):
|
||||
freqai = make_data_dictionary(mocker, freqai_conf)
|
||||
data_dict = freqai.dk.data_dictionary
|
||||
freqai.dk.normalize_data(data_dict)
|
||||
assert len(freqai.dk.data) == 56
|
||||
|
||||
|
||||
def test_filter_features(mocker, freqai_conf):
|
||||
freqai, unfiltered_dataframe = make_unfiltered_dataframe(mocker, freqai_conf)
|
||||
freqai.dk.find_features(unfiltered_dataframe)
|
||||
|
||||
filtered_df, labels = freqai.dk.filter_features(
|
||||
unfiltered_dataframe,
|
||||
freqai.dk.training_features_list,
|
||||
freqai.dk.label_list,
|
||||
training_filter=True,
|
||||
)
|
||||
|
||||
assert len(filtered_df.columns) == 26
|
||||
|
||||
|
||||
def test_make_train_test_datasets(mocker, freqai_conf):
|
||||
freqai, unfiltered_dataframe = make_unfiltered_dataframe(mocker, freqai_conf)
|
||||
freqai.dk.find_features(unfiltered_dataframe)
|
||||
|
||||
features_filtered, labels_filtered = freqai.dk.filter_features(
|
||||
unfiltered_dataframe,
|
||||
freqai.dk.training_features_list,
|
||||
freqai.dk.label_list,
|
||||
training_filter=True,
|
||||
)
|
||||
|
||||
data_dictionary = freqai.dk.make_train_test_datasets(features_filtered, labels_filtered)
|
||||
|
||||
assert data_dictionary
|
||||
assert len(data_dictionary) == 7
|
||||
assert len(data_dictionary['train_features'].index) == 1916
|
||||
|
@@ -17,7 +17,7 @@ def is_arm() -> bool:
|
||||
return "arm" in machine or "aarch64" in machine
|
||||
|
||||
|
||||
def test_train_model_in_series_LightGBM(mocker, freqai_conf):
|
||||
def test_extract_data_and_train_model_LightGBM(mocker, freqai_conf):
|
||||
freqai_conf.update({"timerange": "20180110-20180130"})
|
||||
|
||||
strategy = get_patched_freqai_strategy(mocker, freqai_conf)
|
||||
@@ -35,7 +35,8 @@ def test_train_model_in_series_LightGBM(mocker, freqai_conf):
|
||||
data_load_timerange = TimeRange.parse_timerange("20180110-20180130")
|
||||
new_timerange = TimeRange.parse_timerange("20180120-20180130")
|
||||
|
||||
freqai.train_model_in_series(new_timerange, "ADA/BTC", strategy, freqai.dk, data_load_timerange)
|
||||
freqai.extract_data_and_train_model(
|
||||
new_timerange, "ADA/BTC", strategy, freqai.dk, data_load_timerange)
|
||||
|
||||
assert Path(freqai.dk.data_path / f"{freqai.dk.model_filename}_model.joblib").is_file()
|
||||
assert Path(freqai.dk.data_path / f"{freqai.dk.model_filename}_metadata.json").is_file()
|
||||
@@ -45,7 +46,7 @@ def test_train_model_in_series_LightGBM(mocker, freqai_conf):
|
||||
shutil.rmtree(Path(freqai.dk.full_path))
|
||||
|
||||
|
||||
def test_train_model_in_series_LightGBMMultiModel(mocker, freqai_conf):
|
||||
def test_extract_data_and_train_model_LightGBMMultiModel(mocker, freqai_conf):
|
||||
freqai_conf.update({"timerange": "20180110-20180130"})
|
||||
freqai_conf.update({"strategy": "freqai_test_multimodel_strat"})
|
||||
freqai_conf.update({"freqaimodel": "LightGBMRegressorMultiTarget"})
|
||||
@@ -64,7 +65,8 @@ def test_train_model_in_series_LightGBMMultiModel(mocker, freqai_conf):
|
||||
data_load_timerange = TimeRange.parse_timerange("20180110-20180130")
|
||||
new_timerange = TimeRange.parse_timerange("20180120-20180130")
|
||||
|
||||
freqai.train_model_in_series(new_timerange, "ADA/BTC", strategy, freqai.dk, data_load_timerange)
|
||||
freqai.extract_data_and_train_model(
|
||||
new_timerange, "ADA/BTC", strategy, freqai.dk, data_load_timerange)
|
||||
|
||||
assert len(freqai.dk.label_list) == 2
|
||||
assert Path(freqai.dk.data_path / f"{freqai.dk.model_filename}_model.joblib").is_file()
|
||||
@@ -77,7 +79,7 @@ def test_train_model_in_series_LightGBMMultiModel(mocker, freqai_conf):
|
||||
|
||||
|
||||
@pytest.mark.skipif(is_arm(), reason="no ARM for Catboost ...")
|
||||
def test_train_model_in_series_Catboost(mocker, freqai_conf):
|
||||
def test_extract_data_and_train_model_Catboost(mocker, freqai_conf):
|
||||
freqai_conf.update({"timerange": "20180110-20180130"})
|
||||
freqai_conf.update({"freqaimodel": "CatboostRegressor"})
|
||||
# freqai_conf.get('freqai', {}).update(
|
||||
@@ -98,8 +100,8 @@ def test_train_model_in_series_Catboost(mocker, freqai_conf):
|
||||
data_load_timerange = TimeRange.parse_timerange("20180110-20180130")
|
||||
new_timerange = TimeRange.parse_timerange("20180120-20180130")
|
||||
|
||||
freqai.train_model_in_series(new_timerange, "ADA/BTC",
|
||||
strategy, freqai.dk, data_load_timerange)
|
||||
freqai.extract_data_and_train_model(new_timerange, "ADA/BTC",
|
||||
strategy, freqai.dk, data_load_timerange)
|
||||
|
||||
assert Path(freqai.dk.data_path / f"{freqai.dk.model_filename}_model.joblib").exists()
|
||||
assert Path(freqai.dk.data_path / f"{freqai.dk.model_filename}_metadata.json").exists()
|
||||
@@ -110,7 +112,7 @@ def test_train_model_in_series_Catboost(mocker, freqai_conf):
|
||||
|
||||
|
||||
@pytest.mark.skipif(is_arm(), reason="no ARM for Catboost ...")
|
||||
def test_train_model_in_series_CatboostClassifier(mocker, freqai_conf):
|
||||
def test_extract_data_and_train_model_CatboostClassifier(mocker, freqai_conf):
|
||||
freqai_conf.update({"timerange": "20180110-20180130"})
|
||||
freqai_conf.update({"freqaimodel": "CatboostClassifier"})
|
||||
freqai_conf.update({"strategy": "freqai_test_classifier"})
|
||||
@@ -130,8 +132,8 @@ def test_train_model_in_series_CatboostClassifier(mocker, freqai_conf):
|
||||
data_load_timerange = TimeRange.parse_timerange("20180110-20180130")
|
||||
new_timerange = TimeRange.parse_timerange("20180120-20180130")
|
||||
|
||||
freqai.train_model_in_series(new_timerange, "ADA/BTC",
|
||||
strategy, freqai.dk, data_load_timerange)
|
||||
freqai.extract_data_and_train_model(new_timerange, "ADA/BTC",
|
||||
strategy, freqai.dk, data_load_timerange)
|
||||
|
||||
assert Path(freqai.dk.data_path / f"{freqai.dk.model_filename}_model.joblib").exists()
|
||||
assert Path(freqai.dk.data_path / f"{freqai.dk.model_filename}_metadata.json").exists()
|
||||
@@ -141,7 +143,7 @@ def test_train_model_in_series_CatboostClassifier(mocker, freqai_conf):
|
||||
shutil.rmtree(Path(freqai.dk.full_path))
|
||||
|
||||
|
||||
def test_train_model_in_series_LightGBMClassifier(mocker, freqai_conf):
|
||||
def test_extract_data_and_train_model_LightGBMClassifier(mocker, freqai_conf):
|
||||
freqai_conf.update({"timerange": "20180110-20180130"})
|
||||
freqai_conf.update({"freqaimodel": "LightGBMClassifier"})
|
||||
freqai_conf.update({"strategy": "freqai_test_classifier"})
|
||||
@@ -161,8 +163,8 @@ def test_train_model_in_series_LightGBMClassifier(mocker, freqai_conf):
|
||||
data_load_timerange = TimeRange.parse_timerange("20180110-20180130")
|
||||
new_timerange = TimeRange.parse_timerange("20180120-20180130")
|
||||
|
||||
freqai.train_model_in_series(new_timerange, "ADA/BTC",
|
||||
strategy, freqai.dk, data_load_timerange)
|
||||
freqai.extract_data_and_train_model(new_timerange, "ADA/BTC",
|
||||
strategy, freqai.dk, data_load_timerange)
|
||||
|
||||
assert Path(freqai.dk.data_path / f"{freqai.dk.model_filename}_model.joblib").exists()
|
||||
assert Path(freqai.dk.data_path / f"{freqai.dk.model_filename}_metadata.json").exists()
|
||||
@@ -296,7 +298,8 @@ def test_follow_mode(mocker, freqai_conf):
|
||||
data_load_timerange = TimeRange.parse_timerange("20180110-20180130")
|
||||
new_timerange = TimeRange.parse_timerange("20180120-20180130")
|
||||
|
||||
freqai.train_model_in_series(new_timerange, "ADA/BTC", strategy, freqai.dk, data_load_timerange)
|
||||
freqai.extract_data_and_train_model(
|
||||
new_timerange, "ADA/BTC", strategy, freqai.dk, data_load_timerange)
|
||||
|
||||
assert Path(freqai.dk.data_path / f"{freqai.dk.model_filename}_model.joblib").is_file()
|
||||
assert Path(freqai.dk.data_path / f"{freqai.dk.model_filename}_metadata.json").is_file()
|
||||
@@ -345,7 +348,8 @@ def test_principal_component_analysis(mocker, freqai_conf):
|
||||
data_load_timerange = TimeRange.parse_timerange("20180110-20180130")
|
||||
new_timerange = TimeRange.parse_timerange("20180120-20180130")
|
||||
|
||||
freqai.train_model_in_series(new_timerange, "ADA/BTC", strategy, freqai.dk, data_load_timerange)
|
||||
freqai.extract_data_and_train_model(
|
||||
new_timerange, "ADA/BTC", strategy, freqai.dk, data_load_timerange)
|
||||
|
||||
assert Path(freqai.dk.data_path / f"{freqai.dk.model_filename}_pca_object.pkl")
|
||||
|
||||
|
@@ -117,6 +117,29 @@ def test_merge_informative_pair_lower():
|
||||
merge_informative_pair(data, informative, '1h', '15m', ffill=True)
|
||||
|
||||
|
||||
def test_merge_informative_pair_suffix():
|
||||
data = generate_test_data('15m', 20)
|
||||
informative = generate_test_data('1h', 20)
|
||||
|
||||
result = merge_informative_pair(data, informative, '15m', '1h',
|
||||
append_timeframe=False, suffix="suf")
|
||||
|
||||
assert 'date' in result.columns
|
||||
assert result['date'].equals(data['date'])
|
||||
assert 'date_suf' in result.columns
|
||||
|
||||
assert 'open_suf' in result.columns
|
||||
assert 'open_1h' not in result.columns
|
||||
|
||||
|
||||
def test_merge_informative_pair_suffix_append_timeframe():
|
||||
data = generate_test_data('15m', 20)
|
||||
informative = generate_test_data('1h', 20)
|
||||
|
||||
with pytest.raises(ValueError, match=r"You can not specify `append_timeframe` .*"):
|
||||
merge_informative_pair(data, informative, '15m', '1h', suffix="suf")
|
||||
|
||||
|
||||
def test_stoploss_from_open():
|
||||
open_price_ranges = [
|
||||
[0.01, 1.00, 30],
|
||||
|
@@ -506,7 +506,7 @@ def test_create_trades_multiple_trades(
|
||||
|
||||
|
||||
def test_create_trades_preopen(default_conf_usdt, ticker_usdt, fee, mocker,
|
||||
limit_buy_order_usdt_open) -> None:
|
||||
limit_buy_order_usdt_open, caplog) -> None:
|
||||
patch_RPCManager(mocker)
|
||||
patch_exchange(mocker)
|
||||
default_conf_usdt['max_open_trades'] = 4
|
||||
@@ -515,6 +515,7 @@ def test_create_trades_preopen(default_conf_usdt, ticker_usdt, fee, mocker,
|
||||
fetch_ticker=ticker_usdt,
|
||||
create_order=MagicMock(return_value=limit_buy_order_usdt_open),
|
||||
get_fee=fee,
|
||||
get_funding_fees=MagicMock(side_effect=ExchangeError()),
|
||||
)
|
||||
freqtrade = FreqtradeBot(default_conf_usdt)
|
||||
patch_get_signal(freqtrade)
|
||||
@@ -522,6 +523,7 @@ def test_create_trades_preopen(default_conf_usdt, ticker_usdt, fee, mocker,
|
||||
# Create 2 existing trades
|
||||
freqtrade.execute_entry('ETH/USDT', default_conf_usdt['stake_amount'])
|
||||
freqtrade.execute_entry('NEO/BTC', default_conf_usdt['stake_amount'])
|
||||
assert log_has("Could not find funding fee.", caplog)
|
||||
|
||||
assert len(Trade.get_open_trades()) == 2
|
||||
# Change order_id for new orders
|
||||
@@ -3653,10 +3655,11 @@ def test_may_execute_trade_exit_after_stoploss_on_exchange_hit(
|
||||
assert trade.stoploss_order_id is None
|
||||
assert trade.is_open is False
|
||||
assert trade.exit_reason == ExitType.STOPLOSS_ON_EXCHANGE.value
|
||||
assert rpc_mock.call_count == 4
|
||||
assert rpc_mock.call_args_list[1][0][0]['type'] == RPCMessageType.ENTRY
|
||||
assert rpc_mock.call_args_list[2][0][0]['type'] == RPCMessageType.ENTRY_FILL
|
||||
assert rpc_mock.call_args_list[3][0][0]['type'] == RPCMessageType.EXIT_FILL
|
||||
assert rpc_mock.call_count == 3
|
||||
assert rpc_mock.call_args_list[0][0][0]['type'] == RPCMessageType.ENTRY
|
||||
assert rpc_mock.call_args_list[0][0][0]['amount'] > 20
|
||||
assert rpc_mock.call_args_list[1][0][0]['type'] == RPCMessageType.ENTRY_FILL
|
||||
assert rpc_mock.call_args_list[2][0][0]['type'] == RPCMessageType.EXIT_FILL
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
@@ -3665,7 +3668,7 @@ def test_may_execute_trade_exit_after_stoploss_on_exchange_hit(
|
||||
(True, 29.70297029, 2.2, 2.3, -8.63762376, -0.1443212, 'loss'),
|
||||
])
|
||||
def test_execute_trade_exit_market_order(
|
||||
default_conf_usdt, ticker_usdt, fee, is_short, current_rate, amount,
|
||||
default_conf_usdt, ticker_usdt, fee, is_short, current_rate, amount, caplog,
|
||||
limit, profit_amount, profit_ratio, profit_or_loss, ticker_usdt_sell_up, mocker
|
||||
) -> None:
|
||||
"""
|
||||
@@ -3693,6 +3696,7 @@ def test_execute_trade_exit_market_order(
|
||||
fetch_ticker=ticker_usdt,
|
||||
get_fee=fee,
|
||||
_is_dry_limit_order_filled=MagicMock(return_value=True),
|
||||
get_funding_fees=MagicMock(side_effect=ExchangeError()),
|
||||
)
|
||||
patch_whitelist(mocker, default_conf_usdt)
|
||||
freqtrade = FreqtradeBot(default_conf_usdt)
|
||||
@@ -3718,6 +3722,7 @@ def test_execute_trade_exit_market_order(
|
||||
limit=ticker_usdt_sell_up()['ask' if is_short else 'bid'],
|
||||
exit_check=ExitCheckTuple(exit_type=ExitType.ROI)
|
||||
)
|
||||
assert log_has("Could not update funding fee.", caplog)
|
||||
|
||||
assert not trade.is_open
|
||||
assert pytest.approx(trade.close_profit) == profit_ratio
|
||||
@@ -5429,6 +5434,16 @@ def test_update_funding_fees(
|
||||
))
|
||||
|
||||
|
||||
def test_update_funding_fees_error(mocker, default_conf, caplog):
|
||||
mocker.patch('freqtrade.exchange.Exchange.get_funding_fees', side_effect=ExchangeError())
|
||||
default_conf['trading_mode'] = 'futures'
|
||||
default_conf['margin_mode'] = 'isolated'
|
||||
freqtrade = get_patched_freqtradebot(mocker, default_conf)
|
||||
freqtrade.update_funding_fees()
|
||||
|
||||
log_has("Could not update funding fees for open trades.", caplog)
|
||||
|
||||
|
||||
def test_position_adjust(mocker, default_conf_usdt, fee) -> None:
|
||||
patch_RPCManager(mocker)
|
||||
patch_exchange(mocker)
|
||||
|
@@ -485,7 +485,7 @@ def test_dca_exiting(default_conf_usdt, ticker_usdt, fee, mocker, caplog) -> Non
|
||||
assert len(trade.orders) == 1
|
||||
assert pytest.approx(trade.stake_amount) == 60
|
||||
assert pytest.approx(trade.amount) == 30.0
|
||||
assert log_has_re("Remaining amount of 1.6.* would be too small.", caplog)
|
||||
assert log_has_re("Remaining amount of 1.6.* would be smaller than the minimum of 10.", caplog)
|
||||
|
||||
freqtrade.strategy.adjust_trade_position = MagicMock(return_value=-20)
|
||||
|
||||
@@ -504,9 +504,21 @@ def test_dca_exiting(default_conf_usdt, ticker_usdt, fee, mocker, caplog) -> Non
|
||||
freqtrade.strategy.adjust_trade_position = MagicMock(return_value=-50)
|
||||
freqtrade.process()
|
||||
assert log_has_re("Adjusting amount to trade.amount as it is higher.*", caplog)
|
||||
assert log_has_re("Remaining amount of 0.0 would be too small.", caplog)
|
||||
assert log_has_re("Remaining amount of 0.0 would be smaller than the minimum of 10.", caplog)
|
||||
trade = Trade.get_trades().first()
|
||||
assert len(trade.orders) == 2
|
||||
assert trade.orders[-1].ft_order_side == 'sell'
|
||||
assert pytest.approx(trade.stake_amount) == 40.198
|
||||
assert trade.is_open
|
||||
|
||||
# use amount that would trunc to 0.0 once selling
|
||||
mocker.patch("freqtrade.exchange.Exchange.amount_to_contract_precision",
|
||||
lambda s, p, v: round(v, 1))
|
||||
freqtrade.strategy.adjust_trade_position = MagicMock(return_value=-0.01)
|
||||
freqtrade.process()
|
||||
trade = Trade.get_trades().first()
|
||||
assert len(trade.orders) == 2
|
||||
assert trade.orders[-1].ft_order_side == 'sell'
|
||||
assert pytest.approx(trade.stake_amount) == 40.198
|
||||
assert trade.is_open
|
||||
assert log_has_re('Amount to sell is 0.0 due to exchange limits - not selling.', caplog)
|
||||
|
Reference in New Issue
Block a user