mirror of
https://github.com/freqtrade/freqtrade.git
synced 2025-11-29 00:23:07 +00:00
Merge remote-tracking branch 'origin/develop' into develop
This commit is contained in:
10
.github/workflows/ci.yml
vendored
10
.github/workflows/ci.yml
vendored
@@ -65,9 +65,12 @@ jobs:
|
||||
export LD_LIBRARY_PATH=${HOME}/dependencies/lib:$LD_LIBRARY_PATH
|
||||
export TA_LIBRARY_PATH=${HOME}/dependencies/lib
|
||||
export TA_INCLUDE_PATH=${HOME}/dependencies/include
|
||||
echo "numpy<2.3.0" > constraints.txt
|
||||
export UV_BUILD_CONSTRAINT=constraints.txt
|
||||
uv pip install -r requirements-dev.txt
|
||||
uv pip install -e ft_client/
|
||||
uv pip install -e .
|
||||
rm constraints.txt
|
||||
|
||||
- name: Check for version alignment
|
||||
run: |
|
||||
@@ -228,9 +231,12 @@ jobs:
|
||||
export LD_LIBRARY_PATH=${HOME}/dependencies/lib:$LD_LIBRARY_PATH
|
||||
export TA_LIBRARY_PATH=${HOME}/dependencies/lib
|
||||
export TA_INCLUDE_PATH=${HOME}/dependencies/include
|
||||
echo "numpy<2.3.0" > constraints.txt
|
||||
export UV_BUILD_CONSTRAINT=constraints.txt
|
||||
uv pip install -r requirements-dev.txt
|
||||
uv pip install -e ft_client/
|
||||
uv pip install -e .
|
||||
rm constraints.txt
|
||||
|
||||
- name: Tests
|
||||
run: |
|
||||
@@ -480,9 +486,13 @@ jobs:
|
||||
export LD_LIBRARY_PATH=${HOME}/dependencies/lib:$LD_LIBRARY_PATH
|
||||
export TA_LIBRARY_PATH=${HOME}/dependencies/lib
|
||||
export TA_INCLUDE_PATH=${HOME}/dependencies/include
|
||||
echo "numpy<2.3.0" > constraints.txt
|
||||
export UV_BUILD_CONSTRAINT=constraints.txt
|
||||
uv pip install -r requirements-dev.txt
|
||||
uv pip install -e ft_client/
|
||||
uv pip install -e .
|
||||
rm constraints.txt
|
||||
|
||||
|
||||
- name: Tests incl. ccxt compatibility tests
|
||||
env:
|
||||
|
||||
@@ -35,7 +35,9 @@ ENV LD_LIBRARY_PATH /usr/local/lib
|
||||
# Install dependencies
|
||||
COPY --chown=ftuser:ftuser requirements.txt requirements-hyperopt.txt /freqtrade/
|
||||
USER ftuser
|
||||
RUN pip install --user --no-cache-dir "numpy<3.0" \
|
||||
RUN pip install --user --no-cache-dir "numpy<2.3.0" \
|
||||
&& echo "numpy<2.3.0" > /tmp/constraints.txt \
|
||||
&& export PIP_CONSTRAINT=/tmp/constraints.txt \
|
||||
&& pip install --user --no-cache-dir -r requirements-hyperopt.txt
|
||||
|
||||
# Copy dependencies to runtime-image
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
python -m pip install --upgrade pip
|
||||
python -c "import sys; print(f'{sys.version_info.major}.{sys.version_info.minor}')"
|
||||
|
||||
pip install -U wheel "numpy<3"
|
||||
pip install -U wheel "numpy<2.3"
|
||||
pip install --only-binary ta-lib --find-links=build_helpers\ ta-lib
|
||||
|
||||
pip install -r requirements-dev.txt
|
||||
|
||||
@@ -1247,7 +1247,11 @@
|
||||
"type": "object"
|
||||
},
|
||||
"ccxt_async_config": {
|
||||
"description": "CCXT asynchronous configuration settings.",
|
||||
"description": "CCXT asynchronous configuration settings.Usually ccxt_config should be used instead.",
|
||||
"type": "object"
|
||||
},
|
||||
"ccxt_sync_config": {
|
||||
"description": "CCXT synchronous configuration settings. Usually ccxt_config should be used instead.",
|
||||
"type": "object"
|
||||
}
|
||||
},
|
||||
|
||||
@@ -34,7 +34,7 @@ COPY build_helpers/* /tmp/
|
||||
# Install dependencies
|
||||
COPY --chown=ftuser:ftuser requirements.txt /freqtrade/
|
||||
USER ftuser
|
||||
RUN pip install --user --no-cache-dir "numpy<3" \
|
||||
RUN pip install --user --no-cache-dir "numpy<2.3.0" \
|
||||
&& pip install --user --no-index --find-links /tmp/ pyarrow TA-Lib \
|
||||
&& pip install --user --no-cache-dir -r requirements.txt
|
||||
|
||||
|
||||
@@ -5,6 +5,8 @@ This page explains how to validate your strategy performance by using Backtestin
|
||||
Backtesting requires historic data to be available.
|
||||
To learn how to get data for the pairs and exchange you're interested in, head over to the [Data Downloading](data-download.md) section of the documentation.
|
||||
|
||||
Backtesting is also available in [webserver mode](freq-ui.md#backtesting), which allows you to run backtests via the web interface.
|
||||
|
||||
## Backtesting command reference
|
||||
|
||||
--8<-- "commands/backtesting.md"
|
||||
@@ -435,6 +437,10 @@ To save time, by default backtest will reuse a cached result from within the las
|
||||
To further analyze your backtest results, freqtrade will export the trades to file by default.
|
||||
You can then load the trades to perform further analysis as shown in the [data analysis](strategy_analysis_example.md#load-backtest-results-to-pandas-dataframe) backtesting section.
|
||||
|
||||
Also, you can use freqtrade in [webserver mode](freq-ui.md#backtesting) to visualize the backtest results in a web interface.
|
||||
This mode also allows you to load existing backtest results, so you can analyze them without running the backtest again.
|
||||
For this mode - `--notes "<notes>"` can be used to add notes to the backtest results, which will be shown in the web interface.
|
||||
|
||||
### Backtest output file
|
||||
|
||||
The output file freqtrade produces is a zip file containing the following files:
|
||||
|
||||
@@ -17,7 +17,7 @@ usage: freqtrade backtesting [-h] [-v] [--no-color] [--logfile FILE] [-V]
|
||||
[--export-filename PATH]
|
||||
[--breakdown {day,week,month,year} [{day,week,month,year} ...]]
|
||||
[--cache {none,day,week,month}]
|
||||
[--freqai-backtest-live-models]
|
||||
[--freqai-backtest-live-models] [--notes TEXT]
|
||||
|
||||
options:
|
||||
-h, --help show this help message and exit
|
||||
@@ -73,6 +73,7 @@ options:
|
||||
age (default: day).
|
||||
--freqai-backtest-live-models
|
||||
Run backtest with ready models.
|
||||
--notes TEXT Add notes to the backtest results.
|
||||
|
||||
Common arguments:
|
||||
-v, --verbose Verbose mode (-vv for more, -vvv to get all messages).
|
||||
|
||||
@@ -57,6 +57,7 @@ ARGS_BACKTEST = [
|
||||
"backtest_breakdown",
|
||||
"backtest_cache",
|
||||
"freqai_backtest_live_models",
|
||||
"backtest_notes",
|
||||
]
|
||||
|
||||
ARGS_HYPEROPT = [
|
||||
@@ -250,7 +251,7 @@ ARGS_STRATEGY_UPDATER = ["strategy_list", "strategy_path", "recursive_strategy_s
|
||||
ARGS_LOOKAHEAD_ANALYSIS = [
|
||||
a
|
||||
for a in ARGS_BACKTEST
|
||||
if a not in ("position_stacking", "backtest_cache", "backtest_breakdown")
|
||||
if a not in ("position_stacking", "backtest_cache", "backtest_breakdown", "backtest_notes")
|
||||
] + ["minimum_trade_amount", "targeted_trade_amount", "lookahead_analysis_exportfilename"]
|
||||
|
||||
ARGS_RECURSIVE_ANALYSIS = ["timeframe", "timerange", "dataformat_ohlcv", "pairs", "startup_candle"]
|
||||
|
||||
@@ -204,6 +204,11 @@ AVAILABLE_CLI_OPTIONS = {
|
||||
help="Export backtest results (default: trades).",
|
||||
choices=constants.EXPORT_OPTIONS,
|
||||
),
|
||||
"backtest_notes": Arg(
|
||||
"--notes",
|
||||
help="Add notes to the backtest results.",
|
||||
metavar="TEXT",
|
||||
),
|
||||
"exportfilename": Arg(
|
||||
"--export-filename",
|
||||
"--backtest-filename",
|
||||
|
||||
@@ -913,7 +913,17 @@ CONF_SCHEMA = {
|
||||
},
|
||||
"ccxt_config": {"description": "CCXT configuration settings.", "type": "object"},
|
||||
"ccxt_async_config": {
|
||||
"description": "CCXT asynchronous configuration settings.",
|
||||
"description": (
|
||||
"CCXT asynchronous configuration settings."
|
||||
"Usually ccxt_config should be used instead."
|
||||
),
|
||||
"type": "object",
|
||||
},
|
||||
"ccxt_sync_config": {
|
||||
"description": (
|
||||
"CCXT synchronous configuration settings. "
|
||||
"Usually ccxt_config should be used instead."
|
||||
),
|
||||
"type": "object",
|
||||
},
|
||||
},
|
||||
|
||||
@@ -310,6 +310,7 @@ class Configuration:
|
||||
("backtest_cache", "Parameter --cache={} detected ..."),
|
||||
("disableparamexport", "Parameter --disableparamexport detected: {} ..."),
|
||||
("freqai_backtest_live_models", "Parameter --freqai-backtest-live-models detected ..."),
|
||||
("backtest_notes", "Parameter --notes detected: {} ..."),
|
||||
]
|
||||
self._args_to_config_loop(config, configurations)
|
||||
|
||||
|
||||
@@ -43,15 +43,27 @@ def _flat_vars_to_nested_dict(env_dict: dict[str, Any], prefix: str) -> dict[str
|
||||
:return: Nested dict based on available and relevant variables.
|
||||
"""
|
||||
no_convert = ["CHAT_ID", "PASSWORD"]
|
||||
ccxt_config_keys = ["ccxt_config", "ccxt_sync_config", "ccxt_async_config"]
|
||||
relevant_vars: dict[str, Any] = {}
|
||||
|
||||
for env_var, val in sorted(env_dict.items()):
|
||||
if env_var.startswith(prefix):
|
||||
logger.info(f"Loading variable '{env_var}'")
|
||||
key = env_var.replace(prefix, "")
|
||||
for k in reversed(key.split("__")):
|
||||
key_parts = key.split("__")
|
||||
logger.info("Key parts: %s", key_parts)
|
||||
|
||||
# Check if any ccxt config key is in the key parts
|
||||
preserve_case = key_parts[0].lower() == "exchange" and any(
|
||||
ccxt_key in [part.lower() for part in key_parts] for ccxt_key in ccxt_config_keys
|
||||
)
|
||||
|
||||
for i, k in enumerate(reversed(key_parts)):
|
||||
# Preserve case for the final key if ccxt config is involved
|
||||
key_name = k if preserve_case and i == 0 else k.lower()
|
||||
|
||||
val = {
|
||||
k.lower(): (
|
||||
key_name: (
|
||||
_get_var_typed(val)
|
||||
if not isinstance(val, dict) and k not in no_convert
|
||||
else val
|
||||
|
||||
@@ -1822,7 +1822,11 @@ class Backtesting:
|
||||
# Update old results with new ones.
|
||||
if len(self.all_bt_content) > 0:
|
||||
results = generate_backtest_stats(
|
||||
data, self.all_bt_content, min_date=min_date, max_date=max_date
|
||||
data,
|
||||
self.all_bt_content,
|
||||
min_date=min_date,
|
||||
max_date=max_date,
|
||||
notes=self.config.get("backtest_notes"),
|
||||
)
|
||||
if self.results:
|
||||
self.results["metadata"].update(results["metadata"])
|
||||
|
||||
@@ -347,7 +347,7 @@ def generate_trading_stats(results: DataFrame) -> dict[str, Any]:
|
||||
else timedelta()
|
||||
)
|
||||
winner_holding_min = (
|
||||
timedelta(minutes=round(winning_duration[winning_duration > 0].min()))
|
||||
timedelta(minutes=round(winning_duration.min()))
|
||||
if not winning_duration.empty
|
||||
else timedelta()
|
||||
)
|
||||
@@ -362,7 +362,7 @@ def generate_trading_stats(results: DataFrame) -> dict[str, Any]:
|
||||
else timedelta()
|
||||
)
|
||||
loser_holding_min = (
|
||||
timedelta(minutes=round(losing_duration[losing_duration > 0].min()))
|
||||
timedelta(minutes=round(losing_duration.min()))
|
||||
if not losing_duration.empty
|
||||
else timedelta()
|
||||
)
|
||||
@@ -669,6 +669,7 @@ def generate_backtest_stats(
|
||||
all_results: dict[str, BacktestContentType],
|
||||
min_date: datetime,
|
||||
max_date: datetime,
|
||||
notes: str | None = None,
|
||||
) -> BacktestResultType:
|
||||
"""
|
||||
:param btdata: Backtest data
|
||||
@@ -694,6 +695,8 @@ def generate_backtest_stats(
|
||||
"backtest_start_ts": int(min_date.timestamp()),
|
||||
"backtest_end_ts": int(max_date.timestamp()),
|
||||
}
|
||||
if notes:
|
||||
metadata[strategy]["notes"] = notes
|
||||
result["strategy"][strategy] = strat_stats
|
||||
|
||||
strategy_results = generate_strategy_comparison(bt_stats=result["strategy"])
|
||||
|
||||
@@ -1477,7 +1477,9 @@ def test_flat_vars_to_nested_dict(caplog):
|
||||
test_args = {
|
||||
"FREQTRADE__EXCHANGE__SOME_SETTING": "true",
|
||||
"FREQTRADE__EXCHANGE__SOME_FALSE_SETTING": "false",
|
||||
"FREQTRADE__EXCHANGE__CONFIG__whatever": "sometime",
|
||||
"FREQTRADE__EXCHANGE__CONFIG__whatEver": "sometime", # Lowercased
|
||||
# Preserve case for ccxt_config
|
||||
"FREQTRADE__EXCHANGE__CCXT_CONFIG__httpsProxy": "something",
|
||||
"FREQTRADE__EXIT_PRICING__PRICE_SIDE": "bid",
|
||||
"FREQTRADE__EXIT_PRICING__cccc": "500",
|
||||
"FREQTRADE__STAKE_AMOUNT": "200.05",
|
||||
@@ -1500,6 +1502,9 @@ def test_flat_vars_to_nested_dict(caplog):
|
||||
"config": {
|
||||
"whatever": "sometime",
|
||||
},
|
||||
"ccxt_config": {
|
||||
"httpsProxy": "something",
|
||||
},
|
||||
"some_setting": True,
|
||||
"some_false_setting": False,
|
||||
"pair_whitelist": ["BTC/USDT", "ETH/USDT"],
|
||||
|
||||
Reference in New Issue
Block a user