跳到主要内容

Freqtrade Strategies 101: A Quick Start for Strategy Development

For the purposes of this quick start, we are assuming you are familiar with the basics of trading, and have read the Bot Basics page.

Core Concepts

Trading Terminology

  • Assets/Pairs: Represent the coin you're trading and the stake currency (e.g., BTC/USDT)
  • Candles: OHLCV data (Open, High, Low, Close, Volume) for specific time periods
  • Indicators: Technical analysis values calculated from candle data
  • Signals: Entry/exit conditions based on indicator analysis
  • Orders/Trades: Actual buy/sell transactions on the exchange

Long vs Short Trading

  • Long: Buy low, sell high - profit when price increases
  • Short: Borrow and sell high, buy back low - profit when price decreases
Focus on Spot Trading

This guide focuses on spot (long) trading for simplicity, though Freqtrade supports both spot and futures markets.

Strategy Structure

Main Components

A Freqtrade strategy consists of three main functions:

  1. populate_indicators() - Calculate technical indicators
  2. populate_entry_trend() - Define entry conditions
  3. populate_exit_trend() - Define exit conditions

Dataframe Structure

Each trading pair has its own dataframe with:

  • Index: Date/time (e.g., 2024-06-31 12:00)
  • Columns: OHLCV data plus custom indicators
  • Signals: Entry/exit columns with 1/0 values

Basic Strategy Example

Here's a simple RSI-based strategy:

from freqtrade.strategy import IStrategy
from pandas import DataFrame
import talib.abstract as ta

class MyFirstStrategy(IStrategy):

# Strategy settings
timeframe = '15m'
stoploss = -0.10 # 10% stop loss
minimal_roi = {"0": 0.01} # 1% minimum profit

def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
"""Calculate technical indicators"""
# RSI (Relative Strength Index)
dataframe['rsi'] = ta.RSI(dataframe, timeperiod=14)

# Moving averages
dataframe['sma_20'] = ta.SMA(dataframe, timeperiod=20)
dataframe['sma_50'] = ta.SMA(dataframe, timeperiod=50)

return dataframe

def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
"""Define entry conditions"""
dataframe.loc[
(
(dataframe['rsi'] < 30) & # Oversold condition
(dataframe['sma_20'] > dataframe['sma_50']) # Upward trend
),
'enter_long'
] = 1

return dataframe

def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
"""Define exit conditions"""
dataframe.loc[
(dataframe['rsi'] > 70), # Overbought condition
'exit_long'
] = 1

return dataframe

Strategy Configuration

Essential Parameters

class MyStrategy(IStrategy):
# Timeframe for analysis
timeframe = '5m' # 1m, 5m, 15m, 1h, 4h, 1d

# Risk management
stoploss = -0.05 # 5% stop loss

# Profit targets
minimal_roi = {
"0": 0.10, # 10% profit immediately
"40": 0.05, # 5% profit after 40 minutes
"100": 0.02, # 2% profit after 100 minutes
"180": 0.01 # 1% profit after 180 minutes
}

# Optional: Trailing stop
trailing_stop = True
trailing_stop_positive = 0.01
trailing_stop_positive_offset = 0.02

Common Indicators

Trend Indicators

# Moving Averages
dataframe['sma_20'] = ta.SMA(dataframe, timeperiod=20)
dataframe['ema_12'] = ta.EMA(dataframe, timeperiod=12)

# MACD
macd = ta.MACD(dataframe)
dataframe['macd'] = macd['macd']
dataframe['macdsignal'] = macd['macdsignal']
dataframe['macdhist'] = macd['macdhist']

Momentum Indicators

# RSI
dataframe['rsi'] = ta.RSI(dataframe, timeperiod=14)

# Stochastic
stoch = ta.STOCH(dataframe)
dataframe['slowk'] = stoch['slowk']
dataframe['slowd'] = stoch['slowd']

# Williams %R
dataframe['willr'] = ta.WILLR(dataframe, timeperiod=14)

Volatility Indicators

# Bollinger Bands
bollinger = ta.BBANDS(dataframe, timeperiod=20)
dataframe['bb_lower'] = bollinger['lowerband']
dataframe['bb_middle'] = bollinger['middleband']
dataframe['bb_upper'] = bollinger['upperband']

# Average True Range
dataframe['atr'] = ta.ATR(dataframe, timeperiod=14)

Entry and Exit Logic

Complex Entry Conditions

def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
dataframe.loc[
(
# Trend conditions
(dataframe['ema_12'] > dataframe['ema_26']) &
(dataframe['close'] > dataframe['sma_50']) &

# Momentum conditions
(dataframe['rsi'] > 30) & (dataframe['rsi'] < 70) &

# Volume condition
(dataframe['volume'] > dataframe['volume'].rolling(20).mean()) &

# Price action
(dataframe['close'] > dataframe['open']) # Green candle
),
'enter_long'
] = 1

return dataframe

Multiple Exit Strategies

def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
# Exit on overbought RSI
dataframe.loc[
(dataframe['rsi'] > 80),
'exit_long'
] = 1

# Exit on bearish MACD crossover
dataframe.loc[
(
(dataframe['macd'] < dataframe['macdsignal']) &
(dataframe['macd'].shift(1) >= dataframe['macdsignal'].shift(1))
),
'exit_long'
] = 1

return dataframe

Testing Your Strategy

Backtesting

Test your strategy with historical data:

# Basic backtest
freqtrade backtesting --strategy MyFirstStrategy

# Backtest with specific timerange
freqtrade backtesting \
--strategy MyFirstStrategy \
--timerange 20230101-20230601

# Backtest with specific pairs
freqtrade backtesting \
--strategy MyFirstStrategy \
--pairs BTC/USDT ETH/USDT

Dry Run (Paper Trading)

Test with live data without real money:

# Enable dry run in config.json
{
"dry_run": true,
"strategy": "MyFirstStrategy"
}

# Start dry run
freqtrade trade --config config.json

Strategy Optimization

Hyperparameter Optimization

from freqtrade.optimize.space import Categorical, Dimension, Integer, SKDecimal

class OptimizedStrategy(IStrategy):

# Hyperopt parameters
buy_rsi = IntParameter(20, 40, default=30, space="buy")
sell_rsi = IntParameter(60, 80, default=70, space="sell")

def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
dataframe.loc[
(dataframe['rsi'] < self.buy_rsi.value),
'enter_long'
] = 1
return dataframe

def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
dataframe.loc[
(dataframe['rsi'] > self.sell_rsi.value),
'exit_long'
] = 1
return dataframe

Run optimization:

freqtrade hyperopt \
--strategy OptimizedStrategy \
--hyperopt-loss SharpeHyperOptLoss \
--epochs 100

Best Practices

Strategy Development

  1. Start Simple: Begin with basic indicators and logic
  2. Avoid Overfitting: Don't optimize for past data only
  3. Test Thoroughly: Use both backtesting and dry runs
  4. Risk Management: Always include stop losses
  5. Documentation: Comment your code and logic

Common Mistakes

  • Look-ahead bias: Using future data in calculations
  • Overfitting: Too many conditions or parameters
  • Ignoring fees: Not accounting for trading costs
  • No risk management: Missing stop losses or position sizing
  • Unrealistic expectations: Expecting 100% win rates

Performance Metrics

Monitor these key metrics:

  • Total Return: Overall profit/loss
  • Sharpe Ratio: Risk-adjusted returns
  • Maximum Drawdown: Largest peak-to-trough decline
  • Win Rate: Percentage of profitable trades
  • Profit Factor: Ratio of gross profit to gross loss

Advanced Features

Custom Indicators

def custom_indicator(dataframe: DataFrame) -> DataFrame:
"""Custom indicator calculation"""
high_low = (dataframe['high'] - dataframe['low']).abs()
high_close = (dataframe['high'] - dataframe['close'].shift()).abs()
low_close = (dataframe['low'] - dataframe['close'].shift()).abs()

ranges = pd.concat([high_low, high_close, low_close], axis=1)
true_range = ranges.max(axis=1)

return true_range.rolling(14).mean()

Strategy Callbacks

def confirm_trade_entry(self, pair: str, order_type: str, amount: float,
rate: float, time_in_force: str, current_time: datetime,
entry_tag: Optional[str], side: str, **kwargs) -> bool:
"""Confirm trade entry"""
# Add custom logic to confirm or reject trades
return True

def confirm_trade_exit(self, pair: str, trade: Trade, order_type: str,
amount: float, rate: float, time_in_force: str,
exit_reason: str, current_time: datetime, **kwargs) -> bool:
"""Confirm trade exit"""
# Add custom logic to confirm or reject exits
return True

Next Steps

  1. Strategy Customization - Advanced strategy features
  2. Backtesting - Comprehensive testing guide
  3. Hyperopt - Parameter optimization
  4. Strategy Callbacks - Advanced control mechanisms

Resources

Risk Disclaimer

Always test strategies thoroughly before using real money. Past performance doesn't guarantee future results. Only invest what you can afford to lose.