在 GitHub 上查看

烛形模式测试策略

概述

Candle Patterns Test Strategy 是 MetaTrader 5 指标 CandlePatternsTest EA 的 StockSharp 高级版实现。策略会在每根完成的 K 线上寻找经典的日本蜡烛形态,并在出现看涨或看跌结构时开仓。该移植版本保留了原始 EA 的形态识别逻辑,同时利用 StockSharp 的风控与数据订阅接口。

交易逻辑

  1. 订阅蜡烛:订阅参数指定的蜡烛类型,仅在蜡烛收盘后执行形态检测。
  2. 平均实体过滤:计算蜡烛实体长度的简单移动平均,只有实体大于平均值的蜡烛才参与判断,对应原始代码中的 AvgBody 函数。
  3. 形态识别:检测以下组合:
    • 三白兵 / 三只乌鸦
    • 刺透形态 / 乌云盖顶
    • 早晨十字星 / 黄昏十字星
    • 看涨吞没 / 看跌吞没
    • 看涨孕线 / 看跌孕线
    • 会合线
  4. 入场管理:识别出看涨形态时以市价买入,看跌形态则市价卖出。若出现反向信号,会先平仓后反手。
  5. 离场管理:根据平均实体计算止损与止盈水平,并在每根收盘蜡烛上检查是否触发。

参数

参数 说明
CandleType 订阅的蜡烛数据类型,默认 1 小时。
AverageBodyPeriod 计算平均实体长度的蜡烛数量。
EnableBullishPatterns 是否允许看涨形态开多。
EnableBearishPatterns 是否允许看跌形态开空。
StopLossFactor 止损距离与平均实体的倍数。
TakeProfitFactor 止盈距离与平均实体的倍数。

所有参数均通过 StrategyParam<T> 暴露,可在界面中配置或用于优化。

图表

若可用,策略会绘制:

  • 订阅的蜡烛
  • 用于趋势背景的收盘价均线
  • 策略成交记录

与原始 EA 的差异

  • 原始 MQ5 中的新闻过滤、交易时间、对冲开单以及网格尾随等功能被省略,专注于形态交易核心。
  • 风险控制简化为基于平均实体的对称止损/止盈模型。
  • 使用 StockSharp 的 BuyMarket / SellMarket 方法管理头寸,而非手动下单。

使用建议

  • 根据所需周期设置 CandleType,周期越大信号越少但质量越高。
  • 调整 AverageBodyPeriod 以匹配当前波动率;较小的周期响应更快但噪声也更大。
  • 可优化 StopLossFactorTakeProfitFactor 以适配具体品种。

环境要求

  • 已配置的 StockSharp 环境及可生成目标蜡烛的行情源。
  • 所选交易所需能提供连续且无重叠的蜡烛序列。
namespace StockSharp.Samples.Strategies;

using System;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.Messages;

/// <summary>
/// Candle Patterns Test strategy: Doji + trend reversal.
/// Buys on doji in downtrend (below EMA), sells on doji in uptrend (above EMA).
/// </summary>
public class CandlePatternsTestStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _emaPeriod;
	private readonly StrategyParam<int> _signalCooldownCandles;
	private int _candlesSinceTrade;

	public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
	public int EmaPeriod { get => _emaPeriod.Value; set => _emaPeriod.Value = value; }
	public int SignalCooldownCandles { get => _signalCooldownCandles.Value; set => _signalCooldownCandles.Value = value; }

	public CandlePatternsTestStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(60).TimeFrame())
			.SetDisplay("Candle Type", "Candle timeframe", "General");
		_emaPeriod = Param(nameof(EmaPeriod), 50)
			.SetGreaterThanZero()
			.SetDisplay("EMA Period", "EMA trend filter", "Indicators");
		_signalCooldownCandles = Param(nameof(SignalCooldownCandles), 6)
			.SetGreaterThanZero()
			.SetDisplay("Signal Cooldown", "Bars to wait between trades", "Trading");
	}

	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();
		_candlesSinceTrade = SignalCooldownCandles;
	}

	/// <inheritdoc />
	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);
		_candlesSinceTrade = SignalCooldownCandles;
		var ema = new ExponentialMovingAverage { Length = EmaPeriod };
		var subscription = SubscribeCandles(CandleType);
		subscription.Bind(ema, ProcessCandle).Start();
	}

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

		if (_candlesSinceTrade < SignalCooldownCandles)
			_candlesSinceTrade++;

		var body = Math.Abs(candle.ClosePrice - candle.OpenPrice);
		var range = candle.HighPrice - candle.LowPrice;
		if (range <= 0) return;

		// Doji: body is very small relative to range
		var isDoji = body < range * 0.05m;

		var close = candle.ClosePrice;

		if (isDoji && close < emaValue && Position <= 0 && _candlesSinceTrade >= SignalCooldownCandles)
		{
			BuyMarket();
			_candlesSinceTrade = 0;
		}
		else if (isDoji && close > emaValue && Position >= 0 && _candlesSinceTrade >= SignalCooldownCandles)
		{
			SellMarket();
			_candlesSinceTrade = 0;
		}
	}
}