Alexav D1 Profit GBPUSD 策略
基于日线级别的 GBP/USD 突破策略,结合高价 EMA、RSI 滤波、MACD 动量确认以及 ATR 风险管理。此实现完整复刻了原始 MetaTrader 版本的四层分批止盈与保本移动规则。
核心信息
- 市场:GBP/USD 现货或差价合约
- 时间框架:日线(可配置)
- 方向:多空双向
- 仓位结构:每次信号分四笔入场,共用止损
- 技术指标:高价 EMA、RSI、MACD 主线、ATR
指标设置
- 高价 EMA – 默认周期 6,用于确定突破基准。
- RSI – 默认周期 10,设定动量区间过滤。
- MACD 主线 – 快线 5、慢线 21、信号线 14,仅使用主线判断动量加速度。
- ATR – 周期 28,提供波动性自适应的止损与目标。
入场逻辑
多头
- 前一根日线开盘价低于 EMA(High),收盘价高于 EMA(High),形成向上穿越。
- RSI 位于 60 与 80 之间,过滤动量不足或过度延伸的行情。
- 满足以下任一 MACD 条件:
- 两根之前的 MACD 主线值为负数,显示动量刚转正;
- 近两根 K 线的 MACD 绝对值相对变化大于 MacdDiffBuy(默认 0.5)。
条件满足时,先平掉所有空头,再以相同数量提交 4 笔市价买单(默认每笔 0.1 手)。
空头
- 日线开盘价高于 EMA(High),收盘价跌至 EMA(High) 下方。
- RSI 介于 25 与 39 之间,对应多头区间的镜像设置。
- 满足以下任一 MACD 条件:
- 两根之前的 MACD 主线值为正;
- 近两根 MACD 绝对值的相对变化超过 MacdDiffSell(默认 0.15)。
确认后,若存在多头先行平仓,再发送四笔等量市价卖单。
仓位管理
- 初始止损:按 ATR 设置共享止损。多头为
entry - ATR * StopLossMultiplier(默认 1.6),空头为 entry + ATR * StopLossMultiplier。
- 分批止盈:每笔仓位对应四个 ATR 目标,系数依次为
1.0、1.5、2.0、2.5,再乘以 TakeProfitMultiplier(默认 1)。价格触及目标时以市价平掉四分之一仓位。
- 移动保本:每次部分止盈后,将剩余仓位的保护价上移(或下移)到最新止盈价,复刻原 EA 的止盈触发后移至保本的处理。
- 止损触发:若 K 线最高/最低触及保护价,立即市价全平剩余仓位。
风险控制
- 策略不会加码超过四笔初始仓位,未清空前的新信号会被忽略。
- ATR 必须有效(>0),指标未形成时跳过信号。
- 运行过程中参数变动只影响后续下单,入场时的每笔数量会被记录用于后续止盈。
参数列表
| 参数 |
说明 |
默认值 |
OrderVolume |
单笔市价单量 |
0.1 |
EmaPeriod |
高价 EMA 周期 |
6 |
RsiPeriod |
RSI 周期 |
10 |
AtrPeriod |
ATR 周期 |
28 |
StopLossMultiplier |
ATR 止损倍数 |
1.6 |
TakeProfitMultiplier |
ATR 止盈倍数基准 |
1.0 |
MacdFastPeriod |
MACD 快线周期 |
5 |
MacdSlowPeriod |
MACD 慢线周期 |
21 |
MacdSignalPeriod |
MACD 信号线周期 |
14 |
MacdDiffBuyThreshold |
多头最小 MACD 加速度 |
0.5 |
MacdDiffSellThreshold |
空头最小 MACD 加速度 |
0.15 |
RsiUpperLimit |
多头允许的最大 RSI |
80 |
RsiUpperLevel |
多头需要的最小 RSI |
60 |
RsiLowerLevel |
空头允许的最大 RSI |
39 |
RsiLowerLimit |
空头需要的最小 RSI |
25 |
CandleType |
订阅的 K 线类型 |
1 Day |
实践建议
- 联合优化 RSI 与 MACD 阈值,避免只放宽 RSI 而造成假信号。
- 分批止盈依赖蜡烛高低点,回测需保证数据质量。
- 需准备足够保证金以承载四笔同时在途的订单。
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;
/// <summary>
/// Alexav D1 Profit GBPUSD strategy (simplified). Uses EMA crossover with RSI
/// filter for breakout entries with ATR-based stop/take management.
/// </summary>
public class AlexavD1ProfitGbpUsdStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _emaFastLength;
private readonly StrategyParam<int> _emaSlowLength;
private readonly StrategyParam<int> _rsiLength;
private readonly StrategyParam<decimal> _rsiUpperLevel;
private readonly StrategyParam<decimal> _rsiLowerLevel;
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public int EmaFastLength
{
get => _emaFastLength.Value;
set => _emaFastLength.Value = value;
}
public int EmaSlowLength
{
get => _emaSlowLength.Value;
set => _emaSlowLength.Value = value;
}
public int RsiLength
{
get => _rsiLength.Value;
set => _rsiLength.Value = value;
}
public decimal RsiUpperLevel
{
get => _rsiUpperLevel.Value;
set => _rsiUpperLevel.Value = value;
}
public decimal RsiLowerLevel
{
get => _rsiLowerLevel.Value;
set => _rsiLowerLevel.Value = value;
}
public AlexavD1ProfitGbpUsdStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Candles", "General");
_emaFastLength = Param(nameof(EmaFastLength), 6)
.SetGreaterThanZero()
.SetDisplay("EMA Fast", "Fast EMA period", "Indicators");
_emaSlowLength = Param(nameof(EmaSlowLength), 21)
.SetGreaterThanZero()
.SetDisplay("EMA Slow", "Slow EMA period", "Indicators");
_rsiLength = Param(nameof(RsiLength), 10)
.SetGreaterThanZero()
.SetDisplay("RSI Length", "RSI period", "Indicators");
_rsiUpperLevel = Param(nameof(RsiUpperLevel), 65m)
.SetDisplay("RSI Upper", "Max RSI for buy", "Filters");
_rsiLowerLevel = Param(nameof(RsiLowerLevel), 35m)
.SetDisplay("RSI Lower", "Min RSI for sell", "Filters");
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var emaFast = new ExponentialMovingAverage { Length = EmaFastLength };
var emaSlow = new ExponentialMovingAverage { Length = EmaSlowLength };
decimal prevFast = 0, prevSlow = 0;
var hasPrev = false;
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(emaFast, emaSlow, (ICandleMessage candle, decimal fastVal, decimal slowVal) =>
{
if (candle.State != CandleStates.Finished)
return;
if (!hasPrev)
{
prevFast = fastVal;
prevSlow = slowVal;
hasPrev = true;
return;
}
if (!IsFormedAndOnlineAndAllowTrading())
{
prevFast = fastVal;
prevSlow = slowVal;
return;
}
var close = candle.ClosePrice;
// EMA fast crosses above slow - buy signal
var bullishCross = prevFast <= prevSlow && fastVal > slowVal;
// EMA fast crosses below slow - sell signal
var bearishCross = prevFast >= prevSlow && fastVal < slowVal;
if (bullishCross && Position <= 0)
BuyMarket();
else if (bearishCross && Position >= 0)
SellMarket();
prevFast = fastVal;
prevSlow = slowVal;
})
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, emaFast);
DrawIndicator(area, emaSlow);
DrawOwnTrades(area);
}
}
}
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 alexav_d1_profit_gbp_usd_strategy(Strategy):
def __init__(self):
super(alexav_d1_profit_gbp_usd_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Candles", "General")
self._ema_fast_length = self.Param("EmaFastLength", 6) \
.SetDisplay("EMA Fast", "Fast EMA period", "Indicators")
self._ema_slow_length = self.Param("EmaSlowLength", 21) \
.SetDisplay("EMA Slow", "Slow EMA period", "Indicators")
self._prev_fast = 0.0
self._prev_slow = 0.0
self._has_prev = False
@property
def CandleType(self):
return self._candle_type.Value
@property
def EmaFastLength(self):
return self._ema_fast_length.Value
@property
def EmaSlowLength(self):
return self._ema_slow_length.Value
def OnReseted(self):
super(alexav_d1_profit_gbp_usd_strategy, self).OnReseted()
self._prev_fast = 0.0
self._prev_slow = 0.0
self._has_prev = False
def OnStarted2(self, time):
super(alexav_d1_profit_gbp_usd_strategy, self).OnStarted2(time)
self._prev_fast = 0.0
self._prev_slow = 0.0
self._has_prev = False
ema_fast = ExponentialMovingAverage()
ema_fast.Length = self.EmaFastLength
ema_slow = ExponentialMovingAverage()
ema_slow.Length = self.EmaSlowLength
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(ema_fast, ema_slow, self._on_process).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, ema_fast)
self.DrawIndicator(area, ema_slow)
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 not self._has_prev:
self._prev_fast = fv
self._prev_slow = sv
self._has_prev = True
return
if self._prev_fast <= self._prev_slow and fv > sv and self.Position <= 0:
self.BuyMarket()
elif self._prev_fast >= self._prev_slow and fv < sv and self.Position >= 0:
self.SellMarket()
self._prev_fast = fv
self._prev_slow = sv
def CreateClone(self):
return alexav_d1_profit_gbp_usd_strategy()