在 GitHub 上查看

Fibonacci Retracement Momentum 策略

概述

Fibonacci Retracement Momentum Strategy 是将原始 MetaTrader 专家顾问 "FIBONACCI.mq4" 迁移到 StockSharp 高级 API 的版本。策略把多周期的斐波那契回撤位与 Momentum 和 MACD 过滤器结合起来,用于在趋势方向上寻找回调入场点。主要交易逻辑运行在基础周期,而确认信号来自更高的时间框架。

算法完全按照 StockSharp 的风格重写:使用蜡烛订阅、指标 Bind 绑定以及内置的仓位管理辅助函数。为了突出核心思想(斐波那契触碰 + 动能爆发 + 趋势过滤),原 EA 中的货币追踪和附加资金管理被有意简化。

工作流程

  1. 基础周期 —— 策略订阅所选周期的蜡烛(默认 15 分钟),计算两条线性加权移动平均线(快线与慢线)以衡量局部趋势。
  2. 斐波那契锚定周期 —— 较高的时间框架(默认 1 小时)提供最近闭合蜡烛,其最高点和最低点用于构建 0%–100% 的斐波那契网格。同一数据流驱动 Momentum 指标(默认周期 14),并保存最近三个值与中性水平 100 的绝对差。
  3. MACD 过滤周期 —— 在近似 30 天的月度蜡烛上计算 MACD(12/26/9),用于确认长期趋势方向。
  4. 每当基础蜡烛收盘时,策略检查价格是否回踩到某个斐波那契级别,同时之前的收盘价仍位于该级别的另一侧。若再满足均线排列、动能阈值以及 MACD 方向,便生成入场信号。
  5. 风险控制依靠以价格步长为单位的止损和止盈。一旦价格触发保护阈值或达到目标,仓位立即平掉。

入场条件

做多

  • 上级周期的最新蜡烛确定斐波那契水平;当前基础蜡烛的最低价触及某一级别,同时最近三根蜡烛中至少一根的收盘价仍在该级别之上。
  • 基础周期上快线 WMA 位于慢线 WMA 之上。
  • 过去三次 |Momentum - 100| 中任意一次超过设定阈值。
  • MACD 时间框架上主线高于信号线。
  • 结构过滤:上一根蜡烛的最高价高于两根之前蜡烛的最低价(对应 EA 中的 Low[2] < High[1] 条件)。

做空

  • 当前基础蜡烛的最高价触及某个斐波那契水平,同时最近三根蜡烛中至少一根的收盘价仍在该级别之下。
  • 快线 WMA 低于慢线 WMA。
  • 动能阈值在最近三次测量中的任意一次被突破。
  • MACD 主线低于信号线。
  • 结构过滤:上一根蜡烛的最高价高于上一根蜡烛的最低价(对应 Low[1] < High[2])。

仓位管理

  • 如果出现反向信号,策略先调用 ClosePosition() 平掉当前仓位,并等待下一根蜡烛再考虑反向入场,以保持与原 EA 类似的谨慎执行方式。

风险管理

  • 止损 / 止盈 —— 以价格步长的数量配置,设置为 0 表示关闭该功能。
  • 入场价格跟踪 —— 使用信号蜡烛的收盘价作为参考来计算保护距离。

参数

参数 默认值 说明
FastMaLength 6 基础周期上快速 WMA 的长度。
SlowMaLength 85 基础周期上慢速 WMA 的长度。
MomentumLength 14 斐波那契周期上的 Momentum 周期。
MomentumThreshold 0.3 动能偏离 100 所需的最小绝对值。
StopLossSteps 20 止损距离(价格步长为单位,0 表示禁用)。
TakeProfitSteps 50 止盈距离(价格步长为单位,0 表示禁用)。
MacdFastLength 12 MACD 中的快速 EMA 周期。
MacdSlowLength 26 MACD 中的慢速 EMA 周期。
MacdSignalLength 9 MACD 信号线的 EMA 周期。
CandleType 15 分钟蜡烛 基础执行周期。
FibonacciCandleType 1 小时蜡烛 提供斐波那契锚点与 Momentum 的周期。
MacdCandleType 30 天蜡烛 提供 MACD 趋势过滤的周期。

使用建议

  • 根据需要调整三个周期参数,以匹配原 EA 的映射关系(如 M5 → M30、M15 → H1 等)。
  • 策略通过 ClosePosition() 平仓,因此请确保 Volume 属性设置为目标仓位规模。
  • 本移植专注于指标驱动的逻辑;原版中的额外资金管理(权益止损、资金追踪等)未包含在内,可在 ManageRisk 方法中扩展。
  • 在 StockSharp Designer、Shell 或 Runner 中运行策略前,请配置好所需的市场数据适配器。
using System;
using System.Collections.Generic;

using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;

namespace StockSharp.Samples.Strategies;

public class FibonacciRetracementMomentumStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _fastPeriod;
	private readonly StrategyParam<int> _slowPeriod;
	private decimal? _prevFast, _prevSlow;

	public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
	public int FastPeriod { get => _fastPeriod.Value; set => _fastPeriod.Value = value; }
	public int SlowPeriod { get => _slowPeriod.Value; set => _slowPeriod.Value = value; }

	public FibonacciRetracementMomentumStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).TimeFrame()).SetDisplay("Candle Type", "Timeframe", "General");
		_fastPeriod = Param(nameof(FastPeriod), 6).SetGreaterThanZero().SetDisplay("Fast WMA", "Fast WMA period", "Indicators");
		_slowPeriod = Param(nameof(SlowPeriod), 21).SetGreaterThanZero().SetDisplay("Slow WMA", "Slow WMA period", "Indicators");
	}

	public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities() => [(Security, CandleType)];

	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();
		_prevFast = null;
		_prevSlow = null;
	}

	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);
		_prevFast = null; _prevSlow = null;
		var fast = new WeightedMovingAverage { Length = FastPeriod };
		var slow = new WeightedMovingAverage { Length = SlowPeriod };
		var subscription = SubscribeCandles(CandleType);
		subscription.Bind(fast, slow, ProcessCandle).Start();
		var area = CreateChartArea();
		if (area != null) { DrawCandles(area, subscription); DrawIndicator(area, fast); DrawIndicator(area, slow); DrawOwnTrades(area); }
	}

	private void ProcessCandle(ICandleMessage candle, decimal fast, decimal slow)
	{
		if (candle.State != CandleStates.Finished) return;
		if (!IsFormedAndOnlineAndAllowTrading()) { _prevFast = fast; _prevSlow = slow; return; }
		if (_prevFast == null || _prevSlow == null) { _prevFast = fast; _prevSlow = slow; return; }
		var prevAbove = _prevFast.Value > _prevSlow.Value;
		var currAbove = fast > slow;
		_prevFast = fast; _prevSlow = slow;
		if (!prevAbove && currAbove && Position <= 0) { if (Position < 0) BuyMarket(); BuyMarket(); }
		else if (prevAbove && !currAbove && Position >= 0) { if (Position > 0) SellMarket(); SellMarket(); }
	}
}