在 GitHub 上查看

OHLC 随机指标策略

基于 OHLC 蜡烛图的动量跟随策略,核心为经典的 %K/%D 随机指标。 当指标在超买/超卖区域内交叉时触发交易,并通过按价格步长移动的跟踪止损保护浮动利润。

详情

  • 核心思想:利用随机指标在极值区域的 %K 与 %D 交叉来捕捉动量反转。
  • 入场条件
    • 做多
      • %K 上穿 %D,且至少一条线低于 LevelDown 阈值。
      • 若存在空头仓位,则先平仓再反手做多。
    • 做空
      • %K 下穿 %D,且至少一条线高于 LevelUp 阈值。
      • 若存在多头仓位,则先平仓再反手做空。
  • 出场条件
    • 触发跟踪止损(距离由 TrailingStopSteps 决定,移动需满足 TrailingStepSteps 的最小改进)。
    • 出现反向信号,策略将执行反向交易。
  • 跟踪止损逻辑
    • 距离与步进都会乘以标的的 PriceStep,从而把“点”转换为实际价格。
    • 只有当价格相对入场价突破 TrailingStopSteps + TrailingStepSteps 后,止损才会前移。
    • 多头与空头分别维护独立的跟踪止损价位。
  • 指标
  • 方向:多空双向。
  • 止损:仅使用跟踪止损,无固定 SL/TP。
  • 仓位管理:使用策略的 Volume 参数;反手时下单量为 Volume + |Position|
  • 默认参数
    • CandleType = TimeSpan.FromHours(12).TimeFrame()
    • KPeriod = 5
    • DPeriod = 3
    • Slowing = 3
    • LevelUp = 70
    • LevelDown = 30
    • TrailingStopSteps = 5(价格步长)
    • TrailingStepSteps = 2(价格步长)
  • 可视化
    • 支持显示蜡烛图、随机指标曲线以及策略成交点。

使用建议

  1. 启动前先设置交易标的与时间框架。
  2. 根据品种的最小报价单位调整 TrailingStopSteps,使其对应真实的“点数”。
  3. 策略调用 StartProtection(),可方便地叠加外部风控规则。
  4. 在趋势行情中表现最佳,因为随机指标交叉通常领先价格反转。
  5. 短周期或日内品种建议缩小跟踪距离,避免被噪音行情提前出场。
using System;
using System.Collections.Generic;

using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;

namespace StockSharp.Samples.Strategies;

public class OhlcStochasticStrategy : 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 OhlcStochasticStrategy()
	{
		_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() => [(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 < 30m && rsiVal >= 30m && Position <= 0) { if (Position < 0) BuyMarket(); BuyMarket(); }
		else if (_prevRsi.Value > 70m && rsiVal <= 70m && Position >= 0) { if (Position > 0) SellMarket(); SellMarket(); }
		_prevRsi = rsiVal;
	}
}