GitHub で見る

MA Trend 2戦略

概要

  • MetaTrader 5エキスパートアドバイザー MA Trend 2.mq5 から変換。
  • 設定可能な移動平均を使用して、価格がシフトした平均の上下どちらで取引されているかを検出します。
  • ポジションはオプションのストップロス、テイクプロフィット、トレーリングストップ、マネー管理機能で管理されます。

戦略ロジック

  1. ユーザー選択のロウソク足シリーズを購読し、選択した方法、期間、シフト、価格ソースで移動平均を計算します。
  2. 各確定ロウソク足で最新の移動平均値を保存し、シフトされたサンプル(前のバーに MaShift を加えたもの)を現在の終値と比較できるようにします。
  3. 価格が参照平均を上回り、方向フィルターがロング取引を許可している場合に買いシグナルを生成します。逆の条件に対して売りシグナルを生成します。ReverseSignals が有効な場合、これらのルールは反転します。
  4. 取引に入る前に、OnlyOnePositionCloseOppositePositions フラグを確認します。戦略は反対のエクスポージャーが存在する場合にエントリーをスキップするか、同じ注文で閉じてポジションをフリップできます。
  5. ポジションサイジングは固定ボリュームまたは元のEAから派生したリスクパーセントモデルを使用します。パーセントモードは、設定されたストップ距離での損失がリスクバジェットと一致するように必要なボリュームを推定します。
  6. トレーリングストップは元のステップロジックを再現します:利益が TrailingStopPips + TrailingStepPips を超えると、ストップを決して緩めずにステップで移動します。価格がトレーリングストップを越えると、ポジションは成行で閉じられます。
  7. オプションのストップロスとテイクプロフィット保護は、高レベルの StartProtection ヘルパーを通じてアタッチされ、証券会社モデルがロウソク足更新間でポジションを閉じられるようにします。

パラメーター

名前 説明 デフォルト値
StopLossPips pip単位のストップロス距離。無効化するには 0 に設定。 50
TakeProfitPips pip単位のテイクプロフィット距離。無効化するには 0 に設定。 140
TrailingStopPips pip単位のトレーリングストップの基本距離。 15
TrailingStepPips トレーリングストップが引き締められる前の最小追加利益。 5
LotMode FixedVolumeLotOrRiskValue を直接使用。RiskPercent は口座リスクパーセントとして解釈します。 RiskPercent
LotOrRiskValue LotMode によって固定注文サイズまたはリスクパーセント。 3
MaPeriod 移動平均の期間。 12
MaShift 現在のバーとシグナルに使用する移動平均サンプルの間の確定ロウソク足の数。 3
MaMethod 移動平均メソッド(SimpleExponentialSmoothedLinearWeighted)。 LinearWeighted
MaPrice 移動平均が使用するロウソク足価格(終値、始値、加重など)。 Weighted
CandleType 戦略が購読するロウソク足データタイプ。 1 minute time frame
Direction 許可する方向(BuyOnlySellOnlyBoth)。 Both
OnlyOnePosition 単一のオープンポジションのみを許可。 false
ReverseSignals 買い/売りロジックを反転。 false
CloseOppositePositions 新しい取引を開く前に反対のエクスポージャーを閉じる。 false

マネー管理

  • LotMode = RiskPercent の場合、戦略は証券メタデータ(PriceStepStepPrice)を使用してストップロス距離(pip単位)を価格単位に変換します。
  • リスクはポートフォリオ値(CurrentValueBeginValue へのフォールバックあり)から計算されます。
  • 要求されたボリュームは取引所の拒否を避けるために最も近い VolumeStep に切り上げられます。

トレーリングストップ

  • トレーリング距離とステップはpipで表現されます;コードは楽器のpipサイズを使用して実際の価格距離を導出します。
  • ロングポジションは終値が少なくとも TrailingStopPips + TrailingStepPips だけエントリーを超えると、ストップを上に移動します。利益が戻るとストップは固定のままです。
  • ショートポジションは対称的な価格チェックで同じロジックを反映します。

変換上の注意事項

  • すべての取引アクションは高レベルの Strategy API(BuyMarketSellMarketStartProtection)を使用します。
  • 戦略は大きなデータセットを保存せずに前のバー参照を再現するために、短い移動平均履歴(シフト+バッファ)のみを保持します。
  • コメントは各主要なロジックブロックを文書化するために英語で提供されています。
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 MaTrend2Strategy : 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 MaTrend2Strategy()
	{
		_fastPeriod = Param(nameof(FastPeriod), 14).SetGreaterThanZero().SetDisplay("Fast Period", "Fast EMA period", "Indicator");
		_slowPeriod = Param(nameof(SlowPeriod), 50).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;
	}
}