在 GitHub 上查看

Stochastic Automated 策略

该策略在选定的K线周期上使用 Stochastic 振荡器。当 %K 与 %D 进入极端区域并发生交叉时触发交易。每笔交易都设置固定的止盈和止损,并使用移动止损来锁定利润。

逻辑

  1. 入场
    • 做多:
      • 两根K线之前,%K 与 %D 都低于 OverSold
      • 两根K线之前 %D 在 %K 之上,而一根K线之前在 %K 之下。
      • %D 正在上升。
    • 做空:
      • 两根K线之前,%K 与 %D 都高于 OverBought
      • 两根K线之前 %D 在 %K 之下,而一根K线之前在 %K 之上。
      • %D 正在下降。
  2. 出场
    • 当 Stochastic 脱离极端区域或 %D 反转时平仓。
    • 如果价格回撤超过 TrailingStop,移动止损将退出头寸。
    • 每笔交易都应用全局 TakeProfitStopLoss

参数

名称 说明
CandleType Stochastic 计算所用的K线周期。
KPeriod %K 的回溯周期。
DPeriod %D 的平滑周期。
Slowing %K 的附加平滑。
OverBought 超买阈值。
OverSold 超卖阈值。
TakeProfit 入场到止盈的距离(价格单位)。
StopLoss 入场到止损的距离(价格单位)。
TrailingStop 移动止损的距离(价格单位)。

指标

  • StochasticOscillator

备注

  • 代码注释为英文。
  • 暂无 Python 版本。
using System;
using System.Linq;
using System.Collections.Generic;

using Ecng.Common;
using Ecng.Collections;
using Ecng.Serialization;

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

namespace StockSharp.Samples.Strategies;

/// <summary>
/// Stochastic oscillator based strategy.
/// Buys on K/D crossover in oversold, sells on crossover in overbought.
/// </summary>
public class StochasticAutomatedStrategy : Strategy
{
	private readonly StrategyParam<int> _kPeriod;
	private readonly StrategyParam<int> _dPeriod;
	private readonly StrategyParam<decimal> _overBought;
	private readonly StrategyParam<decimal> _overSold;
	private readonly StrategyParam<DataType> _candleType;

	private decimal? _prevK;
	private decimal? _prevD;

	public int KPeriod { get => _kPeriod.Value; set => _kPeriod.Value = value; }
	public int DPeriod { get => _dPeriod.Value; set => _dPeriod.Value = value; }
	public decimal OverBought { get => _overBought.Value; set => _overBought.Value = value; }
	public decimal OverSold { get => _overSold.Value; set => _overSold.Value = value; }
	public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }

	public StochasticAutomatedStrategy()
	{
		_kPeriod = Param(nameof(KPeriod), 14)
			.SetGreaterThanZero()
			.SetDisplay("%K Period", "Stochastic %K period", "Stochastic");

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

		_overBought = Param(nameof(OverBought), 80m)
			.SetDisplay("Overbought", "Overbought threshold", "Stochastic");

		_overSold = Param(nameof(OverSold), 20m)
			.SetDisplay("Oversold", "Oversold threshold", "Stochastic");

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

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

	protected override void OnReseted()
	{
		base.OnReseted();
		_prevK = _prevD = null;
	}

	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);

		var stochastic = new StochasticOscillator();
		stochastic.K.Length = KPeriod;
		stochastic.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;

		var stoch = (IStochasticOscillatorValue)stochValue;
		if (stoch.K is not decimal k || stoch.D is not decimal d)
			return;

		if (_prevK is decimal pk && _prevD is decimal pd)
		{
			// Buy: K crosses above D in oversold zone
			if (pk <= pd && k > d && pd < OverSold && Position <= 0)
				BuyMarket();

			// Sell: K crosses below D in overbought zone
			if (pk >= pd && k < d && pd > OverBought && Position >= 0)
				SellMarket();
		}

		_prevK = k;
		_prevD = d;
	}
}