Estrategia de Mínimo de 3 Barras
La estrategia de Mínimo de 3 Barras compra cuando el precio de cierre cae por debajo del cierre mínimo de las tres barras anteriores y sale cuando el precio cierra por encima del cierre máximo de las siete barras anteriores. Un filtro EMA opcional puede requerir que el precio se mantenga por encima de una media de largo plazo antes de permitir entradas.
Detalles
- Criterios de entrada:
- El precio de cierre está por debajo del cierre mínimo de las tres barras anteriores.
- Opcional: el precio de cierre está por encima de la EMA cuando el filtro está activado.
- Largo/Corto: Solo largos.
- Criterios de salida:
- El precio de cierre está por encima del cierre máximo de las siete barras anteriores.
- Stops: Ninguno.
- Valores predeterminados:
MaPeriod= 200LowestLength= 3HighestLength= 7UseEmaFilter= false
- Filtros:
- Categoría: Ruptura
- Dirección: Long
- Indicadores: EMA, Highest/Lowest
- Stops: No
- Complejidad: Bajo
- Marco temporal: Cualquiera
- Estacionalidad: No
- Redes neuronales: No
- Divergencia: No
- Nivel de riesgo: Bajo
namespace StockSharp.Samples.Strategies;
using System;
using System.Collections.Generic;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
/// <summary>
/// 3-Bar Low Strategy.
/// Buys when price breaks below recent 3-bar low (mean reversion).
/// Exits when price breaks above recent 7-bar high.
/// Uses EMA as optional trend filter.
/// </summary>
public class ThreeBarLowStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _emaLength;
private readonly StrategyParam<int> _lookbackLow;
private readonly StrategyParam<int> _lookbackHigh;
private readonly StrategyParam<int> _cooldownBars;
private ExponentialMovingAverage _ema;
private readonly List<decimal> _lows = new();
private readonly List<decimal> _highs = new();
private int _cooldownRemaining;
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public int EmaLength
{
get => _emaLength.Value;
set => _emaLength.Value = value;
}
public int LookbackLow
{
get => _lookbackLow.Value;
set => _lookbackLow.Value = value;
}
public int LookbackHigh
{
get => _lookbackHigh.Value;
set => _lookbackHigh.Value = value;
}
public int CooldownBars
{
get => _cooldownBars.Value;
set => _cooldownBars.Value = value;
}
public ThreeBarLowStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(30).TimeFrame())
.SetDisplay("Candle Type", "Type of candles to use", "General");
_emaLength = Param(nameof(EmaLength), 50)
.SetGreaterThanZero()
.SetDisplay("EMA Length", "EMA trend filter period", "Indicators");
_lookbackLow = Param(nameof(LookbackLow), 3)
.SetGreaterThanZero()
.SetDisplay("Lookback Low", "Bars for lowest low", "Parameters");
_lookbackHigh = Param(nameof(LookbackHigh), 7)
.SetGreaterThanZero()
.SetDisplay("Lookback High", "Bars for highest high", "Parameters");
_cooldownBars = Param(nameof(CooldownBars), 10)
.SetDisplay("Cooldown Bars", "Bars between trades", "Risk");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
=> [(Security, CandleType)];
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_ema = null;
_lows.Clear();
_highs.Clear();
_cooldownRemaining = 0;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_ema = new ExponentialMovingAverage { Length = EmaLength };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(_ema, OnProcess)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, _ema);
DrawOwnTrades(area);
}
}
private void OnProcess(ICandleMessage candle, decimal emaVal)
{
if (candle.State != CandleStates.Finished)
return;
if (!_ema.IsFormed)
return;
// Track lows and highs
_lows.Add(candle.LowPrice);
_highs.Add(candle.HighPrice);
if (_lows.Count > LookbackLow + 1)
_lows.RemoveAt(0);
if (_highs.Count > LookbackHigh + 1)
_highs.RemoveAt(0);
if (!IsFormedAndOnlineAndAllowTrading())
return;
if (_cooldownRemaining > 0)
{
_cooldownRemaining--;
return;
}
if (_lows.Count <= LookbackLow || _highs.Count <= LookbackHigh)
return;
// Find lowest low of previous N bars (excluding current)
var lowestLow = decimal.MaxValue;
for (var i = 0; i < _lows.Count - 1; i++)
lowestLow = Math.Min(lowestLow, _lows[i]);
// Find highest high of previous N bars (excluding current)
var highestHigh = decimal.MinValue;
for (var i = 0; i < _highs.Count - 1; i++)
highestHigh = Math.Max(highestHigh, _highs[i]);
var price = candle.ClosePrice;
// Buy: price breaks below previous N-bar low (mean reversion)
if (price < lowestLow && Position <= 0)
{
if (Position < 0)
BuyMarket(Math.Abs(Position));
BuyMarket(Volume);
_cooldownRemaining = CooldownBars;
}
// Sell short: price breaks above previous N-bar high
else if (price > highestHigh && Position >= 0)
{
if (Position > 0)
SellMarket(Math.Abs(Position));
SellMarket(Volume);
_cooldownRemaining = CooldownBars;
}
// Exit long: price above previous high
else if (Position > 0 && price > highestHigh)
{
SellMarket(Math.Abs(Position));
_cooldownRemaining = CooldownBars;
}
// Exit short: price below previous low
else if (Position < 0 && price < lowestLow)
{
BuyMarket(Math.Abs(Position));
_cooldownRemaining = CooldownBars;
}
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
from System import TimeSpan, Math
from StockSharp.Messages import DataType, CandleStates
from StockSharp.Algo.Indicators import ExponentialMovingAverage
from StockSharp.Algo.Strategies import Strategy
class three_bar_low_strategy(Strategy):
"""3-Bar Low Strategy."""
def __init__(self):
super(three_bar_low_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(30))) \
.SetDisplay("Candle Type", "Type of candles to use", "General")
self._ema_length = self.Param("EmaLength", 50) \
.SetDisplay("EMA Length", "EMA trend filter period", "Indicators")
self._lookback_low = self.Param("LookbackLow", 3) \
.SetDisplay("Lookback Low", "Bars for lowest low", "Parameters")
self._lookback_high = self.Param("LookbackHigh", 7) \
.SetDisplay("Lookback High", "Bars for highest high", "Parameters")
self._cooldown_bars = self.Param("CooldownBars", 10) \
.SetDisplay("Cooldown Bars", "Bars between trades", "Risk")
self._ema = None
self._lows = []
self._highs = []
self._cooldown_remaining = 0
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(three_bar_low_strategy, self).OnReseted()
self._ema = None
self._lows = []
self._highs = []
self._cooldown_remaining = 0
def OnStarted2(self, time):
super(three_bar_low_strategy, self).OnStarted2(time)
self._ema = ExponentialMovingAverage()
self._ema.Length = int(self._ema_length.Value)
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(self._ema, self._on_process).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, self._ema)
self.DrawOwnTrades(area)
def _on_process(self, candle, ema_val):
if candle.State != CandleStates.Finished:
return
if not self._ema.IsFormed:
return
lb_low = int(self._lookback_low.Value)
lb_high = int(self._lookback_high.Value)
self._lows.append(float(candle.LowPrice))
self._highs.append(float(candle.HighPrice))
if len(self._lows) > lb_low + 1:
self._lows.pop(0)
if len(self._highs) > lb_high + 1:
self._highs.pop(0)
if not self.IsFormedAndOnlineAndAllowTrading():
return
if self._cooldown_remaining > 0:
self._cooldown_remaining -= 1
return
if len(self._lows) <= lb_low or len(self._highs) <= lb_high:
return
lowest_low = min(self._lows[:-1])
highest_high = max(self._highs[:-1])
price = float(candle.ClosePrice)
cooldown = int(self._cooldown_bars.Value)
if price < lowest_low and self.Position <= 0:
if self.Position < 0:
self.BuyMarket(Math.Abs(self.Position))
self.BuyMarket(self.Volume)
self._cooldown_remaining = cooldown
elif price > highest_high and self.Position >= 0:
if self.Position > 0:
self.SellMarket(Math.Abs(self.Position))
self.SellMarket(self.Volume)
self._cooldown_remaining = cooldown
elif self.Position > 0 and price > highest_high:
self.SellMarket(Math.Abs(self.Position))
self._cooldown_remaining = cooldown
elif self.Position < 0 and price < lowest_low:
self.BuyMarket(Math.Abs(self.Position))
self._cooldown_remaining = cooldown
def CreateClone(self):
return three_bar_low_strategy()