This article describes a professional trend-following trading strategy implemented in Backtrader that uses the Vortex Indicator to identify trend signals, filtered by a long-term moving average and a volatility condition. The strategy employs ATR-based trailing stops to manage risk and capture profits during sustained trends.
The Vortex Trend Capture Trading Strategy integrates the following components:
Below is the complete Backtrader code for the strategy:
import backtrader as bt
class VortexTrendCaptureStrategy(bt.Strategy):
"""
A professional trend-following system that uses the Vortex Indicator for entry
signals, filtered by a long-term MA and a volatility condition.
"""
= (
params # Vortex Indicator
'vortex_period', 30),
(# Macro Trend Filter
'long_term_ma_period', 30),
(# Volatility Filter
'atr_period', 7),
('atr_threshold', 0.05), # Max ATR as % of price to allow trades
(# Risk Management
'atr_stop_multiplier', 3.0),
(
)
def __init__(self):
self.order = None
# --- Indicators ---
self.vortex = bt.indicators.Vortex(self.data, period=self.p.vortex_period)
self.long_term_ma = bt.indicators.SimpleMovingAverage(self.data, period=self.p.long_term_ma_period)
self.atr = bt.indicators.AverageTrueRange(self.data, period=self.p.atr_period)
# Crossover for the Vortex signal
self.vortex_cross = bt.indicators.CrossOver(self.vortex.lines.vi_plus, self.vortex.lines.vi_minus)
# --- Trailing Stop State ---
self.stop_price = None
self.highest_price_since_entry = None
self.lowest_price_since_entry = None
def notify_order(self, order):
if order.status in [order.Submitted, order.Accepted]:
return
if order.status in [order.Completed]:
if self.position and self.stop_price is None:
if order.isbuy():
self.highest_price_since_entry = self.data.high[0]
self.stop_price = self.highest_price_since_entry - (self.atr[0] * self.p.atr_stop_multiplier)
elif order.issell():
self.lowest_price_since_entry = self.data.low[0]
self.stop_price = self.lowest_price_since_entry + (self.atr[0] * self.p.atr_stop_multiplier)
elif not self.position:
self.stop_price = None
self.highest_price_since_entry = None
self.lowest_price_since_entry = None
self.order = None
def next(self):
if self.order:
return
if not self.position:
# --- Filter Conditions ---
# 1. Is market volatility stable?
= (self.atr[0] / self.data.close[0]) < self.p.atr_threshold
is_stable # 2. Is price aligned with the macro trend?
= self.data.close[0] > self.long_term_ma[0]
is_macro_uptrend = self.data.close[0] < self.long_term_ma[0]
is_macro_downtrend # 3. Has a Vortex crossover signal occurred?
= self.vortex_cross[0] > 0
is_buy_signal = self.vortex_cross[0] < 0
is_sell_signal
# --- Entry Logic ---
if is_stable and is_macro_uptrend and is_buy_signal:
self.order = self.buy()
elif is_stable and is_macro_downtrend and is_sell_signal:
self.order = self.sell()
elif self.position:
# --- Manual ATR Trailing Stop Logic ---
if self.position.size > 0: # Long
self.highest_price_since_entry = max(self.highest_price_since_entry, self.data.high[0])
= self.highest_price_since_entry - (self.atr[0] * self.p.atr_stop_multiplier)
new_stop self.stop_price = max(self.stop_price, new_stop)
if self.data.close[0] < self.stop_price:
self.order = self.close()
elif self.position.size < 0: # Short
self.lowest_price_since_entry = min(self.lowest_price_since_entry, self.data.low[0])
= self.lowest_price_since_entry + (self.atr[0] * self.p.atr_stop_multiplier)
new_stop self.stop_price = min(self.stop_price, new_stop)
if self.data.close[0] > self.stop_price:
self.order = self.close()
The strategy uses the Vortex Indicator with trend and volatility filters to trade trend changes:
Indicators:
CrossOver
indicator to detect when VI+ crosses above (buy
signal) or below (sell signal) VI-.Trading Logic (next
):
Order Management
(notify_order
):
vortex_period
, long_term_ma_period
,
atr_period
, atr_threshold
, or
atr_stop_multiplier
to optimize for specific assets or
market conditions.This strategy is designed for trending markets where the Vortex Indicator can effectively capture directional moves, suitable for assets like forex, stocks, or cryptocurrencies, and can be backtested to evaluate its effectiveness across various timeframes and assets.