在 GitHub 上查看

Previous Candle Breakdown 2

该策略复刻 MetaTrader 专家顾问“Previous Candle Breakdown 2”的逻辑。算法在可配置的时间周期上追踪最新收盘的蜡烛, 当价格上破其最高价或下破最低价并超过指定点差时触发交易。可选的均线过滤器、严格的交易时段限制、固定 或百分比风险头寸规模控制以及多层保护性止损机制,使原始 MQL 版本能够在 StockSharp 环境中运行。

概览

  • 入场条件:当价格突破上一根蜡烛最高价加上偏移量时做多;突破最低价减去偏移量时做空。
  • 过滤条件:可选的快慢均线(支持位移参数)需给出方向确认,交易还会受限于开始与结束时间窗口。
  • 仓位规模:可设定固定下单手数,或根据账户权益和止损距离按风险百分比自动计算手数。
  • 风险控制:以点数定义的止损与止盈、带阶梯的跟踪止损,以及达到 ProfitClose 时的全局平仓。
  • 加仓限制MaxPositions 用于限制每个方向上的净持仓规模。

默认参数

  • IndentPips = 10
  • FastPeriod = 10,FastShift = 3,SlowPeriod = 30,SlowShift = 0,MaMethod = Simple
  • StopLossPips = 50,TakeProfitPips = 150
  • TrailingStopPips = 15,TrailingStepPips = 5
  • ProfitClose = 100(实现金额 + 浮动盈亏的货币数值)
  • MaxPositions = 10(每个方向允许的最大净合约/手数)
  • OrderVolume = 0(禁用),RiskPercent = 5(当 OrderVolume 为 0 且启用止损时生效)
  • StartTime = 09:09,EndTime = 19:19
  • CandleType = 4 小时蜡烛

交易流程

  1. 订阅所选蜡烛序列并保存每根已收盘的蜡烛。
  2. 检查当前时间是否位于允许的交易区间内;若 ProfitClose 达标则立即平仓。
  3. 以上一根蜡烛的最高价和最低价为基础,加/减点差得到突破价位。
  4. 当价格突破这些价位并满足均线条件(若已启用)时,在 MaxPositions 限制内开仓。
  5. 基于入场价设置初始止损与止盈,并在价格朝有利方向运行到至少“跟踪距离 + 阶梯距离”后激活跟踪止损。
  6. 每根蜡烛检查是否触发止损/止盈,更新跟踪止损,并在仓位关闭后重置保护参数。

说明

  • 点值会根据 3 位或 5 位小数的品种自动调整,以匹配 MetaTrader 中的 Point→Pip 转换。
  • 使用风险百分比时,策略会依据组合当前价值与止损距离估算下单手数。
  • 策略基于已完成蜡烛的高低价判断突破,因此不会在未收盘的波动中重复触发。
  • MaxPositions 针对策略的净持仓;若使用小数手数,该参数代表允许的最大绝对净头寸。
  • 图表会绘制蜡烛、启用时的均线以及成交记录,便于复核策略行为。
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>
/// Previous candle breakdown strategy v2.
/// Trades breakout of previous candle high/low filtered by EMA crossover.
/// </summary>
public class PreviousCandleBreakdown2Strategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _fastPeriod;
	private readonly StrategyParam<int> _slowPeriod;
	private decimal? _prevHigh;
	private decimal? _prevLow;
	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 PreviousCandleBreakdown2Strategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame()).SetDisplay("Candle Type", "Timeframe", "General");
		_fastPeriod = Param(nameof(FastPeriod), 10).SetGreaterThanZero().SetDisplay("Fast EMA", "Fast EMA period", "Indicators");
		_slowPeriod = Param(nameof(SlowPeriod), 30).SetGreaterThanZero().SetDisplay("Slow EMA", "Slow EMA period", "Indicators");
	}

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

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

	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);
		_prevHigh = null; _prevLow = null; _prevFast = null; _prevSlow = null;
		var fast = new ExponentialMovingAverage { Length = FastPeriod };
		var slow = new ExponentialMovingAverage { 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())
		{
			_prevHigh = candle.HighPrice;
			_prevLow = candle.LowPrice;
			_prevFast = fast;
			_prevSlow = slow;
			return;
		}
		if (_prevHigh == null || _prevLow == null || _prevFast == null || _prevSlow == null)
		{
			_prevHigh = candle.HighPrice; _prevLow = candle.LowPrice; _prevFast = fast; _prevSlow = slow;
			return;
		}
		var close = candle.ClosePrice;
		var bullTrend = fast > slow;
		var bearTrend = fast < slow;
		if (bullTrend && close > _prevHigh.Value && Position <= 0)
		{
			if (Position < 0) BuyMarket();
			BuyMarket();
		}
		else if (bearTrend && close < _prevLow.Value && Position >= 0)
		{
			if (Position > 0) SellMarket();
			SellMarket();
		}
		_prevHigh = candle.HighPrice; _prevLow = candle.LowPrice; _prevFast = fast; _prevSlow = slow;
	}
}