Стратегия I Gap
Стратегия I Gap повторяет логику советника "i-GAP" из MetaTrader. Она отслеживает ценовой разрыв между закрытием предыдущей свечи и открытием текущей. Нисходящий разрыв, превышающий заданное количество шагов цены, может открыть длинную позицию и при желании закрыть короткую. Восходящий разрыв работает аналогично для коротких позиций.
Детали
- Условия входа: Разрыв на открытии между соседними свечами превышает заданный порог.
- Длинные/Короткие: Оба направления.
- Условия выхода: Сигнал противоположного разрыва.
- Стопы: Фиксированные стоп-лосс и тейк-профит отсутствуют.
- Значения по умолчанию:
CandleType= 1 часGapSize= 5BuyPosOpen= trueSellPosOpen= trueBuyPosClose= trueSellPosClose= true
- Фильтры:
- Категория: Разрыв
- Направление: Оба
- Индикаторы: Нет
- Стопы: Нет
- Сложность: Начальный уровень
- Таймфрейм: Внутридневной
- Сезонность: Нет
- Нейросети: Нет
- Дивергенция: Нет
- Уровень риска: Низкий
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>
/// Strategy based on gap between previous close and current open.
/// </summary>
public class IGapStrategy : Strategy
{
private readonly StrategyParam<decimal> _gapSize;
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<bool> _buyPosOpen;
private readonly StrategyParam<bool> _sellPosOpen;
private readonly StrategyParam<bool> _buyPosClose;
private readonly StrategyParam<bool> _sellPosClose;
private decimal? _prevClose;
/// <summary>
/// Gap size in price steps.
/// </summary>
public decimal GapSize
{
get => _gapSize.Value;
set => _gapSize.Value = value;
}
/// <summary>
/// Candle type used for analysis.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Allow opening long positions on gap down.
/// </summary>
public bool BuyPosOpen
{
get => _buyPosOpen.Value;
set => _buyPosOpen.Value = value;
}
/// <summary>
/// Allow opening short positions on gap up.
/// </summary>
public bool SellPosOpen
{
get => _sellPosOpen.Value;
set => _sellPosOpen.Value = value;
}
/// <summary>
/// Close long position on opposite signal.
/// </summary>
public bool BuyPosClose
{
get => _buyPosClose.Value;
set => _buyPosClose.Value = value;
}
/// <summary>
/// Close short position on opposite signal.
/// </summary>
public bool SellPosClose
{
get => _sellPosClose.Value;
set => _sellPosClose.Value = value;
}
/// <summary>
/// Constructor.
/// </summary>
public IGapStrategy()
{
_gapSize = Param(nameof(GapSize), 5m)
.SetGreaterThanZero()
.SetDisplay("Gap Size", "Gap in price steps required to trigger signal", "General")
;
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame())
.SetDisplay("Candle Type", "Timeframe for gap detection", "General");
_buyPosOpen = Param(nameof(BuyPosOpen), true)
.SetDisplay("Enable Buy", "Allow opening long positions", "Trading");
_sellPosOpen = Param(nameof(SellPosOpen), true)
.SetDisplay("Enable Sell", "Allow opening short positions", "Trading");
_buyPosClose = Param(nameof(BuyPosClose), true)
.SetDisplay("Close Buy", "Close long on opposite signal", "Trading");
_sellPosClose = Param(nameof(SellPosClose), true)
.SetDisplay("Close Sell", "Close short on opposite signal", "Trading");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return new[] { (Security, CandleType) };
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevClose = null;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(ProcessCandle)
.Start();
StartProtection(
takeProfit: new Unit(2, UnitTypes.Percent),
stopLoss: new Unit(1, UnitTypes.Percent)
);
}
private void ProcessCandle(ICandleMessage candle)
{
if (candle.State != CandleStates.Finished)
return;
if (_prevClose is null)
{
_prevClose = candle.ClosePrice;
return;
}
// Use percentage-based gap: GapSize * 0.01%
var threshold = _prevClose.Value * GapSize * 0.01m / 100m;
var gap = _prevClose.Value - candle.OpenPrice;
if (gap > threshold && Position == 0)
{
if (BuyPosOpen)
BuyMarket();
}
else if (-gap > threshold && Position == 0)
{
if (SellPosOpen)
SellMarket();
}
_prevClose = candle.ClosePrice;
}
}
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, Unit, UnitTypes
from StockSharp.Algo.Strategies import Strategy
class i_gap_strategy(Strategy):
def __init__(self):
super(i_gap_strategy, self).__init__()
self._gap_size = self.Param("GapSize", 5.0) \
.SetDisplay("Gap Size", "Gap in price steps required to trigger signal", "General")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(5))) \
.SetDisplay("Candle Type", "Timeframe for gap detection", "General")
self._buy_pos_open = self.Param("BuyPosOpen", True) \
.SetDisplay("Enable Buy", "Allow opening long positions", "Trading")
self._sell_pos_open = self.Param("SellPosOpen", True) \
.SetDisplay("Enable Sell", "Allow opening short positions", "Trading")
self._buy_pos_close = self.Param("BuyPosClose", True) \
.SetDisplay("Close Buy", "Close long on opposite signal", "Trading")
self._sell_pos_close = self.Param("SellPosClose", True) \
.SetDisplay("Close Sell", "Close short on opposite signal", "Trading")
self._prev_close = None
@property
def gap_size(self):
return self._gap_size.Value
@property
def candle_type(self):
return self._candle_type.Value
@property
def buy_pos_open(self):
return self._buy_pos_open.Value
@property
def sell_pos_open(self):
return self._sell_pos_open.Value
@property
def buy_pos_close(self):
return self._buy_pos_close.Value
@property
def sell_pos_close(self):
return self._sell_pos_close.Value
def OnReseted(self):
super(i_gap_strategy, self).OnReseted()
self._prev_close = None
def OnStarted2(self, time):
super(i_gap_strategy, self).OnStarted2(time)
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(self.process_candle).Start()
self.StartProtection(
takeProfit=Unit(2.0, UnitTypes.Percent),
stopLoss=Unit(1.0, UnitTypes.Percent))
def process_candle(self, candle):
if candle.State != CandleStates.Finished:
return
close = float(candle.ClosePrice)
open_price = float(candle.OpenPrice)
if self._prev_close is None:
self._prev_close = close
return
# Use percentage-based gap
threshold = self._prev_close * float(self.gap_size) * 0.01 / 100.0
gap = self._prev_close - open_price
if gap > threshold and self.Position == 0:
if self.buy_pos_open:
self.BuyMarket()
elif -gap > threshold and self.Position == 0:
if self.sell_pos_open:
self.SellMarket()
self._prev_close = close
def CreateClone(self):
return i_gap_strategy()