GitHub で見る
Three Timeframes戦略
概要
Three Timeframes戦略は、StockSharpの高レベルAPIを使用してMetaTraderエキスパート Three timeframes.mq5 を複製します。システムは異なる時間軸から取得したモメンタムとトレンドフィルターを組み合わせます:
- MACD (M5) がトレード時間軸での最近のモメンタム反転を検出します。
- Alligator (H4) が上位時間軸の構造が意図したトレード方向と一致していることを確認します。
- RSI (H1) が中間時間軸のモメンタムがブレイクアウトをサポートしていることを確認します。
- オプションのセッションフィルタリングが設定された営業時間外のトレードをブロックします。
戦略はpipsベースのリスク管理を使用します。初期のストップロスとテイクプロフィットのレベルが各新しいポジションに付加されます。価格が前進すると、オプションのトレーリングストップが市場がトレーリング距離とトレーリングステップの両方をカバーした後に保護ストップを締め付けます。
シグナルロジック
- 価格は3つの異なるサブスクリプションで処理されます:トレードローソク足、Alligator用の高位時間軸ローソク足、RSI用の中間ローソク足。
- ロングセットアップには以下が必要です:
- MACDメインラインが前のバーでシグナルラインを下方クロスし、その前のバーはシグナルラインの上にあった。MetaTraderの「青が赤を下方にクロス」ルールを再現。
- H1フィードのRSIが50より上。
- 前の完成したH4ローソク足でAlligator jaw > teeth > lips、上昇構造を示す。
- ショートセットアップはルールを反映します:MACDメインラインがシグナルラインを上方クロス、RSIが50未満、Alligatorで lips > teeth > jaw が下降構造を確認。
- 反対ポジションが存在する場合、戦略はEAオリジナルが新しいトレードを開く前と同様に、ネットサイズの成行注文を送信してクローズします。
- エントリー後、戦略は初期ストップロス/テイクプロフィット距離を適用し、価格がエントリーから
TrailingStopPips + TrailingStepPips 移動するとストップのトレーリングを続けます。
トレードセッションフィルターはMetaTraderの実装を反映します。開始時間が終了時間より小さい場合、取引はその間隔内でのみ許可されます。開始時間が終了時間より大きい場合、アクティブウィンドウは深夜をまたぎます。
リスク管理
- ストップロス / テイクプロフィット – 距離はpipsで表されます。戦略はシンボルの価格ステップを使用して価格単位に変換し、3桁または5桁のFX相場に調整します。
- トレーリングストップ – トレードがトレーリングストップとトレーリングステップ距離の両方をカバーするとアクティブになります。ストップはロングでは
price - trailing distance、ショートでは price + trailing distance に移動されます。
- トレードボリューム – 新しい成行注文のベースロットサイズを指定します。反転前に反対のエクスポージャーが自動的に平らにされます。
- StockSharpの非同期注文モデルにより、明示的なトランザクション追跡フラグ(
m_waiting_transaction)が不要になります。注文は内部で確認を待つ BuyMarket/SellMarket を使用して実行されます。
- MQLバージョンのスリッページ、フィリングポリシー、マージンモード設定はStockSharpによって抽象化されています。これらのプラットフォーム固有のコントロールは.NET実装には不要です。
- Alligatorインジケーターは元の期間とシフトを保持しながら平滑化移動平均から再構築されます。インジケーター値はMetaTraderの組み込みAlligatorのオフセット動作を再現するためにスライディングバッファに保存されます。
パラメーター
| 名前 |
説明 |
デフォルト |
TradeVolume |
ロット/コントラクト単位の成行注文サイズ。 |
1 |
StopLossPips |
pipsでの初期ストップロス距離。 |
50 |
TakeProfitPips |
pipsでの初期テイクプロフィット距離。 |
140 |
TrailingStopPips |
pipsでのトレーリングストップ距離。 |
5 |
TrailingStepPips |
トレーリングストップを移動する前に必要な追加pip移動。 |
5 |
MacdFastPeriod |
MACDの速いEMAの長さ。 |
13 |
MacdSlowPeriod |
MACDの遅いEMAの長さ。 |
26 |
MacdSignalPeriod |
MACDのシグナル平滑化期間。 |
10 |
JawPeriod, TeethPeriod, LipsPeriod |
jaw/teeth/lipsのAlligator SMMAの期間。 |
13, 8, 5 |
JawShift, TeethShift, LipsShift |
Alligatorラインの前方シフト。 |
8, 5, 3 |
RsiPeriod |
中間時間軸でのRSI平均長。 |
14 |
CandleType |
トレード時間軸(デフォルト5分足)。 |
M5 |
AlligatorCandleType |
Alligator計算の高位時間軸(デフォルト4時間足)。 |
H4 |
RsiCandleType |
RSI確認の中間時間軸(デフォルト1時間足)。 |
H1 |
UseTimeFilter |
セッションフィルターを有効にします。 |
true |
StartHour |
セッション開始時間(含む)。 |
10 |
EndHour |
セッション終了時間(含まない)。 |
15 |
使用上のノート
- 選択したインストゥルメントが設定された3つのローソク足ストリーム(デフォルトM5、H1、H4)を提供することを確認してください。StockSharpは
GetWorkingSecurities() を通じて必要なすべてのサブスクリプションを自動的に要求します。
- pip変換は
Security.PriceStep に依存します。異常なティックサイズを持つインストゥルメントはストップ/テイクパラメーターの手動調整が必要な場合があります。
- トレーリングストップには
TrailingStopPips と TrailingStepPips の両方がゼロより大きい必要があります。いずれかのパラメーターをゼロに設定すると、MQLエキスパートと一致してトレーリングロジックが無効になります。
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 ThreeTimeframesStrategy : 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 ThreeTimeframesStrategy()
{
_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;
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
from System import TimeSpan
from StockSharp.Messages import DataType, CandleStates
from StockSharp.Algo.Indicators import ExponentialMovingAverage
from StockSharp.Algo.Strategies import Strategy
class three_timeframes_strategy(Strategy):
def __init__(self):
super(three_timeframes_strategy, self).__init__()
self._fast_period = self.Param("FastPeriod", 14) \
.SetDisplay("Fast Period", "Fast MA period", "Indicator")
self._slow_period = self.Param("SlowPeriod", 50) \
.SetDisplay("Slow Period", "Slow MA period", "Indicator")
self._stop_loss_points = self.Param("StopLossPoints", 200) \
.SetDisplay("Stop Loss", "Stop-loss in price steps", "Risk")
self._take_profit_points = self.Param("TakeProfitPoints", 400) \
.SetDisplay("Take Profit", "Take-profit in price steps", "Risk")
self._fast = None
self._slow = None
self._prev_fast = 0.0
self._prev_slow = 0.0
self._entry_price = 0.0
self._cooldown = 0
@property
def fast_period(self):
return self._fast_period.Value
@property
def slow_period(self):
return self._slow_period.Value
@property
def stop_loss_points(self):
return self._stop_loss_points.Value
@property
def take_profit_points(self):
return self._take_profit_points.Value
def OnReseted(self):
super(three_timeframes_strategy, self).OnReseted()
self._fast = None
self._slow = None
self._prev_fast = 0.0
self._prev_slow = 0.0
self._entry_price = 0.0
self._cooldown = 0
def OnStarted2(self, time):
super(three_timeframes_strategy, self).OnStarted2(time)
self._fast = ExponentialMovingAverage()
self._fast.Length = self.fast_period
self._slow = ExponentialMovingAverage()
self._slow.Length = self.slow_period
subscription = self.SubscribeCandles(DataType.TimeFrame(TimeSpan.FromMinutes(5)))
subscription.Bind(self._fast, self._slow, self._process_candle)
subscription.Start()
def _process_candle(self, candle, fast_value, slow_value):
if candle.State != CandleStates.Finished:
return
fast_val = float(fast_value)
slow_val = float(slow_value)
if not self._fast.IsFormed or not self._slow.IsFormed:
self._prev_fast = fast_val
self._prev_slow = slow_val
return
if self._cooldown > 0:
self._cooldown -= 1
self._prev_fast = fast_val
self._prev_slow = slow_val
return
close = float(candle.ClosePrice)
step = float(self.Security.PriceStep) if self.Security is not None and self.Security.PriceStep is not None else 1.0
if self.Position > 0 and self._entry_price > 0:
if self.stop_loss_points > 0 and close <= self._entry_price - self.stop_loss_points * step:
self.SellMarket()
self._entry_price = 0.0
self._cooldown = 100
self._prev_fast = fast_val
self._prev_slow = slow_val
return
if self.take_profit_points > 0 and close >= self._entry_price + self.take_profit_points * step:
self.SellMarket()
self._entry_price = 0.0
self._cooldown = 100
self._prev_fast = fast_val
self._prev_slow = slow_val
return
elif self.Position < 0 and self._entry_price > 0:
if self.stop_loss_points > 0 and close >= self._entry_price + self.stop_loss_points * step:
self.BuyMarket()
self._entry_price = 0.0
self._cooldown = 100
self._prev_fast = fast_val
self._prev_slow = slow_val
return
if self.take_profit_points > 0 and close <= self._entry_price - self.take_profit_points * step:
self.BuyMarket()
self._entry_price = 0.0
self._cooldown = 100
self._prev_fast = fast_val
self._prev_slow = slow_val
return
if self._prev_fast <= self._prev_slow and fast_val > slow_val and self.Position <= 0:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
self._entry_price = close
self._cooldown = 100
elif self._prev_fast >= self._prev_slow and fast_val < slow_val and self.Position >= 0:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
self._entry_price = close
self._cooldown = 100
self._prev_fast = fast_val
self._prev_slow = slow_val
def CreateClone(self):
return three_timeframes_strategy()