GitHub で見る

Freeman ATR MA RSI Grid戦略

概要

この戦略はStockSharpの高レベルAPIを使用してMetaTraderの「Freeman」エキスパートアドバイザーを複製します。移動平均の傾きによって測定されたトレンドがRSI確認と一致している間、複数の市場ポジションを積み重ねます。各エントリーとエグジットの距離はpipsで定義され、インストゥルメントのティックサイズを使用して価格単位に変換されるため、動作が元のforex実装と一致します。

トレードロジック

  1. 単一のローソク足シリーズ(設定可能な時間軸)をサブスクライブし、完成した各ローソク足でATR、移動平均、RSIインジケーターを更新します。
  2. 以下の場合に方向性シグナルを生成します:
    • 最新の値を前のバーと比較することで移動平均の傾きが正または負(オプションのトレンドフィルター)。
    • 価格が移動平均から十分に離れていて、直接ライン上でのエントリーを避けます。
    • RSIフィルターが有効な場合、RSIが上限または下限のしきい値をクロスします。MetaTraderのロジックはそのまま維持され、RSI売りの確認が-11を返す特性も含まれているため、両方のフィルターを有効にするとロングトレードのみが優先されます。
  3. 同時に開いているポジションの最大数を尊重します。同じ方向への追加エントリーは、価格が設定されたpip距離だけ最後の約定に対して逆行した場合にのみ許可され、事実上グリッドを構築します。
  4. 各エントリーはATRベースのストップロスとテイクプロフィットレベルを使用します。トレーリングストップは、価格がトレーリングステップ+トレーリングストップ距離だけ移動すると保護ストップを締めます。
  5. エグジットはローソク足の範囲がストップ、ターゲット、またはトレーリングレベルに達したとき、反対の成行注文を通じて実行されます。

リスク管理

  • ATR乗数が固定ストップロスとテイクプロフィットの距離を制御します。乗数をゼロに設定するとその保護が無効になります。
  • トレーリングストップはオプションで、2つのpipパラメーターで定義されます:実際のトレーリング距離と、ストップを再度移動する前に必要な追加ステップ。
  • 戦略はサイジングのためにベースVolumeプロパティに依存します;ポジション上限を超えた自動化された資金管理は適用されません。

パラメータ

名前 説明
CandleType インジケーター計算に使用する時間軸。
MaxPositions 同時に開いているポジションの最大数(ロングとショートの合計)。
DistancePips 同じ方向での連続エントリー間の最小pip距離。
AtrPeriod ATRインジケーターの平均期間。
AtrStopLossMultiplier 保護ストップのATR乗数。0でストップを無効にします。
AtrTakeProfitMultiplier 利益目標のATR乗数。0で目標を無効にします。
UseTrendFilter 移動平均の傾きフィルターを有効にします。
DistanceFromMaPips トレンドフィルターが有効なときの価格と移動平均の間の最小pip距離。
MaPeriod, MaShift, MaMethod, MaPriceType MetaTraderの入力を反映した移動平均パラメータ。
UseRsiFilter RSI確認フィルターを有効にします。
RsiLevelUp, RsiLevelDown, RsiPeriod, RsiPriceType 適用される価格選択によるRSI設定。
TrailingStopPips, TrailingStepPips pipsで測定されたトレーリングストップの距離とステップ。
CurrentBarOffset インジケーター値を読み取る際に適用されるオフセット、エキスパートアドバイザーのCurrentBar入力をエミュレートします。

注意事項

  • pipの変換は、インストゥルメントが3または5桁の小数点以下を持つ場合、MetaTraderのポイント対pip調整を再現するためにインストゥルメントのPriceStepを10倍します。
  • 戦略はネッティングポジションモデルを使用します;反対シグナルは新しい方向でのトレードを開く前に既存のポジションをクローズします。
  • トレードが配置される前の予期しない再接続に対して保護するため、スタート保護は起動時に有効になります。
using System;
using System.Collections.Generic;

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

namespace StockSharp.Samples.Strategies;

public class FreemanAtrMaRsiGridStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _fastPeriod;
	private readonly StrategyParam<int> _slowPeriod;
	private decimal? _prevFast, _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 FreemanAtrMaRsiGridStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).TimeFrame()).SetDisplay("Candle Type", "Timeframe", "General");
		_fastPeriod = Param(nameof(FastPeriod), 8).SetGreaterThanZero().SetDisplay("Fast EMA", "Fast EMA period", "Indicators");
		_slowPeriod = Param(nameof(SlowPeriod), 21).SetGreaterThanZero().SetDisplay("Slow EMA", "Slow EMA period", "Indicators");
	}

	public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities() => [(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 fast, decimal slow)
	{
		if (candle.State != CandleStates.Finished) return;
		if (!IsFormedAndOnlineAndAllowTrading()) { _prevFast = fast; _prevSlow = slow; return; }
		if (_prevFast == null || _prevSlow == null) { _prevFast = fast; _prevSlow = slow; return; }
		var prevAbove = _prevFast.Value > _prevSlow.Value;
		var currAbove = fast > slow;
		_prevFast = fast; _prevSlow = slow;
		if (!prevAbove && currAbove && Position <= 0) { if (Position < 0) BuyMarket(); BuyMarket(); }
		else if (prevAbove && !currAbove && Position >= 0) { if (Position > 0) SellMarket(); SellMarket(); }
	}
}