Стратегия Expert MACD EURUSD 1 Hour
Обзор
Данная стратегия представляет собой перевод советника MetaTrader 5 Expert MACD EURUSD 1 Hour на C#. Торговля ведётся по часовым свечам с использованием индикатора MACD с периодами 5 / 15 / 3. Стратегия ищет импульсные развороты, когда основная линия MACD пересекает нулевой уровень, а сигнальная линия подтверждает движение. Для защиты позиций используется трейлинг-стоп, а выход из сделки происходит при смене наклона MACD против текущей позиции.
Параметры
FastLength – период быстрой EMA для MACD (по умолчанию 5).
SlowLength – период медленной EMA для MACD (по умолчанию 15).
SignalLength – период сигнальной линии MACD (по умолчанию 3).
TrailingPoints – размер трейлинг-стопа в пунктах цены (по умолчанию 25).
CandleType – тип свечей, таймфрейм (по умолчанию 1 час).
- Объём позиций задаётся свойством стратегии
Volume.
Логика торговли
Вход в лонг
- Значения сигнальной линии:
mac8 > mac7 > mac6 и mac6 < mac5 (рост сигнальной линии).
- Значения основной линии:
mac4 > mac3 < mac2 < mac1 (рост основной линии после снижения).
mac2 < -0.00020, mac4 < 0 и mac1 > 0.00020 – основная линия пересекает нулевой уровень вверх.
- При выполнении условий и отсутствии позиции покупается по рынку.
Вход в шорт
- Значения сигнальной линии:
mac8 < mac7 < mac6 и mac6 > mac5 (падение сигнальной линии).
- Значения основной линии:
mac4 < mac3 > mac2 > mac1 (падение основной линии после вершины).
mac2 > 0.00020, mac4 > 0 и mac1 < -0.00035 – основная линия пересекает нулевой уровень вниз.
- При выполнении условий и отсутствии позиции продаётся по рынку.
Правила выхода
- Лонг закрывается, если текущее значение основной линии ниже предыдущего.
- Шорт закрывается, если текущее значение основной линии выше предыдущего.
- Трейлинг-стоп обновляется на каждой свече и закрывает позицию при пересечении цены уровня стопа.
Примечания
Пример демонстрирует использование высокоуровневого API StockSharp с привязкой индикаторов и ручным управлением трейлинг-стопом. Стратегия предназначена для учебных целей и не содержит расширенного манименеджмента помимо фиксированного параметра Volume.
using System;
using System.Linq;
using System.Collections.Generic;
using Ecng.Common;
using Ecng.Collections;
using Ecng.Serialization;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// MACD based strategy converted from MetaTrader 5 Expert Advisor.
/// Uses MACD indicator with custom pattern checks on recent values and optional trailing stop.
/// </summary>
public class ExpertMacdEurusd1HourStrategy : Strategy
{
private readonly StrategyParam<int> _fastLength;
private readonly StrategyParam<int> _slowLength;
private readonly StrategyParam<int> _signalLength;
private readonly StrategyParam<decimal> _trailingPoints;
private readonly StrategyParam<DataType> _candleType;
private ExponentialMovingAverage _fastEma;
private ExponentialMovingAverage _slowEma;
private ExponentialMovingAverage _signalEma;
private decimal _main0, _main1;
private decimal _signal0, _signal1;
private int _counter;
/// <summary>
/// Fast EMA length for MACD.
/// </summary>
public int FastLength { get => _fastLength.Value; set => _fastLength.Value = value; }
/// <summary>
/// Slow EMA length for MACD.
/// </summary>
public int SlowLength { get => _slowLength.Value; set => _slowLength.Value = value; }
/// <summary>
/// Signal line length for MACD.
/// </summary>
public int SignalLength { get => _signalLength.Value; set => _signalLength.Value = value; }
/// <summary>
/// Trailing stop distance in price points.
/// </summary>
public decimal TrailingPoints { get => _trailingPoints.Value; set => _trailingPoints.Value = value; }
/// <summary>
/// Candle type for analysis.
/// </summary>
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
/// <summary>
/// Initialize strategy with default parameters.
/// </summary>
public ExpertMacdEurusd1HourStrategy()
{
_fastLength = Param(nameof(FastLength), 12)
.SetDisplay("Fast Length", "Fast EMA length for MACD", "Parameters")
;
_slowLength = Param(nameof(SlowLength), 26)
.SetDisplay("Slow Length", "Slow EMA length for MACD", "Parameters")
;
_signalLength = Param(nameof(SignalLength), 9)
.SetDisplay("Signal Length", "Signal length for MACD", "Parameters")
;
_trailingPoints = Param(nameof(TrailingPoints), 25m)
.SetDisplay("Trailing Points", "Trailing stop distance in points", "Risk");
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).TimeFrame())
.SetDisplay("Candle Type", "Working timeframe", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_main0 = _main1 = 0m;
_signal0 = _signal1 = 0m;
_counter = 0;
_fastEma = null;
_slowEma = null;
_signalEma = null;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_fastEma = new ExponentialMovingAverage { Length = FastLength };
_slowEma = new ExponentialMovingAverage { Length = SlowLength };
_signalEma = new ExponentialMovingAverage { Length = SignalLength };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(ProcessCandle)
.Start();
StartProtection(
new Unit(2000m, UnitTypes.Absolute),
new Unit(1000m, UnitTypes.Absolute));
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle)
{
if (candle.State != CandleStates.Finished)
return;
var fast = _fastEma.Process(candle.ClosePrice, candle.CloseTime, true).ToDecimal();
var slow = _slowEma.Process(candle.ClosePrice, candle.CloseTime, true).ToDecimal();
if (!_fastEma.IsFormed || !_slowEma.IsFormed)
return;
var main = fast - slow;
var signal = _signalEma.Process(main, candle.CloseTime, true).ToDecimal();
if (!_signalEma.IsFormed)
return;
// shift stored values
_main1 = _main0;
_main0 = main;
_signal1 = _signal0;
_signal0 = signal;
if (_counter < 3)
{
_counter++;
return;
}
var buySignal = _main1 <= _signal1 && _main0 > _signal0 && _main0 < 0m;
var sellSignal = _main1 >= _signal1 && _main0 < _signal0 && _main0 > 0m;
if (buySignal && Position <= 0)
BuyMarket();
else if (sellSignal && 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, Unit, UnitTypes
from StockSharp.Algo.Indicators import ExponentialMovingAverage
from StockSharp.Algo.Strategies import Strategy
from indicator_extensions import *
class expert_macd_eurusd1_hour_strategy(Strategy):
def __init__(self):
super(expert_macd_eurusd1_hour_strategy, self).__init__()
self._fast_length = self.Param("FastLength", 12)
self._slow_length = self.Param("SlowLength", 26)
self._signal_length = self.Param("SignalLength", 9)
self._trailing_points = self.Param("TrailingPoints", 25.0)
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(1)))
self._fast_ema = None
self._slow_ema = None
self._signal_ema = None
self._main0 = 0.0
self._main1 = 0.0
self._signal0 = 0.0
self._signal1 = 0.0
self._counter = 0
@property
def FastLength(self):
return self._fast_length.Value
@FastLength.setter
def FastLength(self, value):
self._fast_length.Value = value
@property
def SlowLength(self):
return self._slow_length.Value
@SlowLength.setter
def SlowLength(self, value):
self._slow_length.Value = value
@property
def SignalLength(self):
return self._signal_length.Value
@SignalLength.setter
def SignalLength(self, value):
self._signal_length.Value = value
@property
def TrailingPoints(self):
return self._trailing_points.Value
@TrailingPoints.setter
def TrailingPoints(self, value):
self._trailing_points.Value = value
@property
def CandleType(self):
return self._candle_type.Value
@CandleType.setter
def CandleType(self, value):
self._candle_type.Value = value
def OnStarted2(self, time):
super(expert_macd_eurusd1_hour_strategy, self).OnStarted2(time)
self._main0 = 0.0
self._main1 = 0.0
self._signal0 = 0.0
self._signal1 = 0.0
self._counter = 0
self._fast_ema = ExponentialMovingAverage()
self._fast_ema.Length = self.FastLength
self._slow_ema = ExponentialMovingAverage()
self._slow_ema.Length = self.SlowLength
self._signal_ema = ExponentialMovingAverage()
self._signal_ema.Length = self.SignalLength
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(self.ProcessCandle).Start()
self.StartProtection(
Unit(2000.0, UnitTypes.Absolute),
Unit(1000.0, UnitTypes.Absolute))
def ProcessCandle(self, candle):
if candle.State != CandleStates.Finished:
return
t = candle.OpenTime
fast_result = process_float(self._fast_ema, candle.ClosePrice, t, True)
slow_result = process_float(self._slow_ema, candle.ClosePrice, t, True)
if not self._fast_ema.IsFormed or not self._slow_ema.IsFormed:
return
fast_val = float(fast_result)
slow_val = float(slow_result)
main = fast_val - slow_val
signal_result = process_float(self._signal_ema, main, t, True)
if not self._signal_ema.IsFormed:
return
signal = float(signal_result)
self._main1 = self._main0
self._main0 = main
self._signal1 = self._signal0
self._signal0 = signal
if self._counter < 3:
self._counter += 1
return
buy_signal = self._main1 <= self._signal1 and self._main0 > self._signal0 and self._main0 < 0.0
sell_signal = self._main1 >= self._signal1 and self._main0 < self._signal0 and self._main0 > 0.0
if buy_signal and self.Position <= 0:
self.BuyMarket()
elif sell_signal and self.Position >= 0:
self.SellMarket()
def OnReseted(self):
super(expert_macd_eurusd1_hour_strategy, self).OnReseted()
self._main0 = 0.0
self._main1 = 0.0
self._signal0 = 0.0
self._signal1 = 0.0
self._counter = 0
self._fast_ema = None
self._slow_ema = None
self._signal_ema = None
def CreateClone(self):
return expert_macd_eurusd1_hour_strategy()