Стратегия повторяет ключевые механики экспертного советника NewsReleaseEA: заранее выставляет симметричные стоп‑ордера перед выходом новости и активно сопровождает открытую позицию.
Основные идеи
Пять входных параметров (время новости, временные окна до/после, базовое расстояние и шаг между ордерами) определяют момент размещения и уровни заявок.
Непосредственно перед событием публикуется пара Buy Stop и Sell Stop. Первая пара ставится на расстоянии DistancePips от текущего ask/bid, следующие пары смещаются на StepPips.
Все отложенные ордера остаются активными до истечения PostNewsMinutes минут после новости. По окончании окна стратегия отменяет их и, при необходимости, закрывает открытую позицию.
После срабатывания любой заявки противоположные ордера снимаются автоматически, а позиция управляется правилами стоп‑лосса, тейк‑профита, перевода в безубыток и трейлинга (все значения указываются в пунктах).
Модуль безубытка активируется, когда цена проходит BreakEvenTriggerPips в прибыльную сторону, и закрывает сделку, если цена возвращается к уровню входа плюс BreakEvenOffsetPips (для лонга) или минус этот сдвиг (для шорта).
Трейлинг отслеживает максимальное/минимальное значение после входа. Как только расстояние до текущей цены превысит TrailingPips, позиция закрывается для фиксации прибыли.
Флаг TradeOnce соответствует параметру «TradeOneTimePerNews» из оригинального советника и запрещает повторный запуск после завершения первой сделки.
Параметры
NewsTime – момент выхода новости.
PreNewsMinutes – за сколько минут до события выставлять ордера.
PostNewsMinutes – сколько минут держать ордера после новости.
OrderPairs – количество пар Buy Stop/Sell Stop.
DistancePips – расстояние (в пунктах) до первой пары от текущих цен.
StepPips – дополнительный шаг между соседними парами.
OrderVolume – объем каждого отложенного ордера.
TradeOnce – разрешить только одну сделку на событие.
UseStopLoss / StopLossPips – включить стоп‑лосс и задать расстояние.
UseTakeProfit / TakeProfitPips – включить тейк‑профит и задать расстояние.
UseBreakEven, BreakEvenTriggerPips, BreakEvenOffsetPips – параметры перевода в безубыток.
UseTrailing / TrailingPips – включить трейлинг и определить его шаг.
CloseAfterEvent – закрывать позицию после завершения пост‑новостного окна.
Заметки
Стратегия использует только поток Level1 (SubscribeLevel1), поэтому реагирует на изменения bid/ask без ожидания закрытия свечи.
Пункты переводятся в абсолютные цены через PriceStep инструмента; если шаг цены неизвестен, используется значение 1 для безопасного расчёта.
Все защитные правила закрывают позицию рыночной заявкой (ClosePosition()), что сохраняет реактивный стиль управления, присущий оригинальному EA.
Python‑версия преднамеренно отсутствует.
using System;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// News Release strategy: Volatility breakout using Highest/Lowest channel.
/// Buys when close >= highest. Sells when close <= lowest.
/// </summary>
public class NewsReleaseStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _channelPeriod;
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public int ChannelPeriod
{
get => _channelPeriod.Value;
set => _channelPeriod.Value = value;
}
public NewsReleaseStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame())
.SetDisplay("Candle Type", "Candle timeframe", "General");
_channelPeriod = Param(nameof(ChannelPeriod), 10)
.SetGreaterThanZero()
.SetDisplay("Channel Period", "Highest/Lowest lookback", "Indicators");
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var high = new Highest { Length = ChannelPeriod };
var low = new Lowest { Length = ChannelPeriod };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(high, low, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal high, decimal low)
{
if (candle.State != CandleStates.Finished)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
if (candle.ClosePrice >= high && Position <= 0)
{
BuyMarket();
}
else if (candle.ClosePrice <= low && Position >= 0)
{
SellMarket();
}
}
}
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 Highest, Lowest
from StockSharp.Algo.Strategies import Strategy
class news_release_strategy(Strategy):
def __init__(self):
super(news_release_strategy, self).__init__()
self._channel_period = self.Param("ChannelPeriod", 10) \
.SetDisplay("Channel Period", "Highest/Lowest lookback", "Indicators")
self._highest = None
self._lowest = None
@property
def channel_period(self):
return self._channel_period.Value
def OnReseted(self):
super(news_release_strategy, self).OnReseted()
self._highest = None
self._lowest = None
def OnStarted2(self, time):
super(news_release_strategy, self).OnStarted2(time)
self._highest = Highest()
self._highest.Length = self.channel_period
self._lowest = Lowest()
self._lowest.Length = self.channel_period
subscription = self.SubscribeCandles(DataType.TimeFrame(TimeSpan.FromMinutes(5)))
subscription.Bind(self._highest, self._lowest, self._process_candle)
subscription.Start()
def _process_candle(self, candle, high_val, low_val):
if candle.State != CandleStates.Finished:
return
if not self._highest.IsFormed or not self._lowest.IsFormed:
return
close = float(candle.ClosePrice)
h = float(high_val)
l = float(low_val)
if close >= h and self.Position <= 0:
self.BuyMarket()
elif close <= l and self.Position >= 0:
self.SellMarket()
def CreateClone(self):
return news_release_strategy()