From 9041000bc40b83a756dd69239b3942cdc079775a Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 19 Oct 2025 12:05:52 +0200 Subject: [PATCH 1/6] fix: attempt to work around deprecation message --- freqtrade/optimize/hyperopt/hyperopt_optimizer.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/freqtrade/optimize/hyperopt/hyperopt_optimizer.py b/freqtrade/optimize/hyperopt/hyperopt_optimizer.py index f1b3f7cdd..91703b6c1 100644 --- a/freqtrade/optimize/hyperopt/hyperopt_optimizer.py +++ b/freqtrade/optimize/hyperopt/hyperopt_optimizer.py @@ -7,7 +7,7 @@ import logging import sys import warnings from datetime import UTC, datetime -from multiprocessing import Manager +from multiprocessing import Manager, get_all_start_methods, set_start_method from pathlib import Path from typing import Any @@ -125,6 +125,12 @@ class HyperOptimizer: local_queue must be a global and passed to the child process via inheritance. """ global log_queue + try: + sms = get_all_start_methods() + if "forkserver" in sms: + set_start_method("forkserver") + except RuntimeError: + pass # start method has already been set m = Manager() log_queue = m.Queue() logger.info(f"manager queue {type(log_queue)}") From 8d95ca35063dc4e2ec6e7456e86c5659f7cc13c9 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 19 Oct 2025 16:32:25 +0200 Subject: [PATCH 2/6] chore: disable deprecationWarning Very targeted at 'CatBoostClassifier' object has no attribute '__sklearn_tags__' --- tests/freqai/test_freqai_interface.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/freqai/test_freqai_interface.py b/tests/freqai/test_freqai_interface.py index 0710591c9..3e7e96d85 100644 --- a/tests/freqai/test_freqai_interface.py +++ b/tests/freqai/test_freqai_interface.py @@ -143,6 +143,7 @@ def test_extract_data_and_train_model_Standard( ("CatboostClassifierMultiTarget", "freqai_test_multimodel_classifier_strat"), ], ) +@pytest.mark.filterwarnings(r"ignore:.*__sklearn_tags__.*:DeprecationWarning") def test_extract_data_and_train_model_MultiTargets(mocker, freqai_conf, model, strat): can_run_model(model) From 886d5d1db6c998290472ecb859dd3690ef7a91e5 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 19 Oct 2025 16:45:13 +0200 Subject: [PATCH 3/6] chore: update catboost install --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 4bac06296..203faabfa 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -85,7 +85,7 @@ hyperopt = [ freqai = [ "scikit-learn", "joblib", - 'catboost; platform_machine != "aarch64"', + 'catboost; platform_machine != "arm"', "lightgbm", "xgboost", "tensorboard", From 763f08a08e1c1ec57751ba4823f4eb1897e1ae05 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 19 Oct 2025 16:46:33 +0200 Subject: [PATCH 4/6] test: test catboost on aarch64 runners --- tests/commands/test_startup_time.py | 2 +- tests/conftest.py | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/tests/commands/test_startup_time.py b/tests/commands/test_startup_time.py index 62baab20a..32b4f80fd 100644 --- a/tests/commands/test_startup_time.py +++ b/tests/commands/test_startup_time.py @@ -4,7 +4,7 @@ import time from tests.conftest import is_arm, is_mac -MAXIMUM_STARTUP_TIME = 0.7 if is_mac() and not is_arm() else 0.5 +MAXIMUM_STARTUP_TIME = 0.7 if is_mac() and not is_arm(True) else 0.5 def test_startup_time(): diff --git a/tests/conftest.py b/tests/conftest.py index a390dea07..ca9239375 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -500,9 +500,11 @@ def patch_gc(mocker) -> None: mocker.patch("freqtrade.main.gc_set_threshold") -def is_arm() -> bool: +def is_arm(include_aarch64: bool = False) -> bool: machine = platform.machine() - return "arm" in machine or "aarch64" in machine + if include_aarch64: + return "aarch64" in machine or "arm" in machine + return "arm" in machine def is_mac() -> bool: From 161e5e3dfa35f6a32dbe5362ca176b3794d532c9 Mon Sep 17 00:00:00 2001 From: Matthias Date: Mon, 20 Oct 2025 19:28:14 +0200 Subject: [PATCH 5/6] refactor: switch mp-method to forkserver globally --- freqtrade/main.py | 8 +++++++- freqtrade/optimize/hyperopt/hyperopt_optimizer.py | 8 +------- freqtrade/system/__init__.py | 3 ++- freqtrade/system/set_mp_start_method.py | 14 ++++++++++++++ 4 files changed, 24 insertions(+), 9 deletions(-) create mode 100644 freqtrade/system/set_mp_start_method.py diff --git a/freqtrade/main.py b/freqtrade/main.py index fd142452a..6720e5eeb 100755 --- a/freqtrade/main.py +++ b/freqtrade/main.py @@ -18,7 +18,12 @@ from freqtrade.commands import Arguments from freqtrade.constants import DOCS_LINK from freqtrade.exceptions import ConfigurationError, FreqtradeException, OperationalException from freqtrade.loggers import setup_logging_pre -from freqtrade.system import asyncio_setup, gc_set_threshold, print_version_info +from freqtrade.system import ( + asyncio_setup, + gc_set_threshold, + print_version_info, + set_mp_start_method, +) logger = logging.getLogger("freqtrade") @@ -44,6 +49,7 @@ def main(sysargv: list[str] | None = None) -> None: elif "func" in args: logger.info(f"freqtrade {__version__}") gc_set_threshold() + set_mp_start_method() return_code = args["func"](args) else: # No subcommand was issued. diff --git a/freqtrade/optimize/hyperopt/hyperopt_optimizer.py b/freqtrade/optimize/hyperopt/hyperopt_optimizer.py index 91703b6c1..f1b3f7cdd 100644 --- a/freqtrade/optimize/hyperopt/hyperopt_optimizer.py +++ b/freqtrade/optimize/hyperopt/hyperopt_optimizer.py @@ -7,7 +7,7 @@ import logging import sys import warnings from datetime import UTC, datetime -from multiprocessing import Manager, get_all_start_methods, set_start_method +from multiprocessing import Manager from pathlib import Path from typing import Any @@ -125,12 +125,6 @@ class HyperOptimizer: local_queue must be a global and passed to the child process via inheritance. """ global log_queue - try: - sms = get_all_start_methods() - if "forkserver" in sms: - set_start_method("forkserver") - except RuntimeError: - pass # start method has already been set m = Manager() log_queue = m.Queue() logger.info(f"manager queue {type(log_queue)}") diff --git a/freqtrade/system/__init__.py b/freqtrade/system/__init__.py index e69e90de8..9bb472d01 100644 --- a/freqtrade/system/__init__.py +++ b/freqtrade/system/__init__.py @@ -2,7 +2,8 @@ from freqtrade.system.asyncio_config import asyncio_setup from freqtrade.system.gc_setup import gc_set_threshold +from freqtrade.system.set_mp_start_method import set_mp_start_method from freqtrade.system.version_info import print_version_info -__all__ = ["asyncio_setup", "gc_set_threshold", "print_version_info"] +__all__ = ["asyncio_setup", "gc_set_threshold", "print_version_info", "set_mp_start_method"] diff --git a/freqtrade/system/set_mp_start_method.py b/freqtrade/system/set_mp_start_method.py new file mode 100644 index 000000000..34b7051c5 --- /dev/null +++ b/freqtrade/system/set_mp_start_method.py @@ -0,0 +1,14 @@ +from multiprocessing import get_all_start_methods, get_start_method, set_start_method + + +def set_mp_start_method(): + """ + Set multiprocessing start method to not be fork. + forkserver will become the default in 3.14 - and is deprecated in 3.13 + """ + try: + sms = get_all_start_methods() + if "forkserver" in sms and get_start_method(True) is None: + set_start_method("forkserver") + except RuntimeError: + pass From f4656a0c6e70aab9e1ff8c3fd8ead2c892cf5dac Mon Sep 17 00:00:00 2001 From: Matthias Date: Mon, 20 Oct 2025 19:29:03 +0200 Subject: [PATCH 6/6] test: ensure mp_start runs on startup --- tests/conftest.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/tests/conftest.py b/tests/conftest.py index ca9239375..93144ffc4 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -21,6 +21,7 @@ from freqtrade.exchange import Exchange, timeframe_to_minutes, timeframe_to_seco from freqtrade.freqtradebot import FreqtradeBot from freqtrade.persistence import LocalTrade, Order, Trade, init_db from freqtrade.resolvers import ExchangeResolver +from freqtrade.system import set_mp_start_method from freqtrade.util import dt_now, dt_ts from freqtrade.worker import Worker from tests.conftest_trades import ( @@ -500,6 +501,15 @@ def patch_gc(mocker) -> None: mocker.patch("freqtrade.main.gc_set_threshold") +@pytest.fixture(scope="session", autouse=True) +def fixture_set_mp_start_method(): + """ + Patch multiprocessing start mode globally + Auto-used, runs once per session. + """ + set_mp_start_method() + + def is_arm(include_aarch64: bool = False) -> bool: machine = platform.machine() if include_aarch64: