GitHub で見る

RAVI + Awesome Oscillator 戦略

概要

  • MetaTrader 5 エキスパートアドバイザー「Ravi AO(barabashkakvn版)」をStockSharpの高レベルAPIにポートしたもの。
  • Range Action Verification Index(RAVI)とAwesome Oscillator(AO)を組み合わせて、同期した強気および弱気のモメンタムシフトを検出します。
  • StockSharpがサポートする任意の時間軸と銘柄で動作します;すべての数値設定は元の実装に近づけるためにpipsで表現されています。

インジケーター

  • RAVI – 選択した価格系列で100 * (FastMA - SlowMA) / SlowMAとして計算されます。平滑化メソッド(単純、指数、平滑、加重)、長さ、価格ソース(クローズ、オープン、ハイ、ロー、メジアン、典型値、加重、シンプル、クォーター、トレンドフォロー、Demark)を選択できます。
  • Awesome Oscillator – 設定可能な短期・長期のメジアン価格モメンタムインジケーター。デフォルト値はMT5の値(5と34)と一致します。

パラメーター

名前 説明
CandleType 購読するキャンドルの時間軸またはデータタイプ。
StopLossPips pipsでの保護ストップロス距離。0はストップを無効にします。
TakeProfitPips pipsでのテイクプロフィット距離。0はテイクプロフィットを無効にします。
TrailingStopPips pipsでのベーストレーリングストップ距離。0はトレーリングを無効にします。
TrailingStepPips トレーリングストップが引き締められる前に必要な最小追加利益(pips)。トレーリングが有効な場合は> 0でなければなりません。
FastMethod / FastLength RAVI高速移動平均の平滑化メソッドと長さ。
SlowMethod / SlowLength RAVI低速移動平均の平滑化メソッドと長さ。
AppliedPrices 両方のRAVI平均が使用する価格式(クローズ、オープン、ハイ、ロー、メジアン、典型値、加重、シンプル、クォーター、トレンドフォロー #1/#2、Demark)。
AoShortPeriod / AoLongPeriod Awesome Oscillatorの高速・低速期間。

取引ルール

  1. 戦略はキャンドルがクローズすると(CandleStates.Finished)インジケーターを更新します。
  2. 強気エントリーは以下のときにトリガーされます:
    • 2バー前のAO < 0かつ1バー前のAO > 0(正のゼロクロス)、かつ
    • 2バー前のRAVI < 0かつ1バー前のRAVI > 0
  3. 弱気エントリーは以下のときにトリガーされます:
    • 2バー前のAO > 0かつ1バー前のAO < 0、かつ
    • 2バー前のRAVI > 0かつ1バー前のRAVI < 0
  4. 一度に1つのポジションのみオープンできます。ポジションが存在する間はシグナルが無視されます。

エグジット管理

  • ストップロス: StopLossPipsを使用してインストゥルメントの価格ステップで計算されます(5桁および3桁のFXシンボルはMT5のpip定義に合わせて10×乗数を使用)。キャンドルの極値がストップレベルに触れると発動します。
  • テイクプロフィット: 同じ方法で計算されるオプションのターゲット;TakeProfitPips = 0のとき無効。
  • トレーリングストップ: 有効な場合、浮動利益がTrailingStopPips + TrailingStepPipsを超えるとストップが引き締められます。ロングの場合ストップはClosePrice - TrailingStopPipsに動きます;ショートの場合はClosePrice + TrailingStopPipsに。
  • すべてのエグジットは成行注文でポジション全体をクローズします。

実装上の注意

  • シグナルはバーのクローズ時に評価されます;実際のエントリーは同じキャンドルのクローズで発生し、MT5バージョンは次のバーのオープンでエントリーします。この差を補正する必要がある場合は設定を調整してください。
  • StockSharpが提供する移動平均のみが使用されます;MT5ライブラリのエキゾチックな平滑化モード(JJMA、Jurik、T3など)は利用できません。
  • MT5インジケーターの視覚的なShiftパラメーターはプロットのみに影響します;取引への影響はなく、そのため省略されています。
  • AppliedPricesの式はTrendFollowとDemark オプションを含むMetaTraderの定義に従います。

使用上のヒント

  • 戦略はトレンドフォロー型です;ダマシを減らすために上位の時間軸フィルターやボラティリティフィルターと組み合わせてください。
  • pipサイズはSecurity.PriceStepから導出されるため、FX、CFD、先物間で切り替える際は特に各銘柄ごとに長さとpip距離を最適化してください。
  • 戦略内エグジットではなくブローカー側のストップ注文が必要な場合は外部でStrategy.StartProtectionを有効にしてください。
using System;
using System.Collections.Generic;

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

namespace StockSharp.Samples.Strategies;

/// <summary>
/// RAVI AO strategy. Uses fast/slow EMA difference (RAVI concept) for crossover signals.
/// </summary>
public class RaviAoStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _fastPeriod;
	private readonly StrategyParam<int> _slowPeriod;

	private decimal? _prevFast;
	private decimal? _prevSlow;

	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 RaviAoStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).TimeFrame())
			.SetDisplay("Candle Type", "Timeframe", "General");

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

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

	public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
	{
		return [(Security, CandleType)];
	}

	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();
		_prevFast = null;
		_prevSlow = null;
	}

	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);
		_prevFast = null;
		_prevSlow = null;
		var fast = new ExponentialMovingAverage { Length = FastPeriod };
		var slow = new ExponentialMovingAverage { Length = SlowPeriod };
		var subscription = SubscribeCandles(CandleType);
		subscription.Bind(fast, slow, 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)
	{
		if (candle.State != CandleStates.Finished) return;
		if (!IsFormedAndOnlineAndAllowTrading()) { _prevFast = fastVal; _prevSlow = slowVal; return; }
		if (_prevFast == null || _prevSlow == null) { _prevFast = fastVal; _prevSlow = slowVal; return; }
		var prevAbove = _prevFast.Value > _prevSlow.Value;
		var currAbove = fastVal > slowVal;
		_prevFast = fastVal; _prevSlow = slowVal;
		if (!prevAbove && currAbove && Position <= 0) { if (Position < 0) BuyMarket(); BuyMarket(); }
		else if (prevAbove && !currAbove && Position >= 0) { if (Position > 0) SellMarket(); SellMarket(); }
	}
}