Expert MACD EURUSD 1 Hour 策略
概述
该策略是 MetaTrader 5 指标顾问 Expert MACD EURUSD 1 Hour 的 C# 翻译版本。策略在一小时K线图上运行,使用 MACD 指标(快速、慢速和信号周期分别为 5 / 15 / 3)。当 MACD 主线越过零轴并且信号线同步确认时,策略认为出现强劲动量并开仓。策略使用追踪止损保护持仓,当 MACD 斜率反转时平仓。
参数
FastLength– MACD 快速 EMA 周期(默认 5)。SlowLength– MACD 慢速 EMA 周期(默认 15)。SignalLength– MACD 信号线周期(默认 3)。TrailingPoints– 追踪止损距离(默认 25 点)。CandleType– 使用的K线类型与时间框架(默认 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—— 主线向下穿越零轴。- 若满足上述条件且没有空头持仓,则市价卖出。
退出规则
- 当当前主线值低于前一个值时,平掉多头。
- 当当前主线值高于前一个值时,平掉空头。
- 追踪止损在每根K线更新,价格触及止损线时平仓。
备注
该示例展示了如何使用 StockSharp 高级 API、指标绑定以及手动管理追踪止损。策略仅用于学习目的,仅包含固定 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()