GitHub で見る

カジノ111戦略

概要

Casino111 は、同じ名前の MetaTrader 4 エキスパート アドバイザーに由来するカウンター トレンド ブレイクアウト システムです。新しいバーごとに、戦略は現在の始値を前の日次ローソク足から導出された基準レベルと比較します。開いたギャップが毎日の極値 (および設定可能なバッファー) を超えた場合、アルゴリズムは直ちに反対方向に市場ポジションを開き、対称的なストップロス / テイクプロフィット保護に依存します。 StockSharp ポートは、元のロボットの単一位置の動作を維持し、研究と最適化のための広範なパラメータ化を追加します。

エントリーとエグジットのロジック

  1. 過去の日次高値と安値は、専用の日次キャンドル サブスクリプションから取得されます。 MetaTrader ポイントで表される 2 つのオフセット (UpperOffsetPointsLowerOffsetPoints) は、参照チャネルを拡張します。
  2. 終了した取引キャンドルごとに、戦略は以前のオープンと現在のオープンを検査します。
    • 新しい始値が日次高値と上限オフセットを上回った場合、ショート ポジションがオープンされます (ギャップのフェード)。
    • 新しい始値が日次安値から下限オフセットを引いた値を下回ると、ロング ポジションがオープンされます。
  3. 一度に許可されるポジションは 1 つだけです。新しいシグナルが考慮される前に、アクティブな注文が約定される必要があります。
  4. StartProtection は元の固定ストップとテイク ターゲットを反映しており、両方ともエントリー価格から BetPoints 離れた位置にあります (価格ステップに変換)。

お金の管理

  • UseMoneyManagement = false は取引サイズを固定します (BaseVolume)。
  • UseMoneyManagement = true は、MT4 コードに見られるマーチンゲール数列を有効にします。
    • 損失または損益分岐点取引が行われるたびに、次の注文量に (BetPoints * 2) / (BetPoints - spreadPoints) が乗算されます。
    • スプレッドは、オーダーブックのサブスクリプションを通じて収集された最新の最良買値/売値から推定されます。引用符が使用できない場合、乗数はデフォルトで 2 に設定されます。
    • 勝利はポジションサイズを BaseVolume にリセットします。すべてのボリュームは楽器 VolumeStep に合わせて調整され、MaxVolume によって上限が設定されます。

パラメーター

名前 種類 デフォルト 説明
EnableBuy bool true 日次チャネルを下回るギャップによってトリガーされるロングエントリーを許可します。
EnableSell bool true 日次チャネルを上回るギャップによってトリガーされる短いエントリーを許可します。
BetPoints decimal 400 MetaTrader ポイント単位の対称のストップロスとテイクプロフィット距離 (StockSharp の価格ステップに変換)。
UpperOffsetPoints decimal 97 弱気のギャップ反転を検出するために、前の毎日の高値を上回るバッファーが追加されました。
LowerOffsetPoints decimal 77 強気のギャップ反転を検出するために、前の毎日の安値を下回るバッファーが差し引かれます。
UseMoneyManagement bool false マーチンゲール形式のロット進行を有効にします。
MaxVolume decimal 4 資金管理がアクティブな場合に計算されたボリュームに適用される上限。
BaseVolume decimal 0.1 利益のある取引後、または資金管理が無効になっている場合に使用される開始注文サイズ。
CandleType DataType H1 オープンギャップ条件の評価に使用される主な時間枠 (デフォルトは 1 時間)。
DailyCandleType DataType D1 前日の高値/安値を供給するローソク足タイプ(デフォルトは1日)。

実装メモ

  • この戦略は、StockSharp のハイレベルな API に依存しています。SubscribeCandles は取引と毎日のストリームの両方を提供し、SubscribeOrderBook は資金管理乗数の最新のスプレッドを維持します。
  • StartProtection はストップロスとテイクプロフィットの両方のレッグを管理するため、MT4 と同様に、すべてのエントリーはすぐに対称的なエグジットを受け取ります。
  • 英語のインライン コメントは、メンテナンスを容易にするために各決定ポイントを強調表示します。
  • すべての計算ではインジケーター履歴の検索が回避されます。現在のローソク足のオープン値のみが必要で、MetaTrader の Time[0] / Open[0] ロジックをミラーリングします。

使い方のヒント

  • 自分の研究に合った取引時間枠を選択してください。デフォルトの 1 時間足ローソク足は一般的な MT4 設定を複製していますが、StockSharp でサポートされている任意の DataType を指定できます。
  • 資金管理を使用するときは、MaxVolume がブローカーの制限を遵守していることを確認してください。アライメントヘルパーは結果を VolumeStepMinVolume、および MaxVolume にクランプします。
  • システムは常に最大でも 1 つのポジションをオープン状態に保つため、手動検査用にエントリー/エグジット マーカーをプロットする StockSharp チャートとよく組み合わせます。
  • ライブ会場に接続する前に、リプレイ環境内で戦略をテストします。ギャップフェードのアプローチは積極的であり、信頼性の高いスプレッドに依存します。
using System;

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

namespace StockSharp.Samples.Strategies;

/// <summary>
/// Casino111: RSI overbought/oversold reversal with ATR stops.
/// </summary>
public class Casino111Strategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _rsiLength;
	private readonly StrategyParam<int> _atrLength;
	private readonly StrategyParam<int> _emaLength;

	private decimal _prevRsi;
	private decimal _entryPrice;

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

		_rsiLength = Param(nameof(RsiLength), 14)
			.SetDisplay("RSI Length", "RSI period.", "Indicators");

		_atrLength = Param(nameof(AtrLength), 14)
			.SetDisplay("ATR Length", "ATR period.", "Indicators");

		_emaLength = Param(nameof(EmaLength), 50)
			.SetDisplay("EMA Length", "Trend filter.", "Indicators");
	}

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

	public int RsiLength
	{
		get => _rsiLength.Value;
		set => _rsiLength.Value = value;
	}

	public int AtrLength
	{
		get => _atrLength.Value;
		set => _atrLength.Value = value;
	}

	public int EmaLength
	{
		get => _emaLength.Value;
		set => _emaLength.Value = value;
	}

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

		_prevRsi = 0;
		_entryPrice = 0;
	}

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

		_prevRsi = 0;
		_entryPrice = 0;

		var rsi = new RelativeStrengthIndex { Length = RsiLength };
		var atr = new AverageTrueRange { Length = AtrLength };
		var ema = new ExponentialMovingAverage { Length = EmaLength };

		var subscription = SubscribeCandles(CandleType);
		subscription
			.Bind(rsi, atr, ema, ProcessCandle)
			.Start();

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

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

		if (_prevRsi == 0 || atrVal <= 0)
		{
			_prevRsi = rsiVal;
			return;
		}

		var close = candle.ClosePrice;

		if (Position > 0)
		{
			if (close >= _entryPrice + atrVal * 2.5m || close <= _entryPrice - atrVal * 1.5m || rsiVal > 70)
			{
				SellMarket();
				_entryPrice = 0;
			}
		}
		else if (Position < 0)
		{
			if (close <= _entryPrice - atrVal * 2.5m || close >= _entryPrice + atrVal * 1.5m || rsiVal < 30)
			{
				BuyMarket();
				_entryPrice = 0;
			}
		}

		if (Position == 0)
		{
			if (rsiVal > 50 && _prevRsi <= 50 && close > emaVal)
			{
				_entryPrice = close;
				BuyMarket();
			}
			else if (rsiVal < 50 && _prevRsi >= 50 && close < emaVal)
			{
				_entryPrice = close;
				SellMarket();
			}
		}

		_prevRsi = rsiVal;
	}
}