在 GitHub 上查看
Elite eFibo Trader v2.1 策略
概述
Elite eFibo Trader v2.1 复刻了 MetaTrader 专家顾问,在单一方向上按斐波那契数列叠加仓位,并为所有挂单共用同一个保护性止损。移植到 StockSharp 后保持了原有行为:首笔市价单启动后,会根据 LevelDistancePips 间隔批量放置止损挂单,每当新的层级成交,就按斐波那契权重增加仓位。一旦共享止损被触发或浮动利润达到 MoneyTakeProfit,策略会立即平掉整个篮子。
该算法是刻意的单向结构。将 OpenBuy 设为 true(同时把 OpenSell 设为 false)可运行多头版本,反之则运行空头版本。任意时刻只会存在一个阶梯,完全复制 MQL4 脚本的一次性循环逻辑。
数据要求
- 订阅逐笔成交流以获取最新成交价,用于放置阶梯挂单、更新共享止损以及计算货币止盈。
- 依赖品种元数据(
PriceStep、StepPrice、VolumeStep)将 MetaTrader 中的点值和手数转换为交易所价格与数量。
阶梯构建流程
- 当没有持仓且允许交易时,策略检查方向开关。必须只有
OpenBuy 或 OpenSell 其中一个为 true,否则不会启动阶梯。
- 第一个斐波那契层级以市价成交;其余层级按
LevelDistancePips * pipSize 的距离放置止损挂单,基准价为阶梯启动时记录的市价。
- 每个层级的下单量来自
Level1Volume … Level14Volume 参数,并会根据品种的 VolumeStep 进行归一化。
- 所有层级共用同一止损偏移量:
StopLossPips * pipSize。每当有新层级成交时会生成初始止损,随后会自动收紧,使所有持仓共享距离最近的保护价格。
止损管理
- 每个成交层级都会保存自己的入场价与基于点值计算出的初始止损。
- 在每笔成交事件中,策略会重新计算所有持仓的止损,并向最紧的价格对齐(多头取最高止损,空头取最低止损),以模拟 MetaTrader 中频繁的
OrderModify 调整。
- 当最新成交价穿越任何共享止损时,策略会撤销剩余挂单,并用市价立即平掉整个篮子。
资金管理
- 未实现盈亏按照品种的
PriceStep 与 StepPrice 计算,确保现金目标与 MetaTrader 中的 OrderProfit() 一致。
- 当浮动利润达到或超过
MoneyTakeProfit 时,会即时平掉所有仓位并取消挂单。
- 若
TradeAgainAfterProfit 设为 false,在达到现金目标后策略会保持空闲,直到手动重新启动。
参数
| 名称 |
说明 |
OpenBuy |
允许构建多头阶梯(必须与 OpenSell 互斥)。 |
OpenSell |
允许构建空头阶梯(必须与 OpenBuy 互斥)。 |
TradeAgainAfterProfit |
在篮子达到货币止盈后是否重新开始交易。 |
LevelDistancePips |
相邻止损挂单之间的 MetaTrader 点数距离。 |
StopLossPips |
每个成交层级的保护性止损点数距离。 |
MoneyTakeProfit |
平掉整个篮子的货币止盈目标。 |
Level1Volume … Level14Volume |
各斐波那契层级的下单量,设为 0 可跳过对应层级。 |
实现细节
- 点值换算遵循 MetaTrader 规则:报价带有 3 或 5 位小数时,真实点值为
PriceStep * 10。
- 启动时调用一次
StartProtection(),启用 StockSharp 内置的安全检查。
- 共享止损逻辑确保所有持仓保持同步;一旦出现更紧的止损,就会应用到每个活动层级。
- 当阶梯没有持仓时会自动清理挂单,对应 MQL 代码中反复执行的
subCloseAllPending()。
使用建议
- 请确保品种已正确配置
PriceStep、StepPrice 和 VolumeStep,否则点值换算和货币止盈都会失准。
- 平均加仓系统会迅速放大敞口,实盘前务必核对交易所的数量限制和保证金要求。
- 将
TradeAgainAfterProfit 设为 false 可复现原始 EA 中在盈利后停止交易的“一次性”模式。
using System;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
public class EliteEfiboTraderV21Strategy : Strategy
{
private readonly StrategyParam<int> _emaPeriod;
private readonly StrategyParam<int> _cooldownCandles;
private readonly StrategyParam<DataType> _candleType;
private decimal _prevClose;
private decimal _prevEma;
private bool _hasPrev;
private int _cooldownRemaining;
public int EmaPeriod { get => _emaPeriod.Value; set => _emaPeriod.Value = value; }
public int CooldownCandles { get => _cooldownCandles.Value; set => _cooldownCandles.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public EliteEfiboTraderV21Strategy()
{
_emaPeriod = Param(nameof(EmaPeriod), 50).SetDisplay("EMA Period", "EMA lookback", "Indicators");
_cooldownCandles = Param(nameof(CooldownCandles), 200).SetDisplay("Cooldown", "Candles between signals", "General");
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame()).SetDisplay("Candle Type", "Candle timeframe", "General");
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevClose = default;
_prevEma = default;
_hasPrev = default;
_cooldownRemaining = default;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_prevClose = 0;
_prevEma = 0;
_hasPrev = false;
_cooldownRemaining = 0;
var ema = new ExponentialMovingAverage { Length = EmaPeriod };
var subscription = SubscribeCandles(CandleType);
subscription.Bind(ema, ProcessCandle).Start();
}
private void ProcessCandle(ICandleMessage candle, decimal ema)
{
if (candle.State != CandleStates.Finished) return;
var close = candle.ClosePrice;
if (!_hasPrev) { _prevClose = close; _prevEma = ema; _hasPrev = true; return; }
if (_cooldownRemaining > 0)
{
_cooldownRemaining--;
_prevClose = close;
_prevEma = ema;
return;
}
if (_prevClose <= _prevEma && close > ema && Position <= 0)
{
if (Position < 0) BuyMarket();
BuyMarket();
_cooldownRemaining = CooldownCandles;
}
else if (_prevClose >= _prevEma && close < ema && Position >= 0)
{
if (Position > 0) SellMarket();
SellMarket();
_cooldownRemaining = CooldownCandles;
}
_prevClose = close;
_prevEma = ema;
}
}
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 elite_efibo_trader_v21_strategy(Strategy):
def __init__(self):
super(elite_efibo_trader_v21_strategy, self).__init__()
self._ema_period = self.Param("EmaPeriod", 50) \
.SetDisplay("EMA Period", "EMA lookback", "Indicators")
self._cooldown_candles = self.Param("CooldownCandles", 200) \
.SetDisplay("Cooldown", "Candles between signals", "General")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(5))) \
.SetDisplay("Candle Type", "Candle timeframe", "General")
self._prev_close = 0.0
self._prev_ema = 0.0
self._has_prev = False
self._cooldown_remaining = 0
@property
def ema_period(self):
return self._ema_period.Value
@property
def cooldown_candles(self):
return self._cooldown_candles.Value
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(elite_efibo_trader_v21_strategy, self).OnReseted()
self._prev_close = 0.0
self._prev_ema = 0.0
self._has_prev = False
self._cooldown_remaining = 0
def OnStarted2(self, time):
super(elite_efibo_trader_v21_strategy, self).OnStarted2(time)
self._prev_close = 0.0
self._prev_ema = 0.0
self._has_prev = False
self._cooldown_remaining = 0
ema = ExponentialMovingAverage()
ema.Length = self.ema_period
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(ema, self.process_candle).Start()
def process_candle(self, candle, ema):
if candle.State != CandleStates.Finished:
return
close = float(candle.ClosePrice)
ema_val = float(ema)
if not self._has_prev:
self._prev_close = close
self._prev_ema = ema_val
self._has_prev = True
return
if self._cooldown_remaining > 0:
self._cooldown_remaining -= 1
self._prev_close = close
self._prev_ema = ema_val
return
if self._prev_close <= self._prev_ema and close > ema_val and self.Position <= 0:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
self._cooldown_remaining = self.cooldown_candles
elif self._prev_close >= self._prev_ema and close < ema_val and self.Position >= 0:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
self._cooldown_remaining = self.cooldown_candles
self._prev_close = close
self._prev_ema = ema_val
def CreateClone(self):
return elite_efibo_trader_v21_strategy()