Merge branch 'develop' into pairlocks_direction
This commit is contained in:
@@ -859,8 +859,8 @@ def test_start_list_strategies(capsys):
|
||||
# pargs['config'] = None
|
||||
start_list_strategies(pargs)
|
||||
captured = capsys.readouterr()
|
||||
assert "TestStrategyLegacyV1" in captured.out
|
||||
assert "legacy_strategy_v1.py" not in captured.out
|
||||
assert "StrategyTestV2" in captured.out
|
||||
assert "strategy_test_v2.py" not in captured.out
|
||||
assert CURRENT_TEST_STRATEGY in captured.out
|
||||
|
||||
# Test regular output
|
||||
@@ -874,8 +874,8 @@ def test_start_list_strategies(capsys):
|
||||
# pargs['config'] = None
|
||||
start_list_strategies(pargs)
|
||||
captured = capsys.readouterr()
|
||||
assert "TestStrategyLegacyV1" in captured.out
|
||||
assert "legacy_strategy_v1.py" in captured.out
|
||||
assert "StrategyTestV2" in captured.out
|
||||
assert "strategy_test_v2.py" in captured.out
|
||||
assert CURRENT_TEST_STRATEGY in captured.out
|
||||
|
||||
# Test color output
|
||||
@@ -888,8 +888,8 @@ def test_start_list_strategies(capsys):
|
||||
# pargs['config'] = None
|
||||
start_list_strategies(pargs)
|
||||
captured = capsys.readouterr()
|
||||
assert "TestStrategyLegacyV1" in captured.out
|
||||
assert "legacy_strategy_v1.py" in captured.out
|
||||
assert "StrategyTestV2" in captured.out
|
||||
assert "strategy_test_v2.py" in captured.out
|
||||
assert CURRENT_TEST_STRATEGY in captured.out
|
||||
assert "LOAD FAILED" in captured.out
|
||||
# Recursive
|
||||
@@ -907,8 +907,8 @@ def test_start_list_strategies(capsys):
|
||||
# pargs['config'] = None
|
||||
start_list_strategies(pargs)
|
||||
captured = capsys.readouterr()
|
||||
assert "TestStrategyLegacyV1" in captured.out
|
||||
assert "legacy_strategy_v1.py" in captured.out
|
||||
assert "StrategyTestV2" in captured.out
|
||||
assert "strategy_test_v2.py" in captured.out
|
||||
assert "StrategyTestV2" in captured.out
|
||||
assert "TestStrategyNoImplements" in captured.out
|
||||
assert str(Path("broken_strats/broken_futures_strategies.py")) in captured.out
|
||||
|
@@ -8,14 +8,14 @@ from pandas import DataFrame, DateOffset, Timestamp, to_datetime
|
||||
|
||||
from freqtrade.configuration import TimeRange
|
||||
from freqtrade.constants import LAST_BT_RESULT_FN
|
||||
from freqtrade.data.btanalysis import (BT_DATA_COLUMNS, analyze_trade_parallelism, calculate_csum,
|
||||
calculate_market_change, calculate_max_drawdown,
|
||||
calculate_underwater, combine_dataframes_with_mean,
|
||||
create_cum_profit, extract_trades_of_period,
|
||||
get_latest_backtest_filename, get_latest_hyperopt_file,
|
||||
load_backtest_data, load_backtest_metadata, load_trades,
|
||||
load_trades_from_db)
|
||||
from freqtrade.data.btanalysis import (BT_DATA_COLUMNS, analyze_trade_parallelism,
|
||||
extract_trades_of_period, get_latest_backtest_filename,
|
||||
get_latest_hyperopt_file, load_backtest_data,
|
||||
load_backtest_metadata, load_trades, load_trades_from_db)
|
||||
from freqtrade.data.history import load_data, load_pair_history
|
||||
from freqtrade.data.metrics import (calculate_cagr, calculate_csum, calculate_market_change,
|
||||
calculate_max_drawdown, calculate_underwater,
|
||||
combine_dataframes_with_mean, create_cum_profit)
|
||||
from freqtrade.exceptions import OperationalException
|
||||
from tests.conftest import CURRENT_TEST_STRATEGY, create_mock_trades
|
||||
from tests.conftest_trades import MOCK_TRADE_COUNT
|
||||
@@ -336,6 +336,19 @@ def test_calculate_csum(testdatadir):
|
||||
csum_min, csum_max = calculate_csum(DataFrame())
|
||||
|
||||
|
||||
@pytest.mark.parametrize('start,end,days, expected', [
|
||||
(64900, 176000, 3 * 365, 0.3945),
|
||||
(64900, 176000, 365, 1.7119),
|
||||
(1000, 1000, 365, 0.0),
|
||||
(1000, 1500, 365, 0.5),
|
||||
(1000, 1500, 100, 3.3927), # sub year
|
||||
(0.01000000, 0.01762792, 120, 4.6087), # sub year BTC values
|
||||
])
|
||||
def test_calculate_cagr(start, end, days, expected):
|
||||
|
||||
assert round(calculate_cagr(days, start, end), 4) == expected
|
||||
|
||||
|
||||
def test_calculate_max_drawdown2():
|
||||
values = [0.011580, 0.010048, 0.011340, 0.012161, 0.010416, 0.010009, 0.020024,
|
||||
-0.024662, -0.022350, 0.020496, -0.029859, -0.030511, 0.010041, 0.010872,
|
||||
|
@@ -909,7 +909,7 @@ def test_validate_timeframes_emulated_ohlcv_1(default_conf, mocker):
|
||||
mocker.patch('freqtrade.exchange.Exchange.validate_stakecurrency')
|
||||
with pytest.raises(OperationalException,
|
||||
match=r'The ccxt library does not provide the list of timeframes '
|
||||
r'for the exchange ".*" and this exchange '
|
||||
r'for the exchange .* and this exchange '
|
||||
r'is therefore not supported. *'):
|
||||
Exchange(default_conf)
|
||||
|
||||
@@ -930,7 +930,7 @@ def test_validate_timeframes_emulated_ohlcvi_2(default_conf, mocker):
|
||||
mocker.patch('freqtrade.exchange.Exchange.validate_stakecurrency')
|
||||
with pytest.raises(OperationalException,
|
||||
match=r'The ccxt library does not provide the list of timeframes '
|
||||
r'for the exchange ".*" and this exchange '
|
||||
r'for the exchange .* and this exchange '
|
||||
r'is therefore not supported. *'):
|
||||
Exchange(default_conf)
|
||||
|
||||
|
@@ -22,7 +22,7 @@ from freqtrade.data.history import get_timerange
|
||||
from freqtrade.enums import ExitType, RunMode
|
||||
from freqtrade.exceptions import DependencyException, OperationalException
|
||||
from freqtrade.exchange.exchange import timeframe_to_next_date
|
||||
from freqtrade.misc import get_strategy_run_id
|
||||
from freqtrade.optimize.backtest_caching import get_strategy_run_id
|
||||
from freqtrade.optimize.backtesting import Backtesting
|
||||
from freqtrade.persistence import LocalTrade
|
||||
from freqtrade.resolvers import StrategyResolver
|
||||
@@ -312,6 +312,7 @@ def test_backtesting_init(mocker, default_conf, order_types) -> None:
|
||||
get_fee.assert_called()
|
||||
assert backtesting.fee == 0.5
|
||||
assert not backtesting.strategy.order_types["stoploss_on_exchange"]
|
||||
assert backtesting.strategy.bot_started is True
|
||||
|
||||
|
||||
def test_backtesting_init_no_timeframe(mocker, default_conf, caplog) -> None:
|
||||
@@ -500,7 +501,7 @@ def test_backtesting_pairlist_list(default_conf, mocker, caplog, testdatadir, ti
|
||||
Backtesting(default_conf)
|
||||
|
||||
# Multiple strategies
|
||||
default_conf['strategy_list'] = [CURRENT_TEST_STRATEGY, 'TestStrategyLegacyV1']
|
||||
default_conf['strategy_list'] = [CURRENT_TEST_STRATEGY, 'StrategyTestV2']
|
||||
with pytest.raises(OperationalException,
|
||||
match='PrecisionFilter not allowed for backtesting multiple strategies.'):
|
||||
Backtesting(default_conf)
|
||||
@@ -1198,7 +1199,7 @@ def test_backtest_start_multi_strat(default_conf, mocker, caplog, testdatadir):
|
||||
'--disable-max-market-positions',
|
||||
'--strategy-list',
|
||||
CURRENT_TEST_STRATEGY,
|
||||
'TestStrategyLegacyV1',
|
||||
'StrategyTestV2',
|
||||
]
|
||||
args = get_args(args)
|
||||
start_backtesting(args)
|
||||
@@ -1221,14 +1222,13 @@ def test_backtest_start_multi_strat(default_conf, mocker, caplog, testdatadir):
|
||||
'up to 2017-11-14 22:58:00 (0 days).',
|
||||
'Parameter --enable-position-stacking detected ...',
|
||||
f'Running backtesting for Strategy {CURRENT_TEST_STRATEGY}',
|
||||
'Running backtesting for Strategy TestStrategyLegacyV1',
|
||||
'Running backtesting for Strategy StrategyTestV2',
|
||||
]
|
||||
|
||||
for line in exists:
|
||||
assert log_has(line, caplog)
|
||||
|
||||
|
||||
@pytest.mark.filterwarnings("ignore:deprecated")
|
||||
def test_backtest_start_multi_strat_nomock(default_conf, mocker, caplog, testdatadir, capsys):
|
||||
default_conf.update({
|
||||
"use_exit_signal": True,
|
||||
@@ -1310,7 +1310,7 @@ def test_backtest_start_multi_strat_nomock(default_conf, mocker, caplog, testdat
|
||||
'--breakdown', 'day',
|
||||
'--strategy-list',
|
||||
CURRENT_TEST_STRATEGY,
|
||||
'TestStrategyLegacyV1',
|
||||
'StrategyTestV2',
|
||||
]
|
||||
args = get_args(args)
|
||||
start_backtesting(args)
|
||||
@@ -1327,7 +1327,7 @@ def test_backtest_start_multi_strat_nomock(default_conf, mocker, caplog, testdat
|
||||
'up to 2017-11-14 22:58:00 (0 days).',
|
||||
'Parameter --enable-position-stacking detected ...',
|
||||
f'Running backtesting for Strategy {CURRENT_TEST_STRATEGY}',
|
||||
'Running backtesting for Strategy TestStrategyLegacyV1',
|
||||
'Running backtesting for Strategy StrategyTestV2',
|
||||
]
|
||||
|
||||
for line in exists:
|
||||
@@ -1342,6 +1342,39 @@ def test_backtest_start_multi_strat_nomock(default_conf, mocker, caplog, testdat
|
||||
assert 'STRATEGY SUMMARY' in captured.out
|
||||
|
||||
|
||||
@pytest.mark.filterwarnings("ignore:deprecated")
|
||||
def test_backtest_start_futures_noliq(default_conf_usdt, mocker,
|
||||
caplog, testdatadir, capsys):
|
||||
# Tests detail-data loading
|
||||
default_conf_usdt.update({
|
||||
"trading_mode": "futures",
|
||||
"margin_mode": "isolated",
|
||||
"use_exit_signal": True,
|
||||
"exit_profit_only": False,
|
||||
"exit_profit_offset": 0.0,
|
||||
"ignore_roi_if_entry_signal": False,
|
||||
"strategy": CURRENT_TEST_STRATEGY,
|
||||
})
|
||||
patch_exchange(mocker)
|
||||
|
||||
mocker.patch('freqtrade.plugins.pairlistmanager.PairListManager.whitelist',
|
||||
PropertyMock(return_value=['HULUMULU/USDT', 'XRP/USDT']))
|
||||
# mocker.patch('freqtrade.optimize.backtesting.Backtesting.backtest', backtestmock)
|
||||
|
||||
patched_configuration_load_config_file(mocker, default_conf_usdt)
|
||||
|
||||
args = [
|
||||
'backtesting',
|
||||
'--config', 'config.json',
|
||||
'--datadir', str(testdatadir),
|
||||
'--strategy-path', str(Path(__file__).parents[1] / 'strategy/strats'),
|
||||
'--timeframe', '1h',
|
||||
]
|
||||
args = get_args(args)
|
||||
with pytest.raises(OperationalException, match=r"Pairs .* got no leverage tiers available\."):
|
||||
start_backtesting(args)
|
||||
|
||||
|
||||
@pytest.mark.filterwarnings("ignore:deprecated")
|
||||
def test_backtest_start_nomock_futures(default_conf_usdt, mocker,
|
||||
caplog, testdatadir, capsys):
|
||||
@@ -1592,7 +1625,7 @@ def test_backtest_start_multi_strat_caching(default_conf, mocker, caplog, testda
|
||||
min_backtest_date = now - timedelta(weeks=4)
|
||||
load_backtest_metadata = MagicMock(return_value={
|
||||
'StrategyTestV2': {'run_id': '1', 'backtest_start_time': now.timestamp()},
|
||||
'TestStrategyLegacyV1': {'run_id': run_id, 'backtest_start_time': start_time.timestamp()}
|
||||
'StrategyTestV3': {'run_id': run_id, 'backtest_start_time': start_time.timestamp()}
|
||||
})
|
||||
load_backtest_stats = MagicMock(side_effect=[
|
||||
{
|
||||
@@ -1601,9 +1634,9 @@ def test_backtest_start_multi_strat_caching(default_conf, mocker, caplog, testda
|
||||
'strategy_comparison': [{'key': 'StrategyTestV2'}]
|
||||
},
|
||||
{
|
||||
'metadata': {'TestStrategyLegacyV1': {'run_id': '2'}},
|
||||
'strategy': {'TestStrategyLegacyV1': {}},
|
||||
'strategy_comparison': [{'key': 'TestStrategyLegacyV1'}]
|
||||
'metadata': {'StrategyTestV3': {'run_id': '2'}},
|
||||
'strategy': {'StrategyTestV3': {}},
|
||||
'strategy_comparison': [{'key': 'StrategyTestV3'}]
|
||||
}
|
||||
])
|
||||
mocker.patch('pathlib.Path.glob', return_value=[
|
||||
@@ -1627,7 +1660,7 @@ def test_backtest_start_multi_strat_caching(default_conf, mocker, caplog, testda
|
||||
'--cache', cache,
|
||||
'--strategy-list',
|
||||
'StrategyTestV2',
|
||||
'TestStrategyLegacyV1',
|
||||
'StrategyTestV3',
|
||||
]
|
||||
args = get_args(args)
|
||||
start_backtesting(args)
|
||||
@@ -1649,7 +1682,7 @@ def test_backtest_start_multi_strat_caching(default_conf, mocker, caplog, testda
|
||||
assert backtestmock.call_count == 2
|
||||
exists = [
|
||||
'Running backtesting for Strategy StrategyTestV2',
|
||||
'Running backtesting for Strategy TestStrategyLegacyV1',
|
||||
'Running backtesting for Strategy StrategyTestV3',
|
||||
'Ignoring max_open_trades (--disable-max-market-positions was used) ...',
|
||||
'Backtesting with data from 2017-11-14 21:17:00 up to 2017-11-14 22:58:00 (0 days).',
|
||||
]
|
||||
@@ -1657,12 +1690,12 @@ def test_backtest_start_multi_strat_caching(default_conf, mocker, caplog, testda
|
||||
assert backtestmock.call_count == 0
|
||||
exists = [
|
||||
'Reusing result of previous backtest for StrategyTestV2',
|
||||
'Reusing result of previous backtest for TestStrategyLegacyV1',
|
||||
'Reusing result of previous backtest for StrategyTestV3',
|
||||
]
|
||||
else:
|
||||
exists = [
|
||||
'Reusing result of previous backtest for StrategyTestV2',
|
||||
'Running backtesting for Strategy TestStrategyLegacyV1',
|
||||
'Running backtesting for Strategy StrategyTestV3',
|
||||
'Ignoring max_open_trades (--disable-max-market-positions was used) ...',
|
||||
'Backtesting with data from 2017-11-14 21:17:00 up to 2017-11-14 22:58:00 (0 days).',
|
||||
]
|
||||
|
@@ -94,6 +94,7 @@ def test_edge_init(mocker, edge_conf) -> None:
|
||||
assert edge_cli.config == edge_conf
|
||||
assert edge_cli.config['stake_amount'] == 'unlimited'
|
||||
assert callable(edge_cli.edge.calculate)
|
||||
assert edge_cli.strategy.bot_started is True
|
||||
|
||||
|
||||
def test_edge_init_fee(mocker, edge_conf) -> None:
|
||||
|
@@ -4,7 +4,7 @@ from unittest.mock import MagicMock
|
||||
import pytest
|
||||
|
||||
from freqtrade.exceptions import OperationalException
|
||||
from freqtrade.optimize.hyperopt_loss_short_trade_dur import ShortTradeDurHyperOptLoss
|
||||
from freqtrade.optimize.hyperopt_loss.hyperopt_loss_short_trade_dur import ShortTradeDurHyperOptLoss
|
||||
from freqtrade.resolvers.hyperopt_resolver import HyperOptLossResolver
|
||||
|
||||
|
||||
|
@@ -13,7 +13,6 @@ import uvicorn
|
||||
from fastapi import FastAPI
|
||||
from fastapi.exceptions import HTTPException
|
||||
from fastapi.testclient import TestClient
|
||||
from numpy import isnan
|
||||
from requests.auth import _basic_auth_str
|
||||
|
||||
from freqtrade.__init__ import __version__
|
||||
@@ -985,7 +984,7 @@ def test_api_status(botclient, mocker, ticker, fee, markets, is_short,
|
||||
assert_response(rc)
|
||||
resp_values = rc.json()
|
||||
assert len(resp_values) == 4
|
||||
assert isnan(resp_values[0]['profit_abs'])
|
||||
assert resp_values[0]['profit_abs'] is None
|
||||
|
||||
|
||||
def test_api_version(botclient):
|
||||
@@ -1389,7 +1388,6 @@ def test_api_strategies(botclient):
|
||||
'StrategyTestV2',
|
||||
'StrategyTestV3',
|
||||
'StrategyTestV3Futures',
|
||||
'TestStrategyLegacyV1',
|
||||
]}
|
||||
|
||||
|
||||
@@ -1485,7 +1483,7 @@ def test_api_backtesting(botclient, mocker, fee, caplog, tmpdir):
|
||||
assert not result['running']
|
||||
assert result['status_msg'] == 'Backtest reset'
|
||||
ftbot.config['export'] = 'trades'
|
||||
ftbot.config['backtest_cache'] = 'none'
|
||||
ftbot.config['backtest_cache'] = 'day'
|
||||
ftbot.config['user_data_dir'] = Path(tmpdir)
|
||||
ftbot.config['exportfilename'] = Path(tmpdir) / "backtest_results"
|
||||
ftbot.config['exportfilename'].mkdir()
|
||||
@@ -1558,19 +1556,19 @@ def test_api_backtesting(botclient, mocker, fee, caplog, tmpdir):
|
||||
|
||||
ApiServer._bgtask_running = False
|
||||
|
||||
mocker.patch('freqtrade.optimize.backtesting.Backtesting.backtest_one_strategy',
|
||||
side_effect=DependencyException())
|
||||
rc = client_post(client, f"{BASE_URI}/backtest", data=json.dumps(data))
|
||||
assert log_has("Backtesting caused an error: ", caplog)
|
||||
|
||||
ftbot.config['backtest_cache'] = 'day'
|
||||
|
||||
# Rerun backtest (should get previous result)
|
||||
rc = client_post(client, f"{BASE_URI}/backtest", data=json.dumps(data))
|
||||
assert_response(rc)
|
||||
result = rc.json()
|
||||
assert log_has_re('Reusing result of previous backtest.*', caplog)
|
||||
|
||||
data['stake_amount'] = 101
|
||||
|
||||
mocker.patch('freqtrade.optimize.backtesting.Backtesting.backtest_one_strategy',
|
||||
side_effect=DependencyException())
|
||||
rc = client_post(client, f"{BASE_URI}/backtest", data=json.dumps(data))
|
||||
assert log_has("Backtesting caused an error: ", caplog)
|
||||
|
||||
# Delete backtesting to avoid leakage since the backtest-object may stick around.
|
||||
rc = client_delete(client, f"{BASE_URI}/backtest")
|
||||
assert_response(rc)
|
||||
|
30
tests/strategy/strats/broken_strats/legacy_strategy_v1.py
Normal file
30
tests/strategy/strats/broken_strats/legacy_strategy_v1.py
Normal file
@@ -0,0 +1,30 @@
|
||||
# type: ignore
|
||||
from pandas import DataFrame
|
||||
|
||||
from freqtrade.strategy import IStrategy
|
||||
|
||||
|
||||
# Dummy strategy - no longer loads but raises an exception.
|
||||
class TestStrategyLegacyV1(IStrategy):
|
||||
|
||||
minimal_roi = {
|
||||
"40": 0.0,
|
||||
"30": 0.01,
|
||||
"20": 0.02,
|
||||
"0": 0.04
|
||||
}
|
||||
stoploss = -0.10
|
||||
|
||||
timeframe = '5m'
|
||||
|
||||
def populate_indicators(self, dataframe: DataFrame) -> DataFrame:
|
||||
|
||||
return dataframe
|
||||
|
||||
def populate_buy_trend(self, dataframe: DataFrame) -> DataFrame:
|
||||
|
||||
return dataframe
|
||||
|
||||
def populate_sell_trend(self, dataframe: DataFrame) -> DataFrame:
|
||||
|
||||
return dataframe
|
@@ -1,85 +0,0 @@
|
||||
|
||||
# --- Do not remove these libs ---
|
||||
# Add your lib to import here
|
||||
import talib.abstract as ta
|
||||
from pandas import DataFrame
|
||||
|
||||
from freqtrade.strategy import IStrategy
|
||||
|
||||
|
||||
# --------------------------------
|
||||
|
||||
# This class is a sample. Feel free to customize it.
|
||||
class TestStrategyLegacyV1(IStrategy):
|
||||
"""
|
||||
This is a test strategy using the legacy function headers, which will be
|
||||
removed in a future update.
|
||||
Please do not use this as a template, but refer to user_data/strategy/sample_strategy.py
|
||||
for a uptodate version of this template.
|
||||
"""
|
||||
|
||||
# Minimal ROI designed for the strategy.
|
||||
# This attribute will be overridden if the config file contains "minimal_roi"
|
||||
minimal_roi = {
|
||||
"40": 0.0,
|
||||
"30": 0.01,
|
||||
"20": 0.02,
|
||||
"0": 0.04
|
||||
}
|
||||
|
||||
# Optimal stoploss designed for the strategy
|
||||
# This attribute will be overridden if the config file contains "stoploss"
|
||||
stoploss = -0.10
|
||||
|
||||
timeframe = '5m'
|
||||
|
||||
def populate_indicators(self, dataframe: DataFrame) -> DataFrame:
|
||||
"""
|
||||
Adds several different TA indicators to the given DataFrame
|
||||
|
||||
Performance Note: For the best performance be frugal on the number of indicators
|
||||
you are using. Let uncomment only the indicator you are using in your strategies
|
||||
or your hyperopt configuration, otherwise you will waste your memory and CPU usage.
|
||||
"""
|
||||
|
||||
# Momentum Indicator
|
||||
# ------------------------------------
|
||||
|
||||
# ADX
|
||||
dataframe['adx'] = ta.ADX(dataframe)
|
||||
|
||||
# TEMA - Triple Exponential Moving Average
|
||||
dataframe['tema'] = ta.TEMA(dataframe, timeperiod=9)
|
||||
|
||||
return dataframe
|
||||
|
||||
def populate_buy_trend(self, dataframe: DataFrame) -> DataFrame:
|
||||
"""
|
||||
Based on TA indicators, populates the buy signal for the given dataframe
|
||||
:param dataframe: DataFrame
|
||||
:return: DataFrame with buy column
|
||||
"""
|
||||
dataframe.loc[
|
||||
(
|
||||
(dataframe['adx'] > 30) &
|
||||
(dataframe['tema'] > dataframe['tema'].shift(1)) &
|
||||
(dataframe['volume'] > 0)
|
||||
),
|
||||
'buy'] = 1
|
||||
|
||||
return dataframe
|
||||
|
||||
def populate_sell_trend(self, dataframe: DataFrame) -> DataFrame:
|
||||
"""
|
||||
Based on TA indicators, populates the sell signal for the given dataframe
|
||||
:param dataframe: DataFrame
|
||||
:return: DataFrame with buy column
|
||||
"""
|
||||
dataframe.loc[
|
||||
(
|
||||
(dataframe['adx'] > 70) &
|
||||
(dataframe['tema'] < dataframe['tema'].shift(1)) &
|
||||
(dataframe['volume'] > 0)
|
||||
),
|
||||
'sell'] = 1
|
||||
return dataframe
|
@@ -56,19 +56,6 @@ class StrategyTestV2(IStrategy):
|
||||
# By default this strategy does not use Position Adjustments
|
||||
position_adjustment_enable = False
|
||||
|
||||
def informative_pairs(self):
|
||||
"""
|
||||
Define additional, informative pair/interval combinations to be cached from the exchange.
|
||||
These pair/interval combinations are non-tradeable, unless they are part
|
||||
of the whitelist as well.
|
||||
For more information, please consult the documentation
|
||||
:return: List of tuples in the format (pair, interval)
|
||||
Sample: return [("ETH/USDT", "5m"),
|
||||
("BTC/USDT", "15m"),
|
||||
]
|
||||
"""
|
||||
return []
|
||||
|
||||
def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||
"""
|
||||
Adds several different TA indicators to the given DataFrame
|
||||
|
@@ -82,6 +82,11 @@ class StrategyTestV3(IStrategy):
|
||||
# })
|
||||
# return prot
|
||||
|
||||
bot_started = False
|
||||
|
||||
def bot_start(self):
|
||||
self.bot_started = True
|
||||
|
||||
def informative_pairs(self):
|
||||
|
||||
return []
|
||||
|
@@ -686,7 +686,7 @@ def test_is_pair_locked(default_conf):
|
||||
|
||||
|
||||
def test_is_informative_pairs_callback(default_conf):
|
||||
default_conf.update({'strategy': 'TestStrategyLegacyV1'})
|
||||
default_conf.update({'strategy': 'StrategyTestV2'})
|
||||
strategy = StrategyResolver.load_strategy(default_conf)
|
||||
# Should return empty
|
||||
# Uses fallback to base implementation
|
||||
|
@@ -1,6 +1,5 @@
|
||||
# pragma pylint: disable=missing-docstring, protected-access, C0103
|
||||
import logging
|
||||
import warnings
|
||||
from base64 import urlsafe_b64encode
|
||||
from pathlib import Path
|
||||
|
||||
@@ -35,7 +34,7 @@ def test_search_all_strategies_no_failed():
|
||||
directory = Path(__file__).parent / "strats"
|
||||
strategies = StrategyResolver.search_all_objects(directory, enum_failed=False)
|
||||
assert isinstance(strategies, list)
|
||||
assert len(strategies) == 6
|
||||
assert len(strategies) == 5
|
||||
assert isinstance(strategies[0], dict)
|
||||
|
||||
|
||||
@@ -43,10 +42,10 @@ def test_search_all_strategies_with_failed():
|
||||
directory = Path(__file__).parent / "strats"
|
||||
strategies = StrategyResolver.search_all_objects(directory, enum_failed=True)
|
||||
assert isinstance(strategies, list)
|
||||
assert len(strategies) == 7
|
||||
assert len(strategies) == 6
|
||||
# with enum_failed=True search_all_objects() shall find 2 good strategies
|
||||
# and 1 which fails to load
|
||||
assert len([x for x in strategies if x['class'] is not None]) == 6
|
||||
assert len([x for x in strategies if x['class'] is not None]) == 5
|
||||
assert len([x for x in strategies if x['class'] is None]) == 1
|
||||
|
||||
|
||||
@@ -100,7 +99,7 @@ def test_load_strategy_noname(default_conf):
|
||||
|
||||
|
||||
@pytest.mark.filterwarnings("ignore:deprecated")
|
||||
@pytest.mark.parametrize('strategy_name', ['StrategyTestV2', 'TestStrategyLegacyV1'])
|
||||
@pytest.mark.parametrize('strategy_name', ['StrategyTestV2'])
|
||||
def test_strategy_pre_v3(result, default_conf, strategy_name):
|
||||
default_conf.update({'strategy': strategy_name})
|
||||
|
||||
@@ -346,40 +345,6 @@ def test_strategy_override_use_exit_profit_only(caplog, default_conf):
|
||||
assert log_has("Override strategy 'exit_profit_only' with value in config file: True.", caplog)
|
||||
|
||||
|
||||
@pytest.mark.filterwarnings("ignore:deprecated")
|
||||
def test_deprecate_populate_indicators(result, default_conf):
|
||||
default_location = Path(__file__).parent / "strats"
|
||||
default_conf.update({'strategy': 'TestStrategyLegacyV1',
|
||||
'strategy_path': default_location})
|
||||
strategy = StrategyResolver.load_strategy(default_conf)
|
||||
with warnings.catch_warnings(record=True) as w:
|
||||
# Cause all warnings to always be triggered.
|
||||
warnings.simplefilter("always")
|
||||
indicators = strategy.advise_indicators(result, {'pair': 'ETH/BTC'})
|
||||
assert len(w) == 1
|
||||
assert issubclass(w[-1].category, DeprecationWarning)
|
||||
assert "deprecated - check out the Sample strategy to see the current function headers!" \
|
||||
in str(w[-1].message)
|
||||
|
||||
with warnings.catch_warnings(record=True) as w:
|
||||
# Cause all warnings to always be triggered.
|
||||
warnings.simplefilter("always")
|
||||
strategy.advise_entry(indicators, {'pair': 'ETH/BTC'})
|
||||
assert len(w) == 1
|
||||
assert issubclass(w[-1].category, DeprecationWarning)
|
||||
assert "deprecated - check out the Sample strategy to see the current function headers!" \
|
||||
in str(w[-1].message)
|
||||
|
||||
with warnings.catch_warnings(record=True) as w:
|
||||
# Cause all warnings to always be triggered.
|
||||
warnings.simplefilter("always")
|
||||
strategy.advise_exit(indicators, {'pair': 'ETH_BTC'})
|
||||
assert len(w) == 1
|
||||
assert issubclass(w[-1].category, DeprecationWarning)
|
||||
assert "deprecated - check out the Sample strategy to see the current function headers!" \
|
||||
in str(w[-1].message)
|
||||
|
||||
|
||||
@pytest.mark.filterwarnings("ignore:deprecated")
|
||||
def test_missing_implements(default_conf, caplog):
|
||||
|
||||
@@ -438,33 +403,14 @@ def test_missing_implements(default_conf, caplog):
|
||||
StrategyResolver.load_strategy(default_conf)
|
||||
|
||||
|
||||
@pytest.mark.filterwarnings("ignore:deprecated")
|
||||
def test_call_deprecated_function(result, default_conf, caplog):
|
||||
default_location = Path(__file__).parent / "strats"
|
||||
def test_call_deprecated_function(default_conf):
|
||||
default_location = Path(__file__).parent / "strats/broken_strats/"
|
||||
del default_conf['timeframe']
|
||||
default_conf.update({'strategy': 'TestStrategyLegacyV1',
|
||||
'strategy_path': default_location})
|
||||
strategy = StrategyResolver.load_strategy(default_conf)
|
||||
metadata = {'pair': 'ETH/BTC'}
|
||||
|
||||
# Make sure we are using a legacy function
|
||||
assert strategy._populate_fun_len == 2
|
||||
assert strategy._buy_fun_len == 2
|
||||
assert strategy._sell_fun_len == 2
|
||||
assert strategy.INTERFACE_VERSION == 1
|
||||
assert strategy.timeframe == '5m'
|
||||
|
||||
indicator_df = strategy.advise_indicators(result, metadata=metadata)
|
||||
assert isinstance(indicator_df, DataFrame)
|
||||
assert 'adx' in indicator_df.columns
|
||||
|
||||
enterdf = strategy.advise_entry(result, metadata=metadata)
|
||||
assert isinstance(enterdf, DataFrame)
|
||||
assert 'enter_long' in enterdf.columns
|
||||
|
||||
exitdf = strategy.advise_exit(result, metadata=metadata)
|
||||
assert isinstance(exitdf, DataFrame)
|
||||
assert 'exit_long' in exitdf
|
||||
with pytest.raises(OperationalException,
|
||||
match=r"Strategy Interface v1 is no longer supported.*"):
|
||||
StrategyResolver.load_strategy(default_conf)
|
||||
|
||||
|
||||
def test_strategy_interface_versioning(result, default_conf):
|
||||
@@ -472,10 +418,6 @@ def test_strategy_interface_versioning(result, default_conf):
|
||||
strategy = StrategyResolver.load_strategy(default_conf)
|
||||
metadata = {'pair': 'ETH/BTC'}
|
||||
|
||||
# Make sure we are using a legacy function
|
||||
assert strategy._populate_fun_len == 3
|
||||
assert strategy._buy_fun_len == 3
|
||||
assert strategy._sell_fun_len == 3
|
||||
assert strategy.INTERFACE_VERSION == 2
|
||||
|
||||
indicator_df = strategy.advise_indicators(result, metadata=metadata)
|
||||
|
@@ -718,12 +718,12 @@ def test_process_informative_pairs_added(default_conf_usdt, ticker_usdt, mocker)
|
||||
(True, 'spot', 'gateio', None, 0.0, None),
|
||||
(False, 'spot', 'okx', None, 0.0, None),
|
||||
(True, 'spot', 'okx', None, 0.0, None),
|
||||
(True, 'futures', 'binance', 'isolated', 0.0, 11.89108910891089),
|
||||
(False, 'futures', 'binance', 'isolated', 0.0, 8.070707070707071),
|
||||
(True, 'futures', 'binance', 'isolated', 0.0, 11.88151815181518),
|
||||
(False, 'futures', 'binance', 'isolated', 0.0, 8.080471380471382),
|
||||
(True, 'futures', 'gateio', 'isolated', 0.0, 11.87413417771621),
|
||||
(False, 'futures', 'gateio', 'isolated', 0.0, 8.085708510208207),
|
||||
(True, 'futures', 'binance', 'isolated', 0.05, 11.796534653465345),
|
||||
(False, 'futures', 'binance', 'isolated', 0.05, 8.167171717171717),
|
||||
(True, 'futures', 'binance', 'isolated', 0.05, 11.7874422442244),
|
||||
(False, 'futures', 'binance', 'isolated', 0.05, 8.17644781144781),
|
||||
(True, 'futures', 'gateio', 'isolated', 0.05, 11.7804274688304),
|
||||
(False, 'futures', 'gateio', 'isolated', 0.05, 8.181423084697796),
|
||||
(True, 'futures', 'okx', 'isolated', 0.0, 11.87413417771621),
|
||||
@@ -846,6 +846,7 @@ def test_execute_entry(mocker, default_conf_usdt, fee, limit_order,
|
||||
assert trade.open_order_id is None
|
||||
assert trade.open_rate == 10
|
||||
assert trade.stake_amount == round(order['price'] * order['filled'] / leverage, 8)
|
||||
assert pytest.approx(trade.liquidation_price) == liq_price
|
||||
|
||||
# In case of rejected or expired order and partially filled
|
||||
order['status'] = 'expired'
|
||||
@@ -933,8 +934,6 @@ def test_execute_entry(mocker, default_conf_usdt, fee, limit_order,
|
||||
assert trade.open_rate_requested == 10
|
||||
|
||||
# In case of custom entry price not float type
|
||||
freqtrade.exchange.get_maintenance_ratio_and_amt = MagicMock(return_value=(0.01, 0.01))
|
||||
freqtrade.exchange.name = exchange_name
|
||||
order['status'] = 'open'
|
||||
order['id'] = '5568'
|
||||
freqtrade.strategy.custom_entry_price = lambda **kwargs: "string price"
|
||||
@@ -947,7 +946,6 @@ def test_execute_entry(mocker, default_conf_usdt, fee, limit_order,
|
||||
trade.is_short = is_short
|
||||
assert trade
|
||||
assert trade.open_rate_requested == 10
|
||||
assert trade.liquidation_price == liq_price
|
||||
|
||||
# In case of too high stake amount
|
||||
|
||||
@@ -3222,7 +3220,7 @@ def test_execute_trade_exit_custom_exit_price(
|
||||
freqtrade.execute_trade_exit(
|
||||
trade=trade,
|
||||
limit=ticker_usdt_sell_up()['ask' if is_short else 'bid'],
|
||||
exit_check=ExitCheckTuple(exit_type=ExitType.EXIT_SIGNAL)
|
||||
exit_check=ExitCheckTuple(exit_type=ExitType.EXIT_SIGNAL, exit_reason='foo')
|
||||
)
|
||||
|
||||
# Sell price must be different to default bid price
|
||||
@@ -3250,8 +3248,8 @@ def test_execute_trade_exit_custom_exit_price(
|
||||
'profit_ratio': profit_ratio,
|
||||
'stake_currency': 'USDT',
|
||||
'fiat_currency': 'USD',
|
||||
'sell_reason': ExitType.EXIT_SIGNAL.value,
|
||||
'exit_reason': ExitType.EXIT_SIGNAL.value,
|
||||
'sell_reason': 'foo',
|
||||
'exit_reason': 'foo',
|
||||
'open_date': ANY,
|
||||
'close_date': ANY,
|
||||
'close_rate': ANY,
|
||||
|
@@ -10,7 +10,8 @@ from plotly.subplots import make_subplots
|
||||
from freqtrade.commands import start_plot_dataframe, start_plot_profit
|
||||
from freqtrade.configuration import TimeRange
|
||||
from freqtrade.data import history
|
||||
from freqtrade.data.btanalysis import create_cum_profit, load_backtest_data
|
||||
from freqtrade.data.btanalysis import load_backtest_data
|
||||
from freqtrade.data.metrics import create_cum_profit
|
||||
from freqtrade.exceptions import OperationalException
|
||||
from freqtrade.plot.plotting import (add_areas, add_indicators, add_profit, create_plotconfig,
|
||||
generate_candlestick_graph, generate_plot_filename,
|
||||
|
Reference in New Issue
Block a user