GitHub で見る

Up3x1 投資家範囲フィルター戦略

概要

この戦略は、MetaTrader 4 エキスパート アドバイザー up3x1_Investor を直接移植したものです。設定可能な時間枠 (デフォルトでは H1) から完成したローソク足を使用して単一の商品を取引します。このポートは、StockSharp の高レベル API を使用して元のロジックを複製し、明確なリスク管理パラメータを追加します。

取引ロジック

  • この戦略は、最後に完全に閉じたローソク足を評価し、次のことを確認します。
    • ローソク足の範囲(高値から安値を引いたもの)が 0.0060 価格単位を超えています。
    • ローソク本体(始値と終値の絶対差)が 0.0050 価格単位を超えています。
  • ローソク足が強気で終了し、上記の条件が満たされた場合、この戦略は ロング 市場ポジションを開きます。
  • ローソク足が弱気で終了し、条件が満たされた場合、この戦略は ショート 市場ポジションを開きます。
  • 月曜日は取引が完全に無効になります(MQL コードからの DayOfWeek()==1 ガードを反映するため)。

ポジション管理

  • 開始すると、戦略は構成されたステップベースの距離を使用して内部目標を設定します。
    • TakeProfitPoints → 利益目標までの距離。
    • StopLossPoints → 保護停止距離。
    • TrailingStopPoints → 価格が有利に推移した場合にストップを追跡するために使用される距離。
  • ストップとターゲットは、完成したローソク足ごとに評価されます。
    • 価格が目標価格に達すると、ポジションは目標価格でクローズされます。
    • 価格がストップに達すると、損失を制限するためにポジションがクローズされます。
    • 価格が後続距離を超えて上昇すると、利益を確定するためにストップを市場価格に近づけます。
  • さらに、同じローソク足で計算された 24 期間と 60 期間の単純移動平均が(1 価格ステップ内で)等しくなった場合、ポジションは直ちにクローズされます。これは、両方の平均が正確に一致したときに注文がクローズされる MQL ロジックを模倣しています。

量とリスクの管理

  • BaseVolume は、アカウントベースの調整を計算できない場合のフォールバック ロット サイズを定義します。
  • MaximumRisk は元の AccountFreeMargin()*MaximumRisk/1000 式を複製します。ポートフォリオ値が利用可能な場合、ストラテジーはポジションを value * MaximumRisk / 1000 としてサイズ設定し、小数点第 1 位に四捨五入します。
  • DecreaseFactor は連敗削減を模倣します。複数の連続損失の後、ボリュームは losses / DecreaseFactor に比例して減少します。
  • MinimumVolume は、ボリュームが MQL スクリプトで使用される取引可能な最小サイズ (0.1 ロット) を下回らないようにします。

パラメーター

名前 デフォルト 説明
BaseVolume 0.1 リスク調整が適用されない場合のロットの基準ポジションサイズ。
MaximumRisk 0.2 アカウントの資本からボリュームを導き出すために使用されるリスク係数 (元の EA と同じ)。
DecreaseFactor 3 連続損失の後、ポジションサイズを減らします。
MinimumVolume 0.1 許容される最小のボリューム。
TakeProfitPoints 20 価格ステップで測定される利益目標距離。
StopLossPoints 50 価格ステップで測定されるストップロス距離。
TrailingStopPoints 10 価格ステップで測定されるトレーリングストップ距離。
SkipMondays true 月曜日にはすべての取引活動を無効にします。
CandleType 1 hour キャンドルのサブスクリプションの期間。

注意事項

  • この戦略は、元の CalculateCurrentOrders ガードと一致する、一度に 1 つのポジションのみをオープン状態に保ちます。
  • StockSharp ブローカーは MetaTrader の注文履歴を公開しないため、連続損失追跡は純粋に内部的なものです。
  • 未決注文は使用されません。すべての取引は、BuyMarket および SellMarket を介して成行注文として送信されます。
using System;







using StockSharp.Algo.Indicators;



using StockSharp.Algo.Strategies;



using StockSharp.BusinessEntities;



using StockSharp.Messages;







namespace StockSharp.Samples.Strategies;







public class Up3x1InvestorRangeFilterStrategy : Strategy



{



	private readonly StrategyParam<int> _emaPeriod;



	private readonly StrategyParam<int> _atrPeriod;



	private readonly StrategyParam<DataType> _candleType;







	private decimal _prevClose; private decimal _prevEma; private bool _hasPrev;



	private int _cooldown;







	public int EmaPeriod { get => _emaPeriod.Value; set => _emaPeriod.Value = value; }



	public int AtrPeriod { get => _atrPeriod.Value; set => _atrPeriod.Value = value; }



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







	public Up3x1InvestorRangeFilterStrategy()



	{



		_emaPeriod = Param(nameof(EmaPeriod), 14).SetDisplay("EMA Period", "EMA lookback", "Indicators");



		_atrPeriod = Param(nameof(AtrPeriod), 14).SetDisplay("ATR Period", "ATR lookback", "Indicators");



		_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(30).TimeFrame()).SetDisplay("Candle Type", "Candle timeframe", "General");



	}







	/// <inheritdoc />



	protected override void OnReseted()



	{



		base.OnReseted();



		_prevClose = default;



		_prevEma = default;



		_hasPrev = default;



		_cooldown = default;



	}







	/// <inheritdoc />



	/// <inheritdoc />

	protected override void OnStarted2(DateTime time)



	{



		base.OnStarted2(time);



		_hasPrev = false;



		var ema = new ExponentialMovingAverage { Length = EmaPeriod };



		var subscription = SubscribeCandles(CandleType);



		subscription.Bind(ema, ProcessCandle).Start();



	}







	private void ProcessCandle(ICandleMessage candle, decimal ema)



	{



		if (candle.State != CandleStates.Finished) return;



		if (!IsFormedAndOnlineAndAllowTrading()) return;



		var close = candle.ClosePrice;



		if (!_hasPrev) { _prevClose = close; _prevEma = ema; _hasPrev = true; return; }



		if (_cooldown > 0)



		{



			_cooldown--;



			_prevClose = close; _prevEma = ema;



			return;



		}







		if (_prevClose <= _prevEma && close > ema && Position <= 0)



		{



			var volume = Volume + Math.Abs(Position);



			BuyMarket(volume);



			_cooldown = 6;



		}



		else if (_prevClose >= _prevEma && close < ema && Position >= 0)



		{



			var volume = Volume + Math.Abs(Position);



			SellMarket(volume);



			_cooldown = 6;



		}



		_prevClose = close; _prevEma = ema;



	}



}