Timeframe
1d
Direction
Long Only
Stoploss
-90.0%
Trailing Stop
No
ROI
0m: 10000.0%
Interface Version
3
Startup Candles
N/A
Indicators
6
freqtrade/freqtrade-strategies
Strategy 003 author@: Gerald Lonlas github@: https://github.com/freqtrade/freqtrade-strategies
# pragma pylint: disable=missing-docstring, invalid-name, pointless-string-statement
# flake8: noqa: F401
# isort: skip_file
# --- Do not remove these libs ---
import numpy as np
import pandas as pd
from pandas import DataFrame
from datetime import datetime
from typing import Optional, Union, Dict
from freqtrade.exchange import timeframe_to_prev_date
from freqtrade.optimize.space import SKDecimal, Integer
from freqtrade.strategy import (BooleanParameter, CategoricalParameter, DecimalParameter,
IntParameter, IStrategy, merge_informative_pair, stoploss_from_absolute)
# --------------------------------
# Add your lib to import here
import talib.abstract as ta
import pandas_ta as pta
from technical import qtpylib
from technical.candles import heikinashi
# 1 backtest with roi, no stoploss + custom entry amount
# 2 backtest no roi, stoploss + custom entry amount
# 3 roi , stoploss + custom entry amount
# no roi, no / stoploss, no custom entry emount 10 orders
class Heikin_Ashi1D174(IStrategy):
INTERFACE_VERSION = 3
# class HyperOpt:
# def stoploss_space():
# return [SKDecimal(-0.9, -0.1, decimals=1, name='stoploss')]
#
# # Define custom ROI space
# def roi_space():
# return [
# Integer(0, 1, name='roi_t'),
# Integer(100, 101, name='roi_p'),
# ]
#
# def generate_roi_table(params: Dict) -> Dict[int, float]:
# roi_table = {}
# roi_table[0] = params['roi_p']
#
# return roi_table
buy_RSI_long = IntParameter(30, 60, default=58, space="buy")
buy_RSI_short = IntParameter(30, 60, default=45, space="buy")
buy_cust_one_trade_limit_max = IntParameter(5, 30, default=24, space="buy")
buy_cust_one_trade_limit_min = IntParameter(1, 8, default=3, space="buy")
buy_low_line = IntParameter(-100, -70, default=-93, space="buy")
buy_high_line = IntParameter(-30, 0, default=-18, space="buy")
timeframe = '1d'
# Can this strategy go short?
can_short: bool = True
minimal_roi = {
"0": 100
}
stoploss = -0.90
trailing_stop = False
# trailing_only_offset_is_reached = False
# trailing_stop_positive = 0.01
# trailing_stop_positive_offset = 0.0 # Disabled / not configured
process_only_new_candles = True
# These values can be overridden in the config.
use_exit_signal = True
exit_profit_only = False
ignore_roi_if_entry_signal = False
startup_candle_count: int = 10
# Optional order type mapping.
order_types = {
'entry': 'market',
'exit': 'market',
'stoploss': 'market',
'stoploss_on_exchange': False
}
# Optional order time in force.
order_time_in_force = {
'entry': 'GTC',
'exit': 'GTC'
}
@property
def plot_config(self):
return {
# Main plot indicators (Moving averages, ...)
'main_plot': {
'tema': {},
'sar': {'color': 'white'},
},
'subplots': {
# Subplots - each dict defines one additional plot
"MACD": {
'macd': {'color': 'blue'},
'macdsignal': {'color': 'orange'},
},
"RSI": {
'rsi': {'color': 'red'},
},
"Willy": {
'willy': {'color': 'red'}
},
"Ema_willy": {
'ema_will': {'color': 'blue'}
}
}
}
def informative_pairs(self):
return []
def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
dataframe['rsi'] = ta.RSI(dataframe)
dataframe['plot_rsi'] = self.plot_RSI(dataframe)['Plot_rsi']
dataframe['ha_open'] = heikinashi(dataframe)['open']
dataframe['ha_high'] = heikinashi(dataframe)['high']
dataframe['ha_low'] = heikinashi(dataframe)['low']
dataframe['ha_close'] = heikinashi(dataframe)['close']
# Heikin Ashi Strategy
# heikinashi = qtpylib.heikinashi(dataframe)
# dataframe['ha_open'] = heikinashi['open']
# dataframe['ha_close'] = heikinashi['close']
# dataframe['ha_high'] = heikinashi['high']
# dataframe['ha_low'] = heikinashi['low']
dataframe['doji_cand'] = self.heikin_asi_trigger(dataframe)['Doji_cand']
dataframe['bear_cand'] = self.heikin_asi_trigger(dataframe)['Bear_cand']
dataframe['bull_cand'] = self.heikin_asi_trigger(dataframe)['Bull_cand']
dataframe['red_or_green'] = self.heikin_asi_trigger(dataframe)['Red_or_green']
dataframe['plot_bull'] = self.heikin_asi_trigger(dataframe)['Plot_bull']
dataframe['plot_bear'] = self.heikin_asi_trigger(dataframe)['Plot_bear']
dataframe['plot_doji'] = self.heikin_asi_trigger(dataframe)['Plot_doji']
dataframe['willy'] = self.willy_ema(dataframe, low_line=self.buy_low_line.value, up_line=self.buy_high_line.value, willyLen=21, emaLen=13)['Willy']
dataframe['ema_will'] = self.willy_ema(dataframe, low_line=-80, up_line=-20, willyLen=21, emaLen=13)['Ema_will']
# 'Doshi_cand': df['doshi_cand'],
# 'Bear_cand': df['bear_cand'],
# 'Bull_cand': df['bull_cand']
# Retrieve best bid and best ask from the orderbook
# ------------------------------------
"""
# first check if dataprovider is available
if self.dp:
if self.dp.runmode.value in ('live', 'dry_run'):
ob = self.dp.orderbook(metadata['pair'], 1)
dataframe['best_bid'] = ob['bids'][0][0]
dataframe['best_ask'] = ob['asks'][0][0]
"""
return dataframe
def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
dataframe.loc[
(
(dataframe['rsi'] > self.buy_RSI_long.value) & # Signal: RSI
(dataframe['bull_cand'] == 1) &
(dataframe['bull_cand'].shift(1) == 1) &
(dataframe['willy'] < self.buy_high_line.value) &
(dataframe['ema_will'] < self.buy_high_line.value)
),
'enter_long'] = 1
dataframe.loc[
(
(dataframe['rsi'] < self.buy_RSI_short.value) & # Signal: RSI
(dataframe['bear_cand'] == 1) &
(dataframe['bear_cand'].shift(1) == 1)&
(dataframe['willy'] > self.buy_low_line.value) &
(dataframe['ema_will'] > self.buy_low_line.value)
),
'enter_short'] = 1
return dataframe
def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
dataframe.loc[
(
(dataframe['bear_cand'] > 0) |
((dataframe['doji_cand'] > 0) &
(dataframe['doji_cand'].shift(1) > 0))
),
'exit_long'] = 1
dataframe.loc[
(
(dataframe['bull_cand'] > 0) |
((dataframe['doji_cand'] > 0) &
(dataframe['doji_cand'].shift(1) > 0))
),
'exit_short'] = 1
# print(dataframe.tail(30))
return dataframe
def plot_RSI(self, dataframe: DataFrame):
df = dataframe.copy()
df['drop_rsi'] = ta.RSI(df)
df['plot_rsi'] = np.where((df["drop_rsi"] > self.buy_RSI_long.value), df['high'] + (df['high'] * 0.01),
np.where((df["drop_rsi"] < self.buy_RSI_short.value),
df['low'] - (df['low'] * 0.01), np.nan))
df.drop(['drop_rsi'], inplace=True, axis=1)
return DataFrame(index=df.index, data={
'Plot_rsi': df['plot_rsi']
})
def heikin_asi_trigger(self, dataframe: DataFrame):
def _flat_top(close, low, open, high):
if high == open and low < close:
return 1
else:
return 0
def _wick_length(close, low, open, high):
if close > open:
top_wick = high - close
bottom_wick = open - low
else:
top_wick = high - open
bottom_wick = close - low
if top_wick > 0 and bottom_wick > 0:
return 1
else:
return 0
def _is_red_green(open, close):
if open < close:
return 1
else:
return 0
def _flat_bottom(close, low, open, high):
if open == low and high > close:
return 1
else:
return 0
df = dataframe.copy()
# heikinashi = qtpylib.heikinashi(df)
# df['ha_open'] = heikinashi['open']
# df['ha_close'] = heikinashi['close']
# df['ha_high'] = heikinashi['high']
# df['ha_low'] = heikinashi['low']
df['ha_open'] = heikinashi(df)['open']
df['ha_high'] = heikinashi(df)['high']
df['ha_low'] = heikinashi(df)['low']
df['ha_close'] = heikinashi(df)['close']
# df['doshi_cand'] = 0.0
# df['bull_cand'] = 0.0
# df['bear_cand'] = 0.0
df['ha_red_or_green'] = np.vectorize(_is_red_green)(df['ha_open'], df['ha_close'])
df['bull_cand'] = np.vectorize(_flat_bottom)(df['ha_close'], df['ha_low'], df['ha_open'], df['ha_high'])
df['plot_bull'] = np.where(df['bull_cand'] > 0, df['high'], np.NaN)
df['bear_cand'] = np.vectorize(_flat_top)(df['ha_close'], df['ha_low'], df['ha_open'], df['ha_high'])
df['plot_bear'] = np.where(df['bear_cand'] > 0, df['low'], np.NaN)
df['doji_cand'] = np.vectorize(_wick_length)(df['ha_close'], df['ha_low'], df['ha_open'], df['ha_high'])
df['plot_doji'] = np.where(df['doji_cand'] > 0, df['close'], np.NaN)
df.drop(['ha_open', 'ha_high', 'ha_low', 'ha_close'], inplace=True, axis=1)
return DataFrame(index=df.index, data={
'Doji_cand': df['doji_cand'],
'Bear_cand': df['bear_cand'],
'Bull_cand': df['bull_cand'],
'Red_or_green': df['ha_red_or_green'],
'Plot_bull': df['plot_bull'],
'Plot_bear': df['plot_bear'],
'Plot_doji': df['plot_doji']
})
def willy_ema(self, dataframe: DataFrame, low_line=-80.0, up_line=-20.0, willyLen=21, emaLen=13):
def max_help(open, high, low, close):
return max(open, high, low, close)
def min_help(open, high, low, close):
return min(open, high, low, close)
df = dataframe.copy()
df['highest'] = np.vectorize(max_help)(df['open'], df['high'], df['low'], df['close'])
df['lowest'] = np.vectorize(min_help)(df['open'], df['high'], df['low'], df['close'])
df['upper'] = df['highest'].rolling(willyLen).max()
df['lower'] = df['highest'].rolling(willyLen).min()
df['willy'] = 100 * (df['close'] - df['upper']) / (df['upper'] - df['lower'])
df['ema_will'] = ta.EMA(df['willy'], emaLen)
# df['ema_willy'] =
df.drop(['highest', 'lowest', 'upper', 'lower'], inplace=True, axis=1)
df['low_line'] = low_line
df['up_line'] = up_line
return DataFrame(index=df.index, data={
'Willy': df['willy'],
'Ema_will': df['ema_will'],
'Low_line': df['low_line'],
'Up_line': df['up_line']
})
# def bot_loop_start(self, **kwargs) -> None:
# """
# Called at the start of the bot iteration (one loop).
# Might be used to perform pair-independent tasks
# (e.g. gather some remote ressource for comparison)
#
# For full documentation please go to https://www.freqtrade.io/en/latest/strategy-advanced/
#
# When not implemented by a strategy, this simply does nothing.
# :param **kwargs: Ensure to keep this here so updates to this won't break your strategy.
# """
# pass
#
# def custom_entry_price(self, pair: str, current_time: 'datetime', proposed_rate: float,
# entry_tag: 'Optional[str]', side: str, **kwargs) -> float:
# """
# Custom entry price logic, returning the new entry price.
#
# For full documentation please go to https://www.freqtrade.io/en/latest/strategy-advanced/
#
# When not implemented by a strategy, returns None, orderbook is used to set entry price
#
# :param pair: Pair that's currently analyzed
# :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 **kwargs: Ensure to keep this here so updates to this won't break your strategy.
# :return float: New entry price value if provided
# """
# return proposed_rate
#
# def adjust_entry_price(self, trade: 'Trade', order: 'Optional[Order]', pair: str,
# current_time: datetime, proposed_rate: float, current_order_rate: float,
# entry_tag: Optional[str], side: str, **kwargs) -> float:
# """
# Entry price re-adjustment logic, returning the user desired limit price.
# This only executes when a order was already placed, still open (unfilled fully or partially)
# and not timed out on subsequent candles after entry trigger.
#
# For full documentation please go to https://www.freqtrade.io/en/latest/strategy-callbacks/
#
# When not implemented by a strategy, returns current_order_rate as default.
# If current_order_rate is returned then the existing order is maintained.
# If None is returned then order gets canceled but not replaced by a new one.
#
# :param pair: Pair that's currently analyzed
# :param trade: Trade object.
# :param order: Order object
# :param current_time: datetime object, containing the current datetime
# :param proposed_rate: Rate, calculated based on pricing settings in entry_pricing.
# :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 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
#
# """
# return current_order_rate
#
# def custom_exit_price(self, pair: str, trade: 'Trade',
# current_time: 'datetime', proposed_rate: float,
# current_profit: float, exit_tag: Optional[str], **kwargs) -> float:
# """
# Custom exit price logic, returning the new exit price.
#
# For full documentation please go to https://www.freqtrade.io/en/latest/strategy-advanced/
#
# When not implemented by a strategy, returns None, orderbook is used to set exit 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 current_profit: Current profit (as ratio), calculated based on current_rate.
# :param exit_tag: Exit reason.
# :param **kwargs: Ensure to keep this here so updates to this won't break your strategy.
# :return float: New exit price value if provided
# """
# return proposed_rate
#
def custom_stake_amount(self, pair: str, current_time: datetime, current_rate: float,
proposed_stake: float, min_stake: Optional[float], max_stake: float,
leverage: float, entry_tag: Optional[str], side: str,
**kwargs) -> float:
dataframe, last_updated = self.dp.get_analyzed_dataframe(pair=pair,
timeframe=self.timeframe)
stoploss_amount = max_stake / 200 # 0.5%
current_candle = dataframe.iloc[-1].squeeze()
if current_candle['ha_close'] >= current_candle['ha_open']:
if current_candle['ha_low'] >= current_candle['low']:
entry_by_norm_cand = (current_candle['close'] - current_candle['low']) / current_candle['close'] * 100
entry = stoploss_amount / entry_by_norm_cand * 100
if entry < max_stake / 100 * self.buy_cust_one_trade_limit_min.value:
# print(max_stake / 100 * self.buy_cust_one_trade_limit_min.value, 1)
return max_stake / 100 * self.buy_cust_one_trade_limit_min.value
elif entry > max_stake / 100 * self.buy_cust_one_trade_limit_max.value:
# print(max_stake / 100 * self.buy_cust_one_trade_limit_max.value , 2)
return max_stake / 100 * self.buy_cust_one_trade_limit_max.value
else:
# print(entry, 3)
return entry
else:
entry_by_ha_cand = (current_candle['close'] - (
(current_candle['low'] + current_candle['ha_low']) / 2)) / \
current_candle['close'] * 100
entry = stoploss_amount / entry_by_ha_cand * 100
if entry < max_stake / 100 * self.buy_cust_one_trade_limit_min.value:
# print(max_stake / 100 * self.buy_cust_one_trade_limit_min.value ,4)
return max_stake / 100 * self.buy_cust_one_trade_limit_min.value
elif entry > max_stake / 100 * self.buy_cust_one_trade_limit_max.value:
# print(max_stake / 100 * self.buy_cust_one_trade_limit_max.value, 5)
return max_stake / 100 * self.buy_cust_one_trade_limit_max.value
else:
# print(entry,6)
return entry
else:
if current_candle['ha_high'] <= current_candle['high']:
entry_by_norm_cand = (current_candle['close'] - current_candle['high']) / current_candle[
'close'] * 100 * -1
entry = stoploss_amount / entry_by_norm_cand * 100
if entry < max_stake / 100 * self.buy_cust_one_trade_limit_min.value:
# print(max_stake / 100 * self.buy_cust_one_trade_limit_min.value,7)
return max_stake / 100 * self.buy_cust_one_trade_limit_min.value
elif entry > max_stake / 100 * self.cbuy_cust_one_trade_limit_max:
# print(max_stake / 100 * self.buy_cust_one_trade_limit_max.value,8)
return max_stake / 100 * self.buy_cust_one_trade_limit_max.value
else:
# print(entry, 9)
return entry
else:
entry_by_ha_cand = (current_candle['close'] - ((current_candle['high'] + current_candle['ha_high']) /
2)) / current_candle['close'] * 100 * -1
entry = stoploss_amount / entry_by_ha_cand * 100
if entry < max_stake / 100 * self.buy_cust_one_trade_limit_min.value:
# print(max_stake / 100 * self.buy_cust_one_trade_limit_min.value ,10)
return max_stake / 100 * self.buy_cust_one_trade_limit_min.value
elif entry > max_stake / 100 * self.buy_cust_one_trade_limit_max.value:
# print(max_stake / 100 * self.buy_cust_one_trade_limit_max.value,11)
return max_stake / 100 * self.buy_cust_one_trade_limit_max.value
else:
# print(entry, 12)
return entry
# use_custom_stoploss = True
#
# def custom_stoploss(self, pair: str, trade: 'Trade', current_time: 'datetime',
# current_rate: float, current_profit: float, **kwargs) -> float:
#
# dataframe, _ = self.dp.get_analyzed_dataframe(pair, self.timeframe)
#
# trade_date = timeframe_to_prev_date(self.timeframe, trade.open_date_utc)
# # Look up trade candle.
# trade_candle = dataframe.loc[dataframe['date'] == trade_date]
# # trade_candle may be empty for trades that just opened as it is still incomplete.
#
# if not trade_candle.empty:
# trade_candle = trade_candle.squeeze()
#
# if trade_candle['ha_close'] >= trade_candle['ha_open']:
# if trade_candle['ha_low'] >= trade_candle['low']:
# print((trade_candle['close'] - trade_candle['low']) / trade_candle['close'] * -1)
# return (trade_candle['close'] - trade_candle['low']) / trade_candle['close'] * -1
#
# else:
# print((trade_candle['close'] - ((trade_candle['low'] + trade_candle['ha_low']) / 2))
# / trade_candle['close'] * -1)
# return (trade_candle['close'] - ((trade_candle['low'] + trade_candle['ha_low']) / 2)) \
# / trade_candle['close'] * -1
# else:
# if trade_candle['ha_high'] <= trade_candle['high']:
# print((trade_candle['close'] - trade_candle['high']) / trade_candle['close'])
# return (trade_candle['close'] - trade_candle['high']) / trade_candle['close']
# else:
# print((trade_candle['close'] - ((trade_candle['high'] + trade_candle['ha_high']) / 2))
# / trade_candle['close'])
# return (trade_candle['close'] - ((trade_candle['high'] + trade_candle['ha_high']) / 2))\
# / trade_candle['close']
#
# # return some value that won't cause stoploss to update
#
# return 100
#
# def custom_exit(self, pair: str, trade: 'Trade', current_time: 'datetime', current_rate: float,
# current_profit: float, **kwargs) -> 'Optional[Union[str, bool]]':
# """
# Custom exit signal logic indicating that specified position should be sold. Returning a
# string or True from this method is equal to setting sell signal on a candle at specified
# time. This method is not called when sell signal is set.
#
# This method should be overridden to create sell signals that depend on trade parameters. For
# example you could implement a sell relative to the candle when the trade was opened,
# or a custom 1:2 risk-reward ROI.
#
# Custom exit reason max length is 64. Exceeding characters will be removed.
#
# :param pair: Pair that's currently analyzed
# :param trade: trade object.
# :param current_time: datetime object, containing the current datetime
# :param current_rate: Rate, calculated based on pricing settings in exit_pricing.
# :param current_profit: Current profit (as ratio), calculated based on current_rate.
# :param **kwargs: Ensure to keep this here so updates to this won't break your strategy.
# :return: To execute sell, return a string with custom exit reason or True. Otherwise return
# None or False.
# """
# return None
#
# 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],
# side: str, **kwargs) -> bool:
# """
# Called right before placing a entry order.
# Timing for this function is critical, so avoid doing heavy computations or
# network requests in this method.
#
# For full documentation please go to https://www.freqtrade.io/en/latest/strategy-advanced/
#
# When not implemented by a strategy, returns True (always confirming).
#
# :param pair: Pair that's about to be bought/shorted.
# :param order_type: Order type (as configured in order_types). usually limit or market.
# :param amount: Amount in target (base) currency that's going to be traded.
# :param rate: Rate that's going to be used when using limit orders
# or current rate for market orders.
# :param time_in_force: Time in force. Defaults to GTC (Good-til-cancelled).
# :param current_time: datetime object, containing the current datetime
# :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 bool: When True is returned, then the buy-order is placed on the exchange.
# False aborts the process
# """
# return True
#
# def confirm_trade_exit(self, pair: str, trade: 'Trade', order_type: str, amount: float,
# rate: float, time_in_force: str, exit_reason: str,
# current_time: 'datetime', **kwargs) -> bool:
# """
# Called right before placing a regular exit order.
# Timing for this function is critical, so avoid doing heavy computations or
# network requests in this method.
#
# For full documentation please go to https://www.freqtrade.io/en/latest/strategy-advanced/
#
# When not implemented by a strategy, returns True (always confirming).
#
# :param pair: Pair for trade that's about to be exited.
# :param trade: trade object.
# :param order_type: Order type (as configured in order_types). usually limit or market.
# :param amount: Amount in base currency.
# :param rate: Rate that's going to be used when using limit orders
# or current rate for market orders.
# :param time_in_force: Time in force. Defaults to GTC (Good-til-cancelled).
# :param exit_reason: Exit reason.
# Can be any of ['roi', 'stop_loss', 'stoploss_on_exchange', 'trailing_stop_loss',
# 'exit_signal', 'force_exit', 'emergency_exit']
# :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.
# :return bool: When True, then the exit-order is placed on the exchange.
# False aborts the process
# """
# return True
#
# def check_entry_timeout(self, pair: str, trade: 'Trade', order: 'Order',
# current_time: datetime, **kwargs) -> bool:
# """
# Check entry timeout function callback.
# This method can be used to override the entry-timeout.
# It is called whenever a limit entry order has been created,
# and is not yet fully filled.
# Configuration options in `unfilledtimeout` will be verified before this,
# so ensure to set these timeouts high enough.
#
# For full documentation please go to https://www.freqtrade.io/en/latest/strategy-advanced/
#
# When not implemented by a strategy, this simply returns False.
# :param pair: Pair the trade is for
# :param trade: Trade object.
# :param order: Order object.
# :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.
# :return bool: When True is returned, then the entry order is cancelled.
# """
# return False
#
# def check_exit_timeout(self, pair: str, trade: 'Trade', order: 'Order',
# current_time: datetime, **kwargs) -> bool:
# """
# Check exit timeout function callback.
# This method can be used to override the exit-timeout.
# It is called whenever a limit exit order has been created,
# and is not yet fully filled.
# Configuration options in `unfilledtimeout` will be verified before this,
# so ensure to set these timeouts high enough.
#
# For full documentation please go to https://www.freqtrade.io/en/latest/strategy-advanced/
#
# When not implemented by a strategy, this simply returns False.
# :param pair: Pair the trade is for
# :param trade: Trade object.
# :param order: Order object.
# :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.
# :return bool: When True is returned, then the exit-order is cancelled.
# """
# return False
#
# def adjust_trade_position(self, trade: 'Trade', current_time: datetime,
# current_rate: float, current_profit: float,
# min_stake: Optional[float], max_stake: float,
# current_entry_rate: float, current_exit_rate: float,
# current_entry_profit: float, current_exit_profit: float,
# **kwargs) -> Optional[float]:
# """
# Custom trade adjustment logic, returning the stake amount that a trade should be
# increased or decreased.
# This means extra buy or sell orders with additional fees.
# Only called when `position_adjustment_enable` is set to True.
#
# For full documentation please go to https://www.freqtrade.io/en/latest/strategy-advanced/
#
# When not implemented by a strategy, returns None
#
# :param trade: trade object.
# :param current_time: datetime object, containing the current datetime
# :param current_rate: Current buy rate.
# :param current_profit: Current profit (as ratio), calculated based on current_rate.
# :param min_stake: Minimal stake size allowed by exchange (for both entries and exits)
# :param max_stake: Maximum stake allowed (either through balance, or by exchange limits).
# :param current_entry_rate: Current rate using entry pricing.
# :param current_exit_rate: Current rate using exit pricing.
# :param current_entry_profit: Current profit using entry pricing.
# :param current_exit_profit: Current profit using exit pricing.
# :param **kwargs: Ensure to keep this here so updates to this won't break your strategy.
# :return float: Stake amount to adjust your trade,
# Positive values to increase position, Negative values to decrease position.
# Return None for no action.
# """
# return None
#
# def leverage(self, pair: str, current_time: datetime, current_rate: float,
# proposed_leverage: float, max_leverage: float, entry_tag: Optional[str],
# side: str, **kwargs) -> float:
# """
# Customize leverage for each new trade. This method is only called in futures mode.
#
# :param pair: Pair that's currently analyzed
# :param current_time: datetime object, containing the current datetime
# :param current_rate: Rate, calculated based on pricing settings in exit_pricing.
# :param proposed_leverage: A leverage proposed by the bot.
# :param max_leverage: Max leverage allowed on this pair
# :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
# :return: A leverage amount, which is between 1.0 and max_leverage.
# """
# return 1.0