mirror of
https://github.com/freqtrade/freqtrade.git
synced 2025-11-29 00:23:07 +00:00
Compare commits
12 Commits
1bd60c2afb
...
develop
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bfe9aac16b | ||
|
|
1770a68457 | ||
|
|
57fd455adf | ||
|
|
61ecaa4c41 | ||
|
|
682c4137b4 | ||
|
|
759c18df3d | ||
|
|
04fda255de | ||
|
|
26f23c10b5 | ||
|
|
001baa07b1 | ||
|
|
72724037af | ||
|
|
77e8a53572 | ||
|
|
f98efdbe07 |
@@ -675,7 +675,7 @@ Should you experience problems you suspect are caused by websockets, you can dis
|
||||
Should you be required to use a proxy, please refer to the [proxy section](#using-a-proxy-with-freqtrade) for more information.
|
||||
|
||||
!!! Info "Rollout"
|
||||
We're implementing this out slowly, ensuring stability of your bots.
|
||||
We're rolling this out slowly, ensuring stability of your bots.
|
||||
Currently, usage is limited to ohlcv data streams.
|
||||
It's also limited to a few exchanges, with new exchanges being added on an ongoing basis.
|
||||
|
||||
|
||||
@@ -26,10 +26,19 @@ Alternatively (e.g. if your system is not supported by the setup.sh script), fol
|
||||
|
||||
This will install all required tools for development, including `pytest`, `ruff`, `mypy`, and `coveralls`.
|
||||
|
||||
Then install the git hook scripts by running `pre-commit install`, so your changes will be verified locally before committing.
|
||||
This avoids a lot of waiting for CI already, as some basic formatting checks are done locally on your machine.
|
||||
Run the following command to install the git hook scripts:
|
||||
|
||||
Before opening a pull request, please familiarize yourself with our [Contributing Guidelines](https://github.com/freqtrade/freqtrade/blob/develop/CONTRIBUTING.md).
|
||||
``` bash
|
||||
pre-commit install
|
||||
```
|
||||
|
||||
These pre-commit scripts check your changes automatically before each commit.
|
||||
If any formatting issues are found, the commit will fail and will prompt for fixes.
|
||||
This reduces unnecessary CI failures, reduces maintenance burden, and improves code quality.
|
||||
|
||||
You can run the checks manually when necessary with `pre-commit run -a`.
|
||||
|
||||
Before opening a pull request, please also familiarize yourself with our [Contributing Guidelines](https://github.com/freqtrade/freqtrade/blob/develop/CONTRIBUTING.md).
|
||||
|
||||
### Devcontainer setup
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1769,7 +1769,7 @@ class Exchange:
|
||||
balances.pop("total", None)
|
||||
balances.pop("used", None)
|
||||
|
||||
self._log_exchange_response("fetch_balances", balances)
|
||||
self._log_exchange_response("fetch_balance", balances)
|
||||
return balances
|
||||
except ccxt.DDoSProtection as e:
|
||||
raise DDosProtection(e) from e
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
import logging
|
||||
from copy import deepcopy
|
||||
from datetime import datetime
|
||||
from typing import Any
|
||||
|
||||
from freqtrade.constants import BuySell
|
||||
from freqtrade.enums import MarginMode, TradingMode
|
||||
@@ -56,6 +57,13 @@ class Hyperliquid(Exchange):
|
||||
config.update(super()._ccxt_config)
|
||||
return config
|
||||
|
||||
def market_is_tradable(self, market: dict[str, Any]) -> bool:
|
||||
parent_check = super().market_is_tradable(market)
|
||||
|
||||
# Exclude hip3 markets for now - which have the format XYZ:GOOGL/USDT:USDT -
|
||||
# and XYZ:GOOGL as base
|
||||
return parent_check and ":" not in market["base"]
|
||||
|
||||
def get_max_leverage(self, pair: str, stake_amount: float | None) -> float:
|
||||
# There are no leverage tiers
|
||||
if self.trading_mode == TradingMode.FUTURES:
|
||||
|
||||
@@ -82,7 +82,7 @@ class Kraken(Exchange):
|
||||
balances.pop("free", None)
|
||||
balances.pop("total", None)
|
||||
balances.pop("used", None)
|
||||
self._log_exchange_response("fetch_balances", balances)
|
||||
self._log_exchange_response("fetch_balance", balances)
|
||||
|
||||
# Consolidate balances
|
||||
balances = self.consolidate_balances(balances)
|
||||
@@ -104,7 +104,7 @@ class Kraken(Exchange):
|
||||
balances[bal]["used"] = sum(order[1] for order in order_list if order[0] == bal)
|
||||
balances[bal]["free"] = balances[bal]["total"] - balances[bal]["used"]
|
||||
|
||||
self._log_exchange_response("fetch_balances2", balances)
|
||||
self._log_exchange_response("fetch_balance2", balances)
|
||||
return balances
|
||||
except ccxt.DDoSProtection as e:
|
||||
raise DDosProtection(e) from e
|
||||
|
||||
@@ -126,6 +126,7 @@ class Backtesting:
|
||||
|
||||
self.config["dry_run"] = True
|
||||
self.price_pair_prec: dict[str, Series] = {}
|
||||
self.available_pairs: list[str] = []
|
||||
self.run_ids: dict[str, str] = {}
|
||||
self.strategylist: list[IStrategy] = []
|
||||
self.all_bt_content: dict[str, BacktestContentType] = {}
|
||||
@@ -176,7 +177,8 @@ class Backtesting:
|
||||
self._validate_pairlists_for_backtesting()
|
||||
|
||||
self.dataprovider.add_pairlisthandler(self.pairlists)
|
||||
self.pairlists.refresh_pairlist()
|
||||
self.dynamic_pairlist: bool = self.config.get("enable_dynamic_pairlist", False)
|
||||
self.pairlists.refresh_pairlist(only_first=self.dynamic_pairlist)
|
||||
|
||||
if len(self.pairlists.whitelist) == 0:
|
||||
raise OperationalException("No pair in whitelist.")
|
||||
@@ -211,7 +213,6 @@ class Backtesting:
|
||||
self._can_short = self.trading_mode != TradingMode.SPOT
|
||||
self._position_stacking: bool = self.config.get("position_stacking", False)
|
||||
self.enable_protections: bool = self.config.get("enable_protections", False)
|
||||
self.dynamic_pairlist: bool = self.config.get("enable_dynamic_pairlist", False)
|
||||
migrate_data(config, self.exchange)
|
||||
|
||||
self.init_backtest()
|
||||
@@ -335,10 +336,12 @@ class Backtesting:
|
||||
self.progress.set_new_value(1)
|
||||
self._load_bt_data_detail()
|
||||
self.price_pair_prec = {}
|
||||
|
||||
for pair in self.pairlists.whitelist:
|
||||
if pair in data:
|
||||
# Load price precision logic
|
||||
self.price_pair_prec[pair] = get_tick_size_over_time(data[pair])
|
||||
self.available_pairs.append(pair)
|
||||
return data, self.timerange
|
||||
|
||||
def _load_bt_data_detail(self) -> None:
|
||||
@@ -1587,7 +1590,7 @@ class Backtesting:
|
||||
self.check_abort()
|
||||
|
||||
if self.dynamic_pairlist and self.pairlists:
|
||||
self.pairlists.refresh_pairlist()
|
||||
self.pairlists.refresh_pairlist(pairs=self.available_pairs)
|
||||
pairs = self.pairlists.whitelist
|
||||
|
||||
# Reset open trade count for this candle
|
||||
|
||||
@@ -75,11 +75,11 @@ def init_plotscript(config, markets: list, startup_candles: int = 0):
|
||||
)
|
||||
|
||||
no_trades = False
|
||||
filename = config.get("exportfilename")
|
||||
filename = config.get("exportfilename") or config.get("exportdirectory")
|
||||
if config.get("no_trades", False):
|
||||
no_trades = True
|
||||
elif config["trade_source"] == "file":
|
||||
if not filename.is_dir() and not filename.is_file():
|
||||
if not filename or (not filename.is_dir() and not filename.is_file()):
|
||||
logger.warning("Backtest file is missing skipping trades.")
|
||||
no_trades = True
|
||||
try:
|
||||
|
||||
@@ -134,8 +134,20 @@ class PairListManager(LoggingMixin):
|
||||
def _get_cached_tickers(self) -> Tickers:
|
||||
return self._exchange.get_tickers()
|
||||
|
||||
def refresh_pairlist(self) -> None:
|
||||
"""Run pairlist through all configured Pairlist Handlers."""
|
||||
def refresh_pairlist(self, only_first: bool = False, pairs: list[str] | None = None) -> None:
|
||||
"""
|
||||
Run pairlist through all configured Pairlist Handlers.
|
||||
|
||||
:param only_first: If True, only run the first PairList handler (the generator)
|
||||
and skip all subsequent filters. Used during backtesting startup to ensure
|
||||
historic data is loaded for the complete universe of pairs that the
|
||||
generator can produce (even if later filters would reduce the list size).
|
||||
Prevents missing data when a filter returns a variable number of pairs
|
||||
across refresh cycles.
|
||||
:param pairs: Optional list of pairs to intersect with the generated pairlist.
|
||||
Only pairs present both in the generated list and this parameter are kept.
|
||||
Used in backtesting to filter out pairs with no available data.
|
||||
"""
|
||||
# Tickers should be cached to avoid calling the exchange on each call.
|
||||
tickers: dict = {}
|
||||
if self._tickers_needed:
|
||||
@@ -144,10 +156,15 @@ class PairListManager(LoggingMixin):
|
||||
# Generate the pairlist with first Pairlist Handler in the chain
|
||||
pairlist = self._pairlist_handlers[0].gen_pairlist(tickers)
|
||||
|
||||
# Process all Pairlist Handlers in the chain
|
||||
# except for the first one, which is the generator.
|
||||
for pairlist_handler in self._pairlist_handlers[1:]:
|
||||
pairlist = pairlist_handler.filter_pairlist(pairlist, tickers)
|
||||
# Optional intersection with an explicit list of pairs (used in backtesting)
|
||||
if pairs is not None:
|
||||
pairlist = [p for p in pairlist if p in pairs]
|
||||
|
||||
if not only_first:
|
||||
# Process all Pairlist Handlers in the chain
|
||||
# except for the first one, which is the generator.
|
||||
for pairlist_handler in self._pairlist_handlers[1:]:
|
||||
pairlist = pairlist_handler.filter_pairlist(pairlist, tickers)
|
||||
|
||||
# Validation against blacklist happens after the chain of Pairlist Handlers
|
||||
# to ensure blacklist is respected.
|
||||
|
||||
@@ -2772,7 +2772,7 @@ def test_time_pair_generator_open_trades_first(mocker, default_conf, dynamic_pai
|
||||
dummy_row = (end_date, 1.0, 1.1, 0.9, 1.0, 0, 0, 0, 0, None, None)
|
||||
data = {pair: [dummy_row] for pair in pairs}
|
||||
|
||||
def mock_refresh(self):
|
||||
def mock_refresh(self, **kwargs):
|
||||
# Simulate shuffle
|
||||
self._whitelist = pairs[::-1] # ['ETH/BTC', 'NEO/BTC', 'LTC/BTC', 'XRP/BTC']
|
||||
|
||||
|
||||
Reference in New Issue
Block a user