GitHub で見る
移動平均クロス戦略
概要
- MetaTrader 5エキスパートアドバイザー**「Crossing Moving Average (barabashkakvn's edition)」**をソース
MQL/21515から変換したもの。
- ローソク足サブスクリプションとインジケーターバインディングを使用したStockSharpの高レベルAPIでロジックを実装。
- モメンタムと移動平均クロスがトレンドリバーサルを捉えるインストゥルメント向けに設計。
- このパッケージはC#バージョンのみ含みます。Pythonの翻訳はリクエスト通り意図的に省略されています。
コアアイデア
戦略はオプションの先行シフトを持つ2つの設定可能な移動平均(高速と低速)を監視し、そのクロスをモメンタム確認フィルターと組み合わせます。トレードは以下の場合のみ開きます:
- 高速平均が最新の2つの完成したバー上で設定された最小距離(pips)以上で低速平均を交差します。
- モメンタムインジケーターがユーザー定義の閾値を上回る(ロング)または下回る(ショート)と上昇し、トレードの方向に改善しています。
- シグナル価格ソースは、MetaTraderの適用価格モードを模倣するために、始値、高値、安値、終値、中央値、典型値、または加重ローソク足価格から選択できます。
リスクとトレード管理
- 注文ボリュームはトレードごとに固定されており、新しいポジションへのエントリー時も既存のポジションの逆転時も適用されます。
- ストップロス/テイクプロフィット距離はpipsで設定され、
Security.PriceStepを使用して自動的に価格オフセットに変換されます。3桁または5桁の小数で引用されるインストゥルメントの場合、戦略はMetaTraderのpipサイズを再現するためにステップを10倍にします。
- トレーリングストップは、価格がエントリーから
TrailingStop + TrailingStep(pips)移動した後に活性化します。一旦トリガーされると、少なくともTrailingStep pips進むことができる場合はいつでも、ロングポジションの場合は現在価格 - TrailingStop(またはショートの場合は現在価格 + TrailingStop)にストップが移動します。
- 保護レベルは各完成したローソク足で評価されます:ローソク足の範囲がストップロスまたはテイクプロフィットに触れると、MetaTraderでの注文執行を模倣するためにポジションが成行でクローズされます。
インジケーター
- 高速移動平均 – 設定可能な期間、シフト、平滑化方法(SMA、EMA、SMMA、WMA)。
- 低速移動平均 – 高速MAと同じオプション。
- モメンタム – 期間と価格ソースは移動平均と同一。戦略はインジケーターが0または100付近の値を出力するかを自動検出し、それに応じてフィルターを適用します。
シグナルロジック
- すべてのインジケーターが完全に形成されるまで待ちます。アルゴリズムは、オリジナルのエキスパートアドバイザーと全く同様にシフトされたクロスを評価するために、最新の値の内部履歴を維持します。
- 前の2つのバー(適用されたシフト付き)の高速と低速平均間の価格距離を計算します。高速ラインは低速ラインを交差し、最小距離フィルターを超えなければなりません。
- 同じバーのモメンタム値を取得します。ロングエントリーの場合、現在のモメンタムは設定された閾値と前のモメンタム値の両方より大きくなければなりません;ショートエントリーの場合は逆が必要です。
- ポジションが反対の状態で新しいシグナルが現れると、戦略は既存のポジションをクローズし、設定されたロットサイズで新しい方向にすぐに開きます。
パラメーター参照
| パラメーター |
説明 |
デフォルト |
OrderVolume |
各成行注文のベースボリューム。 |
1 |
StopLossPips |
pipsでのストップロス距離(0はストップを無効にします)。 |
50 |
TakeProfitPips |
pipsでのテイクプロフィット距離(0はターゲットを無効にします)。 |
50 |
TrailingStopPips |
pipsでのトレーリングストップ距離(0はトレーリングを無効にします)。 |
5 |
TrailingStepPips |
トレーリングストップを移動するために必要な最小pip改善。 |
5 |
MinDistancePips |
クロスを検証するためのMA間の最小間隔。 |
0 |
MomentumFilter |
エントリーを許可するために必要な最小モメンタム差。 |
0.1 |
FastPeriod / FastShift |
高速MA長と水平シフト(バー)。 |
13 / 1 |
SlowPeriod / SlowShift |
低速MA長と水平シフト(バー)。 |
34 / 3 |
MaMethod |
移動平均平滑化タイプ(Simple、Exponential、Smoothed、Weighted)。 |
Exponential |
AppliedPrice |
インジケーター計算のローソク足価格。 |
Close |
MomentumPeriod |
バーでのモメンタムルックバック長。 |
14 |
CandleType |
戦略に供給されるローソク足のデータタイプ。 |
TimeFrame(1m) |
実践的なノート
- インストゥルメントに対して
Security.PriceStepが設定されていることを常に確認します;そうでない場合、pipベースのリスク管理は生の価格単位にフォールバックします。
- トレーリングロジックは
TrailingStopPipsが有効な場合、正のTrailingStepPipsを必要とします — オリジナルのMetaTrader検証を反映しています。
- ストップとテイクレベルはローソク足の範囲で評価されるため、より高解像度のローソク足を使用することでtickベースの実行に近い近似が得られます。
- エントリーとトレーリング調整のログメッセージが含まれており、デバッグとパラメーター調整を容易にします。
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>
/// Moving average crossover strategy.
/// Enters long when fast EMA crosses above slow EMA, enters short on the opposite crossover.
/// </summary>
public class CrossingMovingAverageStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _fastPeriod;
private readonly StrategyParam<int> _slowPeriod;
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 CrossingMovingAverageStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).TimeFrame())
.SetDisplay("Candle Type", "Timeframe", "General");
_fastPeriod = Param(nameof(FastPeriod), 13)
.SetGreaterThanZero()
.SetDisplay("Fast Period", "Fast EMA period", "Indicators");
_slowPeriod = Param(nameof(SlowPeriod), 34)
.SetGreaterThanZero()
.SetDisplay("Slow Period", "Slow EMA period", "Indicators");
}
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 fastEma = new ExponentialMovingAverage { Length = FastPeriod };
var slowEma = new ExponentialMovingAverage { Length = SlowPeriod };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(fastEma, slowEma, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, fastEma);
DrawIndicator(area, slowEma);
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;
}
// Crossover detection
var prevAbove = _prevFast.Value > _prevSlow.Value;
var currAbove = fast > slow;
_prevFast = fast;
_prevSlow = slow;
// Golden cross: fast crosses above slow
if (!prevAbove && currAbove)
{
if (Position < 0)
BuyMarket();
if (Position <= 0)
BuyMarket();
}
// Death cross: fast crosses below slow
else if (prevAbove && !currAbove)
{
if (Position > 0)
SellMarket();
if (Position >= 0)
SellMarket();
}
}
}
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 crossing_moving_average_strategy(Strategy):
def __init__(self):
super(crossing_moving_average_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(1))) \
.SetDisplay("Candle Type", "Timeframe", "General")
self._fast_period = self.Param("FastPeriod", 13) \
.SetDisplay("Fast Period", "Fast EMA period", "Indicators")
self._slow_period = self.Param("SlowPeriod", 34) \
.SetDisplay("Slow Period", "Slow EMA period", "Indicators")
self._prev_fast = None
self._prev_slow = None
@property
def CandleType(self):
return self._candle_type.Value
@property
def FastPeriod(self):
return self._fast_period.Value
@property
def SlowPeriod(self):
return self._slow_period.Value
def OnReseted(self):
super(crossing_moving_average_strategy, self).OnReseted()
self._prev_fast = None
self._prev_slow = None
def OnStarted2(self, time):
super(crossing_moving_average_strategy, self).OnStarted2(time)
self._prev_fast = None
self._prev_slow = None
fast_ema = ExponentialMovingAverage()
fast_ema.Length = self.FastPeriod
slow_ema = ExponentialMovingAverage()
slow_ema.Length = self.SlowPeriod
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(fast_ema, slow_ema, self._on_process).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, fast_ema)
self.DrawIndicator(area, slow_ema)
self.DrawOwnTrades(area)
def _on_process(self, candle, fast_value, slow_value):
if candle.State != CandleStates.Finished:
return
fv = float(fast_value)
sv = float(slow_value)
if self._prev_fast is None or self._prev_slow is None:
self._prev_fast = fv
self._prev_slow = sv
return
prev_above = self._prev_fast > self._prev_slow
curr_above = fv > sv
self._prev_fast = fv
self._prev_slow = sv
# Golden cross: fast crosses above slow
if not prev_above and curr_above:
if self.Position < 0:
self.BuyMarket()
if self.Position <= 0:
self.BuyMarket()
# Death cross: fast crosses below slow
elif prev_above and not curr_above:
if self.Position > 0:
self.SellMarket()
if self.Position >= 0:
self.SellMarket()
def CreateClone(self):
return crossing_moving_average_strategy()