GitHub で見る

Lossless MA戦略

この戦略は、速い単純移動平均(SMA)と遅いSMAのクロスオーバーで取引します。 逆シグナルが現れたとき、損失ポジションを損益分岐点に移動させることで、損失の実現を任意に回避します。

動作の仕組み

  1. インジケーター
    • 速いSMA
    • 遅いSMA
  2. エントリー
    • 速いSMA > 遅いSMA かつ現在の方向がロングでない場合にロング
    • 速いSMA < 遅いSMA かつ現在の方向がショートでない場合にショート
    • Close Losses が無効で、オープン取引数が Max Deals を下回る場合、追加エントリーが許可されます。
  3. エグジット
    • 逆のクロスオーバー時。
    • Close Losses が有効な場合、ポジションは即座に閉じられます。
    • Close Losses が無効で取引が損失状態の場合、損益分岐点で退出するためにエントリー価格で指値注文が発注されます。

パラメーター

名前 説明 デフォルト
FastLength 速いSMAの期間。 10
SlowLength 遅いSMAの期間。 30
MaxDeals 同時取引の最大数。 5
CloseLosses 損失取引を即座に閉じる。 true
Volume 注文ボリューム。 1
CandleType 計算用のローソク足。 1-minute

注意事項

戦略はエントリーとエグジットに成行注文を使用します。CloseLosses が無効の場合、損失で閉じる代わりにエントリー価格で指値注文を発注してポジションを保護しようとします。

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>
/// Lossless Moving Average strategy.
/// Trades fast and slow SMA crossovers.
/// </summary>
public class LosslessMaStrategy : Strategy
{
	private readonly StrategyParam<int> _fastLength;
	private readonly StrategyParam<int> _slowLength;
	private readonly StrategyParam<DataType> _candleType;

	private decimal? _prevFast;
	private decimal? _prevSlow;

	/// <summary>
	/// Fast SMA period.
	/// </summary>
	public int FastLength { get => _fastLength.Value; set => _fastLength.Value = value; }

	/// <summary>
	/// Slow SMA period.
	/// </summary>
	public int SlowLength { get => _slowLength.Value; set => _slowLength.Value = value; }

	/// <summary>
	/// Type of candles used for calculations.
	/// </summary>
	public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }

	/// <summary>
	/// Constructor.
	/// </summary>
	public LosslessMaStrategy()
	{
		_fastLength = Param(nameof(FastLength), 10)
			.SetGreaterThanZero()
			.SetDisplay("Fast MA", "Fast SMA length", "Parameters");

		_slowLength = Param(nameof(SlowLength), 30)
			.SetGreaterThanZero()
			.SetDisplay("Slow MA", "Slow SMA length", "Parameters");

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

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

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

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

		var fastMa = new ExponentialMovingAverage { Length = FastLength };
		var slowMa = new ExponentialMovingAverage { Length = SlowLength };

		var subscription = SubscribeCandles(CandleType);

		subscription
			.Bind(fastMa, slowMa, ProcessCandle)
			.Start();

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

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

		if (!IsFormedAndOnlineAndAllowTrading())
			return;

		var prevFast = _prevFast;
		var prevSlow = _prevSlow;

		_prevFast = fastValue;
		_prevSlow = slowValue;

		if (prevFast is null || prevSlow is null)
			return;

		// Bullish crossover
		if (prevFast <= prevSlow && fastValue > slowValue && Position <= 0)
		{
			if (Position < 0)
				BuyMarket();
			BuyMarket();
		}

		// Bearish crossover
		if (prevFast >= prevSlow && fastValue < slowValue && Position >= 0)
		{
			if (Position > 0)
				SellMarket();
			SellMarket();
		}
	}
}