Estrategia Intraday Beta
Esta estrategia busca puntos de giro intradía utilizando pendientes de medias móviles suavizadas y el Índice de Fuerza Relativa (RSI). Se abre una posición larga cuando la pendiente de la media móvil de 10 períodos gira al alza tras un movimiento bajista, el RSI está por debajo de 70 y la vela anterior es alcista. Se abre una posición corta cuando la pendiente gira a la baja tras un movimiento alcista, el RSI está por encima de 30 y la vela anterior es bajista.
Un filtro de Average True Range (ATR) bloquea nuevas entradas cuando la volatilidad es demasiado alta. Las posiciones abiertas están protegidas por un stop trailing adaptativo que se mueve a favor de la operación y sale cuando el precio cruza el nivel del stop.
Parámetros
- RSI Period – período del indicador RSI.
- Trailing Stop – distancia del stop trailing en unidades de precio.
- ATR Threshold – valor máximo de ATR permitido para operar.
- Candle Type – marco temporal de las velas utilizadas para el análisis.
using System;
using System.Collections.Generic;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Intraday strategy based on SMA slope changes and RSI with ATR trailing stop.
/// </summary>
public class IntradayBetaStrategy : Strategy
{
private readonly StrategyParam<int> _rsiPeriod;
private readonly StrategyParam<int> _atrPeriod;
private readonly StrategyParam<DataType> _candleType;
private decimal _prevMa10;
private decimal _prevSlope;
private decimal _prevCandleDiff;
private decimal _longStop;
private decimal _shortStop;
private decimal _entryPrice;
public int RsiPeriod { get => _rsiPeriod.Value; set => _rsiPeriod.Value = value; }
public int AtrPeriod { get => _atrPeriod.Value; set => _atrPeriod.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public IntradayBetaStrategy()
{
_rsiPeriod = Param(nameof(RsiPeriod), 9)
.SetGreaterThanZero()
.SetDisplay("RSI Period", "RSI period", "Indicators");
_atrPeriod = Param(nameof(AtrPeriod), 14)
.SetGreaterThanZero()
.SetDisplay("ATR Period", "ATR period for trailing", "Indicators");
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Type of candles", "General");
}
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
=> [(Security, CandleType)];
protected override void OnReseted()
{
base.OnReseted();
_prevMa10 = 0; _prevSlope = 0; _prevCandleDiff = 0;
_longStop = 0; _shortStop = 0; _entryPrice = 0;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var ma10 = new SimpleMovingAverage { Length = 10 };
var rsi = new RelativeStrengthIndex { Length = RsiPeriod };
var atr = new StandardDeviation { Length = AtrPeriod };
SubscribeCandles(CandleType).Bind(ma10, rsi, atr, ProcessCandle).Start();
}
private void ProcessCandle(ICandleMessage candle, decimal ma10Value, decimal rsiValue, decimal atrValue)
{
if (candle.State != CandleStates.Finished) return;
if (_prevMa10 == 0) { _prevMa10 = ma10Value; return; }
var ma10Slope = ma10Value - _prevMa10;
var candleDiff = candle.ClosePrice - candle.OpenPrice;
var trailDist = atrValue > 0 ? atrValue * 2 : 100;
var sellSignal = ma10Slope < 0 && _prevSlope > 0 && rsiValue >= 30 && _prevCandleDiff < 0;
var buySignal = ma10Slope > 0 && _prevSlope < 0 && rsiValue <= 70 && _prevCandleDiff > 0;
if (sellSignal && Position >= 0)
{
if (Position > 0) SellMarket();
SellMarket();
_entryPrice = candle.ClosePrice;
_shortStop = _entryPrice + trailDist;
}
else if (buySignal && Position <= 0)
{
if (Position < 0) BuyMarket();
BuyMarket();
_entryPrice = candle.ClosePrice;
_longStop = _entryPrice - trailDist;
}
if (Position > 0)
{
var newStop = candle.ClosePrice - trailDist;
if (newStop > _longStop && candle.ClosePrice > _entryPrice)
_longStop = newStop;
if (candle.LowPrice <= _longStop) SellMarket();
}
else if (Position < 0)
{
var newStop = candle.ClosePrice + trailDist;
if (newStop < _shortStop && candle.ClosePrice < _entryPrice)
_shortStop = newStop;
if (candle.HighPrice >= _shortStop) BuyMarket();
}
_prevMa10 = ma10Value;
_prevSlope = ma10Slope;
_prevCandleDiff = candleDiff;
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
from System import TimeSpan
from StockSharp.Messages import DataType, CandleStates
from StockSharp.Algo.Indicators import RelativeStrengthIndex, SimpleMovingAverage, StandardDeviation
from StockSharp.Algo.Strategies import Strategy
class intraday_beta_strategy(Strategy):
def __init__(self):
super(intraday_beta_strategy, self).__init__()
self._rsi_period = self.Param("RsiPeriod", 9) \
.SetDisplay("RSI Period", "RSI period", "Indicators")
self._atr_period = self.Param("AtrPeriod", 14) \
.SetDisplay("ATR Period", "ATR period for trailing", "Indicators")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Type of candles", "General")
self._prev_ma10 = 0.0
self._prev_slope = 0.0
self._prev_candle_diff = 0.0
self._long_stop = 0.0
self._short_stop = 0.0
self._entry_price = 0.0
@property
def rsi_period(self):
return self._rsi_period.Value
@property
def atr_period(self):
return self._atr_period.Value
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(intraday_beta_strategy, self).OnReseted()
self._prev_ma10 = 0.0
self._prev_slope = 0.0
self._prev_candle_diff = 0.0
self._long_stop = 0.0
self._short_stop = 0.0
self._entry_price = 0.0
def OnStarted2(self, time):
super(intraday_beta_strategy, self).OnStarted2(time)
ma10 = SimpleMovingAverage()
ma10.Length = 10
rsi = RelativeStrengthIndex()
rsi.Length = self.rsi_period
atr = StandardDeviation()
atr.Length = self.atr_period
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(ma10, rsi, atr, self.on_process).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawOwnTrades(area)
def on_process(self, candle, ma10_value, rsi_value, atr_value):
if candle.State != CandleStates.Finished:
return
if self._prev_ma10 == 0:
self._prev_ma10 = ma10_value
return
ma10_slope = ma10_value - self._prev_ma10
candle_diff = candle.ClosePrice - candle.OpenPrice
trail_dist = atr_value * 2 if atr_value > 0 else 100
sell_signal = ma10_slope < 0 and self._prev_slope > 0 and rsi_value >= 30 and self._prev_candle_diff < 0
buy_signal = ma10_slope > 0 and self._prev_slope < 0 and rsi_value <= 70 and self._prev_candle_diff > 0
if sell_signal and self.Position >= 0:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
self._entry_price = candle.ClosePrice
self._short_stop = self._entry_price + trail_dist
elif buy_signal and self.Position <= 0:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
self._entry_price = candle.ClosePrice
self._long_stop = self._entry_price - trail_dist
if self.Position > 0:
new_stop = candle.ClosePrice - trail_dist
if new_stop > self._long_stop and candle.ClosePrice > self._entry_price:
self._long_stop = new_stop
if candle.LowPrice <= self._long_stop:
self.SellMarket()
elif self.Position < 0:
new_stop = candle.ClosePrice + trail_dist
if new_stop < self._short_stop and candle.ClosePrice < self._entry_price:
self._short_stop = new_stop
if candle.HighPrice >= self._short_stop:
self.BuyMarket()
self._prev_ma10 = ma10_value
self._prev_slope = ma10_slope
self._prev_candle_diff = candle_diff
def CreateClone(self):
return intraday_beta_strategy()