GitHub で見る
シンプルな MACD EA 戦略
概要
Simple MACD EA 戦略は、古典的な MetaTrader エキスパート アドバイザー「Simple MACD EA」の直接移植です。このアプローチでは、2 つの指数移動平均 (EMA) を使用して MACD ヒストグラムをエミュレートし、1 分足のローソク足の支配的なトレンドを決定します。速い EMA (期間 100) が遅い EMA (ユーザー定義の MACD レベル) を上回ったときに、ロング ポジションがオープンされます。速い EMA が遅い EMA を下回るとショート ポジションがオープンします。常に 1 つのポジションのみが維持されます。
貿易管理ロジック
- トレンド検出: 100 期間 EMA と設定可能な MACD EMA の差により、現在のトレンドの方向 (
+1、0、-1) が定義されます。マイナスからプラスへの反転によりロングポジションがオープンします。プラスからマイナスに反転するとショートポジションがオープンします。
- 勢いの確認: この戦略は、MACD EMA とわずかに遅い EMA (
MACD level + 1) の間の違いを追跡します。価格が少なくとも 5 ポイント利益を上げた後、現在の取引との差が縮まった場合、ポジションは早期にクローズされます。
- 時間ベースの保護: ユーザー定義の評価サイクル数の間、取引が開かれたままになった後、システムはソフト ストップをアクティブにし、エントリー価格に対する不利な価格変動に対する許容度を低減します。
- トレーリングエグジット: 取引が利益に転じ、十分なサイクルにわたってアクティブな状態が続くと、内部トレーリングストップがかかります。ストップレベルは、設定されたポイント数によって価格に従い、限られた回数だけ更新できます。リミットに達するとポジションはクローズされます。
- トレンド反転エグジット: 価格が既に 5 ポイントの利益を上げているときにトレンド シグナルが反対方向に反転すると、ポジションは即座にクローズされます。
パラメーター
- ローソク足タイプ – EMA の計算に使用される時間枠 (デフォルト: 1 分ローソク足)。
- 数量 – 新規エントリの注文数量。
- MACD レベル – 遅い MACD コンポーネントを定義する EMA の長さ。長さ
MACD Level + 1 のセカンダリ EMA が自動的に導出されます。
- トレーリング ストップ – トレーリング エグジットまでのポイント単位の距離。無効にするには、ゼロに設定します。
- トレーリング更新 – 取引ごとのトレーリング ストップ調整の最大数。
- 待機サイクル – 適応ソフトストップがアクティブになる前に待機するローソク足評価の数。
追加メモ
- この戦略は、方向を反転する前に常に現在のポジションを平坦化します。
- 選択した証券からの価格ステップ情報は、ポイントベースの距離を実際の価格に変換するために使用されます。
- この実装は、StockSharp の高レベルのローソク足サブスクリプション API に依存しており、カスタム インジケーター バッファーをキューに入れません。
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>
/// Simple MACD EA strategy using fast/slow EMA difference for trend detection.
/// Buy when EMA difference crosses above zero, sell when it crosses below zero.
/// </summary>
public class SimpleMacdEaStrategy : Strategy
{
private readonly StrategyParam<int> _fastEmaPeriod;
private readonly StrategyParam<int> _slowEmaPeriod;
private readonly StrategyParam<DataType> _candleType;
private decimal _prevDiff;
private bool _hasPrev;
public int FastEmaPeriod
{
get => _fastEmaPeriod.Value;
set => _fastEmaPeriod.Value = value;
}
public int SlowEmaPeriod
{
get => _slowEmaPeriod.Value;
set => _slowEmaPeriod.Value = value;
}
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public SimpleMacdEaStrategy()
{
_fastEmaPeriod = Param(nameof(FastEmaPeriod), 12)
.SetDisplay("Fast EMA", "Fast EMA period", "Indicators");
_slowEmaPeriod = Param(nameof(SlowEmaPeriod), 26)
.SetDisplay("Slow EMA", "Slow EMA period", "Indicators");
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).TimeFrame())
.SetDisplay("Candle Type", "Candle timeframe", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevDiff = 0m;
_hasPrev = false;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_hasPrev = false;
var fastEma = new ExponentialMovingAverage { Length = FastEmaPeriod };
var slowEma = new ExponentialMovingAverage { Length = SlowEmaPeriod };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(fastEma, slowEma, ProcessCandle)
.Start();
}
private void ProcessCandle(ICandleMessage candle, decimal fast, decimal slow)
{
if (candle.State != CandleStates.Finished)
return;
var diff = fast - slow;
if (!_hasPrev)
{
_prevDiff = diff;
_hasPrev = true;
return;
}
// Buy: MACD crosses above zero
var longSignal = _prevDiff <= 0 && diff > 0;
// Sell: MACD crosses below zero
var shortSignal = _prevDiff >= 0 && diff < 0;
if (Position <= 0 && longSignal)
{
if (Position < 0)
BuyMarket();
BuyMarket();
}
else if (Position >= 0 && shortSignal)
{
if (Position > 0)
SellMarket();
SellMarket();
}
_prevDiff = diff;
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
from System import TimeSpan, Math
from StockSharp.Messages import DataType, CandleStates
from StockSharp.Algo.Indicators import ExponentialMovingAverage
from StockSharp.Algo.Strategies import Strategy
class simple_macd_ea_strategy(Strategy):
"""Simple MACD EA using fast/slow EMA difference for trend detection.
Buy when EMA difference crosses above zero, sell when it crosses below zero."""
def __init__(self):
super(simple_macd_ea_strategy, self).__init__()
self._fast_ema_period = self.Param("FastEmaPeriod", 12) \
.SetDisplay("Fast EMA", "Fast EMA period", "Indicators")
self._slow_ema_period = self.Param("SlowEmaPeriod", 26) \
.SetDisplay("Slow EMA", "Slow EMA period", "Indicators")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(1))) \
.SetDisplay("Candle Type", "Candle timeframe", "General")
self._prev_diff = 0.0
self._has_prev = False
@property
def CandleType(self):
return self._candle_type.Value
@CandleType.setter
def CandleType(self, value):
self._candle_type.Value = value
@property
def FastEmaPeriod(self):
return self._fast_ema_period.Value
@property
def SlowEmaPeriod(self):
return self._slow_ema_period.Value
def OnReseted(self):
super(simple_macd_ea_strategy, self).OnReseted()
self._prev_diff = 0.0
self._has_prev = False
def OnStarted2(self, time):
super(simple_macd_ea_strategy, self).OnStarted2(time)
self._has_prev = False
fast_ema = ExponentialMovingAverage()
fast_ema.Length = self.FastEmaPeriod
slow_ema = ExponentialMovingAverage()
slow_ema.Length = self.SlowEmaPeriod
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(fast_ema, slow_ema, self._process_candle).Start()
def _process_candle(self, candle, fast, slow):
if candle.State != CandleStates.Finished:
return
diff = float(fast) - float(slow)
if not self._has_prev:
self._prev_diff = diff
self._has_prev = True
return
# Buy: MACD crosses above zero
long_signal = self._prev_diff <= 0 and diff > 0
# Sell: MACD crosses below zero
short_signal = self._prev_diff >= 0 and diff < 0
if self.Position <= 0 and long_signal:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
elif self.Position >= 0 and short_signal:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
self._prev_diff = diff
def CreateClone(self):
return simple_macd_ea_strategy()