strategies
This commit is contained in:
parent
6d5cfba012
commit
4907a66fc1
566
strategies/BigZ06.py
Executable file
566
strategies/BigZ06.py
Executable file
@ -0,0 +1,566 @@
|
|||||||
|
import freqtrade.vendor.qtpylib.indicators as qtpylib
|
||||||
|
import numpy as np
|
||||||
|
import talib.abstract as ta
|
||||||
|
from freqtrade.persistence import Trade
|
||||||
|
from freqtrade.strategy.interface import IStrategy
|
||||||
|
from pandas import DataFrame
|
||||||
|
from datetime import datetime, timedelta
|
||||||
|
from freqtrade.strategy import merge_informative_pair, CategoricalParameter, DecimalParameter, IntParameter
|
||||||
|
from functools import reduce
|
||||||
|
|
||||||
|
|
||||||
|
###########################################################################################################
|
||||||
|
## BigZ06 by ilya ##
|
||||||
|
## ##
|
||||||
|
## https://github.com/i1ya/freqtrade-strategies ##
|
||||||
|
## The stratagy most inspired by iterativ (authors of the CombinedBinHAndClucV6) ##
|
||||||
|
## ## ##
|
||||||
|
###########################################################################################################
|
||||||
|
## The main point of this strat is: ##
|
||||||
|
## - make drawdown as low as possible ##
|
||||||
|
## - buy at dip ##
|
||||||
|
## - sell quick as fast as you can (release money for the next buy) ##
|
||||||
|
## - soft check if market if rising ##
|
||||||
|
## - hard check is market if fallen ##
|
||||||
|
## - 14 buy signals ##
|
||||||
|
## - stoploss function preventing from big fall ##
|
||||||
|
## - no sell signal. Whether ROI or stoploss =) ##
|
||||||
|
## ##
|
||||||
|
###########################################################################################################
|
||||||
|
## GENERAL RECOMMENDATIONS ##
|
||||||
|
## ##
|
||||||
|
## For optimal performance, suggested to use between 3 and 5 open trades. ##
|
||||||
|
## ##
|
||||||
|
## As a pairlist you can use VolumePairlist. ##
|
||||||
|
## ##
|
||||||
|
## Ensure that you don't override any variables in your config.json. Especially ##
|
||||||
|
## the timeframe (must be 5m). ##
|
||||||
|
## ##
|
||||||
|
## sell_profit_only: ##
|
||||||
|
## True - risk more (gives you higher profit and higher Drawdown) ##
|
||||||
|
## False (default) - risk less (gives you less ~10-15% profit and much lower Drawdown) ##
|
||||||
|
## ##
|
||||||
|
## BigZ06 using market orders. ##
|
||||||
|
## Ensure you're familar with https://www.freqtrade.io/en/stable/configuration/#market-order-pricing ##
|
||||||
|
## ##
|
||||||
|
###########################################################################################################
|
||||||
|
## DONATIONS 2 @iterativ (author of the original strategy) ##
|
||||||
|
## ##
|
||||||
|
## Absolutely not required. However, will be accepted as a token of appreciation. ##
|
||||||
|
## ##
|
||||||
|
## BTC: bc1qvflsvddkmxh7eqhc4jyu5z5k6xcw3ay8jl49sk ##
|
||||||
|
## ETH: 0x83D3cFb8001BDC5d2211cBeBB8cB3461E5f7Ec91 ##
|
||||||
|
## ##
|
||||||
|
###########################################################################################################
|
||||||
|
|
||||||
|
|
||||||
|
class BigZ06(IStrategy):
|
||||||
|
INTERFACE_VERSION = 2
|
||||||
|
|
||||||
|
minimal_roi = {
|
||||||
|
"0": 0.028, # I feel lucky!
|
||||||
|
"10": 0.018,
|
||||||
|
"40": 0.005,
|
||||||
|
"180": 0.018, # We're going up?
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
stoploss = -0.99 # effectively disabled.
|
||||||
|
|
||||||
|
timeframe = '5m'
|
||||||
|
inf_1h = '1h'
|
||||||
|
|
||||||
|
# Sell signal
|
||||||
|
use_exit_signal = True
|
||||||
|
exit_profit_only = False
|
||||||
|
exit_profit_offset = 0.001 # it doesn't meant anything, just to guarantee there is a minimal profit.
|
||||||
|
ignore_roi_if_entry_signal = False
|
||||||
|
|
||||||
|
# Trailing stoploss
|
||||||
|
trailing_stop = False
|
||||||
|
trailing_only_offset_is_reached = False
|
||||||
|
trailing_stop_positive = 0.01
|
||||||
|
trailing_stop_positive_offset = 0.025
|
||||||
|
|
||||||
|
# Custom stoploss
|
||||||
|
use_custom_stoploss = True
|
||||||
|
|
||||||
|
# Run "populate_indicators()" only for new candle.
|
||||||
|
process_only_new_candles = True
|
||||||
|
|
||||||
|
# Number of candles the strategy requires before producing valid signals
|
||||||
|
startup_candle_count: int = 200
|
||||||
|
|
||||||
|
# Optional order type mapping.
|
||||||
|
order_types = {
|
||||||
|
'entry': 'market',
|
||||||
|
'exit': 'market',
|
||||||
|
'stoploss': 'market',
|
||||||
|
'stoploss_on_exchange': False
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
buy_params = {
|
||||||
|
#############
|
||||||
|
# Enable/Disable conditions
|
||||||
|
"buy_condition_0_enable": True,
|
||||||
|
"buy_condition_1_enable": True,
|
||||||
|
"buy_condition_2_enable": True,
|
||||||
|
"buy_condition_3_enable": True,
|
||||||
|
"buy_condition_4_enable": True,
|
||||||
|
"buy_condition_5_enable": True,
|
||||||
|
"buy_condition_6_enable": True,
|
||||||
|
"buy_condition_7_enable": True,
|
||||||
|
"buy_condition_8_enable": True,
|
||||||
|
"buy_condition_9_enable": True,
|
||||||
|
"buy_condition_10_enable": True,
|
||||||
|
"buy_condition_11_enable": True,
|
||||||
|
"buy_condition_12_enable": True,
|
||||||
|
"buy_condition_13_enable": True,
|
||||||
|
}
|
||||||
|
|
||||||
|
############################################################################
|
||||||
|
|
||||||
|
# Buy
|
||||||
|
|
||||||
|
buy_condition_0_enable = CategoricalParameter([True, False], default=True, space='buy', optimize=False, load=True)
|
||||||
|
buy_condition_1_enable = CategoricalParameter([True, False], default=True, space='buy', optimize=False, load=True)
|
||||||
|
buy_condition_2_enable = CategoricalParameter([True, False], default=True, space='buy', optimize=False, load=True)
|
||||||
|
buy_condition_3_enable = CategoricalParameter([True, False], default=True, space='buy', optimize=False, load=True)
|
||||||
|
buy_condition_4_enable = CategoricalParameter([True, False], default=True, space='buy', optimize=False, load=True)
|
||||||
|
buy_condition_5_enable = CategoricalParameter([True, False], default=True, space='buy', optimize=False, load=True)
|
||||||
|
buy_condition_6_enable = CategoricalParameter([True, False], default=True, space='buy', optimize=False, load=True)
|
||||||
|
buy_condition_7_enable = CategoricalParameter([True, False], default=True, space='buy', optimize=False, load=True)
|
||||||
|
buy_condition_8_enable = CategoricalParameter([True, False], default=True, space='buy', optimize=False, load=True)
|
||||||
|
buy_condition_9_enable = CategoricalParameter([True, False], default=True, space='buy', optimize=False, load=True)
|
||||||
|
buy_condition_10_enable = CategoricalParameter([True, False], default=True, space='buy', optimize=False, load=True)
|
||||||
|
buy_condition_11_enable = CategoricalParameter([True, False], default=True, space='buy', optimize=False, load=True)
|
||||||
|
buy_condition_12_enable = CategoricalParameter([True, False], default=True, space='buy', optimize=False, load=True)
|
||||||
|
buy_condition_13_enable = CategoricalParameter([True, False], default=True, space='buy', optimize=False, load=True)
|
||||||
|
|
||||||
|
buy_bb20_close_bblowerband_safe_1 = DecimalParameter(0.7, 1.1, default=0.989, space='buy', optimize=False, load=True)
|
||||||
|
buy_bb20_close_bblowerband_safe_2 = DecimalParameter(0.7, 1.1, default=0.982, space='buy', optimize=False, load=True)
|
||||||
|
|
||||||
|
buy_volume_pump_1 = DecimalParameter(0.1, 0.9, default=0.4, space='buy', decimals=1, optimize=False, load=True)
|
||||||
|
buy_volume_drop_1 = DecimalParameter(1, 10, default=3.8, space='buy', decimals=1, optimize=False, load=True)
|
||||||
|
buy_volume_drop_2 = DecimalParameter(1, 10, default=3, space='buy', decimals=1, optimize=False, load=True)
|
||||||
|
buy_volume_drop_3 = DecimalParameter(1, 10, default=2.7, space='buy', decimals=1, optimize=False, load=True)
|
||||||
|
|
||||||
|
buy_rsi_1h_1 = DecimalParameter(10.0, 40.0, default=16.5, space='buy', decimals=1, optimize=False, load=True)
|
||||||
|
buy_rsi_1h_2 = DecimalParameter(10.0, 40.0, default=15.0, space='buy', decimals=1, optimize=False, load=True)
|
||||||
|
buy_rsi_1h_3 = DecimalParameter(10.0, 40.0, default=20.0, space='buy', decimals=1, optimize=False, load=True)
|
||||||
|
buy_rsi_1h_4 = DecimalParameter(10.0, 40.0, default=35.0, space='buy', decimals=1, optimize=False, load=True)
|
||||||
|
buy_rsi_1h_5 = DecimalParameter(10.0, 60.0, default=39.0, space='buy', decimals=1, optimize=False, load=True)
|
||||||
|
|
||||||
|
buy_rsi_1 = DecimalParameter(10.0, 40.0, default=28.0, space='buy', decimals=1, optimize=False, load=True)
|
||||||
|
buy_rsi_2 = DecimalParameter(7.0, 40.0, default=10.0, space='buy', decimals=1, optimize=False, load=True)
|
||||||
|
buy_rsi_3 = DecimalParameter(7.0, 40.0, default=14.2, space='buy', decimals=1, optimize=False, load=True)
|
||||||
|
|
||||||
|
buy_macd_1 = DecimalParameter(0.01, 0.09, default=0.02, space='buy', decimals=2, optimize=False, load=True)
|
||||||
|
buy_macd_2 = DecimalParameter(0.01, 0.09, default=0.03, space='buy', decimals=2, optimize=False, load=True)
|
||||||
|
|
||||||
|
def confirm_trade_exit(self, pair: str, trade: Trade, order_type: str, amount: float,
|
||||||
|
rate: float, time_in_force: str, sell_reason: str, **kwargs) -> bool:
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
def custom_sell(self, pair: str, trade: 'Trade', current_time: 'datetime', current_rate: float,
|
||||||
|
current_profit: float, **kwargs):
|
||||||
|
|
||||||
|
return False
|
||||||
|
|
||||||
|
dataframe, _ = self.dp.get_analyzed_dataframe(pair, self.timeframe)
|
||||||
|
last_candle = dataframe.iloc[-1].squeeze()
|
||||||
|
last_candle_2 = dataframe.iloc[-2].squeeze()
|
||||||
|
|
||||||
|
if (last_candle is not None):
|
||||||
|
if (last_candle['high'] > last_candle['bb_upperband']) & (last_candle['volume'] > (last_candle_2['volume'] * 1.5)):
|
||||||
|
return 'sell_signal_1'
|
||||||
|
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def custom_stoploss(self, pair: str, trade: 'Trade', current_time: datetime,
|
||||||
|
current_rate: float, current_profit: float, **kwargs) -> float:
|
||||||
|
# Manage losing trades and open room for better ones.
|
||||||
|
|
||||||
|
if (current_profit > 0):
|
||||||
|
return 0.99
|
||||||
|
else:
|
||||||
|
trade_time_50 = trade.open_date_utc + timedelta(minutes=50)
|
||||||
|
|
||||||
|
# Trade open more then 60 minutes. For this strategy it's means -> loss
|
||||||
|
# Let's try to minimize the loss
|
||||||
|
|
||||||
|
if (current_time > trade_time_50):
|
||||||
|
|
||||||
|
try:
|
||||||
|
number_of_candle_shift = int((current_time - trade_time_50).total_seconds() / 300)
|
||||||
|
dataframe, _ = self.dp.get_analyzed_dataframe(pair, self.timeframe)
|
||||||
|
candle = dataframe.iloc[-number_of_candle_shift].squeeze()
|
||||||
|
|
||||||
|
# We are at bottom. Wait...
|
||||||
|
if candle['rsi_1h'] < 40:
|
||||||
|
return 0.99
|
||||||
|
|
||||||
|
# Are we still sinking?
|
||||||
|
if candle['close'] > candle['ema_200']:
|
||||||
|
if current_rate * 1.035 < candle['open']:
|
||||||
|
return 0.01
|
||||||
|
|
||||||
|
if current_rate * 1.025 < candle['open']:
|
||||||
|
return 0.01
|
||||||
|
|
||||||
|
except IndexError as error:
|
||||||
|
|
||||||
|
# Whoops, set stoploss at 10%
|
||||||
|
return 0.1
|
||||||
|
|
||||||
|
return 0.99
|
||||||
|
|
||||||
|
def informative_pairs(self):
|
||||||
|
pairs = self.dp.current_whitelist()
|
||||||
|
informative_pairs = [(pair, '1h') for pair in pairs]
|
||||||
|
return informative_pairs
|
||||||
|
|
||||||
|
def informative_1h_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||||
|
assert self.dp, "DataProvider is required for multiple timeframes."
|
||||||
|
# Get the informative pair
|
||||||
|
informative_1h = self.dp.get_pair_dataframe(pair=metadata['pair'], timeframe=self.inf_1h)
|
||||||
|
# EMA
|
||||||
|
informative_1h['ema_50'] = ta.EMA(informative_1h, timeperiod=50)
|
||||||
|
informative_1h['ema_200'] = ta.EMA(informative_1h, timeperiod=200)
|
||||||
|
# RSI
|
||||||
|
informative_1h['rsi'] = ta.RSI(informative_1h, timeperiod=14)
|
||||||
|
|
||||||
|
bollinger = qtpylib.bollinger_bands(qtpylib.typical_price(dataframe), window=20, stds=2)
|
||||||
|
informative_1h['bb_lowerband'] = bollinger['lower']
|
||||||
|
informative_1h['bb_middleband'] = bollinger['mid']
|
||||||
|
informative_1h['bb_upperband'] = bollinger['upper']
|
||||||
|
|
||||||
|
return informative_1h
|
||||||
|
|
||||||
|
def normal_tf_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||||
|
|
||||||
|
bollinger = qtpylib.bollinger_bands(qtpylib.typical_price(dataframe), window=20, stds=2)
|
||||||
|
dataframe['bb_lowerband'] = bollinger['lower']
|
||||||
|
dataframe['bb_middleband'] = bollinger['mid']
|
||||||
|
dataframe['bb_upperband'] = bollinger['upper']
|
||||||
|
|
||||||
|
dataframe['volume_mean_slow'] = dataframe['volume'].rolling(window=48).mean()
|
||||||
|
|
||||||
|
# EMA
|
||||||
|
dataframe['ema_200'] = ta.EMA(dataframe, timeperiod=200)
|
||||||
|
|
||||||
|
dataframe['ema_26'] = ta.EMA(dataframe, timeperiod=26)
|
||||||
|
dataframe['ema_12'] = ta.EMA(dataframe, timeperiod=12)
|
||||||
|
|
||||||
|
# MACD
|
||||||
|
dataframe['macd'], dataframe['signal'], dataframe['hist'] = ta.MACD(dataframe['close'], fastperiod=12, slowperiod=26, signalperiod=9)
|
||||||
|
|
||||||
|
# SMA
|
||||||
|
dataframe['sma_5'] = ta.EMA(dataframe, timeperiod=5)
|
||||||
|
|
||||||
|
# RSI
|
||||||
|
dataframe['rsi'] = ta.RSI(dataframe, timeperiod=14)
|
||||||
|
|
||||||
|
# Chaikin A/D Oscillator
|
||||||
|
dataframe['mfv'] = MFV(dataframe)
|
||||||
|
dataframe['cmf'] = dataframe['mfv'].rolling(20).sum()/dataframe['volume'].rolling(20).sum()
|
||||||
|
|
||||||
|
return dataframe
|
||||||
|
|
||||||
|
|
||||||
|
def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||||
|
# The indicators for the 1h informative timeframe
|
||||||
|
informative_1h = self.informative_1h_indicators(dataframe, metadata)
|
||||||
|
dataframe = merge_informative_pair(dataframe, informative_1h, self.timeframe, self.inf_1h, ffill=True)
|
||||||
|
|
||||||
|
# The indicators for the normal (5m) timeframe
|
||||||
|
dataframe = self.normal_tf_indicators(dataframe, metadata)
|
||||||
|
|
||||||
|
return dataframe
|
||||||
|
|
||||||
|
def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||||
|
|
||||||
|
conditions = []
|
||||||
|
|
||||||
|
conditions.append(
|
||||||
|
(
|
||||||
|
self.buy_condition_13_enable.value &
|
||||||
|
|
||||||
|
(dataframe['close'] > dataframe['ema_200_1h']) &
|
||||||
|
|
||||||
|
(dataframe['cmf'] < -0.435) &
|
||||||
|
(dataframe['rsi'] < 22) &
|
||||||
|
|
||||||
|
(dataframe['volume_mean_slow'] > dataframe['volume_mean_slow'].shift(48) * self.buy_volume_pump_1.value) &
|
||||||
|
(dataframe['volume_mean_slow'] * self.buy_volume_pump_1.value < dataframe['volume_mean_slow'].shift(48)) &
|
||||||
|
(dataframe['volume'] > 0)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
conditions.append(
|
||||||
|
(
|
||||||
|
self.buy_condition_12_enable.value &
|
||||||
|
|
||||||
|
(dataframe['close'] > dataframe['ema_200']) &
|
||||||
|
(dataframe['close'] > dataframe['ema_200_1h']) &
|
||||||
|
|
||||||
|
(dataframe['close'] < dataframe['bb_lowerband'] * 0.993) &
|
||||||
|
(dataframe['low'] < dataframe['bb_lowerband'] * 0.985) &
|
||||||
|
(dataframe['close'].shift() > dataframe['bb_lowerband']) &
|
||||||
|
(dataframe['rsi_1h'] < 72.8) &
|
||||||
|
(dataframe['open'] > dataframe['close']) &
|
||||||
|
|
||||||
|
(dataframe['volume_mean_slow'] > dataframe['volume_mean_slow'].shift(48) * self.buy_volume_pump_1.value) &
|
||||||
|
(dataframe['volume_mean_slow'] * self.buy_volume_pump_1.value < dataframe['volume_mean_slow'].shift(48)) &
|
||||||
|
(dataframe['volume'] < (dataframe['volume'].shift() * self.buy_volume_drop_1.value)) &
|
||||||
|
((dataframe['open'] - dataframe['close']) < dataframe['bb_upperband'].shift(2) - dataframe['bb_lowerband'].shift(2)) &
|
||||||
|
|
||||||
|
(dataframe['volume'] > 0)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
conditions.append(
|
||||||
|
(
|
||||||
|
self.buy_condition_11_enable.value &
|
||||||
|
|
||||||
|
(dataframe['close'] > dataframe['ema_200']) &
|
||||||
|
|
||||||
|
(dataframe['hist'] > 0) &
|
||||||
|
(dataframe['hist'].shift() > 0) &
|
||||||
|
(dataframe['hist'].shift(2) > 0) &
|
||||||
|
(dataframe['hist'].shift(3) > 0) &
|
||||||
|
(dataframe['hist'].shift(5) > 0) &
|
||||||
|
|
||||||
|
(dataframe['bb_middleband'] - dataframe['bb_middleband'].shift(5) > dataframe['close']/200) &
|
||||||
|
(dataframe['bb_middleband'] - dataframe['bb_middleband'].shift(10) > dataframe['close']/100) &
|
||||||
|
((dataframe['bb_upperband'] - dataframe['bb_lowerband']) < (dataframe['close']*0.1)) &
|
||||||
|
((dataframe['open'].shift() - dataframe['close'].shift()) < (dataframe['close'] * 0.018)) &
|
||||||
|
(dataframe['rsi'] > 51) &
|
||||||
|
|
||||||
|
(dataframe['open'] < dataframe['close']) &
|
||||||
|
(dataframe['open'].shift() > dataframe['close'].shift()) &
|
||||||
|
|
||||||
|
(dataframe['close'] > dataframe['bb_middleband']) &
|
||||||
|
(dataframe['close'].shift() < dataframe['bb_middleband'].shift()) &
|
||||||
|
(dataframe['low'].shift(2) > dataframe['bb_middleband'].shift(2)) &
|
||||||
|
|
||||||
|
(dataframe['volume'] > 0) # Make sure Volume is not 0
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
conditions.append(
|
||||||
|
(
|
||||||
|
self.buy_condition_0_enable.value &
|
||||||
|
|
||||||
|
(dataframe['close'] > dataframe['ema_200']) &
|
||||||
|
|
||||||
|
(dataframe['rsi'] < 30) &
|
||||||
|
(dataframe['close'] * 1.024 < dataframe['open'].shift(3)) &
|
||||||
|
(dataframe['rsi_1h'] < 71) &
|
||||||
|
|
||||||
|
(dataframe['volume_mean_slow'] > dataframe['volume_mean_slow'].shift(48) * self.buy_volume_pump_1.value) &
|
||||||
|
(dataframe['volume_mean_slow'] * self.buy_volume_pump_1.value < dataframe['volume_mean_slow'].shift(48)) &
|
||||||
|
(dataframe['volume'] > 0) # Make sure Volume is not 0
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
conditions.append(
|
||||||
|
(
|
||||||
|
self.buy_condition_1_enable.value &
|
||||||
|
|
||||||
|
(dataframe['close'] > dataframe['ema_200']) &
|
||||||
|
(dataframe['close'] > dataframe['ema_200_1h']) &
|
||||||
|
|
||||||
|
(dataframe['close'] < dataframe['bb_lowerband'] * self.buy_bb20_close_bblowerband_safe_1.value) &
|
||||||
|
(dataframe['rsi_1h'] < 69) &
|
||||||
|
(dataframe['open'] > dataframe['close']) &
|
||||||
|
|
||||||
|
(dataframe['volume_mean_slow'] > dataframe['volume_mean_slow'].shift(48) * self.buy_volume_pump_1.value) &
|
||||||
|
(dataframe['volume_mean_slow'] * self.buy_volume_pump_1.value < dataframe['volume_mean_slow'].shift(48)) &
|
||||||
|
(dataframe['volume'] < (dataframe['volume'].shift() * self.buy_volume_drop_1.value)) &
|
||||||
|
((dataframe['open'] - dataframe['close']) < dataframe['bb_upperband'].shift(2) - dataframe['bb_lowerband'].shift(2)) &
|
||||||
|
|
||||||
|
(dataframe['volume'] > 0)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
conditions.append(
|
||||||
|
(
|
||||||
|
self.buy_condition_2_enable.value &
|
||||||
|
|
||||||
|
(dataframe['close'] > dataframe['ema_200']) &
|
||||||
|
|
||||||
|
(dataframe['close'] < dataframe['bb_lowerband'] * self.buy_bb20_close_bblowerband_safe_2.value) &
|
||||||
|
|
||||||
|
(dataframe['volume_mean_slow'] > dataframe['volume_mean_slow'].shift(48) * self.buy_volume_pump_1.value) &
|
||||||
|
(dataframe['volume_mean_slow'] * self.buy_volume_pump_1.value < dataframe['volume_mean_slow'].shift(48)) &
|
||||||
|
(dataframe['volume'] < (dataframe['volume'].shift() * self.buy_volume_drop_1.value)) &
|
||||||
|
(dataframe['open'] - dataframe['close'] < dataframe['bb_upperband'].shift(2) - dataframe['bb_lowerband'].shift(2)) &
|
||||||
|
(dataframe['volume'] > 0)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
conditions.append(
|
||||||
|
(
|
||||||
|
self.buy_condition_3_enable.value &
|
||||||
|
|
||||||
|
(dataframe['close'] > dataframe['ema_200_1h']) &
|
||||||
|
|
||||||
|
(dataframe['close'] < dataframe['bb_lowerband']) &
|
||||||
|
(dataframe['rsi'] < self.buy_rsi_3.value) &
|
||||||
|
|
||||||
|
(dataframe['volume_mean_slow'] > dataframe['volume_mean_slow'].shift(48) * self.buy_volume_pump_1.value) &
|
||||||
|
(dataframe['volume_mean_slow'] * self.buy_volume_pump_1.value < dataframe['volume_mean_slow'].shift(48)) &
|
||||||
|
(dataframe['volume'] < (dataframe['volume'].shift() * self.buy_volume_drop_3.value)) &
|
||||||
|
|
||||||
|
(dataframe['volume'] > 0)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
conditions.append(
|
||||||
|
(
|
||||||
|
self.buy_condition_4_enable.value &
|
||||||
|
|
||||||
|
(dataframe['rsi_1h'] < self.buy_rsi_1h_1.value) &
|
||||||
|
|
||||||
|
(dataframe['close'] < dataframe['bb_lowerband']) &
|
||||||
|
|
||||||
|
(dataframe['volume_mean_slow'] > dataframe['volume_mean_slow'].shift(48) * self.buy_volume_pump_1.value) &
|
||||||
|
(dataframe['volume_mean_slow'] * self.buy_volume_pump_1.value < dataframe['volume_mean_slow'].shift(48)) &
|
||||||
|
(dataframe['volume'] < (dataframe['volume'].shift() * self.buy_volume_drop_1.value)) &
|
||||||
|
(dataframe['volume'] > 0)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
conditions.append(
|
||||||
|
(
|
||||||
|
self.buy_condition_5_enable.value &
|
||||||
|
|
||||||
|
(dataframe['close'] > dataframe['ema_200']) &
|
||||||
|
(dataframe['close'] > dataframe['ema_200_1h']) &
|
||||||
|
|
||||||
|
(dataframe['ema_26'] > dataframe['ema_12']) &
|
||||||
|
((dataframe['ema_26'] - dataframe['ema_12']) > (dataframe['open'] * self.buy_macd_1.value)) &
|
||||||
|
((dataframe['ema_26'].shift() - dataframe['ema_12'].shift()) > (dataframe['open']/100)) &
|
||||||
|
(dataframe['close'] < (dataframe['bb_lowerband'])) &
|
||||||
|
|
||||||
|
(dataframe['volume'] < (dataframe['volume'].shift() * self.buy_volume_drop_1.value)) &
|
||||||
|
(dataframe['volume_mean_slow'] > dataframe['volume_mean_slow'].shift(48) * self.buy_volume_pump_1.value) &
|
||||||
|
(dataframe['volume_mean_slow'] * self.buy_volume_pump_1.value < dataframe['volume_mean_slow'].shift(48)) &
|
||||||
|
(dataframe['volume'] > 0) # Make sure Volume is not 0
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
conditions.append(
|
||||||
|
(
|
||||||
|
self.buy_condition_6_enable.value &
|
||||||
|
|
||||||
|
(dataframe['rsi_1h'] < self.buy_rsi_1h_5.value) &
|
||||||
|
|
||||||
|
(dataframe['ema_26'] > dataframe['ema_12']) &
|
||||||
|
((dataframe['ema_26'] - dataframe['ema_12']) > (dataframe['open'] * self.buy_macd_2.value)) &
|
||||||
|
((dataframe['ema_26'].shift() - dataframe['ema_12'].shift()) > (dataframe['open']/100)) &
|
||||||
|
(dataframe['close'] < (dataframe['bb_lowerband'])) &
|
||||||
|
|
||||||
|
(dataframe['volume_mean_slow'] > dataframe['volume_mean_slow'].shift(48) * self.buy_volume_pump_1.value) &
|
||||||
|
(dataframe['volume_mean_slow'] * self.buy_volume_pump_1.value < dataframe['volume_mean_slow'].shift(48)) &
|
||||||
|
(dataframe['volume'] < (dataframe['volume'].shift() * self.buy_volume_drop_1.value)) &
|
||||||
|
(dataframe['volume'] > 0)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
conditions.append(
|
||||||
|
(
|
||||||
|
self.buy_condition_7_enable.value &
|
||||||
|
|
||||||
|
(dataframe['rsi_1h'] < self.buy_rsi_1h_2.value) &
|
||||||
|
|
||||||
|
(dataframe['ema_26'] > dataframe['ema_12']) &
|
||||||
|
((dataframe['ema_26'] - dataframe['ema_12']) > (dataframe['open'] * self.buy_macd_1.value)) &
|
||||||
|
((dataframe['ema_26'].shift() - dataframe['ema_12'].shift()) > (dataframe['open']/100)) &
|
||||||
|
|
||||||
|
(dataframe['volume'] < (dataframe['volume'].shift() * self.buy_volume_drop_1.value)) &
|
||||||
|
(dataframe['volume_mean_slow'] > dataframe['volume_mean_slow'].shift(48) * self.buy_volume_pump_1.value) &
|
||||||
|
(dataframe['volume_mean_slow'] * self.buy_volume_pump_1.value < dataframe['volume_mean_slow'].shift(48)) &
|
||||||
|
(dataframe['volume'] > 0)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
conditions.append(
|
||||||
|
(
|
||||||
|
|
||||||
|
self.buy_condition_8_enable.value &
|
||||||
|
|
||||||
|
(dataframe['rsi_1h'] < self.buy_rsi_1h_3.value) &
|
||||||
|
(dataframe['rsi'] < self.buy_rsi_1.value) &
|
||||||
|
|
||||||
|
(dataframe['volume'] < (dataframe['volume'].shift() * self.buy_volume_drop_1.value)) &
|
||||||
|
|
||||||
|
(dataframe['volume'] > 0)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
conditions.append(
|
||||||
|
(
|
||||||
|
|
||||||
|
self.buy_condition_9_enable.value &
|
||||||
|
|
||||||
|
(dataframe['rsi_1h'] < self.buy_rsi_1h_4.value) &
|
||||||
|
(dataframe['rsi'] < self.buy_rsi_2.value) &
|
||||||
|
|
||||||
|
(dataframe['volume'] < (dataframe['volume'].shift() * self.buy_volume_drop_1.value)) &
|
||||||
|
(dataframe['volume_mean_slow'] > dataframe['volume_mean_slow'].shift(48) * self.buy_volume_pump_1.value) &
|
||||||
|
(dataframe['volume_mean_slow'] * self.buy_volume_pump_1.value < dataframe['volume_mean_slow'].shift(48)) &
|
||||||
|
(dataframe['volume'] > 0)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
conditions.append(
|
||||||
|
(
|
||||||
|
|
||||||
|
self.buy_condition_10_enable.value &
|
||||||
|
|
||||||
|
(dataframe['rsi_1h'] < self.buy_rsi_1h_4.value) &
|
||||||
|
(dataframe['close_1h'] < dataframe['bb_lowerband_1h']) &
|
||||||
|
|
||||||
|
(dataframe['hist'] > 0) &
|
||||||
|
(dataframe['hist'].shift(2) < 0) &
|
||||||
|
(dataframe['rsi'] < 40.5) &
|
||||||
|
(dataframe['hist'] > dataframe['close'] * 0.0012) &
|
||||||
|
(dataframe['open'] < dataframe['close']) &
|
||||||
|
|
||||||
|
(dataframe['volume'] > 0)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
if conditions:
|
||||||
|
dataframe.loc[
|
||||||
|
reduce(lambda x, y: x | y, conditions),
|
||||||
|
'buy'
|
||||||
|
] = 1
|
||||||
|
|
||||||
|
return dataframe
|
||||||
|
|
||||||
|
def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||||
|
dataframe.loc[
|
||||||
|
(
|
||||||
|
(dataframe['close'] > dataframe['bb_middleband'] * 1.01) & # Don't be gready, sell fast
|
||||||
|
(dataframe['volume'] > 0) # Make sure Volume is not 0
|
||||||
|
)
|
||||||
|
,
|
||||||
|
'sell'
|
||||||
|
] = 0
|
||||||
|
return dataframe
|
||||||
|
|
||||||
|
# Chaikin Money Flow Volume
|
||||||
|
def MFV(dataframe):
|
||||||
|
df = dataframe.copy()
|
||||||
|
N = ((df['close'] - df['low']) - (df['high'] - df['close'])) / (df['high'] - df['low'])
|
||||||
|
M = N * df['volume']
|
||||||
|
return M
|
596
strategies/BigZ07.py
Executable file
596
strategies/BigZ07.py
Executable file
@ -0,0 +1,596 @@
|
|||||||
|
import freqtrade.vendor.qtpylib.indicators as qtpylib
|
||||||
|
import numpy as np
|
||||||
|
import talib.abstract as ta
|
||||||
|
from freqtrade.persistence import Trade
|
||||||
|
from freqtrade.strategy.interface import IStrategy
|
||||||
|
from pandas import DataFrame
|
||||||
|
from datetime import datetime, timedelta
|
||||||
|
from freqtrade.strategy import merge_informative_pair, CategoricalParameter, DecimalParameter, IntParameter
|
||||||
|
from functools import reduce
|
||||||
|
|
||||||
|
|
||||||
|
###########################################################################################################
|
||||||
|
## BigZ07 by ilya ##
|
||||||
|
## ##
|
||||||
|
## https://github.com/i1ya/freqtrade-strategies ##
|
||||||
|
## The stratagy most inspired by iterativ (authors of the CombinedBinHAndClucV6) ##
|
||||||
|
## ## ##
|
||||||
|
###########################################################################################################
|
||||||
|
## The main point of this strat is: ##
|
||||||
|
## - make drawdown as low as possible ##
|
||||||
|
## - buy at dip ##
|
||||||
|
## - sell quick as fast as you can (release money for the next buy) ##
|
||||||
|
## - soft check if market if rising ##
|
||||||
|
## - hard check is market if fallen ##
|
||||||
|
## - 14 buy signals ##
|
||||||
|
## - stoploss function preventing from big fall ##
|
||||||
|
## - no sell signal. Whether ROI or stoploss =) ##
|
||||||
|
## ##
|
||||||
|
###########################################################################################################
|
||||||
|
## GENERAL RECOMMENDATIONS ##
|
||||||
|
## ##
|
||||||
|
## For optimal performance, suggested to use between 3 and 5 open trades. ##
|
||||||
|
## ##
|
||||||
|
## As a pairlist you can use VolumePairlist. ##
|
||||||
|
## ##
|
||||||
|
## Ensure that you don't override any variables in your config.json. Especially ##
|
||||||
|
## the timeframe (must be 5m). ##
|
||||||
|
## ##
|
||||||
|
## sell_profit_only: ##
|
||||||
|
## True - risk more (gives you higher profit and higher Drawdown) ##
|
||||||
|
## False (default) - risk less (gives you less ~10-15% profit and much lower Drawdown) ##
|
||||||
|
## ##
|
||||||
|
## BigZ06 using market orders. ##
|
||||||
|
## Ensure you're familar with https://www.freqtrade.io/en/stable/configuration/#market-order-pricing ##
|
||||||
|
## ##
|
||||||
|
###########################################################################################################
|
||||||
|
## DONATIONS 2 @iterativ (author of the original strategy) ##
|
||||||
|
## ##
|
||||||
|
## Absolutely not required. However, will be accepted as a token of appreciation. ##
|
||||||
|
## ##
|
||||||
|
## BTC: bc1qvflsvddkmxh7eqhc4jyu5z5k6xcw3ay8jl49sk ##
|
||||||
|
## ETH: 0x83D3cFb8001BDC5d2211cBeBB8cB3461E5f7Ec91 ##
|
||||||
|
## ##
|
||||||
|
###########################################################################################################
|
||||||
|
|
||||||
|
|
||||||
|
class BigZ07(IStrategy):
|
||||||
|
INTERFACE_VERSION = 2
|
||||||
|
|
||||||
|
minimal_roi = {
|
||||||
|
"0": 0.028, # I feel lucky!
|
||||||
|
"10": 0.018,
|
||||||
|
"40": 0.005,
|
||||||
|
"180": 0.018, # We're going up?
|
||||||
|
}
|
||||||
|
|
||||||
|
stoploss = -0.99 # effectively disabled.
|
||||||
|
|
||||||
|
timeframe = '5m'
|
||||||
|
inf_1h = '1h'
|
||||||
|
|
||||||
|
# Sell signal
|
||||||
|
use_sell_signal = True
|
||||||
|
sell_profit_only = False
|
||||||
|
sell_profit_offset = 0.001 # it doesn't meant anything, just to guarantee there is a minimal profit.
|
||||||
|
ignore_roi_if_buy_signal = False
|
||||||
|
|
||||||
|
# Trailing stoploss
|
||||||
|
trailing_stop = False
|
||||||
|
trailing_only_offset_is_reached = False
|
||||||
|
trailing_stop_positive = 0.01
|
||||||
|
trailing_stop_positive_offset = 0.025
|
||||||
|
|
||||||
|
# Custom stoploss
|
||||||
|
use_custom_stoploss = True
|
||||||
|
|
||||||
|
# Run "populate_indicators()" only for new candle.
|
||||||
|
process_only_new_candles = True
|
||||||
|
|
||||||
|
# Number of candles the strategy requires before producing valid signals
|
||||||
|
startup_candle_count: int = 200
|
||||||
|
|
||||||
|
# Optional order type mapping.
|
||||||
|
order_types = {
|
||||||
|
'buy': 'market',
|
||||||
|
'sell': 'market',
|
||||||
|
'stoploss': 'market',
|
||||||
|
'stoploss_on_exchange': False
|
||||||
|
}
|
||||||
|
|
||||||
|
buy_params = {
|
||||||
|
#############
|
||||||
|
# Enable/Disable conditions
|
||||||
|
"buy_condition_0_enable": True,
|
||||||
|
"buy_condition_1_enable": True,
|
||||||
|
"buy_condition_2_enable": True,
|
||||||
|
"buy_condition_3_enable": True,
|
||||||
|
"buy_condition_4_enable": True,
|
||||||
|
"buy_condition_5_enable": True,
|
||||||
|
"buy_condition_6_enable": True,
|
||||||
|
"buy_condition_7_enable": True,
|
||||||
|
"buy_condition_8_enable": True,
|
||||||
|
"buy_condition_9_enable": True,
|
||||||
|
"buy_condition_10_enable": True,
|
||||||
|
"buy_condition_11_enable": True,
|
||||||
|
"buy_condition_12_enable": True,
|
||||||
|
"buy_condition_13_enable": True,
|
||||||
|
}
|
||||||
|
|
||||||
|
############################################################################
|
||||||
|
|
||||||
|
# Buy
|
||||||
|
|
||||||
|
buy_condition_0_enable = CategoricalParameter([True, False], default=True, space='buy', optimize=False, load=True)
|
||||||
|
buy_condition_1_enable = CategoricalParameter([True, False], default=True, space='buy', optimize=False, load=True)
|
||||||
|
buy_condition_2_enable = CategoricalParameter([True, False], default=True, space='buy', optimize=False, load=True)
|
||||||
|
buy_condition_3_enable = CategoricalParameter([True, False], default=True, space='buy', optimize=False, load=True)
|
||||||
|
buy_condition_4_enable = CategoricalParameter([True, False], default=True, space='buy', optimize=False, load=True)
|
||||||
|
buy_condition_5_enable = CategoricalParameter([True, False], default=True, space='buy', optimize=False, load=True)
|
||||||
|
buy_condition_6_enable = CategoricalParameter([True, False], default=True, space='buy', optimize=False, load=True)
|
||||||
|
buy_condition_7_enable = CategoricalParameter([True, False], default=True, space='buy', optimize=False, load=True)
|
||||||
|
buy_condition_8_enable = CategoricalParameter([True, False], default=True, space='buy', optimize=False, load=True)
|
||||||
|
buy_condition_9_enable = CategoricalParameter([True, False], default=True, space='buy', optimize=False, load=True)
|
||||||
|
buy_condition_10_enable = CategoricalParameter([True, False], default=True, space='buy', optimize=False, load=True)
|
||||||
|
buy_condition_11_enable = CategoricalParameter([True, False], default=True, space='buy', optimize=False, load=True)
|
||||||
|
buy_condition_12_enable = CategoricalParameter([True, False], default=True, space='buy', optimize=False, load=True)
|
||||||
|
buy_condition_13_enable = CategoricalParameter([True, False], default=True, space='buy', optimize=False, load=True)
|
||||||
|
|
||||||
|
buy_bb20_close_bblowerband_safe_1 = DecimalParameter(0.7, 1.1, default=0.989, space='buy', optimize=False,
|
||||||
|
load=True)
|
||||||
|
buy_bb20_close_bblowerband_safe_2 = DecimalParameter(0.7, 1.1, default=0.982, space='buy', optimize=False,
|
||||||
|
load=True)
|
||||||
|
|
||||||
|
buy_volume_pump_1 = DecimalParameter(0.1, 0.9, default=0.4, space='buy', decimals=1, optimize=False, load=True)
|
||||||
|
buy_volume_drop_1 = DecimalParameter(1, 10, default=3.8, space='buy', decimals=1, optimize=False, load=True)
|
||||||
|
buy_volume_drop_2 = DecimalParameter(1, 10, default=3, space='buy', decimals=1, optimize=False, load=True)
|
||||||
|
buy_volume_drop_3 = DecimalParameter(1, 10, default=2.7, space='buy', decimals=1, optimize=False, load=True)
|
||||||
|
|
||||||
|
buy_rsi_1h_1 = DecimalParameter(10.0, 40.0, default=16.5, space='buy', decimals=1, optimize=False, load=True)
|
||||||
|
buy_rsi_1h_2 = DecimalParameter(10.0, 40.0, default=15.0, space='buy', decimals=1, optimize=False, load=True)
|
||||||
|
buy_rsi_1h_3 = DecimalParameter(10.0, 40.0, default=20.0, space='buy', decimals=1, optimize=False, load=True)
|
||||||
|
buy_rsi_1h_4 = DecimalParameter(10.0, 40.0, default=35.0, space='buy', decimals=1, optimize=False, load=True)
|
||||||
|
buy_rsi_1h_5 = DecimalParameter(10.0, 60.0, default=39.0, space='buy', decimals=1, optimize=False, load=True)
|
||||||
|
|
||||||
|
buy_rsi_1 = DecimalParameter(10.0, 40.0, default=28.0, space='buy', decimals=1, optimize=False, load=True)
|
||||||
|
buy_rsi_2 = DecimalParameter(7.0, 40.0, default=10.0, space='buy', decimals=1, optimize=False, load=True)
|
||||||
|
buy_rsi_3 = DecimalParameter(7.0, 40.0, default=14.2, space='buy', decimals=1, optimize=False, load=True)
|
||||||
|
|
||||||
|
buy_macd_1 = DecimalParameter(0.01, 0.09, default=0.02, space='buy', decimals=2, optimize=False, load=True)
|
||||||
|
buy_macd_2 = DecimalParameter(0.01, 0.09, default=0.03, space='buy', decimals=2, optimize=False, load=True)
|
||||||
|
|
||||||
|
def confirm_trade_exit(self, pair: str, trade: Trade, order_type: str, amount: float,
|
||||||
|
rate: float, time_in_force: str, sell_reason: str, **kwargs) -> bool:
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
dataframe, _ = self.dp.get_analyzed_dataframe(pair, self.timeframe)
|
||||||
|
last_candle = dataframe.iloc[-1].squeeze()
|
||||||
|
last_candle_1 = dataframe.iloc[-2].squeeze()
|
||||||
|
|
||||||
|
if (sell_reason == 'roi'):
|
||||||
|
# Looks like we can get a little have more
|
||||||
|
if (last_candle['cmf'] < -0.1) & (last_candle['close'] > last_candle['ema_200_1h']):
|
||||||
|
return False
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
def custom_sell(self, pair: str, trade: 'Trade', current_time: 'datetime', current_rate: float,
|
||||||
|
current_profit: float, **kwargs):
|
||||||
|
|
||||||
|
return False
|
||||||
|
|
||||||
|
dataframe, _ = self.dp.get_analyzed_dataframe(pair, self.timeframe)
|
||||||
|
last_candle = dataframe.iloc[-1].squeeze()
|
||||||
|
last_candle_2 = dataframe.iloc[-2].squeeze()
|
||||||
|
|
||||||
|
if (last_candle is not None):
|
||||||
|
if (last_candle['high'] > last_candle['bb_upperband']) & (
|
||||||
|
last_candle['volume'] > (last_candle_2['volume'] * 1.5)):
|
||||||
|
return 'sell_signal_1'
|
||||||
|
|
||||||
|
return False
|
||||||
|
|
||||||
|
def custom_stoploss(self, pair: str, trade: 'Trade', current_time: datetime,
|
||||||
|
current_rate: float, current_profit: float, **kwargs) -> float:
|
||||||
|
# Manage losing trades and open room for better ones.
|
||||||
|
|
||||||
|
if (current_profit > 0):
|
||||||
|
return 0.99
|
||||||
|
else:
|
||||||
|
trade_time_50 = trade.open_date_utc + timedelta(minutes=50)
|
||||||
|
|
||||||
|
# Trade open more then 60 minutes. For this strategy it's means -> loss
|
||||||
|
# Let's try to minimize the loss
|
||||||
|
|
||||||
|
if (current_time > trade_time_50):
|
||||||
|
|
||||||
|
try:
|
||||||
|
number_of_candle_shift = int((current_time - trade_time_50).total_seconds() / 300)
|
||||||
|
dataframe, _ = self.dp.get_analyzed_dataframe(pair, self.timeframe)
|
||||||
|
candle = dataframe.iloc[-number_of_candle_shift].squeeze()
|
||||||
|
|
||||||
|
# We are at bottom. Wait...
|
||||||
|
if candle['rsi_1h'] < 40:
|
||||||
|
return 0.99
|
||||||
|
|
||||||
|
if candle['open_1h'] > candle['ema_200_1h']:
|
||||||
|
return 0.1
|
||||||
|
|
||||||
|
# Are we still sinking?
|
||||||
|
if current_rate * 1.025 < candle['open']:
|
||||||
|
return 0.01
|
||||||
|
|
||||||
|
except IndexError as error:
|
||||||
|
|
||||||
|
# Whoops, set stoploss at 10%
|
||||||
|
return 0.1
|
||||||
|
|
||||||
|
return 0.99
|
||||||
|
|
||||||
|
def informative_pairs(self):
|
||||||
|
pairs = self.dp.current_whitelist()
|
||||||
|
informative_pairs = [(pair, '1h') for pair in pairs]
|
||||||
|
return informative_pairs
|
||||||
|
|
||||||
|
def informative_1h_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||||
|
assert self.dp, "DataProvider is required for multiple timeframes."
|
||||||
|
# Get the informative pair
|
||||||
|
informative_1h = self.dp.get_pair_dataframe(pair=metadata['pair'], timeframe=self.inf_1h)
|
||||||
|
# EMA
|
||||||
|
informative_1h['ema_50'] = ta.EMA(informative_1h, timeperiod=50)
|
||||||
|
informative_1h['ema_200'] = ta.EMA(informative_1h, timeperiod=200)
|
||||||
|
# RSI
|
||||||
|
informative_1h['rsi'] = ta.RSI(informative_1h, timeperiod=14)
|
||||||
|
|
||||||
|
bollinger = qtpylib.bollinger_bands(qtpylib.typical_price(dataframe), window=20, stds=2)
|
||||||
|
informative_1h['bb_lowerband'] = bollinger['lower']
|
||||||
|
informative_1h['bb_middleband'] = bollinger['mid']
|
||||||
|
informative_1h['bb_upperband'] = bollinger['upper']
|
||||||
|
|
||||||
|
return informative_1h
|
||||||
|
|
||||||
|
def normal_tf_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||||
|
|
||||||
|
bollinger = qtpylib.bollinger_bands(qtpylib.typical_price(dataframe), window=20, stds=2)
|
||||||
|
dataframe['bb_lowerband'] = bollinger['lower']
|
||||||
|
dataframe['bb_middleband'] = bollinger['mid']
|
||||||
|
dataframe['bb_upperband'] = bollinger['upper']
|
||||||
|
|
||||||
|
dataframe['volume_mean_slow'] = dataframe['volume'].rolling(window=48).mean()
|
||||||
|
|
||||||
|
# EMA
|
||||||
|
dataframe['ema_200'] = ta.EMA(dataframe, timeperiod=200)
|
||||||
|
|
||||||
|
dataframe['ema_26'] = ta.EMA(dataframe, timeperiod=26)
|
||||||
|
dataframe['ema_12'] = ta.EMA(dataframe, timeperiod=12)
|
||||||
|
|
||||||
|
# MACD
|
||||||
|
dataframe['macd'], dataframe['signal'], dataframe['hist'] = ta.MACD(dataframe['close'], fastperiod=12,
|
||||||
|
slowperiod=26, signalperiod=9)
|
||||||
|
|
||||||
|
# RSI
|
||||||
|
dataframe['rsi'] = ta.RSI(dataframe, timeperiod=14)
|
||||||
|
|
||||||
|
# Chaikin A/D Oscillator
|
||||||
|
dataframe['mfv'] = MFV(dataframe)
|
||||||
|
dataframe['cmf'] = dataframe['mfv'].rolling(20).sum() / dataframe['volume'].rolling(20).sum()
|
||||||
|
|
||||||
|
return dataframe
|
||||||
|
|
||||||
|
def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||||
|
# The indicators for the 1h informative timeframe
|
||||||
|
informative_1h = self.informative_1h_indicators(dataframe, metadata)
|
||||||
|
dataframe = merge_informative_pair(dataframe, informative_1h, self.timeframe, self.inf_1h, ffill=True)
|
||||||
|
|
||||||
|
# The indicators for the normal (5m) timeframe
|
||||||
|
dataframe = self.normal_tf_indicators(dataframe, metadata)
|
||||||
|
|
||||||
|
return dataframe
|
||||||
|
|
||||||
|
def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||||
|
|
||||||
|
conditions = []
|
||||||
|
|
||||||
|
conditions.append(
|
||||||
|
(
|
||||||
|
self.buy_condition_13_enable.value &
|
||||||
|
|
||||||
|
(dataframe['close'] > dataframe['ema_200_1h']) &
|
||||||
|
|
||||||
|
(dataframe['cmf'] < -0.435) &
|
||||||
|
(dataframe['rsi'] < 22) &
|
||||||
|
|
||||||
|
(dataframe['volume_mean_slow'] > dataframe['volume_mean_slow'].shift(
|
||||||
|
48) * self.buy_volume_pump_1.value) &
|
||||||
|
(dataframe['volume_mean_slow'] * self.buy_volume_pump_1.value < dataframe['volume_mean_slow'].shift(
|
||||||
|
48)) &
|
||||||
|
(dataframe['volume'] > 0)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
conditions.append(
|
||||||
|
(
|
||||||
|
self.buy_condition_12_enable.value &
|
||||||
|
|
||||||
|
(dataframe['close'] > dataframe['ema_200']) &
|
||||||
|
(dataframe['close'] > dataframe['ema_200_1h']) &
|
||||||
|
|
||||||
|
(dataframe['close'] < dataframe['bb_lowerband'] * 0.993) &
|
||||||
|
(dataframe['low'] < dataframe['bb_lowerband'] * 0.985) &
|
||||||
|
(dataframe['close'].shift() > dataframe['bb_lowerband']) &
|
||||||
|
(dataframe['rsi_1h'] < 72.8) &
|
||||||
|
(dataframe['open'] > dataframe['close']) &
|
||||||
|
|
||||||
|
(dataframe['volume_mean_slow'] > dataframe['volume_mean_slow'].shift(
|
||||||
|
48) * self.buy_volume_pump_1.value) &
|
||||||
|
(dataframe['volume_mean_slow'] * self.buy_volume_pump_1.value < dataframe['volume_mean_slow'].shift(
|
||||||
|
48)) &
|
||||||
|
(dataframe['volume'] < (dataframe['volume'].shift() * self.buy_volume_drop_1.value)) &
|
||||||
|
((dataframe['open'] - dataframe['close']) < dataframe['bb_upperband'].shift(2) - dataframe[
|
||||||
|
'bb_lowerband'].shift(2)) &
|
||||||
|
|
||||||
|
(dataframe['volume'] > 0)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
conditions.append(
|
||||||
|
(
|
||||||
|
self.buy_condition_11_enable.value &
|
||||||
|
|
||||||
|
(dataframe['close'] > dataframe['ema_200']) &
|
||||||
|
|
||||||
|
(dataframe['hist'] > 0) &
|
||||||
|
(dataframe['hist'].shift() > 0) &
|
||||||
|
(dataframe['hist'].shift(2) > 0) &
|
||||||
|
(dataframe['hist'].shift(3) > 0) &
|
||||||
|
(dataframe['hist'].shift(5) > 0) &
|
||||||
|
|
||||||
|
(dataframe['bb_middleband'] - dataframe['bb_middleband'].shift(5) > dataframe['close'] / 200) &
|
||||||
|
(dataframe['bb_middleband'] - dataframe['bb_middleband'].shift(10) > dataframe['close'] / 100) &
|
||||||
|
((dataframe['bb_upperband'] - dataframe['bb_lowerband']) < (dataframe['close'] * 0.1)) &
|
||||||
|
((dataframe['open'].shift() - dataframe['close'].shift()) < (dataframe['close'] * 0.018)) &
|
||||||
|
(dataframe['rsi'] > 51) &
|
||||||
|
|
||||||
|
(dataframe['open'] < dataframe['close']) &
|
||||||
|
(dataframe['open'].shift() > dataframe['close'].shift()) &
|
||||||
|
|
||||||
|
(dataframe['close'] > dataframe['bb_middleband']) &
|
||||||
|
(dataframe['close'].shift() < dataframe['bb_middleband'].shift()) &
|
||||||
|
(dataframe['low'].shift(2) > dataframe['bb_middleband'].shift(2)) &
|
||||||
|
|
||||||
|
(dataframe['volume'] > 0) # Make sure Volume is not 0
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
conditions.append(
|
||||||
|
(
|
||||||
|
self.buy_condition_0_enable.value &
|
||||||
|
|
||||||
|
(dataframe['close'] > dataframe['ema_200']) &
|
||||||
|
|
||||||
|
(dataframe['rsi'] < 30) &
|
||||||
|
(dataframe['close'] * 1.024 < dataframe['open'].shift(3)) &
|
||||||
|
(dataframe['rsi_1h'] < 71) &
|
||||||
|
|
||||||
|
(dataframe['volume_mean_slow'] > dataframe['volume_mean_slow'].shift(
|
||||||
|
48) * self.buy_volume_pump_1.value) &
|
||||||
|
(dataframe['volume_mean_slow'] * self.buy_volume_pump_1.value < dataframe['volume_mean_slow'].shift(
|
||||||
|
48)) &
|
||||||
|
(dataframe['volume'] > 0) # Make sure Volume is not 0
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
conditions.append(
|
||||||
|
(
|
||||||
|
self.buy_condition_1_enable.value &
|
||||||
|
|
||||||
|
(dataframe['close'] > dataframe['ema_200']) &
|
||||||
|
(dataframe['close'] > dataframe['ema_200_1h']) &
|
||||||
|
|
||||||
|
(dataframe['close'] < dataframe['bb_lowerband'] * self.buy_bb20_close_bblowerband_safe_1.value) &
|
||||||
|
(dataframe['rsi_1h'] < 69) &
|
||||||
|
(dataframe['open'] > dataframe['close']) &
|
||||||
|
|
||||||
|
(dataframe['volume_mean_slow'] > dataframe['volume_mean_slow'].shift(
|
||||||
|
48) * self.buy_volume_pump_1.value) &
|
||||||
|
(dataframe['volume_mean_slow'] * self.buy_volume_pump_1.value < dataframe['volume_mean_slow'].shift(
|
||||||
|
48)) &
|
||||||
|
(dataframe['volume'] < (dataframe['volume'].shift() * self.buy_volume_drop_1.value)) &
|
||||||
|
((dataframe['open'] - dataframe['close']) < dataframe['bb_upperband'].shift(2) - dataframe[
|
||||||
|
'bb_lowerband'].shift(2)) &
|
||||||
|
|
||||||
|
(dataframe['volume'] > 0)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
conditions.append(
|
||||||
|
(
|
||||||
|
self.buy_condition_2_enable.value &
|
||||||
|
|
||||||
|
(dataframe['close'] > dataframe['ema_200']) &
|
||||||
|
|
||||||
|
(dataframe['close'] < dataframe['bb_lowerband'] * self.buy_bb20_close_bblowerband_safe_2.value) &
|
||||||
|
|
||||||
|
(dataframe['volume_mean_slow'] > dataframe['volume_mean_slow'].shift(
|
||||||
|
48) * self.buy_volume_pump_1.value) &
|
||||||
|
(dataframe['volume_mean_slow'] * self.buy_volume_pump_1.value < dataframe['volume_mean_slow'].shift(
|
||||||
|
48)) &
|
||||||
|
(dataframe['volume'] < (dataframe['volume'].shift() * self.buy_volume_drop_1.value)) &
|
||||||
|
(dataframe['open'] - dataframe['close'] < dataframe['bb_upperband'].shift(2) - dataframe[
|
||||||
|
'bb_lowerband'].shift(2)) &
|
||||||
|
(dataframe['volume'] > 0)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
conditions.append(
|
||||||
|
(
|
||||||
|
self.buy_condition_3_enable.value &
|
||||||
|
|
||||||
|
(dataframe['close'] > dataframe['ema_200_1h']) &
|
||||||
|
|
||||||
|
(dataframe['close'] < dataframe['bb_lowerband']) &
|
||||||
|
(dataframe['rsi'] < self.buy_rsi_3.value) &
|
||||||
|
|
||||||
|
(dataframe['volume_mean_slow'] > dataframe['volume_mean_slow'].shift(
|
||||||
|
48) * self.buy_volume_pump_1.value) &
|
||||||
|
(dataframe['volume_mean_slow'] * self.buy_volume_pump_1.value < dataframe['volume_mean_slow'].shift(
|
||||||
|
48)) &
|
||||||
|
(dataframe['volume'] < (dataframe['volume'].shift() * self.buy_volume_drop_3.value)) &
|
||||||
|
|
||||||
|
(dataframe['volume'] > 0)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
conditions.append(
|
||||||
|
(
|
||||||
|
self.buy_condition_4_enable.value &
|
||||||
|
|
||||||
|
(dataframe['rsi_1h'] < self.buy_rsi_1h_1.value) &
|
||||||
|
|
||||||
|
(dataframe['close'] < dataframe['bb_lowerband']) &
|
||||||
|
|
||||||
|
(dataframe['volume_mean_slow'] > dataframe['volume_mean_slow'].shift(
|
||||||
|
48) * self.buy_volume_pump_1.value) &
|
||||||
|
(dataframe['volume_mean_slow'] * self.buy_volume_pump_1.value < dataframe['volume_mean_slow'].shift(
|
||||||
|
48)) &
|
||||||
|
(dataframe['volume'] < (dataframe['volume'].shift() * self.buy_volume_drop_1.value)) &
|
||||||
|
(dataframe['volume'] > 0)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
conditions.append(
|
||||||
|
(
|
||||||
|
self.buy_condition_5_enable.value &
|
||||||
|
|
||||||
|
(dataframe['close'] > dataframe['ema_200']) &
|
||||||
|
(dataframe['close'] > dataframe['ema_200_1h']) &
|
||||||
|
|
||||||
|
(dataframe['ema_26'] > dataframe['ema_12']) &
|
||||||
|
((dataframe['ema_26'] - dataframe['ema_12']) > (dataframe['open'] * self.buy_macd_1.value)) &
|
||||||
|
((dataframe['ema_26'].shift() - dataframe['ema_12'].shift()) > (dataframe['open'] / 100)) &
|
||||||
|
(dataframe['close'] < (dataframe['bb_lowerband'])) &
|
||||||
|
|
||||||
|
(dataframe['volume'] < (dataframe['volume'].shift() * self.buy_volume_drop_1.value)) &
|
||||||
|
(dataframe['volume_mean_slow'] > dataframe['volume_mean_slow'].shift(
|
||||||
|
48) * self.buy_volume_pump_1.value) &
|
||||||
|
(dataframe['volume_mean_slow'] * self.buy_volume_pump_1.value < dataframe['volume_mean_slow'].shift(
|
||||||
|
48)) &
|
||||||
|
(dataframe['volume'] > 0) # Make sure Volume is not 0
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
conditions.append(
|
||||||
|
(
|
||||||
|
self.buy_condition_6_enable.value &
|
||||||
|
|
||||||
|
(dataframe['rsi_1h'] < self.buy_rsi_1h_5.value) &
|
||||||
|
|
||||||
|
(dataframe['ema_26'] > dataframe['ema_12']) &
|
||||||
|
((dataframe['ema_26'] - dataframe['ema_12']) > (dataframe['open'] * self.buy_macd_2.value)) &
|
||||||
|
((dataframe['ema_26'].shift() - dataframe['ema_12'].shift()) > (dataframe['open'] / 100)) &
|
||||||
|
(dataframe['close'] < (dataframe['bb_lowerband'])) &
|
||||||
|
|
||||||
|
(dataframe['volume_mean_slow'] > dataframe['volume_mean_slow'].shift(
|
||||||
|
48) * self.buy_volume_pump_1.value) &
|
||||||
|
(dataframe['volume_mean_slow'] * self.buy_volume_pump_1.value < dataframe['volume_mean_slow'].shift(
|
||||||
|
48)) &
|
||||||
|
(dataframe['volume'] < (dataframe['volume'].shift() * self.buy_volume_drop_1.value)) &
|
||||||
|
(dataframe['volume'] > 0)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
conditions.append(
|
||||||
|
(
|
||||||
|
self.buy_condition_7_enable.value &
|
||||||
|
|
||||||
|
(dataframe['rsi_1h'] < self.buy_rsi_1h_2.value) &
|
||||||
|
|
||||||
|
(dataframe['ema_26'] > dataframe['ema_12']) &
|
||||||
|
((dataframe['ema_26'] - dataframe['ema_12']) > (dataframe['open'] * self.buy_macd_1.value)) &
|
||||||
|
((dataframe['ema_26'].shift() - dataframe['ema_12'].shift()) > (dataframe['open'] / 100)) &
|
||||||
|
|
||||||
|
(dataframe['volume'] < (dataframe['volume'].shift() * self.buy_volume_drop_1.value)) &
|
||||||
|
(dataframe['volume_mean_slow'] > dataframe['volume_mean_slow'].shift(
|
||||||
|
48) * self.buy_volume_pump_1.value) &
|
||||||
|
(dataframe['volume_mean_slow'] * self.buy_volume_pump_1.value < dataframe['volume_mean_slow'].shift(
|
||||||
|
48)) &
|
||||||
|
(dataframe['volume'] > 0)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
conditions.append(
|
||||||
|
(
|
||||||
|
|
||||||
|
self.buy_condition_8_enable.value &
|
||||||
|
|
||||||
|
(dataframe['rsi_1h'] < self.buy_rsi_1h_3.value) &
|
||||||
|
(dataframe['rsi'] < self.buy_rsi_1.value) &
|
||||||
|
|
||||||
|
(dataframe['volume'] < (dataframe['volume'].shift() * self.buy_volume_drop_1.value)) &
|
||||||
|
|
||||||
|
(dataframe['volume'] > 0)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
conditions.append(
|
||||||
|
(
|
||||||
|
|
||||||
|
self.buy_condition_9_enable.value &
|
||||||
|
|
||||||
|
(dataframe['rsi_1h'] < self.buy_rsi_1h_4.value) &
|
||||||
|
(dataframe['rsi'] < self.buy_rsi_2.value) &
|
||||||
|
|
||||||
|
(dataframe['volume'] < (dataframe['volume'].shift() * self.buy_volume_drop_1.value)) &
|
||||||
|
(dataframe['volume_mean_slow'] > dataframe['volume_mean_slow'].shift(
|
||||||
|
48) * self.buy_volume_pump_1.value) &
|
||||||
|
(dataframe['volume_mean_slow'] * self.buy_volume_pump_1.value < dataframe['volume_mean_slow'].shift(
|
||||||
|
48)) &
|
||||||
|
(dataframe['volume'] > 0)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
conditions.append(
|
||||||
|
(
|
||||||
|
|
||||||
|
self.buy_condition_10_enable.value &
|
||||||
|
|
||||||
|
(dataframe['rsi_1h'] < self.buy_rsi_1h_4.value) &
|
||||||
|
(dataframe['close_1h'] < dataframe['bb_lowerband_1h']) &
|
||||||
|
|
||||||
|
(dataframe['hist'] > 0) &
|
||||||
|
(dataframe['hist'].shift(2) < 0) &
|
||||||
|
(dataframe['rsi'] < 40.5) &
|
||||||
|
(dataframe['hist'] > dataframe['close'] * 0.0012) &
|
||||||
|
(dataframe['open'] < dataframe['close']) &
|
||||||
|
|
||||||
|
(dataframe['volume'] > 0)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
if conditions:
|
||||||
|
dataframe.loc[
|
||||||
|
reduce(lambda x, y: x | y, conditions),
|
||||||
|
'buy'
|
||||||
|
] = 1
|
||||||
|
|
||||||
|
return dataframe
|
||||||
|
|
||||||
|
def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||||
|
dataframe.loc[
|
||||||
|
(
|
||||||
|
(dataframe['close'] > dataframe['bb_middleband'] * 1.01) & # Don't be gready, sell fast
|
||||||
|
(dataframe['volume'] > 0) # Make sure Volume is not 0
|
||||||
|
)
|
||||||
|
,
|
||||||
|
'sell'
|
||||||
|
] = 0
|
||||||
|
return dataframe
|
||||||
|
|
||||||
|
|
||||||
|
# Chaikin Money Flow Volume
|
||||||
|
def MFV(dataframe):
|
||||||
|
df = dataframe.copy()
|
||||||
|
N = ((df['close'] - df['low']) - (df['high'] - df['close'])) / (df['high'] - df['low'])
|
||||||
|
M = N * df['volume']
|
||||||
|
return M
|
2617
strategies/E0V1E.py
Executable file
2617
strategies/E0V1E.py
Executable file
File diff suppressed because one or more lines are too long
23206
strategies/NostalgiaForInfinityX.py
Executable file
23206
strategies/NostalgiaForInfinityX.py
Executable file
File diff suppressed because it is too large
Load Diff
8390
strategies/NostalgiaForInfinityX2.py
Executable file
8390
strategies/NostalgiaForInfinityX2.py
Executable file
File diff suppressed because it is too large
Load Diff
595
strategies/ROuGGy.py
Executable file
595
strategies/ROuGGy.py
Executable file
@ -0,0 +1,595 @@
|
|||||||
|
import freqtrade.vendor.qtpylib.indicators as qtpylib
|
||||||
|
import numpy as np
|
||||||
|
import talib.abstract as ta
|
||||||
|
from freqtrade.persistence import Trade
|
||||||
|
from freqtrade.strategy.interface import IStrategy
|
||||||
|
from pandas import DataFrame
|
||||||
|
from datetime import datetime, timedelta
|
||||||
|
from freqtrade.strategy import merge_informative_pair, CategoricalParameter, DecimalParameter, IntParameter
|
||||||
|
from functools import reduce
|
||||||
|
|
||||||
|
|
||||||
|
###########################################################################################################
|
||||||
|
## BigZ06 by ilya ##
|
||||||
|
## ##
|
||||||
|
## https://github.com/i1ya/freqtrade-strategies ##
|
||||||
|
## The stratagy most inspired by iterativ (authors of the CombinedBinHAndClucV6) ##
|
||||||
|
## ## ##
|
||||||
|
###########################################################################################################
|
||||||
|
## The main point of this strat is: ##
|
||||||
|
## - make drawdown as low as possible ##
|
||||||
|
## - buy at dip ##
|
||||||
|
## - sell quick as fast as you can (release money for the next buy) ##
|
||||||
|
## - soft check if market if rising ##
|
||||||
|
## - hard check is market if fallen ##
|
||||||
|
## - 14 buy signals ##
|
||||||
|
## - stoploss function preventing from big fall ##
|
||||||
|
## - no sell signal. Whether ROI or stoploss =) ##
|
||||||
|
## ##
|
||||||
|
###########################################################################################################
|
||||||
|
## GENERAL RECOMMENDATIONS ##
|
||||||
|
## ##
|
||||||
|
## For optimal performance, suggested to use between 3 and 5 open trades. ##
|
||||||
|
## ##
|
||||||
|
## As a pairlist you can use VolumePairlist. ##
|
||||||
|
## ##
|
||||||
|
## Ensure that you don't override any variables in your config.json. Especially ##
|
||||||
|
## the timeframe (must be 5m). ##
|
||||||
|
## ##
|
||||||
|
## sell_profit_only: ##
|
||||||
|
## True - risk more (gives you higher profit and higher Drawdown) ##
|
||||||
|
## False (default) - risk less (gives you less ~10-15% profit and much lower Drawdown) ##
|
||||||
|
## ##
|
||||||
|
## BigZ06 using market orders. ##
|
||||||
|
## Ensure you're familar with https://www.freqtrade.io/en/stable/configuration/#market-order-pricing ##
|
||||||
|
## ##
|
||||||
|
###########################################################################################################
|
||||||
|
## DONATIONS 2 @iterativ (author of the original strategy) ##
|
||||||
|
## ##
|
||||||
|
## Absolutely not required. However, will be accepted as a token of appreciation. ##
|
||||||
|
## ##
|
||||||
|
## BTC: bc1qvflsvddkmxh7eqhc4jyu5z5k6xcw3ay8jl49sk ##
|
||||||
|
## ETH: 0x83D3cFb8001BDC5d2211cBeBB8cB3461E5f7Ec91 ##
|
||||||
|
## ##
|
||||||
|
###########################################################################################################
|
||||||
|
|
||||||
|
|
||||||
|
class ROuGGy(IStrategy):
|
||||||
|
INTERFACE_VERSION = 2
|
||||||
|
|
||||||
|
minimal_roi = {
|
||||||
|
"0": 0.028, # I feel lucky!
|
||||||
|
"10": 0.018,
|
||||||
|
"40": 0.005,
|
||||||
|
"180": 0.018, # We're going up?
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
stoploss = -0.99 # effectively disabled.
|
||||||
|
|
||||||
|
timeframe = '5m'
|
||||||
|
inf_1h = '1h'
|
||||||
|
|
||||||
|
# Sell signal
|
||||||
|
use_exit_signal = True
|
||||||
|
exit_profit_only = False
|
||||||
|
exit_profit_offset = 0.001 # it doesn't meant anything, just to guarantee there is a minimal profit.
|
||||||
|
ignore_roi_if_entry_signal = False
|
||||||
|
|
||||||
|
# Trailing stoploss
|
||||||
|
trailing_stop = False
|
||||||
|
trailing_only_offset_is_reached = False
|
||||||
|
trailing_stop_positive = 0.01
|
||||||
|
trailing_stop_positive_offset = 0.025
|
||||||
|
|
||||||
|
# Custom stoploss
|
||||||
|
use_custom_stoploss = True
|
||||||
|
|
||||||
|
# Run "populate_indicators()" only for new candle.
|
||||||
|
process_only_new_candles = True
|
||||||
|
|
||||||
|
# Number of candles the strategy requires before producing valid signals
|
||||||
|
startup_candle_count: int = 200
|
||||||
|
|
||||||
|
# Optional order type mapping.
|
||||||
|
order_types = {
|
||||||
|
'entry': 'market',
|
||||||
|
'exit': 'market',
|
||||||
|
'stoploss': 'market',
|
||||||
|
'stoploss_on_exchange': False
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
buy_params = {
|
||||||
|
#############
|
||||||
|
# Enable/Disable conditions
|
||||||
|
"buy_condition_0_enable": True,
|
||||||
|
"buy_condition_1_enable": True,
|
||||||
|
"buy_condition_2_enable": True,
|
||||||
|
"buy_condition_3_enable": True,
|
||||||
|
"buy_condition_4_enable": True,
|
||||||
|
"buy_condition_5_enable": True,
|
||||||
|
"buy_condition_6_enable": True,
|
||||||
|
"buy_condition_7_enable": True,
|
||||||
|
"buy_condition_8_enable": True,
|
||||||
|
"buy_condition_9_enable": True,
|
||||||
|
"buy_condition_10_enable": True,
|
||||||
|
"buy_condition_11_enable": True,
|
||||||
|
"buy_condition_12_enable": True,
|
||||||
|
"buy_condition_13_enable": True,
|
||||||
|
"buy_condition_14_enable": True,
|
||||||
|
}
|
||||||
|
|
||||||
|
############################################################################
|
||||||
|
|
||||||
|
# Buy
|
||||||
|
|
||||||
|
buy_condition_0_enable = CategoricalParameter([True, False], default=True, space='buy', optimize=False, load=True)
|
||||||
|
buy_condition_1_enable = CategoricalParameter([True, False], default=True, space='buy', optimize=False, load=True)
|
||||||
|
buy_condition_2_enable = CategoricalParameter([True, False], default=True, space='buy', optimize=False, load=True)
|
||||||
|
buy_condition_3_enable = CategoricalParameter([True, False], default=True, space='buy', optimize=False, load=True)
|
||||||
|
buy_condition_4_enable = CategoricalParameter([True, False], default=True, space='buy', optimize=False, load=True)
|
||||||
|
buy_condition_5_enable = CategoricalParameter([True, False], default=True, space='buy', optimize=False, load=True)
|
||||||
|
buy_condition_6_enable = CategoricalParameter([True, False], default=True, space='buy', optimize=False, load=True)
|
||||||
|
buy_condition_7_enable = CategoricalParameter([True, False], default=True, space='buy', optimize=False, load=True)
|
||||||
|
buy_condition_8_enable = CategoricalParameter([True, False], default=True, space='buy', optimize=False, load=True)
|
||||||
|
buy_condition_9_enable = CategoricalParameter([True, False], default=True, space='buy', optimize=False, load=True)
|
||||||
|
buy_condition_10_enable = CategoricalParameter([True, False], default=True, space='buy', optimize=False, load=True)
|
||||||
|
buy_condition_11_enable = CategoricalParameter([True, False], default=True, space='buy', optimize=False, load=True)
|
||||||
|
buy_condition_12_enable = CategoricalParameter([True, False], default=True, space='buy', optimize=False, load=True)
|
||||||
|
buy_condition_13_enable = CategoricalParameter([True, False], default=True, space='buy', optimize=False, load=True)
|
||||||
|
buy_condition_14_enable = CategoricalParameter([True, False], default=True, space='buy', optimize=False, load=True)
|
||||||
|
|
||||||
|
buy_bb20_close_bblowerband_safe_1 = DecimalParameter(0.7, 1.1, default=0.989, space='buy', optimize=False, load=True)
|
||||||
|
buy_bb20_close_bblowerband_safe_2 = DecimalParameter(0.7, 1.1, default=0.982, space='buy', optimize=False, load=True)
|
||||||
|
|
||||||
|
buy_volume_pump_1 = DecimalParameter(0.1, 0.9, default=0.4, space='buy', decimals=1, optimize=False, load=True)
|
||||||
|
buy_volume_drop_1 = DecimalParameter(1, 10, default=3.8, space='buy', decimals=1, optimize=False, load=True)
|
||||||
|
buy_volume_drop_2 = DecimalParameter(1, 10, default=3, space='buy', decimals=1, optimize=False, load=True)
|
||||||
|
buy_volume_drop_3 = DecimalParameter(1, 10, default=2.7, space='buy', decimals=1, optimize=False, load=True)
|
||||||
|
|
||||||
|
buy_rsi_1h_1 = DecimalParameter(10.0, 40.0, default=16.5, space='buy', decimals=1, optimize=False, load=True)
|
||||||
|
buy_rsi_1h_2 = DecimalParameter(10.0, 40.0, default=15.0, space='buy', decimals=1, optimize=False, load=True)
|
||||||
|
buy_rsi_1h_3 = DecimalParameter(10.0, 40.0, default=20.0, space='buy', decimals=1, optimize=False, load=True)
|
||||||
|
buy_rsi_1h_4 = DecimalParameter(10.0, 40.0, default=35.0, space='buy', decimals=1, optimize=False, load=True)
|
||||||
|
buy_rsi_1h_5 = DecimalParameter(10.0, 60.0, default=39.0, space='buy', decimals=1, optimize=False, load=True)
|
||||||
|
|
||||||
|
buy_rsi_1 = DecimalParameter(10.0, 40.0, default=28.0, space='buy', decimals=1, optimize=False, load=True)
|
||||||
|
buy_rsi_2 = DecimalParameter(7.0, 40.0, default=10.0, space='buy', decimals=1, optimize=False, load=True)
|
||||||
|
buy_rsi_3 = DecimalParameter(7.0, 40.0, default=14.2, space='buy', decimals=1, optimize=False, load=True)
|
||||||
|
|
||||||
|
buy_macd_1 = DecimalParameter(0.01, 0.09, default=0.02, space='buy', decimals=2, optimize=False, load=True)
|
||||||
|
buy_macd_2 = DecimalParameter(0.01, 0.09, default=0.03, space='buy', decimals=2, optimize=False, load=True)
|
||||||
|
|
||||||
|
def confirm_trade_exit(self, pair: str, trade: Trade, order_type: str, amount: float,
|
||||||
|
rate: float, time_in_force: str, sell_reason: str, **kwargs) -> bool:
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
def custom_sell(self, pair: str, trade: 'Trade', current_time: 'datetime', current_rate: float,
|
||||||
|
current_profit: float, **kwargs):
|
||||||
|
|
||||||
|
return False
|
||||||
|
|
||||||
|
dataframe, _ = self.dp.get_analyzed_dataframe(pair, self.timeframe)
|
||||||
|
last_candle = dataframe.iloc[-1].squeeze()
|
||||||
|
last_candle_2 = dataframe.iloc[-2].squeeze()
|
||||||
|
|
||||||
|
if (last_candle is not None):
|
||||||
|
if (last_candle['high'] > last_candle['bb_upperband']) & (last_candle['volume'] > (last_candle_2['volume'] * 1.5)):
|
||||||
|
return 'sell_signal_1'
|
||||||
|
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def custom_stoploss(self, pair: str, trade: 'Trade', current_time: datetime,
|
||||||
|
current_rate: float, current_profit: float, **kwargs) -> float:
|
||||||
|
# Manage losing trades and open room for better ones.
|
||||||
|
|
||||||
|
if (current_profit > 0):
|
||||||
|
return 0.99
|
||||||
|
else:
|
||||||
|
trade_time_50 = trade.open_date_utc + timedelta(minutes=50)
|
||||||
|
|
||||||
|
# Trade open more then 60 minutes. For this strategy it's means -> loss
|
||||||
|
# Let's try to minimize the loss
|
||||||
|
|
||||||
|
if (current_time > trade_time_50):
|
||||||
|
|
||||||
|
try:
|
||||||
|
number_of_candle_shift = int((current_time - trade_time_50).total_seconds() / 300)
|
||||||
|
dataframe, _ = self.dp.get_analyzed_dataframe(pair, self.timeframe)
|
||||||
|
candle = dataframe.iloc[-number_of_candle_shift].squeeze()
|
||||||
|
|
||||||
|
# We are at bottom. Wait...
|
||||||
|
if candle['rsi_1h'] < 40:
|
||||||
|
return 0.99
|
||||||
|
|
||||||
|
# Are we still sinking?
|
||||||
|
if candle['close'] > candle['ema_200']:
|
||||||
|
if current_rate * 1.035 < candle['open']:
|
||||||
|
return 0.01
|
||||||
|
|
||||||
|
if current_rate * 1.025 < candle['open']:
|
||||||
|
return 0.01
|
||||||
|
|
||||||
|
except IndexError as error:
|
||||||
|
|
||||||
|
# Whoops, set stoploss at 10%
|
||||||
|
return 0.1
|
||||||
|
|
||||||
|
return 0.99
|
||||||
|
|
||||||
|
def informative_pairs(self):
|
||||||
|
pairs = self.dp.current_whitelist()
|
||||||
|
informative_pairs = [(pair, '1h') for pair in pairs]
|
||||||
|
return informative_pairs
|
||||||
|
|
||||||
|
def informative_1h_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||||
|
assert self.dp, "DataProvider is required for multiple timeframes."
|
||||||
|
# Get the informative pair
|
||||||
|
informative_1h = self.dp.get_pair_dataframe(pair=metadata['pair'], timeframe=self.inf_1h)
|
||||||
|
# EMA
|
||||||
|
informative_1h['ema_50'] = ta.EMA(informative_1h, timeperiod=50)
|
||||||
|
informative_1h['ema_200'] = ta.EMA(informative_1h, timeperiod=200)
|
||||||
|
# RSI
|
||||||
|
informative_1h['rsi'] = ta.RSI(informative_1h, timeperiod=14)
|
||||||
|
|
||||||
|
bollinger = qtpylib.bollinger_bands(qtpylib.typical_price(dataframe), window=20, stds=2)
|
||||||
|
informative_1h['bb_lowerband'] = bollinger['lower']
|
||||||
|
informative_1h['bb_middleband'] = bollinger['mid']
|
||||||
|
informative_1h['bb_upperband'] = bollinger['upper']
|
||||||
|
|
||||||
|
return informative_1h
|
||||||
|
|
||||||
|
def normal_tf_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||||
|
|
||||||
|
bollinger = qtpylib.bollinger_bands(qtpylib.typical_price(dataframe), window=20, stds=2)
|
||||||
|
dataframe['bb_lowerband'] = bollinger['lower']
|
||||||
|
dataframe['bb_middleband'] = bollinger['mid']
|
||||||
|
dataframe['bb_upperband'] = bollinger['upper']
|
||||||
|
|
||||||
|
dataframe['volume_mean_slow'] = dataframe['volume'].rolling(window=48).mean()
|
||||||
|
|
||||||
|
# EMA
|
||||||
|
dataframe['ema_200'] = ta.EMA(dataframe, timeperiod=200)
|
||||||
|
|
||||||
|
dataframe['ema_26'] = ta.EMA(dataframe, timeperiod=26)
|
||||||
|
dataframe['ema_12'] = ta.EMA(dataframe, timeperiod=12)
|
||||||
|
|
||||||
|
# For sell checks
|
||||||
|
dataframe['crossed_below_ema_12_26'] = qtpylib.crossed_below(dataframe['ema_12'], dataframe['ema_26'])
|
||||||
|
# For buy checks
|
||||||
|
dataframe['crossed_above_ema_12_26'] = qtpylib.crossed_above(dataframe['ema_12'], dataframe['ema_26'])
|
||||||
|
|
||||||
|
# MACD
|
||||||
|
dataframe['macd'], dataframe['signal'], dataframe['hist'] = ta.MACD(dataframe['close'], fastperiod=12, slowperiod=26, signalperiod=9)
|
||||||
|
|
||||||
|
# SMA
|
||||||
|
dataframe['sma_5'] = ta.EMA(dataframe, timeperiod=5)
|
||||||
|
|
||||||
|
# RSI
|
||||||
|
dataframe['rsi'] = ta.RSI(dataframe, timeperiod=14)
|
||||||
|
|
||||||
|
# Chaikin A/D Oscillator
|
||||||
|
dataframe['mfv'] = MFV(dataframe)
|
||||||
|
dataframe['cmf'] = dataframe['mfv'].rolling(20).sum()/dataframe['volume'].rolling(20).sum()
|
||||||
|
|
||||||
|
return dataframe
|
||||||
|
|
||||||
|
|
||||||
|
def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||||
|
# The indicators for the 1h informative timeframe
|
||||||
|
informative_1h = self.informative_1h_indicators(dataframe, metadata)
|
||||||
|
dataframe = merge_informative_pair(dataframe, informative_1h, self.timeframe, self.inf_1h, ffill=True)
|
||||||
|
|
||||||
|
# The indicators for the normal (5m) timeframe
|
||||||
|
dataframe = self.normal_tf_indicators(dataframe, metadata)
|
||||||
|
print(dataframe)
|
||||||
|
|
||||||
|
return dataframe
|
||||||
|
|
||||||
|
def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||||
|
|
||||||
|
conditions = []
|
||||||
|
|
||||||
|
conditions.append(
|
||||||
|
(
|
||||||
|
self.buy_condition_14_enable.value &
|
||||||
|
|
||||||
|
(dataframe['cmf'] > 0) &
|
||||||
|
(dataframe['crossed_above_ema_12_26']) &
|
||||||
|
(dataframe['rsi'] < 45) &
|
||||||
|
# (dataframe['open'] < dataframe['bb_lowerband']) &
|
||||||
|
(dataframe['volume'] > 0)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
conditions.append(
|
||||||
|
(
|
||||||
|
self.buy_condition_13_enable.value &
|
||||||
|
|
||||||
|
(dataframe['close'] > dataframe['ema_200_1h']) &
|
||||||
|
|
||||||
|
(dataframe['cmf'] < -0.435) &
|
||||||
|
(dataframe['rsi'] < 22) &
|
||||||
|
|
||||||
|
(dataframe['volume_mean_slow'] > dataframe['volume_mean_slow'].shift(48) * self.buy_volume_pump_1.value) &
|
||||||
|
(dataframe['volume_mean_slow'] * self.buy_volume_pump_1.value < dataframe['volume_mean_slow'].shift(48)) &
|
||||||
|
(dataframe['volume'] > 0)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
conditions.append(
|
||||||
|
(
|
||||||
|
self.buy_condition_12_enable.value &
|
||||||
|
|
||||||
|
(dataframe['close'] > dataframe['ema_200']) &
|
||||||
|
(dataframe['close'] > dataframe['ema_200_1h']) &
|
||||||
|
|
||||||
|
(dataframe['close'] < dataframe['bb_lowerband'] * 0.993) &
|
||||||
|
(dataframe['low'] < dataframe['bb_lowerband'] * 0.985) &
|
||||||
|
(dataframe['close'].shift() > dataframe['bb_lowerband']) &
|
||||||
|
(dataframe['rsi_1h'] < 72.8) &
|
||||||
|
(dataframe['open'] > dataframe['close']) &
|
||||||
|
(dataframe['volume_mean_slow'] > dataframe['volume_mean_slow'].shift(48) * self.buy_volume_pump_1.value) &
|
||||||
|
(dataframe['volume_mean_slow'] * self.buy_volume_pump_1.value < dataframe['volume_mean_slow'].shift(48)) &
|
||||||
|
(dataframe['volume'] < (dataframe['volume'].shift() * self.buy_volume_drop_1.value)) &
|
||||||
|
((dataframe['open'] - dataframe['close']) < dataframe['bb_upperband'].shift(2) - dataframe['bb_lowerband'].shift(2)) &
|
||||||
|
|
||||||
|
(dataframe['volume'] > 0)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
conditions.append(
|
||||||
|
(
|
||||||
|
self.buy_condition_11_enable.value &
|
||||||
|
|
||||||
|
(dataframe['close'] > dataframe['ema_200']) &
|
||||||
|
|
||||||
|
(dataframe['hist'] > 0) &
|
||||||
|
(dataframe['hist'].shift() > 0) &
|
||||||
|
(dataframe['hist'].shift(2) > 0) &
|
||||||
|
(dataframe['hist'].shift(3) > 0) &
|
||||||
|
(dataframe['hist'].shift(5) > 0) &
|
||||||
|
|
||||||
|
(dataframe['bb_middleband'] - dataframe['bb_middleband'].shift(5) > dataframe['close']/200) &
|
||||||
|
(dataframe['bb_middleband'] - dataframe['bb_middleband'].shift(10) > dataframe['close']/100) &
|
||||||
|
((dataframe['bb_upperband'] - dataframe['bb_lowerband']) < (dataframe['close']*0.1)) &
|
||||||
|
((dataframe['open'].shift() - dataframe['close'].shift()) < (dataframe['close'] * 0.018)) &
|
||||||
|
(dataframe['rsi'] > 51) &
|
||||||
|
|
||||||
|
(dataframe['open'] < dataframe['close']) &
|
||||||
|
(dataframe['open'].shift() > dataframe['close'].shift()) &
|
||||||
|
|
||||||
|
(dataframe['close'] > dataframe['bb_middleband']) &
|
||||||
|
(dataframe['close'].shift() < dataframe['bb_middleband'].shift()) &
|
||||||
|
(dataframe['low'].shift(2) > dataframe['bb_middleband'].shift(2)) &
|
||||||
|
|
||||||
|
(dataframe['volume'] > 0) # Make sure Volume is not 0
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
conditions.append(
|
||||||
|
(
|
||||||
|
self.buy_condition_0_enable.value &
|
||||||
|
|
||||||
|
(dataframe['close'] > dataframe['ema_200']) &
|
||||||
|
|
||||||
|
(dataframe['rsi'] < 30) &
|
||||||
|
(dataframe['close'] * 1.024 < dataframe['open'].shift(3)) &
|
||||||
|
(dataframe['rsi_1h'] < 71) &
|
||||||
|
|
||||||
|
(dataframe['volume_mean_slow'] > dataframe['volume_mean_slow'].shift(48) * self.buy_volume_pump_1.value) &
|
||||||
|
(dataframe['volume_mean_slow'] * self.buy_volume_pump_1.value < dataframe['volume_mean_slow'].shift(48)) &
|
||||||
|
(dataframe['volume'] > 0) # Make sure Volume is not 0
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
conditions.append(
|
||||||
|
(
|
||||||
|
self.buy_condition_1_enable.value &
|
||||||
|
|
||||||
|
(dataframe['close'] > dataframe['ema_200']) &
|
||||||
|
(dataframe['close'] > dataframe['ema_200_1h']) &
|
||||||
|
|
||||||
|
(dataframe['close'] < dataframe['bb_lowerband'] * self.buy_bb20_close_bblowerband_safe_1.value) &
|
||||||
|
(dataframe['rsi_1h'] < 69) &
|
||||||
|
(dataframe['open'] > dataframe['close']) &
|
||||||
|
|
||||||
|
(dataframe['volume_mean_slow'] > dataframe['volume_mean_slow'].shift(48) * self.buy_volume_pump_1.value) &
|
||||||
|
(dataframe['volume_mean_slow'] * self.buy_volume_pump_1.value < dataframe['volume_mean_slow'].shift(48)) &
|
||||||
|
(dataframe['volume'] < (dataframe['volume'].shift() * self.buy_volume_drop_1.value)) &
|
||||||
|
((dataframe['open'] - dataframe['close']) < dataframe['bb_upperband'].shift(2) - dataframe['bb_lowerband'].shift(2)) &
|
||||||
|
|
||||||
|
(dataframe['volume'] > 0)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
conditions.append(
|
||||||
|
(
|
||||||
|
self.buy_condition_2_enable.value &
|
||||||
|
|
||||||
|
(dataframe['close'] > dataframe['ema_200']) &
|
||||||
|
|
||||||
|
(dataframe['close'] < dataframe['bb_lowerband'] * self.buy_bb20_close_bblowerband_safe_2.value) &
|
||||||
|
|
||||||
|
(dataframe['volume_mean_slow'] > dataframe['volume_mean_slow'].shift(48) * self.buy_volume_pump_1.value) &
|
||||||
|
(dataframe['volume_mean_slow'] * self.buy_volume_pump_1.value < dataframe['volume_mean_slow'].shift(48)) &
|
||||||
|
(dataframe['volume'] < (dataframe['volume'].shift() * self.buy_volume_drop_1.value)) &
|
||||||
|
(dataframe['open'] - dataframe['close'] < dataframe['bb_upperband'].shift(2) - dataframe['bb_lowerband'].shift(2)) &
|
||||||
|
(dataframe['volume'] > 0)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
conditions.append(
|
||||||
|
(
|
||||||
|
self.buy_condition_3_enable.value &
|
||||||
|
|
||||||
|
(dataframe['close'] > dataframe['ema_200_1h']) &
|
||||||
|
|
||||||
|
(dataframe['close'] < dataframe['bb_lowerband']) &
|
||||||
|
(dataframe['rsi'] < self.buy_rsi_3.value) &
|
||||||
|
|
||||||
|
(dataframe['volume_mean_slow'] > dataframe['volume_mean_slow'].shift(48) * self.buy_volume_pump_1.value) &
|
||||||
|
(dataframe['volume_mean_slow'] * self.buy_volume_pump_1.value < dataframe['volume_mean_slow'].shift(48)) &
|
||||||
|
(dataframe['volume'] < (dataframe['volume'].shift() * self.buy_volume_drop_3.value)) &
|
||||||
|
|
||||||
|
(dataframe['volume'] > 0)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
conditions.append(
|
||||||
|
(
|
||||||
|
self.buy_condition_4_enable.value &
|
||||||
|
|
||||||
|
(dataframe['rsi_1h'] < self.buy_rsi_1h_1.value) &
|
||||||
|
|
||||||
|
(dataframe['close'] < dataframe['bb_lowerband']) &
|
||||||
|
|
||||||
|
(dataframe['volume_mean_slow'] > dataframe['volume_mean_slow'].shift(48) * self.buy_volume_pump_1.value) &
|
||||||
|
(dataframe['volume_mean_slow'] * self.buy_volume_pump_1.value < dataframe['volume_mean_slow'].shift(48)) &
|
||||||
|
(dataframe['volume'] < (dataframe['volume'].shift() * self.buy_volume_drop_1.value)) &
|
||||||
|
(dataframe['volume'] > 0)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
conditions.append(
|
||||||
|
(
|
||||||
|
self.buy_condition_5_enable.value &
|
||||||
|
|
||||||
|
(dataframe['close'] > dataframe['ema_200']) &
|
||||||
|
(dataframe['close'] > dataframe['ema_200_1h']) &
|
||||||
|
|
||||||
|
(dataframe['ema_26'] > dataframe['ema_12']) &
|
||||||
|
((dataframe['ema_26'] - dataframe['ema_12']) > (dataframe['open'] * self.buy_macd_1.value)) &
|
||||||
|
((dataframe['ema_26'].shift() - dataframe['ema_12'].shift()) > (dataframe['open']/100)) &
|
||||||
|
(dataframe['close'] < (dataframe['bb_lowerband'])) &
|
||||||
|
|
||||||
|
(dataframe['volume'] < (dataframe['volume'].shift() * self.buy_volume_drop_1.value)) &
|
||||||
|
(dataframe['volume_mean_slow'] > dataframe['volume_mean_slow'].shift(48) * self.buy_volume_pump_1.value) &
|
||||||
|
(dataframe['volume_mean_slow'] * self.buy_volume_pump_1.value < dataframe['volume_mean_slow'].shift(48)) &
|
||||||
|
(dataframe['volume'] > 0) # Make sure Volume is not 0
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
conditions.append(
|
||||||
|
(
|
||||||
|
self.buy_condition_6_enable.value &
|
||||||
|
|
||||||
|
(dataframe['rsi_1h'] < self.buy_rsi_1h_5.value) &
|
||||||
|
|
||||||
|
(dataframe['ema_26'] > dataframe['ema_12']) &
|
||||||
|
((dataframe['ema_26'] - dataframe['ema_12']) > (dataframe['open'] * self.buy_macd_2.value)) &
|
||||||
|
((dataframe['ema_26'].shift() - dataframe['ema_12'].shift()) > (dataframe['open']/100)) &
|
||||||
|
(dataframe['close'] < (dataframe['bb_lowerband'])) &
|
||||||
|
|
||||||
|
(dataframe['volume_mean_slow'] > dataframe['volume_mean_slow'].shift(48) * self.buy_volume_pump_1.value) &
|
||||||
|
(dataframe['volume_mean_slow'] * self.buy_volume_pump_1.value < dataframe['volume_mean_slow'].shift(48)) &
|
||||||
|
(dataframe['volume'] < (dataframe['volume'].shift() * self.buy_volume_drop_1.value)) &
|
||||||
|
(dataframe['volume'] > 0)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
conditions.append(
|
||||||
|
(
|
||||||
|
self.buy_condition_7_enable.value &
|
||||||
|
|
||||||
|
(dataframe['rsi_1h'] < self.buy_rsi_1h_2.value) &
|
||||||
|
|
||||||
|
(dataframe['ema_26'] > dataframe['ema_12']) &
|
||||||
|
((dataframe['ema_26'] - dataframe['ema_12']) > (dataframe['open'] * self.buy_macd_1.value)) &
|
||||||
|
((dataframe['ema_26'].shift() - dataframe['ema_12'].shift()) > (dataframe['open']/100)) &
|
||||||
|
|
||||||
|
(dataframe['volume'] < (dataframe['volume'].shift() * self.buy_volume_drop_1.value)) &
|
||||||
|
(dataframe['volume_mean_slow'] > dataframe['volume_mean_slow'].shift(48) * self.buy_volume_pump_1.value) &
|
||||||
|
(dataframe['volume_mean_slow'] * self.buy_volume_pump_1.value < dataframe['volume_mean_slow'].shift(48)) &
|
||||||
|
(dataframe['volume'] > 0)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
conditions.append(
|
||||||
|
(
|
||||||
|
|
||||||
|
self.buy_condition_8_enable.value &
|
||||||
|
|
||||||
|
(dataframe['rsi_1h'] < self.buy_rsi_1h_3.value) &
|
||||||
|
(dataframe['rsi'] < self.buy_rsi_1.value) &
|
||||||
|
|
||||||
|
(dataframe['volume'] < (dataframe['volume'].shift() * self.buy_volume_drop_1.value)) &
|
||||||
|
|
||||||
|
(dataframe['volume'] > 0)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
conditions.append(
|
||||||
|
(
|
||||||
|
|
||||||
|
self.buy_condition_9_enable.value &
|
||||||
|
|
||||||
|
(dataframe['rsi_1h'] < self.buy_rsi_1h_4.value) &
|
||||||
|
(dataframe['rsi'] < self.buy_rsi_2.value) &
|
||||||
|
|
||||||
|
(dataframe['volume'] < (dataframe['volume'].shift() * self.buy_volume_drop_1.value)) &
|
||||||
|
(dataframe['volume_mean_slow'] > dataframe['volume_mean_slow'].shift(48) * self.buy_volume_pump_1.value) &
|
||||||
|
(dataframe['volume_mean_slow'] * self.buy_volume_pump_1.value < dataframe['volume_mean_slow'].shift(48)) &
|
||||||
|
(dataframe['volume'] > 0)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
conditions.append(
|
||||||
|
(
|
||||||
|
|
||||||
|
self.buy_condition_10_enable.value &
|
||||||
|
|
||||||
|
(dataframe['rsi_1h'] < self.buy_rsi_1h_4.value) &
|
||||||
|
(dataframe['close_1h'] < dataframe['bb_lowerband_1h']) &
|
||||||
|
|
||||||
|
(dataframe['hist'] > 0) &
|
||||||
|
(dataframe['hist'].shift(2) < 0) &
|
||||||
|
(dataframe['rsi'] < 40.5) &
|
||||||
|
(dataframe['hist'] > dataframe['close'] * 0.0012) &
|
||||||
|
(dataframe['open'] < dataframe['close']) &
|
||||||
|
|
||||||
|
(dataframe['volume'] > 0)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
if conditions:
|
||||||
|
dataframe.loc[
|
||||||
|
reduce(lambda x, y: x | y, conditions),
|
||||||
|
'buy'
|
||||||
|
] = 1
|
||||||
|
|
||||||
|
return dataframe
|
||||||
|
|
||||||
|
def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||||
|
# dataframe.loc[
|
||||||
|
# (
|
||||||
|
# (dataframe['close'] > dataframe['bb_middleband'] * 1.01) & # Don't be gready, sell fast
|
||||||
|
# (dataframe['volume'] > 0) # Make sure Volume is not 0
|
||||||
|
# )
|
||||||
|
# ,
|
||||||
|
# 'sell'
|
||||||
|
# ] = 0
|
||||||
|
|
||||||
|
dataframe.loc[
|
||||||
|
(
|
||||||
|
(dataframe['crossed_below_ema_12_26']) &
|
||||||
|
(dataframe['volume'] > 0) # Make sure Volume is not 0
|
||||||
|
)
|
||||||
|
,
|
||||||
|
'sell'
|
||||||
|
] = 0
|
||||||
|
|
||||||
|
return dataframe
|
||||||
|
|
||||||
|
# Chaikin Money Flow Volume
|
||||||
|
def MFV(dataframe):
|
||||||
|
df = dataframe.copy()
|
||||||
|
N = ((df['close'] - df['low']) - (df['high'] - df['close'])) / (df['high'] - df['low'])
|
||||||
|
M = N * df['volume']
|
||||||
|
return M
|
568
strategies/RSIDivergence.py
Executable file
568
strategies/RSIDivergence.py
Executable file
@ -0,0 +1,568 @@
|
|||||||
|
# --- Do not remove these libs ---
|
||||||
|
from freqtrade.strategy.interface import IStrategy
|
||||||
|
from typing import Dict, List
|
||||||
|
from functools import reduce
|
||||||
|
from pandas import DataFrame
|
||||||
|
# --------------------------------
|
||||||
|
|
||||||
|
import talib.abstract as ta
|
||||||
|
import numpy as np
|
||||||
|
import freqtrade.vendor.qtpylib.indicators as qtpylib
|
||||||
|
import datetime
|
||||||
|
from technical.util import resample_to_interval, resampled_merge
|
||||||
|
from freqtrade.strategy import DecimalParameter, IntParameter, BooleanParameter
|
||||||
|
|
||||||
|
rangeUpper = 60
|
||||||
|
rangeLower = 5
|
||||||
|
|
||||||
|
def EWO(dataframe, ema_length=5, ema2_length=35):
|
||||||
|
df = dataframe.copy()
|
||||||
|
ema1 = ta.EMA(df, timeperiod=ema_length)
|
||||||
|
ema2 = ta.EMA(df, timeperiod=ema2_length)
|
||||||
|
emadif = (ema1 - ema2) / df['close'] * 100
|
||||||
|
return emadif
|
||||||
|
|
||||||
|
def valuewhen(dataframe, condition, source, occurrence):
|
||||||
|
copy = dataframe.copy()
|
||||||
|
copy['colFromIndex'] = copy.index
|
||||||
|
copy = copy.sort_values(by=[condition, 'colFromIndex'], ascending=False).reset_index(drop=True)
|
||||||
|
copy['valuewhen'] = np.where(copy[condition] > 0, copy[source].shift(-occurrence), copy[source])
|
||||||
|
copy['barrsince'] = copy['colFromIndex'] - copy['colFromIndex'].shift(-occurrence)
|
||||||
|
copy.loc[
|
||||||
|
(
|
||||||
|
(rangeLower <= copy['barrsince']) &
|
||||||
|
(copy['barrsince'] <= rangeUpper)
|
||||||
|
)
|
||||||
|
, "in_range"] = 1
|
||||||
|
copy['in_range'] = copy['in_range'].fillna(0)
|
||||||
|
copy = copy.sort_values(by=['colFromIndex'], ascending=True).reset_index(drop=True)
|
||||||
|
return copy['valuewhen'], copy['in_range']
|
||||||
|
|
||||||
|
|
||||||
|
class Divergence(IStrategy):
|
||||||
|
INTERFACE_VERSION = 2
|
||||||
|
|
||||||
|
# Buy hyperspace params:
|
||||||
|
buy_params = {
|
||||||
|
'use_bull': True,
|
||||||
|
'use_hidden_bull': False,
|
||||||
|
"ewo_high": 5.835,
|
||||||
|
"low_rsi_buy": 30,
|
||||||
|
"high_rsi_buy": 60,
|
||||||
|
"low_adx_buy": 30,
|
||||||
|
"high_adx_buy": 30,
|
||||||
|
"low_stoch_buy": 20,
|
||||||
|
"high_stoch_buy": 80,
|
||||||
|
"low_osc_buy": 80,
|
||||||
|
"high_osc_buy": 80,
|
||||||
|
}
|
||||||
|
# Sell hyperspace params:
|
||||||
|
sell_params = {
|
||||||
|
'use_bear': True,
|
||||||
|
'use_hidden_bear': True
|
||||||
|
}
|
||||||
|
|
||||||
|
# ROI table:
|
||||||
|
minimal_roi = {
|
||||||
|
"0": 0.05,
|
||||||
|
}
|
||||||
|
|
||||||
|
# Stoploss:
|
||||||
|
stoploss = -0.08
|
||||||
|
|
||||||
|
# Trailing stop:
|
||||||
|
trailing_stop = True
|
||||||
|
trailing_stop_positive = 0.005
|
||||||
|
trailing_stop_positive_offset = 0.02
|
||||||
|
trailing_only_offset_is_reached = True
|
||||||
|
|
||||||
|
# Optimal timeframe for the strategy
|
||||||
|
timeframe = '5m'
|
||||||
|
|
||||||
|
use_custom_stoploss = False
|
||||||
|
|
||||||
|
use_bull = BooleanParameter(default=buy_params['use_bull'], space='buy', optimize=False)
|
||||||
|
use_hidden_bull = BooleanParameter(default=buy_params['use_hidden_bull'], space='buy', optimize=False)
|
||||||
|
use_bear = BooleanParameter(default=sell_params['use_bear'], space='sell', optimize=True)
|
||||||
|
use_hidden_bear = BooleanParameter(default=sell_params['use_hidden_bear'], space='sell', optimize=True)
|
||||||
|
# Protection
|
||||||
|
fast_ewo = 50
|
||||||
|
slow_ewo = 200
|
||||||
|
ewo_high = DecimalParameter(0, 7.0, default=buy_params['ewo_high'], space='buy', optimize=False)
|
||||||
|
low_rsi_buy = IntParameter(0, 100, default=buy_params['low_rsi_buy'], space='buy', optimize=True)
|
||||||
|
high_rsi_buy = IntParameter(0, 100, default=buy_params['high_rsi_buy'], space='buy', optimize=True)
|
||||||
|
low_adx_buy = IntParameter(0, 100, default=buy_params['low_adx_buy'], space='buy', optimize=True)
|
||||||
|
high_adx_buy = IntParameter(0, 100, default=buy_params['high_adx_buy'], space='buy', optimize=True)
|
||||||
|
low_stoch_buy = IntParameter(0, 100, default=buy_params['low_stoch_buy'], space='buy', optimize=True)
|
||||||
|
high_stoch_buy = IntParameter(0, 100, default=buy_params['high_stoch_buy'], space='buy', optimize=True)
|
||||||
|
low_osc_buy = IntParameter(0, 100, default=buy_params['low_osc_buy'], space='buy', optimize=True)
|
||||||
|
high_osc_buy = IntParameter(0, 100, default=buy_params['high_osc_buy'], space='buy', optimize=True)
|
||||||
|
|
||||||
|
# Number of candles the strategy requires before producing valid signals
|
||||||
|
startup_candle_count: int = 30
|
||||||
|
|
||||||
|
osc = 'slowd'
|
||||||
|
len = 14
|
||||||
|
src = 'close'
|
||||||
|
lbL = 5
|
||||||
|
lbR = 5
|
||||||
|
|
||||||
|
def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||||
|
"""
|
||||||
|
study(title="Divergence Indicator", format=format.price, resolution="")
|
||||||
|
len = input(title="RSI Period", minval=1, defval=14)
|
||||||
|
src = input(title="RSI Source", defval=close)
|
||||||
|
lbR = input(title="Pivot Lookback Right", defval=5) # lookahead
|
||||||
|
lbL = input(title="Pivot Lookback Left", defval=5)
|
||||||
|
rangeUpper = input(title="Max of Lookback Range", defval=60)
|
||||||
|
rangeLower = input(title="Min of Lookback Range", defval=5)
|
||||||
|
plotBull = input(title="Plot Bullish", defval=true)
|
||||||
|
plotHiddenBull = input(title="Plot Hidden Bullish", defval=false)
|
||||||
|
plotBear = input(title="Plot Bearish", defval=true)
|
||||||
|
plotHiddenBear = input(title="Plot Hidden Bearish", defval=false)
|
||||||
|
bearColor = color.red
|
||||||
|
bullColor = color.green
|
||||||
|
hiddenBullColor = color.new(color.green, 80)
|
||||||
|
hiddenBearColor = color.new(color.red, 80)
|
||||||
|
textColor = color.white
|
||||||
|
noneColor = color.new(color.white, 100)
|
||||||
|
osc = rsi(src, len)
|
||||||
|
"""
|
||||||
|
dataframe['RSI'] = ta.RSI(dataframe[self.src], self.len)
|
||||||
|
dataframe['RSI'] = dataframe['RSI'].fillna(0)
|
||||||
|
stoch = ta.STOCH(dataframe, fastk_period=10, slowk_period=3, slowk_matype=0, slowd_period=3, slowd_matype=0)
|
||||||
|
dataframe['slowk'] = stoch['slowk']
|
||||||
|
dataframe['slowd'] = stoch['slowd']
|
||||||
|
dataframe['osc'] = dataframe[self.osc]
|
||||||
|
|
||||||
|
# plFound = na(pivotlow(osc, lbL, lbR)) ? false : true
|
||||||
|
dataframe['min'] = dataframe['osc'].rolling(self.lbL).min()
|
||||||
|
dataframe['prevMin'] = np.where(dataframe['min'] > dataframe['min'].shift(), dataframe['min'].shift(), dataframe['min'])
|
||||||
|
dataframe.loc[
|
||||||
|
(
|
||||||
|
(dataframe['osc'].shift(1) == dataframe['prevMin'].shift(1)) &
|
||||||
|
(dataframe['osc'] != dataframe['prevMin'])
|
||||||
|
)
|
||||||
|
, 'plFound'] = 1
|
||||||
|
|
||||||
|
# phFound = na(pivothigh(osc, lbL, lbR)) ? false : true
|
||||||
|
dataframe['max'] = dataframe['osc'].rolling(self.lbL).max()
|
||||||
|
dataframe['prevMax'] = np.where(dataframe['max'] < dataframe['max'].shift(), dataframe['max'].shift(), dataframe['max'])
|
||||||
|
dataframe.loc[
|
||||||
|
(
|
||||||
|
(dataframe['osc'].shift(1) == dataframe['prevMax'].shift(1)) &
|
||||||
|
(dataframe['osc'] != dataframe['prevMax'])
|
||||||
|
)
|
||||||
|
, 'phFound'] = 1
|
||||||
|
|
||||||
|
|
||||||
|
#------------------------------------------------------------------------------
|
||||||
|
# Regular Bullish
|
||||||
|
# Osc: Higher Low
|
||||||
|
# oscHL = osc[lbR] > valuewhen(plFound, osc[lbR], 1) and _inRange(plFound[1])
|
||||||
|
dataframe['valuewhen_plFound_osc'], dataframe['inrange_plFound_osc'] = valuewhen(dataframe, 'plFound', 'osc', 1)
|
||||||
|
dataframe.loc[
|
||||||
|
(
|
||||||
|
(dataframe['osc'] > dataframe['valuewhen_plFound_osc']) &
|
||||||
|
(dataframe['inrange_plFound_osc'] == 1)
|
||||||
|
)
|
||||||
|
, 'oscHL'] = 1
|
||||||
|
|
||||||
|
# Price: Lower Low
|
||||||
|
# priceLL = low[lbR] < valuewhen(plFound, low[lbR], 1)
|
||||||
|
dataframe['valuewhen_plFound_low'], dataframe['inrange_plFound_low'] = valuewhen(dataframe, 'plFound', 'low', 1)
|
||||||
|
dataframe.loc[
|
||||||
|
(dataframe['low'] < dataframe['valuewhen_plFound_low'])
|
||||||
|
, 'priceLL'] = 1
|
||||||
|
#bullCond = plotBull and priceLL and oscHL and plFound
|
||||||
|
dataframe.loc[
|
||||||
|
(
|
||||||
|
(dataframe['priceLL'] == 1) &
|
||||||
|
(dataframe['oscHL'] == 1) &
|
||||||
|
(dataframe['plFound'] == 1)
|
||||||
|
)
|
||||||
|
, 'bullCond'] = 1
|
||||||
|
|
||||||
|
# plot(
|
||||||
|
# plFound ? osc[lbR] : na,
|
||||||
|
# offset=-lbR,
|
||||||
|
# title="Regular Bullish",
|
||||||
|
# linewidth=2,
|
||||||
|
# color=(bullCond ? bullColor : noneColor)
|
||||||
|
# )
|
||||||
|
#
|
||||||
|
# plotshape(
|
||||||
|
# bullCond ? osc[lbR] : na,
|
||||||
|
# offset=-lbR,
|
||||||
|
# title="Regular Bullish Label",
|
||||||
|
# text=" Bull ",
|
||||||
|
# style=shape.labelup,
|
||||||
|
# location=location.absolute,
|
||||||
|
# color=bullColor,
|
||||||
|
# textcolor=textColor
|
||||||
|
# )
|
||||||
|
|
||||||
|
# //------------------------------------------------------------------------------
|
||||||
|
# // Hidden Bullish
|
||||||
|
# // Osc: Lower Low
|
||||||
|
#
|
||||||
|
# oscLL = osc[lbR] < valuewhen(plFound, osc[lbR], 1) and _inRange(plFound[1])
|
||||||
|
dataframe['valuewhen_plFound_osc'], dataframe['inrange_plFound_osc'] = valuewhen(dataframe, 'plFound', 'osc', 1)
|
||||||
|
dataframe.loc[
|
||||||
|
(
|
||||||
|
(dataframe['osc'] < dataframe['valuewhen_plFound_osc']) &
|
||||||
|
(dataframe['inrange_plFound_osc'] == 1)
|
||||||
|
)
|
||||||
|
, 'oscLL'] = 1
|
||||||
|
#
|
||||||
|
# // Price: Higher Low
|
||||||
|
#
|
||||||
|
# priceHL = low[lbR] > valuewhen(plFound, low[lbR], 1)
|
||||||
|
dataframe['valuewhen_plFound_low'], dataframe['inrange_plFound_low'] = valuewhen(dataframe,'plFound', 'low', 1)
|
||||||
|
dataframe.loc[
|
||||||
|
(dataframe['low'] > dataframe['valuewhen_plFound_low'])
|
||||||
|
, 'priceHL'] = 1
|
||||||
|
# hiddenBullCond = plotHiddenBull and priceHL and oscLL and plFound
|
||||||
|
dataframe.loc[
|
||||||
|
(
|
||||||
|
(dataframe['priceHL'] == 1) &
|
||||||
|
(dataframe['oscLL'] == 1) &
|
||||||
|
(dataframe['plFound'] == 1)
|
||||||
|
)
|
||||||
|
, 'hiddenBullCond'] = 1
|
||||||
|
#
|
||||||
|
# plot(
|
||||||
|
# plFound ? osc[lbR] : na,
|
||||||
|
# offset=-lbR,
|
||||||
|
# title="Hidden Bullish",
|
||||||
|
# linewidth=2,
|
||||||
|
# color=(hiddenBullCond ? hiddenBullColor : noneColor)
|
||||||
|
# )
|
||||||
|
#
|
||||||
|
# plotshape(
|
||||||
|
# hiddenBullCond ? osc[lbR] : na,
|
||||||
|
# offset=-lbR,
|
||||||
|
# title="Hidden Bullish Label",
|
||||||
|
# text=" H Bull ",
|
||||||
|
# style=shape.labelup,
|
||||||
|
# location=location.absolute,
|
||||||
|
# color=bullColor,
|
||||||
|
# textcolor=textColor
|
||||||
|
# )
|
||||||
|
#
|
||||||
|
# //------------------------------------------------------------------------------
|
||||||
|
# // Regular Bearish
|
||||||
|
# // Osc: Lower High
|
||||||
|
#
|
||||||
|
# oscLH = osc[lbR] < valuewhen(phFound, osc[lbR], 1) and _inRange(phFound[1])
|
||||||
|
dataframe['valuewhen_phFound_osc'], dataframe['inrange_phFound_osc'] = valuewhen(dataframe, 'phFound', 'osc', 1)
|
||||||
|
dataframe.loc[
|
||||||
|
(
|
||||||
|
(dataframe['osc'] < dataframe['valuewhen_phFound_osc']) &
|
||||||
|
(dataframe['inrange_phFound_osc'] == 1)
|
||||||
|
)
|
||||||
|
, 'oscLH'] = 1
|
||||||
|
#
|
||||||
|
# // Price: Higher High
|
||||||
|
#
|
||||||
|
# priceHH = high[lbR] > valuewhen(phFound, high[lbR], 1)
|
||||||
|
dataframe['valuewhen_phFound_high'], dataframe['inrange_phFound_high'] = valuewhen(dataframe, 'phFound', 'high', 1)
|
||||||
|
dataframe.loc[
|
||||||
|
(dataframe['high'] > dataframe['valuewhen_phFound_high'])
|
||||||
|
, 'priceHH'] = 1
|
||||||
|
#
|
||||||
|
# bearCond = plotBear and priceHH and oscLH and phFound
|
||||||
|
dataframe.loc[
|
||||||
|
(
|
||||||
|
(dataframe['priceHH'] == 1) &
|
||||||
|
(dataframe['oscLH'] == 1) &
|
||||||
|
(dataframe['phFound'] == 1)
|
||||||
|
)
|
||||||
|
, 'bearCond'] = 1
|
||||||
|
#
|
||||||
|
# plot(
|
||||||
|
# phFound ? osc[lbR] : na,
|
||||||
|
# offset=-lbR,
|
||||||
|
# title="Regular Bearish",
|
||||||
|
# linewidth=2,
|
||||||
|
# color=(bearCond ? bearColor : noneColor)
|
||||||
|
# )
|
||||||
|
#
|
||||||
|
# plotshape(
|
||||||
|
# bearCond ? osc[lbR] : na,
|
||||||
|
# offset=-lbR,
|
||||||
|
# title="Regular Bearish Label",
|
||||||
|
# text=" Bear ",
|
||||||
|
# style=shape.labeldown,
|
||||||
|
# location=location.absolute,
|
||||||
|
# color=bearColor,
|
||||||
|
# textcolor=textColor
|
||||||
|
# )
|
||||||
|
#
|
||||||
|
# //------------------------------------------------------------------------------
|
||||||
|
# // Hidden Bearish
|
||||||
|
# // Osc: Higher High
|
||||||
|
#
|
||||||
|
# oscHH = osc[lbR] > valuewhen(phFound, osc[lbR], 1) and _inRange(phFound[1])
|
||||||
|
dataframe['valuewhen_phFound_osc'], dataframe['inrange_phFound_osc'] = valuewhen(dataframe, 'phFound', 'osc', 1)
|
||||||
|
dataframe.loc[
|
||||||
|
(
|
||||||
|
(dataframe['osc'] > dataframe['valuewhen_phFound_osc']) &
|
||||||
|
(dataframe['inrange_phFound_osc'] == 1)
|
||||||
|
)
|
||||||
|
, 'oscHH'] = 1
|
||||||
|
#
|
||||||
|
# // Price: Lower High
|
||||||
|
#
|
||||||
|
# priceLH = high[lbR] < valuewhen(phFound, high[lbR], 1)
|
||||||
|
dataframe['valuewhen_phFound_high'], dataframe['inrange_phFound_high'] = valuewhen(dataframe, 'phFound', 'high', 1)
|
||||||
|
dataframe.loc[
|
||||||
|
(dataframe['high'] < dataframe['valuewhen_phFound_high'])
|
||||||
|
, 'priceLH'] = 1
|
||||||
|
#
|
||||||
|
# hiddenBearCond = plotHiddenBear and priceLH and oscHH and phFound
|
||||||
|
dataframe.loc[
|
||||||
|
(
|
||||||
|
(dataframe['priceLH'] == 1) &
|
||||||
|
(dataframe['oscHH'] == 1) &
|
||||||
|
(dataframe['phFound'] == 1)
|
||||||
|
)
|
||||||
|
, 'hiddenBearCond'] = 1
|
||||||
|
#
|
||||||
|
# plot(
|
||||||
|
# phFound ? osc[lbR] : na,
|
||||||
|
# offset=-lbR,
|
||||||
|
# title="Hidden Bearish",
|
||||||
|
# linewidth=2,
|
||||||
|
# color=(hiddenBearCond ? hiddenBearColor : noneColor)
|
||||||
|
# )
|
||||||
|
#
|
||||||
|
# plotshape(
|
||||||
|
# hiddenBearCond ? osc[lbR] : na,
|
||||||
|
# offset=-lbR,
|
||||||
|
# title="Hidden Bearish Label",
|
||||||
|
# text=" H Bear ",
|
||||||
|
# style=shape.labeldown,
|
||||||
|
# location=location.absolute,
|
||||||
|
# color=bearColor,
|
||||||
|
# textcolor=textColor
|
||||||
|
# )"""
|
||||||
|
|
||||||
|
# Elliot
|
||||||
|
dataframe['EWO'] = EWO(dataframe, self.fast_ewo, self.slow_ewo)
|
||||||
|
|
||||||
|
dataframe['ADX'] = ta.ADX(dataframe, timeperiod=14)
|
||||||
|
return dataframe
|
||||||
|
|
||||||
|
def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||||
|
conditions = []
|
||||||
|
|
||||||
|
if self.use_bull.value:
|
||||||
|
conditions.append(
|
||||||
|
(
|
||||||
|
(dataframe['bullCond'] > 0) &
|
||||||
|
(dataframe['valuewhen_plFound_osc'] > self.low_osc_buy.value) &
|
||||||
|
(dataframe['valuewhen_plFound_osc'] < self.high_osc_buy.value) &
|
||||||
|
#(dataframe['EWO'] > self.ewo_high.value) &
|
||||||
|
(dataframe['RSI'] < self.high_rsi_buy.value) &
|
||||||
|
(dataframe['RSI'] > self.low_rsi_buy.value) &
|
||||||
|
(dataframe['ADX'] > self.low_adx_buy.value) &
|
||||||
|
(dataframe['ADX'] < self.high_adx_buy.value) &
|
||||||
|
(dataframe['slowk'] < self.high_stoch_buy.value) &
|
||||||
|
(dataframe['slowk'] > self.low_stoch_buy.value) &
|
||||||
|
(dataframe['volume'] > 0)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
if self.use_hidden_bull.value:
|
||||||
|
conditions.append(
|
||||||
|
(
|
||||||
|
(dataframe['hiddenBullCond'] > 0) &
|
||||||
|
(dataframe['valuewhen_plFound_osc'] > self.low_osc_buy.value) &
|
||||||
|
(dataframe['valuewhen_plFound_osc'] < self.high_osc_buy.value) &
|
||||||
|
(dataframe['RSI'] < self.high_rsi_buy.value) &
|
||||||
|
(dataframe['RSI'] > self.low_rsi_buy.value) &
|
||||||
|
(dataframe['slowk'] < self.high_stoch_buy.value) &
|
||||||
|
(dataframe['slowk'] > self.low_stoch_buy.value) &
|
||||||
|
(dataframe['ADX'] > self.low_adx_buy.value) &
|
||||||
|
(dataframe['ADX'] < self.high_adx_buy.value) &
|
||||||
|
(dataframe['volume'] > 0)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
if conditions:
|
||||||
|
dataframe.loc[
|
||||||
|
reduce(lambda x, y: x | y, conditions),
|
||||||
|
'buy'
|
||||||
|
] = 1
|
||||||
|
|
||||||
|
return dataframe
|
||||||
|
|
||||||
|
def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||||
|
conditions = []
|
||||||
|
|
||||||
|
if self.use_bear.value:
|
||||||
|
conditions.append(
|
||||||
|
(
|
||||||
|
(dataframe['bearCond'] > 0) &
|
||||||
|
(dataframe['volume'] > 0)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
if self.use_hidden_bear.value:
|
||||||
|
conditions.append(
|
||||||
|
(
|
||||||
|
(dataframe['hiddenBearCond'] > 0) &
|
||||||
|
(dataframe['volume'] > 0)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
if conditions:
|
||||||
|
dataframe.loc[
|
||||||
|
reduce(lambda x, y: x | y, conditions),
|
||||||
|
'sell'
|
||||||
|
] = 1
|
||||||
|
|
||||||
|
dataframe.to_csv('user_data/csvs/%s_%s.csv' % (self.__class__.__name__, metadata["pair"].replace("/", "_")))
|
||||||
|
|
||||||
|
return dataframe
|
||||||
|
|
||||||
|
class RSIDivergence(SOTCHDivergence):
|
||||||
|
|
||||||
|
# Buy hyperspace params:
|
||||||
|
buy_params = {
|
||||||
|
"high_adx_buy": 68,
|
||||||
|
"high_osc_buy": 74,
|
||||||
|
"high_rsi_buy": 53,
|
||||||
|
"high_stoch_buy": 64,
|
||||||
|
"low_adx_buy": 41,
|
||||||
|
"low_osc_buy": 15,
|
||||||
|
"low_rsi_buy": 9,
|
||||||
|
"low_stoch_buy": 13,
|
||||||
|
"ewo_high": 5.835, # value loaded from strategy
|
||||||
|
"use_bull": True, # value loaded from strategy
|
||||||
|
"use_hidden_bull": False, # value loaded from strategy
|
||||||
|
}
|
||||||
|
|
||||||
|
# Sell hyperspace params:
|
||||||
|
sell_params = {
|
||||||
|
"use_bear": False, # value loaded from strategy
|
||||||
|
"use_hidden_bear": False, # value loaded from strategy
|
||||||
|
}
|
||||||
|
|
||||||
|
# ROI table: # value loaded from strategy
|
||||||
|
minimal_roi = {
|
||||||
|
"0": 0.131,
|
||||||
|
"13": 0.073,
|
||||||
|
"56": 0.022,
|
||||||
|
"133": 0
|
||||||
|
}
|
||||||
|
|
||||||
|
# Stoploss:
|
||||||
|
stoploss = -0.2 # value loaded from strategy
|
||||||
|
|
||||||
|
# Trailing stop:
|
||||||
|
trailing_stop = True # value loaded from strategy
|
||||||
|
trailing_stop_positive = 0.005 # value loaded from strategy
|
||||||
|
trailing_stop_positive_offset = 0.02 # value loaded from strategy
|
||||||
|
trailing_only_offset_is_reached = True # value loaded from strategy
|
||||||
|
|
||||||
|
|
||||||
|
osc = 'RSI'
|
||||||
|
len = 14
|
||||||
|
src = 'close'
|
||||||
|
lbL = 40
|
||||||
|
|
||||||
|
class RSIDivergenceNPOriginal(RSIDivergence):
|
||||||
|
# Buy hyperspace params:
|
||||||
|
buy_params = {
|
||||||
|
"adx_buy": 36,
|
||||||
|
"high_rsi_buy": 60,
|
||||||
|
"high_stoch_buy": 92,
|
||||||
|
"low_rsi_buy": 21,
|
||||||
|
"low_stoch_buy": 6,
|
||||||
|
"use_bull": True,
|
||||||
|
"use_hidden_bull": False,
|
||||||
|
"ewo_high": 5.835, # value loaded from strategy
|
||||||
|
}
|
||||||
|
|
||||||
|
# Sell hyperspace params:
|
||||||
|
sell_params = {
|
||||||
|
"use_bear": False,
|
||||||
|
"use_hidden_bear": False,
|
||||||
|
}
|
||||||
|
|
||||||
|
# ROI table: # value loaded from strategy
|
||||||
|
minimal_roi = {
|
||||||
|
"0": 0.05
|
||||||
|
}
|
||||||
|
|
||||||
|
# Stoploss:
|
||||||
|
stoploss = -0.2 # value loaded from strategy
|
||||||
|
|
||||||
|
# Trailing stop:
|
||||||
|
trailing_stop = True
|
||||||
|
trailing_stop_positive = 0.001
|
||||||
|
trailing_stop_positive_offset = 0.02
|
||||||
|
trailing_only_offset_is_reached = True
|
||||||
|
|
||||||
|
osc = 'RSI'
|
||||||
|
len = 14
|
||||||
|
src = 'close'
|
||||||
|
lbL = 40
|
||||||
|
|
||||||
|
def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||||
|
conditions = []
|
||||||
|
|
||||||
|
if self.use_bull.value:
|
||||||
|
conditions.append(
|
||||||
|
(
|
||||||
|
(dataframe['bullCond'] > 0) &
|
||||||
|
(dataframe['volume'] > 0)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
if self.use_hidden_bull.value:
|
||||||
|
conditions.append(
|
||||||
|
(
|
||||||
|
(dataframe['hiddenBullCond'] > 0) &
|
||||||
|
(dataframe['volume'] > 0)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
if conditions:
|
||||||
|
dataframe.loc[
|
||||||
|
reduce(lambda x, y: x | y, conditions),
|
||||||
|
'buy'
|
||||||
|
] = 1
|
||||||
|
|
||||||
|
return dataframe
|
||||||
|
|
||||||
|
def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||||
|
conditions = []
|
||||||
|
|
||||||
|
if self.use_bear.value:
|
||||||
|
conditions.append(
|
||||||
|
(
|
||||||
|
(dataframe['bearCond'] > 0) &
|
||||||
|
(dataframe['volume'] > 0)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
if self.use_hidden_bear.value:
|
||||||
|
conditions.append(
|
||||||
|
(
|
||||||
|
(dataframe['hiddenBearCond'] > 0) &
|
||||||
|
(dataframe['volume'] > 0)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
if conditions:
|
||||||
|
dataframe.loc[
|
||||||
|
reduce(lambda x, y: x | y, conditions),
|
||||||
|
'sell'
|
||||||
|
] = 1
|
||||||
|
|
||||||
|
dataframe.to_csv('user_data/csvs/%s_%s.csv' % (self.__class__.__name__, metadata["pair"].replace("/", "_")))
|
||||||
|
|
||||||
|
return dataframe
|
110
strategies/SwingHighToSky.py
Executable file
110
strategies/SwingHighToSky.py
Executable file
@ -0,0 +1,110 @@
|
|||||||
|
"""
|
||||||
|
author = "Kevin Ossenbrück"
|
||||||
|
copyright = "Free For Use"
|
||||||
|
credits = ["Bloom Trading, Mohsen Hassan"]
|
||||||
|
license = "MIT"
|
||||||
|
version = "1.0"
|
||||||
|
maintainer = "Kevin Ossenbrück"
|
||||||
|
email = "kevin.ossenbrueck@pm.de"
|
||||||
|
status = "Live"
|
||||||
|
"""
|
||||||
|
|
||||||
|
from freqtrade.strategy import IStrategy
|
||||||
|
from freqtrade.strategy import IntParameter
|
||||||
|
from functools import reduce
|
||||||
|
from pandas import DataFrame
|
||||||
|
|
||||||
|
import talib.abstract as ta
|
||||||
|
import freqtrade.vendor.qtpylib.indicators as qtpylib
|
||||||
|
import numpy
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# CCI timerperiods and values
|
||||||
|
cciBuyTP = 72
|
||||||
|
cciBuyVal = -175
|
||||||
|
cciSellTP = 66
|
||||||
|
cciSellVal = -106
|
||||||
|
|
||||||
|
# RSI timeperiods and values
|
||||||
|
rsiBuyTP = 36
|
||||||
|
rsiBuyVal = 90
|
||||||
|
rsiSellTP = 45
|
||||||
|
rsiSellVal = 88
|
||||||
|
|
||||||
|
|
||||||
|
class SwingHighToSky(IStrategy):
|
||||||
|
INTERFACE_VERSION = 3
|
||||||
|
|
||||||
|
timeframe = '15m'
|
||||||
|
|
||||||
|
stoploss = -0.34338
|
||||||
|
|
||||||
|
minimal_roi = {"0": 0.27058, "33": 0.0853, "64": 0.04093, "244": 0}
|
||||||
|
|
||||||
|
buy_cci = IntParameter(low=-200, high=200, default=100, space='buy', optimize=True)
|
||||||
|
buy_cciTime = IntParameter(low=10, high=80, default=20, space='buy', optimize=True)
|
||||||
|
buy_rsi = IntParameter(low=10, high=90, default=30, space='buy', optimize=True)
|
||||||
|
buy_rsiTime = IntParameter(low=10, high=80, default=26, space='buy', optimize=True)
|
||||||
|
|
||||||
|
sell_cci = IntParameter(low=-200, high=200, default=100, space='sell', optimize=True)
|
||||||
|
sell_cciTime = IntParameter(low=10, high=80, default=20, space='sell', optimize=True)
|
||||||
|
sell_rsi = IntParameter(low=10, high=90, default=30, space='sell', optimize=True)
|
||||||
|
sell_rsiTime = IntParameter(low=10, high=80, default=26, space='sell', optimize=True)
|
||||||
|
|
||||||
|
# Buy hyperspace params:
|
||||||
|
buy_params = {
|
||||||
|
"buy_cci": -175,
|
||||||
|
"buy_cciTime": 72,
|
||||||
|
"buy_rsi": 90,
|
||||||
|
"buy_rsiTime": 36,
|
||||||
|
}
|
||||||
|
|
||||||
|
# Sell hyperspace params:
|
||||||
|
sell_params = {
|
||||||
|
"sell_cci": -106,
|
||||||
|
"sell_cciTime": 66,
|
||||||
|
"sell_rsi": 88,
|
||||||
|
"sell_rsiTime": 45,
|
||||||
|
}
|
||||||
|
|
||||||
|
def informative_pairs(self):
|
||||||
|
return []
|
||||||
|
|
||||||
|
def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||||
|
|
||||||
|
for val in self.buy_cciTime.range:
|
||||||
|
dataframe[f'cci-{val}'] = ta.CCI(dataframe, timeperiod=val)
|
||||||
|
|
||||||
|
for val in self.sell_cciTime.range:
|
||||||
|
dataframe[f'cci-sell-{val}'] = ta.CCI(dataframe, timeperiod=val)
|
||||||
|
|
||||||
|
for val in self.buy_rsiTime.range:
|
||||||
|
dataframe[f'rsi-{val}'] = ta.RSI(dataframe, timeperiod=val)
|
||||||
|
|
||||||
|
for val in self.sell_rsiTime.range:
|
||||||
|
dataframe[f'rsi-sell-{val}'] = ta.RSI(dataframe, timeperiod=val)
|
||||||
|
|
||||||
|
return dataframe
|
||||||
|
|
||||||
|
def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||||
|
|
||||||
|
dataframe.loc[
|
||||||
|
(
|
||||||
|
(dataframe[f'cci-{self.buy_cciTime.value}'] < self.buy_cci.value) &
|
||||||
|
(dataframe[f'rsi-{self.buy_rsiTime.value}'] < self.buy_rsi.value)
|
||||||
|
),
|
||||||
|
'enter_long'] = 1
|
||||||
|
|
||||||
|
return dataframe
|
||||||
|
|
||||||
|
def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||||
|
|
||||||
|
dataframe.loc[
|
||||||
|
(
|
||||||
|
(dataframe[f'cci-sell-{self.sell_cciTime.value}'] > self.sell_cci.value) &
|
||||||
|
(dataframe[f'rsi-sell-{self.sell_rsiTime.value}'] > self.sell_rsi.value)
|
||||||
|
),
|
||||||
|
'exit_long'] = 1
|
||||||
|
|
||||||
|
return dataframe
|
404
strategies/sample_strategy.py
Executable file
404
strategies/sample_strategy.py
Executable file
@ -0,0 +1,404 @@
|
|||||||
|
# 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 # noqa
|
||||||
|
import pandas as pd # noqa
|
||||||
|
from pandas import DataFrame
|
||||||
|
from typing import Optional, Union
|
||||||
|
|
||||||
|
from freqtrade.strategy import (BooleanParameter, CategoricalParameter, DecimalParameter,
|
||||||
|
IStrategy, IntParameter)
|
||||||
|
|
||||||
|
# --------------------------------
|
||||||
|
# Add your lib to import here
|
||||||
|
import talib.abstract as ta
|
||||||
|
import freqtrade.vendor.qtpylib.indicators as qtpylib
|
||||||
|
|
||||||
|
|
||||||
|
# This class is a sample. Feel free to customize it.
|
||||||
|
class SampleStrategy(IStrategy):
|
||||||
|
"""
|
||||||
|
This is a sample strategy to inspire you.
|
||||||
|
More information in https://www.freqtrade.io/en/latest/strategy-customization/
|
||||||
|
|
||||||
|
You can:
|
||||||
|
:return: a Dataframe with all mandatory indicators for the strategies
|
||||||
|
- Rename the class name (Do not forget to update class_name)
|
||||||
|
- Add any methods you want to build your strategy
|
||||||
|
- Add any lib you need to build your strategy
|
||||||
|
|
||||||
|
You must keep:
|
||||||
|
- the lib in the section "Do not remove these libs"
|
||||||
|
- the methods: populate_indicators, populate_entry_trend, populate_exit_trend
|
||||||
|
You should keep:
|
||||||
|
- timeframe, minimal_roi, stoploss, trailing_*
|
||||||
|
"""
|
||||||
|
# Strategy interface version - allow new iterations of the strategy interface.
|
||||||
|
# Check the documentation or the Sample strategy to get the latest version.
|
||||||
|
INTERFACE_VERSION = 3
|
||||||
|
|
||||||
|
# Can this strategy go short?
|
||||||
|
can_short: bool = False
|
||||||
|
|
||||||
|
# Minimal ROI designed for the strategy.
|
||||||
|
# This attribute will be overridden if the config file contains "minimal_roi".
|
||||||
|
minimal_roi = {
|
||||||
|
"60": 0.01,
|
||||||
|
"30": 0.02,
|
||||||
|
"0": 0.04
|
||||||
|
}
|
||||||
|
|
||||||
|
# Optimal stoploss designed for the strategy.
|
||||||
|
# This attribute will be overridden if the config file contains "stoploss".
|
||||||
|
stoploss = -0.10
|
||||||
|
|
||||||
|
# Trailing stoploss
|
||||||
|
trailing_stop = False
|
||||||
|
# trailing_only_offset_is_reached = False
|
||||||
|
# trailing_stop_positive = 0.01
|
||||||
|
# trailing_stop_positive_offset = 0.0 # Disabled / not configured
|
||||||
|
|
||||||
|
# Optimal timeframe for the strategy.
|
||||||
|
timeframe = '5m'
|
||||||
|
|
||||||
|
# Run "populate_indicators()" only for new candle.
|
||||||
|
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
|
||||||
|
|
||||||
|
# Hyperoptable parameters
|
||||||
|
buy_rsi = IntParameter(low=1, high=50, default=30, space='buy', optimize=True, load=True)
|
||||||
|
sell_rsi = IntParameter(low=50, high=100, default=70, space='sell', optimize=True, load=True)
|
||||||
|
short_rsi = IntParameter(low=51, high=100, default=70, space='sell', optimize=True, load=True)
|
||||||
|
exit_short_rsi = IntParameter(low=1, high=50, default=30, space='buy', optimize=True, load=True)
|
||||||
|
|
||||||
|
# Number of candles the strategy requires before producing valid signals
|
||||||
|
startup_candle_count: int = 30
|
||||||
|
|
||||||
|
# Optional order type mapping.
|
||||||
|
order_types = {
|
||||||
|
'entry': 'limit',
|
||||||
|
'exit': 'limit',
|
||||||
|
'stoploss': 'market',
|
||||||
|
'stoploss_on_exchange': False
|
||||||
|
}
|
||||||
|
|
||||||
|
# Optional order time in force.
|
||||||
|
order_time_in_force = {
|
||||||
|
'entry': 'GTC',
|
||||||
|
'exit': 'GTC'
|
||||||
|
}
|
||||||
|
|
||||||
|
plot_config = {
|
||||||
|
'main_plot': {
|
||||||
|
'tema': {},
|
||||||
|
'sar': {'color': 'white'},
|
||||||
|
},
|
||||||
|
'subplots': {
|
||||||
|
"MACD": {
|
||||||
|
'macd': {'color': 'blue'},
|
||||||
|
'macdsignal': {'color': 'orange'},
|
||||||
|
},
|
||||||
|
"RSI": {
|
||||||
|
'rsi': {'color': 'red'},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def informative_pairs(self):
|
||||||
|
"""
|
||||||
|
Define additional, informative pair/interval combinations to be cached from the exchange.
|
||||||
|
These pair/interval combinations are non-tradeable, unless they are part
|
||||||
|
of the whitelist as well.
|
||||||
|
For more information, please consult the documentation
|
||||||
|
:return: List of tuples in the format (pair, interval)
|
||||||
|
Sample: return [("ETH/USDT", "5m"),
|
||||||
|
("BTC/USDT", "15m"),
|
||||||
|
]
|
||||||
|
"""
|
||||||
|
return []
|
||||||
|
|
||||||
|
def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||||
|
"""
|
||||||
|
Adds several different TA indicators to the given DataFrame
|
||||||
|
|
||||||
|
Performance Note: For the best performance be frugal on the number of indicators
|
||||||
|
you are using. Let uncomment only the indicator you are using in your strategies
|
||||||
|
or your hyperopt configuration, otherwise you will waste your memory and CPU usage.
|
||||||
|
:param dataframe: Dataframe with data from the exchange
|
||||||
|
:param metadata: Additional information, like the currently traded pair
|
||||||
|
:return: a Dataframe with all mandatory indicators for the strategies
|
||||||
|
"""
|
||||||
|
|
||||||
|
# Momentum Indicators
|
||||||
|
# ------------------------------------
|
||||||
|
|
||||||
|
# ADX
|
||||||
|
dataframe['adx'] = ta.ADX(dataframe)
|
||||||
|
|
||||||
|
# # Plus Directional Indicator / Movement
|
||||||
|
# dataframe['plus_dm'] = ta.PLUS_DM(dataframe)
|
||||||
|
# dataframe['plus_di'] = ta.PLUS_DI(dataframe)
|
||||||
|
|
||||||
|
# # Minus Directional Indicator / Movement
|
||||||
|
# dataframe['minus_dm'] = ta.MINUS_DM(dataframe)
|
||||||
|
# dataframe['minus_di'] = ta.MINUS_DI(dataframe)
|
||||||
|
|
||||||
|
# # Aroon, Aroon Oscillator
|
||||||
|
# aroon = ta.AROON(dataframe)
|
||||||
|
# dataframe['aroonup'] = aroon['aroonup']
|
||||||
|
# dataframe['aroondown'] = aroon['aroondown']
|
||||||
|
# dataframe['aroonosc'] = ta.AROONOSC(dataframe)
|
||||||
|
|
||||||
|
# # Awesome Oscillator
|
||||||
|
# dataframe['ao'] = qtpylib.awesome_oscillator(dataframe)
|
||||||
|
|
||||||
|
# # Keltner Channel
|
||||||
|
# keltner = qtpylib.keltner_channel(dataframe)
|
||||||
|
# dataframe["kc_upperband"] = keltner["upper"]
|
||||||
|
# dataframe["kc_lowerband"] = keltner["lower"]
|
||||||
|
# dataframe["kc_middleband"] = keltner["mid"]
|
||||||
|
# dataframe["kc_percent"] = (
|
||||||
|
# (dataframe["close"] - dataframe["kc_lowerband"]) /
|
||||||
|
# (dataframe["kc_upperband"] - dataframe["kc_lowerband"])
|
||||||
|
# )
|
||||||
|
# dataframe["kc_width"] = (
|
||||||
|
# (dataframe["kc_upperband"] - dataframe["kc_lowerband"]) / dataframe["kc_middleband"]
|
||||||
|
# )
|
||||||
|
|
||||||
|
# # Ultimate Oscillator
|
||||||
|
# dataframe['uo'] = ta.ULTOSC(dataframe)
|
||||||
|
|
||||||
|
# # Commodity Channel Index: values [Oversold:-100, Overbought:100]
|
||||||
|
# dataframe['cci'] = ta.CCI(dataframe)
|
||||||
|
|
||||||
|
# RSI
|
||||||
|
dataframe['rsi'] = ta.RSI(dataframe)
|
||||||
|
|
||||||
|
# # Inverse Fisher transform on RSI: values [-1.0, 1.0] (https://goo.gl/2JGGoy)
|
||||||
|
# rsi = 0.1 * (dataframe['rsi'] - 50)
|
||||||
|
# dataframe['fisher_rsi'] = (np.exp(2 * rsi) - 1) / (np.exp(2 * rsi) + 1)
|
||||||
|
|
||||||
|
# # Inverse Fisher transform on RSI normalized: values [0.0, 100.0] (https://goo.gl/2JGGoy)
|
||||||
|
# dataframe['fisher_rsi_norma'] = 50 * (dataframe['fisher_rsi'] + 1)
|
||||||
|
|
||||||
|
# # Stochastic Slow
|
||||||
|
# stoch = ta.STOCH(dataframe)
|
||||||
|
# dataframe['slowd'] = stoch['slowd']
|
||||||
|
# dataframe['slowk'] = stoch['slowk']
|
||||||
|
|
||||||
|
# Stochastic Fast
|
||||||
|
stoch_fast = ta.STOCHF(dataframe)
|
||||||
|
dataframe['fastd'] = stoch_fast['fastd']
|
||||||
|
dataframe['fastk'] = stoch_fast['fastk']
|
||||||
|
|
||||||
|
# # Stochastic RSI
|
||||||
|
# Please read https://github.com/freqtrade/freqtrade/issues/2961 before using this.
|
||||||
|
# STOCHRSI is NOT aligned with tradingview, which may result in non-expected results.
|
||||||
|
# stoch_rsi = ta.STOCHRSI(dataframe)
|
||||||
|
# dataframe['fastd_rsi'] = stoch_rsi['fastd']
|
||||||
|
# dataframe['fastk_rsi'] = stoch_rsi['fastk']
|
||||||
|
|
||||||
|
# MACD
|
||||||
|
macd = ta.MACD(dataframe)
|
||||||
|
dataframe['macd'] = macd['macd']
|
||||||
|
dataframe['macdsignal'] = macd['macdsignal']
|
||||||
|
dataframe['macdhist'] = macd['macdhist']
|
||||||
|
|
||||||
|
# MFI
|
||||||
|
dataframe['mfi'] = ta.MFI(dataframe)
|
||||||
|
|
||||||
|
# # ROC
|
||||||
|
# dataframe['roc'] = ta.ROC(dataframe)
|
||||||
|
|
||||||
|
# Overlap Studies
|
||||||
|
# ------------------------------------
|
||||||
|
|
||||||
|
# Bollinger Bands
|
||||||
|
bollinger = qtpylib.bollinger_bands(qtpylib.typical_price(dataframe), window=20, stds=2)
|
||||||
|
dataframe['bb_lowerband'] = bollinger['lower']
|
||||||
|
dataframe['bb_middleband'] = bollinger['mid']
|
||||||
|
dataframe['bb_upperband'] = bollinger['upper']
|
||||||
|
dataframe["bb_percent"] = (
|
||||||
|
(dataframe["close"] - dataframe["bb_lowerband"]) /
|
||||||
|
(dataframe["bb_upperband"] - dataframe["bb_lowerband"])
|
||||||
|
)
|
||||||
|
dataframe["bb_width"] = (
|
||||||
|
(dataframe["bb_upperband"] - dataframe["bb_lowerband"]) / dataframe["bb_middleband"]
|
||||||
|
)
|
||||||
|
|
||||||
|
# Bollinger Bands - Weighted (EMA based instead of SMA)
|
||||||
|
# weighted_bollinger = qtpylib.weighted_bollinger_bands(
|
||||||
|
# qtpylib.typical_price(dataframe), window=20, stds=2
|
||||||
|
# )
|
||||||
|
# dataframe["wbb_upperband"] = weighted_bollinger["upper"]
|
||||||
|
# dataframe["wbb_lowerband"] = weighted_bollinger["lower"]
|
||||||
|
# dataframe["wbb_middleband"] = weighted_bollinger["mid"]
|
||||||
|
# dataframe["wbb_percent"] = (
|
||||||
|
# (dataframe["close"] - dataframe["wbb_lowerband"]) /
|
||||||
|
# (dataframe["wbb_upperband"] - dataframe["wbb_lowerband"])
|
||||||
|
# )
|
||||||
|
# dataframe["wbb_width"] = (
|
||||||
|
# (dataframe["wbb_upperband"] - dataframe["wbb_lowerband"]) /
|
||||||
|
# dataframe["wbb_middleband"]
|
||||||
|
# )
|
||||||
|
|
||||||
|
# # EMA - Exponential Moving Average
|
||||||
|
# dataframe['ema3'] = ta.EMA(dataframe, timeperiod=3)
|
||||||
|
# dataframe['ema5'] = ta.EMA(dataframe, timeperiod=5)
|
||||||
|
# dataframe['ema10'] = ta.EMA(dataframe, timeperiod=10)
|
||||||
|
# dataframe['ema21'] = ta.EMA(dataframe, timeperiod=21)
|
||||||
|
# dataframe['ema50'] = ta.EMA(dataframe, timeperiod=50)
|
||||||
|
# dataframe['ema100'] = ta.EMA(dataframe, timeperiod=100)
|
||||||
|
|
||||||
|
# # SMA - Simple Moving Average
|
||||||
|
# dataframe['sma3'] = ta.SMA(dataframe, timeperiod=3)
|
||||||
|
# dataframe['sma5'] = ta.SMA(dataframe, timeperiod=5)
|
||||||
|
# dataframe['sma10'] = ta.SMA(dataframe, timeperiod=10)
|
||||||
|
# dataframe['sma21'] = ta.SMA(dataframe, timeperiod=21)
|
||||||
|
# dataframe['sma50'] = ta.SMA(dataframe, timeperiod=50)
|
||||||
|
# dataframe['sma100'] = ta.SMA(dataframe, timeperiod=100)
|
||||||
|
|
||||||
|
# Parabolic SAR
|
||||||
|
dataframe['sar'] = ta.SAR(dataframe)
|
||||||
|
|
||||||
|
# TEMA - Triple Exponential Moving Average
|
||||||
|
dataframe['tema'] = ta.TEMA(dataframe, timeperiod=9)
|
||||||
|
|
||||||
|
# Cycle Indicator
|
||||||
|
# ------------------------------------
|
||||||
|
# Hilbert Transform Indicator - SineWave
|
||||||
|
hilbert = ta.HT_SINE(dataframe)
|
||||||
|
dataframe['htsine'] = hilbert['sine']
|
||||||
|
dataframe['htleadsine'] = hilbert['leadsine']
|
||||||
|
|
||||||
|
# Pattern Recognition - Bullish candlestick patterns
|
||||||
|
# ------------------------------------
|
||||||
|
# # Hammer: values [0, 100]
|
||||||
|
# dataframe['CDLHAMMER'] = ta.CDLHAMMER(dataframe)
|
||||||
|
# # Inverted Hammer: values [0, 100]
|
||||||
|
# dataframe['CDLINVERTEDHAMMER'] = ta.CDLINVERTEDHAMMER(dataframe)
|
||||||
|
# # Dragonfly Doji: values [0, 100]
|
||||||
|
# dataframe['CDLDRAGONFLYDOJI'] = ta.CDLDRAGONFLYDOJI(dataframe)
|
||||||
|
# # Piercing Line: values [0, 100]
|
||||||
|
# dataframe['CDLPIERCING'] = ta.CDLPIERCING(dataframe) # values [0, 100]
|
||||||
|
# # Morningstar: values [0, 100]
|
||||||
|
# dataframe['CDLMORNINGSTAR'] = ta.CDLMORNINGSTAR(dataframe) # values [0, 100]
|
||||||
|
# # Three White Soldiers: values [0, 100]
|
||||||
|
# dataframe['CDL3WHITESOLDIERS'] = ta.CDL3WHITESOLDIERS(dataframe) # values [0, 100]
|
||||||
|
|
||||||
|
# Pattern Recognition - Bearish candlestick patterns
|
||||||
|
# ------------------------------------
|
||||||
|
# # Hanging Man: values [0, 100]
|
||||||
|
# dataframe['CDLHANGINGMAN'] = ta.CDLHANGINGMAN(dataframe)
|
||||||
|
# # Shooting Star: values [0, 100]
|
||||||
|
# dataframe['CDLSHOOTINGSTAR'] = ta.CDLSHOOTINGSTAR(dataframe)
|
||||||
|
# # Gravestone Doji: values [0, 100]
|
||||||
|
# dataframe['CDLGRAVESTONEDOJI'] = ta.CDLGRAVESTONEDOJI(dataframe)
|
||||||
|
# # Dark Cloud Cover: values [0, 100]
|
||||||
|
# dataframe['CDLDARKCLOUDCOVER'] = ta.CDLDARKCLOUDCOVER(dataframe)
|
||||||
|
# # Evening Doji Star: values [0, 100]
|
||||||
|
# dataframe['CDLEVENINGDOJISTAR'] = ta.CDLEVENINGDOJISTAR(dataframe)
|
||||||
|
# # Evening Star: values [0, 100]
|
||||||
|
# dataframe['CDLEVENINGSTAR'] = ta.CDLEVENINGSTAR(dataframe)
|
||||||
|
|
||||||
|
# Pattern Recognition - Bullish/Bearish candlestick patterns
|
||||||
|
# ------------------------------------
|
||||||
|
# # Three Line Strike: values [0, -100, 100]
|
||||||
|
# dataframe['CDL3LINESTRIKE'] = ta.CDL3LINESTRIKE(dataframe)
|
||||||
|
# # Spinning Top: values [0, -100, 100]
|
||||||
|
# dataframe['CDLSPINNINGTOP'] = ta.CDLSPINNINGTOP(dataframe) # values [0, -100, 100]
|
||||||
|
# # Engulfing: values [0, -100, 100]
|
||||||
|
# dataframe['CDLENGULFING'] = ta.CDLENGULFING(dataframe) # values [0, -100, 100]
|
||||||
|
# # Harami: values [0, -100, 100]
|
||||||
|
# dataframe['CDLHARAMI'] = ta.CDLHARAMI(dataframe) # values [0, -100, 100]
|
||||||
|
# # Three Outside Up/Down: values [0, -100, 100]
|
||||||
|
# dataframe['CDL3OUTSIDE'] = ta.CDL3OUTSIDE(dataframe) # values [0, -100, 100]
|
||||||
|
# # Three Inside Up/Down: values [0, -100, 100]
|
||||||
|
# dataframe['CDL3INSIDE'] = ta.CDL3INSIDE(dataframe) # values [0, -100, 100]
|
||||||
|
|
||||||
|
# # Chart type
|
||||||
|
# # ------------------------------------
|
||||||
|
# # 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']
|
||||||
|
|
||||||
|
# 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:
|
||||||
|
"""
|
||||||
|
Based on TA indicators, populates the entry signal for the given dataframe
|
||||||
|
:param dataframe: DataFrame
|
||||||
|
:param metadata: Additional information, like the currently traded pair
|
||||||
|
:return: DataFrame with entry columns populated
|
||||||
|
"""
|
||||||
|
dataframe.loc[
|
||||||
|
(
|
||||||
|
# Signal: RSI crosses above 30
|
||||||
|
(qtpylib.crossed_above(dataframe['rsi'], self.buy_rsi.value)) &
|
||||||
|
(dataframe['tema'] <= dataframe['bb_middleband']) & # Guard: tema below BB middle
|
||||||
|
(dataframe['tema'] > dataframe['tema'].shift(1)) & # Guard: tema is raising
|
||||||
|
(dataframe['volume'] > 0) # Make sure Volume is not 0
|
||||||
|
),
|
||||||
|
'enter_long'] = 1
|
||||||
|
|
||||||
|
dataframe.loc[
|
||||||
|
(
|
||||||
|
# Signal: RSI crosses above 70
|
||||||
|
(qtpylib.crossed_above(dataframe['rsi'], self.short_rsi.value)) &
|
||||||
|
(dataframe['tema'] > dataframe['bb_middleband']) & # Guard: tema above BB middle
|
||||||
|
(dataframe['tema'] < dataframe['tema'].shift(1)) & # Guard: tema is falling
|
||||||
|
(dataframe['volume'] > 0) # Make sure Volume is not 0
|
||||||
|
),
|
||||||
|
'enter_short'] = 1
|
||||||
|
|
||||||
|
return dataframe
|
||||||
|
|
||||||
|
def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||||
|
"""
|
||||||
|
Based on TA indicators, populates the exit signal for the given dataframe
|
||||||
|
:param dataframe: DataFrame
|
||||||
|
:param metadata: Additional information, like the currently traded pair
|
||||||
|
:return: DataFrame with exit columns populated
|
||||||
|
"""
|
||||||
|
dataframe.loc[
|
||||||
|
(
|
||||||
|
# Signal: RSI crosses above 70
|
||||||
|
(qtpylib.crossed_above(dataframe['rsi'], self.sell_rsi.value)) &
|
||||||
|
(dataframe['tema'] > dataframe['bb_middleband']) & # Guard: tema above BB middle
|
||||||
|
(dataframe['tema'] < dataframe['tema'].shift(1)) & # Guard: tema is falling
|
||||||
|
(dataframe['volume'] > 0) # Make sure Volume is not 0
|
||||||
|
),
|
||||||
|
|
||||||
|
'exit_long'] = 1
|
||||||
|
|
||||||
|
dataframe.loc[
|
||||||
|
(
|
||||||
|
# Signal: RSI crosses above 30
|
||||||
|
(qtpylib.crossed_above(dataframe['rsi'], self.exit_short_rsi.value)) &
|
||||||
|
# Guard: tema below BB middle
|
||||||
|
(dataframe['tema'] <= dataframe['bb_middleband']) &
|
||||||
|
(dataframe['tema'] > dataframe['tema'].shift(1)) & # Guard: tema is raising
|
||||||
|
(dataframe['volume'] > 0) # Make sure Volume is not 0
|
||||||
|
),
|
||||||
|
'exit_short'] = 1
|
||||||
|
|
||||||
|
return dataframe
|
Reference in New Issue
Block a user