mirror of
https://github.com/freqtrade/freqtrade.git
synced 2026-02-04 05:10:24 +00:00
Merge pull request #11656 from mrpabloyeah/add-custom-roi-strategy-callback
Add custom_roi() strategy callback
This commit is contained in:
@@ -12,6 +12,7 @@ Currently available callbacks:
|
||||
* [`custom_stake_amount()`](#stake-size-management)
|
||||
* [`custom_exit()`](#custom-exit-signal)
|
||||
* [`custom_stoploss()`](#custom-stoploss)
|
||||
* [`custom_roi()`](#custom-roi)
|
||||
* [`custom_entry_price()` and `custom_exit_price()`](#custom-order-price-rules)
|
||||
* [`check_entry_timeout()` and `check_exit_timeout()`](#custom-order-timeout-rules)
|
||||
* [`confirm_trade_entry()`](#trade-entry-buy-order-confirmation)
|
||||
@@ -499,6 +500,135 @@ The helper function `stoploss_from_absolute()` can be used to convert from an ab
|
||||
|
||||
---
|
||||
|
||||
## Custom ROI
|
||||
|
||||
Called for open trade every iteration (roughly every 5 seconds) until a trade is closed.
|
||||
|
||||
The usage of the custom ROI method must be enabled by setting `use_custom_roi=True` on the strategy object.
|
||||
|
||||
This method allows you to define a custom minimum ROI threshold for exiting a trade, expressed as a ratio (e.g., `0.05` for 5% profit). If both `minimal_roi` and `custom_roi` are defined, the lower of the two thresholds will trigger an exit. For example, if `minimal_roi` is set to `{"0": 0.10}` (10% at 0 minutes) and `custom_roi` returns `0.05`, the trade will exit when the profit reaches 5%. Also, if `custom_roi` returns `0.10` and `minimal_roi` is set to `{"0": 0.05}` (5% at 0 minutes), the trade will be closed when the profit reaches 5%.
|
||||
|
||||
The method must return a float representing the new ROI threshold as a ratio, or `None` to fall back to the `minimal_roi` logic. Returning `NaN` or `inf` values is considered invalid and will be treated as `None`, causing the bot to use the `minimal_roi` configuration.
|
||||
|
||||
### Custom ROI examples
|
||||
|
||||
The following examples illustrate how to use the `custom_roi` function to implement different ROI logics.
|
||||
|
||||
#### Custom ROI per side
|
||||
|
||||
Use different ROI thresholds depending on the `side`. In this example, 5% for long entries and 2% for short entries.
|
||||
|
||||
```python
|
||||
# Default imports
|
||||
|
||||
class AwesomeStrategy(IStrategy):
|
||||
|
||||
use_custom_roi = True
|
||||
|
||||
# ... populate_* methods
|
||||
|
||||
def custom_roi(self, pair: str, trade: Trade, current_time: datetime, trade_duration: int,
|
||||
entry_tag: str | None, side: str, **kwargs) -> float | None:
|
||||
"""
|
||||
Custom ROI logic, returns a new minimum ROI threshold (as a ratio, e.g., 0.05 for +5%).
|
||||
Only called when use_custom_roi is set to True.
|
||||
|
||||
If used at the same time as minimal_roi, an exit will be triggered when the lower
|
||||
threshold is reached. Example: If minimal_roi = {"0": 0.01} and custom_roi returns 0.05,
|
||||
an exit will be triggered if profit reaches 5%.
|
||||
|
||||
:param pair: Pair that's currently analyzed.
|
||||
:param trade: trade object.
|
||||
:param current_time: datetime object, containing the current datetime.
|
||||
:param trade_duration: Current trade duration in minutes.
|
||||
:param entry_tag: Optional entry_tag (buy_tag) if provided with the buy signal.
|
||||
:param side: 'long' or 'short' - indicating the direction of the current trade.
|
||||
:param **kwargs: Ensure to keep this here so updates to this won't break your strategy.
|
||||
:return float: New ROI value as a ratio, or None to fall back to minimal_roi logic.
|
||||
"""
|
||||
return 0.05 if side == "long" else 0.02
|
||||
```
|
||||
|
||||
#### Custom ROI per pair
|
||||
|
||||
Use different ROI thresholds depending on the `pair`.
|
||||
|
||||
```python
|
||||
# Default imports
|
||||
|
||||
class AwesomeStrategy(IStrategy):
|
||||
|
||||
use_custom_roi = True
|
||||
|
||||
# ... populate_* methods
|
||||
|
||||
def custom_roi(self, pair: str, trade: Trade, current_time: datetime, trade_duration: int,
|
||||
entry_tag: str | None, side: str, **kwargs) -> float | None:
|
||||
|
||||
stake = trade.stake_currency
|
||||
roi_map = {
|
||||
f"BTC/{stake}": 0.02, # 2% for BTC
|
||||
f"ETH/{stake}": 0.03, # 3% for ETH
|
||||
f"XRP/{stake}": 0.04, # 4% for XRP
|
||||
}
|
||||
|
||||
return roi_map.get(pair, 0.01) # 1% for any other pair
|
||||
```
|
||||
|
||||
#### Custom ROI per entry tag
|
||||
|
||||
Use different ROI thresholds depending on the `entry_tag` provided with the buy signal.
|
||||
|
||||
```python
|
||||
# Default imports
|
||||
|
||||
class AwesomeStrategy(IStrategy):
|
||||
|
||||
use_custom_roi = True
|
||||
|
||||
# ... populate_* methods
|
||||
|
||||
def custom_roi(self, pair: str, trade: Trade, current_time: datetime, trade_duration: int,
|
||||
entry_tag: str | None, side: str, **kwargs) -> float | None:
|
||||
|
||||
roi_by_tag = {
|
||||
"breakout": 0.08, # 8% if tag is "breakout"
|
||||
"rsi_overbought": 0.05, # 5% if tag is "rsi_overbought"
|
||||
"mean_reversion": 0.03, # 3% if tag is "mean_reversion"
|
||||
}
|
||||
|
||||
return roi_by_tag.get(entry_tag, 0.01) # 1% if tag is unknown
|
||||
```
|
||||
|
||||
#### Custom ROI based on ATR
|
||||
|
||||
ROI value may be derived from indicators stored in dataframe. This example uses the ATR ratio as ROI.
|
||||
|
||||
``` python
|
||||
# Default imports
|
||||
# <...>
|
||||
import talib.abstract as ta
|
||||
|
||||
class AwesomeStrategy(IStrategy):
|
||||
|
||||
use_custom_roi = True
|
||||
|
||||
def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||
# <...>
|
||||
dataframe["atr"] = ta.ATR(dataframe, timeperiod=10)
|
||||
|
||||
def custom_roi(self, pair: str, trade: Trade, current_time: datetime, trade_duration: int,
|
||||
entry_tag: str | None, side: str, **kwargs) -> float | None:
|
||||
|
||||
dataframe, _ = self.dp.get_analyzed_dataframe(pair, self.timeframe)
|
||||
last_candle = dataframe.iloc[-1].squeeze()
|
||||
atr_ratio = last_candle["atr"] / last_candle["close"]
|
||||
|
||||
return atr_ratio # Returns the ATR value as ratio
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Custom order price rules
|
||||
|
||||
By default, freqtrade use the orderbook to automatically set an order price([Relevant documentation](configuration.md#prices-used-for-orders)), you also have the option to create custom order prices based on your strategy.
|
||||
|
||||
Reference in New Issue
Block a user