GitHub で見る

タグバゴールド戦略

概要

TugbaGold は、MetaTrader 5 を起源とするグリッドベースの平均化エキスパート アドバイザーです。変換された戦略は、StockSharp の高レベルの API を使用して、マーチンゲール ポジションのサイジングとバスケット管理ロジックを再作成します。このシステムは、前のローソク足が方向性のある勢いで閉じるたびに新しい注文を出し、設定可能な距離だけ離れたポジションのグリッドを徐々に構築します。平均化エグジットは、選択したモードに応じて、極端なポジションで利益を確定するか、バスケットを部分的に閉じることによって実行されます。

仕組み

  1. この戦略は、完成したローソク足を CandleType パラメータから評価します。シグナルは、元の MT5 ロジックと一致する 前の ローソク足を使用します。
  2. 強気のローソク足により、新しい買い注文を出すことができます。弱気のローソク足により、新しい売り注文が可能になります。
  3. 注文は、その方向の既存の最良価格からの距離が PointOrderStepPips を超える場合にのみ追加されます。
  4. 最初の注文では StartVolume を使用します。後続のエントリーでは、MaxVolume とブローカーの制限を尊重しながら、最も有利なポジションのボリュームが 2 倍になります。
  5. 少なくとも 2 つのポジションが存在すると、戦略は MinimalProfitPips バッファを含む目標価格を計算します。計算は終了モードごとに異なります。
    • 平均 – 極端なポジションと利益バッファーの加重平均。
    • 部分 – 最悪のチケットと最良のチケットの組み合わせ。最悪のチケットは StartVolume を使用し、最良のチケットは実際のサイズを使用します。
  6. 目標に達すると、戦略は対応する注文をクローズします。
    • 平均モード – 両方の極端なエントリを完全に閉じます。
    • 部分モード – 最悪のエントリを完全に閉じ、より良いエントリを StartVolume だけ減らします。
  7. 単一のスタンドアロン ポジションは、価格が設定された距離に達すると終了するために TakeProfitPips を使用します。

パラメーター

パラメータ 説明
TakeProfitPips ポジションが 1 つだけオープンしている場合に適用されるテイクプロフィット ディスタンス。無効にするには、0 に設定します。
StartVolume グリッド シーケンスの最初のオーダーの初期ボリューム。
MaxVolume 最大注文量。 0 は、倍増シーケンスを無制限に保ちます。
CloseMode 終了モード: Average (両極端を閉じる) または Partial (部分 + 完全に閉じる)。
PointOrderStepPips 新しい平均化注文を追加できるようになるまでの最小距離 (ピップ単位)。
MinimalProfitPips 平均化ターゲットに追加の利益バッファーが追加されました。
CandleType 信号評価に使用されるCandleシリーズ。

ポジション管理

  • 価格ステップは Security.PriceStep から導出されます。使用できない場合は、デフォルトの 0.0001 が使用されます。
  • ボリュームは、ブローカーの最小、最大、およびステップの制約に合わせて自動的に正規化されます。
  • この戦略は約定したポジションを内部で追跡し、バスケットの一部を閉じるときに成行注文 (BuyMarket / SellMarket) を発行します。
  • 戦略が開始されると、StartProtection() を通じて保護が自動的に有効になります。

注意事項と制限事項

  • この実装は、MT5 環境と同様に、成行注文の即時約定を前提としています。
  • シグナルの平均化は、現在の最良買値/売値に依存します。正確な実行のためにレベル 1 データが利用可能であることを確認します。
  • イグジットは戦略ロジックによって決定されるため、元のエキスパートのストップロス レベルは再現されません。
  • 慎重なリスク管理を使用します。傾向が続く場合、マーチンゲール サイジングは大きなリスクにつながる可能性があります。

変換の詳細

  • 平均化の計算式とバスケットの調整は、元のソース コードを反映しています。
  • ポジションの選択 (最良/最悪のチケット) は、各方向の最高および最低の始値を追跡することによって再現されます。
  • すべてのロジックは、低レベルのデータ アクセスに頼ることなく、StockSharp の高レベルの API を使用してキャンドル サブスクリプション内で実行されます。
namespace StockSharp.Samples.Strategies;

using System;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.Messages;

/// <summary>
/// TugbaGold strategy: candle direction + EMA trend filter with martingale-style averaging.
/// Buys on bullish candle above EMA, sells on bearish candle below EMA.
/// </summary>
public class TugbaGoldStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _emaPeriod;
	private bool _wasBullishSignal;
	private bool _hasPrevSignal;

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

	public TugbaGoldStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(60).TimeFrame())
			.SetDisplay("Candle Type", "Candle timeframe", "General");
		_emaPeriod = Param(nameof(EmaPeriod), 50)
			.SetGreaterThanZero()
			.SetDisplay("EMA Period", "EMA trend filter period", "Indicators");
	}

	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();
		_wasBullishSignal = false;
		_hasPrevSignal = false;
	}

	/// <inheritdoc />
	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);
		_wasBullishSignal = false;
		_hasPrevSignal = false;
		var ema = new ExponentialMovingAverage { Length = EmaPeriod };
		var subscription = SubscribeCandles(CandleType);
		subscription.Bind(ema, ProcessCandle).Start();
	}

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

		var bullish = candle.ClosePrice > candle.OpenPrice;
		var bearish = candle.ClosePrice < candle.OpenPrice;
		var bullishSignal = bullish && candle.ClosePrice > emaValue;
		var bearishSignal = bearish && candle.ClosePrice < emaValue;
		var crossedUp = bullishSignal && (!_hasPrevSignal || !_wasBullishSignal);
		var crossedDown = bearishSignal && (!_hasPrevSignal || _wasBullishSignal);

		if (crossedUp && Position <= 0)
			BuyMarket();
		else if (crossedDown && Position >= 0)
			SellMarket();

		if (bullishSignal || bearishSignal)
		{
			_wasBullishSignal = bullishSignal;
			_hasPrevSignal = true;
		}
	}
}