Files
btc_1h/user_data/strategies/BTC_1h.py
T
jackyu66gitandClaude Opus 4.7 2bd338ad47 Refactor BTC1h strategy: EMA crossover trend-following
Replaced pullback strategy with EMA 12/26 crossover on 1h, filtered by 4h EMA50
uptrend and 1h EMA200. Exits via bearish cross or trailing stop.

Dec 2025-May 2026 backtest: +1.89 USDT (+0.19%), 27 trades, 37% win rate,
0.29% max drawdown, while BTC dropped 6.7%.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-07 15:30:05 +08:00

96 lines
3.0 KiB
Python

from functools import reduce
from freqtrade.strategy import IStrategy, merge_informative_pair
from pandas import DataFrame
import talib.abstract as ta
class BTC1h(IStrategy):
"""
EMA crossover trend-following strategy for BTC/USDT on the 1h timeframe.
Entry: 4h EMA50 uptrend + 1h price above 200 EMA + 12/26 EMA bullish cross.
Exit: 12/26 EMA bearish cross, trailing stop, or stoploss.
Performs best in trending markets. During the Dec 2025-May 2026 period (BTC
dropped 6.7%), this strategy returned +1.89 USDT (+0.19%) with 27 trades,
37% win rate, and max 0.29% drawdown.
"""
timeframe = "1h"
informative_timeframe = "4h"
minimal_roi = {"0": 0.99}
stoploss = -0.025
trailing_stop = True
trailing_stop_positive = 0.01
trailing_stop_positive_offset = 0.025
trailing_only_offset_is_reached = True
use_exit_signal = True
exit_profit_only = False
startup_candle_count = 200
order_types = {
"entry": "limit",
"exit": "limit",
"stoploss": "market",
"stoploss_on_exchange": False,
}
def informative_pairs(self):
pairs = self.dp.current_whitelist()
return [(pair, self.informative_timeframe) for pair in pairs]
def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
if self.dp:
inf = self.dp.get_pair_dataframe(
pair=metadata["pair"], timeframe=self.informative_timeframe
)
inf["ema_50"] = ta.EMA(inf, timeperiod=50)
inf["htf_bull"] = (inf["close"] > inf["ema_50"]).astype(int)
dataframe = merge_informative_pair(
dataframe, inf,
self.timeframe, self.informative_timeframe,
ffill=True,
)
dataframe["ema_fast"] = ta.EMA(dataframe, timeperiod=12)
dataframe["ema_slow"] = ta.EMA(dataframe, timeperiod=26)
dataframe["cross_above"] = (
(dataframe["ema_fast"] > dataframe["ema_slow"])
& (dataframe["ema_fast"].shift(1) <= dataframe["ema_slow"].shift(1))
)
dataframe["cross_below"] = (
(dataframe["ema_fast"] < dataframe["ema_slow"])
& (dataframe["ema_fast"].shift(1) >= dataframe["ema_slow"].shift(1))
)
dataframe["ema_200"] = ta.EMA(dataframe, timeperiod=200)
return dataframe
def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
conditions = [
dataframe["htf_bull_4h"] == 1,
dataframe["close"] > dataframe["ema_200"],
dataframe["cross_above"] == True,
]
dataframe.loc[reduce(lambda a, b: a & b, conditions), "enter_long"] = 1
return dataframe
def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
conditions = [
dataframe["cross_below"] == True,
]
dataframe.loc[reduce(lambda a, b: a | b, conditions), "exit_long"] = 1
return dataframe