Estrategia de Largo Post-Apertura con ATR Stop Loss y Take Profit
La estrategia entra en una posición larga durante la apertura del mercado tras un rompimiento de resistencia mientras el precio permanece cerca de la banda media de Bollinger. Utiliza filtros EMA, RSI, ADX y ATR, y sale mediante stop loss y take profit basados en ATR.
Detalles
- Criterios de entrada:
- Largo: Rompimiento por encima de la resistencia reciente durante la apertura del mercado, precio cerca de la banda media de Bollinger, RSI por encima del umbral, ADX por encima del umbral, tendencia de corto plazo alcista y sin retroceso.
- Largo/Corto: Solo largos.
- Criterios de salida:
- Stop loss o take profit basado en ATR alcanzado.
- Stops:
- Stop loss y take profit basados en ATR.
- Valores predeterminados:
BB Length= 14BB Mult= 1.5EMA Length= 10EMA Long Length= 200RSI Length= 7RSI Threshold= 30ADX Length= 7ADX Threshold= 10ATR Length= 14ATR SL Mult= 2.0ATR TP Mult= 4.0
- Filtros:
- Categoría: Seguimiento de tendencia
- Dirección: Long
- Indicadores: Bollinger Bands, EMA, RSI, ADX, ATR
- Stops: ATR
- Complejidad: Intermedio
- Marco temporal: Cualquiera
- Estacionalidad: No
- Redes neuronales: No
- Divergencia: No
- Nivel de riesgo: Medio
using System;
using System.Linq;
using System.Collections.Generic;
using Ecng.Common;
using Ecng.Collections;
using Ecng.Serialization;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Post open long strategy with ATR-based stop loss and take profit.
/// Enters long after breakout during market open with multiple filters.
/// </summary>
public class PostOpenLongAtrStopLossTakeProfitStrategy : Strategy
{
private readonly StrategyParam<int> _bbLength;
private readonly StrategyParam<decimal> _bbMult;
private readonly StrategyParam<int> _emaLength;
private readonly StrategyParam<int> _emaLongLength;
private readonly StrategyParam<int> _rsiLength;
private readonly StrategyParam<decimal> _rsiThreshold;
private readonly StrategyParam<int> _adxLength;
private readonly StrategyParam<decimal> _adxThreshold;
private readonly StrategyParam<int> _atrLength;
private readonly StrategyParam<decimal> _atrStopLossMultiplier;
private readonly StrategyParam<decimal> _atrTakeProfitMultiplier;
private readonly StrategyParam<DataType> _candleType;
public int BbLength { get => _bbLength.Value; set => _bbLength.Value = value; }
public decimal BbMult { get => _bbMult.Value; set => _bbMult.Value = value; }
public int EmaLength { get => _emaLength.Value; set => _emaLength.Value = value; }
public int EmaLongLength { get => _emaLongLength.Value; set => _emaLongLength.Value = value; }
public int RsiLength { get => _rsiLength.Value; set => _rsiLength.Value = value; }
public decimal RsiThreshold { get => _rsiThreshold.Value; set => _rsiThreshold.Value = value; }
public int AdxLength { get => _adxLength.Value; set => _adxLength.Value = value; }
public decimal AdxThreshold { get => _adxThreshold.Value; set => _adxThreshold.Value = value; }
public int AtrLength { get => _atrLength.Value; set => _atrLength.Value = value; }
public decimal AtrStopLossMultiplier { get => _atrStopLossMultiplier.Value; set => _atrStopLossMultiplier.Value = value; }
public decimal AtrTakeProfitMultiplier { get => _atrTakeProfitMultiplier.Value; set => _atrTakeProfitMultiplier.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public PostOpenLongAtrStopLossTakeProfitStrategy()
{
_bbLength = Param(nameof(BbLength), 14)
.SetGreaterThanZero()
.SetDisplay("BB Length", "Bollinger Bands length", "General")
;
_bbMult = Param(nameof(BbMult), 1.5m)
.SetGreaterThanZero()
.SetDisplay("BB Mult", "Bollinger Bands multiplier", "General")
;
_emaLength = Param(nameof(EmaLength), 10)
.SetGreaterThanZero()
.SetDisplay("EMA Length", "Short EMA length", "General")
;
_emaLongLength = Param(nameof(EmaLongLength), 40)
.SetGreaterThanZero()
.SetDisplay("EMA Long Length", "Long EMA length", "General")
;
_rsiLength = Param(nameof(RsiLength), 7)
.SetGreaterThanZero()
.SetDisplay("RSI Length", "RSI period", "General")
;
_rsiThreshold = Param(nameof(RsiThreshold), 30m)
.SetDisplay("RSI Threshold", "RSI minimum value", "General")
;
_adxLength = Param(nameof(AdxLength), 7)
.SetGreaterThanZero()
.SetDisplay("ADX Length", "ADX period", "General")
;
_adxThreshold = Param(nameof(AdxThreshold), 10m)
.SetDisplay("ADX Threshold", "ADX minimum value", "General")
;
_atrLength = Param(nameof(AtrLength), 14)
.SetGreaterThanZero()
.SetDisplay("ATR Length", "ATR period", "General")
;
_atrStopLossMultiplier = Param(nameof(AtrStopLossMultiplier), 2m)
.SetGreaterThanZero()
.SetDisplay("ATR SL Mult", "ATR stop-loss multiplier", "General")
;
_atrTakeProfitMultiplier = Param(nameof(AtrTakeProfitMultiplier), 4m)
.SetGreaterThanZero()
.SetDisplay("ATR TP Mult", "ATR take-profit multiplier", "General")
;
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame())
.SetDisplay("Candle Type", "Type of candles", "General");
}
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var fast = new ExponentialMovingAverage { Length = EmaLength };
var slow = new ExponentialMovingAverage { Length = EmaLongLength };
var prevF = 0m;
var prevS = 0m;
var init = false;
var lastSignal = DateTimeOffset.MinValue;
var cooldown = TimeSpan.FromMinutes(360);
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(fast, slow, (candle, f, s) =>
{
if (candle.State != CandleStates.Finished)
return;
if (!fast.IsFormed || !slow.IsFormed)
return;
if (!init)
{
prevF = f;
prevS = s;
init = true;
return;
}
if (candle.OpenTime - lastSignal >= cooldown)
{
if (prevF <= prevS && f > s && Position <= 0)
{
BuyMarket();
lastSignal = candle.OpenTime;
}
else if (prevF >= prevS && f < s && Position >= 0)
{
SellMarket();
lastSignal = candle.OpenTime;
}
}
prevF = f;
prevS = s;
})
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, fast);
DrawIndicator(area, slow);
DrawOwnTrades(area);
}
}
}
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 ExponentialMovingAverage
from StockSharp.Algo.Strategies import Strategy
class post_open_long_atr_stop_loss_take_profit_strategy(Strategy):
def __init__(self):
super(post_open_long_atr_stop_loss_take_profit_strategy, self).__init__()
self._slow_length = self.Param("SlowLength", 40) \
.SetGreaterThanZero()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(5)))
self._prev_fast = 0.0
self._prev_slow = 0.0
self._initialized = False
self._last_signal_ticks = 0
@property
def candle_type(self):
return self._candle_type.Value
@candle_type.setter
def candle_type(self, value):
self._candle_type.Value = value
def OnReseted(self):
super(post_open_long_atr_stop_loss_take_profit_strategy, self).OnReseted()
self._prev_fast = 0.0
self._prev_slow = 0.0
self._initialized = False
self._last_signal_ticks = 0
def OnStarted2(self, time):
super(post_open_long_atr_stop_loss_take_profit_strategy, self).OnStarted2(time)
self._prev_fast = 0.0
self._prev_slow = 0.0
self._initialized = False
self._last_signal_ticks = 0
self._fast = ExponentialMovingAverage()
self._fast.Length = 10
self._slow = ExponentialMovingAverage()
self._slow.Length = self._slow_length.Value
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(self._fast, self._slow, self.OnProcess).Start()
def OnProcess(self, candle, f, s):
if candle.State != CandleStates.Finished:
return
if not self._fast.IsFormed or not self._slow.IsFormed:
return
fv = float(f)
sv = float(s)
if not self._initialized:
self._prev_fast = fv
self._prev_slow = sv
self._initialized = True
return
cooldown_ticks = TimeSpan.FromMinutes(360).Ticks
current_ticks = candle.OpenTime.Ticks
if current_ticks - self._last_signal_ticks >= cooldown_ticks:
if self._prev_fast <= self._prev_slow and fv > sv and self.Position <= 0:
self.BuyMarket()
self._last_signal_ticks = current_ticks
elif self._prev_fast >= self._prev_slow and fv < sv and self.Position >= 0:
self.SellMarket()
self._last_signal_ticks = current_ticks
self._prev_fast = fv
self._prev_slow = sv
def CreateClone(self):
return post_open_long_atr_stop_loss_take_profit_strategy()