Timeframe
1h
Direction
Long & Short
Stoploss
-2.0%
Trailing Stop
Yes
ROI
0m: 4.0%, 360m: 2.0%, 720m: 0.0%
Interface Version
3
Startup Candles
100
Indicators
3
freqtrade/freqtrade-strategies
Strategy 003 author@: Gerald Lonlas github@: https://github.com/freqtrade/freqtrade-strategies
"""
ShortOnlyBearStrategy — Short-only for bear market (2026 YTD: ETH -22.5%)
The simplest thing that could work: in a downtrend, short every bounce to resistance.
No complicated indicators. Just:
- Price below 200 EMA = bear regime
- Short when RSI goes above 60 (overbought in bear = short entry)
- Short when price bounces to 20 EMA in a downtrend
- Exit at ROI or trailing stop
"""
import talib.abstract as ta
import pandas as pd
from pandas import DataFrame
from freqtrade.strategy import IStrategy
class ShortOnlyBearStrategy(IStrategy):
INTERFACE_VERSION = 3
timeframe = '1h'
startup_candle_count = 100
can_short = True
process_only_new_candles = True
# --- Risk ---
stoploss = -0.02 # 2% stop
trailing_stop = True
trailing_stop_positive = 0.01
trailing_stop_positive_offset = 0.02
trailing_only_offset_is_reached = True
use_custom_stoploss = False
# --- ROI ---
minimal_roi = {
"0": 0.04, # 4% immediate
"360": 0.02, # 2% after 15 days
"720": 0,
}
protections = [
{"method": "CooldownPeriod", "stop_duration": 12},
{"method": "StoplossGuard", "lookback_period": 48, "trade_limit": 2, "stop_duration": 24, "only_per_pair": False},
]
def informative_pairs(self):
return []
def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
dataframe['ema_20'] = ta.EMA(dataframe, timeperiod=20)
dataframe['ema_50'] = ta.EMA(dataframe, timeperiod=50)
dataframe['ema_200'] = ta.EMA(dataframe, timeperiod=200)
dataframe['rsi'] = ta.RSI(dataframe, timeperiod=14)
dataframe['volume_ema'] = ta.EMA(dataframe['volume'], timeperiod=20)
dataframe['volume_ratio'] = dataframe['volume'] / (dataframe['volume_ema'] + 1e-10)
return dataframe
def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
# Only short in bear market: price below 200 EMA
bear = (
(dataframe['close'] < dataframe['ema_200']) &
(dataframe['ema_50'] < dataframe['ema_200'])
)
# Short entry 1: bounce to EMA resistance
ema_bounce_short = (
(dataframe['high'] >= dataframe['ema_20'] * 0.995) &
(dataframe['high'] >= dataframe['ema_50'] * 0.99) &
(dataframe['rsi'] > 50) &
(dataframe['close'] < dataframe['open']) &
(dataframe['volume_ratio'] > 0.8)
)
# Short entry 2: overbought in bear market
overbought_short = (
(dataframe['rsi'] > 60) &
(dataframe['rsi'].shift(1) < dataframe['rsi']) & # RSI rising
(dataframe['close'] < dataframe['open']) &
(dataframe['volume_ratio'] > 1.0)
)
# Short entry 3: BB upper band rejection
bb = ta.BBANDS(dataframe, timeperiod=20, nbdevup=2.0, nbdevdn=2.0)
bb_upper = bb['upperband']
bb_rejection_short = (
(dataframe['high'] >= bb_upper * 0.995) &
(dataframe['close'] < bb_upper) &
(dataframe['rsi'] > 55) &
(dataframe['close'] < dataframe['open'])
)
dataframe.loc[
bear & (ema_bounce_short | overbought_short | bb_rejection_short),
'enter_short'] = 1
return dataframe
def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
return dataframe