GitHub で見る

Andrews Pitchfork戦略

MetaTraderエキスパートアドバイザー「Andrew's Pitchfork」のポートです。オリジナルスクリプトは手動で描かれたAndrews Pitchforkオブジェクトを必要とし、Momentum、マルチタイムフレーム移動平均、MACDフィルターと組み合わせていました。StockSharpバージョンはインジケータースタックを維持し、手動描画を自動トレンド検出に置き換え、保護ロジック(複数エントリー制限、ストップロス、テイクプロフィット、ブレークイーブン、トレーリング管理)を再現します。

戦略ロジック

  1. インジケーター
    • 選択されたキャンドルシリーズの標準価格で計算された2つの線形加重移動平均(LWMA)。
    • 同じ時間軸でのMomentumオシレーター、均衡レベル100からの絶対偏差で評価。
    • クラシックな*MACD (12, 26, 9)*シグナルラインペア。
  2. エントリールール
    • ロングトレードは高速LWMAが低速LWMAを上回り、最後の3つのMomentum偏差のうち少なくとも1つがMomentumBuyThresholdを超え、MACD線がシグナル線を上回ることを必要とします。
    • ショートトレードはこれらの条件を逆にします。
    • 戦略は絶対ポジションがVolume * MaxPyramidsを下回る間、ベースVolumeを繰り返し追加することでピラミッドを行います。反対のシグナルは新しい方向を開く前に現在のエクスポージャーを閉じます。
  3. リスク管理
    • 初期のストップロスとテイクプロフィットレベルはエントリー周辺の価格ステップに配置されます。ポジションサイズが変化するたびに両方が更新されます。
    • ブレークイーブンロジックは、価格がポジションに有利な設定可能なステップ数を移動した後にストップを移動します。
    • トレーリングストップロジックは追加のパディング距離で最も収益性の高い価格を追従し続けます。

MQLバージョンと比較して、StockSharpポートはユーザーが描いたPitchforkオブジェクトの向きをチェックする代わりにLWMAの傾きを使用してトレンドを自動的に推論します。他のすべてのフィルター(Momentum、MACD、複数注文制限)と資金管理ツールはStockSharpの高レベルAPIで再現されました。

パラメーター

名称 タイプ デフォルト 説明
CandleType DataType 15分時間軸 すべてのインジケーターが使用するプライマリキャンドルシリーズ。
FastMaPeriod int 6 標準価格での高速LWMAの長さ。
SlowMaPeriod int 85 標準価格での低速LWMAの長さ。
MomentumPeriod int 14 Momentumインジケーターのルックバック。
MomentumBuyThreshold decimal 0.3 ロングエントリーの最小|Momentum - 100|。
MomentumSellThreshold decimal 0.3 ショートエントリーの最小|Momentum - 100|。
MaxPyramids int 1 同じ方向で許可される最大ベースロット数。
StopLossSteps int 20 価格ステップで表されたストップロス距離。
TakeProfitSteps int 50 価格ステップで表されたテイクプロフィット距離。
EnableTrailing bool true 動的トレーリングストップを有効化します。
TrailingTriggerSteps int 40 トレーリングストップが有効化される前に必要なステップ単位の利益。
TrailingDistanceSteps int 40 価格極値とトレーリングストップの間に維持されるステップ距離。
TrailingPadSteps int 10 トレーリングストップに適用される追加パディング。
EnableBreakEven bool true ブレークイーブンストップ調整を有効化します。
BreakEvenTriggerSteps int 30 ストップをブレークイーブンに移動する前に必要なステップ単位の利益。
BreakEvenOffsetSteps int 30 ブレークイーブン適用時のエントリーを超えたステップオフセット。

注意事項

  • 戦略はステップベースの距離を価格に変換するために選択されたセキュリティからの有効なPriceStepが必要です。ステップが欠落している場合、トレーリングとブレークイーブンのロジックは非アクティブのままです。
  • 保護注文(ストップとテイクプロフィット)はポジションサイズが変化するたびに再作成され、スケーリングインまたは反転が新しいエクスポージャーに注文を合わせることを保証します。
  • デフォルトパラメーターは元のEA設定と一致しますが、組み込みのStrategyParam範囲を介して最適化できます。
using System;
using System.Collections.Generic;

using Ecng.Common;

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

namespace StockSharp.Samples.Strategies;

public class AndrewsPitchforkStrategy : Strategy
{
	private readonly StrategyParam<int> _fastPeriod;
	private readonly StrategyParam<int> _slowPeriod;
	private readonly StrategyParam<int> _stopLossPoints;
	private readonly StrategyParam<int> _takeProfitPoints;

	private ExponentialMovingAverage _fast;
	private ExponentialMovingAverage _slow;

	private decimal _prevFast;
	private decimal _prevSlow;
	private decimal _entryPrice;
	private int _cooldown;

	public int FastPeriod { get => _fastPeriod.Value; set => _fastPeriod.Value = value; }
	public int SlowPeriod { get => _slowPeriod.Value; set => _slowPeriod.Value = value; }
	public int StopLossPoints { get => _stopLossPoints.Value; set => _stopLossPoints.Value = value; }
	public int TakeProfitPoints { get => _takeProfitPoints.Value; set => _takeProfitPoints.Value = value; }

	public AndrewsPitchforkStrategy()
	{
		_fastPeriod = Param(nameof(FastPeriod), 14).SetGreaterThanZero().SetDisplay("Fast Period", "Fast EMA period", "Indicator");
		_slowPeriod = Param(nameof(SlowPeriod), 50).SetGreaterThanZero().SetDisplay("Slow Period", "Slow EMA period", "Indicator");
		_stopLossPoints = Param(nameof(StopLossPoints), 200).SetNotNegative().SetDisplay("Stop Loss", "Stop-loss in price steps", "Risk");
		_takeProfitPoints = Param(nameof(TakeProfitPoints), 400).SetNotNegative().SetDisplay("Take Profit", "Take-profit in price steps", "Risk");
	}

	public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
	{
		yield return (Security, TimeSpan.FromMinutes(5).TimeFrame());
	}

	protected override void OnReseted()
	{
		base.OnReseted();
		_fast = null; _slow = null;
		_prevFast = 0; _prevSlow = 0; _entryPrice = 0; _cooldown = 0;
	}

	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);
		_fast = new ExponentialMovingAverage { Length = FastPeriod };
		_slow = new ExponentialMovingAverage { Length = SlowPeriod };
		var subscription = SubscribeCandles(TimeSpan.FromMinutes(5).TimeFrame());
		subscription.Bind(_fast, _slow, ProcessCandle);
		subscription.Start();
	}

	private void ProcessCandle(ICandleMessage candle, decimal fastValue, decimal slowValue)
	{
		if (candle.State != CandleStates.Finished) return;
		if (!_fast.IsFormed || !_slow.IsFormed) { _prevFast = fastValue; _prevSlow = slowValue; return; }
		if (_cooldown > 0) { _cooldown--; _prevFast = fastValue; _prevSlow = slowValue; return; }

		var close = candle.ClosePrice;
		var step = Security?.PriceStep ?? 1m;

		if (Position > 0 && _entryPrice > 0)
		{
			if (StopLossPoints > 0 && close <= _entryPrice - StopLossPoints * step) { SellMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
			if (TakeProfitPoints > 0 && close >= _entryPrice + TakeProfitPoints * step) { SellMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
		}
		else if (Position < 0 && _entryPrice > 0)
		{
			if (StopLossPoints > 0 && close >= _entryPrice + StopLossPoints * step) { BuyMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
			if (TakeProfitPoints > 0 && close <= _entryPrice - TakeProfitPoints * step) { BuyMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
		}

		if (_prevFast <= _prevSlow && fastValue > slowValue && Position <= 0)
		{ if (Position < 0) BuyMarket(); BuyMarket(); _entryPrice = close; _cooldown = 100; }
		else if (_prevFast >= _prevSlow && fastValue < slowValue && Position >= 0)
		{ if (Position > 0) SellMarket(); SellMarket(); _entryPrice = close; _cooldown = 100; }

		_prevFast = fastValue; _prevSlow = slowValue;
	}
}