在 GitHub 上查看

Exp XRSI Histogram Vol 策略

概述

该策略是原始 MQL5 专家顾问 Exp_XRSI_Histogram_Vol 的 C# 移植版本。它通过解析体积加权 RSI 直方图的五种颜色状态来交易突破。脚本在 StockSharp 的高级策略 API 上实现,可使用任意通过订阅获得的时间框架蜡烛。

策略逻辑

  1. 在选定时间框架上计算 RSI,并减去 50 使振荡器居中。
  2. 将居中的 RSI 值乘以所选的成交量流(勾号或真实成交量),以强调成交活跃的蜡烛。
  3. 使用相同的移动平均方法与长度对加权 RSI 和原始成交量进行平滑处理。
  4. 通过四个用户定义的倍数与平滑成交量相乘构建自适应阈值,并将直方图划分为以下颜色状态:
    • 0 – 强烈的多头动能(高于 HighLevel2)。
    • 1 – 中等多头动能(介于 HighLevel1HighLevel2 之间)。
    • 2 – 中性区。
    • 3 – 中等空头动能(介于 LowLevel2LowLevel1 之间)。
    • 4 – 强烈的空头动能(低于 LowLevel2)。
  5. 进出场规则与 MQL 版本一致:
    • 当直方图从高于状态 1 的区域跌入状态 1 时开立第一笔多单。
    • 当直方图从高于状态 0 的区域跌入状态 0 时开立第二笔多单。
    • 当直方图从低于状态 3 的区域升入状态 3 时开立第一笔空单。
    • 当直方图从低于状态 4 的区域升入状态 4 时开立第二笔空单。
    • 直方图处于状态 01 时平掉所有空单。
    • 直方图处于状态 34 时平掉所有多单。
  6. 通过 SignalBar 参数可以回溯若干个已收盘的柱体,以模拟原指标缓冲区的索引方式。

每个方向支持两次加仓,分别由 Mm1Mm2 倍数控制。辅助方法会在开仓前先平掉反向头寸,以复制旧版交易管理代码的行为。

资金管理与保护

  • Mm1Mm2 作为体积倍数应用于策略的 Volume 属性(当 Volume 未设置时默认使用 1)。
  • 当品种存在有效的价格步长且相应点值为正时,会通过 StartProtection 启用全局止损与止盈。它们都被解读为价格步长的数量。

参数

参数 说明
CandleType 用于计算指标的蜡烛时间框架。
RsiPeriod RSI 长度。
VolumeMode 选择使用勾号成交量或真实成交量。若成交量缺失,勾号模式会退化为 1。
HighLevel2, HighLevel1, LowLevel1, LowLevel2 平滑成交量的倍数,用于构建直方图阈值。
MaMethod, MaLength, MaPhase 平滑设置。Parabolic、T3、VIDYA、AMA 等缺少原生实现的方法会退化为 SMA;MaPhase 仅在 Jurik 等高级方法中生效。
SignalBar 读取直方图颜色时回溯的已收盘柱数量。
Mm1, Mm2 每个方向第一次和第二次建仓的体积倍数。
BuyPosOpen, SellPosOpen, BuyPosClose, SellPosClose 控制是否允许开仓或平仓多/空头寸。
StopLossPoints, TakeProfitPoints 以价格步长数量表示的保护性止损与止盈。

默认值

  • 蜡烛类型:4 小时。
  • RSI 长度:14。
  • 成交量模式:勾号成交量。
  • 阈值:HighLevel2 = 17HighLevel1 = 5LowLevel1 = -5LowLevel2 = -17
  • 平滑:SMA,长度 12,相位 15。
  • 信号柱偏移:1。
  • 资金管理:Mm1 = 0.1Mm2 = 0.2
  • 止损 / 止盈:分别为 1000 与 2000 点(仅在存在有效价格步长时生效)。

注意事项

  • 策略仅使用已收盘蜡烛,忽略未完成的数据更新。
  • StockSharp 内置的 JurikMovingAverage 可用于 Jurik 平滑;ParMA、T3、VIDYA、AMA 等旧方法会退化为 SMA。
  • 指标读取蜡烛的 TotalVolume。当成交量为零时,勾号模式会使用 1 作为权重以避免信号被抑制。
  • 策略默认在图表上绘制 RSI、蜡烛与成交记录,必要时可添加更多诊断图层。
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>
/// Exp XRSI Histogram Vol strategy. Uses RSI level crossovers.
/// </summary>
public class ExpXrsiHistogramVolStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _rsiPeriod;

	private decimal? _prevRsi;

	public DataType CandleType
	{
		get => _candleType.Value;
		set => _candleType.Value = value;
	}

	public int RsiPeriod
	{
		get => _rsiPeriod.Value;
		set => _rsiPeriod.Value = value;
	}

	public ExpXrsiHistogramVolStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).TimeFrame())
			.SetDisplay("Candle Type", "Timeframe", "General");

		_rsiPeriod = Param(nameof(RsiPeriod), 14)
			.SetGreaterThanZero()
			.SetDisplay("RSI Period", "RSI lookback", "Indicators");
	}

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

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

	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);
		_prevRsi = null;
		var rsi = new RelativeStrengthIndex { Length = RsiPeriod };
		var subscription = SubscribeCandles(CandleType);
		subscription.Bind(rsi, ProcessCandle).Start();
		var area = CreateChartArea();
		if (area != null) { DrawCandles(area, subscription); DrawOwnTrades(area); }
	}

	private void ProcessCandle(ICandleMessage candle, decimal rsiVal)
	{
		if (candle.State != CandleStates.Finished) return;
		if (!IsFormedAndOnlineAndAllowTrading()) { _prevRsi = rsiVal; return; }
		if (_prevRsi == null) { _prevRsi = rsiVal; return; }
		if (_prevRsi.Value < 45m && rsiVal >= 55m && Position <= 0) { if (Position < 0) BuyMarket(); BuyMarket(); }
		else if (_prevRsi.Value > 55m && rsiVal <= 45m && Position >= 0) { if (Position > 0) SellMarket(); SellMarket(); }
		_prevRsi = rsiVal;
	}
}