La Brecha Nocturna opera en la apertura cuando el precio presenta un gap significativo respecto al cierre anterior debido a noticias o actividad fuera de horario.
Los grandes gaps suelen retraerse parcialmente a medida que los operadores digieren el movimiento.
Las pruebas indican un retorno anual promedio de aproximadamente el 124%. Funciona mejor en el mercado de forex.
La estrategia va en contra de los gaps excesivos, entrando en dirección opuesta poco después de la apertura y cerrando antes de que termine la sesión.
Los stops se basan en un porcentaje más allá de los extremos del gap para gestionar el riesgo si el movimiento continúa.
Detalles
Criterios de entrada: señal de indicador
Largo/Corto: Ambos
Criterios de salida: stop-loss o señal opuesta
Stops: Sí, basado en porcentaje
Valores predeterminados:
CandleType = 15 minute
StopLoss = 2%
Filtros:
Categoría: Gap
Dirección: Ambos
Indicadores: Gap
Stops: Sí
Complejidad: Intermedio
Marco temporal: Intradía
Estacionalidad: No
Redes neuronales: No
Divergencia: No
Nivel de riesgo: Medio
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>
/// Implementation of Overnight Gap trading strategy.
/// Trades on gaps between current open and previous close, using MA trend filter.
/// </summary>
public class OvernightGapStrategy : Strategy
{
private readonly StrategyParam<int> _maPeriod;
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _cooldownBars;
private SimpleMovingAverage _ma;
private decimal _prevClose;
private int _cooldown;
/// <summary>
/// Moving average period.
/// </summary>
public int MaPeriod
{
get => _maPeriod.Value;
set => _maPeriod.Value = value;
}
/// <summary>
/// Candle type for strategy.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Cooldown bars between trades.
/// </summary>
public int CooldownBars
{
get => _cooldownBars.Value;
set => _cooldownBars.Value = value;
}
/// <summary>
/// Initializes a new instance of the <see cref="OvernightGapStrategy"/>.
/// </summary>
public OvernightGapStrategy()
{
_maPeriod = Param(nameof(MaPeriod), 20)
.SetGreaterThanZero()
.SetDisplay("MA Period", "Moving average period", "Strategy");
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame())
.SetDisplay("Candle Type", "Type of candles for strategy", "Strategy");
_cooldownBars = Param(nameof(CooldownBars), 30)
.SetDisplay("Cooldown Bars", "Bars between trades", "General")
.SetRange(5, 500);
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_ma = default;
_prevClose = 0;
_cooldown = 0;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_ma = new SimpleMovingAverage { Length = MaPeriod };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(_ma, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, _ma);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal maValue)
{
if (candle.State != CandleStates.Finished)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
var close = candle.ClosePrice;
var open = candle.OpenPrice;
if (_prevClose == 0)
{
_prevClose = close;
return;
}
if (_cooldown > 0)
{
_cooldown--;
_prevClose = close;
return;
}
// Calculate gap
var gap = open - _prevClose;
// Gap up + above MA = Buy
if (gap > 0 && open > maValue && Position == 0)
{
BuyMarket();
_cooldown = CooldownBars;
}
// Gap down + below MA = Sell short
else if (gap < 0 && open < maValue && Position == 0)
{
SellMarket();
_cooldown = CooldownBars;
}
// Exit: gap fill or MA cross
if (Position > 0 && close < maValue)
{
SellMarket();
_cooldown = CooldownBars;
}
else if (Position < 0 && close > maValue)
{
BuyMarket();
_cooldown = CooldownBars;
}
_prevClose = close;
}
}
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 SimpleMovingAverage
from StockSharp.Algo.Strategies import Strategy
class overnight_gap_strategy(Strategy):
"""
Overnight Gap trading strategy.
Trades on gaps between current open and previous close, using MA trend filter.
"""
def __init__(self):
super(overnight_gap_strategy, self).__init__()
self._ma_period = self.Param("MaPeriod", 20).SetDisplay("MA Period", "Moving average period", "Strategy")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(5))).SetDisplay("Candle Type", "Type of candles for strategy", "Strategy")
self._cooldown_bars = self.Param("CooldownBars", 30).SetDisplay("Cooldown Bars", "Bars between trades", "General")
self._prev_close = 0.0
self._cooldown = 0
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(overnight_gap_strategy, self).OnReseted()
self._prev_close = 0.0
self._cooldown = 0
def OnStarted2(self, time):
super(overnight_gap_strategy, self).OnStarted2(time)
self._prev_close = 0.0
self._cooldown = 0
sma = SimpleMovingAverage()
sma.Length = self._ma_period.Value
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(sma, self._process_candle).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, sma)
self.DrawOwnTrades(area)
def _process_candle(self, candle, ma_val):
if candle.State != CandleStates.Finished:
return
close = float(candle.ClosePrice)
open_price = float(candle.OpenPrice)
ma = float(ma_val)
cd = self._cooldown_bars.Value
if self._prev_close == 0:
self._prev_close = close
return
if self._cooldown > 0:
self._cooldown -= 1
self._prev_close = close
return
# Calculate gap
gap = open_price - self._prev_close
# Gap up + above MA = Buy
if gap > 0 and open_price > ma and self.Position == 0:
self.BuyMarket()
self._cooldown = cd
# Gap down + below MA = Sell short
elif gap < 0 and open_price < ma and self.Position == 0:
self.SellMarket()
self._cooldown = cd
# Exit: MA cross
if self.Position > 0 and close < ma:
self.SellMarket()
self._cooldown = cd
elif self.Position < 0 and close > ma:
self.BuyMarket()
self._cooldown = cd
self._prev_close = close
def CreateClone(self):
return overnight_gap_strategy()