在 GitHub 上查看

GBP 9 AM Breakout 策略

概述

GBP 9 AM Breakout Strategy 是经典 MetaTrader "GBP9AM" 专家的 StockSharp 版本。策略在伦敦市场开盘(本地时间 9:00)附近同时放置买入止损和卖出止损订单,以捕捉开盘后的方向性突破。所有距离均以点(pip)为单位,并根据交易品种的最小报价单位自动换算。

交易逻辑

  1. 策略订阅可配置的 K 线类型(默认 1 分钟),仅在 K 线收盘后进行计算,保证时间戳精确。
  2. 每个交易日仅准备一次双向挂单,新交易日会自动重置状态。
  3. 当 K 线时间达到参数 LookHourLookMinute 时:
    • 取消仍在市场中的挂单,并关闭可能存在的持仓,防止信号冲突。
    • 基于最新收盘价计算买入止损、卖出止损及其对应的止损/止盈价位,自动处理 3 位或 5 位小数报价的点值。
    • 同时挂出 Buy Stop 与 Sell Stop 订单,形成开盘突破的“跨式”结构。
  4. 任一方向成交后,另一侧挂单立即撤销。策略随后持续监控价格,满足止损或止盈条件时平仓。
  5. 可选的 UseCloseHour 参数允许在设定时间(默认 18:00)强制平仓并撤单,避免隔夜持仓。

参数说明

参数 说明
Volume 双向挂单的交易量。
LookHour 触发布单的小时(0–23),需与经纪商时区下的伦敦 9:00 对应。
LookMinute 触发布单的分钟。
CloseHour 日内强制平仓与撤单的小时。
UseCloseHour 是否启用日内强制平仓功能。
TakeProfitPips 距离入场价的止盈点数,适用于多空双方。
BuyDistancePips Buy Stop 距离最新价的点数。
SellDistancePips Sell Stop 距离最新价的点数。
BuyStopLossPips 多头仓位的止损点数。
SellStopLossPips 空头仓位的止损点数。
CandleType 用于计时与风控的 K 线类型(默认 1 分钟)。

风险控制

  • 每笔交易在挂单阶段即设定对应的止损与止盈,实现固定的风险回报结构。
  • 日终平仓机制可避免隔夜风险,除非手动关闭该功能。
  • 策略每天仅建立一次突破结构,能够减少横盘行情中的过度交易。

使用建议

  1. 根据行情服务器的时区调整 LookHour,确保 9:00 伦敦时间被正确触发。
  2. 结合当前波动性调整各类点距参数,使止损与目标更加贴合市场。
  3. 建议在具有可靠 PriceStep 信息的外汇品种上使用,以保证点值转换准确。
  4. 注意经纪商的保证金要求,较大的 Volume 设置需要更高的资金占用,与原始 MQL 版本相同。

文件结构

  • CS/Gbp9AmBreakoutStrategy.cs:基于 StockSharp 高级 API 的 C# 实现。
  • README.md:英文说明。
  • README_ru.md:俄文说明。
  • README_zh.md:中文说明(当前文件)。

根据项目约束,本策略暂不提供 Python 版本。

using System;
using System.Collections.Generic;

using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;

namespace StockSharp.Samples.Strategies;

/// <summary>
/// Session breakout strategy using Highest/Lowest channel.
/// Trades on breakouts above/below the previous channel levels.
/// </summary>
public class Gbp9AmBreakoutStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _period;

	private decimal? _prevHigh;
	private decimal? _prevLow;

	public DataType CandleType
	{
		get => _candleType.Value;
		set => _candleType.Value = value;
	}

	public int Period
	{
		get => _period.Value;
		set => _period.Value = value;
	}

	public Gbp9AmBreakoutStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
			.SetDisplay("Candle Type", "Timeframe", "General");

		_period = Param(nameof(Period), 12)
			.SetGreaterThanZero()
			.SetDisplay("Period", "Channel lookback period", "Indicators");
	}

	public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
	{
		return [(Security, CandleType)];
	}

	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();
		_prevHigh = null;
		_prevLow = null;
	}

	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);

		_prevHigh = null;
		_prevLow = null;

		var highest = new Highest { Length = Period };
		var lowest = new Lowest { Length = Period };

		var subscription = SubscribeCandles(CandleType);
		subscription
			.Bind(highest, lowest, ProcessCandle)
			.Start();

		var area = CreateChartArea();
		if (area != null)
		{
			DrawCandles(area, subscription);
			DrawIndicator(area, highest);
			DrawIndicator(area, lowest);
			DrawOwnTrades(area);
		}
	}

	private void ProcessCandle(ICandleMessage candle, decimal high, decimal low)
	{
		if (candle.State != CandleStates.Finished)
			return;

		if (!IsFormedAndOnlineAndAllowTrading())
		{
			_prevHigh = high;
			_prevLow = low;
			return;
		}

		var close = candle.ClosePrice;

		if (_prevHigh == null || _prevLow == null)
		{
			_prevHigh = high;
			_prevLow = low;
			return;
		}

		if (close > _prevHigh.Value && Position <= 0)
		{
			if (Position < 0)
				BuyMarket();
			BuyMarket();
		}
		else if (close < _prevLow.Value && Position >= 0)
		{
			if (Position > 0)
				SellMarket();
			SellMarket();
		}

		_prevHigh = high;
		_prevLow = low;
	}
}