Timeframe
1d
Direction
Long Only
Stoploss
-34.2%
Trailing Stop
Yes
ROI
0m: 24.9%, 9457m: 13.3%, 23285m: 6.8%, 40133m: 0.0%
Interface Version
3
Startup Candles
N/A
Indicators
8
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 ---
from functools import reduce
import numpy as np
import pandas as pd
from pandas import DataFrame
from datetime import datetime
from typing import Optional, Union, Dict
from freqtrade.persistence import Trade
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
from technical import qtpylib
from technical.candles import heikinashi
Debug = False
class Heikin_Ashi1D174_spot_SI(IStrategy):
INTERFACE_VERSION = 3
# class HyperOpt:
# def stoploss_space():
# return [SKDecimal(-0.9, -0.5, decimals=2, 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
timeframe = '1d'
# Can this strategy go short?
can_short: bool = False
minimal_roi = {
"0": 0.249,
"9457": 0.133,
"23285": 0.068,
"40133": 0
}
stoploss = -0.342
trailing_stop = True
# 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 = 300
# 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'},
f'sl_l{self.buy_sl_mult.value}': {'color': 'red'},
f'sl_h{self.buy_sl_mult.value}': {'color': 'green'}
},
'subplots': {
# Subplots - each dict defines one additional plot
"MACD": {
'macd': {'color': 'blue'},
'macdsignal': {'color': 'orange'},
},
"RSI": {
'rsi': {'color': 'red'},
},
"Willy": {
f'willy{self.buy_willy.value}': {'color': 'red'},
f'ema_will{self.buy_ema.value}': {'color': 'blue'},
},
"sell_willy": {
f'sell_willy{self.sell_willy.value}': {'color': 'blue'},
f'sell_ema_will{self.sell_ema.value}': {'color': 'blue'}
},
"Doji_in_row": {
f"doji_in_row{self.sell_doji_in_row.value}": {'color': 'blue', 'type': 'bar'}
},
}
}
buy_RSI_long = IntParameter(30, 60, default=58, space="buy", optimize=True)
buy_RSI_short = IntParameter(30, 60, default=55, space="buy", optimize=True)
buy_bear_row = IntParameter(1, 3, default=1, space='buy', optimize=True)
buy_bull_row = IntParameter(1, 3, default=1, space='buy', optimize=True)
buy_ema = IntParameter(7, 22, default=18, space='buy', optimize=True)
buy_high_line = IntParameter(-30, 0, default=-2, space="buy", optimize=True)
buy_low_line = IntParameter(-100, -70, default=-89, space="buy", optimize=True)
buy_on_willy = BooleanParameter(default=False, space='buy', optimize=True)
buy_sl_mult = DecimalParameter(0.5, 5, default=3.4, decimals=1, space='buy', optimize=True)
buy_willy = IntParameter(15, 30, default=23, space='buy', optimize=True)
sell_doji_in_row = IntParameter(1, 6, default=2, space="sell", optimize=True)
sell_ema = IntParameter(7, 22, default=12, space='sell', optimize=True)
sell_high_line = IntParameter(-25, 0, default=-10, space="sell", optimize=True)
sell_low_line = IntParameter(-100, -75, default=-92, space="sell", optimize=True)
sell_willy = IntParameter(15, 30, default=22, space='sell', optimize=True)
sell_willy_exit = BooleanParameter(default=True, space='sell', optimize=True)
def informative_pairs(self):
pairs = self.dp.current_whitelist()
informative_pairs = [(pair, '1w') for pair in pairs]
informative_pairs += [("ETH/USDT", "1w"), ("BTC/USDT", "1w"), ("DOGE/USDT", "1w"), ("BNB/USDT", "1w"),
("XRP/USDT", "1w"),
("ADA/USDT", "1w"), ("MATIC/USDT", "1w"), ("DOT/USDT", "1w"),
("TRX/USDT", "1w"), ("LTC/USDT", "1w"),
("SOL/USDT", "1w"), ("UNI/USDT", "1w"), ("AVAX/USDT", "1w"), ("LPT/USDT", "1w"),
("LINK/USDT", "1w"), ("XMR/USDT", "1w"), ("ATOM/USDT", "1w"),
("ETC/USDT", "1w"), ("BCH/USDT", "1w"), ("XLM/USDT", "1w"), ("APE/USDT", "1w"),
("QNT/USDT", "1w"),
("ALGO/USDT", "1w"), ("VET/USDT", "1w"), ("NEAR/USDT", "1w"),
("HBAR/USDT", "1w"), ("ICP/USDT", "1w"), ("FIL/USDT", "1w"), ("EOS/USDT", "1w"),
("EGLD/USDT", "1w"),
("FLOW/USDT", "1w"), ("THETA/USDT", "1w"), ("AAVE/USDT", "1w"), ("XTZ/USDT", "1w"),
("AXS/USDT", "1w"), ("CHZ/USDT", "1w"), ("SAND/USDT", "1w"), ("ZEC/USDT", "1w"),
("MANA/USDT", "1w"),
("FTM/USDT", "1w"),
("MKR/USDT", "1w"),
("GRT/USDT", "1w"),
("KLAY/USDT", "1w"), ("DASH/USDT", "1w"), ("APT/USDT", "1w"),
("IOTA/USDT", "1w"),
("RUNE/USDT", "1w"), ("NEO/USDT", "1w"), ("SNX/USDT", "1w"),
("IMX/USDT", "1w"),
("FTT/USDT", "1w"), ("1INCH/USDT", "1w"),
("LDO/USDT", "1w"), ("ZIL/USDT", "1w"), ("BAT/USDT", "1w"),
("CRV/USDT", "1w"), ("LRC/USDT", "1w"),
("XEM/USDT", "1w"), ("ENJ/USDT", "1w"),
("HNT/USDT", "1w"), ("CVX/USDT", "1w"), ("HOT/USDT", "1w"), ("BAL/USDT", "1w"),
("KAVA/USDT", "1w"), ("RVN/USDT", "1w"),
("COMP/USDT", "1w"), ("CELO/USDT", "1w"), ("ENS/USDT", "1w"),
("OP/USDT", "1w"),
("KSM/USDT", "1w"), ("AR/USDT", "1w"), ("SUSHI/USDT", "1w"),
("QTUM/USDT", "1w"),
("YFI/USDT", "1w"), ("ROSE/USDT", "1w"), ("ONE/USDT", "1w"),
("BNX/USDT", "1w"),
("IOTX/USDT", "1w"), ("WAVES/USDT", "1w"),
("GMT/USDT", "1w"), ("ANKR/USDT", "1w"),
("MASK/USDT", "1w")
]
return informative_pairs
def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
inf_tf = '1w'
informative = self.dp.get_pair_dataframe(pair=metadata['pair'], timeframe=inf_tf)
informative['bear_cand'] = self.heikin_asi_trigger(dataframe, metadata, 1, 1, 1)['Bear_cand']
informative['bull_cand'] = self.heikin_asi_trigger(dataframe, metadata, 1, 1, 1)['Bull_cand']
dataframe = merge_informative_pair(dataframe, informative, self.timeframe, inf_tf, ffill=True)
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']
dataframe['doji_cand'] = self.heikin_asi_trigger(dataframe, metadata, 1, 1, 1)['Doji_cand']
dataframe['bear_cand'] = self.heikin_asi_trigger(dataframe, metadata, 1, 1, 1)['Bear_cand']
dataframe['bull_cand'] = self.heikin_asi_trigger(dataframe, metadata, 1, 1, 1)['Bull_cand']
dataframe['red_or_green'] = self.heikin_asi_trigger(dataframe, metadata, 1, 1, 1)['Red_or_green']
dataframe['plot_bull'] = self.heikin_asi_trigger(dataframe, metadata, 1, 1, 1)['Plot_bull']
dataframe['plot_bear'] = self.heikin_asi_trigger(dataframe, metadata, 1, 1, 1)['Plot_bear']
dataframe['plot_doji'] = self.heikin_asi_trigger(dataframe, metadata, 1, 1, 1)['Plot_doji']
for val in self.buy_willy.range:
dataframe[f'willy{val}'] = self.willy_ema(dataframe, low_line=self.buy_low_line.value,
up_line=self.buy_high_line.value, willyLen=val, emaLen=13)[
'Willy']
for val in self.buy_ema.range:
dataframe[f'ema_will{val}'] = self.willy_ema(dataframe, low_line=-80, up_line=-20, willyLen=21, emaLen=val)[
'Ema_will']
for val in self.buy_sl_mult.range:
dataframe[f'sl_l{val}'] = self.cust_stoploss(dataframe, length=20, mult=val)['Sl_low']
for val in self.buy_sl_mult.range:
dataframe[f'sl_h{val}'] = self.cust_stoploss(dataframe, length=20, mult=val)['Sl_high']
for val in self.sell_willy.range:
dataframe[f'sell_willy{val}'] = self.willy_ema(dataframe, low_line=self.buy_low_line.value,
up_line=self.buy_high_line.value, willyLen=val, emaLen=13)[
'Willy']
for val in self.sell_ema.range:
dataframe[f'sell_ema_will{val}'] = \
self.willy_ema(dataframe, low_line=-80, up_line=-20, willyLen=21, emaLen=val)[
'Ema_will']
for val in self.sell_doji_in_row.range:
dataframe[f'doji_in_row{val}'] = self.heikin_asi_trigger(dataframe, metadata, val, 1, 1)['Doji_in_row']
for val in self.buy_bull_row.range:
dataframe[f'buy_bull_row{val}'] = self.heikin_asi_trigger(dataframe, metadata, 1, val, 1)['Bull_in_row']
for val in self.buy_bear_row.range:
dataframe[f'buy_bear_row{val}'] = self.heikin_asi_trigger(dataframe, metadata, 1, 1, val)['Bear_in_row']
return dataframe
def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
conditions = [(dataframe['volume'] > 0)]
conditions.append((dataframe['rsi'] > self.buy_RSI_long.value) & # Signal: RSI
(dataframe[f'buy_bull_row{self.buy_bull_row.value}'] == self.buy_bull_row.value))
if self.buy_on_willy.value:
conditions.append((dataframe[f'willy{self.buy_willy.value}'] < self.buy_low_line.value) &
(dataframe[f'ema_will{self.buy_ema.value}'] < self.buy_low_line.value))
buy_conditions = reduce(lambda x, y: x & y, conditions)
dataframe.loc[buy_conditions, 'enter_long'] = 1
conditions = [(dataframe['volume'] > 0)]
conditions.append((dataframe['rsi'] < self.buy_RSI_short.value) & # Signal: RSI
(dataframe[f'buy_bear_row{self.buy_bear_row.value}'] == self.buy_bear_row.value))
if self.buy_on_willy.value:
conditions.append((dataframe[f'willy{self.buy_willy.value}'] > self.buy_high_line.value) &
(dataframe[f'ema_will{self.buy_ema.value}'] > self.buy_high_line.value))
if Debug:
print(conditions)
sell_conditions = reduce(lambda x, y: x & y, conditions)
dataframe.loc[sell_conditions, 'enter_short'] = 1
if Debug:
print(dataframe.tail(20))
return dataframe
def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
if not self.sell_willy_exit.value:
conditions = [(dataframe['bear_cand'] > 0) |
(dataframe[f'doji_in_row{self.sell_doji_in_row.value}'] == self.sell_doji_in_row.value)
]
else:
conditions = [(dataframe['bear_cand'] > 0) |
(dataframe[f'doji_in_row{self.sell_doji_in_row.value}'] == self.sell_doji_in_row.value) |
((dataframe[f'sell_willy{self.sell_willy.value}'] > self.sell_high_line.value) &
(dataframe[f'sell_ema_will{self.sell_ema.value}'] > self.sell_high_line.value))
]
sell_conditions = reduce(lambda x, y: x & y, conditions)
dataframe.loc[sell_conditions, 'exit_long'] = 1
if not self.sell_willy_exit.value:
conditions = [(dataframe['bull_cand'] > 0) |
(dataframe[f'doji_in_row{self.sell_doji_in_row.value}'] == self.sell_doji_in_row.value)]
else:
conditions = [(dataframe['bull_cand'] > 0) |
(dataframe[f'doji_in_row{self.sell_doji_in_row.value}'] == self.sell_doji_in_row.value) |
((dataframe[f'sell_willy{self.sell_willy.value}'] < self.sell_low_line.value) &
(dataframe[f'sell_ema_will{self.sell_ema.value}'] < self.sell_low_line.value))
]
sell_conditions = reduce(lambda x, y: x & y, conditions)
dataframe.loc[sell_conditions, 'exit_short'] = 1
if Debug:
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, metadata: dict, doji_sum, bull_row, bear_row):
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()
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['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['doji_in_row'] = df['doji_cand'].rolling(window=doji_sum).sum()
df['bull_in_row'] = df['bull_cand'].rolling(window=bull_row).sum()
df['bear_in_row'] = df['bear_cand'].rolling(window=bear_row).sum()
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'],
'Doji_in_row': df['doji_in_row'],
'Bull_in_row': df['bull_in_row'],
'Bear_in_row': df['bear_in_row']
})
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['lowest'].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 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, _ = self.dp.get_analyzed_dataframe(pair, self.timeframe)
candle = dataframe.iloc[-1].squeeze()
stoploss_pricel = candle[f'sl_l{self.buy_sl_mult.value}']
stoploss_prices = candle[f'sl_h{self.buy_sl_mult.value}']
middle_of_cand = (candle['high'] + candle['low'] + candle['close'] + candle['open']) / 4
if candle['ha_open'] < candle['ha_close']:
stoploss_ = (middle_of_cand - stoploss_pricel) / candle['close'] * 100
amount_ = self.wallets.get_total_stake_amount() / 100
if Debug:
print('stoploss from amount = >', stoploss_)
print('полній кошилек =>>>', self.wallets.get_total_stake_amount())
print('amount', amount_)
print('Amount final =>>', amount_ / stoploss_ * 100)
return (amount_ / stoploss_) * 100
if candle['ha_open'] > candle['ha_close']:
stoploss_ = (middle_of_cand - stoploss_prices) / candle['close'] * -1 * 100
amount_ = self.wallets.get_total_stake_amount() / 100
if Debug:
print('stoploos from amount =>', stoploss_)
print('полній кошилек =>>>', self.wallets.get_total_stake_amount())
print('amount', amount_)
print('Amount =>>', (amount_ / stoploss_) * 100)
return (amount_ / stoploss_) * 100
return 2000
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)
candle = dataframe.iloc[-1].squeeze()
stoploss_pricel = candle[f'sl_l{self.buy_sl_mult.value}']
stoploss_prices = candle[f'sl_h{self.buy_sl_mult.value}']
middle_of_cand = (candle['high'] + candle['low'] + candle['close'] + candle['open']) / 4
if Debug:
print('trade ID =>', trade.id, 'Trade is short? =>', trade.is_short)
print('sl hihg =>', candle[f'sl_h{self.buy_sl_mult.value}'], 'sl low =>', candle[f'sl_l{self.buy_sl_mult.value}'])
print('candle middle =>', middle_of_cand)
if not trade.is_short:
if Debug:
print(' ')
print('Trade is long', 'Stoploss ================================>',
(middle_of_cand - stoploss_pricel) / candle['close'] * -1)
print(' ')
return (middle_of_cand - stoploss_pricel) / candle['close'] * -1
if trade.is_short:
if Debug:
print(' ')
print('Trade is short', 'Stoploss ==============================>',
(middle_of_cand - stoploss_prices) / candle['close'])
print(' ')
return (middle_of_cand - stoploss_prices) / candle['close']
return 100
def cust_stoploss(self, dataframe: DataFrame, mult, length):
df = dataframe.copy()
df['sma'] = qtpylib.sma(df['close'], length)
df['tr'] = qtpylib.atr(df, length)
df['sl_high'] = qtpylib.sma(df['tr'], length)
def help1(x, mul, high):
return x * mul + high
df['sl_high'] = np.vectorize(help1)(df['sl_high'], mult, df['high'])
df['sl_low'] = qtpylib.sma(df['tr'], length)
def help1(x, mul, low):
return low - x * mul
df['sl_low'] = np.vectorize(help1)(df['sl_low'], mult, df['low'])
df.drop(['sma', 'tr'], axis=1, inplace=True)
return DataFrame(index=df.index, data={
'Sl_high': df['sl_high'],
'Sl_low': df['sl_low'],
})