GitHub で見る

ColorXdinMA 標準偏差戦略

この戦略は、MQL5エキスパート Exp_ColorXdinMA_StDev のStockSharp移植版です。 2つの移動平均を XdinMA という単一のラインに組み合わせ、その時系列変化を追跡します。 現在の XdinMA 値と前の値の差が、最近の標準偏差の倍数と比較されます。 変化がプラスの閾値を超えるとロングポジションが開設され、マイナスの閾値を下回るとショートポジションが開設されます。

機能の仕組み

  1. 2つの単純移動平均を計算します:
    • Main MAMainLength で定義される期間。
    • Plus MAPlusLength で定義される期間。
  2. カスタムライン XdinMA = 2 * MainMA - PlusMA を構築します。
  3. 連続するローソク足間の XdinMA の変化を、長さ StdPeriod の標準偏差インジケーターに渡します。
  4. 変化が K1 * StdDev より大きい場合、買い注文が出されます。-K1 * StdDev より小さい場合、売り注文が出されます。新規ポジションを開く前に既存の反対ポジションが決済されます。

パラメーター

パラメーター 説明
MainLength 主移動平均の期間。
PlusLength 副移動平均の期間。
StdPeriod 標準偏差に使用するバーの数。
K1 偏差閾値の乗数。
K2 第2フィルターの将来拡張用に予約済み。

すべてのパラメーターは StrategyParam を通じて公開されており、最適化したり ユーザーインターフェースから変更したりすることができます。

備考

  • 完成したローソク足のみが処理されます。
  • 戦略は成行注文を使用し、ストップロスやテイクプロフィットのロジックは実装されていません。
  • チャートの描画には、視覚的分析のために両方の移動平均と実行されたトレードが含まれます。
using System;
using System.Collections.Generic;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
using StockSharp.Algo;

namespace StockSharp.Samples.Strategies;

/// <summary>
/// Strategy based on difference of two moving averages with standard deviation filter.
/// Buys when xdin change exceeds K1*StdDev, sells when below -K1*StdDev.
/// </summary>
public class ColorXdinMAStDevStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _mainLength;
	private readonly StrategyParam<int> _plusLength;
	private readonly StrategyParam<int> _stdPeriod;
	private readonly StrategyParam<decimal> _k1;

	private StandardDeviation _stdDev;
	private decimal? _prevXdin;

	public ColorXdinMAStDevStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
			.SetDisplay("Candle type", "Type of candles", "General");

		_mainLength = Param(nameof(MainLength), 10)
			.SetDisplay("Main MA Length", "Length of primary moving average", "Parameters");

		_plusLength = Param(nameof(PlusLength), 20)
			.SetDisplay("Plus MA Length", "Length of secondary moving average", "Parameters");

		_stdPeriod = Param(nameof(StdPeriod), 9)
			.SetDisplay("StdDev Period", "Period for standard deviation of MA changes", "Parameters");

		_k1 = Param(nameof(K1), 0.5m)
			.SetDisplay("Filter K1", "Multiplier for standard deviation filter", "Parameters");
	}

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

	public int MainLength
	{
		get => _mainLength.Value;
		set => _mainLength.Value = value;
	}

	public int PlusLength
	{
		get => _plusLength.Value;
		set => _plusLength.Value = value;
	}

	public int StdPeriod
	{
		get => _stdPeriod.Value;
		set => _stdPeriod.Value = value;
	}

	public decimal K1
	{
		get => _k1.Value;
		set => _k1.Value = value;
	}

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

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

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

		_prevXdin = null;
		_stdDev = new StandardDeviation { Length = StdPeriod };
		Indicators.Add(_stdDev);

		var mainMa = new ExponentialMovingAverage { Length = MainLength };
		var plusMa = new ExponentialMovingAverage { Length = PlusLength };

		var subscription = SubscribeCandles(CandleType);
		subscription
			.Bind(mainMa, plusMa, ProcessCandle)
			.Start();

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

	private void ProcessCandle(ICandleMessage candle, decimal mainValue, decimal plusValue)
	{
		if (candle.State != CandleStates.Finished)
			return;

		// xdin = extrapolated price using MA difference
		var xdin = mainValue * 2m - plusValue;

		if (_prevXdin is null)
		{
			_prevXdin = xdin;
			return;
		}

		var change = xdin - _prevXdin.Value;
		_prevXdin = xdin;

		var stdResult = _stdDev.Process(new DecimalIndicatorValue(_stdDev, change, candle.ServerTime) { IsFinal = true });
		if (!_stdDev.IsFormed)
			return;

		var stDev = stdResult.ToDecimal();
		if (stDev == 0)
			return;

		if (!IsFormedAndOnlineAndAllowTrading())
			return;

		var filter = K1 * stDev;

		if (change > filter && Position <= 0)
			BuyMarket();
		else if (change < -filter && Position >= 0)
			SellMarket();
	}
}