Skip to content

Commit

Permalink
Merge branch 'test' into freqtrade-develop
Browse files Browse the repository at this point in the history
  • Loading branch information
stash86 committed Jan 28, 2025
2 parents aa77cf9 + 0fb8773 commit 4ef361e
Show file tree
Hide file tree
Showing 51 changed files with 2,182 additions and 701 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -560,7 +560,7 @@ jobs:
merge-multiple: true

- name: Publish to PyPI (Test)
uses: pypa/[email protected].3
uses: pypa/[email protected].4
with:
repository-url: https://test.pypi.org/legacy/

Expand All @@ -587,7 +587,7 @@ jobs:
merge-multiple: true

- name: Publish to PyPI
uses: pypa/[email protected].3
uses: pypa/[email protected].4


deploy-docker:
Expand Down
2 changes: 1 addition & 1 deletion .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ repos:

- repo: https://github.com/charliermarsh/ruff-pre-commit
# Ruff version.
rev: 'v0.9.1'
rev: 'v0.9.2'
hooks:
- id: ruff
- id: ruff-format
Expand Down
Binary file not shown.
2 changes: 1 addition & 1 deletion build_helpers/schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -979,7 +979,7 @@
"type": "string"
}
},
"x": {
"verbosity": {
"description": "Logging verbosity level.",
"type": "string",
"enum": [
Expand Down
28 changes: 27 additions & 1 deletion docs/backtesting.md
Original file line number Diff line number Diff line change
Expand Up @@ -508,7 +508,12 @@ To utilize this, you can append `--timeframe-detail 5m` to your regular backtest
freqtrade backtesting --strategy AwesomeStrategy --timeframe 1h --timeframe-detail 5m
```

This will load 1h data as well as 5m data for the timeframe. The strategy will be analyzed with the 1h timeframe, and Entry orders will only be placed at the main timeframe, however Order fills and exit signals will be evaluated at the 5m candle, simulating intra-candle movements.
This will load 1h data (the main timeframe) as well as 5m data (detail timeframe) for the selected timerange.
The strategy will be analyzed with the 1h timeframe.
Candles where activity may take place (there's an active signal, the pair is in a trade) are evaluated at the 5m timeframe.
This will allow for a more accurate simulation of intra-candle movements - and can lead to different results, especially on higher timeframes.

Entries will generally still happen at the main candle's open, however freed trade slots may be freed earlier (if the exit signal is triggered on the 5m candle), which can then be used for a new trade of a different pair.

All callback functions (`custom_exit()`, `custom_stoploss()`, ... ) will be running for each 5m candle once the trade is opened (so 12 times in the above example of 1h timeframe, and 5m detailed timeframe).

Expand All @@ -520,6 +525,27 @@ Also, data must be available / downloaded already.
!!! Tip
You can use this function as the last part of strategy development, to ensure your strategy is not exploiting one of the [backtesting assumptions](#assumptions-made-by-backtesting). Strategies that perform similarly well with this mode have a good chance to perform well in dry/live modes too (although only forward-testing (dry-mode) can really confirm a strategy).

??? Sample "Extreme Difference Example"
Using `--timeframe-detail` on an extreme example (all below pairs have the 10:00 candle with an entry signal) may lead to the following backtesting Trade sequence with 1 max_open_trades:

| Pair | Entry Time | Exit Time | Duration |
|------|------------|-----------| -------- |
| BTC/USDT | 2024-01-01 10:00:00 | 2021-01-01 10:05:00 | 5m |
| ETH/USDT | 2024-01-01 10:05:00 | 2021-01-01 10:15:00 | 10m |
| XRP/USDT | 2024-01-01 10:15:00 | 2021-01-01 10:30:00 | 15m |
| SOL/USDT | 2024-01-01 10:15:00 | 2021-01-01 11:05:00 | 50m |
| BTC/USDT | 2024-01-01 11:05:00 | 2021-01-01 12:00:00 | 55m |

Without timeframe-detail, this would look like:

| Pair | Entry Time | Exit Time | Duration |
|------|------------|-----------| -------- |
| BTC/USDT | 2024-01-01 10:00:00 | 2021-01-01 11:00:00 | 1h |
| BTC/USDT | 2024-01-01 11:00:00 | 2021-01-01 12:00:00 | 1h |

The difference is significant, as without detail data, only the first `max_open_trades` signals per candle are evaluated, and the trade slots are only freed at the end of the candle, allowing for a new trade to be opened at the next candle.


## Backtesting multiple strategies

To compare multiple strategies, a list of Strategies can be provided to backtesting.
Expand Down
2 changes: 1 addition & 1 deletion docs/exchanges.md
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ To use BNFCR futures, you will have to have the following combination of setting

The `stake_currency` setting defines the markets the bot will be operating in. This choice is really arbitrary.

On the exchange, you'll have to use "Multi-asset Mode" - and "Position Mode set to "One-way Mode".
On the exchange, you'll have to use "Multi-asset Mode" - and "Position Mode set to "One-way Mode".
Freqtrade will check these settings on startup, but won't attempt to change them.

## Bingx
Expand Down
6 changes: 4 additions & 2 deletions docs/faq.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,10 +46,12 @@ Make sure you set the `initial_state` config option to `"running"` in your confi

### I have waited 5 minutes, why hasn't the bot made any trades yet?

* Depending on the buy strategy, the amount of whitelisted coins, the
situation of the market etc, it can take up to hours to find a good entry
* Depending on the entry strategy, the amount of whitelisted coins, the
situation of the market etc, it can take up to hours or days to find a good entry
position for a trade. Be patient!

* Backtesting will tell you roughly how many trades to expect - but that won't guarantee that they'll be distributed evenly across time - so you could have 20 trades on one day, and 0 for the rest of the week.

* It may be because of a configuration error. It's best to check the logs, they usually tell you if the bot is simply not getting buy signals (only heartbeat messages), or if there is something wrong (errors / exceptions in the log).

### I have made 12 trades already, why is my total profit negative?
Expand Down
4 changes: 2 additions & 2 deletions docs/requirements-docs.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
markdown==3.7
mkdocs==1.6.1
mkdocs-material==9.5.49
mkdocs-material==9.5.50
mdx_truly_sane_lists==1.3
pymdown-extensions==10.14
pymdown-extensions==10.14.1
jinja2==3.1.5
mike==2.1.3
12 changes: 6 additions & 6 deletions docs/strategy-callbacks.md
Original file line number Diff line number Diff line change
Expand Up @@ -758,7 +758,7 @@ For performance reasons, it's disabled by default and freqtrade will show a warn

Additional orders also result in additional fees and those orders don't count towards `max_open_trades`.

This callback is **not** called when there is an open order (either buy or sell) waiting for execution.
This callback is also called when there is an open order (either buy or sell) waiting for execution - and will cancel the existing open order to place a new order if the amount, price or direction is different.

`adjust_trade_position()` is called very frequently for the duration of a trade, so you must keep your implementation as performant as possible.

Expand All @@ -774,6 +774,11 @@ The combined stake currently allocated to the position is held in `trade.stake_a

Same thing also can happen with partial exit. So be sure to have a strict logic and/or check for the last filled order.

!!! Warning "Performance with many position adjustments"
Position adjustments can be a good approach to increase a strategy's output - but it can also have drawbacks if using this feature extensively.
Each of the orders will be attached to the trade object for the duration of the trade - hence increasing memory usage.
Trades with long duration and 10s or even 100ds of position adjustments are therefore not recommended, and should be closed at regular intervals to not affect performance.

!!! Warning "Backtesting"
During backtesting this callback is called for each candle in `timeframe` or `timeframe_detail`, so run-time performance will be affected.
This can also cause deviating results between live and backtesting, since backtesting can adjust the trade only once per candle, whereas live could adjust the trade multiple times per candle.
Expand Down Expand Up @@ -810,11 +815,6 @@ Back to the example above, since current rate is 200, the current USDT value of

While `/stopentry` command stops the bot from entering new trades, the position adjustment feature will continue buying new orders on existing trades.

!!! Warning "Performance with many position adjustments"
Position adjustments can be a good approach to increase a strategy's output - but it can also have drawbacks if using this feature extensively.
Each of the orders will be attached to the trade object for the duration of the trade - hence increasing memory usage.
Trades with long duration and 10s or even 100ds of position adjustments are therefore not recommended, and should be closed at regular intervals to not affect performance.

``` python
# Default imports

Expand Down
2 changes: 2 additions & 0 deletions docs/telegram-usage.md
Original file line number Diff line number Diff line change
Expand Up @@ -360,6 +360,8 @@ Return the performance of each crypto-currency the bot has sold.
> 5. `STORJ/BTC 0.0009 BTC (27.24%) (1)`
> ...
The relative performance is calculated against the total investment in the currency, aggregating all filled entries for the currency.

### /balance

Return the balance of all crypto-currency your have on the exchange.
Expand Down
2 changes: 1 addition & 1 deletion freqtrade/commands/arguments.py
Original file line number Diff line number Diff line change
Expand Up @@ -347,7 +347,7 @@ def _build_subcommands(self) -> None:
self.parser = ArgumentParser(
prog="freqtrade", description="Free, open source crypto trading bot"
)
self._build_args(optionlist=["version"], parser=self.parser)
self._build_args(optionlist=["version_main"], parser=self.parser)

from freqtrade.commands import (
start_analysis_entries_exits,
Expand Down
13 changes: 10 additions & 3 deletions freqtrade/commands/cli_options.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

from argparse import SUPPRESS, ArgumentTypeError

from freqtrade import __version__, constants
from freqtrade import constants
from freqtrade.constants import HYPEROPT_LOSS_BUILTIN
from freqtrade.enums import CandleType

Expand Down Expand Up @@ -59,8 +59,15 @@ def __init__(self, *args, **kwargs):
"version": Arg(
"-V",
"--version",
action="version",
version=f"%(prog)s {__version__}",
help="show program's version number and exit",
action="store_true",
),
"version_main": Arg(
# Copy of version - used to have -V available with and without subcommand.
"-V",
"--version",
help="show program's version number and exit",
action="store_true",
),
"config": Arg(
"-c",
Expand Down
2 changes: 1 addition & 1 deletion freqtrade/configuration/config_schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -755,7 +755,7 @@
"type": "array",
"items": {"type": "string"},
},
"x": {
"verbosity": {
"description": "Logging verbosity level.",
"type": "string",
"enum": ["error", "info"],
Expand Down
26 changes: 16 additions & 10 deletions freqtrade/data/history/history_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
from freqtrade.exchange import Exchange
from freqtrade.plugins.pairlist.pairlist_helpers import dynamic_expand_pairlist
from freqtrade.util import dt_now, dt_ts, format_ms_time
from freqtrade.util.datetime_helpers import format_ms_time_det
from freqtrade.util.migrations import migrate_data
from freqtrade.util.progress_tracker import CustomProgress, retrieve_progress_tracker

Expand Down Expand Up @@ -431,19 +432,19 @@ def _download_trades_history(
# DEFAULT_TRADES_COLUMNS: 0 -> timestamp
# DEFAULT_TRADES_COLUMNS: 1 -> id

if not trades.empty and since > 0 and since < trades.iloc[0]["timestamp"]:
if not trades.empty and since > 0 and (since + 1000) < trades.iloc[0]["timestamp"]:
# since is before the first trade
raise ValueError(
f"Start {format_ms_time(since)} earlier than "
f"available data ({trades.iloc[0]['date']:{DATETIME_PRINT_FORMAT}}). "
f"Start {format_ms_time_det(since)} earlier than "
f"available data ({format_ms_time_det(trades.iloc[0]['timestamp'])}). "
f"Please use `--erase` if you'd like to redownload {pair}."
)

from_id = trades.iloc[-1]["id"] if not trades.empty else None
if not trades.empty and since < trades.iloc[-1]["timestamp"]:
# Reset since to the last available point
# - 5 seconds (to ensure we're getting all trades)
since = trades.iloc[-1]["timestamp"] - (5 * 1000)
since = int(trades.iloc[-1]["timestamp"] - (5 * 1000))
logger.info(
f"Using last trade date -5s - Downloading trades for {pair} "
f"since: {format_ms_time(since)}."
Expand All @@ -462,7 +463,6 @@ def _download_trades_history(
)
logger.info(f"Current Amount of trades: {len(trades)}")

# Default since_ms to 30 days if nothing is given
new_trades = exchange.get_historic_trades(
pair=pair,
since=since,
Expand Down Expand Up @@ -679,11 +679,17 @@ def download_data(
)
else:
if not exchange.get_option("ohlcv_has_history", True):
raise OperationalException(
f"Historic klines not available for {exchange.name}. "
"Please use `--dl-trades` instead for this exchange "
"(will unfortunately take a long time)."
)
if not exchange.get_option("trades_has_history", True):
raise OperationalException(
f"Historic data not available for {exchange.name}. "
f"{exchange.name} does not support downloading trades or ohlcv data."
)
else:
raise OperationalException(
f"Historic klines not available for {exchange.name}. "
"Please use `--dl-trades` instead for this exchange "
"(will unfortunately take a long time)."
)
migrate_data(config, exchange)
pairs_not_available = refresh_backtest_ohlcv_data(
exchange,
Expand Down
2 changes: 1 addition & 1 deletion freqtrade/exchange/binance.py
Original file line number Diff line number Diff line change
Expand Up @@ -368,7 +368,7 @@ def load_leverage_tiers(self) -> dict[str, list[dict]]:
return {}

async def _async_get_trade_history_id_startup(
self, pair: str, since: int | None
self, pair: str, since: int
) -> tuple[list[list], str]:
"""
override for initial call
Expand Down
Loading

0 comments on commit 4ef361e

Please sign in to comment.