在 GitHub 上查看

ASCV BrainTrend Signal 策略

ASCV BrainTrend Signal 策略是原始 MetaTrader Expert Advisor 的移植版本,基于 BrainTrend1 指标的信号执行交易。StockSharp 实现通过高层 API 结合 ATR、随机振荡指标以及 Jurik 移动平均 (JMA),用于识别动量反转并设置可选的止损、止盈和跟踪止损。

策略思路

  1. 使用 ATR 计算当前波动率,得到用于确认信号的动态阈值。
  2. 对收盘价应用 Jurik 平滑,并与两根之前的 JMA 值比较。
  3. 当平滑差值大于 ATR / 2.3 时,根据随机指标 %K 判断方向:
    • %K < 47:进入潜在做空状态。
    • %K > 53:进入潜在做多状态。
  4. 信号在下一根完成的 K 线上执行,可通过 ReverseSignals 参数反转多空逻辑。
  5. 止损、止盈及跟踪止损以“点”(最小报价步长的倍数)表示。

开平仓规则

  • 做多:上一根 K 线生成买入信号,且当前仓位不是多头。下单量为 Volume + |Position|,若有空头仓位会先行平仓。
  • 做空:上一根 K 线生成卖出信号,且当前仓位不是空头。
  • 止损entry ± StopLossPips * priceStep,若下一根 K 线触及该价位则市价平仓。
  • 止盈entry ± TakeProfitPips * priceStep(参数大于 0 时启用)。
  • 跟踪止损:当 TrailingStopPipsTrailingStepPips 都大于 0 时启用。价格向有利方向移动 TrailingStopPips + TrailingStepPips 后,止损价向有利方向移动 TrailingStopPips

参数

参数 说明 默认值
AtrPeriod ATR 波动率周期。 14
StochasticPeriod 随机指标基础周期。 12
JmaLength Jurik 平滑长度。 7
StopLossPips 止损点数。 15
TakeProfitPips 止盈点数。 46
TrailingStopPips 跟踪止损距离。 0 (关闭)
TrailingStepPips 跟踪止损触发步长。 5
ReverseSignals 反转多空信号。 false
CandleType 工作时间框架 (默认 15 分钟)。 15m

使用提示

  • 仅在完成的 K 线上计算指标,可减少盘中噪声。
  • Security.MinPriceStep 不可用,会使用默认步长 0.0001 将点值转换为价格差。
  • 图表会绘制蜡烛图、随机指标和 JMA,方便实时监控策略状态。
  • 跟踪止损实现与原始 EA 一致,只会向盈利方向移动,并要求达到距离和步长的双重条件。

建议

  • 根据交易品种的波动率调整 AtrPeriodStochasticPeriod
  • 对于最小报价步长较大的资产,适当增大止损和止盈,避免过早出场。
  • 需要反向运行时可启用 ReverseSignals 参数。
  • 实际交易应结合券商风控或其他风险管理手段。
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>
/// ASCV BrainTrend Signal strategy. Uses DEMA crossover (8/25).
/// </summary>
public class AscvBrainTrendSignalStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _fastPeriod;
	private readonly StrategyParam<int> _slowPeriod;
	private decimal? _prevFast;
	private decimal? _prevSlow;

	public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
	public int FastPeriod { get => _fastPeriod.Value; set => _fastPeriod.Value = value; }
	public int SlowPeriod { get => _slowPeriod.Value; set => _slowPeriod.Value = value; }

	public AscvBrainTrendSignalStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).TimeFrame()).SetDisplay("Candle Type", "Timeframe", "General");
		_fastPeriod = Param(nameof(FastPeriod), 8).SetGreaterThanZero().SetDisplay("Fast DEMA", "Fast DEMA period", "Indicators");
		_slowPeriod = Param(nameof(SlowPeriod), 25).SetGreaterThanZero().SetDisplay("Slow DEMA", "Slow DEMA period", "Indicators");
	}

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

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

	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);
		_prevFast = null; _prevSlow = null;
		var fast = new DoubleExponentialMovingAverage { Length = FastPeriod };
		var slow = new DoubleExponentialMovingAverage { Length = SlowPeriod };
		var subscription = SubscribeCandles(CandleType);
		subscription.Bind(fast, slow, ProcessCandle).Start();
		var area = CreateChartArea();
		if (area != null) { DrawCandles(area, subscription); DrawIndicator(area, fast); DrawIndicator(area, slow); DrawOwnTrades(area); }
	}

	private void ProcessCandle(ICandleMessage candle, decimal fast, decimal slow)
	{
		if (candle.State != CandleStates.Finished) return;
		if (!IsFormedAndOnlineAndAllowTrading()) { _prevFast = fast; _prevSlow = slow; return; }
		if (_prevFast == null || _prevSlow == null) { _prevFast = fast; _prevSlow = slow; return; }
		var prevAbove = _prevFast.Value > _prevSlow.Value;
		var currAbove = fast > slow;
		_prevFast = fast; _prevSlow = slow;
		if (!prevAbove && currAbove && Position <= 0) { if (Position < 0) BuyMarket(); BuyMarket(); }
		else if (prevAbove && !currAbove && Position >= 0) { if (Position > 0) SellMarket(); SellMarket(); }
	}
}