mirror of
https://github.com/freqtrade/freqtrade.git
synced 2025-11-29 08:33:07 +00:00
chore: update strategy to modern typing syntax
This commit is contained in:
@@ -4,8 +4,9 @@ This module defines a base class for auto-hyperoptable strategies.
|
||||
"""
|
||||
|
||||
import logging
|
||||
from collections.abc import Iterator
|
||||
from pathlib import Path
|
||||
from typing import Any, Dict, Iterator, List, Optional, Tuple, Type, Union
|
||||
from typing import Any, Optional, Union
|
||||
|
||||
from freqtrade.constants import Config
|
||||
from freqtrade.exceptions import OperationalException
|
||||
@@ -28,9 +29,9 @@ class HyperStrategyMixin:
|
||||
Initialize hyperoptable strategy mixin.
|
||||
"""
|
||||
self.config = config
|
||||
self.ft_buy_params: List[BaseParameter] = []
|
||||
self.ft_sell_params: List[BaseParameter] = []
|
||||
self.ft_protection_params: List[BaseParameter] = []
|
||||
self.ft_buy_params: list[BaseParameter] = []
|
||||
self.ft_sell_params: list[BaseParameter] = []
|
||||
self.ft_protection_params: list[BaseParameter] = []
|
||||
|
||||
params = self.load_params_from_file()
|
||||
params = params.get("params", {})
|
||||
@@ -39,7 +40,7 @@ class HyperStrategyMixin:
|
||||
|
||||
def enumerate_parameters(
|
||||
self, category: Optional[str] = None
|
||||
) -> Iterator[Tuple[str, BaseParameter]]:
|
||||
) -> Iterator[tuple[str, BaseParameter]]:
|
||||
"""
|
||||
Find all optimizable parameters and return (name, attr) iterator.
|
||||
:param category:
|
||||
@@ -59,9 +60,9 @@ class HyperStrategyMixin:
|
||||
yield par.name, par
|
||||
|
||||
@classmethod
|
||||
def detect_all_parameters(cls) -> Dict:
|
||||
def detect_all_parameters(cls) -> dict:
|
||||
"""Detect all parameters and return them as a list"""
|
||||
params: Dict[str, Any] = {
|
||||
params: dict[str, Any] = {
|
||||
"buy": list(detect_parameters(cls, "buy")),
|
||||
"sell": list(detect_parameters(cls, "sell")),
|
||||
"protection": list(detect_parameters(cls, "protection")),
|
||||
@@ -124,7 +125,7 @@ class HyperStrategyMixin:
|
||||
self._ft_load_params(sell_params, "sell", hyperopt)
|
||||
self._ft_load_params(protection_params, "protection", hyperopt)
|
||||
|
||||
def load_params_from_file(self) -> Dict:
|
||||
def load_params_from_file(self) -> dict:
|
||||
filename_str = getattr(self, "__file__", "")
|
||||
if not filename_str:
|
||||
return {}
|
||||
@@ -144,14 +145,14 @@ class HyperStrategyMixin:
|
||||
|
||||
return {}
|
||||
|
||||
def _ft_load_params(self, params: Dict, space: str, hyperopt: bool = False) -> None:
|
||||
def _ft_load_params(self, params: dict, space: str, hyperopt: bool = False) -> None:
|
||||
"""
|
||||
Set optimizable parameter values.
|
||||
:param params: Dictionary with new parameter values.
|
||||
"""
|
||||
if not params:
|
||||
logger.info(f"No params for {space} found, using default values.")
|
||||
param_container: List[BaseParameter] = getattr(self, f"ft_{space}_params")
|
||||
param_container: list[BaseParameter] = getattr(self, f"ft_{space}_params")
|
||||
|
||||
for attr_name, attr in detect_parameters(self, space):
|
||||
attr.name = attr_name
|
||||
@@ -173,11 +174,11 @@ class HyperStrategyMixin:
|
||||
else:
|
||||
logger.info(f"Strategy Parameter(default): {attr_name} = {attr.value}")
|
||||
|
||||
def get_no_optimize_params(self) -> Dict[str, Dict]:
|
||||
def get_no_optimize_params(self) -> dict[str, dict]:
|
||||
"""
|
||||
Returns list of Parameters that are not part of the current optimize job
|
||||
"""
|
||||
params: Dict[str, Dict] = {
|
||||
params: dict[str, dict] = {
|
||||
"buy": {},
|
||||
"sell": {},
|
||||
"protection": {},
|
||||
@@ -189,8 +190,8 @@ class HyperStrategyMixin:
|
||||
|
||||
|
||||
def detect_parameters(
|
||||
obj: Union[HyperStrategyMixin, Type[HyperStrategyMixin]], category: str
|
||||
) -> Iterator[Tuple[str, BaseParameter]]:
|
||||
obj: Union[HyperStrategyMixin, type[HyperStrategyMixin]], category: str
|
||||
) -> Iterator[tuple[str, BaseParameter]]:
|
||||
"""
|
||||
Detect all parameters for 'category' for "obj"
|
||||
:param obj: Strategy object or class
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
from dataclasses import dataclass
|
||||
from typing import Any, Callable, Dict, Optional, Union
|
||||
from typing import Any, Callable, Optional, Union
|
||||
|
||||
from pandas import DataFrame
|
||||
|
||||
@@ -73,7 +73,7 @@ def informative(
|
||||
return decorator
|
||||
|
||||
|
||||
def __get_pair_formats(market: Optional[Dict[str, Any]]) -> Dict[str, str]:
|
||||
def __get_pair_formats(market: Optional[dict[str, Any]]) -> dict[str, str]:
|
||||
if not market:
|
||||
return {}
|
||||
base = market["base"]
|
||||
@@ -86,7 +86,7 @@ def __get_pair_formats(market: Optional[Dict[str, Any]]) -> Dict[str, str]:
|
||||
}
|
||||
|
||||
|
||||
def _format_pair_name(config, pair: str, market: Optional[Dict[str, Any]] = None) -> str:
|
||||
def _format_pair_name(config, pair: str, market: Optional[dict[str, Any]] = None) -> str:
|
||||
return pair.format(
|
||||
stake_currency=config["stake_currency"],
|
||||
stake=config["stake_currency"],
|
||||
|
||||
@@ -8,7 +8,7 @@ from abc import ABC, abstractmethod
|
||||
from collections import OrderedDict
|
||||
from datetime import datetime, timedelta, timezone
|
||||
from math import isinf, isnan
|
||||
from typing import Dict, List, Optional, Tuple, Union
|
||||
from typing import Optional, Union
|
||||
|
||||
from pandas import DataFrame
|
||||
|
||||
@@ -63,9 +63,9 @@ class IStrategy(ABC, HyperStrategyMixin):
|
||||
# Version 3 - First version with short and leverage support
|
||||
INTERFACE_VERSION: int = 3
|
||||
|
||||
_ft_params_from_file: Dict
|
||||
_ft_params_from_file: dict
|
||||
# associated minimal roi
|
||||
minimal_roi: Dict = {}
|
||||
minimal_roi: dict = {}
|
||||
|
||||
# associated stoploss
|
||||
stoploss: float
|
||||
@@ -87,7 +87,7 @@ class IStrategy(ABC, HyperStrategyMixin):
|
||||
timeframe: str
|
||||
|
||||
# Optional order types
|
||||
order_types: Dict = {
|
||||
order_types: dict = {
|
||||
"entry": "limit",
|
||||
"exit": "limit",
|
||||
"stoploss": "limit",
|
||||
@@ -96,7 +96,7 @@ class IStrategy(ABC, HyperStrategyMixin):
|
||||
}
|
||||
|
||||
# Optional time in force
|
||||
order_time_in_force: Dict = {
|
||||
order_time_in_force: dict = {
|
||||
"entry": "GTC",
|
||||
"exit": "GTC",
|
||||
}
|
||||
@@ -123,7 +123,7 @@ class IStrategy(ABC, HyperStrategyMixin):
|
||||
startup_candle_count: int = 0
|
||||
|
||||
# Protections
|
||||
protections: List = []
|
||||
protections: list = []
|
||||
|
||||
# Class level variables (intentional) containing
|
||||
# the dataprovider (dp) (access to other candles, historic data, ...)
|
||||
@@ -136,24 +136,24 @@ class IStrategy(ABC, HyperStrategyMixin):
|
||||
__source__: str = ""
|
||||
|
||||
# Definition of plot_config. See plotting documentation for more details.
|
||||
plot_config: Dict = {}
|
||||
plot_config: dict = {}
|
||||
|
||||
# A self set parameter that represents the market direction. filled from configuration
|
||||
market_direction: MarketDirection = MarketDirection.NONE
|
||||
|
||||
# Global cache dictionary
|
||||
_cached_grouped_trades_per_pair: Dict[
|
||||
str, OrderedDict[Tuple[datetime, datetime], DataFrame]
|
||||
_cached_grouped_trades_per_pair: dict[
|
||||
str, OrderedDict[tuple[datetime, datetime], DataFrame]
|
||||
] = {}
|
||||
|
||||
def __init__(self, config: Config) -> None:
|
||||
self.config = config
|
||||
# Dict to determine if analysis is necessary
|
||||
self._last_candle_seen_per_pair: Dict[str, datetime] = {}
|
||||
self._last_candle_seen_per_pair: dict[str, datetime] = {}
|
||||
super().__init__(config)
|
||||
|
||||
# Gather informative pairs from @informative-decorated methods.
|
||||
self._ft_informative: List[Tuple[InformativeData, PopulateIndicators]] = []
|
||||
self._ft_informative: list[tuple[InformativeData, PopulateIndicators]] = []
|
||||
for attr_name in dir(self.__class__):
|
||||
cls_method = getattr(self.__class__, attr_name)
|
||||
if not callable(cls_method):
|
||||
@@ -627,7 +627,7 @@ class IStrategy(ABC, HyperStrategyMixin):
|
||||
current_entry_profit: float,
|
||||
current_exit_profit: float,
|
||||
**kwargs,
|
||||
) -> Union[Optional[float], Tuple[Optional[float], Optional[str]]]:
|
||||
) -> Union[Optional[float], tuple[Optional[float], Optional[str]]]:
|
||||
"""
|
||||
Custom trade adjustment logic, returning the stake amount that a trade should be
|
||||
increased or decreased.
|
||||
@@ -761,7 +761,7 @@ class IStrategy(ABC, HyperStrategyMixin):
|
||||
return df
|
||||
|
||||
def feature_engineering_expand_all(
|
||||
self, dataframe: DataFrame, period: int, metadata: Dict, **kwargs
|
||||
self, dataframe: DataFrame, period: int, metadata: dict, **kwargs
|
||||
) -> DataFrame:
|
||||
"""
|
||||
*Only functional with FreqAI enabled strategies*
|
||||
@@ -789,7 +789,7 @@ class IStrategy(ABC, HyperStrategyMixin):
|
||||
return dataframe
|
||||
|
||||
def feature_engineering_expand_basic(
|
||||
self, dataframe: DataFrame, metadata: Dict, **kwargs
|
||||
self, dataframe: DataFrame, metadata: dict, **kwargs
|
||||
) -> DataFrame:
|
||||
"""
|
||||
*Only functional with FreqAI enabled strategies*
|
||||
@@ -820,7 +820,7 @@ class IStrategy(ABC, HyperStrategyMixin):
|
||||
return dataframe
|
||||
|
||||
def feature_engineering_standard(
|
||||
self, dataframe: DataFrame, metadata: Dict, **kwargs
|
||||
self, dataframe: DataFrame, metadata: dict, **kwargs
|
||||
) -> DataFrame:
|
||||
"""
|
||||
*Only functional with FreqAI enabled strategies*
|
||||
@@ -845,7 +845,7 @@ class IStrategy(ABC, HyperStrategyMixin):
|
||||
"""
|
||||
return dataframe
|
||||
|
||||
def set_freqai_targets(self, dataframe: DataFrame, metadata: Dict, **kwargs) -> DataFrame:
|
||||
def set_freqai_targets(self, dataframe: DataFrame, metadata: dict, **kwargs) -> DataFrame:
|
||||
"""
|
||||
*Only functional with FreqAI enabled strategies*
|
||||
Required function to set the targets for the model.
|
||||
@@ -880,7 +880,7 @@ class IStrategy(ABC, HyperStrategyMixin):
|
||||
current_entry_profit: float,
|
||||
current_exit_profit: float,
|
||||
**kwargs,
|
||||
) -> Tuple[Optional[float], str]:
|
||||
) -> tuple[Optional[float], str]:
|
||||
"""
|
||||
wrapper around adjust_trade_position to handle the return value
|
||||
"""
|
||||
@@ -1112,7 +1112,7 @@ class IStrategy(ABC, HyperStrategyMixin):
|
||||
logger.warning("Empty dataframe for pair %s", pair)
|
||||
return
|
||||
|
||||
def analyze(self, pairs: List[str]) -> None:
|
||||
def analyze(self, pairs: list[str]) -> None:
|
||||
"""
|
||||
Analyze all pairs using analyze_pair().
|
||||
:param pairs: List of pairs to analyze
|
||||
@@ -1121,7 +1121,7 @@ class IStrategy(ABC, HyperStrategyMixin):
|
||||
self.analyze_pair(pair)
|
||||
|
||||
@staticmethod
|
||||
def preserve_df(dataframe: DataFrame) -> Tuple[int, float, datetime]:
|
||||
def preserve_df(dataframe: DataFrame) -> tuple[int, float, datetime]:
|
||||
"""keep some data for dataframes"""
|
||||
return len(dataframe), dataframe["close"].iloc[-1], dataframe["date"].iloc[-1]
|
||||
|
||||
@@ -1152,7 +1152,7 @@ class IStrategy(ABC, HyperStrategyMixin):
|
||||
pair: str,
|
||||
timeframe: str,
|
||||
dataframe: DataFrame,
|
||||
) -> Tuple[Optional[DataFrame], Optional[datetime]]:
|
||||
) -> tuple[Optional[DataFrame], Optional[datetime]]:
|
||||
"""
|
||||
Calculates current signal based based on the entry order or exit order
|
||||
columns of the dataframe.
|
||||
@@ -1185,7 +1185,7 @@ class IStrategy(ABC, HyperStrategyMixin):
|
||||
|
||||
def get_exit_signal(
|
||||
self, pair: str, timeframe: str, dataframe: DataFrame, is_short: Optional[bool] = None
|
||||
) -> Tuple[bool, bool, Optional[str]]:
|
||||
) -> tuple[bool, bool, Optional[str]]:
|
||||
"""
|
||||
Calculates current exit signal based based on the dataframe
|
||||
columns of the dataframe.
|
||||
@@ -1221,7 +1221,7 @@ class IStrategy(ABC, HyperStrategyMixin):
|
||||
pair: str,
|
||||
timeframe: str,
|
||||
dataframe: DataFrame,
|
||||
) -> Tuple[Optional[SignalDirection], Optional[str]]:
|
||||
) -> tuple[Optional[SignalDirection], Optional[str]]:
|
||||
"""
|
||||
Calculates current entry signal based based on the dataframe signals
|
||||
columns of the dataframe.
|
||||
@@ -1292,7 +1292,7 @@ class IStrategy(ABC, HyperStrategyMixin):
|
||||
low: Optional[float] = None,
|
||||
high: Optional[float] = None,
|
||||
force_stoploss: float = 0,
|
||||
) -> List[ExitCheckTuple]:
|
||||
) -> list[ExitCheckTuple]:
|
||||
"""
|
||||
This function evaluates if one of the conditions required to trigger an exit order
|
||||
has been reached, which can either be a stop-loss, ROI or exit-signal.
|
||||
@@ -1301,7 +1301,7 @@ class IStrategy(ABC, HyperStrategyMixin):
|
||||
:param force_stoploss: Externally provided stoploss
|
||||
:return: List of exit reasons - or empty list.
|
||||
"""
|
||||
exits: List[ExitCheckTuple] = []
|
||||
exits: list[ExitCheckTuple] = []
|
||||
current_rate = rate
|
||||
current_profit = trade.calc_profit_ratio(current_rate)
|
||||
current_profit_best = current_profit
|
||||
@@ -1520,7 +1520,7 @@ class IStrategy(ABC, HyperStrategyMixin):
|
||||
|
||||
return ExitCheckTuple(exit_type=ExitType.NONE)
|
||||
|
||||
def min_roi_reached_entry(self, trade_dur: int) -> Tuple[Optional[int], Optional[float]]:
|
||||
def min_roi_reached_entry(self, trade_dur: int) -> tuple[Optional[int], Optional[float]]:
|
||||
"""
|
||||
Based on trade duration defines the ROI entry that may have been reached.
|
||||
:param trade_dur: trade duration in minutes
|
||||
@@ -1573,7 +1573,7 @@ class IStrategy(ABC, HyperStrategyMixin):
|
||||
pair=trade.pair, trade=trade, order=order, current_time=current_time
|
||||
)
|
||||
|
||||
def advise_all_indicators(self, data: Dict[str, DataFrame]) -> Dict[str, DataFrame]:
|
||||
def advise_all_indicators(self, data: dict[str, DataFrame]) -> dict[str, DataFrame]:
|
||||
"""
|
||||
Populates indicators for given candle (OHLCV) data (for multiple pairs)
|
||||
Does not run advise_entry or advise_exit!
|
||||
@@ -1611,7 +1611,7 @@ class IStrategy(ABC, HyperStrategyMixin):
|
||||
config["timeframe"] = self.timeframe
|
||||
pair = metadata["pair"]
|
||||
# TODO: slice trades to size of dataframe for faster backtesting
|
||||
cached_grouped_trades: OrderedDict[Tuple[datetime, datetime], DataFrame] = (
|
||||
cached_grouped_trades: OrderedDict[tuple[datetime, datetime], DataFrame] = (
|
||||
self._cached_grouped_trades_per_pair.get(pair, OrderedDict())
|
||||
)
|
||||
dataframe, cached_grouped_trades = populate_dataframe_with_trades(
|
||||
|
||||
@@ -5,8 +5,9 @@ This module defines a base class for auto-hyperoptable strategies.
|
||||
|
||||
import logging
|
||||
from abc import ABC, abstractmethod
|
||||
from collections.abc import Sequence
|
||||
from contextlib import suppress
|
||||
from typing import Any, Optional, Sequence, Union
|
||||
from typing import Any, Optional, Union
|
||||
|
||||
from freqtrade.enums import HyperoptState
|
||||
from freqtrade.optimize.hyperopt_tools import HyperoptStateContainer
|
||||
|
||||
Reference in New Issue
Block a user