Lesson 26: Custom Strategy Development
β± Duration: 2.5 hours
π― Learning Objectives: Learn to write your own trading strategies from scratch
Course Overview
So far, we've been using pre-made strategies. But true advancement is the ability to develop your own strategies based on your trading ideas.
This lesson will teach you:
- Basic structure of Freqtrade strategies
- How to implement buy and sell logic
- How to add and use technical indicators
- Complete strategy development workflow
- Practical examples from simple to complex
Part 1: Strategy Basic Structure
1.1 Strategy Template
Create user_data/strategies/MyFirstStrategy.py:
from freqtrade.strategy import IStrategy
from pandas import DataFrame
import talib.abstract as ta
class MyFirstStrategy(IStrategy):
"""
My first custom strategy
"""
# Strategy basic information
INTERFACE_VERSION = 3
# Minimum ROI (optional, can be set high if strategy has its own sell logic)
minimal_roi = {
"0": 0.10, # 10% take profit
"30": 0.05, # 5% take profit after 30 minutes
"60": 0.03, # 3% take profit after 60 minutes
"120": 0.01 # 1% take profit after 120 minutes
}
# Stop loss
stoploss = -0.03 # -3%
# Trailing stop loss (optional)
trailing_stop = False
trailing_stop_positive = 0.01
trailing_stop_positive_offset = 0.02
# Timeframe
timeframe = '5m'
# Length of historical data to download at startup
startup_candle_count: int = 100
# Order types
order_types = {
'entry': 'limit',
'exit': 'limit',
'stoploss': 'market',
'stoploss_on_exchange': True
}
# Order timeout
order_time_in_force = {
'entry': 'GTC',
'exit': 'GTC'
}
def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
"""
Add technical indicators
This function is called every time new data arrives
"""
# Add indicators you need here
# dataframe['indicator_name'] = ta.INDICATOR(dataframe)
return dataframe
def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
"""
Define buy signals
"""
dataframe.loc[
(
# Add your buy conditions here
# (dataframe['indicator'] > threshold) &
(dataframe['volume'] > 0) # Ensure there is volume
),
'enter_long'] = 1
return dataframe
def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
"""
Define sell signals
"""
dataframe.loc[
(
# Add your sell conditions here
# (dataframe['indicator'] < threshold) &
(dataframe['volume'] > 0)
),
'exit_long'] = 1
return dataframe
1.2 Key Components Explanation
Required Parameters
# 1. Interface version (required)
INTERFACE_VERSION = 3
# 2. Timeframe (required)
timeframe = '5m' # Options: 1m, 3m, 5m, 15m, 30m, 1h, 2h, 4h, 1d
# 3. Stop loss (strongly recommended)
stoploss = -0.03 # -3%
Optional Parameters
# ROI (Return on Investment) configuration
minimal_roi = {
"0": 0.10, # Sell immediately at 10%
"30": 0.05, # After 30 minutes, sell at 5%
"60": 0.03, # After 60 minutes, sell at 3%
}
# Trailing stop loss
trailing_stop = True
trailing_stop_positive = 0.01 # Enable trailing stop after 1% profit
trailing_stop_positive_offset = 0.02 # Activate after 2% profit
trailing_only_offset_is_reached = True
# Historical data needed at startup
startup_candle_count = 100 # Load 100 historical candles
Three Core Functions
# 1. populate_indicators()
# Purpose: Calculate technical indicators
# Called when: When new candle data is received
# 2. populate_entry_trend()
# Purpose: Define buy conditions
# Called when: After indicator calculation
# 3. populate_exit_trend()
# Purpose: Define sell conditions
# Called when: After indicator calculation
Part 2: Practical Example - Simple Moving Average Strategy
2.1 Strategy Logic Design
Trading Idea:
- Use fast EMA (9) and slow EMA (21)
- Buy when fast EMA crosses above slow EMA (golden cross)
- Sell when fast EMA crosses below slow EMA (death cross)
- Use RSI to filter overbought/oversold zones
Specific Rules:
-
Buy conditions:
- EMA 9 crosses above EMA 21
- RSI > 30 (avoid oversold)
- Volume > average volume
-
Sell conditions:
- EMA 9 crosses below EMA 21
- Or RSI > 70 (overbought zone)
2.2 Complete Code Implementation
Create user_data/strategies/SimpleCrossStrategy.py:
from freqtrade.strategy import IStrategy
from pandas import DataFrame
import talib.abstract as ta
import freqtrade.vendor.qtpylib.indicators as qtpylib
class SimpleCrossStrategy(IStrategy):
"""
Simple moving average crossover strategy
EMA 9/21 golden cross/death cross + RSI filter
"""
INTERFACE_VERSION = 3
# ROI configuration (relatively conservative)
minimal_roi = {
"0": 0.15,
"30": 0.08,
"60": 0.05,
"120": 0.02
}
# Stop loss -3%
stoploss = -0.03
# Trailing stop loss
trailing_stop = True
trailing_stop_positive = 0.01
trailing_stop_positive_offset = 0.02
trailing_only_offset_is_reached = True
# Timeframe
timeframe = '5m'
# Load 50 candles at startup (enough to calculate EMA 21)
startup_candle_count: int = 50
# Order configuration
order_types = {
'entry': 'limit',
'exit': 'limit',
'stoploss': 'market',
'stoploss_on_exchange': True
}
def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
"""
Add technical indicators
"""
# 1. Calculate EMA
dataframe['ema_fast'] = ta.EMA(dataframe, timeperiod=9)
dataframe['ema_slow'] = ta.EMA(dataframe, timeperiod=21)
# 2. Calculate RSI
dataframe['rsi'] = ta.RSI(dataframe, timeperiod=14)
# 3. Calculate average volume
dataframe['volume_mean'] = dataframe['volume'].rolling(window=20).mean()
return dataframe
def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
"""
Buy signal: EMA golden cross + RSI filter
"""
dataframe.loc[
(
# Condition 1: Golden cross (fast line crosses above slow line)
(qtpylib.crossed_above(dataframe['ema_fast'], dataframe['ema_slow'])) &
# Condition 2: RSI not in oversold zone (avoid buying at bottom bounce)
(dataframe['rsi'] > 30) &
(dataframe['rsi'] < 70) &
# Condition 3: Volume confirmation
(dataframe['volume'] > dataframe['volume_mean']) &
# Ensure there is volume
(dataframe['volume'] > 0)
),
'enter_long'] = 1
return dataframe
def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
"""
Sell signal: EMA death cross or RSI overbought
"""
dataframe.loc[
(
(
# Condition 1: Death cross (fast line crosses below slow line)
(qtpylib.crossed_below(dataframe['ema_fast'], dataframe['ema_slow'])) |
# Or condition 2: RSI overbought
(dataframe['rsi'] > 70)
) &
# Ensure there is volume
(dataframe['volume'] > 0)
),
'exit_long'] = 1
return dataframe
2.3 Test Strategy
# 1. Download data (if not already)
freqtrade download-data -c config.json --days 30 --timeframe 5m
# 2. Backtest
freqtrade backtesting \
-c config.json \
--strategy SimpleCrossStrategy \
--timerange 20230101-20230131
# 3. View results
# Output similar to:
# =============== SUMMARY METRICS ===============
# | Metric | Value |
# |------------------------|---------------------|
# | Total Trades | 45 |
# | Win Rate | 55.6% |
# | Total Profit | 12.50 USDT (12.5%) |
# | Avg Profit | 0.28 USDT |
# | Best Trade | 2.50 USDT (2.5%) |
# | Worst Trade | -0.95 USDT (-0.95%) |
# | Max Drawdown | -3.2% |
Part 3: Common Technical Indicators
3.1 Trend Indicators
EMA (Exponential Moving Average)
# Fast EMA
dataframe['ema_fast'] = ta.EMA(dataframe, timeperiod=9)
# Slow EMA
dataframe['ema_slow'] = ta.EMA(dataframe, timeperiod=21)
# Buy: Golden cross
(qtpylib.crossed_above(dataframe['ema_fast'], dataframe['ema_slow']))
# Sell: Death cross
(qtpylib.crossed_below(dataframe['ema_fast'], dataframe['ema_slow']))
SMA (Simple Moving Average)
dataframe['sma_20'] = ta.SMA(dataframe, timeperiod=20)
dataframe['sma_50'] = ta.SMA(dataframe, timeperiod=50)
MACD (Moving Average Convergence Divergence)
macd = ta.MACD(dataframe, fastperiod=12, slowperiod=26, signalperiod=9)
dataframe['macd'] = macd['macd']
dataframe['macdsignal'] = macd['macdsignal']
dataframe['macdhist'] = macd['macdhist']
# Buy: MACD crosses above signal line
(qtpylib.crossed_above(dataframe['macd'], dataframe['macdsignal']))
# Sell: MACD crosses below signal line
(qtpylib.crossed_below(dataframe['macd'], dataframe['macdsignal']))
ADX (Average Directional Index)
dataframe['adx'] = ta.ADX(dataframe, timeperiod=14)
# Trend filter: ADX > 25 indicates clear trend
(dataframe['adx'] > 25)
3.2 Oscillator Indicators
RSI (Relative Strength Index)
dataframe['rsi'] = ta.RSI(dataframe, timeperiod=14)
# Oversold: RSI < 30
(dataframe['rsi'] < 30)
# Overbought: RSI > 70
(dataframe['rsi'] > 70)
# Neutral zone: 30 < RSI < 70
(dataframe['rsi'] > 30) & (dataframe['rsi'] < 70)
Stochastic (Stochastics)
stoch = ta.STOCH(dataframe)
dataframe['slowk'] = stoch['slowk']
dataframe['slowd'] = stoch['slowd']
# Oversold: Stoch < 20
(dataframe['slowk'] < 20)
# Overbought: Stoch > 80
(dataframe['slowk'] > 80)
# Golden cross
(qtpylib.crossed_above(dataframe['slowk'], dataframe['slowd']))
CCI (Commodity Channel Index)
dataframe['cci'] = ta.CCI(dataframe, timeperiod=20)
# Oversold: CCI < -100
(dataframe['cci'] < -100)
# Overbought: CCI > 100
(dataframe['cci'] > 100)
3.3 Volatility Indicators
Bollinger Bands
bollinger = qtpylib.bollinger_bands(dataframe['close'], window=20, stds=2)
dataframe['bb_lower'] = bollinger['lower']
dataframe['bb_middle'] = bollinger['mid']
dataframe['bb_upper'] = bollinger['upper']
# Buy: Price touches lower band
(dataframe['close'] < dataframe['bb_lower'])
# Sell: Price touches upper band
(dataframe['close'] > dataframe['bb_upper'])
# Calculate bandwidth (volatility)
dataframe['bb_width'] = (dataframe['bb_upper'] - dataframe['bb_lower']) / dataframe['bb_middle']
ATR (Average True Range)
dataframe['atr'] = ta.ATR(dataframe, timeperiod=14)
# Used for dynamic stop loss
# Stop loss = Current price - 2 Γ ATR
3.4 Volume Indicators
Volume
# Average volume
dataframe['volume_mean'] = dataframe['volume'].rolling(window=20).mean()
# Volume surge (> 1.5x average)
(dataframe['volume'] > dataframe['volume_mean'] * 1.5)
OBV (On-Balance Volume)
dataframe['obv'] = ta.OBV(dataframe)
# OBV uptrend
dataframe['obv_ema'] = ta.EMA(dataframe['obv'], timeperiod=20)
(dataframe['obv'] > dataframe['obv_ema'])
Part 4: Advanced Practice - RSI Mean Reversion Strategy
4.1 Strategy Logic
Trading Idea:
- RSI mean reversion: Price returns to mean after excessive deviation
- Buy in oversold zone, wait for bounce
- Use Bollinger Bands for additional confirmation
Specific Rules:
-
Buy conditions:
- RSI < 30 (oversold)
- Price below Bollinger lower band
- Increased volume (confirmation)
-
Sell conditions:
- RSI > 50 (return to neutral)
- Or price touches Bollinger middle band
- Or reach take profit target
4.2 Complete Code
Create user_data/strategies/RSIMeanReversionStrategy.py:
from freqtrade.strategy import IStrategy
from pandas import DataFrame
import talib.abstract as ta
import freqtrade.vendor.qtpylib.indicators as qtpylib
class RSIMeanReversionStrategy(IStrategy):
"""
RSI mean reversion strategy
Buy in oversold zone, wait for price reversion
"""
INTERFACE_VERSION = 3
# ROI configuration (quick take profit)
minimal_roi = {
"0": 0.05, # 5% immediate take profit
"15": 0.03, # 3% after 15 minutes
"30": 0.02, # 2% after 30 minutes
"60": 0.01 # 1% after 60 minutes
}
# Stop loss
stoploss = -0.04 # -4% (slightly wider to give room for bounce)
# Timeframe
timeframe = '5m'
startup_candle_count: int = 50
# Custom parameters (optimizable)
buy_rsi_threshold = 30
sell_rsi_threshold = 50
volume_factor = 1.5
def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
"""
Add indicators
"""
# RSI
dataframe['rsi'] = ta.RSI(dataframe, timeperiod=14)
# Bollinger Bands
bollinger = qtpylib.bollinger_bands(dataframe['close'], window=20, stds=2)
dataframe['bb_lower'] = bollinger['lower']
dataframe['bb_middle'] = bollinger['mid']
dataframe['bb_upper'] = bollinger['upper']
# Volume
dataframe['volume_mean'] = dataframe['volume'].rolling(window=20).mean()
# EMA (auxiliary for trend judgment)
dataframe['ema_50'] = ta.EMA(dataframe, timeperiod=50)
return dataframe
def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
"""
Buy signal: Oversold + price below Bollinger lower band
"""
dataframe.loc[
(
# Condition 1: RSI oversold
(dataframe['rsi'] < self.buy_rsi_threshold) &
# Condition 2: Price below Bollinger lower band (excessive deviation)
(dataframe['close'] < dataframe['bb_lower']) &
# Condition 3: Volume increase (confirm real breakout)
(dataframe['volume'] > dataframe['volume_mean'] * self.volume_factor) &
# Condition 4: Price near or above EMA 50 (avoid downtrend)
(dataframe['close'] > dataframe['ema_50'] * 0.95) &
# Ensure there is volume
(dataframe['volume'] > 0)
),
'enter_long'] = 1
return dataframe
def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
"""
Sell signal: RSI returns to neutral zone or price touches middle band
"""
dataframe.loc[
(
(
# Condition 1: RSI returns above 50 (reversion complete)
(dataframe['rsi'] > self.sell_rsi_threshold) |
# Or condition 2: Price returns to Bollinger middle band
(dataframe['close'] > dataframe['bb_middle'])
) &
# Ensure there is volume
(dataframe['volume'] > 0)
),
'exit_long'] = 1
return dataframe
def custom_stoploss(self, pair: str, trade: 'Trade', current_time: 'datetime',
current_rate: float, current_profit: float, **kwargs) -> float:
"""
Custom stop loss: move stop loss after profit
"""
# If profit exceeds 2%, move stop loss to +1%
if current_profit > 0.02:
return 0.01
# Otherwise use default stop loss
return self.stoploss
4.3 Testing and Optimization
# Backtest
freqtrade backtesting \
-c config.json \
--strategy RSIMeanReversionStrategy \
--timerange 20230101-20230331
# Use Hyperopt to optimize parameters (will be detailed later)
freqtrade hyperopt \
-c config.json \
--strategy RSIMeanReversionStrategy \
--hyperopt-loss SharpeHyperOptLoss \
--epochs 100 \
--spaces buy sell
Part 5: Advanced Techniques
5.1 Custom Indicators
def custom_indicator(dataframe: DataFrame) -> DataFrame:
"""
Custom indicator example: calculate price momentum
"""
# Calculate N-period price change rate
dataframe['price_momentum'] = (
(dataframe['close'] - dataframe['close'].shift(10)) /
dataframe['close'].shift(10) * 100
)
return dataframe
# Call in populate_indicators
def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
dataframe = self.custom_indicator(dataframe)
return dataframe
5.2 Informative Pairs
Use longer timeframes for auxiliary decisions:
from freqtrade.strategy import informative
class MultiTimeframeStrategy(IStrategy):
@informative('1h')
def populate_indicators_1h(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
"""
Add 1-hour timeframe indicators
"""
dataframe['ema_50_1h'] = ta.EMA(dataframe, timeperiod=50)
dataframe['rsi_1h'] = ta.RSI(dataframe, timeperiod=14)
return dataframe
def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
# 5-minute indicators
dataframe['ema_20'] = ta.EMA(dataframe, timeperiod=20)
dataframe['rsi'] = ta.RSI(dataframe, timeperiod=14)
return dataframe
def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
dataframe.loc[
(
# 5-minute conditions
(dataframe['rsi'] < 30) &
# 1-hour conditions (confirm major uptrend)
(dataframe['close'] > dataframe['ema_50_1h']) &
(dataframe['rsi_1h'] > 40) &
(dataframe['volume'] > 0)
),
'enter_long'] = 1
return dataframe
5.3 Custom Stop Loss
def custom_stoploss(self, pair: str, trade: 'Trade', current_time: 'datetime',
current_rate: float, current_profit: float, **kwargs) -> float:
"""
Dynamic stop loss based on time and profit
"""
# Calculate holding time (minutes)
trade_duration = (current_time - trade.open_date_utc).total_seconds() / 60
# Phase 1 (0-30 minutes): -3% stop loss
if trade_duration < 30:
return -0.03
# Phase 2 (30-60 minutes): -2% stop loss
elif trade_duration < 60:
return -0.02
# Phase 3 (60+ minutes):
# If profit > 2%, move stop loss to breakeven
if current_profit > 0.02:
return 0.0
# Otherwise -1% stop loss
return -0.01
5.4 Custom Stake Amount
def custom_stake_amount(self, pair: str, current_time: 'datetime',
current_rate: float, proposed_stake: float,
min_stake: float, max_stake: float, **kwargs) -> float:
"""
Adjust position size based on market volatility
"""
dataframe, _ = self.dp.get_analyzed_dataframe(pair, self.timeframe)
last_candle = dataframe.iloc[-1].squeeze()
# Get ATR (volatility)
atr = last_candle['atr']
atr_percentage = (atr / last_candle['close']) * 100
# Reduce position in high volatility
if atr_percentage > 2.0:
return proposed_stake * 0.5 # 50% position
# Increase position in low volatility
elif atr_percentage < 1.0:
return proposed_stake * 1.5 # 150% position
# Normal volatility
return proposed_stake
Part 6: Strategy Development Workflow
6.1 Complete Development Process
1. Ideation Phase
β‘ Determine trading concept (trend following? mean reversion?)
β‘ Select timeframe
β‘ Choose indicators to use
β‘ Draw logic flowchart
2. Coding Phase
β‘ Create strategy file
β‘ Implement populate_indicators()
β‘ Implement populate_entry_trend()
β‘ Implement populate_exit_trend()
β‘ Add comments and explanations
3. Testing Phase
β‘ Syntax check: freqtrade test-strategy
β‘ Quick backtest: 30 days of data
β‘ Check if trade count is reasonable
β‘ Check if signals meet expectations
4. Optimization Phase
β‘ Use plot-dataframe to visualize signals
β‘ Analyze best/worst trades
β‘ Adjust parameters or logic
β‘ Backtest again to verify
5. Validation Phase
β‘ Complete backtest: 3-6 months of data
β‘ Out-of-sample testing
β‘ Different market environment testing
β‘ Compare with other strategies
6. Dry-run Phase
β‘ Run 1-2 weeks Dry-run
β‘ Verify real-time performance
β‘ Compare with backtest results
β‘ Confirm no technical issues
7. Live Phase
β‘ Start with small capital
β‘ Intensive monitoring
β‘ Continuous optimization
6.2 Strategy Evaluation Criteria
β
Characteristics of good strategies:
1. Clear Logic
- Simple and clear buy/sell conditions
- Has theoretical support
- Easy to understand and explain
2. Stable Backtest Performance
- Total return > 15% (3 months)
- Win rate > 50%
- Max drawdown < 20%
- Sharpe > 1.0
3. Reasonable Trading Frequency
- Not overtrading (>20 times/day)
- Not undertrading (<2 times/week)
- Average holding time is appropriate
4. Strong Adaptability
- Profitable in different market environments
- Not overly dependent on specific periods
- Not overfitted to historical data
5. Controlled Risk
- Has clear stop loss
- Controllable single trade risk
- Acceptable drawdown
β Characteristics of poor strategies:
1. Overly Complex
- Using too many indicators (>5)
- Conditions too complex
- Difficult to understand logic
2. Overfitted
- Perfect backtest but Dry-run fails
- Only effective in specific periods
- Too many parameter adjustments (>10 times)
3. Abnormal Trading Frequency
- Dozens of trades per day (fees erode profits)
- Or almost no trades (low capital utilization)
4. Uncontrolled Risk
- No stop loss or stop loss too large
- Frequent large drawdowns
- Unreasonable risk-reward ratio
5. Unstable
- Performance fluctuates greatly
- Frequent consecutive losses
- Unable to sustain profits
6.3 Common Errors
Error 1: Using Future Data (Look-ahead Bias)
β Wrong example:
dataframe['future_high'] = dataframe['high'].shift(-1)
if dataframe['close'] < dataframe['future_high']:
enter_long = 1
Problem: Uses future data, perfect backtest but fails in live trading
β
Correct approach:
Only use current and historical data for decisions
Error 2: Over-optimization
β Wrong example:
Adjust parameters 50 times to find configuration with 200% backtest return
Problem: Overfitted to historical data, inevitable failure in live trading
β
Correct approach:
- Parameter adjustments < 5 times
- Use out-of-sample testing
- Keep strategy simple
Error 3: Ignoring Fees and Slippage
β Wrong example:
High-frequency strategy, 50 trades per day
Backtest doesn't consider fees
Problem: Live trading fees erode all profits
β
Correct approach:
- Set real fees in config.json
- "fee": 0.001 # 0.1%
- Consider slippage impact
Error 4: Signal Repainting
β Wrong example:
Use unstable indicators where historical signals change
Problem: Backtest signals don't match live trading signals
β
Correct approach:
- Use stable indicators (EMA, SMA, RSI)
- Avoid repainting indicators
- Carefully test signal stability
π Practical Tasks
Task 1: Implement Simple Strategy
Based on the SimpleCrossStrategy in this lesson, implement and test:
# 1. Create strategy file
# 2. Backtest 3 months of data
# 3. Generate charts to analyze signals
freqtrade plot-dataframe \
-c config.json \
--strategy SimpleCrossStrategy \
--pairs BTC/USDT \
--indicators1 ema_fast ema_slow \
--indicators2 rsi
Task 2: Modify Strategy
Modify SimpleCrossStrategy, try:
- Change EMA periods (9/21 β 12/26)
- Add MACD as additional confirmation
- Add ADX trend filter
- Compare backtest results before and after modification
Task 3: Develop Your Own Strategy
Based on your trading ideas, develop a completely original strategy:
- Write down strategy logic (text description)
- Choose 2-3 core indicators
- Implement code
- Backtest and analyze results
- Optimize at least 3 times
Task 4: Strategy Comparison
Compare the performance of the following three strategies in the same period:
- SimpleCrossStrategy
- RSIMeanReversionStrategy
- Your own developed strategy
Create comparison table:
| Metric | Strategy 1 | Strategy 2 | Strategy 3 |
|---|---|---|---|
| Total Return | |||
| Win Rate | |||
| Max Drawdown | |||
| Trade Count | |||
| Best Market Environment |
π Key Points
Three Elements of Strategy Development
1. Clear Logic
- Can explain strategy in one sentence
- Has theoretical support
- Simple > Complex
2. Backtest Verification
- At least 3 months of data
- Out-of-sample testing
- Different market environments
3. Live Verification
- Dry-run 1-2 weeks
- Small capital testing
- Continuous monitoring and improvement
Common Indicator Combinations
Trend Following Strategies:
- EMA/SMA crossover
- MACD
- ADX (filter)
Mean Reversion Strategies:
- RSI
- Bollinger Bands
- Volume
Breakout Strategies:
- Price highs/lows
- Volume increase
- ATR (volatility)
Pitfalls to Avoid
1. Over-optimization
2. Using future data
3. Ignoring fees
4. Strategy too complex
5. Lack of risk management
π― Next Lesson Preview
Lesson 27: Multi-Timeframe Strategies
In the next lesson, we will learn:
- How to combine multiple timeframes
- Major timeframe confirmation, minor timeframe entry
- Improve signal quality
- Practical examples
Multi-timeframe is an important technique to improve strategy stability. See you in the next lesson!
π Learning Suggestions:
- Start Simple: Don't pursue complex strategies from the beginning
- Understand Principles: Know the meaning and usage of each indicator
- Experiment More: Try different parameters and combinations
- Record and Summarize: Record each modification and its effects
- Be Patient: Good strategies require repeated polishing
Remember: Simple and effective > complex and fancy. The best strategies are often the simplest strategies.
Top comments (0)