GitHub で見る

Stochastic 自動化戦略

この戦略は、選択されたローソク足の時間軸で Stochasticオシレーター を使用して取引します。%Kと%Dが極端なゾーンに入るのを待ち、クロスオーバーを利用してポジションを開きます。固定のテイクプロフィットとストップロスが各取引を保護し、トレーリングストップが利益を確保します。

ロジック

  1. エントリー
    • ロング:
      • 2本前のローソク足で%Kと%Dの両方が OverSold を下回っている。
      • 2本前のローソク足で%Dが%Kを上回り、1本前のローソク足で%Kを下回っている。
      • %Dが上昇している。
    • ショート:
      • 2本前のローソク足で%Kと%Dの両方が OverBought を上回っている。
      • 2本前のローソク足で%Dが%Kを下回り、1本前のローソク足で%Kを上回っている。
      • %Dが下落している。
  2. エグジット
    • StochasticがEzoneから出るか、%Dが反対方向に転換するとポジションをクローズ。
    • 価格が TrailingStop 分だけ押し戻された場合、トレーリングストップが発動。
    • グローバルな TakeProfitStopLoss がすべての取引に適用される。

パラメーター

名前 説明
CandleType Stochastic計算の時間軸。
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;
	}
}