在 GitHub 上查看

随机指标 Komposter 策略

该策略移植自 MQL5 专家 Exp_iStochKomposter,利用随机振荡指标在动量反转时进行交易。

工作原理

  • 在选定时间框架上计算随机振荡指标。
  • 当 %K 线向上穿越下阈值(默认 30)时产生买入信号。
  • 当 %K 线向下穿越上阈值(默认 70)时产生卖出信号。
  • 每次出现信号时,策略会平掉相反方向的头寸,并以市价单开仓新头寸。
  • 通过 StartProtection 应用可选的止损和止盈。

参数

名称 说明 默认值
KPeriod %K 线计算周期 5
DPeriod %D 线平滑周期 3
UpLevel 触发卖出的超买阈值 70
DownLevel 触发买入的超卖阈值 30
StopLoss 绝对价格单位的止损 1000
TakeProfit 绝对价格单位的止盈 2000
CandleType 计算所用时间框架 1 小时

说明

  • 策略仅在完整收盘的K线下工作。
  • 原始指标中的 ATR 仅用于绘制箭头,本策略未使用。
  • 持仓量由策略的 Volume 属性决定。
using System;
using System.Collections.Generic;

using Ecng.Common;

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

namespace StockSharp.Samples.Strategies;

/// <summary>
/// Strategy using Stochastic Oscillator crossovers.
/// Opens long when %K crosses above the lower level and opens short when crossing below the upper level.
/// </summary>
public class StochKomposterStrategy : Strategy
{
	private readonly StrategyParam<int> _kPeriod;
	private readonly StrategyParam<int> _dPeriod;
	private readonly StrategyParam<decimal> _upLevel;
	private readonly StrategyParam<decimal> _downLevel;
	private readonly StrategyParam<DataType> _candleType;

	private decimal? _prevK;

	public int KPeriod { get => _kPeriod.Value; set => _kPeriod.Value = value; }
	public int DPeriod { get => _dPeriod.Value; set => _dPeriod.Value = value; }
	public decimal UpLevel { get => _upLevel.Value; set => _upLevel.Value = value; }
	public decimal DownLevel { get => _downLevel.Value; set => _downLevel.Value = value; }
	public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }

	public StochKomposterStrategy()
	{
		_kPeriod = Param(nameof(KPeriod), 5)
			.SetGreaterThanZero()
			.SetDisplay("K Period", "Stochastic %K calculation period", "Indicators");

		_dPeriod = Param(nameof(DPeriod), 3)
			.SetGreaterThanZero()
			.SetDisplay("D Period", "Stochastic %D smoothing period", "Indicators");

		_upLevel = Param(nameof(UpLevel), 70m)
			.SetDisplay("Upper Level", "Overbought threshold", "Indicators");

		_downLevel = Param(nameof(DownLevel), 30m)
			.SetDisplay("Lower Level", "Oversold threshold", "Indicators");

		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
			.SetDisplay("Candle Type", "Timeframe for strategy", "General");
	}

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

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

	/// <inheritdoc />
	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);

		_prevK = null;

		var stochastic = new StochasticOscillator
		{
			K = { Length = KPeriod },
			D = { Length = DPeriod },
		};

		var subscription = SubscribeCandles(CandleType);
		subscription.BindEx(stochastic, ProcessCandle).Start();

		var area = CreateChartArea();
		if (area != null)
		{
			DrawCandles(area, subscription);
			DrawIndicator(area, stochastic);
			DrawOwnTrades(area);
		}
	}

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

		if (!IsFormedAndOnlineAndAllowTrading())
			return;

		if (stochValue is not IStochasticOscillatorValue value || value.K is not decimal k)
			return;

		if (_prevK is null)
		{
			_prevK = k;
			return;
		}

		var prev = _prevK.Value;

		// %K crosses above lower level -> buy
		if (prev <= DownLevel && k > DownLevel && Position <= 0)
			BuyMarket();
		// %K crosses below upper level -> sell
		else if (prev >= UpLevel && k < UpLevel && Position >= 0)
			SellMarket();

		_prevK = k;
	}
}