Die Overnight-Gap-Strategie spielt die Markteröffnung, wenn der Kurs aufgrund von Nachrichten oder After-Hours-Aktivität erheblich vom vorherigen Schlusskurs abweicht.
Große Gaps schließen sich oft teilweise, wenn Trader die Bewegung verarbeiten.
Tests zeigen eine durchschnittliche jährliche Rendite von etwa 124%. Sie funktioniert am besten am Forex-Markt.
Die Strategie handelt gegen übermäßige Gaps, tritt kurz nach der Eröffnung in die entgegengesetzte Richtung ein und schließt die Position vor Sessionende.
Stops basieren auf einem Prozentsatz jenseits der Gap-Extreme, um das Risiko zu steuern, falls die Bewegung anhält.
Details
Einstiegskriterien: Indikatorsignal
Long/Short: Beide
Ausstiegskriterien: Stop-Loss oder entgegengesetztes Signal
Stops: Ja, prozentbasiert
Standardwerte:
CandleType = 15 minute
StopLossPercent = 2
MinGapPercent = 0.01
Der Markt handelt rund um die Uhr, daher ist die Sitzung der UTC-Tag. Die Lücke ist der Abstand vom letzten Schlusskurs des Vortags zur ersten Eröffnung des Tages. Eine Lücke von mindestens MinGapPercent wird zum Schluss der ersten Kerze gegengehandelt; der Stop liegt StopLossPercent jenseits des Hochs (Short) oder Tiefs (Long) dieser Kerze und wird auf Kerzenschlüssen geprüft, und die Position schließt mit der letzten Kerze des Tages.
Filter:
Kategorie: Gap
Richtung: Beide
Indikatoren: Gap
Stops: Ja
Komplexität: Mittel
Zeitrahmen: Intraday
Saisonalität: Nein
Neuronale Netze: Nein
Divergenz: Nein
Risikolevel: Mittel
using System;
using System.Collections.Generic;
using System.Linq;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Overnight Gap strategy.
/// The market trades around the clock, so the session is the UTC day.
/// The gap is the distance between the previous UTC day's last close and the new day's first open. A gap of at least MinGapPercent
/// is faded at the close of the day's first candle; the stop lies StopLossPercent beyond the first candle's extreme in the gap's direction,
/// and the position closes at the day's last candle.
/// </summary>
public class OvernightGapStrategy : Strategy
{
private readonly StrategyParam<decimal> _minGapPercent;
private readonly StrategyParam<decimal> _stopLossPercent;
private readonly StrategyParam<DataType> _candleType;
private DateTime? _day;
private decimal? _prevClose;
private decimal _stopPrice;
/// <summary>
/// Smallest gap to fade, in percent.
/// </summary>
public decimal MinGapPercent
{
get => _minGapPercent.Value;
set => _minGapPercent.Value = value;
}
/// <summary>
/// Distance of the stop beyond the first candle's extreme, in percent.
/// </summary>
public decimal StopLossPercent
{
get => _stopLossPercent.Value;
set => _stopLossPercent.Value = value;
}
/// <summary>
/// Candle type.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Constructor.
/// </summary>
public OvernightGapStrategy()
{
_minGapPercent = Param(nameof(MinGapPercent), 0.01m)
.SetGreaterThanZero()
.SetDisplay("Min Gap %", "Smallest gap to fade, in percent", "Session");
_stopLossPercent = Param(nameof(StopLossPercent), 2m)
.SetNotNegative()
.SetDisplay("Stop Loss %", "Distance of the stop beyond the first candle's extreme, in percent", "Risk");
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(15).TimeFrame())
.SetDisplay("Candle Type", "Type of candles to use", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_day = null;
_prevClose = null;
_stopPrice = default;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_day = null;
_prevClose = null;
_stopPrice = default;
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawOwnTrades(area);
}
}
private void ClosePosition()
{
if (Position > 0)
SellMarket(Position);
else if (Position < 0)
BuyMarket(-Position);
}
private void ProcessCandle(ICandleMessage candle)
{
if (candle.State != CandleStates.Finished)
return;
var day = candle.OpenTime.Date;
var firstOfDay = _day != day;
if (firstOfDay)
{
_day = day;
}
var frame = CandleType.Arg is TimeSpan tf ? tf : TimeSpan.Zero;
var lastOfDay = (candle.OpenTime + frame).Date != day;
var prevClose = _prevClose;
_prevClose = candle.ClosePrice;
if (!IsFormedAndOnlineAndAllowTrading())
return;
var close = candle.ClosePrice;
if (Position != 0)
{
if (lastOfDay || (Position > 0 ? close <= _stopPrice : close >= _stopPrice))
ClosePosition();
return;
}
if (!firstOfDay || prevClose is not decimal last || last <= 0)
return;
var gap = (candle.OpenPrice - last) / last * 100m;
if (gap >= MinGapPercent)
{
SellMarket(Volume);
_stopPrice = candle.HighPrice * (1 + StopLossPercent / 100m);
}
else if (-gap >= MinGapPercent)
{
BuyMarket(Volume);
_stopPrice = candle.LowPrice * (1 - StopLossPercent / 100m);
}
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
clr.AddReference("StockSharp.BusinessEntities")
from System import TimeSpan, Decimal
from StockSharp.Messages import DataType, CandleStates, Unit, UnitTypes, Level1Fields
from StockSharp.BusinessEntities import Subscription
from StockSharp.Algo.Strategies import Strategy
class overnight_gap_strategy(Strategy):
"""
Overnight Gap strategy.
The market trades around the clock, so the session is the UTC day.
The gap is the distance between the previous UTC day's last close and the new day's first open. A gap of at least MinGapPercent
is faded at the close of the day's first candle; the stop lies StopLossPercent beyond the first candle's extreme in the gap's direction,
and the position closes at the day's last candle.
"""
def __init__(self):
super(overnight_gap_strategy, self).__init__()
self._min_gap_percent = self.Param("MinGapPercent", 0.01).SetGreaterThanZero().SetDisplay("Min Gap %", "Smallest gap to fade, in percent", "Session")
self._stop_loss_percent = self.Param("StopLossPercent", 2.0).SetNotNegative().SetDisplay("Stop Loss %", "Distance of the stop beyond the first candle's extreme, in percent", "Risk")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(15))).SetDisplay("Candle Type", "Type of candles to use", "General")
self._reset_state()
@property
def candle_type(self):
return self._candle_type.Value
def _reset_state(self):
self._day = None
self._prev_close = None
self._stop_price = Decimal(0)
def OnReseted(self):
super(overnight_gap_strategy, self).OnReseted()
self._reset_state()
def OnStarted2(self, time):
super(overnight_gap_strategy, self).OnStarted2(time)
self._reset_state()
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(self._process_candle).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawOwnTrades(area)
def _close_position(self):
if self.Position > 0:
self.SellMarket(self.Position)
elif self.Position < 0:
self.BuyMarket(-self.Position)
def _process_candle(self, candle):
if candle.State != CandleStates.Finished:
return
day = candle.OpenTime.Date
first_of_day = self._day is None or self._day != day
if first_of_day:
self._day = day
frame = self.candle_type.Arg
last_of_day = (candle.OpenTime + frame).Date != day
prev_close = self._prev_close
self._prev_close = candle.ClosePrice
if not self.IsFormedAndOnlineAndAllowTrading():
return
close = candle.ClosePrice
if self.Position != 0:
stopped = close <= self._stop_price if self.Position > 0 else close >= self._stop_price
if last_of_day or stopped:
self._close_position()
return
if not first_of_day or prev_close is None or prev_close <= 0:
return
gap = (candle.OpenPrice - prev_close) / prev_close * Decimal(100)
min_gap = Decimal(self._min_gap_percent.Value)
percent = Decimal(self._stop_loss_percent.Value) / Decimal(100)
if gap >= min_gap:
self.SellMarket(self.Volume)
self._stop_price = candle.HighPrice * (Decimal(1) + percent)
elif -gap >= min_gap:
self.BuyMarket(self.Volume)
self._stop_price = candle.LowPrice * (Decimal(1) - percent)
def CreateClone(self):
return overnight_gap_strategy()