💬 Forum

MultiTFStrategy

🏆 League #1900 / 1922

jinzheng8115/freqtrade-crypto-system/user_data/strategies/MultiTFStrategy.py · first seen 2026-07-16 · repo updated 2026-02-23 · ⬇ 1 download

Basics mode: spot timeframe: 15m interface version: 3 1h
Settings stoploss: -0.05 has minimal roi trailing startup candle count: 200 hyperopt hyperopt params: 2
Indicators ADX EMA RSI talib
Concepts trailing
15 related strategies ( identical code, similar name)

Each tile is a different kind of check — from an instant code lint to full sandboxed backtests and forward tests on recent data. Not sure what a check actually proves? See the FAQ →

Source

Download Raw
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
# 多时间框架策略
# 原理:用更高时间框架确认趋势,低时间框架入场
# 适合:趋势市场,减少假信号
from freqtrade.strategy import IStrategy, IntParameter
from pandas import DataFrame
import talib.abstract as ta
from functools import reduce

class MultiTFStrategy(IStrategy):
    INTERFACE_VERSION = 3
    
    # 参数
    ema_fast = IntParameter(5, 15, default=9, space="buy", optimize=True)
    ema_slow = IntParameter(20, 40, default=21, space="buy", optimize=True)
    
    minimal_roi = {"0": 0.10}
    stoploss = -0.05
    
    timeframe = '15m'
    
    trailing_stop = True
    trailing_stop_positive = 0.03
    trailing_stop_positive_offset = 0.04
    
    startup_candle_count = 200
    
    order_types = {
        'entry': 'limit',
        'exit': 'limit',
        'stoploss': 'market',
        'stoploss_on_exchange': False
    }
    
    def informative_pairs(self):
        # 1小时时间框架用于趋势确认
        return [
            ("BTC/USDT", "1h"),
            ("ETH/USDT", "1h"),
            ("SOL/USDT", "1h"),
            ("DOGE/USDT", "1h"),
        ]
    
    def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        # 15m 指标
        dataframe['ema_fast'] = ta.EMA(dataframe, timeperiod=self.ema_fast.value)
        dataframe['ema_slow'] = ta.EMA(dataframe, timeperiod=self.ema_slow.value)
        dataframe['rsi'] = ta.RSI(dataframe, timeperiod=14)
        dataframe['adx'] = ta.ADX(dataframe, timeperiod=14)
        dataframe['volume_ma'] = dataframe['volume'].rolling(20).mean()
        
        return dataframe
    
    def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        dataframe.loc[:, 'enter_long'] = 0
        
        # 获取 1h 数据
        informative = self.dp.get_pair_dataframe(pair=metadata['pair'], timeframe='1h')
        
        if informative is not None and len(informative) > 0:
            # 1h 趋势
            informative['ema_50'] = ta.EMA(informative, timeperiod=50)
            informative['ema_200'] = ta.EMA(informative, timeperiod=200)
            last_1h = informative.iloc[-1]
            trend_up = last_1h['ema_50'] > last_1h['ema_200']
        else:
            trend_up = True  # 默认允许
        
        conditions = [
            # 15m EMA 多头
            dataframe['ema_fast'] > dataframe['ema_slow'],
            # RSI 不超买
            dataframe['rsi'] < 70,
            # ADX 有趋势
            dataframe['adx'] > 20,
            # 成交量
            dataframe['volume'] > dataframe['volume_ma'],
        ]
        
        if conditions and trend_up:
            dataframe.loc[reduce(lambda x, y: x & y, conditions), 'enter_long'] = 1
        
        return dataframe
    
    def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        dataframe.loc[:, 'exit_long'] = 0
        
        conditions = [
            # EMA 死叉
            dataframe['ema_fast'] < dataframe['ema_slow'],
        ]
        
        if conditions:
            dataframe.loc[reduce(lambda x, y: x & y, conditions), 'exit_long'] = 1
        
        return dataframe