Timeframe
5m
Direction
Long Only
Stoploss
-99.0%
Trailing Stop
No
ROI
0m: 2.9%, 10m: 2.1%, 40m: 0.8%, 120m: 0.5%
Interface Version
2
Startup Candles
N/A
Indicators
7
freqtrade/freqtrade-strategies
Strategy 003 author@: Gerald Lonlas github@: https://github.com/freqtrade/freqtrade-strategies
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
###########################################################################################################
## CombinedBearBullUnifiedV1 by witrer (倪世通) ##
## ##
## Combined strategy integrating V5, V6, V9 features with enhanced bull/bear/sideways detection ##
## Multi-dimensional signal analysis with adaptive position management ##
## Based on ilya's strategies: https://github.com/i1ya/freqtrade-strategies ##
## ##
## GitHub: https://github.com/witrer ##
## Version: 1.0.0 ##
## Date: 2024-12-19 ##
## ##
###########################################################################################################
def SSLChannels(dataframe, length=7):
"""SSL Channels indicator for trend detection"""
df = dataframe.copy()
df['ATR'] = ta.ATR(df, timeperiod=14)
df['smaHigh'] = df['high'].rolling(length).mean() + df['ATR']
df['smaLow'] = df['low'].rolling(length).mean() - df['ATR']
df['hlv'] = np.where(df['close'] > df['smaHigh'], 1, np.where(df['close'] < df['smaLow'], -1, np.NAN))
df['hlv'] = df['hlv'].ffill()
df['sslDown'] = np.where(df['hlv'] < 0, df['smaHigh'], df['smaLow'])
df['sslUp'] = np.where(df['hlv'] < 0, df['smaLow'], df['smaHigh'])
return df['sslDown'], df['sslUp']
def market_direction(dataframe):
"""Detect market direction: Bull (1), Bear (-1), Sideways (0)"""
bull_condition = (
(dataframe['ema_50'] > dataframe['ema_200']) &
(dataframe['ema_20'] > dataframe['ema_50']) &
(dataframe['close'] > dataframe['ema_20']) &
(dataframe['ssl_up'] > dataframe['ssl_down']) &
(dataframe['ema_50_1h'] > dataframe['ema_200_1h'])
)
bear_condition = (
(dataframe['ema_50'] < dataframe['ema_200']) &
(dataframe['ema_20'] < dataframe['ema_50']) &
(dataframe['close'] < dataframe['ema_20']) &
(dataframe['ssl_up'] < dataframe['ssl_down']) &
(dataframe['ema_50_1h'] < dataframe['ema_200_1h'])
)
return np.where(bull_condition, 1, np.where(bear_condition, -1, 0))
class CombinedBearBullUnifiedV1(IStrategy):
INTERFACE_VERSION = 2
minimal_roi = {
"0": 0.029,
"10": 0.021,
"40": 0.008,
"120": 0.005,
"300": 0.002,
}
stoploss = -0.99
timeframe = '5m'
inf_1h = '1h'
inf_4h = '4h'
use_sell_signal = True
sell_profit_only = False
sell_profit_offset = 0.001
ignore_roi_if_buy_signal = False
trailing_stop = False
trailing_only_offset_is_reached = False
trailing_stop_positive = 0.01
trailing_stop_positive_offset = 0.025
use_custom_stoploss = True
process_only_new_candles = False
startup_candle_count: int = 200
order_types = {
'buy': 'market',
'sell': 'market',
'stoploss': 'market',
'stoploss_on_exchange': False
}
# Parameters
buy_params = {
"buy_condition_bull_1_enable": True,
"buy_condition_bull_2_enable": True,
"buy_condition_bull_3_enable": True,
"buy_condition_bear_1_enable": True,
"buy_condition_bear_2_enable": True,
"buy_condition_bear_3_enable": True,
"buy_condition_sideways_1_enable": True,
"buy_condition_sideways_2_enable": True,
"buy_condition_universal_1_enable": True,
"buy_condition_universal_2_enable": True,
"buy_condition_extreme_dip_enable": False,
"buy_condition_breakout_enable": True,
"buy_condition_diamond_hands_enable": True,
}
# Categorical parameters
buy_condition_bull_1_enable = CategoricalParameter([True, False], default=True, space='buy', optimize=False, load=True)
buy_condition_bull_2_enable = CategoricalParameter([True, False], default=True, space='buy', optimize=False, load=True)
buy_condition_bull_3_enable = CategoricalParameter([True, False], default=True, space='buy', optimize=False, load=True)
buy_condition_bear_1_enable = CategoricalParameter([True, False], default=True, space='buy', optimize=False, load=True)
buy_condition_bear_2_enable = CategoricalParameter([True, False], default=True, space='buy', optimize=False, load=True)
buy_condition_bear_3_enable = CategoricalParameter([True, False], default=True, space='buy', optimize=False, load=True)
buy_condition_sideways_1_enable = CategoricalParameter([True, False], default=True, space='buy', optimize=False, load=True)
buy_condition_sideways_2_enable = CategoricalParameter([True, False], default=True, space='buy', optimize=False, load=True)
buy_condition_universal_1_enable = CategoricalParameter([True, False], default=True, space='buy', optimize=False, load=True)
buy_condition_universal_2_enable = CategoricalParameter([True, False], default=True, space='buy', optimize=False, load=True)
buy_condition_extreme_dip_enable = CategoricalParameter([True, False], default=False, space='buy', optimize=False, load=True)
buy_condition_breakout_enable = CategoricalParameter([True, False], default=True, space='buy', optimize=False, load=True)
buy_condition_diamond_hands_enable = CategoricalParameter([True, False], default=True, space='buy', optimize=False, load=True)
# Bollinger Bands parameters
buy_bb20_close_bblowerband_bull = DecimalParameter(0.98, 1.02, default=0.99, space='buy', optimize=False, load=True)
buy_bb20_close_bblowerband_bear = DecimalParameter(0.94, 0.98, default=0.975, space='buy', optimize=False, load=True)
buy_bb20_close_bblowerband_sideways = DecimalParameter(0.96, 1.00, default=0.985, space='buy', optimize=False, load=True)
# Volume parameters
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=4, space='buy', decimals=1, optimize=False, load=True)
# RSI parameters
buy_rsi_1h_bull = DecimalParameter(20.0, 45.0, default=35.0, space='buy', decimals=1, optimize=False, load=True)
buy_rsi_1h_bear = DecimalParameter(10.0, 25.0, default=15.0, space='buy', decimals=1, optimize=False, load=True)
buy_rsi_1h_sideways = DecimalParameter(15.0, 35.0, default=25.0, space='buy', decimals=1, optimize=False, load=True)
buy_rsi_bull = DecimalParameter(25.0, 45.0, default=35.0, space='buy', decimals=1, optimize=False, load=True)
buy_rsi_bear = DecimalParameter(7.0, 25.0, default=14.2, space='buy', decimals=1, optimize=False, load=True)
buy_rsi_sideways = DecimalParameter(15.0, 35.0, default=25.0, space='buy', decimals=1, optimize=False, load=True)
# MACD parameters
buy_macd_bull = DecimalParameter(0.01, 0.05, default=0.02, space='buy', decimals=2, optimize=False, load=True)
buy_macd_bear = DecimalParameter(0.02, 0.08, default=0.03, space='buy', decimals=2, optimize=False, load=True)
# Additional parameters
buy_extreme_rsi_threshold = DecimalParameter(15.0, 25.0, default=20.0, space='buy', decimals=1, optimize=False, load=True)
buy_breakout_volume_threshold = DecimalParameter(1.2, 2.0, default=1.5, space='buy', decimals=1, optimize=False, load=True)
buy_diamond_hands_dip_threshold = DecimalParameter(1.02, 1.08, default=1.05, space='buy', decimals=2, optimize=False, load=True)
# Sell parameters
sell_bull_profit_threshold = DecimalParameter(1.01, 1.03, default=1.015, space='sell', decimals=3, optimize=False, load=True)
sell_bear_profit_threshold = DecimalParameter(1.003, 1.01, default=1.005, space='sell', decimals=3, optimize=False, load=True)
sell_sideways_profit_threshold = DecimalParameter(1.005, 1.02, default=1.01, space='sell', decimals=3, optimize=False, load=True)
def custom_stoploss(self, pair: str, trade: 'Trade', current_time: datetime,
current_rate: float, current_profit: float, **kwargs) -> float:
"""Enhanced stoploss function combining V6 and V9 features"""
if current_profit > 0.05:
return 0.03
elif current_profit > 0.02:
return 0.01
elif current_profit > 0:
return 0.99
else:
if (current_time - timedelta(minutes=240) > trade.open_date_utc):
return 0.01
trade_time_50 = current_time - timedelta(minutes=50)
if (trade_time_50 > trade.open_date_utc):
try:
number_of_candle_shift = int((trade_time_50 - trade.open_date_utc).total_seconds() / 300)
dataframe, _ = self.dp.get_analyzed_dataframe(pair, self.timeframe)
candle = dataframe.iloc[-number_of_candle_shift].squeeze()
if current_rate * 1.015 < candle['open']:
return 0.01
except IndexError:
return 0.01
return 0.99
def informative_pairs(self):
pairs = self.dp.current_whitelist()
informative_pairs = [(pair, '1h') for pair in pairs]
informative_pairs += [(pair, '4h') 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."
informative_1h = self.dp.get_pair_dataframe(pair=metadata['pair'], timeframe=self.inf_1h)
informative_1h['ema_20'] = ta.EMA(informative_1h, timeperiod=20)
informative_1h['ema_50'] = ta.EMA(informative_1h, timeperiod=50)
informative_1h['ema_200'] = ta.EMA(informative_1h, timeperiod=200)
informative_1h['rsi'] = ta.RSI(informative_1h, timeperiod=14)
ssl_down_1h, ssl_up_1h = SSLChannels(informative_1h, 20)
informative_1h['ssl_down'] = ssl_down_1h
informative_1h['ssl_up'] = ssl_up_1h
macd, macdsignal, macdhist = ta.MACD(informative_1h)
informative_1h['macd'] = macd
informative_1h['macdsignal'] = macdsignal
informative_1h['macdhist'] = macdhist
return informative_1h
def informative_4h_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
assert self.dp, "DataProvider is required for multiple timeframes."
informative_4h = self.dp.get_pair_dataframe(pair=metadata['pair'], timeframe=self.inf_4h)
informative_4h['ema_50'] = ta.EMA(informative_4h, timeperiod=50)
informative_4h['ema_200'] = ta.EMA(informative_4h, timeperiod=200)
informative_4h['rsi'] = ta.RSI(informative_4h, timeperiod=14)
return informative_4h
def normal_tf_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
# 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']
# BinHV45 indicators from V5
bb_40 = qtpylib.bollinger_bands(dataframe['close'], window=40, stds=2)
dataframe['lower'] = bb_40['lower']
dataframe['mid'] = bb_40['mid']
dataframe['bbdelta'] = (bb_40['mid'] - dataframe['lower']).abs()
dataframe['closedelta'] = (dataframe['close'] - dataframe['close'].shift()).abs()
dataframe['tail'] = (dataframe['close'] - dataframe['low']).abs()
# Volume analysis
dataframe['volume_mean_slow'] = dataframe['volume'].rolling(window=30).mean()
dataframe['volume_mean_fast'] = dataframe['volume'].rolling(window=10).mean()
# Moving averages
dataframe['ema_12'] = ta.EMA(dataframe, timeperiod=12)
dataframe['ema_20'] = ta.EMA(dataframe, timeperiod=20)
dataframe['ema_26'] = ta.EMA(dataframe, timeperiod=26)
dataframe['ema_50'] = ta.EMA(dataframe, timeperiod=50)
dataframe['ema_200'] = ta.EMA(dataframe, timeperiod=200)
dataframe['sma_5'] = ta.SMA(dataframe, timeperiod=5)
dataframe['sma_20'] = ta.SMA(dataframe, timeperiod=20)
# Momentum indicators
dataframe['rsi'] = ta.RSI(dataframe, timeperiod=14)
dataframe['rsi_fast'] = ta.RSI(dataframe, timeperiod=7)
# SSL Channels
ssl_down, ssl_up = SSLChannels(dataframe, 7)
dataframe['ssl_down'] = ssl_down
dataframe['ssl_up'] = ssl_up
# MACD
macd, macdsignal, macdhist = ta.MACD(dataframe)
dataframe['macd'] = macd
dataframe['macdsignal'] = macdsignal
dataframe['macdhist'] = macdhist
# Market direction detection
dataframe['market_direction'] = market_direction(dataframe)
return dataframe
def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
informative_1h = self.informative_1h_indicators(dataframe, metadata)
dataframe = merge_informative_pair(dataframe, informative_1h, self.timeframe, self.inf_1h, ffill=True)
informative_4h = self.informative_4h_indicators(dataframe, metadata)
dataframe = merge_informative_pair(dataframe, informative_4h, self.timeframe, self.inf_4h, ffill=True)
dataframe = self.normal_tf_indicators(dataframe, metadata)
return dataframe
def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
dataframe.loc[
# 🐂 BULL MARKET CONDITIONS
(
self.buy_condition_bull_1_enable.value &
(dataframe['market_direction'] == 1) &
(dataframe['close'] > dataframe['ema_200']) &
(dataframe['close'] > dataframe['ema_200_1h']) &
(dataframe['ema_50_4h'] > dataframe['ema_200_4h']) &
(dataframe['close'] < dataframe['bb_lowerband'] * self.buy_bb20_close_bblowerband_bull.value) &
(dataframe['volume_mean_slow'] > dataframe['volume_mean_slow'].shift(30) * self.buy_volume_pump_1.value) &
(dataframe['volume'] < (dataframe['volume'].shift() * self.buy_volume_drop_1.value)) &
(dataframe['rsi_1h'] < self.buy_rsi_1h_bull.value) &
(dataframe['volume'] > 0)
)
|
(
self.buy_condition_bull_2_enable.value &
(dataframe['market_direction'] == 1) &
(dataframe['close'] > dataframe['ema_200']) &
(dataframe['ssl_up_1h'] > dataframe['ssl_down_1h']) &
(dataframe['ema_26'] > dataframe['ema_12']) &
((dataframe['ema_26'] - dataframe['ema_12']) > (dataframe['open'] * self.buy_macd_bull.value)) &
(dataframe['close'] < dataframe['bb_lowerband']) &
(dataframe['rsi'] < self.buy_rsi_bull.value) &
(dataframe['volume'] < (dataframe['volume'].shift() * self.buy_volume_drop_1.value)) &
(dataframe['volume'] > 0)
)
|
(
self.buy_condition_bull_3_enable.value &
(dataframe['market_direction'] == 1) &
(dataframe['close'] < dataframe['sma_5']) &
(dataframe['ssl_up_1h'] > dataframe['ssl_down_1h']) &
(dataframe['ema_50'] > dataframe['ema_200']) &
(dataframe['ema_50_1h'] > dataframe['ema_200_1h']) &
(dataframe['rsi'] < dataframe['rsi_1h'] - 20) &
(dataframe['volume'] > 0)
)
|
# 🐻 BEAR MARKET CONDITIONS
(
self.buy_condition_bear_1_enable.value &
(dataframe['market_direction'] == -1) & # Bear market detected
(dataframe['close'] < dataframe['bb_lowerband'] * self.buy_bb20_close_bblowerband_bear.value) &
(dataframe['rsi_1h'] < self.buy_rsi_1h_bear.value) &
(dataframe['rsi'] < self.buy_rsi_bear.value) &
(dataframe['volume'] < (dataframe['volume'].shift() * self.buy_volume_drop_1.value)) &
(dataframe['volume_mean_slow'] > dataframe['volume_mean_slow'].shift(30) * self.buy_volume_pump_1.value) &
(dataframe['volume'] > 0)
)
|
(
self.buy_condition_bear_2_enable.value &
(dataframe['market_direction'] == -1) & # Bear market
(dataframe['ema_26'] > dataframe['ema_12']) &
((dataframe['ema_26'] - dataframe['ema_12']) > (dataframe['open'] * self.buy_macd_bear.value)) &
(dataframe['close'] < dataframe['bb_lowerband']) &
(dataframe['rsi_1h'] < self.buy_rsi_1h_bear.value) &
(dataframe['volume'] < (dataframe['volume'].shift() * self.buy_volume_drop_1.value)) &
(dataframe['volume'] > 0)
)
|
(
self.buy_condition_bear_3_enable.value &
(dataframe['market_direction'] == -1) & # Bear market
(dataframe['close'] < dataframe['bb_lowerband']) &
(dataframe['bbdelta'] > dataframe['close'] * 0.008) & # V5 BinHV45 condition
(dataframe['closedelta'] > dataframe['close'] * 0.0175) &
(dataframe['tail'] < dataframe['bbdelta'] * 0.25) &
(dataframe['close'] < dataframe['lower'].shift()) &
(dataframe['close'] <= dataframe['close'].shift()) &
(dataframe['volume'] > 0)
)
|
# 📊 SIDEWAYS MARKET CONDITIONS
(
self.buy_condition_sideways_1_enable.value &
(dataframe['market_direction'] == 0) & # Sideways market detected
(dataframe['close'] < dataframe['bb_lowerband'] * self.buy_bb20_close_bblowerband_sideways.value) &
(dataframe['rsi_1h'] < self.buy_rsi_1h_sideways.value) &
(dataframe['rsi'] < self.buy_rsi_sideways.value) &
(dataframe['volume'] < (dataframe['volume'].shift() * self.buy_volume_drop_1.value)) &
(dataframe['volume'] > 0)
)
|
(
self.buy_condition_sideways_2_enable.value &
(dataframe['market_direction'] == 0) & # Sideways market
(dataframe['close'] < dataframe['sma_20']) &
(dataframe['rsi_fast'] < 30) &
(dataframe['macdhist'] < 0) &
(dataframe['volume_mean_fast'] > dataframe['volume_mean_slow']) &
(dataframe['volume'] > 0)
)
|
# 🌐 UNIVERSAL CONDITIONS (work in any market)
(
self.buy_condition_universal_1_enable.value &
(dataframe['close'] < dataframe['bb_lowerband']) &
(dataframe['rsi'] < 30) &
(dataframe['rsi_1h'] < 40) &
(dataframe['volume'] < (dataframe['volume'].shift() * self.buy_volume_drop_1.value)) &
(dataframe['volume'] > 0)
)
|
(
self.buy_condition_universal_2_enable.value &
(dataframe['close'] < dataframe['sma_5']) &
(dataframe['ssl_up'] > dataframe['ssl_down']) &
(dataframe['rsi'] < 35) &
(dataframe['volume'] > dataframe['volume_mean_slow'] * 1.2) &
(dataframe['volume'] > 0)
)
|
# 🔥 EXTREME DIP CONDITIONS (high risk, high reward)
(
self.buy_condition_extreme_dip_enable.value &
(dataframe['rsi'] < 20) &
(dataframe['rsi_1h'] < 25) &
(dataframe['close'] < dataframe['bb_lowerband'] * 0.95) &
(dataframe['volume'] > dataframe['volume_mean_slow'] * 2) &
(dataframe['close'] < dataframe['close'].shift(5) * 0.97) & # 3% drop in 5 candles
(dataframe['volume'] > 0)
)
|
# 🎯 BREAKOUT CONDITIONS (momentum plays)
(
self.buy_condition_breakout_enable.value &
(dataframe['close'] > dataframe['bb_middleband']) &
(dataframe['close'] > dataframe['close'].shift()) &
(dataframe['volume'] > dataframe['volume_mean_slow'] * 1.5) &
(dataframe['rsi'] > 50) & (dataframe['rsi'] < 65) &
(dataframe['ssl_up'] > dataframe['ssl_down']) &
(dataframe['ema_12'] > dataframe['ema_26']) &
(dataframe['volume'] > 0)
)
|
# 💎 DIAMOND HANDS CONDITIONS (long-term holders)
(
self.buy_condition_diamond_hands_enable.value &
(dataframe['ema_200'] > dataframe['ema_200'].shift(10)) & # Long-term uptrend
(dataframe['ema_50_4h'] > dataframe['ema_200_4h']) & # 4h uptrend
(dataframe['close'] < dataframe['ema_200'] * 1.05) & # Near major support
(dataframe['rsi_4h'] < 40) & # 4h oversold
(dataframe['volume'] > 0)
),
'buy'
] = 1
return dataframe
def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
"""
Enhanced market-adaptive sell logic with multiple exit strategies
"""
dataframe.loc[
(
# 🐂 BULL MARKET SELL CONDITIONS (less aggressive)
(
(dataframe['market_direction'] == 1) &
(
# Take profit conditions for bull market
(dataframe['close'] > dataframe['bb_middleband'] * 1.015) |
(dataframe['rsi'] > 75) |
(dataframe['close'] > dataframe['bb_upperband']) |
# Momentum reversal in bull market
(
(dataframe['rsi'] > 65) &
(dataframe['rsi'].shift() > dataframe['rsi']) &
(dataframe['close'] > dataframe['bb_middleband'])
)
)
)
|
# 🐻 BEAR MARKET SELL CONDITIONS (more aggressive)
(
(dataframe['market_direction'] == -1) &
(
# Quick profit taking in bear market
(dataframe['close'] > dataframe['bb_middleband'] * 1.005) |
(dataframe['rsi'] > 60) |
# Any sign of weakness
(
(dataframe['close'] > dataframe['bb_middleband']) &
(dataframe['volume'] > dataframe['volume_mean_slow'] * 1.5)
) |
# Dead cat bounce protection
(
(dataframe['rsi'] > 55) &
(dataframe['close'] > dataframe['sma_20'])
)
)
)
|
# 📊 SIDEWAYS MARKET SELL CONDITIONS (balanced)
(
(dataframe['market_direction'] == 0) &
(
# Standard profit taking
(dataframe['close'] > dataframe['bb_middleband'] * 1.01) |
(dataframe['rsi'] > 70) |
# Range trading exits
(
(dataframe['close'] > dataframe['bb_upperband'] * 0.98) &
(dataframe['rsi'] > 60)
)
)
)
|
# 🚨 UNIVERSAL EMERGENCY SELLS
(
# Extreme overbought
(dataframe['rsi'] > 85) |
(dataframe['rsi_1h'] > 80) |
# Parabolic move
(dataframe['close'] > dataframe['bb_upperband'] * 1.05) |
# Volume spike with reversal
(
(dataframe['volume'] > dataframe['volume_mean_slow'] * 3) &
(dataframe['close'] < dataframe['open']) &
(dataframe['rsi'] > 65)
) |
# MACD bearish divergence
(
(dataframe['macd'] < dataframe['macdsignal']) &
(dataframe['rsi'] > 60) &
(dataframe['close'] > dataframe['bb_middleband'])
) |
# SSL channel reversal
(
(dataframe['ssl_up'] < dataframe['ssl_down']) &
(dataframe['close'] > dataframe['bb_middleband']) &
(dataframe['rsi'] > 50)
)
)
|
# 💰 PROFIT PROTECTION SELLS
(
# Protect profits in any market condition
(dataframe['close'] > dataframe['ema_12'] * 1.02) &
(dataframe['rsi'] > 65) &
(dataframe['volume'] > dataframe['volume_mean_slow'] * 1.2)
)
) &
(dataframe['volume'] > 0), # Always ensure volume > 0
'sell'
] = 1
return dataframe
def leverage_tier(self, pair: str, current_time: datetime, current_rate: float) -> float:
"""
Dynamic leverage based on market conditions and volatility
Note: This is for futures trading platforms that support leverage
"""
try:
dataframe, _ = self.dp.get_analyzed_dataframe(pair, self.timeframe)
latest = dataframe.iloc[-1].squeeze()
# Base leverage
base_leverage = 1.0
# Market direction adjustment
if latest['market_direction'] == 1: # Bull market
base_leverage = 1.2
elif latest['market_direction'] == -1: # Bear market
base_leverage = 0.8
else: # Sideways
base_leverage = 1.0
# Volatility adjustment
atr_pct = latest.get('atr', 0) / current_rate if current_rate > 0 else 0
if atr_pct > 0.05: # High volatility
base_leverage *= 0.7
elif atr_pct < 0.02: # Low volatility
base_leverage *= 1.1
# Volume confirmation
volume_ratio = latest['volume'] / latest['volume_mean_slow']
if volume_ratio > 2: # High volume
base_leverage *= 1.1
elif volume_ratio < 0.5: # Low volume
base_leverage *= 0.8
return max(0.1, min(base_leverage, 2.0)) # Cap between 0.1 and 2.0
except Exception:
return 1.0 # Default leverage
def confirm_trade_entry(self, pair: str, order_type: str, amount: float,
rate: float, time_in_force: str, current_time: datetime,
**kwargs) -> bool:
"""
Advanced trade entry confirmation with risk management
"""
try:
dataframe, _ = self.dp.get_analyzed_dataframe(pair, self.timeframe)
latest = dataframe.iloc[-1].squeeze()
# Market condition checks
market_dir = latest['market_direction']
# Risk score calculation
risk_score = 0
# Volume spike risk
volume_ratio = latest['volume'] / latest['volume_mean_slow']
if volume_ratio > 3:
risk_score += 30
elif volume_ratio > 2:
risk_score += 15
# Volatility risk
candle_size = abs(latest['close'] - latest['open']) / latest['open']
if candle_size > 0.05:
risk_score += 25
elif candle_size > 0.03:
risk_score += 10
# RSI extremes
if latest['rsi'] < 10 or latest['rsi'] > 90:
risk_score += 20
# Market timing risk
hour = current_time.hour
if hour in [0, 1, 2, 23]: # Low liquidity hours
risk_score += 15
# Bear market additional caution
if market_dir == -1:
risk_score += 10
# Reject trade if risk score too high
if risk_score > 60:
return False
# Additional quality checks
quality_score = 0
# Technical setup quality
if latest['close'] < latest['bb_lowerband']:
quality_score += 20
if latest['rsi'] < 30:
quality_score += 15
if latest['ssl_up'] > latest['ssl_down']:
quality_score += 10
# Trend alignment
if market_dir == 1 and latest['ema_50'] > latest['ema_200']:
quality_score += 15
# Require minimum quality score
return quality_score >= 25
except Exception:
# If analysis fails, err on side of caution
return True
def confirm_trade_exit(self, pair: str, trade: Trade, order_type: str, amount: float,
rate: float, time_in_force: str, sell_reason: str,
current_time: datetime, **kwargs) -> bool:
"""
Confirm trade exit with additional logic
"""
try:
dataframe, _ = self.dp.get_analyzed_dataframe(pair, self.timeframe)
latest = dataframe.iloc[-1].squeeze()
# Always allow stoploss and ROI exits
if sell_reason in ['stoploss', 'roi']:
return True
# Market-specific exit confirmation
market_dir = latest['market_direction']
# In bear markets, be more aggressive with exits
if market_dir == -1:
return True
# In bull markets, allow more room for growth
if market_dir == 1 and trade.calc_profit_ratio(rate) < 0.02:
# Don't exit early in bull market unless good reason
if latest['rsi'] < 70 and latest['close'] < latest['bb_upperband']:
return False
return True
except Exception:
return True
# Additional utility functions for enhanced strategy performance
def calculate_support_resistance(dataframe, window=20):
"""
Calculate dynamic support and resistance levels
"""
# Rolling max/min for resistance/support
dataframe['resistance'] = dataframe['high'].rolling(window=window).max()
dataframe['support'] = dataframe['low'].rolling(window=window).min()
# Pivot points
dataframe['pivot'] = (dataframe['high'] + dataframe['low'] + dataframe['close']) / 3
dataframe['r1'] = 2 * dataframe['pivot'] - dataframe['low']
dataframe['s1'] = 2 * dataframe['pivot'] - dataframe['high']
return dataframe
def market_structure_analysis(dataframe):
"""
Analyze market structure for better entries
"""
# Higher highs and higher lows detection
dataframe['higher_high'] = (
(dataframe['high'] > dataframe['high'].shift(1)) &
(dataframe['high'].shift(1) > dataframe['high'].shift(2))
)
dataframe['higher_low'] = (
(dataframe['low'] > dataframe['low'].shift(1)) &
(dataframe['low'].shift(1) > dataframe['low'].shift(2))
)
# Lower highs and lower lows
dataframe['lower_high'] = (
(dataframe['high'] < dataframe['high'].shift(1)) &
(dataframe['high'].shift(1) < dataframe['high'].shift(2))
)
dataframe['lower_low'] = (
(dataframe['low'] < dataframe['low'].shift(1)) &
(dataframe['low'].shift(1) < dataframe['low'].shift(2))
)
return dataframe
# Performance monitoring and statistics
class StrategyStats:
"""
Track strategy performance metrics
"""
def __init__(self):
self.total_trades = 0
self.winning_trades = 0
self.losing_trades = 0
self.bull_market_trades = 0
self.bear_market_trades = 0
self.sideways_market_trades = 0
def update_trade(self, profit, market_direction):
self.total_trades += 1
if profit > 0:
self.winning_trades += 1
else:
self.losing_trades += 1
if market_direction == 1:
self.bull_market_trades += 1
elif market_direction == -1:
self.bear_market_trades += 1
else:
self.sideways_market_trades += 1
def get_win_rate(self):
return self.winning_trades / self.total_trades if self.total_trades > 0 else 0
def get_market_distribution(self):
total = self.total_trades
if total == 0:
return {"bull": 0, "bear": 0, "sideways": 0}
return {
"bull": self.bull_market_trades / total,
"bear": self.bear_market_trades / total,
"sideways": self.sideways_market_trades / total
}
# Configuration templates for different market conditions
STRATEGY_CONFIGS = {
"aggressive": {
"max_open_trades": 5,
"buy_conditions_enabled": 10,
"roi_multiplier": 1.2,
"risk_tolerance": "high"
},
"conservative": {
"max_open_trades": 2,
"buy_conditions_enabled": 6,
"roi_multiplier": 0.8,
"risk_tolerance": "low"
},
"balanced": {
"max_open_trades": 3,
"buy_conditions_enabled": 8,
"roi_multiplier": 1.0,
"risk_tolerance": "medium"
}
}
# Additional parameters for the strategy class
# (These would be added to the main class)
# Additional buy conditions that were referenced
buy_condition_extreme_dip_enable = CategoricalParameter([True, False], default=False, space='buy', optimize=False, load=True)
buy_condition_breakout_enable = CategoricalParameter([True, False], default=True, space='buy', optimize=False, load=True)
buy_condition_diamond_hands_enable = CategoricalParameter([True, False], default=True, space='buy', optimize=False, load=True)
# Advanced parameters for fine-tuning
buy_extreme_rsi_threshold = DecimalParameter(15.0, 25.0, default=20.0, space='buy', decimals=1, optimize=False, load=True)
buy_breakout_volume_threshold = DecimalParameter(1.2, 2.0, default=1.5, space='buy', decimals=1, optimize=False, load=True)
buy_diamond_hands_dip_threshold = DecimalParameter(1.02, 1.08, default=1.05, space='buy', decimals=2, optimize=False, load=True)
# Sell parameters for fine-tuning
sell_bull_profit_threshold = DecimalParameter(1.01, 1.03, default=1.015, space='sell', decimals=3, optimize=False, load=True)
sell_bear_profit_threshold = DecimalParameter(1.003, 1.01, default=1.005, space='sell', decimals=3, optimize=False, load=True)
sell_sideways_profit_threshold = DecimalParameter(1.005, 1.02, default=1.001, space='sell', decimals=3, optimize=False, load=True)