GitHub で見る

MA RSI EA戦略

概要

MA RSI EA戦略は、高速移動平均線と短期RSIフィルターを組み合わせた元のMetaTraderエキスパートアドバイザーのロジックを再現します。戦略は選択したローソク足シリーズで取引し、確定済みバーのみで新しい注文を評価し、口座残高または純資産に基づく動的なポジションサイジングを使用します。すべてのオープンポジションの浮動利益が正になると、利益を確定するためにすべてのポジションが即座にクローズされます。

インジケーター

  • Moving Average – 価格ソース選択とオプションのシフトを持つ設定可能なメソッド(シンプル、指数、スムーズド、線形加重)。
  • Relative Strength Index (RSI) – MQLバージョンと同じローソク足価格ファミリーから読み取る短期オシレーター。

トレードロジック

  1. 各完了ローソク足について、戦略は設定された価格ソースを使用して移動平均線とRSIの値を計算します。
  2. 最新の移動平均値は、MQL動作と一致させるためにユーザー定義のバー数だけシフトできます。
  3. 現在の純ポジションの浮動PnLを評価します:
    • すべてのオープンポジションの浮動結果がゼロより大きい場合、戦略は利益を実現するために全ポジションをクローズします。
    • 浮動結果がの場合、損失の小さい側(買い側対売り側)をその方向に追加トレードを開いて強化します。
  4. 平均化シグナルがない場合、RSI + MAフィルターが適用されます:
    • ショートエントリー – RSI ≥ RsiOverboughtかつローソク足の始値がシフトした移動平均線を下回る。
    • ロングエントリー – RSI ≤ RsiOversoldかつローソク足の始値がシフトした移動平均線を上回る。

エグジットロジック

  • 正の浮動PnLがCloseAllPositionsをトリガーし、戦略を即座にフラット化します。
  • 平均化ロジックからの手動反転シグナルは、StockSharpがネットポジションで動作するため反対側のエクスポージャーをクローズします。

ポジションサイジング

LotSizingModesはEAのOptLot選択を反映します:

  • Fixed – 常にLotSizeボリュームを送信します。
  • Balance – ローソク足クローズ価格を使用してPercentOfBalanceのポートフォリオ価値をボリュームに変換します。
  • Equity – 現在のポートフォリオ純資産のPercentOfEquityをボリュームに変換します。

計算されたボリュームは最寄りのSecurity.VolumeStepに丸められ(利用可能な場合)、注文がインストルメントのロットサイズに準拠するようにします。

パラメーター

パラメーター 説明 デフォルト
LotOption ボリューム計算モード(FixedBalanceEquity)。 Balance
LotSize Fixedモードの固定ロット値。 0.01
PercentOfBalance Balanceモードで使用する残高のパーセンテージ。 2
PercentOfEquity Equityモードで使用する純資産のパーセンテージ。 3
FastMaPeriod 移動平均線の長さ。 4
FastMaShift 移動平均結果に適用するシフト。 0
FastMaMethod 移動平均計算メソッド(SimpleExponentialSmoothedLinearWeighted)。 LinearWeighted
FastMaPrice 移動平均線のローソク足価格ソース。 Open
RsiPeriod RSIの長さ。 4
RsiPrice RSIのローソク足価格ソース。 Open
RsiOverbought 買われすぎ市場を定義するRSIレベル。 80
RsiOversold 売られすぎ市場を定義するRSIレベル。 20
CandleType 戦略が使用するローソク足シリーズ。 15分タイムフレーム

ローソク足価格ソース

CandlePriceSourcesはMQLの適用価格リストを複製します:

  • OpenHighLowClose
  • Median = (High + Low) / 2
  • Typical = (High + Low + Close) / 3
  • Weighted = (High + Low + Close + Close) / 4

注意事項

  • 注文は戦略がオンラインで、ローソク足が完了したときのみ生成されます。新しいバーでトリガーする元のEAと一致します。
  • StockSharpはネットポジションを維持するため、平均化シグナルはヘッジポジションを作成する代わりに現在のエクスポージャーを自動的に削減または反転します。
  • Python実装は要求に従い意図的に省略されています。
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>
/// MA + RSI strategy. Uses EMA trend direction with RSI momentum confirmation.
/// </summary>
public class MaRsiEaStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _maPeriod;
	private readonly StrategyParam<int> _rsiPeriod;
	private readonly StrategyParam<decimal> _rsiOverbought;
	private readonly StrategyParam<decimal> _rsiOversold;

	private decimal? _prevRsi;

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

	public int MaPeriod
	{
		get => _maPeriod.Value;
		set => _maPeriod.Value = value;
	}

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

	public decimal RsiOverbought
	{
		get => _rsiOverbought.Value;
		set => _rsiOverbought.Value = value;
	}

	public decimal RsiOversold
	{
		get => _rsiOversold.Value;
		set => _rsiOversold.Value = value;
	}

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

		_maPeriod = Param(nameof(MaPeriod), 20)
			.SetGreaterThanZero()
			.SetDisplay("MA Period", "EMA period for trend", "Indicators");

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

		_rsiOverbought = Param(nameof(RsiOverbought), 65m)
			.SetDisplay("Overbought", "RSI overbought level", "Levels");

		_rsiOversold = Param(nameof(RsiOversold), 35m)
			.SetDisplay("Oversold", "RSI oversold level", "Levels");
	}

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

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

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

		_prevRsi = null;

		var ema = new ExponentialMovingAverage { Length = MaPeriod };
		var rsi = new RelativeStrengthIndex { Length = RsiPeriod };

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

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

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

		if (!IsFormedAndOnlineAndAllowTrading())
		{
			_prevRsi = rsiValue;
			return;
		}

		var close = candle.ClosePrice;

		if (_prevRsi == null)
		{
			_prevRsi = rsiValue;
			return;
		}

		// Buy: price above EMA and RSI crosses above oversold
		if (close > emaValue && _prevRsi.Value <= RsiOversold && rsiValue > RsiOversold && Position <= 0)
		{
			if (Position < 0)
				BuyMarket();
			BuyMarket();
		}
		// Sell: price below EMA and RSI crosses below overbought
		else if (close < emaValue && _prevRsi.Value >= RsiOverbought && rsiValue < RsiOverbought && Position >= 0)
		{
			if (Position > 0)
				SellMarket();
			SellMarket();
		}

		_prevRsi = rsiValue;
	}
}