Esta estrategia opera rupturas después de una barra interior donde el rango de la vela más reciente es más estrecho que el de la barra de referencia Length períodos atrás. Se colocan órdenes stop en el máximo y mínimo de referencia con un take profit igual al rango de referencia y un stop loss establecido como porcentaje de dicho rango.
Detalles
Criterios de entrada:
Largo: el precio supera el máximo de referencia tras una barra de rango estrecho
Corto: el precio rompe por debajo del mínimo de referencia tras una barra de rango estrecho
Largo/Corto: Ambos
Criterios de salida:
Take profit en el rango de referencia
Stop loss como porcentaje del rango
Stops: Sí
Valores predeterminados:
Length = 4
StopLossPercent = 0.35m
CandleType = TimeSpan.FromMinutes(5).TimeFrame()
Filtros:
Categoría: Ruptura
Dirección: Ambos
Indicadores: Ninguno
Stops: Sí
Complejidad: Básico
Marco temporal: Corto plazo
Estacionalidad: No
Redes neuronales: No
Divergencia: No
Nivel de riesgo: Medio
using System;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
public class NarrowRangeStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public NarrowRangeStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame());
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var fast = new ExponentialMovingAverage { Length = 14 };
var slow = new ExponentialMovingAverage { Length = 40 };
var rsi = new RelativeStrengthIndex { Length = 14 };
var prevF = 0m; var prevS = 0m; var init = false;
var lastSignal = DateTimeOffset.MinValue;
var cooldown = TimeSpan.FromMinutes(120);
var sub = SubscribeCandles(CandleType);
sub.Bind(fast, slow, rsi, (c, f, s, r) =>
{
if (c.State != CandleStates.Finished || !fast.IsFormed || !slow.IsFormed || !rsi.IsFormed) return;
if (!init) { prevF = f; prevS = s; init = true; return; }
if (c.OpenTime - lastSignal >= cooldown)
{
if (prevF <= prevS && f > s && r > 50 && Position <= 0) { BuyMarket(); lastSignal = c.OpenTime; }
else if (prevF >= prevS && f < s && r < 50 && Position > 0) { SellMarket(); lastSignal = c.OpenTime; }
}
prevF = f; prevS = s;
}).Start();
var area = CreateChartArea();
if (area != null) { DrawCandles(area, sub); 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, RelativeStrengthIndex
from StockSharp.Algo.Strategies import Strategy
class narrow_range_strategy(Strategy):
"""
Narrow Range: EMA crossover with RSI filter and time-based cooldown.
"""
def __init__(self):
super(narrow_range_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(5))).SetDisplay("Candle Type", "Candles", "General")
self._prev_fast = 0.0
self._prev_slow = 0.0
self._initialized = False
self._cooldown_bars = 24
self._bar_index = 0
self._last_signal_bar = -1000000
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(narrow_range_strategy, self).OnReseted()
self._prev_fast = 0.0
self._prev_slow = 0.0
self._initialized = False
self._bar_index = 0
self._last_signal_bar = -1000000
def OnStarted2(self, time):
super(narrow_range_strategy, self).OnStarted2(time)
fast = ExponentialMovingAverage()
fast.Length = 14
slow = ExponentialMovingAverage()
slow.Length = 40
rsi = RelativeStrengthIndex()
rsi.Length = 14
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(fast, slow, rsi, self._process_candle).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, fast)
self.DrawIndicator(area, slow)
self.DrawOwnTrades(area)
def _process_candle(self, candle, fast_val, slow_val, rsi_val):
if candle.State != CandleStates.Finished:
return
fast = float(fast_val)
slow = float(slow_val)
rsi = float(rsi_val)
self._bar_index += 1
if not self._initialized:
self._prev_fast = fast
self._prev_slow = slow
self._initialized = True
return
can_signal = self._bar_index - self._last_signal_bar >= self._cooldown_bars
if can_signal and self._prev_fast <= self._prev_slow and fast > slow and rsi > 50 and self.Position <= 0:
self.BuyMarket()
self._last_signal_bar = self._bar_index
elif can_signal and self._prev_fast >= self._prev_slow and fast < slow and rsi < 50 and self.Position > 0:
self.SellMarket()
self._last_signal_bar = self._bar_index
self._prev_fast = fast
self._prev_slow = slow
def CreateClone(self):
return narrow_range_strategy()