From 528c65c194dcd4ab309e0e0de96945897f685135 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 30 Oct 2023 09:13:28 +0000 Subject: [PATCH 1/7] Bump pandas from 2.0.3 to 2.1.2 Bumps [pandas](https://github.com/pandas-dev/pandas) from 2.0.3 to 2.1.2. - [Release notes](https://github.com/pandas-dev/pandas/releases) - [Commits](https://github.com/pandas-dev/pandas/compare/v2.0.3...v2.1.2) --- updated-dependencies: - dependency-name: pandas dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 64b0cb6f8..146f468a6 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,5 +1,5 @@ numpy==1.26.1 -pandas==2.0.3 +pandas==2.1.2 pandas-ta==0.3.14b ccxt==4.1.31 From bbdc6c0f5c1af11f859011fae6db705db8fe9b78 Mon Sep 17 00:00:00 2001 From: Matthias Date: Mon, 30 Oct 2023 18:11:38 +0100 Subject: [PATCH 2/7] improve pandas syntax to avoid deprecation error --- tests/data/test_converter.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/data/test_converter.py b/tests/data/test_converter.py index 74bb8d9f9..ebee4a3be 100644 --- a/tests/data/test_converter.py +++ b/tests/data/test_converter.py @@ -50,8 +50,8 @@ def test_trades_to_ohlcv(trades_history_df, caplog): assert 'high' in df.columns assert 'low' in df.columns assert 'close' in df.columns - assert df.loc[:, 'high'][0] == 0.019627 - assert df.loc[:, 'low'][0] == 0.019626 + assert df.iloc[0, :]['high'] == 0.019627 + assert df.iloc[0, :]['low'] == 0.019626 def test_ohlcv_fill_up_missing_data(testdatadir, caplog): From b19f17fdfa88385373fa8839c0c61cf90aa6625c Mon Sep 17 00:00:00 2001 From: Matthias Date: Mon, 30 Oct 2023 18:26:01 +0100 Subject: [PATCH 3/7] Improve handling of bt results in optimize_reports --- freqtrade/optimize/optimize_reports/optimize_reports.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/freqtrade/optimize/optimize_reports/optimize_reports.py b/freqtrade/optimize/optimize_reports/optimize_reports.py index b68fc708e..2ca6ee947 100644 --- a/freqtrade/optimize/optimize_reports/optimize_reports.py +++ b/freqtrade/optimize/optimize_reports/optimize_reports.py @@ -219,8 +219,10 @@ def _get_resample_from_period(period: str) -> str: raise ValueError(f"Period {period} is not supported.") -def generate_periodic_breakdown_stats(trade_list: List, period: str) -> List[Dict[str, Any]]: - results = DataFrame.from_records(trade_list) +def generate_periodic_breakdown_stats( + trade_list: Union[List, DataFrame], period: str) -> List[Dict[str, Any]]: + + results = trade_list if not isinstance(trade_list, list) else DataFrame.from_records(trade_list) if len(results) == 0: return [] results['close_date'] = to_datetime(results['close_date'], utc=True) From 9297a90d7f996e4db32d31e47aca26a219c3ef9c Mon Sep 17 00:00:00 2001 From: Matthias Date: Mon, 30 Oct 2023 18:26:25 +0100 Subject: [PATCH 4/7] Use proper indexing to avoid deprecation warnings --- freqtrade/optimize/analysis/lookahead.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/freqtrade/optimize/analysis/lookahead.py b/freqtrade/optimize/analysis/lookahead.py index 924e43e07..9fa4235e7 100755 --- a/freqtrade/optimize/analysis/lookahead.py +++ b/freqtrade/optimize/analysis/lookahead.py @@ -94,8 +94,8 @@ class LookaheadAnalysis(BaseAnalysis): # compare_df now comprises tuples with [1] having either 'self' or 'other' if 'other' in col_name[1]: continue - self_value = compare_df_row[col_idx] - other_value = compare_df_row[col_idx + 1] + self_value = compare_df_row.iloc[col_idx] + other_value = compare_df_row.iloc[col_idx + 1] # output differences if self_value != other_value: From 949c3c660b9ef9fc77c808a76979ecefea80cbf4 Mon Sep 17 00:00:00 2001 From: Matthias Date: Mon, 30 Oct 2023 19:05:15 +0100 Subject: [PATCH 5/7] Ignore "nan" enter and exit tags these happen if strings are assigned to individual rows without initializing the whole column --- freqtrade/strategy/interface.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/freqtrade/strategy/interface.py b/freqtrade/strategy/interface.py index cbe6afc26..651ca14bf 100644 --- a/freqtrade/strategy/interface.py +++ b/freqtrade/strategy/interface.py @@ -1006,7 +1006,7 @@ class IStrategy(ABC, HyperStrategyMixin): exit_ = latest.get(SignalType.EXIT_LONG.value, 0) == 1 exit_tag = latest.get(SignalTagType.EXIT_TAG.value, None) # Tags can be None, which does not resolve to False. - exit_tag = exit_tag if isinstance(exit_tag, str) else None + exit_tag = exit_tag if isinstance(exit_tag, str) and exit_tag != 'nan' else None logger.debug(f"exit-trigger: {latest['date']} (pair={pair}) " f"enter={enter} exit={exit_}") @@ -1038,17 +1038,17 @@ class IStrategy(ABC, HyperStrategyMixin): exit_short = latest.get(SignalType.EXIT_SHORT.value, 0) == 1 enter_signal: Optional[SignalDirection] = None - enter_tag_value: Optional[str] = None + enter_tag: Optional[str] = None if enter_long == 1 and not any([exit_long, enter_short]): enter_signal = SignalDirection.LONG - enter_tag_value = latest.get(SignalTagType.ENTER_TAG.value, None) + enter_tag = latest.get(SignalTagType.ENTER_TAG.value, None) if (self.config.get('trading_mode', TradingMode.SPOT) != TradingMode.SPOT and self.can_short and enter_short == 1 and not any([exit_short, enter_long])): enter_signal = SignalDirection.SHORT - enter_tag_value = latest.get(SignalTagType.ENTER_TAG.value, None) + enter_tag = latest.get(SignalTagType.ENTER_TAG.value, None) - enter_tag_value = enter_tag_value if isinstance(enter_tag_value, str) else None + enter_tag = enter_tag if isinstance(enter_tag, str) and enter_tag != 'nan' else None timeframe_seconds = timeframe_to_seconds(timeframe) @@ -1058,11 +1058,11 @@ class IStrategy(ABC, HyperStrategyMixin): timeframe_seconds=timeframe_seconds, enter=bool(enter_signal) ): - return None, enter_tag_value + return None, enter_tag logger.debug(f"entry trigger: {latest['date']} (pair={pair}) " - f"enter={enter_long} enter_tag_value={enter_tag_value}") - return enter_signal, enter_tag_value + f"enter={enter_long} enter_tag_value={enter_tag}") + return enter_signal, enter_tag def ignore_expired_candle( self, From b8a6330c3f662080f868a0d39b56f132ead6ae15 Mon Sep 17 00:00:00 2001 From: Matthias Date: Mon, 30 Oct 2023 19:16:22 +0100 Subject: [PATCH 6/7] Improve pandas handling --- freqtrade/optimize/hyperopt_tools.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/freqtrade/optimize/hyperopt_tools.py b/freqtrade/optimize/hyperopt_tools.py index 6bbf3c15d..ee03aae1a 100644 --- a/freqtrade/optimize/hyperopt_tools.py +++ b/freqtrade/optimize/hyperopt_tools.py @@ -429,14 +429,18 @@ class HyperoptTools: trials = trials.drop(columns=['Total profit']) if print_colorized: + trials2 = trials.astype(str) for i in range(len(trials)): if trials.loc[i]['is_profit']: for j in range(len(trials.loc[i]) - 3): - trials.iat[i, j] = f"{Fore.GREEN}{str(trials.loc[i][j])}{Fore.RESET}" + trials2.iat[i, j] = f"{Fore.GREEN}{str(trials.iloc[i, j])}{Fore.RESET}" if trials.loc[i]['is_best'] and highlight_best: for j in range(len(trials.loc[i]) - 3): - trials.iat[i, j] = f"{Style.BRIGHT}{str(trials.loc[i][j])}{Style.RESET_ALL}" - + trials2.iat[i, j] = ( + f"{Style.BRIGHT}{str(trials.iloc[i, j])}{Style.RESET_ALL}" + ) + trials = trials2 + del trials2 trials = trials.drop(columns=['is_initial_point', 'is_best', 'is_profit', 'is_random']) if remove_header > 0: table = tabulate.tabulate( From 04cd931cc8822eee7b0336d3fd99745c3d3741b8 Mon Sep 17 00:00:00 2001 From: Matthias Date: Mon, 30 Oct 2023 19:20:59 +0100 Subject: [PATCH 7/7] Pass explicit stringIO type to pandas read_json --- freqtrade/misc.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/freqtrade/misc.py b/freqtrade/misc.py index cbebf99eb..bd4f17d05 100644 --- a/freqtrade/misc.py +++ b/freqtrade/misc.py @@ -3,6 +3,7 @@ Various tool function for Freqtrade and scripts """ import gzip import logging +from io import StringIO from pathlib import Path from typing import Any, Dict, Iterator, List, Mapping, Optional, TextIO, Union from urllib.parse import urlparse @@ -231,7 +232,7 @@ def json_to_dataframe(data: str) -> pd.DataFrame: :param data: A JSON string :returns: A pandas DataFrame from the JSON string """ - dataframe = pd.read_json(data, orient='split') + dataframe = pd.read_json(StringIO(data), orient='split') if 'date' in dataframe.columns: dataframe['date'] = pd.to_datetime(dataframe['date'], unit='ms', utc=True)