Strategy 1: RegimeSafe Daily EMA50/200 Crossover + BTC > EMA200 regime filter. Only trades when macro trend is bullish.
Timeframe
1d
Direction
Long Only
Stoploss
-5.0%
Trailing Stop
No
ROI
0m: 0.0%, 1440m: 3.0%, 2880m: 1.0%, 4320m: 0.5%
Interface Version
3
Startup Candles
250
Indicators
2
# pragma pylint: disable=missing-docstring, invalid-name, pointless-string-statement
# flake8: noqa: F401
from freqtrade.strategy import IStrategy, DecimalParameter, IntParameter
from pandas import DataFrame
import talib.abstract as ta
import freqtrade.vendor.qtpylib.indicators as qtpylib
from functools import reduce
import numpy as np
class RegimeSafe(IStrategy):
"""
Strategy 1: RegimeSafe
Daily EMA50/200 Crossover + BTC > EMA200 regime filter.
Only trades when macro trend is bullish.
"""
INTERFACE_VERSION = 3
# ROI table: take 7% profit, scale down over time
minimal_roi = {
"0": 0.07,
"1440": 0.03,
"2880": 0.01,
"4320": 0.005,
"0": 0
}
# Stoploss: wide for daily timeframe
stoploss = -0.05
# Can short? No, regime filter is long-only
can_short = False
# Timeframe
timeframe = '1d'
# Startup candle count for indicators
startup_candle_count = 250
# No trailing stop - proven profit killer on crypto
trailing_stop = False
use_custom_stoploss = False
# Hyperoptable parameters
ema_short = IntParameter(20, 80, default=50, space="buy")
ema_long = IntParameter(100, 300, default=200, space="buy")
def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
# Main pair indicators
dataframe['ema_short'] = ta.EMA(dataframe['close'], timeperiod=self.ema_short.value)
dataframe['ema_long'] = ta.EMA(dataframe['close'], timeperiod=self.ema_long.value)
dataframe['ema_short_slope'] = dataframe['ema_short'].diff(3)
dataframe['ema_long_slope'] = dataframe['ema_long'].diff(5)
dataframe['adx'] = ta.ADX(dataframe, timeperiod=14)
# BTC regime filter
if 'btc_data' not in self.__dict__:
self.btc_data = {}
try:
btc_df = self.dp.get_pair_dataframe("BTC/USDT:USDT", "1d")
btc_df['btc_ema200'] = ta.EMA(btc_df['close'], timeperiod=200)
dataframe['btc_ema200'] = btc_df['btc_ema200'].reindex(dataframe.index, method='ffill')
dataframe['btc_close'] = btc_df['close'].reindex(dataframe.index, method='ffill')
except Exception:
# Fallback: no BTC data = no regime filter
dataframe['btc_ema200'] = 0
dataframe['btc_close'] = 999999
# Regime condition
dataframe['macro_uptrend'] = dataframe['btc_close'] > dataframe['btc_ema200']
# EMA crossover signal
dataframe['ema_bullish'] = (
(dataframe['ema_short'] > dataframe['ema_long']) &
(dataframe['ema_short_slope'] > 0)
)
dataframe['ema_bearish'] = dataframe['ema_short'] < dataframe['ema_long']
return dataframe
def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
dataframe.loc[
(
(dataframe['ema_bullish']) &
(dataframe['macro_uptrend']) &
(dataframe['adx'] > 20) &
(dataframe['volume'] > 0)
),
['enter_long', 'enter_tag']
] = (1, 'regime_safe_long')
return dataframe
def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
dataframe.loc[
(
(dataframe['ema_bearish']) |
(~dataframe['macro_uptrend'])
),
['exit_long', 'exit_tag']
] = (1, 'regime_safe_exit')
return dataframe