GitHub で見る

Plateau戦略

Plateau戦略は、元のMetaTrader 5エキスパートアドバイザーを変換したものです。価格が下部バンド付近で取引されている場合の潜在的なリバーサルを検出するために、線形加重移動平均のペアとBollinger Bandsを組み合わせています。

トレーディングアイデア

  • 選択された平滑化方法と価格ソースを使用して高速および低速の移動平均を計算します。
  • 同じ価格シリーズの周りにBollinger Bandsを構築します。
  • 前のローソク足が下部バンドを下回ってクローズしながら高速平均が低速平均を上回ると、ロングポジションを開きます。
  • 前のローソク足が下部バンドを上回ってクローズしながら高速平均が低速平均を下回ると、ショートポジションを開きます。
  • Reverseスイッチが有効な場合、オプションでシグナルを反転します。

注文管理

  • ポジションは固定ロットまたは取引ごとにポートフォリオ価値のパーセンテージをリスクにさらすことでサイジングできます。
  • ストップロスとテイクプロフィットレベルはpipで表され、マーケット注文が約定した直後に設定されます。
  • トレーリング距離とステップの両方が正の場合、トレーリングストップを有効にできます。
  • Close Oppositeが有効な場合、戦略は新しい取引に入る前に自動的に反対のポジションを閉じます。

パラメーター

パラメーター 説明
Stop Loss pipでのストップロス距離。
Take Profit pipでのテイクプロフィット距離。
Trailing Stop pipでのトレーリングストップ距離。
Trailing Step トレーリングストップを動かすために必要な最小増分(pip単位)。
Money Mode 固定ロットとリスクパーセンテージのサイジングのどちらかを選択します。
Lot / Risk 選択されたマネーモードに応じた固定ロットサイズまたはリスクパーセンテージ。
Fast MA / Slow MA 移動平均ペアの期間。
MA Shift 両方の移動平均に適用される水平シフト。
MA Method 移動平均の平滑化アルゴリズム。
MA Price 移動平均計算に使用する価格ソース。
Bands Period Bollinger Bandsの平均化期間。
Bands Shift Bollinger Bands値に適用される水平シフト。
Bands Deviation Bollinger Bandsの標準偏差乗数。
Bands Price Bollinger Bands計算に使用する価格ソース。
Reverse ロングとショートのシグナルロジックを反転します。
Close Opposite 新しいポジションを開く前に反対方向の既存ポジションを閉じます。
Verbose Log 詳細な実行情報をログに印刷します。
Candle Type インジケーター計算に使用するローソク足データシリーズ。

注意事項

  • pip サイズは元のエキスパートの動作に合わせるために、3桁または5桁の小数点を持つインストゥルメントに自動的に調整されます。
  • トレーリングストップが有効な場合、トレーリングステップは厳密に正の値でなければなりません。そうでなければ、戦略は起動時にエラーをスローします。
  • リスクベースのポジションサイジングには、有効なストップロス距離とポートフォリオ評価データの両方が必要です。利用できない場合、戦略はデフォルトボリュームにフォールバックします。
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;

public class PlateauStrategy : Strategy
{
	private readonly StrategyParam<int> _fastPeriod;
	private readonly StrategyParam<int> _slowPeriod;
	private readonly StrategyParam<int> _stopLossPoints;
	private readonly StrategyParam<int> _takeProfitPoints;

	private ExponentialMovingAverage _fast;
	private ExponentialMovingAverage _slow;

	private decimal _prevFast;
	private decimal _prevSlow;
	private decimal _entryPrice;
	private int _cooldown;

	public int FastPeriod { get => _fastPeriod.Value; set => _fastPeriod.Value = value; }
	public int SlowPeriod { get => _slowPeriod.Value; set => _slowPeriod.Value = value; }
	public int StopLossPoints { get => _stopLossPoints.Value; set => _stopLossPoints.Value = value; }
	public int TakeProfitPoints { get => _takeProfitPoints.Value; set => _takeProfitPoints.Value = value; }

	public PlateauStrategy()
	{
		_fastPeriod = Param(nameof(FastPeriod), 15).SetGreaterThanZero().SetDisplay("Fast Period", "Fast EMA period", "Indicator");
		_slowPeriod = Param(nameof(SlowPeriod), 60).SetGreaterThanZero().SetDisplay("Slow Period", "Slow EMA period", "Indicator");
		_stopLossPoints = Param(nameof(StopLossPoints), 200).SetNotNegative().SetDisplay("Stop Loss", "Stop-loss in price steps", "Risk");
		_takeProfitPoints = Param(nameof(TakeProfitPoints), 400).SetNotNegative().SetDisplay("Take Profit", "Take-profit in price steps", "Risk");
	}

	public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
	{
		yield return (Security, TimeSpan.FromMinutes(5).TimeFrame());
	}

	protected override void OnReseted()
	{
		base.OnReseted();
		_fast = null; _slow = null;
		_prevFast = 0; _prevSlow = 0; _entryPrice = 0; _cooldown = 0;
	}

	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);
		_fast = new ExponentialMovingAverage { Length = FastPeriod };
		_slow = new ExponentialMovingAverage { Length = SlowPeriod };
		var subscription = SubscribeCandles(TimeSpan.FromMinutes(5).TimeFrame());
		subscription.Bind(_fast, _slow, ProcessCandle);
		subscription.Start();
	}

	private void ProcessCandle(ICandleMessage candle, decimal fastValue, decimal slowValue)
	{
		if (candle.State != CandleStates.Finished) return;
		if (!_fast.IsFormed || !_slow.IsFormed) { _prevFast = fastValue; _prevSlow = slowValue; return; }
		if (_cooldown > 0) { _cooldown--; _prevFast = fastValue; _prevSlow = slowValue; return; }

		var close = candle.ClosePrice;
		var step = Security?.PriceStep ?? 1m;

		if (Position > 0 && _entryPrice > 0)
		{
			if (StopLossPoints > 0 && close <= _entryPrice - StopLossPoints * step) { SellMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
			if (TakeProfitPoints > 0 && close >= _entryPrice + TakeProfitPoints * step) { SellMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
		}
		else if (Position < 0 && _entryPrice > 0)
		{
			if (StopLossPoints > 0 && close >= _entryPrice + StopLossPoints * step) { BuyMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
			if (TakeProfitPoints > 0 && close <= _entryPrice - TakeProfitPoints * step) { BuyMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
		}

		if (_prevFast <= _prevSlow && fastValue > slowValue && Position <= 0)
		{ if (Position < 0) BuyMarket(); BuyMarket(); _entryPrice = close; _cooldown = 100; }
		else if (_prevFast >= _prevSlow && fastValue < slowValue && Position >= 0)
		{ if (Position > 0) SellMarket(); SellMarket(); _entryPrice = close; _cooldown = 100; }

		_prevFast = fastValue; _prevSlow = slowValue;
	}
}