在 GitHub 上查看
新闻发布策略
该策略复刻了 NewsReleaseEA 智能交易系统的核心思想:在预定的新闻发布时间前后布设对称的挂单,并对触发后的头寸进行主动管理。
核心思路
- 五个主要输入(新闻时间、提前/滞后窗口、挂单距离以及层间间距)决定了挂单的时间与位置。
- 在设定的新闻时间之前,策略会提交一组买入止损单与卖出止损单。第一组挂单距离当前买卖价
DistancePips 个点,其余组之间通过 StepPips 调整间隔。
- 所有挂单会保留至新闻发布后
PostNewsMinutes 分钟,窗口结束时会自动撤销全部挂单,并在需要时平掉现有头寸。
- 当任意方向的挂单被触发时,对侧挂单立即撤销,剩余仓位由止损、止盈、保本和追踪四套规则(以点数表示)进行管理。
- 保本逻辑会在价格朝有利方向运行
BreakEvenTriggerPips 点后启动,并在价格回落至入场价加减 BreakEvenOffsetPips 点时平仓,确保盈利不被完全回吐。
- 追踪管理会记录入场后的最佳价位,一旦当前价格与极值之间的距离超过
TrailingPips 点,策略立即平仓以锁定利润。
TradeOnce 参数对应 MQL 程序中的“一次事件仅交易一次”选项,可防止在首次交易结束后再次激活。
参数说明
NewsTime – 新闻发布时间。
PreNewsMinutes – 提前多少分钟开始挂单。
PostNewsMinutes – 新闻发布后挂单保留的分钟数。
OrderPairs – 同时提交的买入止损/卖出止损对数。
DistancePips – 第一组挂单距离当前买卖价的点数。
StepPips – 相邻挂单组之间额外的点数间距。
OrderVolume – 每个挂单的下单量。
TradeOnce – 开启后一个事件窗口内仅允许交易一次。
UseStopLoss / StopLossPips – 启用并设置止损点数。
UseTakeProfit / TakeProfitPips – 启用并设置止盈点数。
UseBreakEven, BreakEvenTriggerPips, BreakEvenOffsetPips – 配置保本策略。
UseTrailing / TrailingPips – 启用追踪平仓逻辑及其点数距离。
CloseAfterEvent – 事件窗口结束后是否强制平仓。
备注
- 策略仅使用 Level1 行情数据(
SubscribeLevel1),无需等待蜡烛收盘即可根据最新买卖价做出反应。
- 点数会根据合约的
PriceStep 转换为实际价格距离;若 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()