Merge branch 'freqtrade:develop' into develop

This commit is contained in:
Simon Waiblinger
2024-05-20 11:10:58 +02:00
committed by GitHub
17 changed files with 1035 additions and 1035 deletions

View File

@@ -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

View File

@@ -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"},
}

View File

@@ -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)

View File

@@ -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: (

View File

@@ -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,

View File

@@ -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,"

View File

@@ -1,3 +1,3 @@
# Requirements for freqtrade client library
requests==2.31.0
python-rapidjson==1.16
python-rapidjson==1.17

View File

@@ -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

View File

@@ -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

View File

@@ -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

File diff suppressed because it is too large Load Diff

View File

@@ -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,

View File

@@ -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:

View File

@@ -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: