Update docs to include info on new functionality.
This commit is contained in:
parent
43779232e1
commit
16b6b08227
@ -24,7 +24,7 @@ By default, loop runs every few seconds (`internals.process_throttle_secs`) and
|
|||||||
|
|
||||||
* Fetch open trades from persistence.
|
* Fetch open trades from persistence.
|
||||||
* Calculate current list of tradable pairs.
|
* Calculate current list of tradable pairs.
|
||||||
* Download OHLCV data for the pairlist including all [informative pairs](strategy-customization.md#get-data-for-non-tradeable-pairs)
|
* Download OHLCV data for the pairlist including all [informative pairs](strategy-customization.md#get-data-for-non-tradeable-pairs)
|
||||||
This step is only executed once per Candle to avoid unnecessary network traffic.
|
This step is only executed once per Candle to avoid unnecessary network traffic.
|
||||||
* Call `bot_loop_start()` strategy callback.
|
* Call `bot_loop_start()` strategy callback.
|
||||||
* Analyze strategy per pair.
|
* Analyze strategy per pair.
|
||||||
@ -34,6 +34,8 @@ By default, loop runs every few seconds (`internals.process_throttle_secs`) and
|
|||||||
* Check timeouts for open orders.
|
* Check timeouts for open orders.
|
||||||
* Calls `check_entry_timeout()` strategy callback for open entry orders.
|
* Calls `check_entry_timeout()` strategy callback for open entry orders.
|
||||||
* Calls `check_exit_timeout()` strategy callback for open exit orders.
|
* Calls `check_exit_timeout()` strategy callback for open exit orders.
|
||||||
|
* Check readjustment request for open orders.
|
||||||
|
* Calls `readjust_entry_price()` strategy callback for open entry orders.
|
||||||
* Verifies existing positions and eventually places exit orders.
|
* Verifies existing positions and eventually places exit orders.
|
||||||
* Considers stoploss, ROI and exit-signal, `custom_exit()` and `custom_stoploss()`.
|
* Considers stoploss, ROI and exit-signal, `custom_exit()` and `custom_stoploss()`.
|
||||||
* Determine exit-price based on `exit_pricing` configuration setting or by using the `custom_exit_price()` callback.
|
* Determine exit-price based on `exit_pricing` configuration setting or by using the `custom_exit_price()` callback.
|
||||||
|
@ -16,6 +16,7 @@ Currently available callbacks:
|
|||||||
* [`confirm_trade_entry()`](#trade-entry-buy-order-confirmation)
|
* [`confirm_trade_entry()`](#trade-entry-buy-order-confirmation)
|
||||||
* [`confirm_trade_exit()`](#trade-exit-sell-order-confirmation)
|
* [`confirm_trade_exit()`](#trade-exit-sell-order-confirmation)
|
||||||
* [`adjust_trade_position()`](#adjust-trade-position)
|
* [`adjust_trade_position()`](#adjust-trade-position)
|
||||||
|
* [`readjust_entry_price()`](#readjust-entry-price)
|
||||||
* [`leverage()`](#leverage-callback)
|
* [`leverage()`](#leverage-callback)
|
||||||
|
|
||||||
!!! Tip "Callback calling sequence"
|
!!! Tip "Callback calling sequence"
|
||||||
@ -365,13 +366,13 @@ class AwesomeStrategy(IStrategy):
|
|||||||
|
|
||||||
# ... populate_* methods
|
# ... populate_* methods
|
||||||
|
|
||||||
def custom_entry_price(self, pair: str, current_time: datetime, proposed_rate: float,
|
def custom_entry_price(self, pair: str, current_time: datetime, proposed_rate: float,
|
||||||
entry_tag: Optional[str], side: str, **kwargs) -> float:
|
entry_tag: Optional[str], side: str, **kwargs) -> float:
|
||||||
|
|
||||||
dataframe, last_updated = self.dp.get_analyzed_dataframe(pair=pair,
|
dataframe, last_updated = self.dp.get_analyzed_dataframe(pair=pair,
|
||||||
timeframe=self.timeframe)
|
timeframe=self.timeframe)
|
||||||
new_entryprice = dataframe['bollinger_10_lowerband'].iat[-1]
|
new_entryprice = dataframe['bollinger_10_lowerband'].iat[-1]
|
||||||
|
|
||||||
return new_entryprice
|
return new_entryprice
|
||||||
|
|
||||||
def custom_exit_price(self, pair: str, trade: Trade,
|
def custom_exit_price(self, pair: str, trade: Trade,
|
||||||
@ -381,14 +382,14 @@ class AwesomeStrategy(IStrategy):
|
|||||||
dataframe, last_updated = self.dp.get_analyzed_dataframe(pair=pair,
|
dataframe, last_updated = self.dp.get_analyzed_dataframe(pair=pair,
|
||||||
timeframe=self.timeframe)
|
timeframe=self.timeframe)
|
||||||
new_exitprice = dataframe['bollinger_10_upperband'].iat[-1]
|
new_exitprice = dataframe['bollinger_10_upperband'].iat[-1]
|
||||||
|
|
||||||
return new_exitprice
|
return new_exitprice
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
!!! Warning
|
!!! Warning
|
||||||
Modifying entry and exit prices will only work for limit orders. Depending on the price chosen, this can result in a lot of unfilled orders. By default the maximum allowed distance between the current price and the custom price is 2%, this value can be changed in config with the `custom_price_max_distance_ratio` parameter.
|
Modifying entry and exit prices will only work for limit orders. Depending on the price chosen, this can result in a lot of unfilled orders. By default the maximum allowed distance between the current price and the custom price is 2%, this value can be changed in config with the `custom_price_max_distance_ratio` parameter.
|
||||||
**Example**:
|
**Example**:
|
||||||
If the new_entryprice is 97, the proposed_rate is 100 and the `custom_price_max_distance_ratio` is set to 2%, The retained valid custom entry price will be 98, which is 2% below the current (proposed) rate.
|
If the new_entryprice is 97, the proposed_rate is 100 and the `custom_price_max_distance_ratio` is set to 2%, The retained valid custom entry price will be 98, which is 2% below the current (proposed) rate.
|
||||||
|
|
||||||
!!! Warning "Backtesting"
|
!!! Warning "Backtesting"
|
||||||
@ -430,7 +431,7 @@ class AwesomeStrategy(IStrategy):
|
|||||||
'exit': 60 * 25
|
'exit': 60 * 25
|
||||||
}
|
}
|
||||||
|
|
||||||
def check_entry_timeout(self, pair: str, trade: 'Trade', order: dict,
|
def check_entry_timeout(self, pair: str, trade: 'Trade', order: dict,
|
||||||
current_time: datetime, **kwargs) -> bool:
|
current_time: datetime, **kwargs) -> bool:
|
||||||
if trade.open_rate > 100 and trade.open_date_utc < current_time - timedelta(minutes=5):
|
if trade.open_rate > 100 and trade.open_date_utc < current_time - timedelta(minutes=5):
|
||||||
return True
|
return True
|
||||||
@ -508,7 +509,7 @@ class AwesomeStrategy(IStrategy):
|
|||||||
# ... populate_* methods
|
# ... populate_* methods
|
||||||
|
|
||||||
def confirm_trade_entry(self, pair: str, order_type: str, amount: float, rate: float,
|
def confirm_trade_entry(self, pair: str, order_type: str, amount: float, rate: float,
|
||||||
time_in_force: str, current_time: datetime, entry_tag: Optional[str],
|
time_in_force: str, current_time: datetime, entry_tag: Optional[str],
|
||||||
side: str, **kwargs) -> bool:
|
side: str, **kwargs) -> bool:
|
||||||
"""
|
"""
|
||||||
Called right before placing a entry order.
|
Called right before placing a entry order.
|
||||||
@ -616,35 +617,35 @@ from freqtrade.persistence import Trade
|
|||||||
|
|
||||||
|
|
||||||
class DigDeeperStrategy(IStrategy):
|
class DigDeeperStrategy(IStrategy):
|
||||||
|
|
||||||
position_adjustment_enable = True
|
position_adjustment_enable = True
|
||||||
|
|
||||||
# Attempts to handle large drops with DCA. High stoploss is required.
|
# Attempts to handle large drops with DCA. High stoploss is required.
|
||||||
stoploss = -0.30
|
stoploss = -0.30
|
||||||
|
|
||||||
# ... populate_* methods
|
# ... populate_* methods
|
||||||
|
|
||||||
# Example specific variables
|
# Example specific variables
|
||||||
max_entry_position_adjustment = 3
|
max_entry_position_adjustment = 3
|
||||||
# This number is explained a bit further down
|
# This number is explained a bit further down
|
||||||
max_dca_multiplier = 5.5
|
max_dca_multiplier = 5.5
|
||||||
|
|
||||||
# This is called when placing the initial order (opening trade)
|
# This is called when placing the initial order (opening trade)
|
||||||
def custom_stake_amount(self, pair: str, current_time: datetime, current_rate: float,
|
def custom_stake_amount(self, pair: str, current_time: datetime, current_rate: float,
|
||||||
proposed_stake: float, min_stake: float, max_stake: float,
|
proposed_stake: float, min_stake: float, max_stake: float,
|
||||||
entry_tag: Optional[str], side: str, **kwargs) -> float:
|
entry_tag: Optional[str], side: str, **kwargs) -> float:
|
||||||
|
|
||||||
# We need to leave most of the funds for possible further DCA orders
|
# We need to leave most of the funds for possible further DCA orders
|
||||||
# This also applies to fixed stakes
|
# This also applies to fixed stakes
|
||||||
return proposed_stake / self.max_dca_multiplier
|
return proposed_stake / self.max_dca_multiplier
|
||||||
|
|
||||||
def adjust_trade_position(self, trade: Trade, current_time: datetime,
|
def adjust_trade_position(self, trade: Trade, current_time: datetime,
|
||||||
current_rate: float, current_profit: float, min_stake: float,
|
current_rate: float, current_profit: float, min_stake: float,
|
||||||
max_stake: float, **kwargs):
|
max_stake: float, **kwargs):
|
||||||
"""
|
"""
|
||||||
Custom trade adjustment logic, returning the stake amount that a trade should be increased.
|
Custom trade adjustment logic, returning the stake amount that a trade should be increased.
|
||||||
This means extra buy orders with additional fees.
|
This means extra buy orders with additional fees.
|
||||||
|
|
||||||
:param trade: trade object.
|
:param trade: trade object.
|
||||||
:param current_time: datetime object, containing the current datetime
|
:param current_time: datetime object, containing the current datetime
|
||||||
:param current_rate: Current buy rate.
|
:param current_rate: Current buy rate.
|
||||||
@ -654,7 +655,7 @@ class DigDeeperStrategy(IStrategy):
|
|||||||
:param **kwargs: Ensure to keep this here so updates to this won't break your strategy.
|
:param **kwargs: Ensure to keep this here so updates to this won't break your strategy.
|
||||||
:return float: Stake amount to adjust your trade
|
:return float: Stake amount to adjust your trade
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if current_profit > -0.05:
|
if current_profit > -0.05:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
@ -689,6 +690,46 @@ class DigDeeperStrategy(IStrategy):
|
|||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Readjust Entry Price
|
||||||
|
|
||||||
|
The `readjust_entry_price()` callback may be used by strategy developer to refresh/replace limit orders upon arrival of new candles.
|
||||||
|
Be aware that `custom_entry_price()` is still the one dictating initial entry limit order price target at the time of entry trigger.
|
||||||
|
|
||||||
|
!!! Warning This mechanism will not trigger if previous orders were partially or fully filled.
|
||||||
|
|
||||||
|
!!! Warning Entry `unfilledtimeout` mechanism takes precedence over this. Be sure to update timeout values to match your expectancy.
|
||||||
|
|
||||||
|
```python
|
||||||
|
from freqtrade.persistence import Trade
|
||||||
|
from datetime import timedelta
|
||||||
|
|
||||||
|
class AwesomeStrategy(IStrategy):
|
||||||
|
|
||||||
|
# ... populate_* methods
|
||||||
|
|
||||||
|
def readjust_entry_price(self, pair: str, current_time: datetime, proposed_rate: float,
|
||||||
|
entry_tag: Optional[str], side: str, **kwargs) -> float:
|
||||||
|
"""
|
||||||
|
Entry price readjustment logic, returning the readjusted entry price.
|
||||||
|
|
||||||
|
:param pair: Pair that's currently analyzed
|
||||||
|
:param trade: Trade object.
|
||||||
|
:param current_time: datetime object, containing the current datetime
|
||||||
|
:param proposed_rate: Rate, calculated based on pricing settings in exit_pricing.
|
||||||
|
:param entry_tag: Optional entry_tag (buy_tag) if provided with the buy signal.
|
||||||
|
:param side: 'long' or 'short' - indicating the direction of the proposed trade
|
||||||
|
:param **kwargs: Ensure to keep this here so updates to this won't break your strategy.
|
||||||
|
:return float: New entry price value if provided
|
||||||
|
|
||||||
|
"""
|
||||||
|
# Limit orders to use and follow SMA200 as price target for the first 10 minutes since entry trigger for BTC/USDT pair.
|
||||||
|
if pair == 'BTC/USDT' and entry_tag == 'long_sma200' and side == 'long' and (current_time - timedelta(minutes=10) > trade.open_date_utc:
|
||||||
|
dataframe, _ = self.dp.get_analyzed_dataframe(pair=pair, timeframe=self.timeframe)
|
||||||
|
current_candle = dataframe.iloc[-1].squeeze()
|
||||||
|
return current_candle['sma_200']
|
||||||
|
return proposed_rate
|
||||||
|
```
|
||||||
|
|
||||||
## Leverage Callback
|
## Leverage Callback
|
||||||
|
|
||||||
When trading in markets that allow leverage, this method must return the desired Leverage (Defaults to 1 -> No leverage).
|
When trading in markets that allow leverage, this method must return the desired Leverage (Defaults to 1 -> No leverage).
|
||||||
|
Loading…
Reference in New Issue
Block a user