Ver en GitHub

Estrategia Fibonacci Time Zones

Descripción general

Esta estrategia es una adaptación a StockSharp del asesor experto de MetaTrader "Fibonacci Time Zones". Conserva el carácter discrecional del script original al combinar un filtro MACD de marco temporal superior con salidas por bandas de Bollinger y un módulo amplio de gestión monetaria. Todas las rutinas de gestión de operaciones se reescribieron usando la API de alto nivel: la estrategia se suscribe a dos flujos de velas (un marco temporal de trading y un marco temporal más lento para la confirmación MACD) y enlaza indicadores directamente mediante callbacks Bind/BindEx.

Lógica central

  1. Filtro de momentum - Se calcula un histograma MACD mensual (configurable). Un cruce alcista por encima de la línea de señal programa entradas largas, mientras que un cruce bajista programa entradas cortas. La posición real se abre en la siguiente vela de trading para evitar órdenes repetidas en el mismo cruce.
  2. Ejecución de entrada - Cada señal envía un número de órdenes de mercado definido por el usuario. La exposición opuesta existente se cierra antes de abrir una nueva posición.
  3. Reglas de salida - Se aplican múltiples capas de defensa:
    • Salida por banda de Bollinger: los largos se cierran cuando el precio toca la banda superior; los cortos, cuando se alcanza la banda inferior.
    • Stop/objetivo clásico: las distancias estáticas de stop-loss, take-profit y trailing-stop se convierten de pips a unidades de precio y se pasan a StartProtection.
    • Break-even: después de que el precio recorre un número configurable de pips, el stop se lleva a break-even más un desplazamiento. Si el precio retrocede a ese nivel, la posición se cierra.
    • Trailing monetario: se monitorizan el PnL abierto y el realizado. Cuando la ganancia flotante alcanza un umbral, la estrategia empieza a seguirla y cierra todo después de un drawdown configurable.
    • Objetivos de equity: objetivos opcionales de ganancia absoluta o porcentual cierran todas las operaciones inmediatamente cuando se cumplen.

Parámetros

Parámetro Descripción
UseTakeProfitMoney, TakeProfitMoney Cierra todas las posiciones cuando la ganancia combinada (realizada + no realizada) alcanza el importe especificado en la divisa de la cuenta.
UseTakeProfitPercent, TakeProfitPercent Similar a la opción anterior, pero medido como porcentaje del equity inicial.
EnableTrailingProfit, TrailingTakeProfitMoney, TrailingStopLossMoney Activa el trailing basado en dinero cuando se alcanza el primer umbral y protege las ganancias acumuladas.
UseStop, StopLossPips, TakeProfitPips, TrailingStopPips Stop clásico, objetivo y distancias trailing expresadas en pips.
UseMoveToBreakEven, WhenToMoveToBreakEven, PipsToMoveStopLoss Controla el comportamiento de break-even.
NumberOfTrades Número de órdenes de mercado enviadas por cada señal (imita el EA original, que podía apilar entradas).
CandleType, MacdCandleType Marcos temporales para las velas de gestión y el filtro MACD.

Diferencias con el EA original

  • La gestión de botones en el gráfico y los objetos gráficos Fibonacci no se reproducen; la adaptación a StockSharp se centra exclusivamente en la ejecución sistemática.
  • El experto original operaba mediante clics manuales en botones. La adaptación entra automáticamente en cruces MACD para ofrecer una estrategia determinista y apta para backtesting.
  • Las funciones de cuenta específicas de MetaTrader se sustituyeron por equivalentes de StockSharp (valores de Portfolio y PnL).

Consejos de uso

  1. Seleccione tipos de vela adecuados antes de iniciar la estrategia. Los valores predeterminados corresponden a un gráfico de trading de 15 minutos con un filtro MACD mensual.
  2. Ajuste las distancias basadas en pips según el tamaño de tick del instrumento. La estrategia convierte internamente pips a precio usando Security.PriceStep.
  3. Para intervención discrecional, desactive los objetivos automáticos de ganancia y use solo la salida por Bollinger.
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;

public class FibonacciTimeZonesStrategy : Strategy
{
	private readonly StrategyParam<int> _fastPeriod;
	private readonly StrategyParam<int> _slowPeriod;
	private readonly StrategyParam<int> _stopLossPoints;
	private readonly StrategyParam<int> _takeProfitPoints;

	private ExponentialMovingAverage _fast;
	private ExponentialMovingAverage _slow;

	private decimal _prevFast;
	private decimal _prevSlow;
	private decimal _entryPrice;
	private int _cooldown;

	public int FastPeriod { get => _fastPeriod.Value; set => _fastPeriod.Value = value; }
	public int SlowPeriod { get => _slowPeriod.Value; set => _slowPeriod.Value = value; }
	public int StopLossPoints { get => _stopLossPoints.Value; set => _stopLossPoints.Value = value; }
	public int TakeProfitPoints { get => _takeProfitPoints.Value; set => _takeProfitPoints.Value = value; }

	public FibonacciTimeZonesStrategy()
	{
		_fastPeriod = Param(nameof(FastPeriod), 14).SetGreaterThanZero().SetDisplay("Fast Period", "Fast EMA period", "Indicator");
		_slowPeriod = Param(nameof(SlowPeriod), 50).SetGreaterThanZero().SetDisplay("Slow Period", "Slow EMA period", "Indicator");
		_stopLossPoints = Param(nameof(StopLossPoints), 200).SetNotNegative().SetDisplay("Stop Loss", "Stop-loss in price steps", "Risk");
		_takeProfitPoints = Param(nameof(TakeProfitPoints), 400).SetNotNegative().SetDisplay("Take Profit", "Take-profit in price steps", "Risk");
	}

	public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
	{
		yield return (Security, TimeSpan.FromMinutes(5).TimeFrame());
	}

	protected override void OnReseted()
	{
		base.OnReseted();
		_fast = null; _slow = null;
		_prevFast = 0; _prevSlow = 0; _entryPrice = 0; _cooldown = 0;
	}

	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);
		_fast = new ExponentialMovingAverage { Length = FastPeriod };
		_slow = new ExponentialMovingAverage { Length = SlowPeriod };
		var subscription = SubscribeCandles(TimeSpan.FromMinutes(5).TimeFrame());
		subscription.Bind(_fast, _slow, ProcessCandle);
		subscription.Start();
	}

	private void ProcessCandle(ICandleMessage candle, decimal fastValue, decimal slowValue)
	{
		if (candle.State != CandleStates.Finished) return;
		if (!_fast.IsFormed || !_slow.IsFormed) { _prevFast = fastValue; _prevSlow = slowValue; return; }
		if (_cooldown > 0) { _cooldown--; _prevFast = fastValue; _prevSlow = slowValue; return; }

		var close = candle.ClosePrice;
		var step = Security?.PriceStep ?? 1m;

		if (Position > 0 && _entryPrice > 0)
		{
			if (StopLossPoints > 0 && close <= _entryPrice - StopLossPoints * step) { SellMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
			if (TakeProfitPoints > 0 && close >= _entryPrice + TakeProfitPoints * step) { SellMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
		}
		else if (Position < 0 && _entryPrice > 0)
		{
			if (StopLossPoints > 0 && close >= _entryPrice + StopLossPoints * step) { BuyMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
			if (TakeProfitPoints > 0 && close <= _entryPrice - TakeProfitPoints * step) { BuyMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
		}

		if (_prevFast <= _prevSlow && fastValue > slowValue && Position <= 0)
		{ if (Position < 0) BuyMarket(); BuyMarket(); _entryPrice = close; _cooldown = 100; }
		else if (_prevFast >= _prevSlow && fastValue < slowValue && Position >= 0)
		{ if (Position > 0) SellMarket(); SellMarket(); _entryPrice = close; _cooldown = 100; }

		_prevFast = fastValue; _prevSlow = slowValue;
	}
}