From 033050e6cf9bade7a629e3116f68d09e929d454a Mon Sep 17 00:00:00 2001 From: dev-starlight <50508216+dev-starlight@users.noreply.github.com> Date: Tue, 11 Nov 2025 17:00:56 +0800 Subject: [PATCH 1/6] read text encoding='utf-8' --- freqtrade/resolvers/iresolver.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/freqtrade/resolvers/iresolver.py b/freqtrade/resolvers/iresolver.py index b437166e7..0462d5ce0 100644 --- a/freqtrade/resolvers/iresolver.py +++ b/freqtrade/resolvers/iresolver.py @@ -148,7 +148,7 @@ class IResolver: logger.debug("Ignoring broken symlink %s", entry) continue module_path = entry.resolve() - if entry.read_text().find(f"class {object_name}(") == -1: + if entry.read_text(encoding='utf-8').find(f"class {object_name}(") == -1: logger.debug(f"Skipping {module_path} as it does not contain class {object_name}.") continue From 8caf7a888eda9a4b140d2d077bfc7eeabd491f20 Mon Sep 17 00:00:00 2001 From: dev-starlight <50508216+dev-starlight@users.noreply.github.com> Date: Tue, 11 Nov 2025 17:02:36 +0800 Subject: [PATCH 2/6] Add UTF-8 encoding to read_text method --- freqtrade/configuration/load_config.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/freqtrade/configuration/load_config.py b/freqtrade/configuration/load_config.py index e18707a99..51d0d381f 100644 --- a/freqtrade/configuration/load_config.py +++ b/freqtrade/configuration/load_config.py @@ -30,7 +30,7 @@ def log_config_error_range(path: str, errmsg: str) -> str: offsetlist = re.findall(r"(?<=Parse\serror\sat\soffset\s)\d+", errmsg) if offsetlist: offset = int(offsetlist[0]) - text = Path(path).read_text() + text = Path(path).read_text(encoding='utf-8') # Fetch an offset of 80 characters around the error line subtext = text[offset - min(80, offset) : offset + 80] segments = subtext.split("\n") From 6cef73947c4aea090c1a99b81854ccfb780f5ee8 Mon Sep 17 00:00:00 2001 From: Matthias Date: Thu, 27 Nov 2025 06:45:06 +0100 Subject: [PATCH 3/6] chore: apply formatting --- freqtrade/configuration/load_config.py | 2 +- freqtrade/resolvers/iresolver.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/freqtrade/configuration/load_config.py b/freqtrade/configuration/load_config.py index 51d0d381f..d3bc91002 100644 --- a/freqtrade/configuration/load_config.py +++ b/freqtrade/configuration/load_config.py @@ -30,7 +30,7 @@ def log_config_error_range(path: str, errmsg: str) -> str: offsetlist = re.findall(r"(?<=Parse\serror\sat\soffset\s)\d+", errmsg) if offsetlist: offset = int(offsetlist[0]) - text = Path(path).read_text(encoding='utf-8') + text = Path(path).read_text(encoding="utf-8") # Fetch an offset of 80 characters around the error line subtext = text[offset - min(80, offset) : offset + 80] segments = subtext.split("\n") diff --git a/freqtrade/resolvers/iresolver.py b/freqtrade/resolvers/iresolver.py index 0462d5ce0..b51293615 100644 --- a/freqtrade/resolvers/iresolver.py +++ b/freqtrade/resolvers/iresolver.py @@ -148,7 +148,7 @@ class IResolver: logger.debug("Ignoring broken symlink %s", entry) continue module_path = entry.resolve() - if entry.read_text(encoding='utf-8').find(f"class {object_name}(") == -1: + if entry.read_text(encoding="utf-8").find(f"class {object_name}(") == -1: logger.debug(f"Skipping {module_path} as it does not contain class {object_name}.") continue From 3543437fc58d5be546a9ca10c44d8397f0dcde3a Mon Sep 17 00:00:00 2001 From: Matthias Date: Fri, 2 Jan 2026 12:01:35 +0000 Subject: [PATCH 4/6] test: add test chinese comment to strategy_test file --- tests/strategy/strats/strategy_test_v2.py | 10 ++++++++++ tests/strategy/strats/strategy_test_v3.py | 10 ++++++++++ 2 files changed, 20 insertions(+) diff --git a/tests/strategy/strats/strategy_test_v2.py b/tests/strategy/strats/strategy_test_v2.py index 58473e9c0..04d218bc6 100644 --- a/tests/strategy/strats/strategy_test_v2.py +++ b/tests/strategy/strats/strategy_test_v2.py @@ -14,6 +14,16 @@ class StrategyTestV2(IStrategy): Please look at the SampleStrategy in the user_data/strategy directory or strategy repository https://github.com/freqtrade/freqtrade-strategies for samples and inspiration. + + --- + + Some test asian characters. + Ensures that unicode characters are handled correctly when reading strategy files. + Otherwise this may break on windows systems. + All roughly translate to "hello world". + chinese string: "你好世界" + korean string: "안녕하세요,세계" + japanese string: "こんにちは、世界" """ INTERFACE_VERSION = 2 diff --git a/tests/strategy/strats/strategy_test_v3.py b/tests/strategy/strats/strategy_test_v3.py index e87810111..993b04d4b 100644 --- a/tests/strategy/strats/strategy_test_v3.py +++ b/tests/strategy/strats/strategy_test_v3.py @@ -23,6 +23,16 @@ class StrategyTestV3(IStrategy): Please look at the SampleStrategy in the user_data/strategy directory or strategy repository https://github.com/freqtrade/freqtrade-strategies for samples and inspiration. + + --- + + Some test asian characters. + Ensures that unicode characters are handled correctly when reading strategy files. + Otherwise this may break on windows systems. + All roughly translate to "hello world". + chinese string: "你好世界" + korean string: "안녕하세요,세계" + japanese string: "こんにちは、世界" """ INTERFACE_VERSION = 3 From bc2be74b3623b64b75571af0d95d519fe250f3b2 Mon Sep 17 00:00:00 2001 From: Matthias Date: Fri, 2 Jan 2026 12:20:09 +0000 Subject: [PATCH 5/6] fix: further fixes for utf8 reading on windows --- tests/rpc/test_rpc_apiserver.py | 4 +++- tests/test_strategy_updater.py | 4 ++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/tests/rpc/test_rpc_apiserver.py b/tests/rpc/test_rpc_apiserver.py index f7f99f288..0aad24602 100644 --- a/tests/rpc/test_rpc_apiserver.py +++ b/tests/rpc/test_rpc_apiserver.py @@ -2496,7 +2496,9 @@ def test_api_strategy(botclient, tmp_path, mocker): assert_response(rc) assert rc.json()["strategy"] == CURRENT_TEST_STRATEGY - data = (Path(__file__).parents[1] / "strategy/strats/strategy_test_v3.py").read_text() + data = (Path(__file__).parents[1] / "strategy/strats/strategy_test_v3.py").read_text( + encoding="utf-8" + ) assert rc.json()["code"] == data rc = client_get(client, f"{BASE_URI}/strategy/NoStrat") diff --git a/tests/test_strategy_updater.py b/tests/test_strategy_updater.py index 48f1d27d7..3c53f425e 100644 --- a/tests/test_strategy_updater.py +++ b/tests/test_strategy_updater.py @@ -15,7 +15,7 @@ def test_strategy_updater_start(user_dir, capsys) -> None: tmpdirp = Path(user_dir) / "strategies" tmpdirp.mkdir(parents=True, exist_ok=True) shutil.copy(teststrats / "strategy_test_v2.py", tmpdirp) - old_code = (teststrats / "strategy_test_v2.py").read_text() + old_code = (teststrats / "strategy_test_v2.py").read_text(encoding="utf-8") args = ["strategy-updater", "--userdir", str(user_dir), "--strategy-list", "StrategyTestV2"] pargs = get_args(args) @@ -29,7 +29,7 @@ def test_strategy_updater_start(user_dir, capsys) -> None: # updated file exists new_file = tmpdirp / "strategy_test_v2.py" assert new_file.exists() - new_code = new_file.read_text() + new_code = new_file.read_text(encoding="utf-8") assert "INTERFACE_VERSION = 3" in new_code assert "INTERFACE_VERSION = 2" in old_code captured = capsys.readouterr() From 00bd3e5a5c7b9c9f183f2579729c6c07ec6464c6 Mon Sep 17 00:00:00 2001 From: Matthias Date: Fri, 2 Jan 2026 12:42:12 +0000 Subject: [PATCH 6/6] fix: strategy-updater should support non-english characters on windows --- freqtrade/strategy/strategyupdater.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/freqtrade/strategy/strategyupdater.py b/freqtrade/strategy/strategyupdater.py index 5377865d7..965f6bcd6 100644 --- a/freqtrade/strategy/strategyupdater.py +++ b/freqtrade/strategy/strategyupdater.py @@ -66,8 +66,7 @@ class StrategyUpdater: target_file = Path.joinpath(strategies_backup_folder, strategy_obj["location_rel"]) # read the file - with Path(source_file).open("r") as f: - old_code = f.read() + old_code = Path(source_file).read_text(encoding="utf-8") if not strategies_backup_folder.is_dir(): Path(strategies_backup_folder).mkdir(parents=True, exist_ok=True) @@ -80,8 +79,7 @@ class StrategyUpdater: # update the code new_code = self.update_code(old_code) # write the modified code to the destination folder - with Path(source_file).open("w") as f: - f.write(new_code) + Path(source_file).write_text(new_code, encoding="utf-8") # define the function to update the code def update_code(self, code):