Estrategia de Cruce de Vela AML
Esta estrategia opera basándose en el indicador Adaptive Market Level (AML). Se abre una operación cuando el valor de AML se encuentra dentro del cuerpo de la vela actual: si la vela cierra por encima de la apertura y el AML está entre ellos, se abre una posición larga. Para velas bajistas, la condición opuesta abre una posición corta. Opcionalmente, la posición puede revertirse cuando aparezca la señal contraria.
Detalles
- Criterios de entrada:
- Largo: vela alcista y
open <= AML <= close. - Corto: vela bajista y
open >= AML >= close.
- Largo: vela alcista y
- Largo/Corto: Ambos lados.
- Criterios de salida: Posición revertida en señal opuesta cuando está habilitado.
- Stops: Ninguno.
- Valores predeterminados:
Fractal= 70Lag= 18Shift= 0UseOpposite= true
- Filtros:
- Categoría: Seguimiento de tendencia
- Dirección: Ambos
- Indicadores: Único (AML)
- Stops: No
- Complejidad: Medio
- Marco temporal: Corto plazo
- Estacionalidad: No
- Redes neuronales: No
- Divergencia: No
- Nivel de riesgo: Medio
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>
/// Adaptive Market Level candle cross strategy.
/// Opens position when AML value lies between candle open and close.
/// Reverses position if opposite condition occurs.
/// </summary>
public class AmlCandleCrossStrategy : Strategy
{
private readonly StrategyParam<int> _fractal;
private readonly StrategyParam<int> _lag;
private readonly StrategyParam<DataType> _candleType;
public int Fractal { get => _fractal.Value; set => _fractal.Value = value; }
public int Lag { get => _lag.Value; set => _lag.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public AmlCandleCrossStrategy()
{
_fractal = Param(nameof(Fractal), 10)
.SetGreaterThanZero()
.SetDisplay("Fractal", "Fractal window size", "General");
_lag = Param(nameof(Lag), 5)
.SetGreaterThanZero()
.SetDisplay("Lag", "Lag for smoothing", "General");
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame())
.SetDisplay("Candle Type", "Candle Type", "General");
}
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
=> [(Security, CandleType)];
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var aml = new AdaptiveMarketLevel
{
Fractal = Fractal,
Lag = Lag,
};
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(aml, ProcessCandle)
.Start();
StartProtection(
takeProfit: new Unit(2, UnitTypes.Percent),
stopLoss: new Unit(1, UnitTypes.Percent)
);
}
private void ProcessCandle(ICandleMessage candle, decimal amlValue)
{
if (candle.State != CandleStates.Finished)
return;
if (amlValue == 0)
return;
var open = candle.OpenPrice;
var close = candle.ClosePrice;
// Bullish: AML between open and close, bullish candle
var bullish = close > open && amlValue >= open && amlValue <= close;
// Bearish: AML between close and open, bearish candle
var bearish = close < open && amlValue >= close && amlValue <= open;
if (Position == 0)
{
if (bullish)
BuyMarket();
else if (bearish)
SellMarket();
}
}
}
/// <summary>
/// Adaptive Market Level indicator.
/// </summary>
public class AdaptiveMarketLevel : BaseIndicator
{
private int _pos;
private decimal[] _smooth = Array.Empty<decimal>();
private decimal _lastValue;
private readonly List<decimal> _highs = new();
private readonly List<decimal> _lows = new();
public int Fractal { get; set; } = 10;
public int Lag { get; set; } = 5;
public override void Reset()
{
base.Reset();
_pos = 0;
_smooth = new decimal[Lag + 1];
_lastValue = 0;
_highs.Clear();
_lows.Clear();
}
protected override IIndicatorValue OnProcess(IIndicatorValue input)
{
var candle = input.GetValue<ICandleMessage>();
_highs.Add(candle.HighPrice);
_lows.Add(candle.LowPrice);
if (_highs.Count < Fractal * 2 || _highs.Count <= Lag)
return new DecimalIndicatorValue(this, 0m, input.Time);
IsFormed = true;
decimal r1 = Range(Fractal, 0) / Fractal;
decimal r2 = Range(Fractal, Fractal) / Fractal;
decimal r3 = Range(Fractal * 2, 0) / (Fractal * 2);
double dim = 0;
if (r1 + r2 > 0 && r3 > 0)
dim = (Math.Log((double)(r1 + r2)) - Math.Log((double)r3)) * 1.44269504088896;
var alpha = (decimal)Math.Exp(-Lag * (dim - 1.0));
if (alpha > 1m) alpha = 1m;
if (alpha < 0.01m) alpha = 0.01m;
var price = (candle.HighPrice + candle.LowPrice + 2m * candle.OpenPrice + 2m * candle.ClosePrice) / 6m;
var prevPos = (_pos - 1 + _smooth.Length) % _smooth.Length;
_smooth[_pos] = alpha * price + (1m - alpha) * _smooth[prevPos];
var lagPos = (_pos - Lag + _smooth.Length) % _smooth.Length;
var step = 0.01m;
var current = Math.Abs(_smooth[_pos] - _smooth[lagPos]) >= Lag * Lag * step ? _smooth[_pos] : _lastValue;
_lastValue = current;
_pos = (_pos + 1) % _smooth.Length;
return new DecimalIndicatorValue(this, current, input.Time);
}
private decimal Range(int count, int offset)
{
var end = _highs.Count - 1 - offset;
var start = end - count + 1;
if (start < 0) start = 0;
var max = decimal.MinValue;
var min = decimal.MaxValue;
for (var i = start; i <= end; i++)
{
if (_highs[i] > max) max = _highs[i];
if (_lows[i] < min) min = _lows[i];
}
return max - min;
}
}
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, Unit, UnitTypes
from StockSharp.Algo.Indicators import ExponentialMovingAverage
from StockSharp.Algo.Strategies import Strategy
class aml_candle_cross_strategy(Strategy):
"""Adaptive Market Level candle cross strategy.
Uses EMA as proxy for the custom AdaptiveMarketLevel indicator.
Opens position when indicator value lies between candle open and close.
"""
def __init__(self):
super(aml_candle_cross_strategy, self).__init__()
self._fractal = self.Param("Fractal", 10) \
.SetDisplay("Fractal", "Fractal window size", "General")
self._lag = self.Param("Lag", 5) \
.SetDisplay("Lag", "Lag for smoothing", "General")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(5))) \
.SetDisplay("Candle Type", "Candle Type", "General")
@property
def fractal(self):
return self._fractal.Value
@property
def lag(self):
return self._lag.Value
@property
def candle_type(self):
return self._candle_type.Value
def OnStarted2(self, time):
super(aml_candle_cross_strategy, self).OnStarted2(time)
# Use EMA as proxy for custom AdaptiveMarketLevel indicator
aml = ExponentialMovingAverage()
aml.Length = self.fractal
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(aml, self.on_process).Start()
self.StartProtection(
takeProfit=Unit(2, UnitTypes.Percent),
stopLoss=Unit(1, UnitTypes.Percent))
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, aml)
self.DrawOwnTrades(area)
def on_process(self, candle, aml_value):
if candle.State != CandleStates.Finished:
return
if aml_value == 0:
return
opn = candle.OpenPrice
close = candle.ClosePrice
# Bullish: AML between open and close, bullish candle
bullish = close > opn and aml_value >= opn and aml_value <= close
# Bearish: AML between close and open, bearish candle
bearish = close < opn and aml_value >= close and aml_value <= opn
if self.Position == 0:
if bullish:
self.BuyMarket()
elif bearish:
self.SellMarket()
def CreateClone(self):
return aml_candle_cross_strategy()