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;
}
}
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
from StockSharp.Algo.Strategies import Strategy
class frama_candle_trend_strategy(Strategy):
def __init__(self):
super(frama_candle_trend_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Timeframe for indicator calculation", "General")
self._frama_period = self.Param("FramaPeriod", 15) \
.SetDisplay("FrAMA Period", "Length of the Fractal Adaptive Moving Average", "Indicator")
self._prev_frama_value = 0.0
self._prev_prev_frama_value = 0.0
self._has_prev = False
@property
def candle_type(self):
return self._candle_type.Value
@property
def frama_period(self):
return self._frama_period.Value
def OnReseted(self):
super(frama_candle_trend_strategy, self).OnReseted()
self._prev_frama_value = 0.0
self._prev_prev_frama_value = 0.0
self._has_prev = False
def OnStarted2(self, time):
super(frama_candle_trend_strategy, self).OnStarted2(time)
self._has_prev = False
frama = FractalAdaptiveMovingAverage()
frama.Length = self.frama_period
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(frama, self.on_process).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, frama)
self.DrawOwnTrades(area)
def on_process(self, candle, frama_value):
if candle.State != CandleStates.Finished:
return
frama_value = float(frama_value)
if not self._has_prev:
self._prev_frama_value = frama_value
self._has_prev = True
return
rising = frama_value > self._prev_frama_value
falling = frama_value < self._prev_frama_value
was_rising = self._prev_frama_value > self._prev_prev_frama_value
was_falling = self._prev_frama_value < self._prev_prev_frama_value
if rising and was_falling and self.Position <= 0:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
elif falling and was_rising and self.Position >= 0:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
self._prev_prev_frama_value = self._prev_frama_value
self._prev_frama_value = frama_value
def CreateClone(self):
return frama_candle_trend_strategy()