mirror of
https://github.com/freqtrade/freqtrade.git
synced 2024-11-10 10:21:59 +00:00
chore: update samples to use doublequotes
This commit is contained in:
parent
d754a2e295
commit
7952712c5e
|
@ -43,10 +43,10 @@ class AwesomeStrategy(IStrategy):
|
||||||
Called only once after bot instantiation.
|
Called only once after bot instantiation.
|
||||||
: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.
|
||||||
"""
|
"""
|
||||||
if self.config['runmode'].value in ('live', 'dry_run'):
|
if self.config["runmode"].value in ("live", "dry_run"):
|
||||||
# Assign this to the class by using self.*
|
# Assign this to the class by using self.*
|
||||||
# can then be used by populate_* methods
|
# can then be used by populate_* methods
|
||||||
self.custom_remote_data = requests.get('https://some_remote_source.example.com')
|
self.custom_remote_data = requests.get("https://some_remote_source.example.com")
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -59,6 +59,7 @@ seconds, unless configured differently) or once per candle in backtest/hyperopt
|
||||||
This can be used to perform calculations which are pair independent (apply to all pairs), loading of external data, etc.
|
This can be used to perform calculations which are pair independent (apply to all pairs), loading of external data, etc.
|
||||||
|
|
||||||
``` python
|
``` python
|
||||||
|
# Default imports
|
||||||
import requests
|
import requests
|
||||||
|
|
||||||
class AwesomeStrategy(IStrategy):
|
class AwesomeStrategy(IStrategy):
|
||||||
|
@ -73,10 +74,10 @@ class AwesomeStrategy(IStrategy):
|
||||||
:param current_time: datetime object, containing the current datetime
|
:param current_time: datetime object, containing the current datetime
|
||||||
: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.
|
||||||
"""
|
"""
|
||||||
if self.config['runmode'].value in ('live', 'dry_run'):
|
if self.config["runmode"].value in ("live", "dry_run"):
|
||||||
# Assign this to the class by using self.*
|
# Assign this to the class by using self.*
|
||||||
# can then be used by populate_* methods
|
# can then be used by populate_* methods
|
||||||
self.remote_data = requests.get('https://some_remote_source.example.com')
|
self.remote_data = requests.get("https://some_remote_source.example.com")
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -85,6 +86,8 @@ class AwesomeStrategy(IStrategy):
|
||||||
Called before entering a trade, makes it possible to manage your position size when placing a new trade.
|
Called before entering a trade, makes it possible to manage your position size when placing a new trade.
|
||||||
|
|
||||||
```python
|
```python
|
||||||
|
# Default imports
|
||||||
|
|
||||||
class AwesomeStrategy(IStrategy):
|
class AwesomeStrategy(IStrategy):
|
||||||
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: Optional[float], max_stake: float,
|
proposed_stake: float, min_stake: Optional[float], max_stake: float,
|
||||||
|
@ -94,13 +97,13 @@ class AwesomeStrategy(IStrategy):
|
||||||
dataframe, _ = self.dp.get_analyzed_dataframe(pair=pair, timeframe=self.timeframe)
|
dataframe, _ = self.dp.get_analyzed_dataframe(pair=pair, timeframe=self.timeframe)
|
||||||
current_candle = dataframe.iloc[-1].squeeze()
|
current_candle = dataframe.iloc[-1].squeeze()
|
||||||
|
|
||||||
if current_candle['fastk_rsi_1h'] > current_candle['fastd_rsi_1h']:
|
if current_candle["fastk_rsi_1h"] > current_candle["fastd_rsi_1h"]:
|
||||||
if self.config['stake_amount'] == 'unlimited':
|
if self.config["stake_amount"] == "unlimited":
|
||||||
# Use entire available wallet during favorable conditions when in compounding mode.
|
# Use entire available wallet during favorable conditions when in compounding mode.
|
||||||
return max_stake
|
return max_stake
|
||||||
else:
|
else:
|
||||||
# Compound profits during favorable conditions instead of using a static stake.
|
# Compound profits during favorable conditions instead of using a static stake.
|
||||||
return self.wallets.get_total_stake_amount() / self.config['max_open_trades']
|
return self.wallets.get_total_stake_amount() / self.config["max_open_trades"]
|
||||||
|
|
||||||
# Use default stake amount.
|
# Use default stake amount.
|
||||||
return proposed_stake
|
return proposed_stake
|
||||||
|
@ -131,25 +134,27 @@ Using `custom_exit()` signals in place of stoploss though *is not recommended*.
|
||||||
An example of how we can use different indicators depending on the current profit and also exit trades that were open longer than one day:
|
An example of how we can use different indicators depending on the current profit and also exit trades that were open longer than one day:
|
||||||
|
|
||||||
``` python
|
``` python
|
||||||
|
# Default imports
|
||||||
|
|
||||||
class AwesomeStrategy(IStrategy):
|
class AwesomeStrategy(IStrategy):
|
||||||
def custom_exit(self, pair: str, trade: 'Trade', current_time: 'datetime', current_rate: float,
|
def custom_exit(self, pair: str, trade: Trade, current_time: datetime, current_rate: float,
|
||||||
current_profit: float, **kwargs):
|
current_profit: float, **kwargs):
|
||||||
dataframe, _ = self.dp.get_analyzed_dataframe(pair, self.timeframe)
|
dataframe, _ = self.dp.get_analyzed_dataframe(pair, self.timeframe)
|
||||||
last_candle = dataframe.iloc[-1].squeeze()
|
last_candle = dataframe.iloc[-1].squeeze()
|
||||||
|
|
||||||
# Above 20% profit, sell when rsi < 80
|
# Above 20% profit, sell when rsi < 80
|
||||||
if current_profit > 0.2:
|
if current_profit > 0.2:
|
||||||
if last_candle['rsi'] < 80:
|
if last_candle["rsi"] < 80:
|
||||||
return 'rsi_below_80'
|
return "rsi_below_80"
|
||||||
|
|
||||||
# Between 2% and 10%, sell if EMA-long above EMA-short
|
# Between 2% and 10%, sell if EMA-long above EMA-short
|
||||||
if 0.02 < current_profit < 0.1:
|
if 0.02 < current_profit < 0.1:
|
||||||
if last_candle['emalong'] > last_candle['emashort']:
|
if last_candle["emalong"] > last_candle["emashort"]:
|
||||||
return 'ema_long_below_80'
|
return "ema_long_below_80"
|
||||||
|
|
||||||
# Sell any positions at a loss if they are held for more than one day.
|
# Sell any positions at a loss if they are held for more than one day.
|
||||||
if current_profit < 0.0 and (current_time - trade.open_date_utc).days >= 1:
|
if current_profit < 0.0 and (current_time - trade.open_date_utc).days >= 1:
|
||||||
return 'unclog'
|
return "unclog"
|
||||||
```
|
```
|
||||||
|
|
||||||
See [Dataframe access](strategy-advanced.md#dataframe-access) for more information about dataframe use in strategy callbacks.
|
See [Dataframe access](strategy-advanced.md#dataframe-access) for more information about dataframe use in strategy callbacks.
|
||||||
|
@ -170,7 +175,6 @@ The absolute value of the return value is used (the sign is ignored), so returni
|
||||||
Returning `None` will be interpreted as "no desire to change", and is the only safe way to return when you'd like to not modify the stoploss.
|
Returning `None` will be interpreted as "no desire to change", and is the only safe way to return when you'd like to not modify the stoploss.
|
||||||
`NaN` and `inf` values are considered invalid and will be ignored (identical to `None`).
|
`NaN` and `inf` values are considered invalid and will be ignored (identical to `None`).
|
||||||
|
|
||||||
|
|
||||||
Stoploss on exchange works similar to `trailing_stop`, and the stoploss on exchange is updated as configured in `stoploss_on_exchange_interval` ([More details about stoploss on exchange](stoploss.md#stop-loss-on-exchangefreqtrade)).
|
Stoploss on exchange works similar to `trailing_stop`, and the stoploss on exchange is updated as configured in `stoploss_on_exchange_interval` ([More details about stoploss on exchange](stoploss.md#stop-loss-on-exchangefreqtrade)).
|
||||||
|
|
||||||
!!! Note "Use of dates"
|
!!! Note "Use of dates"
|
||||||
|
@ -303,9 +307,9 @@ class AwesomeStrategy(IStrategy):
|
||||||
current_rate: float, current_profit: float, after_fill: bool,
|
current_rate: float, current_profit: float, after_fill: bool,
|
||||||
**kwargs) -> Optional[float]:
|
**kwargs) -> Optional[float]:
|
||||||
|
|
||||||
if pair in ('ETH/BTC', 'XRP/BTC'):
|
if pair in ("ETH/BTC", "XRP/BTC"):
|
||||||
return -0.10
|
return -0.10
|
||||||
elif pair in ('LTC/BTC'):
|
elif pair in ("LTC/BTC"):
|
||||||
return -0.05
|
return -0.05
|
||||||
return -0.15
|
return -0.15
|
||||||
```
|
```
|
||||||
|
@ -384,7 +388,7 @@ class AwesomeStrategy(IStrategy):
|
||||||
|
|
||||||
def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||||
# <...>
|
# <...>
|
||||||
dataframe['sar'] = ta.SAR(dataframe)
|
dataframe["sar"] = ta.SAR(dataframe)
|
||||||
|
|
||||||
use_custom_stoploss = True
|
use_custom_stoploss = True
|
||||||
|
|
||||||
|
@ -396,7 +400,7 @@ class AwesomeStrategy(IStrategy):
|
||||||
last_candle = dataframe.iloc[-1].squeeze()
|
last_candle = dataframe.iloc[-1].squeeze()
|
||||||
|
|
||||||
# Use parabolic sar as absolute stoploss price
|
# Use parabolic sar as absolute stoploss price
|
||||||
stoploss_price = last_candle['sar']
|
stoploss_price = last_candle["sar"]
|
||||||
|
|
||||||
# Convert absolute price to percentage relative to current_rate
|
# Convert absolute price to percentage relative to current_rate
|
||||||
if stoploss_price < current_rate:
|
if stoploss_price < current_rate:
|
||||||
|
@ -462,7 +466,7 @@ The helper function `stoploss_from_absolute()` can be used to convert from an ab
|
||||||
|
|
||||||
??? Example "Returning a stoploss using absolute price from the custom stoploss function"
|
??? Example "Returning a stoploss using absolute price from the custom stoploss function"
|
||||||
|
|
||||||
If we want to trail a stop price at 2xATR below current price we can call `stoploss_from_absolute(current_rate + (side * candle['atr'] * 2), current_rate=current_rate, is_short=trade.is_short, leverage=trade.leverage)`.
|
If we want to trail a stop price at 2xATR below current price we can call `stoploss_from_absolute(current_rate + (side * candle["atr"] * 2), current_rate=current_rate, is_short=trade.is_short, leverage=trade.leverage)`.
|
||||||
For futures, we need to adjust the direction (up or down), as well as adjust for leverage, since the [`custom_stoploss`](strategy-callbacks.md#custom-stoploss) callback returns the ["risk for this trade"](stoploss.md#stoploss-and-leverage) - not the relative price movement.
|
For futures, we need to adjust the direction (up or down), as well as adjust for leverage, since the [`custom_stoploss`](strategy-callbacks.md#custom-stoploss) callback returns the ["risk for this trade"](stoploss.md#stoploss-and-leverage) - not the relative price movement.
|
||||||
|
|
||||||
``` python
|
``` python
|
||||||
|
@ -472,8 +476,8 @@ The helper function `stoploss_from_absolute()` can be used to convert from an ab
|
||||||
|
|
||||||
use_custom_stoploss = True
|
use_custom_stoploss = True
|
||||||
|
|
||||||
def populate_indicators_1h(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||||
dataframe['atr'] = ta.ATR(dataframe, timeperiod=14)
|
dataframe["atr"] = ta.ATR(dataframe, timeperiod=14)
|
||||||
return dataframe
|
return dataframe
|
||||||
|
|
||||||
def custom_stoploss(self, pair: str, trade: Trade, current_time: datetime,
|
def custom_stoploss(self, pair: str, trade: Trade, current_time: datetime,
|
||||||
|
@ -483,7 +487,7 @@ The helper function `stoploss_from_absolute()` can be used to convert from an ab
|
||||||
trade_date = timeframe_to_prev_date(self.timeframe, trade.open_date_utc)
|
trade_date = timeframe_to_prev_date(self.timeframe, trade.open_date_utc)
|
||||||
candle = dataframe.iloc[-1].squeeze()
|
candle = dataframe.iloc[-1].squeeze()
|
||||||
side = 1 if trade.is_short else -1
|
side = 1 if trade.is_short else -1
|
||||||
return stoploss_from_absolute(current_rate + (side * candle['atr'] * 2),
|
return stoploss_from_absolute(current_rate + (side * candle["atr"] * 2),
|
||||||
current_rate=current_rate,
|
current_rate=current_rate,
|
||||||
is_short=trade.is_short,
|
is_short=trade.is_short,
|
||||||
leverage=trade.leverage)
|
leverage=trade.leverage)
|
||||||
|
@ -575,8 +579,8 @@ class AwesomeStrategy(IStrategy):
|
||||||
|
|
||||||
# Set unfilledtimeout to 25 hours, since the maximum timeout from below is 24 hours.
|
# Set unfilledtimeout to 25 hours, since the maximum timeout from below is 24 hours.
|
||||||
unfilledtimeout = {
|
unfilledtimeout = {
|
||||||
'entry': 60 * 25,
|
"entry": 60 * 25,
|
||||||
'exit': 60 * 25
|
"exit": 60 * 25
|
||||||
}
|
}
|
||||||
|
|
||||||
def check_entry_timeout(self, pair: str, trade: Trade, order: Order,
|
def check_entry_timeout(self, pair: str, trade: Trade, order: Order,
|
||||||
|
@ -677,7 +681,7 @@ class AwesomeStrategy(IStrategy):
|
||||||
:param time_in_force: Time in force. Defaults to GTC (Good-til-cancelled).
|
:param time_in_force: Time in force. Defaults to GTC (Good-til-cancelled).
|
||||||
:param current_time: datetime object, containing the current datetime
|
:param current_time: datetime object, containing the current datetime
|
||||||
:param entry_tag: Optional entry_tag (buy_tag) if provided with the buy signal.
|
: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 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.
|
:param **kwargs: Ensure to keep this here so updates to this won't break your strategy.
|
||||||
:return bool: When True is returned, then the buy-order is placed on the exchange.
|
:return bool: When True is returned, then the buy-order is placed on the exchange.
|
||||||
False aborts the process
|
False aborts the process
|
||||||
|
@ -725,8 +729,8 @@ class AwesomeStrategy(IStrategy):
|
||||||
or current rate for market orders.
|
or current rate for market orders.
|
||||||
:param time_in_force: Time in force. Defaults to GTC (Good-til-cancelled).
|
:param time_in_force: Time in force. Defaults to GTC (Good-til-cancelled).
|
||||||
:param exit_reason: Exit reason.
|
:param exit_reason: Exit reason.
|
||||||
Can be any of ['roi', 'stop_loss', 'stoploss_on_exchange', 'trailing_stop_loss',
|
Can be any of ["roi", "stop_loss", "stoploss_on_exchange", "trailing_stop_loss",
|
||||||
'exit_signal', 'force_exit', 'emergency_exit']
|
"exit_signal", "force_exit", "emergency_exit"]
|
||||||
:param current_time: datetime object, containing the current datetime
|
:param current_time: datetime object, containing the current datetime
|
||||||
: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 bool: When True, then the exit-order is placed on the exchange.
|
:return bool: When True, then the exit-order is placed on the exchange.
|
||||||
|
@ -758,7 +762,7 @@ This callback is **not** called when there is an open order (either buy or sell)
|
||||||
`adjust_trade_position()` is called very frequently for the duration of a trade, so you must keep your implementation as performant as possible.
|
`adjust_trade_position()` is called very frequently for the duration of a trade, so you must keep your implementation as performant as possible.
|
||||||
|
|
||||||
Position adjustments will always be applied in the direction of the trade, so a positive value will always increase your position (negative values will decrease your position), no matter if it's a long or short trade.
|
Position adjustments will always be applied in the direction of the trade, so a positive value will always increase your position (negative values will decrease your position), no matter if it's a long or short trade.
|
||||||
Adjustment orders can be assigned with a tag by returning a 2 element Tuple, with the first element being the adjustment amount, and the 2nd element the tag (e.g. `return 250, 'increase_favorable_conditions'`).
|
Adjustment orders can be assigned with a tag by returning a 2 element Tuple, with the first element being the adjustment amount, and the 2nd element the tag (e.g. `return 250, "increase_favorable_conditions"`).
|
||||||
|
|
||||||
Modifications to leverage are not possible, and the stake-amount returned is assumed to be before applying leverage.
|
Modifications to leverage are not possible, and the stake-amount returned is assumed to be before applying leverage.
|
||||||
|
|
||||||
|
@ -780,7 +784,7 @@ Returning a value more than the above (so remaining stake_amount would become ne
|
||||||
!!! Note "About stake size"
|
!!! Note "About stake size"
|
||||||
Using fixed stake size means it will be the amount used for the first order, just like without position adjustment.
|
Using fixed stake size means it will be the amount used for the first order, just like without position adjustment.
|
||||||
If you wish to buy additional orders with DCA, then make sure to leave enough funds in the wallet for that.
|
If you wish to buy additional orders with DCA, then make sure to leave enough funds in the wallet for that.
|
||||||
Using 'unlimited' stake amount with DCA orders requires you to also implement the `custom_stake_amount()` callback to avoid allocating all funds to the initial order.
|
Using `"unlimited"` stake amount with DCA orders requires you to also implement the `custom_stake_amount()` callback to avoid allocating all funds to the initial order.
|
||||||
|
|
||||||
!!! Warning "Stoploss calculation"
|
!!! Warning "Stoploss calculation"
|
||||||
Stoploss is still calculated from the initial opening price, not averaged price.
|
Stoploss is still calculated from the initial opening price, not averaged price.
|
||||||
|
@ -799,9 +803,6 @@ Returning a value more than the above (so remaining stake_amount would become ne
|
||||||
|
|
||||||
``` python
|
``` python
|
||||||
# Default imports
|
# Default imports
|
||||||
from freqtrade.persistence import Trade
|
|
||||||
from typing import Optional, Tuple, Union
|
|
||||||
|
|
||||||
|
|
||||||
class DigDeeperStrategy(IStrategy):
|
class DigDeeperStrategy(IStrategy):
|
||||||
|
|
||||||
|
@ -864,7 +865,7 @@ class DigDeeperStrategy(IStrategy):
|
||||||
|
|
||||||
if current_profit > 0.05 and trade.nr_of_successful_exits == 0:
|
if current_profit > 0.05 and trade.nr_of_successful_exits == 0:
|
||||||
# Take half of the profit at +5%
|
# Take half of the profit at +5%
|
||||||
return -(trade.stake_amount / 2), 'half_profit_5%'
|
return -(trade.stake_amount / 2), "half_profit_5%"
|
||||||
|
|
||||||
if current_profit > -0.05:
|
if current_profit > -0.05:
|
||||||
return None
|
return None
|
||||||
|
@ -874,7 +875,7 @@ class DigDeeperStrategy(IStrategy):
|
||||||
# Only buy when not actively falling price.
|
# Only buy when not actively falling price.
|
||||||
last_candle = dataframe.iloc[-1].squeeze()
|
last_candle = dataframe.iloc[-1].squeeze()
|
||||||
previous_candle = dataframe.iloc[-2].squeeze()
|
previous_candle = dataframe.iloc[-2].squeeze()
|
||||||
if last_candle['close'] < previous_candle['close']:
|
if last_candle["close"] < previous_candle["close"]:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
filled_entries = trade.select_filled_orders(trade.entry_side)
|
filled_entries = trade.select_filled_orders(trade.entry_side)
|
||||||
|
@ -892,7 +893,7 @@ class DigDeeperStrategy(IStrategy):
|
||||||
stake_amount = filled_entries[0].stake_amount
|
stake_amount = filled_entries[0].stake_amount
|
||||||
# This then calculates current safety order size
|
# This then calculates current safety order size
|
||||||
stake_amount = stake_amount * (1 + (count_of_entries * 0.25))
|
stake_amount = stake_amount * (1 + (count_of_entries * 0.25))
|
||||||
return stake_amount, '1/3rd_increase'
|
return stake_amount, "1/3rd_increase"
|
||||||
except Exception as exception:
|
except Exception as exception:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
@ -964,7 +965,7 @@ class AwesomeStrategy(IStrategy):
|
||||||
:param proposed_rate: Rate, calculated based on pricing settings in entry_pricing.
|
:param proposed_rate: Rate, calculated based on pricing settings in entry_pricing.
|
||||||
:param current_order_rate: Rate of the existing order in place.
|
:param current_order_rate: Rate of the existing order in place.
|
||||||
:param entry_tag: Optional entry_tag (buy_tag) if provided with the buy signal.
|
: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 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.
|
:param **kwargs: Ensure to keep this here so updates to this won't break your strategy.
|
||||||
:return float: New entry price value if provided
|
:return float: New entry price value if provided
|
||||||
|
|
||||||
|
@ -1013,7 +1014,7 @@ class AwesomeStrategy(IStrategy):
|
||||||
:param proposed_leverage: A leverage proposed by the bot.
|
:param proposed_leverage: A leverage proposed by the bot.
|
||||||
:param max_leverage: Max leverage allowed on this pair
|
:param max_leverage: Max leverage allowed on this pair
|
||||||
:param entry_tag: Optional entry_tag (buy_tag) if provided with the buy signal.
|
: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 side: "long" or "short" - indicating the direction of the proposed trade
|
||||||
:return: A leverage amount, which is between 1.0 and max_leverage.
|
:return: A leverage amount, which is between 1.0 and max_leverage.
|
||||||
"""
|
"""
|
||||||
return 1.0
|
return 1.0
|
||||||
|
@ -1048,7 +1049,7 @@ class AwesomeStrategy(IStrategy):
|
||||||
last_candle = dataframe.iloc[-1].squeeze()
|
last_candle = dataframe.iloc[-1].squeeze()
|
||||||
|
|
||||||
if (trade.nr_of_successful_entries == 1) and (order.ft_order_side == trade.entry_side):
|
if (trade.nr_of_successful_entries == 1) and (order.ft_order_side == trade.entry_side):
|
||||||
trade.set_custom_data(key='entry_candle_high', value=last_candle['high'])
|
trade.set_custom_data(key="entry_candle_high", value=last_candle["high"])
|
||||||
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user