mirror of
https://github.com/freqtrade/freqtrade.git
synced 2026-01-20 14:00:38 +00:00
Merge branch 'freqtrade:develop' into develop
This commit is contained in:
Binary file not shown.
Binary file not shown.
@@ -1,6 +1,6 @@
|
||||
markdown==3.6
|
||||
mkdocs==1.6.0
|
||||
mkdocs-material==9.5.22
|
||||
mkdocs-material==9.5.23
|
||||
mdx_truly_sane_lists==1.3
|
||||
pymdown-extensions==10.8.1
|
||||
jinja2==3.1.4
|
||||
|
||||
@@ -17,4 +17,6 @@ class Bingx(Exchange):
|
||||
|
||||
_ft_has: Dict = {
|
||||
"ohlcv_candle_limit": 1000,
|
||||
"stoploss_on_exchange": False,
|
||||
"stoploss_order_types": {"limit": "limit", "market": "market"},
|
||||
}
|
||||
|
||||
@@ -10,23 +10,26 @@ individual needs.
|
||||
|
||||
from pandas import DataFrame
|
||||
|
||||
from freqtrade.constants import Config
|
||||
from freqtrade.data.metrics import calculate_max_drawdown
|
||||
from freqtrade.optimize.hyperopt import IHyperOptLoss
|
||||
|
||||
|
||||
# higher numbers penalize drawdowns more severely
|
||||
# smaller numbers penalize drawdowns more severely
|
||||
DRAWDOWN_MULT = 0.075
|
||||
|
||||
|
||||
class ProfitDrawDownHyperOptLoss(IHyperOptLoss):
|
||||
@staticmethod
|
||||
def hyperopt_loss_function(results: DataFrame, trade_count: int, *args, **kwargs) -> float:
|
||||
def hyperopt_loss_function(results: DataFrame, config: Config, *args, **kwargs) -> float:
|
||||
total_profit = results["profit_abs"].sum()
|
||||
|
||||
try:
|
||||
drawdown = calculate_max_drawdown(results, value_col="profit_abs")
|
||||
drawdown = calculate_max_drawdown(
|
||||
results, starting_balance=config["dry_run_wallet"], value_col="profit_abs"
|
||||
)
|
||||
relative_account_drawdown = drawdown.relative_account_drawdown
|
||||
except ValueError:
|
||||
relative_account_drawdown = 0
|
||||
|
||||
return -1 * (total_profit * (1 - relative_account_drawdown * DRAWDOWN_MULT))
|
||||
return -1 * (total_profit - (relative_account_drawdown * total_profit) / DRAWDOWN_MULT)
|
||||
|
||||
@@ -358,14 +358,15 @@ class HyperoptTools:
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def prepare_trials_columns(trials: pd.DataFrame, has_drawdown: bool) -> pd.DataFrame:
|
||||
def prepare_trials_columns(trials: pd.DataFrame) -> pd.DataFrame:
|
||||
trials["Best"] = ""
|
||||
|
||||
if "results_metrics.winsdrawslosses" not in trials.columns:
|
||||
# Ensure compatibility with older versions of hyperopt results
|
||||
trials["results_metrics.winsdrawslosses"] = "N/A"
|
||||
|
||||
if not has_drawdown:
|
||||
has_account_drawdown = "results_metrics.max_drawdown_account" in trials.columns
|
||||
if not has_account_drawdown:
|
||||
# Ensure compatibility with older versions of hyperopt results
|
||||
trials["results_metrics.max_drawdown_account"] = None
|
||||
if "is_random" not in trials.columns:
|
||||
@@ -389,7 +390,6 @@ class HyperoptTools:
|
||||
"results_metrics.profit_total_abs",
|
||||
"results_metrics.profit_total",
|
||||
"results_metrics.holding_avg",
|
||||
"results_metrics.max_drawdown",
|
||||
"results_metrics.max_drawdown_account",
|
||||
"results_metrics.max_drawdown_abs",
|
||||
"loss",
|
||||
@@ -408,7 +408,6 @@ class HyperoptTools:
|
||||
"Total profit",
|
||||
"Profit",
|
||||
"Avg duration",
|
||||
"max_drawdown",
|
||||
"max_drawdown_account",
|
||||
"max_drawdown_abs",
|
||||
"Objective",
|
||||
@@ -437,9 +436,7 @@ class HyperoptTools:
|
||||
tabulate.PRESERVE_WHITESPACE = True
|
||||
trials = json_normalize(results, max_level=1)
|
||||
|
||||
has_account_drawdown = "results_metrics.max_drawdown_account" in trials.columns
|
||||
|
||||
trials = HyperoptTools.prepare_trials_columns(trials, has_account_drawdown)
|
||||
trials = HyperoptTools.prepare_trials_columns(trials)
|
||||
|
||||
trials["is_profit"] = False
|
||||
trials.loc[trials["is_initial_point"] | trials["is_random"], "Best"] = "* "
|
||||
@@ -471,23 +468,19 @@ class HyperoptTools:
|
||||
|
||||
stake_currency = config["stake_currency"]
|
||||
|
||||
trials[f"Max Drawdown{' (Acct)' if has_account_drawdown else ''}"] = trials.apply(
|
||||
trials["Max Drawdown (Acct)"] = trials.apply(
|
||||
lambda x: (
|
||||
"{} {}".format(
|
||||
fmt_coin(x["max_drawdown_abs"], stake_currency, keep_trailing_zeros=True),
|
||||
(
|
||||
f"({x['max_drawdown_account']:,.2%})"
|
||||
if has_account_drawdown
|
||||
else f"({x['max_drawdown']:,.2%})"
|
||||
).rjust(10, " "),
|
||||
(f"({x['max_drawdown_account']:,.2%})").rjust(10, " "),
|
||||
).rjust(25 + len(stake_currency))
|
||||
if x["max_drawdown"] != 0.0 or x["max_drawdown_account"] != 0.0
|
||||
if x["max_drawdown_account"] != 0.0
|
||||
else "--".rjust(25 + len(stake_currency))
|
||||
),
|
||||
axis=1,
|
||||
)
|
||||
|
||||
trials = trials.drop(columns=["max_drawdown_abs", "max_drawdown", "max_drawdown_account"])
|
||||
trials = trials.drop(columns=["max_drawdown_abs", "max_drawdown_account"])
|
||||
|
||||
trials["Profit"] = trials.apply(
|
||||
lambda x: (
|
||||
|
||||
@@ -497,7 +497,6 @@ def generate_strategy_stats(
|
||||
}
|
||||
|
||||
try:
|
||||
max_drawdown_legacy = calculate_max_drawdown(results, value_col="profit_ratio")
|
||||
drawdown = calculate_max_drawdown(
|
||||
results, value_col="profit_abs", starting_balance=start_balance
|
||||
)
|
||||
@@ -508,7 +507,6 @@ def generate_strategy_stats(
|
||||
|
||||
strat_stats.update(
|
||||
{
|
||||
"max_drawdown": max_drawdown_legacy.drawdown_abs, # Deprecated - do not use
|
||||
"max_drawdown_account": drawdown.relative_account_drawdown,
|
||||
"max_relative_drawdown": underwater.relative_account_drawdown,
|
||||
"max_drawdown_abs": drawdown.drawdown_abs,
|
||||
@@ -527,7 +525,6 @@ def generate_strategy_stats(
|
||||
except ValueError:
|
||||
strat_stats.update(
|
||||
{
|
||||
"max_drawdown": 0.0,
|
||||
"max_drawdown_account": 0.0,
|
||||
"max_relative_drawdown": 0.0,
|
||||
"max_drawdown_abs": 0.0,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import logging
|
||||
from ipaddress import IPv4Address
|
||||
from ipaddress import ip_address
|
||||
from typing import Any, Optional
|
||||
|
||||
import orjson
|
||||
@@ -180,7 +180,7 @@ class ApiServer(RPCHandler):
|
||||
rest_port = self._config["api_server"]["listen_port"]
|
||||
|
||||
logger.info(f"Starting HTTP Server at {rest_ip}:{rest_port}")
|
||||
if not IPv4Address(rest_ip).is_loopback and not running_in_docker():
|
||||
if not ip_address(rest_ip).is_loopback and not running_in_docker():
|
||||
logger.warning("SECURITY WARNING - Local Rest Server listening to external connections")
|
||||
logger.warning(
|
||||
"SECURITY WARNING - This is insecure please set to your loopback,"
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
# Requirements for freqtrade client library
|
||||
requests==2.31.0
|
||||
python-rapidjson==1.16
|
||||
python-rapidjson==1.17
|
||||
|
||||
@@ -6,12 +6,12 @@
|
||||
-r requirements-freqai-rl.txt
|
||||
-r docs/requirements-docs.txt
|
||||
|
||||
coveralls==4.0.0
|
||||
coveralls==4.0.1
|
||||
ruff==0.4.4
|
||||
mypy==1.10.0
|
||||
pre-commit==3.7.1
|
||||
pytest==8.2.0
|
||||
pytest-asyncio==0.23.6
|
||||
pytest==8.2.1
|
||||
pytest-asyncio==0.23.7
|
||||
pytest-cov==5.0.0
|
||||
pytest-mock==3.14.0
|
||||
pytest-random-order==1.1.1
|
||||
|
||||
@@ -2,7 +2,7 @@ numpy==1.26.4
|
||||
pandas==2.2.2
|
||||
pandas-ta==0.3.14b
|
||||
|
||||
ccxt==4.3.24
|
||||
ccxt==4.3.27
|
||||
cryptography==42.0.7
|
||||
aiohttp==3.9.5
|
||||
SQLAlchemy==2.0.30
|
||||
@@ -22,13 +22,13 @@ jinja2==3.1.4
|
||||
tables==3.9.1
|
||||
joblib==1.4.2
|
||||
rich==13.7.1
|
||||
pyarrow==16.0.0; platform_machine != 'armv7l'
|
||||
pyarrow==16.1.0; platform_machine != 'armv7l'
|
||||
|
||||
# find first, C search in arrays
|
||||
py_find_1st==1.1.6
|
||||
|
||||
# Load ticker files 30% faster
|
||||
python-rapidjson==1.16
|
||||
python-rapidjson==1.17
|
||||
# Properly format api responses
|
||||
orjson==3.10.3
|
||||
|
||||
|
||||
@@ -54,6 +54,7 @@ from tests.conftest import (
|
||||
patch_exchange,
|
||||
patched_configuration_load_config_file,
|
||||
)
|
||||
from tests.conftest_hyperopt import hyperopt_test_result
|
||||
from tests.conftest_trades import MOCK_TRADE_COUNT
|
||||
|
||||
|
||||
@@ -1137,7 +1138,8 @@ def test_start_test_pairlist(mocker, caplog, tickers, default_conf, capsys):
|
||||
pytest.fail(f"Expected well formed JSON, but failed to parse: {captured.out}")
|
||||
|
||||
|
||||
def test_hyperopt_list(mocker, capsys, caplog, saved_hyperopt_results, tmp_path):
|
||||
def test_hyperopt_list(mocker, capsys, caplog, tmp_path):
|
||||
saved_hyperopt_results = hyperopt_test_result()
|
||||
csv_file = tmp_path / "test.csv"
|
||||
mocker.patch(
|
||||
"freqtrade.optimize.hyperopt_tools.HyperoptTools._test_hyperopt_results_exist",
|
||||
@@ -1507,7 +1509,8 @@ def test_hyperopt_list(mocker, capsys, caplog, saved_hyperopt_results, tmp_path)
|
||||
csv_file.unlink()
|
||||
|
||||
|
||||
def test_hyperopt_show(mocker, capsys, saved_hyperopt_results):
|
||||
def test_hyperopt_show(mocker, capsys):
|
||||
saved_hyperopt_results = hyperopt_test_result()
|
||||
mocker.patch(
|
||||
"freqtrade.optimize.hyperopt_tools.HyperoptTools._test_hyperopt_results_exist",
|
||||
return_value=True,
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
1000
tests/conftest_hyperopt.py
Normal file
1000
tests/conftest_hyperopt.py
Normal file
File diff suppressed because it is too large
Load Diff
@@ -47,7 +47,7 @@ def generate_result_metrics():
|
||||
"profit_total_abs": 0.001,
|
||||
"profit_total": 0.01,
|
||||
"holding_avg": timedelta(minutes=20),
|
||||
"max_drawdown": 0.001,
|
||||
"max_drawdown_account": 0.001,
|
||||
"max_drawdown_abs": 0.001,
|
||||
"loss": 0.001,
|
||||
"is_initial_point": 0.001,
|
||||
|
||||
@@ -52,7 +52,7 @@ class HyperoptableStrategy(StrategyTestV3):
|
||||
bot_loop_started = False
|
||||
bot_started = False
|
||||
|
||||
def bot_loop_start(self):
|
||||
def bot_loop_start(self, **kwargs):
|
||||
self.bot_loop_started = True
|
||||
|
||||
def bot_start(self, **kwargs) -> None:
|
||||
|
||||
@@ -48,7 +48,7 @@ class HyperoptableStrategyV2(StrategyTestV2):
|
||||
|
||||
bot_loop_started = False
|
||||
|
||||
def bot_loop_start(self):
|
||||
def bot_loop_start(self, **kwargs):
|
||||
self.bot_loop_started = True
|
||||
|
||||
def bot_start(self, **kwargs) -> None:
|
||||
|
||||
Reference in New Issue
Block a user