mirror of
https://github.com/freqtrade/freqtrade.git
synced 2024-11-10 02:12:01 +00:00
Changed max_open_trades type to int or inf
This commit is contained in:
parent
192f75254f
commit
b0f1d914c8
|
@ -681,3 +681,4 @@ MakerTaker = Literal['maker', 'taker']
|
|||
BidAsk = Literal['bid', 'ask']
|
||||
|
||||
Config = Dict[str, Any]
|
||||
IntOrInf = float
|
||||
|
|
|
@ -10,7 +10,7 @@ from typing import Any, Dict, List, Optional, Union
|
|||
import numpy as np
|
||||
import pandas as pd
|
||||
|
||||
from freqtrade.constants import LAST_BT_RESULT_FN
|
||||
from freqtrade.constants import LAST_BT_RESULT_FN, IntOrInf
|
||||
from freqtrade.exceptions import OperationalException
|
||||
from freqtrade.misc import json_load
|
||||
from freqtrade.optimize.backtest_caching import get_backtest_metadata_filename
|
||||
|
@ -332,7 +332,7 @@ def analyze_trade_parallelism(results: pd.DataFrame, timeframe: str) -> pd.DataF
|
|||
|
||||
|
||||
def evaluate_result_multi(results: pd.DataFrame, timeframe: str,
|
||||
max_open_trades: int) -> pd.DataFrame:
|
||||
max_open_trades: IntOrInf) -> pd.DataFrame:
|
||||
"""
|
||||
Find overlapping trades by expanding each trade once per period it was open
|
||||
and then counting overlaps
|
||||
|
|
|
@ -1237,8 +1237,8 @@ class Backtesting:
|
|||
if not self.config.get('use_max_market_positions', True):
|
||||
logger.info(
|
||||
'Ignoring max_open_trades (--disable-max-market-positions was used) ...')
|
||||
self.strategy.max_open_trades = -1
|
||||
self.config.update({'max_open_trades': float('inf')})
|
||||
self.strategy.max_open_trades = float('inf')
|
||||
self.config.update({'max_open_trades': self.strategy.max_open_trades})
|
||||
|
||||
# need to reprocess data every time to populate signals
|
||||
preprocessed = self.strategy.advise_all_indicators(data)
|
||||
|
|
|
@ -120,8 +120,8 @@ class Hyperopt:
|
|||
# Use max_open_trades for hyperopt as well, except --disable-max-market-positions is set
|
||||
if not self.config.get('use_max_market_positions', True):
|
||||
logger.debug('Ignoring max_open_trades (--disable-max-market-positions was used) ...')
|
||||
self.backtesting.strategy.max_open_trades = -1
|
||||
config.update({'max_open_trades': float('inf')})
|
||||
self.backtesting.strategy.max_open_trades = float('inf')
|
||||
config.update({'max_open_trades': self.backtesting.strategy.max_open_trades})
|
||||
|
||||
if HyperoptTools.has_space(self.config, 'sell'):
|
||||
# Make sure use_exit_signal is enabled
|
||||
|
@ -211,7 +211,8 @@ class Hyperopt:
|
|||
result['trailing'] = self.custom_hyperopt.generate_trailing_params(params)
|
||||
if HyperoptTools.has_space(self.config, 'trades'):
|
||||
result['max_open_trades'] = {
|
||||
'max_open_trades': self.backtesting.strategy.max_open_trades}
|
||||
'max_open_trades': self.backtesting.strategy.max_open_trades
|
||||
if self.backtesting.strategy.max_open_trades != float('inf') else -1}
|
||||
|
||||
return result
|
||||
|
||||
|
@ -344,16 +345,13 @@ class Hyperopt:
|
|||
# Ignore unlimited max open trades if stake amount is unlimited
|
||||
params_dict.update({'max_open_trades': self.config['max_open_trades']})
|
||||
|
||||
updated_config_max_open_trades = int(params_dict['max_open_trades']) \
|
||||
updated_max_open_trades = int(params_dict['max_open_trades']) \
|
||||
if (params_dict['max_open_trades'] != -1
|
||||
and params_dict['max_open_trades'] != 0) else float('inf')
|
||||
|
||||
updated_strategy_max_open_trades = int(updated_config_max_open_trades) \
|
||||
if updated_config_max_open_trades != float('inf') else -1
|
||||
self.config.update({'max_open_trades': updated_max_open_trades})
|
||||
|
||||
self.config.update({'max_open_trades': updated_config_max_open_trades})
|
||||
|
||||
self.backtesting.strategy.max_open_trades = updated_strategy_max_open_trades
|
||||
self.backtesting.strategy.max_open_trades = updated_max_open_trades
|
||||
|
||||
with self.data_pickle_file.open('rb') as f:
|
||||
processed = load(f, mmap_mode='r')
|
||||
|
|
|
@ -8,7 +8,7 @@ from pandas import DataFrame, to_datetime
|
|||
from tabulate import tabulate
|
||||
|
||||
from freqtrade.constants import (DATETIME_PRINT_FORMAT, LAST_BT_RESULT_FN, UNLIMITED_STAKE_AMOUNT,
|
||||
Config)
|
||||
Config, IntOrInf)
|
||||
from freqtrade.data.metrics import (calculate_cagr, calculate_calmar, calculate_csum,
|
||||
calculate_expectancy, calculate_market_change,
|
||||
calculate_max_drawdown, calculate_sharpe, calculate_sortino)
|
||||
|
@ -191,7 +191,7 @@ def generate_tag_metrics(tag_type: str,
|
|||
return []
|
||||
|
||||
|
||||
def generate_exit_reason_stats(max_open_trades: int, results: DataFrame) -> List[Dict]:
|
||||
def generate_exit_reason_stats(max_open_trades: IntOrInf, results: DataFrame) -> List[Dict]:
|
||||
"""
|
||||
Generate small table outlining Backtest results
|
||||
:param max_open_trades: Max_open_trades parameter
|
||||
|
|
|
@ -104,11 +104,7 @@ class StrategyResolver(IResolver):
|
|||
if (attribute in config
|
||||
and not isinstance(getattr(type(strategy), attribute, None), property)):
|
||||
# Ensure Properties are not overwritten
|
||||
val = config[attribute]
|
||||
# max_open_trades set to float('inf') in the config will be copied as -1 in the strategy
|
||||
if attribute == 'max_open_trades' and val == float('inf'):
|
||||
val = -1
|
||||
setattr(strategy, attribute, val)
|
||||
setattr(strategy, attribute, config[attribute])
|
||||
logger.info("Override strategy '%s' with value in config file: %s.",
|
||||
attribute, config[attribute])
|
||||
elif hasattr(strategy, attribute):
|
||||
|
@ -137,6 +133,8 @@ class StrategyResolver(IResolver):
|
|||
key=lambda t: t[0]))
|
||||
if hasattr(strategy, 'stoploss'):
|
||||
strategy.stoploss = float(strategy.stoploss)
|
||||
if hasattr(strategy, 'max_open_trades') and strategy.max_open_trades < 0:
|
||||
strategy.max_open_trades = float('inf')
|
||||
return strategy
|
||||
|
||||
@staticmethod
|
||||
|
|
|
@ -3,7 +3,7 @@ from typing import Any, Dict, List, Optional, Union
|
|||
|
||||
from pydantic import BaseModel
|
||||
|
||||
from freqtrade.constants import DATETIME_PRINT_FORMAT
|
||||
from freqtrade.constants import DATETIME_PRINT_FORMAT, IntOrInf
|
||||
from freqtrade.enums import OrderTypeValues, SignalDirection, TradingMode
|
||||
|
||||
|
||||
|
@ -165,7 +165,7 @@ class ShowConfig(BaseModel):
|
|||
stake_amount: str
|
||||
available_capital: Optional[float]
|
||||
stake_currency_decimals: int
|
||||
max_open_trades: int
|
||||
max_open_trades: IntOrInf
|
||||
minimal_roi: Dict[str, Any]
|
||||
stoploss: Optional[float]
|
||||
trailing_stop: Optional[bool]
|
||||
|
@ -422,7 +422,7 @@ class BacktestRequest(BaseModel):
|
|||
timeframe: Optional[str]
|
||||
timeframe_detail: Optional[str]
|
||||
timerange: Optional[str]
|
||||
max_open_trades: Optional[int]
|
||||
max_open_trades: Optional[IntOrInf]
|
||||
stake_amount: Optional[str]
|
||||
enable_protections: bool
|
||||
dry_run_wallet: Optional[float]
|
||||
|
|
|
@ -673,6 +673,7 @@ class RPC:
|
|||
if self._freqtrade.state == State.RUNNING:
|
||||
# Set 'max_open_trades' to 0
|
||||
self._freqtrade.config['max_open_trades'] = 0
|
||||
self._freqtrade.strategy.max_open_trades = 0
|
||||
|
||||
return {'status': 'No more entries will occur from now. Run /reload_config to reset.'}
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@ from typing import Dict, List, Optional, Tuple, Union
|
|||
import arrow
|
||||
from pandas import DataFrame
|
||||
|
||||
from freqtrade.constants import Config, ListPairsWithTimeframes
|
||||
from freqtrade.constants import Config, IntOrInf, ListPairsWithTimeframes
|
||||
from freqtrade.data.dataprovider import DataProvider
|
||||
from freqtrade.enums import (CandleType, ExitCheckTuple, ExitType, RunMode, SignalDirection,
|
||||
SignalTagType, SignalType, TradingMode)
|
||||
|
@ -55,7 +55,7 @@ class IStrategy(ABC, HyperStrategyMixin):
|
|||
stoploss: float
|
||||
|
||||
# max open trades for the strategy
|
||||
max_open_trades: int
|
||||
max_open_trades: IntOrInf
|
||||
|
||||
# trailing stoploss
|
||||
trailing_stop: bool = False
|
||||
|
|
|
@ -1020,6 +1020,52 @@ def test_stake_amount_unlimited_max_open_trades(mocker, hyperopt_conf, tmpdir, f
|
|||
assert hyperopt.backtesting.strategy.max_open_trades == 1
|
||||
|
||||
|
||||
def test_max_open_trades_dump(mocker, hyperopt_conf, tmpdir, fee, capsys) -> None:
|
||||
# This test is to ensure that after hyperopting, max_open_trades is never
|
||||
# saved as inf in the output json params
|
||||
patch_exchange(mocker)
|
||||
mocker.patch('freqtrade.exchange.Exchange.get_fee', fee)
|
||||
(Path(tmpdir) / 'hyperopt_results').mkdir(parents=True)
|
||||
hyperopt_conf.update({
|
||||
'strategy': 'HyperoptableStrategy',
|
||||
'user_data_dir': Path(tmpdir),
|
||||
'hyperopt_random_state': 42,
|
||||
'spaces': ['trades'],
|
||||
})
|
||||
hyperopt = Hyperopt(hyperopt_conf)
|
||||
mocker.patch('freqtrade.optimize.hyperopt.Hyperopt._get_params_dict',
|
||||
return_value={
|
||||
'max_open_trades': -1
|
||||
})
|
||||
|
||||
assert isinstance(hyperopt.custom_hyperopt, HyperOptAuto)
|
||||
|
||||
hyperopt.start()
|
||||
|
||||
out, err = capsys.readouterr()
|
||||
|
||||
assert 'max_open_trades = -1' in out
|
||||
assert 'max_open_trades = inf' not in out
|
||||
|
||||
##############
|
||||
|
||||
hyperopt_conf.update({'print_json': True})
|
||||
|
||||
hyperopt = Hyperopt(hyperopt_conf)
|
||||
mocker.patch('freqtrade.optimize.hyperopt.Hyperopt._get_params_dict',
|
||||
return_value={
|
||||
'max_open_trades': -1
|
||||
})
|
||||
|
||||
assert isinstance(hyperopt.custom_hyperopt, HyperOptAuto)
|
||||
|
||||
hyperopt.start()
|
||||
|
||||
out, err = capsys.readouterr()
|
||||
|
||||
assert '"max_open_trades":-1' in out
|
||||
|
||||
|
||||
def test_max_open_trades_consistency(mocker, hyperopt_conf, tmpdir, fee) -> None:
|
||||
# This test is to ensure that max_open_trades is the same across all functions needing it
|
||||
# after it has been changed from the hyperopt
|
||||
|
|
|
@ -6,6 +6,7 @@ from pathlib import Path
|
|||
import pytest
|
||||
from pandas import DataFrame
|
||||
|
||||
from freqtrade.configuration.configuration import Configuration
|
||||
from freqtrade.exceptions import OperationalException
|
||||
from freqtrade.resolvers import StrategyResolver
|
||||
from freqtrade.strategy.interface import IStrategy
|
||||
|
@ -371,20 +372,26 @@ def test_strategy_max_open_trades_infinity_from_strategy(caplog, default_conf):
|
|||
strategy = StrategyResolver.load_strategy(default_conf)
|
||||
|
||||
# this test assumes -1 set to 'max_open_trades' in CURRENT_TEST_STRATEGY
|
||||
assert strategy.max_open_trades == -1
|
||||
assert strategy.max_open_trades == float('inf')
|
||||
assert default_conf['max_open_trades'] == float('inf')
|
||||
|
||||
|
||||
def test_strategy_max_open_trades_infinity_from_config(caplog, default_conf):
|
||||
def test_strategy_max_open_trades_infinity_from_config(caplog, default_conf, mocker):
|
||||
caplog.set_level(logging.INFO)
|
||||
default_conf.update({
|
||||
'strategy': CURRENT_TEST_STRATEGY,
|
||||
'max_open_trades': float('inf')
|
||||
'max_open_trades': -1,
|
||||
'exchange': 'binance'
|
||||
})
|
||||
|
||||
strategy = StrategyResolver.load_strategy(default_conf)
|
||||
configuration = Configuration(args=default_conf)
|
||||
parsed_config = configuration.get_config()
|
||||
|
||||
assert strategy.max_open_trades == -1
|
||||
assert parsed_config['max_open_trades'] == float('inf')
|
||||
|
||||
strategy = StrategyResolver.load_strategy(parsed_config)
|
||||
|
||||
assert strategy.max_open_trades == float('inf')
|
||||
|
||||
|
||||
@ pytest.mark.filterwarnings("ignore:deprecated")
|
||||
|
@ -476,3 +483,19 @@ def test_strategy_interface_versioning(dataframe_1m, default_conf):
|
|||
assert isinstance(exitdf, DataFrame)
|
||||
assert 'sell' not in exitdf
|
||||
assert 'exit_long' in exitdf
|
||||
|
||||
|
||||
def test_strategy_ft_load_params_from_file(mocker, default_conf):
|
||||
default_conf.update({'strategy': 'StrategyTestV2'})
|
||||
del default_conf['max_open_trades']
|
||||
mocker.patch('freqtrade.strategy.hyper.HyperStrategyMixin.load_params_from_file',
|
||||
return_value={
|
||||
'params': {
|
||||
'max_open_trades': {
|
||||
'max_open_trades': -1
|
||||
}
|
||||
}
|
||||
})
|
||||
strategy = StrategyResolver.load_strategy(default_conf)
|
||||
assert strategy.max_open_trades == float('inf')
|
||||
assert strategy.config['max_open_trades'] == float('inf')
|
||||
|
|
Loading…
Reference in New Issue
Block a user