Ver en GitHub

Estrategia FrAMA Candle Trend

Esta estrategia convierte el asesor experto MetaTrader Exp_FrAMACandle en una estrategia de alto nivel de StockSharp.

Lógica de la estrategia

  • Utiliza la Media Móvil Adaptativa Fractal (FrAMA) calculada por separado para los precios de apertura y cierre de las velas.
  • Una señal alcista ocurre cuando la FrAMA del precio de cierre sube por encima de la FrAMA del precio de apertura. Si la barra anterior no fue alcista, la estrategia abre una posición larga y cierra los cortos existentes.
  • Una señal bajista ocurre cuando la FrAMA del precio de cierre cae por debajo de la FrAMA del precio de apertura. Si la barra anterior no fue bajista, la estrategia abre una posición corta y cierra los largos existentes.
  • Las señales se evalúan solo en velas completadas. Los valores históricos de color se almacenan para respetar el desplazamiento SignalBar.

Parámetros

Nombre Descripción
CandleType Marco temporal utilizado para el cálculo del indicador. Predeterminado: 4 horas.
FramaPeriod Período del indicador FrAMA.
SignalBar Desplazamiento de la barra utilizada para la detección de señales.
BuyOpen / SellOpen Habilitar apertura de posiciones largas/cortas.
BuyClose / SellClose Habilitar cierre de posiciones largas/cortas.

Notas

  • La estrategia se basa únicamente en cruces de FrAMA y no implementa gestión de stop-loss o take-profit.
  • El volumen de la posición está controlado por la propiedad base Volume de la estrategia.
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>
/// FrAMA candle trend-following strategy.
/// Uses FrAMA indicator for trend detection and trades on direction changes.
/// </summary>
public class FramaCandleTrendStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _framaPeriod;

	private decimal _prevFramaValue;
	private decimal _prevPrevFramaValue;
	private bool _hasPrev;

	public DataType CandleType
	{
		get => _candleType.Value;
		set => _candleType.Value = value;
	}

	public int FramaPeriod
	{
		get => _framaPeriod.Value;
		set => _framaPeriod.Value = value;
	}

	public FramaCandleTrendStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
			.SetDisplay("Candle Type", "Timeframe for indicator calculation", "General");

		_framaPeriod = Param(nameof(FramaPeriod), 15)
			.SetGreaterThanZero()
			.SetDisplay("FrAMA Period", "Length of the Fractal Adaptive Moving Average", "Indicator");
	}

	/// <inheritdoc />
	public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
	{
		return [(Security, CandleType)];
	}

	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();
		_prevFramaValue = 0;
		_prevPrevFramaValue = 0;
		_hasPrev = false;
	}

	/// <inheritdoc />
	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);

		_hasPrev = false;
		_prevFramaValue = 0;
		_prevPrevFramaValue = 0;

		var frama = new FractalAdaptiveMovingAverage { Length = FramaPeriod };

		var subscription = SubscribeCandles(CandleType);
		subscription
			.Bind(frama, OnProcess)
			.Start();

		var area = CreateChartArea();
		if (area != null)
		{
			DrawCandles(area, subscription);
			DrawIndicator(area, frama);
			DrawOwnTrades(area);
		}
	}

	private void OnProcess(ICandleMessage candle, decimal framaValue)
	{
		if (candle.State != CandleStates.Finished)
			return;

		if (!_hasPrev)
		{
			_prevFramaValue = framaValue;
			_hasPrev = true;
			return;
		}

		// Trend direction from FrAMA slope
		var rising = framaValue > _prevFramaValue;
		var falling = framaValue < _prevFramaValue;
		var wasRising = _prevFramaValue > _prevPrevFramaValue;
		var wasFalling = _prevFramaValue < _prevPrevFramaValue;

		// Buy on transition from falling to rising
		if (rising && wasFalling && Position <= 0)
		{
			if (Position < 0) BuyMarket();
			BuyMarket();
		}
		// Sell on transition from rising to falling
		else if (falling && wasRising && Position >= 0)
		{
			if (Position > 0) SellMarket();
			SellMarket();
		}

		_prevPrevFramaValue = _prevFramaValue;
		_prevFramaValue = framaValue;
	}
}