Estrategia de Escalpe con Momentum Chaikin
Esta estrategia de escalpe utiliza el oscilador Chaikin para capturar cambios de momentum. Las operaciones largas ocurren cuando el oscilador cruza por encima de cero y el precio está por encima de la SMA de 200 períodos. Las operaciones cortas ocurren con un cruce por debajo de cero y el precio por debajo de la SMA. Los múltiplos del ATR definen los niveles de stop-loss y take-profit.
Detalles
- Criterios de entrada: El oscilador Chaikin cruza por encima/debajo de cero con el precio por encima/debajo de la SMA.
- Largo/Corto: Ambos.
- Criterios de salida: Stop-loss y take-profit basados en ATR.
- Stops: Sí.
- Valores predeterminados:
FastLength= 3SlowLength= 10SmaLength= 200AtrLength= 14AtrMultiplierSL= 1.5mAtrMultiplierTP= 2.0mCandleType= TimeSpan.FromHours(1)
- Filtros:
- Categoría: Momentum
- Dirección: Ambos
- Indicadores: Chaikin Oscillator, SMA, ATR
- Stops: Sí
- Complejidad: Básico
- Marco temporal: Intradía
- 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>
/// Chaikin Momentum Scalper strategy.
/// The Chaikin oscillator is EMA(FastLength) minus EMA(SlowLength) of the accumulation/distribution line. A cross above zero with the
/// close above SMA(SmaLength) goes long, a cross below zero with the close below the SMA goes short, reversing an opposite position.
/// Each entry freezes a stop AtrMultiplierSL ATRs and a target AtrMultiplierTP ATRs away.
/// </summary>
public class ChaikinMomentumScalperStrategy : Strategy
{
private readonly StrategyParam<int> _fastLength;
private readonly StrategyParam<int> _slowLength;
private readonly StrategyParam<int> _smaLength;
private readonly StrategyParam<int> _atrLength;
private readonly StrategyParam<decimal> _atrMultiplierSl;
private readonly StrategyParam<decimal> _atrMultiplierTp;
private readonly StrategyParam<DataType> _candleType;
private ExponentialMovingAverage _fastAdl;
private ExponentialMovingAverage _slowAdl;
private decimal _adl;
private decimal? _prevOscillator;
private decimal? _stopPrice;
private decimal? _targetPrice;
/// <summary>
/// Fast EMA period of the oscillator.
/// </summary>
public int FastLength
{
get => _fastLength.Value;
set => _fastLength.Value = value;
}
/// <summary>
/// Slow EMA period of the oscillator.
/// </summary>
public int SlowLength
{
get => _slowLength.Value;
set => _slowLength.Value = value;
}
/// <summary>
/// Period of the trend SMA.
/// </summary>
public int SmaLength
{
get => _smaLength.Value;
set => _smaLength.Value = value;
}
/// <summary>
/// ATR period.
/// </summary>
public int AtrLength
{
get => _atrLength.Value;
set => _atrLength.Value = value;
}
/// <summary>
/// ATR multiple of the stop.
/// </summary>
public decimal AtrMultiplierSL
{
get => _atrMultiplierSl.Value;
set => _atrMultiplierSl.Value = value;
}
/// <summary>
/// ATR multiple of the target.
/// </summary>
public decimal AtrMultiplierTP
{
get => _atrMultiplierTp.Value;
set => _atrMultiplierTp.Value = value;
}
/// <summary>
/// Candle type.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Constructor.
/// </summary>
public ChaikinMomentumScalperStrategy()
{
_fastLength = Param(nameof(FastLength), 3)
.SetGreaterThanZero()
.SetDisplay("Fast Length", "Fast EMA period of the oscillator", "Chaikin");
_slowLength = Param(nameof(SlowLength), 10)
.SetGreaterThanZero()
.SetDisplay("Slow Length", "Slow EMA period of the oscillator", "Chaikin");
_smaLength = Param(nameof(SmaLength), 200)
.SetGreaterThanZero()
.SetDisplay("SMA Length", "Period of the trend SMA", "Trend");
_atrLength = Param(nameof(AtrLength), 14)
.SetGreaterThanZero()
.SetDisplay("ATR Length", "ATR period", "Risk");
_atrMultiplierSl = Param(nameof(AtrMultiplierSL), 1.5m)
.SetGreaterThanZero()
.SetDisplay("ATR Multiplier SL", "ATR multiple of the stop", "Risk");
_atrMultiplierTp = Param(nameof(AtrMultiplierTP), 2.0m)
.SetGreaterThanZero()
.SetDisplay("ATR Multiplier TP", "ATR multiple of the target", "Risk");
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).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();
ResetState();
}
private void ResetState()
{
_fastAdl = null;
_slowAdl = null;
_adl = 0m;
_prevOscillator = null;
_stopPrice = null;
_targetPrice = null;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
ResetState();
_fastAdl = new ExponentialMovingAverage { Length = FastLength };
_slowAdl = new ExponentialMovingAverage { Length = SlowLength };
var sma = new SimpleMovingAverage { Length = SmaLength };
var atr = new AverageTrueRange { Length = AtrLength };
var subscription = SubscribeCandles(CandleType);
subscription
.BindEx(sma, atr, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, sma);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, IIndicatorValue smaValue, IIndicatorValue atrValue)
{
if (candle.State != CandleStates.Finished)
return;
var range = candle.HighPrice - candle.LowPrice;
if (range > 0)
_adl += ((candle.ClosePrice - candle.LowPrice) - (candle.HighPrice - candle.ClosePrice)) / range * candle.TotalVolume;
var fast = _fastAdl.Process(new DecimalIndicatorValue(_fastAdl, _adl, candle.OpenTime) { IsFinal = true });
var slow = _slowAdl.Process(new DecimalIndicatorValue(_slowAdl, _adl, candle.OpenTime) { IsFinal = true });
if (!fast.IsFormed || !slow.IsFormed)
return;
var oscillator = fast.GetValue<decimal>() - slow.GetValue<decimal>();
var prevOscillator = _prevOscillator;
_prevOscillator = oscillator;
if (!smaValue.IsFormed || !atrValue.IsFormed || prevOscillator is not decimal prev)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
// Stop and target frozen at entry.
if (Position > 0 && _stopPrice is decimal longStop && _targetPrice is decimal longTarget && (candle.LowPrice <= longStop || candle.HighPrice >= longTarget))
{
SellMarket(Position);
_stopPrice = null;
_targetPrice = null;
return;
}
if (Position < 0 && _stopPrice is decimal shortStop && _targetPrice is decimal shortTarget && (candle.HighPrice >= shortStop || candle.LowPrice <= shortTarget))
{
BuyMarket(-Position);
_stopPrice = null;
_targetPrice = null;
return;
}
var close = candle.ClosePrice;
var sma = smaValue.GetValue<decimal>();
var atr = atrValue.GetValue<decimal>();
if (prev <= 0 && oscillator > 0 && close > sma && Position <= 0)
{
BuyMarket(Volume + Math.Abs(Position));
_stopPrice = close - atr * AtrMultiplierSL;
_targetPrice = close + atr * AtrMultiplierTP;
}
else if (prev >= 0 && oscillator < 0 && close < sma && Position >= 0)
{
SellMarket(Volume + Math.Abs(Position));
_stopPrice = close + atr * AtrMultiplierSL;
_targetPrice = close - atr * AtrMultiplierTP;
}
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
clr.AddReference("StockSharp.BusinessEntities")
from System import TimeSpan, Decimal
from StockSharp.Messages import DataType, CandleStates
from StockSharp.Algo.Indicators import ExponentialMovingAverage, SimpleMovingAverage, AverageTrueRange, DecimalIndicatorValue
from StockSharp.Algo.Strategies import Strategy
class chaikin_momentum_scalper_strategy(Strategy):
"""
Chaikin Momentum Scalper strategy.
The Chaikin oscillator is EMA(FastLength) minus EMA(SlowLength) of the accumulation/distribution line. A cross above zero with the
close above SMA(SmaLength) goes long, a cross below zero with the close below the SMA goes short, reversing an opposite position.
Each entry freezes a stop AtrMultiplierSL ATRs and a target AtrMultiplierTP ATRs away.
"""
def __init__(self):
super(chaikin_momentum_scalper_strategy, self).__init__()
self._fast_length = self.Param("FastLength", 3).SetGreaterThanZero().SetDisplay("Fast Length", "Fast EMA period of the oscillator", "Chaikin")
self._slow_length = self.Param("SlowLength", 10).SetGreaterThanZero().SetDisplay("Slow Length", "Slow EMA period of the oscillator", "Chaikin")
self._sma_length = self.Param("SmaLength", 200).SetGreaterThanZero().SetDisplay("SMA Length", "Period of the trend SMA", "Trend")
self._atr_length = self.Param("AtrLength", 14).SetGreaterThanZero().SetDisplay("ATR Length", "ATR period", "Risk")
self._atr_multiplier_sl = self.Param("AtrMultiplierSL", 1.5).SetGreaterThanZero().SetDisplay("ATR Multiplier SL", "ATR multiple of the stop", "Risk")
self._atr_multiplier_tp = self.Param("AtrMultiplierTP", 2.0).SetGreaterThanZero().SetDisplay("ATR Multiplier TP", "ATR multiple of the target", "Risk")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(1))).SetDisplay("Candle Type", "Type of candles to use", "General")
self._reset_state()
@property
def candle_type(self):
return self._candle_type.Value
def _reset_state(self):
self._fast_adl = None
self._slow_adl = None
self._adl = Decimal(0)
self._prev_oscillator = None
self._stop_price = None
self._target_price = None
def OnReseted(self):
super(chaikin_momentum_scalper_strategy, self).OnReseted()
self._reset_state()
def OnStarted2(self, time):
super(chaikin_momentum_scalper_strategy, self).OnStarted2(time)
self._reset_state()
self._fast_adl = ExponentialMovingAverage()
self._fast_adl.Length = self._fast_length.Value
self._slow_adl = ExponentialMovingAverage()
self._slow_adl.Length = self._slow_length.Value
sma = SimpleMovingAverage()
sma.Length = self._sma_length.Value
atr = AverageTrueRange()
atr.Length = self._atr_length.Value
subscription = self.SubscribeCandles(self.candle_type)
subscription.BindEx(sma, atr, self._process_candle).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, sma)
self.DrawOwnTrades(area)
def _feed(self, indicator, value, time):
indicator_input = DecimalIndicatorValue(indicator, value, time)
indicator_input.IsFinal = True
return indicator.Process(indicator_input)
def _process_candle(self, candle, sma_value, atr_value):
if candle.State != CandleStates.Finished:
return
price_range = candle.HighPrice - candle.LowPrice
if price_range > 0:
self._adl += ((candle.ClosePrice - candle.LowPrice) - (candle.HighPrice - candle.ClosePrice)) / price_range * candle.TotalVolume
fast = self._feed(self._fast_adl, self._adl, candle.OpenTime)
slow = self._feed(self._slow_adl, self._adl, candle.OpenTime)
if not fast.IsFormed or not slow.IsFormed:
return
oscillator = fast.GetValue[Decimal](None) - slow.GetValue[Decimal](None)
prev = self._prev_oscillator
self._prev_oscillator = oscillator
if not sma_value.IsFormed or not atr_value.IsFormed or prev is None:
return
if not self.IsFormedAndOnlineAndAllowTrading():
return
# Stop and target frozen at entry.
if self.Position > 0 and self._stop_price is not None and self._target_price is not None and (candle.LowPrice <= self._stop_price or candle.HighPrice >= self._target_price):
self.SellMarket(self.Position)
self._stop_price = None
self._target_price = None
return
if self.Position < 0 and self._stop_price is not None and self._target_price is not None and (candle.HighPrice >= self._stop_price or candle.LowPrice <= self._target_price):
self.BuyMarket(-self.Position)
self._stop_price = None
self._target_price = None
return
close = candle.ClosePrice
sma = sma_value.GetValue[Decimal](None)
atr = atr_value.GetValue[Decimal](None)
sl = Decimal(self._atr_multiplier_sl.Value)
tp = Decimal(self._atr_multiplier_tp.Value)
if prev <= 0 and oscillator > 0 and close > sma and self.Position <= 0:
self.BuyMarket(self.Volume + abs(self.Position))
self._stop_price = close - atr * sl
self._target_price = close + atr * tp
elif prev >= 0 and oscillator < 0 and close < sma and self.Position >= 0:
self.SellMarket(self.Volume + abs(self.Position))
self._stop_price = close + atr * sl
self._target_price = close - atr * tp
def CreateClone(self):
return chaikin_momentum_scalper_strategy()