在 GitHub 上查看

AH HM RSI 策略

概述

该策略是 MetaTrader 智能交易系统 Expert_AH_HM_RSI 的 StockSharp 移植版本。策略在已收盘的 K 线中寻找锤子线或上吊线,并使用相对强弱指数(RSI)进行确认。风险管理与原版 EA 一致:当出现新的反向信号时立即反手。

交易逻辑

  1. 趋势过滤:使用一个非常短周期的简单移动平均线(默认周期为 2)来判断市场处于微弱上升还是下降趋势。
  2. K 线形态:分析最新收盘的 K 线。
    • 锤子线 条件:K 线实体位于全日波动范围的上三分之一,开收盘价格低于前一根 K 线,并且该 K 线的中点位于移动平均线下方。
    • 上吊线 条件:K 线实体位于上三分之一,开收盘价格高于前一根 K 线,并且该 K 线的中点位于移动平均线上方。
  3. RSI 过滤
    • 做多信号要求 RSI 低于锤子线阈值(默认 40)。
    • 做空信号要求 RSI 高于上吊线阈值(默认 60)。
  4. 执行方式:当信号成立时,以 Volume + |Position| 的数量下单,使得当前持仓在出现反向信号时会立刻反转,与原始 EA 行为一致。
  5. 离场规则:当 RSI 向上突破下轨(默认 30)或向下跌破上轨(默认 70)时,平掉相应方向的仓位,再现原始代码中的“投票”退出逻辑。

指标

  • RelativeStrengthIndex(默认周期 33)。
  • SimpleMovingAverage(默认周期 2,基于收盘价)。

参数

名称 说明 默认值
Volume 每次开仓使用的数量。 1
RsiPeriod RSI 的计算周期。 33
MaPeriod 趋势过滤用的移动平均周期。 2
HammerRsiThreshold 允许锤子线进场的 RSI 上限。 40
HangingManRsiThreshold 允许上吊线进场的 RSI 下限。 60
LowerExitLevel RSI 向上突破时平空的阈值。 30
UpperExitLevel RSI 向下跌破时平多的阈值。 70
CandleType 使用的 K 线周期。 1 小时 K 线

所有参数都可以通过 StockSharp 的参数界面进行优化。

使用提示

  • 策略仅在确认收盘的 K 线上工作,确保所选周期的数据是完整的。
  • 由于使用 Volume + |Position| 下单,反向信号会立即反手。
  • 启动时会调用 StartProtection(),只需执行一次即可激活内置保护模块。
namespace StockSharp.Samples.Strategies;

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

/// <summary>
/// Hammer/Hanging Man + RSI strategy.
/// Buys on hammer with low RSI, sells on hanging man with high RSI.
/// </summary>
public class AhHmRsiStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _rsiPeriod;
	private readonly StrategyParam<decimal> _rsiLow;
	private readonly StrategyParam<decimal> _rsiHigh;

	public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
	public int RsiPeriod { get => _rsiPeriod.Value; set => _rsiPeriod.Value = value; }
	public decimal RsiLow { get => _rsiLow.Value; set => _rsiLow.Value = value; }
	public decimal RsiHigh { get => _rsiHigh.Value; set => _rsiHigh.Value = value; }

	public AhHmRsiStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame())
			.SetDisplay("Candle Type", "Candle timeframe", "General");
		_rsiPeriod = Param(nameof(RsiPeriod), 14)
			.SetGreaterThanZero()
			.SetDisplay("RSI Period", "RSI period", "Indicators");
		_rsiLow = Param(nameof(RsiLow), 40m)
			.SetDisplay("RSI Low", "RSI oversold threshold for buy", "Signals");
		_rsiHigh = Param(nameof(RsiHigh), 60m)
			.SetDisplay("RSI High", "RSI overbought threshold for sell", "Signals");
	}

	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);
		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;

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

		var upperShadow = candle.HighPrice - Math.Max(candle.OpenPrice, candle.ClosePrice);
		var lowerShadow = Math.Min(candle.OpenPrice, candle.ClosePrice) - candle.LowPrice;

		var isHammer = lowerShadow > body * 2 && upperShadow < body;
		var isHangingMan = upperShadow > body * 2 && lowerShadow < body;

		if (isHammer && rsiValue < RsiLow && Position <= 0)
			BuyMarket();
		else if (isHangingMan && rsiValue > RsiHigh && Position >= 0)
			SellMarket();
	}
}