在 GitHub 上查看

Potential Entries 策略

概述

Potential Entries Strategy 复刻了 EA_PotentialEntries.mq5 智能交易系统的思想。策略每次评估最近两根已经收盘的蜡烛,寻找反转或动能累积形态。当检测到预设模式时,只在选定方向(做多或做空)开仓,对应模式通过 Pattern Side 参数切换。入场后会根据两根蜡烛的极值重新计算保护价位,从而与原始 MetaTrader 版本的止损设置保持一致。

该实现基于 StockSharp 的高级 API:订阅所需的蜡烛数据,在 ProcessCandle 方法中处理序列,使用 BuyMarket/SellMarket 下达市价单,并在内部记录的止损价被突破时用市价单离场。图表会绘制蜡烛序列以及策略成交,方便快速验证信号。

数据与参数

分组 名称 说明
General Pattern Side 模式方向:Bullish 仅搜索做多信号,Bearish 仅搜索做空信号。
Trading Trade Volume 每次入场使用的市价单手数。开仓前会先平掉相反方向的持仓。
General Candle Type 用于识别形态的蜡烛类型(默认使用 1 小时 K 线)。

交易逻辑

策略对比当前完成的蜡烛(C1)与上一根蜡烛(C2),所有影线和实体长度都以价格单位计算。

做多模式

Pattern Side = Bullish 时,满足以下任一条件即开多:

  1. Bullish Hammer(看涨锤子线)
    • C1 为阳线,C2 为阴线。
    • C1 下影线至少为实体的两倍,且大于上影线的三倍。
    • 发送买入市价单,并把止损设置在 C1C2 的最低价中较低的一侧。
  2. Bullish Inverted Hammer(看涨倒锤子线)
    • C1 为阳线,C2 为阴线。
    • C1 上影线至少为实体的两倍,同时至少是下影线的三倍。
    • 按照同样规则买入并设置止损。
  3. Bullish Momentum(动能增强)
    • C1C2 都是阳线。
    • C1 的振幅大于 C2,且实体至少是 C2 的两倍。
    • 开多后把止损放在两根蜡烛最低价的较小值。

做空模式

Pattern Side = Bearish 时,满足以下任一条件即开空:

  1. Shooting Star(流星线)
    • C1 为阴线,C2 为阳线。
    • C1 上影线至少为实体的两倍,且至少是下影线的三倍。
    • 下达卖出市价单,并把止损放在 C1C2 的最高价中较高的一侧。
  2. Hanging Man(上吊线)
    • C1 为阴线,C2 为阳线。
    • C1 下影线至少为实体的两倍,并且超过上影线的三倍。
    • 按同样方式开空并更新止损位置。
  3. Bearish Momentum(动能增强向下)
    • C1C2 都是阴线。
    • C1 的实体大于 C2,且振幅至少是 C2 的两倍。
    • 建立空头仓位,止损位于两根蜡烛最高价的最大值。

止损与仓位管理

  • 策略一次只运行一个方向。如果出现反向信号,会先平掉现有反向仓位再开新单。
  • 每次入场都会记录一个新的止损价,基于最新两根蜡烛的极值。之后每根已完成蜡烛都会检查是否击穿该水平,若触发则以市价单离场。
  • 当没有持仓时,会清除保存的止损值,避免重复使用过期价格。

使用提示

  • 根据需求选择 BullishBearish 模式以扫描多头或空头机会。
  • 默认的小时蜡烛可以替换为任意可用的蜡烛数据类型。
  • 按要求暂未提供 Python 版本,也未创建 PY 目录,仅包含 C# 实现。
  • 策略没有设置固定的盈利目标,退出完全依赖止损或人工干预。
namespace StockSharp.Samples.Strategies;

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

/// <summary>
/// Potential Entries strategy: two-candle reversal patterns with RSI confirmation.
/// Detects bullish/bearish reversals and trades with RSI filter.
/// </summary>
public class PotentialEntriesStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _rsiPeriod;
	private readonly StrategyParam<int> _signalCooldownCandles;

	private readonly List<ICandleMessage> _candles = new();
	private int _candlesSinceTrade;

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

	public PotentialEntriesStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(30).TimeFrame())
			.SetDisplay("Candle Type", "Candle timeframe", "General");
		_rsiPeriod = Param(nameof(RsiPeriod), 14)
			.SetGreaterThanZero()
			.SetDisplay("RSI Period", "RSI period", "Indicators");
		_signalCooldownCandles = Param(nameof(SignalCooldownCandles), 6)
			.SetGreaterThanZero()
			.SetDisplay("Signal Cooldown", "Bars to wait between trades", "Trading");
	}

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

	/// <inheritdoc />
	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);
		_candles.Clear();
		_candlesSinceTrade = SignalCooldownCandles;
		var rsi = new RelativeStrengthIndex { Length = RsiPeriod };
		var subscription = SubscribeCandles(CandleType);
		subscription.Bind(rsi, ProcessCandle).Start();
	}

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

		if (_candlesSinceTrade < SignalCooldownCandles)
			_candlesSinceTrade++;

		_candles.Add(candle);
		if (_candles.Count > 5)
			_candles.RemoveAt(0);

		if (_candles.Count >= 2)
		{
			var curr = _candles[^1];
			var prev = _candles[^2];

			// Bullish reversal: prev bearish, curr bullish with higher close
			var bullish = prev.OpenPrice > prev.ClosePrice
				&& curr.ClosePrice > curr.OpenPrice
				&& curr.ClosePrice > prev.OpenPrice;

			// Bearish reversal: prev bullish, curr bearish with lower close
			var bearish = prev.ClosePrice > prev.OpenPrice
				&& curr.OpenPrice > curr.ClosePrice
				&& curr.ClosePrice < prev.OpenPrice;

			if (bullish && rsiValue < 50 && Position <= 0 && _candlesSinceTrade >= SignalCooldownCandles)
			{
				BuyMarket();
				_candlesSinceTrade = 0;
			}
			else if (bearish && rsiValue > 50 && Position >= 0 && _candlesSinceTrade >= SignalCooldownCandles)
			{
				SellMarket();
				_candlesSinceTrade = 0;
			}
		}
	}
}