在 GitHub 上查看

BrainTrend2 V2 Duplex 策略

概述

BrainTrend2 V2 Duplex 策略是 MetaTrader 5 专家顾问 Exp_BrainTrend2_V2_Duplex 在 StockSharp 平台上的高阶移植版本。策略并行运行两个 BrainTrend2 V2 指标实例:一个专门监控做多机会,另一个负责做空。两条通道都可以拥有独立的蜡烛类型、ATR 周期以及信号偏移,方便实现多周期确认或不对称风险配置。

BrainTrend2 V2 是一种趋势跟随模型,通过比较最近的真实波幅与加权 ATR 均值来构建动态“河道”。指标会为蜡烛染色,共有五种颜色:

  • 0 – 上升河道中的多头蜡烛。
  • 1 – 上升河道中的空头蜡烛。
  • 2 – 河道切换时的过渡颜色。
  • 3 – 下降河道中的多头蜡烛。
  • 4 – 下降河道中的空头蜡烛。

策略通过识别颜色的切换来产生入场与离场信号,完全复刻 MQL5 原版的交易规则。

交易逻辑

多头规则

  • 观察 Long Signal Bar 指定的历史蜡烛(默认 1 表示上一根已收盘的蜡烛)。
  • 当以下条件满足时开多:
    • SignalBar + 1(向前两根蜡烛)的颜色 小于 2(绿色调代表上升河道),并且
    • SignalBar 的颜色 大于 1(从纯多头状态转变)。
  • SignalBar + 1 的颜色 大于 2(洋红色调代表下降河道)时平多。

空头规则

  • 观察 Short Signal Bar 指定的历史蜡烛。
  • 当以下条件满足时开空:
    • SignalBar + 1 的颜色 大于 2(洋红色调),并且
    • SignalBar 的颜色 大于 0(除纯多头蜡烛之外的任何颜色)。
  • SignalBar + 1 的颜色 小于 2(回到上升河道)时平空。

若开仓方向与当前仓位相反,策略会先自动对冲已有仓位,然后再按设置的交易量下单。

风险管理

  • 多头与空头均可单独设置止损和止盈点数,数值为 0 时表示禁用。
  • 止损/止盈会根据合约的报价步长换算为绝对价格。多头监控蜡烛的最低价与最高价,空头则监控最高价与最低价,从而模拟盘中触发。
  • 交易量以合约单位表示,长短两侧可设置不同数值。
  • 策略调用 StartProtection(),可与 StockSharp 的组合级安全机制协同使用。

参数

参数 说明 默认值
Long Candle Type 多头指标使用的蜡烛类型(时间框架)。 H4
Long ATR Period 多头通道的 BrainTrend2 ATR 周期。 7
Long Signal Bar 多头信号使用的历史偏移。 1
Enable Long Entries 是否允许开多。 true
Enable Long Exits 是否允许多头根据指标平仓。 true
Long Volume 多头开仓的基础交易量。 1
Long Stop Loss 多头止损点数(0 = 禁用)。 1000
Long Take Profit 多头止盈点数(0 = 禁用)。 2000
Short Candle Type 空头指标使用的蜡烛类型。 H4
Short ATR Period 空头通道的 BrainTrend2 ATR 周期。 7
Short Signal Bar 空头信号使用的历史偏移。 1
Enable Short Entries 是否允许开空。 true
Enable Short Exits 是否允许空头根据指标平仓。 true
Short Volume 空头开仓的基础交易量。 1
Short Stop Loss 空头止损点数(0 = 禁用)。 1000
Short Take Profit 空头止盈点数(0 = 禁用)。 2000

使用建议

  • 通过增大 Signal Bar 可以等待更多蜡烛确认,或为多空两侧配置不同的时间框架以实现多周期过滤。
  • 自定义 BrainTrend2 指标完全在 C# 内实现,无需额外的 MQL 文件或库。
  • 策略在每根蜡烛收盘时检查止损和止盈。若需要更精细的风险控制,请选择较小的时间框架。
  • 当止损与止盈均为 0 时,仓位只会在出现相反颜色信号时平仓。
  • 指标需要累计不少于 ATR 周期数量的蜡烛后才会输出有效信号,在此之前策略不会交易。
using System;
using System.Collections.Generic;

using Ecng.Common;

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

namespace StockSharp.Samples.Strategies;

/// <summary>
/// BrainTrend2 V2 Duplex strategy (simplified).
/// Uses ATR-based channel breakout for trend detection.
/// </summary>
public class BrainTrend2V2DuplexStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _atrPeriod;
	private readonly StrategyParam<int> _emaPeriod;
	private readonly StrategyParam<decimal> _channelMult;

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

	public int AtrPeriod
	{
		get => _atrPeriod.Value;
		set => _atrPeriod.Value = value;
	}

	public int EmaPeriod
	{
		get => _emaPeriod.Value;
		set => _emaPeriod.Value = value;
	}

	public decimal ChannelMult
	{
		get => _channelMult.Value;
		set => _channelMult.Value = value;
	}

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

		_atrPeriod = Param(nameof(AtrPeriod), 7)
			.SetGreaterThanZero()
			.SetDisplay("ATR Period", "ATR length", "Indicators");

		_emaPeriod = Param(nameof(EmaPeriod), 14)
			.SetGreaterThanZero()
			.SetDisplay("EMA Period", "EMA length for trend", "Indicators");

		_channelMult = Param(nameof(ChannelMult), 2.5m)
			.SetGreaterThanZero()
			.SetDisplay("Channel Mult", "ATR multiplier for channel width", "Indicators");
	}

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

		var atr = new AverageTrueRange { Length = AtrPeriod };
		var ema = new ExponentialMovingAverage { Length = EmaPeriod };

		var subscription = SubscribeCandles(CandleType);
		subscription
			.Bind(atr, ema, (ICandleMessage candle, decimal atrValue, decimal emaValue) =>
			{
				if (candle.State != CandleStates.Finished)
					return;

				if (!IsFormedAndOnlineAndAllowTrading())
					return;

				var close = candle.ClosePrice;
				var upper = emaValue + ChannelMult * atrValue;
				var lower = emaValue - ChannelMult * atrValue;

				// Buy when close breaks above upper channel
				if (close > upper && Position <= 0)
				{
					BuyMarket();
				}
				// Sell when close breaks below lower channel
				else if (close < lower && Position >= 0)
				{
					SellMarket();
				}
			})
			.Start();

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