GitHub で見る

Freeman戦略

Freemanはトレンドにスケールインするために複数のモメンタムフィルターを重ねたイントラデイ戦略です。取引タイムフレームの移動平均線に駆動された2つのRSI「ティーチャー」と、より高いタイムフレームの移動平均フィルターを使用します。リスクはATRベースのストップロスとテイクプロフィット目標、プラスpipsベースのトレーリングストップで制御されます。

戦略の概要

  • CandleTypeパラメーターで選択した任意のタイムフレームのローソク足で動作します(デフォルトは15分)。
  • 信号を受け入れる前にトレンドを判定するための時間フィルター(FilterCandleType)を使用します。
  • 移動平均線の傾きと組み合わせて現在値と前の値を比較する2つのRSIブロックからロングとショートの信号を構築します。
  • 市場が動き続けるときにピラミッディングを許可し、負けエグジット後に次の注文を拡大するオプションがあります。

トレードロジック

ロング条件

  1. 高いタイムフレームフィルターはオプションです。有効にすると、時間足の移動平均線が上向きに傾く必要があります。
  2. RSIティーチャー#1は以下の条件でアクティブになります:
    • RSI #1が前のバーでRsiSellLevelを下回り、現在のバーで上昇する。
    • 速い移動平均線が上昇する。
    • 時間RSI(期間14)がRsiBuyLevelを下回り、高いタイムフレームが買われすぎでないことを確認する。
  3. RSIティーチャー#2は以下の条件でアクティブになります:
    • RSI #2がRsiSellLevel2を下回り、上向きに転じる。
    • 遅い移動平均線が上昇する。
    • 時間RSIがRsiBuyLevel2を下回る。
  4. 少なくとも1つのティーチャーがアクティブで、トレンドフィルター(有効な場合)が同意するとロングエントリーが取られます。
  5. 追加のロングエントリーは、終値が最後のロング約定からDistancePips(インストルメントのプライスステップで変換)以上動く必要があります。最後のロングエグジットが損失だった場合、MT5のロック動作を模倣するためにボリュームがLockCoefficientで乗算されます。

ショート条件

逆の比較でロングロジックを反映します:

  • フィルターが有効な場合、高いタイムフレームの移動平均線が低下する必要があります。
  • RSIティーチャー#1はRSI #1がRsiBuyLevelを超えて低下すること、速いMAが下落すること、時間RSIがRsiSellLevelを超えることが必要です。
  • RSIティーチャー#2はRSI #2がRsiBuyLevel2を超えて低下すること、遅いMAが下落すること、時間RSIがRsiSellLevel2を超えることが必要です。
  • 追加のショートエントリーは同じ距離とロックルールに従います。

ポジション管理

  • ストップロスとテイクプロフィットは、StopLossAtrFactorTakeProfitAtrFactorを使用して現在のATR値からすべてのエントリーに対して再計算されます。
  • トレーリングストップは価格がTrailingStopPips + TrailingStepPipsを超えて移動するとアクティブになり、その後最後のクローズからTrailingStopPipsだけストップを維持して利益を確保します。
  • ローソク足の高値/安値が計算されたストップまたはターゲットレベルを突破すると、マーケットオーダーでエグジットが実行されます。
  • PositionsMaximumパラメーターは約定済みエントリーの合計数(ロングとショートの合計)を制限します。ゼロの値は上限を削除します。

時間フィルター

  • 金曜日の取引はTradeOnFridayで無効にできます。
  • StartHourEndHourは取引所時刻でのオプションのセッションウィンドウを定義します。ゼロ値は市場を一日中オープンに保ちます。

パラメーター

名前 説明
CandleType メインシグナルロジックに使用する取引タイムフレーム。
FilterCandleType 移動平均線とRSIフィルターの高いタイムフレーム(デフォルト1時間)。
FirstMaPeriod / SecondMaPeriod RSIティーチャーに供給する速いと遅い移動平均線の期間。
FilterMaPeriod 高いタイムフレーム移動平均線の長さ。
MaType 移動平均線タイプ(SMA、EMA、SMMA、またはWMA)。
RsiFirstPeriod / RsiSecondPeriod 2つのRSIティーチャーの期間。
RsiSellLevel, RsiBuyLevel, RsiSellLevel2, RsiBuyLevel2 ティーチャーブロックを制御するRSI閾値。
UseRsiTeacher1, UseRsiTeacher2, UseTrendFilter 各コンポーネントのトグル。
StopLossAtrFactor, TakeProfitAtrFactor ストップロスとテイクプロフィット距離のATR乗数。
TrailingStopPips, TrailingStepPips トレーリングストップエンジンのpipsオフセット。
PositionsMaximum 合計エントリー数の最大数;ゼロ = 無制限。
DistancePips ポジションに追加する前の最小pips距離。
TradeOnFriday 金曜日のシグナルを有効または無効にする。
StartHour, EndHour オプションの取引セッション制限。
LockCoefficient 同じ方向に積み上げるときの損失エグジット後のボリューム乗数。
SignalShift インジケーター値を読む際に適用するオフセット(0 = 現在の確定バー)。

実装上の注意

  • StockSharpポートは確定済みローソク足のみを処理し、元のティクベース取引を許可していた場合でも、MT5の「Bars Control」動作に一致します。
  • pipsで表現された価格距離はインストルメントのPriceStepを使用して変換されます。
  • 保護ロジック(ストップ、ターゲット、トレーリング)は高レベルAPIバインディングを使用しているため、個別のMT5ポジション変更の代わりにマーケットオーダーでポジションをクローズします。
  • 戦略は集計されたロングとショートのボリュームを保持します。一方が閉じると損失追跡がリセットされ、次のシグナルが元のロックルールのように動作します。

ライブ市場に展開する前に適切なリスク管理を使用し、十分にテストしてください。

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>
/// Freeman strategy using dual MA crossover with RSI filter.
/// </summary>
public class FreemanStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _fastPeriod;
	private readonly StrategyParam<int> _slowPeriod;
	private readonly StrategyParam<int> _rsiPeriod;
	private readonly StrategyParam<decimal> _rsiBuyLevel;
	private readonly StrategyParam<decimal> _rsiSellLevel;

	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 int RsiPeriod
	{
		get => _rsiPeriod.Value;
		set => _rsiPeriod.Value = value;
	}

	public decimal RsiBuyLevel
	{
		get => _rsiBuyLevel.Value;
		set => _rsiBuyLevel.Value = value;
	}

	public decimal RsiSellLevel
	{
		get => _rsiSellLevel.Value;
		set => _rsiSellLevel.Value = value;
	}

	public FreemanStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).TimeFrame())
			.SetDisplay("Candle Type", "Timeframe", "General");

		_fastPeriod = Param(nameof(FastPeriod), 10)
			.SetGreaterThanZero()
			.SetDisplay("Fast Period", "Fast SMA period", "Indicators");

		_slowPeriod = Param(nameof(SlowPeriod), 30)
			.SetGreaterThanZero()
			.SetDisplay("Slow Period", "Slow SMA period", "Indicators");

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

		_rsiBuyLevel = Param(nameof(RsiBuyLevel), 55m)
			.SetDisplay("RSI Buy Level", "RSI below which buys are allowed", "Levels");

		_rsiSellLevel = Param(nameof(RsiSellLevel), 45m)
			.SetDisplay("RSI Sell Level", "RSI above which sells are allowed", "Levels");
	}

	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 fastSma = new SimpleMovingAverage { Length = FastPeriod };
		var slowSma = new SimpleMovingAverage { Length = SlowPeriod };
		var rsi = new RelativeStrengthIndex { Length = RsiPeriod };

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

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

	private void ProcessCandle(ICandleMessage candle, decimal fast, decimal slow, decimal rsiValue)
	{
		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;

		// MA crossover
		if (!prevAbove && currAbove)
		{
			if (Position < 0)
				BuyMarket();
			if (Position <= 0)
				BuyMarket();
		}
		else if (prevAbove && !currAbove)
		{
			if (Position > 0)
				SellMarket();
			if (Position >= 0)
				SellMarket();
		}
	}
}