Indicators¶
Indicators calculate derived values from price data. Backtrader provides 100+ built-in indicators and supports TA-Lib integration.
小技巧
Always declare indicators in __init__ for best performance. This allows
vectorized calculation before next() is called.
Indicator Sources¶
Backtrader supports three types of indicators:
Built-in indicators: bt.indicators
TA-Lib indicators: bt.talib
Custom indicators: User-defined
警告
When using TA-Lib indicators, always verify the results match your expectations. Some TA-Lib calculations may differ from Backtrader's built-in versions.
Using Built-in Indicators¶
class MyStrategy(bt.Strategy):
def __init__(self):
# Moving averages
self.sma = bt.indicators.SMA(self.data.close, period=20)
self.ema = bt.indicators.EMA(self.data.close, period=20)
# Momentum
self.rsi = bt.indicators.RSI(self.data.close, period=14)
self.macd = bt.indicators.MACD(self.data.close)
# Volatility
self.atr = bt.indicators.ATR(self.data, period=14)
self.bbands = bt.indicators.BollingerBands(self.data.close)
# Crossovers
self.crossover = bt.indicators.CrossOver(self.sma, self.ema)
Using TA-Lib Indicators¶
class MyStrategy(bt.Strategy):
def __init__(self):
# TA-Lib SMA (note: uses 'timeperiod' instead of 'period')
self.sma = bt.talib.SMA(self.data.close, timeperiod=20)
# TA-Lib MACD
self.macd = bt.talib.MACD(self.data.close)
# TA-Lib Bollinger Bands
self.bbands = bt.talib.BBANDS(self.data.close, timeperiod=20)
Multi-Data Indicators¶
For strategies with multiple data feeds, use dictionaries to store indicators:
class MultiDataStrategy(bt.Strategy):
params = (('period', 20),)
def __init__(self):
# Store indicators for each data feed
self.sma_dict = {
data._name: bt.indicators.SMA(data.close, period=self.p.period)
for data in self.datas
}
def next(self):
for data in self.datas:
sma = self.sma_dict[data._name]
if data.close[0] > sma[0]:
self.buy(data=data)
Creating Custom Indicators¶
Simple Custom Indicator¶
class MyIndicator(bt.Indicator):
lines = ('signal',)
params = (('period', 20),)
def __init__(self):
self.addminperiod(self.p.period)
def next(self):
# Calculate value
values = self.data.close.get(size=self.p.period)
self.lines.signal[0] = sum(values) / self.p.period
Vectorized Indicator (Faster)¶
class MyFastIndicator(bt.Indicator):
lines = ('signal',)
params = (('period', 20),)
def __init__(self):
# Use built-in operations
self.lines.signal = bt.indicators.SMA(
self.data.close, period=self.p.period
)
Multi-Line Indicator¶
class MyBands(bt.Indicator):
lines = ('mid', 'top', 'bot')
params = (('period', 20), ('devfactor', 2.0))
def __init__(self):
self.lines.mid = bt.indicators.SMA(
self.data.close, period=self.p.period
)
stddev = bt.indicators.StdDev(
self.data.close, period=self.p.period
)
self.lines.top = self.lines.mid + self.p.devfactor * stddev
self.lines.bot = self.lines.mid - self.p.devfactor * stddev
Indicator Operations¶
# Arithmetic operations
diff = self.data.close - self.sma
ratio = self.data.close / self.sma
# Logical operations
above = self.data.close > self.sma
below = self.data.close < self.sma
# Combine indicators
combined = bt.And(
self.data.close > self.sma,
self.rsi < 30
)
Plotting Indicators¶
class MyIndicator(bt.Indicator):
lines = ('signal',)
plotinfo = dict(
plot=True,
subplot=True, # Separate subplot (False = overlay on price)
plotname='My Signal',
plotlinevalues=True,
)
plotlines = dict(
signal=dict(
color='blue',
linewidth=1.0,
_plotskip=False,
),
)
Plotting Intermediate Variables¶
Regular indicator results plot automatically. Intermediate variables need explicit declaration:
from backtrader.indicators import LinePlotterIndicator
class MyStrategy(bt.Strategy):
def __init__(self):
sma = bt.indicators.SMA(self.data.close, period=20)
ema = bt.indicators.EMA(self.data.close, period=20)
# This intermediate variable won't plot by default
close_over_sma = self.data.close > sma
# Use LinePlotterIndicator to plot it
LinePlotterIndicator(close_over_sma, name='Close_over_SMA')
Controlling Plot Location¶
# Plot on price chart (subplot=False) or separate (subplot=True)
self.sma = bt.indicators.SMA(
self.data.close,
period=20,
subplot=False, # Overlay on price chart
plotname='SMA 20' # Custom name in legend
)
Best Practices¶
Declare in __init__: Indicators declared in
__init__are calculated vectorized (faster)Use built-in operations: Prefer
bt.indicators.SMAover manual loopsVerify TA-Lib results: Cross-check TA-Lib calculations with expected values
Use dictionaries for multi-data: Store indicators per data feed for easy access
See Also¶
Core Concepts - Lines data structure
Strategies - Using indicators in strategies