La estrategia de cruce Fractal AMA MBK utiliza la Media Móvil Adaptativa Fractal (FRAMA) junto con una línea de activación de Media Móvil Exponencial (EMA). Las señales de operación se generan cuando la línea FRAMA cruza la línea EMA.
Cómo funciona
FRAMA adapta su factor de suavizado basándose en la dimensión fractal del movimiento reciente del precio.
La EMA actúa como línea de activación que suaviza los datos del precio.
Entrada larga: cuando FRAMA cruza hacia arriba la EMA y no hay posición larga abierta.
Entrada corta: cuando FRAMA cruza hacia abajo la EMA y no hay posición corta abierta.
Las posiciones existentes pueden protegerse con niveles opcionales de stop-loss y take-profit.
Parámetros
Nombre
Descripción
CandleType
Tipo y marco temporal de las velas usadas para los cálculos (predeterminado: velas de 4 horas).
FramaPeriod
Período del indicador FRAMA.
SignalPeriod
Período de la línea EMA de activación.
StopLoss
Distancia del stop-loss desde el precio de entrada en unidades de precio absolutas (0 lo deshabilita).
TakeProfit
Distancia del take-profit desde el precio de entrada en unidades de precio absolutas (0 lo deshabilita).
Volume
Volumen de operación en lotes.
Notas
Solo se procesan las velas completadas.
Las operaciones se ejecutan con órdenes de mercado (BuyMarket/SellMarket).
Los parámetros FramaPeriod y SignalPeriod admiten optimización.
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>
/// Fractal AMA MBK crossover strategy.
/// Uses FRAMA and a signal EMA to generate trade signals on crossover.
/// </summary>
public class FractalAmaMbkStrategy : Strategy
{
private readonly StrategyParam<int> _framaPeriod;
private readonly StrategyParam<int> _signalPeriod;
private readonly StrategyParam<DataType> _candleType;
private decimal _prevFrama;
private decimal _prevSignal;
private bool _isFirst = true;
public int FramaPeriod { get => _framaPeriod.Value; set => _framaPeriod.Value = value; }
public int SignalPeriod { get => _signalPeriod.Value; set => _signalPeriod.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public FractalAmaMbkStrategy()
{
_framaPeriod = Param(nameof(FramaPeriod), 18)
.SetGreaterThanZero()
.SetDisplay("FRAMA Period", "Period for Fractal Adaptive Moving Average", "Indicator");
_signalPeriod = Param(nameof(SignalPeriod), 18)
.SetGreaterThanZero()
.SetDisplay("Signal EMA Period", "Period for signal EMA", "Indicator");
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Type of candles to use", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevFrama = default;
_prevSignal = default;
_isFirst = true;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_isFirst = true;
var frama = new FractalAdaptiveMovingAverage { Length = FramaPeriod };
var signal = new ExponentialMovingAverage { Length = SignalPeriod };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(frama, signal, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, frama);
DrawIndicator(area, signal);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal framaValue, decimal signalValue)
{
if (candle.State != CandleStates.Finished)
return;
if (_isFirst)
{
_prevFrama = framaValue;
_prevSignal = signalValue;
_isFirst = false;
return;
}
// Detect crossover
var wasAbove = _prevFrama > _prevSignal;
var isAbove = framaValue > signalValue;
if (!wasAbove && isAbove && Position <= 0)
{
// FRAMA crossed above signal -> buy
if (Position < 0) BuyMarket();
BuyMarket();
}
else if (wasAbove && !isAbove && Position >= 0)
{
// FRAMA crossed below signal -> sell
if (Position > 0) SellMarket();
SellMarket();
}
_prevFrama = framaValue;
_prevSignal = signalValue;
}
}
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 FractalAdaptiveMovingAverage, ExponentialMovingAverage
from StockSharp.Algo.Strategies import Strategy
class fractal_ama_mbk_strategy(Strategy):
def __init__(self):
super(fractal_ama_mbk_strategy, self).__init__()
self._frama_period = self.Param("FramaPeriod", 18) \
.SetDisplay("FRAMA Period", "Period for Fractal Adaptive Moving Average", "Indicator")
self._signal_period = self.Param("SignalPeriod", 18) \
.SetDisplay("Signal EMA Period", "Period for signal EMA", "Indicator")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Type of candles to use", "General")
self._prev_frama = 0.0
self._prev_signal = 0.0
self._is_first = True
@property
def FramaPeriod(self):
return self._frama_period.Value
@FramaPeriod.setter
def FramaPeriod(self, value):
self._frama_period.Value = value
@property
def SignalPeriod(self):
return self._signal_period.Value
@SignalPeriod.setter
def SignalPeriod(self, value):
self._signal_period.Value = value
@property
def CandleType(self):
return self._candle_type.Value
@CandleType.setter
def CandleType(self, value):
self._candle_type.Value = value
def OnStarted2(self, time):
super(fractal_ama_mbk_strategy, self).OnStarted2(time)
self._is_first = True
frama = FractalAdaptiveMovingAverage()
frama.Length = self.FramaPeriod
signal = ExponentialMovingAverage()
signal.Length = self.SignalPeriod
self.SubscribeCandles(self.CandleType) \
.Bind(frama, signal, self.ProcessCandle) \
.Start()
def ProcessCandle(self, candle, frama_value, signal_value):
if candle.State != CandleStates.Finished:
return
frama = float(frama_value)
signal = float(signal_value)
if self._is_first:
self._prev_frama = frama
self._prev_signal = signal
self._is_first = False
return
was_above = self._prev_frama > self._prev_signal
is_above = frama > signal
if not was_above and is_above and self.Position <= 0:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
elif was_above and not is_above and self.Position >= 0:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
self._prev_frama = frama
self._prev_signal = signal
def OnReseted(self):
super(fractal_ama_mbk_strategy, self).OnReseted()
self._prev_frama = 0.0
self._prev_signal = 0.0
self._is_first = True
def CreateClone(self):
return fractal_ama_mbk_strategy()