GitHub で見る

ウェーブパワー EA 戦略

Wave Power EA 戦略 は、MQL4 エキスパート アドバイザー「Wave Power EA1」の C# ポートです。オリジナルロボットがポジションを構築 確率シグナルまたは MACD シグナルの方向を調整し、固定ピップ数ごとに成行注文を追加します。 テイクプロフィットレベルを共有。 StockSharp バージョンは、高レベルの戦略 API、インジケーター バインディングを使用してこの動作を再現します。 組み込みの順序ヘルパー。必要に応じて、すべてのコメントは英語のままになります。

戦略の仕組み

  1. シグナル選択 – 最初の取引は、インジケーター フィルターの 1 つが方向を生成した場合にのみ開始されます。

    • Stochastic – 売られ過ぎ/買われ過ぎ領域内で %K が %D と交差しています。
    • MacdSlope – MACD ラインが前の値を上回るか下降します。
    • CciLevels – CCI が -120 を下回るか、+120 を超える。
    • AwesomeBreakout – 初期化中に捕捉された適応可能な過去の安値/高値を破る素晴らしいオシレーター。
    • RsiMa – 速い SMA が遅い SMA と交差し、RSI が勢いを確認します (50 以上/以下)。
    • SmaTrend – 最小の傾斜差で同じ方向を向く 15/20/25/50 SMA ファン。
  2. グリッド拡張 – 最初の成行注文が約定された後、ストラテジーは約定価格を記憶します。市場が動くたびに 現在のポジションに対して GridStepPips によって、最大注文数を超えていない場合、戦略は新しいマーケットを提出します 同じ方向に並べてください。新しいレイヤーごとに、ボリュームに Multiplier パラメータが乗算されます。

  3. 共有ターゲット – 新しい注文ごとに、共通のテイクプロフィット価格と (オプションで) ストップロス価格が再計算されます。 When the number of アクティブな注文が OrdersToProtect のしきい値に近づくと、テイクプロフィットディスタンスは ReboundProfitPrimary に置き換えられます。 しきい値を超えると、距離が ReboundProfitSecondary に切り替わり、より迅速な回復が促進されます。

  4. バスケットモニタリング – ローソクを閉じるたびに、ストラテジーはオープン損益をロットごとのピップに変換します。 If the rebound profit or 損失保護のしきい値に達すると、バスケット全体が成行注文を使用して清算されます。最年長の場合も同じことが起こります 取引が OrdersTimeAliveSeconds より古いか、金曜日の取引が無効になっている場合。

  5. ライフサイクル – バスケットがフラットになると、すべての内部カウンターがリセットされ、次の信号で新しい平均化を開始できるようになります。 cycle.

オリジナルの EA と比較して、このポートは一定数のグリッドの後に反対の (ヘッジ) ポジションをオープンすることを意図的に回避します。 layers.追加のエントリはすべて、最初の指示に従います。残りの資金管理ルール、保護ロジック、 インジケーター フィルターは、MQL4 リファレンス実装との互換性を維持します。

パラメーター

パラメータ 説明
EntryLogic 最初の注文に使用されるインジケーター モード。
CandleType すべてのインジケーターをフィードする時間枠 (デフォルト: 1 時間)。
InitialVolume ロット/契約における最初の注文のボリューム。
GridStepPips グリッドレイヤー間の最小距離(ピップ単位)。
MaxOrders バスケット内の最大同時注文数。
TakeProfitPips 共有テイクプロフィット距離 (ピップ単位) (0 はターゲットを無効にします)。
StopLossPips 共有ストップロス距離 (ピップ単位) (0 はストップを無効にします)。
Multiplier 追加注文ごとに適用されるボリューム乗数。
SecureProfitProtection リバウンド利益ロジックを有効にします。
OrdersToProtect リバウンド保護が開始されるまでに必要な注文数。
ReboundProfitPrimary 最初の保護ステージのロットあたりの利益 (pips 単位)。
ReboundProfitSecondary 保護された注文数を超えた場合のロットあたりの利益 (ピップ単位)。
LossProtection フローティングロスガードを有効にします。
LossThreshold バスケットがいっぱいになったときにガードがトリガーされる、ロットごとの損失 (ピップ単位)。
ReverseCondition 売買シグナルを反転します。
TradeOnFriday 金曜日に新しい注文を開始できるようになります。
OrdersTimeAliveSeconds 最新の注文の最大存続期間 (秒単位) (0 はタイマーを無効にします)。
TrendSlopeThreshold SmaTrend ロジックで使用される最小の SMA 勾配差。

使い方のヒント

  1. ピップ変換が正しく機能するように、構成された価格ステップを持つ証券にストラテジーをアタッチします。
  2. 商品のボラティリティとブローカーのマージンポリシーに従って、GridStepPipsMultiplier、および MaxOrders を調整します。
  3. ライブ口座で実行するときに保護ブロックを有効にして、長期にわたるトレンド中の暴走損失を防ぎます。
  4. この戦略は閉じたローソク足に依存しています。希望の取引リズムを反映する時間枠を選択します (元の EA は M30 を使用します) と H1 の組み合わせですが、デフォルトの H1 キャンドルはうまく機能します)。
  5. 5 番目のレイヤー以降のヘッジは実装されていないため、正確なオリジナルが必要な場合は、MaxOrders を下げることを検討してください。 行動。

ファイル

  • CS/WavePowerEAStrategy.cs – Wave Power EA グリッド ロジックの StockSharp 実装。
  • README.md / README_ru.md / README_zh.md – 英語、ロシア語、中国語のドキュメント。

Python のバージョンは、タスク要件に従って意図的に省略されています。

using System;

using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;

namespace StockSharp.Samples.Strategies;

/// <summary>
/// Wave Power strategy using RSI + EMA crossover for entry
/// with grid-like averaging on drawdown.
/// </summary>
public class WavePowerEAStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _fastPeriod;
	private readonly StrategyParam<int> _slowPeriod;
	private readonly StrategyParam<int> _rsiPeriod;
	private readonly StrategyParam<decimal> _gridStepPercent;
	private readonly StrategyParam<int> _maxGridOrders;

	private decimal _prevFast;
	private decimal _prevSlow;
	private decimal _entryPrice;
	private int _gridCount;

	public WavePowerEAStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(30).TimeFrame())
			.SetDisplay("Candle Type", "Timeframe.", "General");

		_fastPeriod = Param(nameof(FastPeriod), 5)
			.SetDisplay("Fast EMA", "Fast EMA period.", "Indicators");

		_slowPeriod = Param(nameof(SlowPeriod), 12)
			.SetDisplay("Slow EMA", "Slow EMA period.", "Indicators");

		_rsiPeriod = Param(nameof(RsiPeriod), 14)
			.SetDisplay("RSI Period", "RSI period.", "Indicators");

		_gridStepPercent = Param(nameof(GridStepPercent), 0.5m)
			.SetDisplay("Grid Step %", "Price move % to add to position.", "Grid");

		_maxGridOrders = Param(nameof(MaxGridOrders), 5)
			.SetDisplay("Max Grid Orders", "Maximum averaging orders.", "Grid");
	}

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

	public int FastPeriod
	{
		get => _fastPeriod.Value;
		set => _fastPeriod.Value = value;
	}

	public int SlowPeriod
	{
		get => _slowPeriod.Value;
		set => _slowPeriod.Value = value;
	}

	public int RsiPeriod
	{
		get => _rsiPeriod.Value;
		set => _rsiPeriod.Value = value;
	}

	public decimal GridStepPercent
	{
		get => _gridStepPercent.Value;
		set => _gridStepPercent.Value = value;
	}

	public int MaxGridOrders
	{
		get => _maxGridOrders.Value;
		set => _maxGridOrders.Value = value;
	}

	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();

		_prevFast = 0;
		_prevSlow = 0;
		_entryPrice = 0;
		_gridCount = 0;
	}

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

		var fast = new ExponentialMovingAverage { Length = FastPeriod };
		var slow = new ExponentialMovingAverage { Length = SlowPeriod };
		var rsi = new RelativeStrengthIndex { Length = RsiPeriod };

		var subscription = SubscribeCandles(CandleType);
		subscription
			.Bind(fast, slow, rsi, ProcessCandle)
			.Start();

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

	private void ProcessCandle(ICandleMessage candle, decimal fastVal, decimal slowVal, decimal rsiVal)
	{
		if (candle.State != CandleStates.Finished)
			return;

		if (_prevFast == 0 || _prevSlow == 0)
		{
			_prevFast = fastVal;
			_prevSlow = slowVal;
			return;
		}

		var close = candle.ClosePrice;
		var bullishCross = _prevFast <= _prevSlow && fastVal > slowVal;
		var bearishCross = _prevFast >= _prevSlow && fastVal < slowVal;

		// Exit on opposite cross
		if (Position > 0 && bearishCross)
		{
			SellMarket();
			_gridCount = 0;
			_entryPrice = 0;
		}
		else if (Position < 0 && bullishCross)
		{
			BuyMarket();
			_gridCount = 0;
			_entryPrice = 0;
		}

		// Grid averaging: add to position if price moved against us
		if (Position > 0 && _entryPrice > 0 && _gridCount < MaxGridOrders)
		{
			var dropPercent = (_entryPrice - close) / _entryPrice * 100;
			if (dropPercent >= GridStepPercent * (_gridCount + 1))
			{
				BuyMarket();
				_gridCount++;
			}
		}
		else if (Position < 0 && _entryPrice > 0 && _gridCount < MaxGridOrders)
		{
			var risePercent = (close - _entryPrice) / _entryPrice * 100;
			if (risePercent >= GridStepPercent * (_gridCount + 1))
			{
				SellMarket();
				_gridCount++;
			}
		}

		// New entry
		if (Position == 0)
		{
			if (bullishCross && rsiVal > 50)
			{
				_entryPrice = close;
				_gridCount = 0;
				BuyMarket();
			}
			else if (bearishCross && rsiVal < 50)
			{
				_entryPrice = close;
				_gridCount = 0;
				SellMarket();
			}
		}

		_prevFast = fastVal;
		_prevSlow = slowVal;
	}
}