GitHub で見る

ランダム戦略で

概要

この戦略は、MetaTrader 5 エキスパート アドバイザー「ランダム」(MQL ID 39835) の StockSharp 移植です。オリジナルのボットは、常に市場に存在することが強制された場合に、純粋にランダムな決定プロセスがどのように動作するかを示しています。完了したバーごとにコイン投げがトリガーされ、次のアクションが買いか売りかを決定します。 StockSharp バージョンは同じアイデアを保持していますが、それを高レベルの API プリミティブ (SubscribeCandlesBuyMarketSellMarket) で表現しており、デザイナーまたはランナーとスムーズに統合されています。

この実装では、テイクプロフィット、ストップロス、またはトレーリングストップを意図的に回避し、リファレンス MQL スクリプトをミラーリングしています。したがって、これは収益性の高い戦略ではなく、テストの手段または教育的な例として機能します。

取引ロジック

  1. 設定されたキャンドル シリーズ (CandleType) をサブスクライブします。 MetaTrader の「現在のタイムフレーム」動作を模倣するため、デフォルトの間隔は 15 分です。
  2. ローソク足が終了したらすぐに、前の取引を閉じる必要があるかどうかを確認します。 CloseBeforeReversal が有効な場合、戦略はポジションをフラット化し、エクスポージャが残っていないことの確認を待ってから次の注文を発行します。
  3. 擬似乱数発生器を使用してランダムな方向を生成します。オプションの RandomSeed パラメータを使用すると、再現可能なバックテストの決定的シーケンスが可能になります。
  4. 固定の TradeVolume を使用して成行注文を送信します。ロングとショートの取引は対称的であり、保護命令はありません。 LogSignals を介してロギングを有効にして、ランダムな決定を追跡できます。

各ローソク足はランダムな決定を 1 つだけトリガーするため、戦略はフラットであるか、常に 1 つのポジションを保持します。ポジションは、次のバーが表示されたときにのみ反転またはクローズされます。

注文管理とリスク

  • すべてのエントリと終了は、構成されたボリュームを使用して BuyMarket / SellMarket で実行されます。指値注文や逆指値注文はありません。
  • CloseBeforeReversal が無効になっている場合、戦略はポジションを連続して保持する可能性があります。新しいランダム シグナルにより、前の取引を最初に明示的にクローズすることなく、反対側をすぐにオープンできます。
  • 資金管理やアカウント保護は実装されていません。移植の目的は、教育およびインフラストラクチャのテスト シナリオでの参照エキスパート アドバイザの動作を再現することです。

パラメーター

パラメータ 説明
TradeVolume すべてのランダムなエントリーに使用される基本注文サイズ。ポジティブであり続けなければなりません。
CloseBeforeReversal 次のランダムな取引を行う前に、戦略に現在のポジションを強制的にクローズさせます。
LogSignals ランダムな方向が生成されるたびに、AddInfoLog メッセージを書き込みます。
CandleType ランダムなコイン投げを駆動するローソク足シリーズを生成するタイムフレーム。
RandomSeed 擬似乱数生成器のシード値。システム クロックに依存するには、0 を使用します。

使用上の注意

  • このポートには、MQL リファレンスと同様に、テイクプロフィットとストップロスのレベルが存在しません。戦略が実物資本を用いた実験に使用される場合は、リスク管理を手動で追加する必要があります。
  • 決定論的シードは、ランダムな動作を最適化またはベンチマークするときに、再現可能なデータセットを作成するのに役立ちます。
  • 純粋なランダム戦略ではチャート上に視覚的なフィードバックがほとんどないため、テスト中にログを有効にすることをお勧めします。
using System;

using Ecng.Common;

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

namespace StockSharp.Samples.Strategies;

/// <summary>
/// Strategy that randomly opens long or short positions based on a random threshold.
/// Mirrors the "At random" MetaTrader expert.
/// </summary>
public class AtRandomStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _randomSeed;

	private Random _random;
	private int _barCount;

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

	public int RandomSeed
	{
		get => _randomSeed.Value;
		set => _randomSeed.Value = value;
	}

	public AtRandomStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(60).TimeFrame())
			.SetDisplay("Candle Type", "Timeframe that triggers random decisions", "Data");

		_randomSeed = Param(nameof(RandomSeed), 42)
			.SetDisplay("Random Seed", "Seed for the pseudo random generator (0 = system clock)", "Diagnostics");
	}

	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);

		_random = RandomSeed == 0 ? new Random() : new Random(RandomSeed);
		_barCount = 0;

		var subscription = SubscribeCandles(CandleType);
		subscription
			.Bind(ProcessCandle)
			.Start();

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

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

		_barCount++;

		// Only trade occasionally to keep turnover within runner limits.
		if (_random.Next(0, 6) != 0)
			return;

		var volume = Volume;
		if (volume <= 0)
			volume = 1;

		// Random direction
		var goLong = _random.Next(0, 2) == 0;

		if (goLong)
		{
			if (Position <= 0)
				BuyMarket(Position < 0 ? Math.Abs(Position) + volume : volume);
		}
		else
		{
			if (Position >= 0)
				SellMarket(Position > 0 ? Math.Abs(Position) + volume : volume);
		}
	}

	/// <inheritdoc />
	protected override void OnReseted()
	{
		_random = null;
		_barCount = 0;

		base.OnReseted();
	}
}