ATR Volatility Filter, RSI Entries, and Trailing Stops on 15-Minute Bars
Summary
This event-driven trading strategy builds 15-minute bars from incoming market data and calculates ATR and RSI. It only considers entries when current ATR is above the recent average of ATR values, using that condition as a volatility filter. RSI thresholds around its midpoint then trigger a long or short order, with the order price set slightly above or below the bar close. Position size is fixed by a configurable quantity.
Once a position is open, the strategy tracks the most favorable price reached and places a trailing stop at a configurable percentage distance. The code cancels outstanding orders on each new bar and refreshes the stop as the trade evolves. The document contains implementation code but no backtest setup, performance evidence, or discussion of market-specific behavior. It also does not specify a separate profit target or show how slippage and order fills affect the strategy, so profitability and execution behavior cannot be inferred from the source alone.
Key ideas
- The strategy aggregates incoming data into 15-minute bars before calculating signals.
- Entries require ATR to exceed its recent average and RSI to cross a threshold around the midpoint.
- Entry orders are placed at prices offset from the signal bar's close.
- Open positions use a percentage-based trailing stop that follows favorable price movement.
- The source provides no results to establish performance or execution quality.
Tags
Full text
# AtrRsi15MinStrategy
# AtrRsi15MinStrategy
## Source (MIT)
```python
from howtrader.app.cta_strategy import (
CtaTemplate,
StopOrder
)
from howtrader.trader.object import TickData, BarData, TradeData, OrderData
from howtrader.trader.utility import BarGenerator, ArrayManager
from decimal import Decimal
class AtrRsi15MinStrategy(CtaTemplate):
""""""
author = "51bitquant"
atr_length = 22
atr_ma_length = 10
rsi_length = 5
rsi_entry = 16
trailing_percent = 0.8
fixed_size = 1
atr_value = 0
atr_ma = 0
rsi_value = 0
rsi_buy = 0
rsi_sell = 0
intra_trade_high = 0
intra_trade_low = 0
parameters = [
"atr_length",
"atr_ma_length",
"rsi_length",
"rsi_entry",
"trailing_percent",
"fixed_size"
]
variables = [
"atr_value",
"atr_ma",
"rsi_value",
"rsi_buy",
"rsi_sell",
"intra_trade_high",
"intra_trade_low"
]
def __init__(self, cta_engine, strategy_name, vt_symbol, setting):
""""""
super().__init__(cta_engine, strategy_name, vt_symbol, setting)
self.bg = BarGenerator(self.on_bar, 15, self.on_15min_bar)
self.am = ArrayManager()
def on_init(self):
"""
Callback when strategy is inited.
"""
self.write_log("策略初始化")
self.rsi_buy = 50 + self.rsi_entry
self.rsi_sell = 50 - self.rsi_entry
self.load_bar(10)
def on_start(self):
"""
Callback when strategy is started.
"""
self.write_log("策略启动")
def on_stop(self):
"""
Callback when strategy is stopped.
"""
self.write_log("策略停止")
def on_tick(self, tick: TickData):
"""
Callback of new tick data update.
"""
self.bg.update_tick(tick)
def on_bar(self, bar: BarData):
"""
Callback of new bar data update.
"""
self.bg.update_bar(bar)
def on_15min_bar(self, bar: BarData):
self.cancel_all()
am = self.am
am.update_bar(bar)
if not am.inited:
return
atr_array = am.atr(self.atr_length, array=True)
self.atr_value = atr_array[-1]
self.atr_ma = atr_array[-self.atr_ma_length:].mean()
self.rsi_value = am.rsi(self.rsi_length)
if self.pos == 0:
self.intra_trade_high = bar.high_price
self.intra_trade_low = bar.low_price
if self.atr_value > self.atr_ma:
if self.rsi_value > self.rsi_buy:
price = bar.close_price * 1.01
self.buy(Decimal(price), Decimal(self.fixed_size))
elif self.rsi_value < self.rsi_sell:
price = bar.close_price * 0.99
self.short(Decimal(price), Decimal(self.fixed_size))
elif self.pos > 0:
self.intra_trade_high = max(self.intra_trade_high, bar.high_price)
self.intra_trade_low = bar.low_price
long_stop = self.intra_trade_high * (1 - self.trailing_percent / 100)
self.sell(Decimal(long_stop), Decimal(abs(self.pos)), stop=True)
elif self.pos < 0:
self.intra_trade_low = min(self.intra_trade_low, bar.low_price)
self.intra_trade_high = bar.high_price
short_stop = self.intra_trade_low * (1 + self.trailing_percent / 100)
self.cover(Decimal(short_stop), Decimal(abs(self.pos)), stop=True)
self.put_event()
def on_order(self, order: OrderData):
"""
Callback of new order data update.
"""
pass
def on_trade(self, trade: TradeData):
"""
Callback of new trade data update.
"""
self.put_event()
def on_stop_order(self, stop_order: StopOrder):
"""
Callback of stop order update.
"""
pass
```Shown in full with attribution under the source's licence. Licence: MIT
This summary was written by Stratmill's research agent from the original; it is not a copy of the source.