Esta estrategia replica la lógica del Asesor Experto original "CHO Smoothed EA". Observa los cruces del oscilador Chaikin en velas completadas y suaviza el oscilador con una media móvil configurable. Los filtros opcionales limitan las operaciones a una sesión específica, restringen la dirección de las operaciones y validan las señales con confirmación de línea cero. Cuando se acepta una señal, la estrategia envía una orden de mercado y gestiona la posición utilizando distancias fijas en puntos para protección de stop-loss, take-profit y trailing.
Lógica de trading
Los valores del Oscilador Chaikin se calculan en cada vela terminada con períodos rápidos y lentos configurables.
Una media móvil del oscilador crea la línea de señal. El período y el tipo de media móvil se pueden ajustar.
Las entradas largas se producen cuando el oscilador cruza por encima de la línea suavizada. Las entradas cortas ocurren en el cruce opuesto. Las señales se pueden revertir para operar en contra de la dirección original.
Si el filtro de nivel cero está habilitado, ambos valores del oscilador deben estar por debajo de cero para operaciones largas y por encima de cero para operaciones cortas.
La estrategia puede cerrar automáticamente posiciones opuestas antes de iniciar una nueva operación o ignorar las señales hasta que la posición actual sea plana. También puede imponer un modo de posición única.
El comercio se puede restringir a una ventana de tiempo diaria. Se admiten ventanas que cruzan la medianoche.
Después de una entrada, la estrategia almacena el precio de entrada, convierte las distancias de puntos configuradas en compensaciones de precios y monitorea las velas para eventos de stop-loss, take-profit y trailing-stop.
Gestión del riesgo
Los niveles de stop-loss y take-profit se calculan a partir del precio de entrada utilizando distancias entre puntos multiplicadas por el paso del precio del instrumento.
El trailing stop se activa después de que el precio avanza en el paso de seguimiento configurado y luego sigue la distancia de seguimiento.
Cuando se alcanza un nivel de protección, la posición se cierra inmediatamente con una orden de mercado y se restablecen todos los niveles de riesgo.
Parámetros
Tipo de vela: período de tiempo utilizado para crear las velas para los cálculos del indicador.
Período rápido / Período lento – Períodos rápidos y lentos del oscilador Chaikin.
Período MA de señal/Tipo MA de señal: suaviza los ajustes de media móvil aplicados al oscilador.
Usar nivel cero: requiere que ambos valores de oscilador estén en el lado correcto de cero antes de operar.
Modo comercial: permite solo direcciones largas, solo cortas o ambas direcciones.
Señales inversas: intercambia entradas largas y cortas.
Cerrar opuesto: cierre posiciones opuestas existentes antes de abrir una nueva operación.
Solo una posición: evita entradas cuando una posición ya está abierta.
Usar control de tiempo/hora de inicio/hora de finalización: habilite y configure la ventana de negociación diaria.
Stop Loss (pts) – distancia en puntos para la parada de protección.
Take Profit (pts) – distancia en puntos para objetivos de ganancias.
Trailing Stop (pts) – distancia del trailing stop en puntos.
Trailing Step (pts) – movimiento mínimo favorable (en puntos) antes de mover el trailing stop.
Notas adicionales
Establezca la propiedad Volume de la estrategia antes de iniciarla para controlar el tamaño de la operación.
Debido a que la estrategia emite órdenes de mercado, garantiza suficiente liquidez y considera el deslizamiento en entornos reales.
Cuando los tiempos de inicio y finalización de la ventana de negociación son iguales, la estrategia permanece inactiva, coincidiendo con el comportamiento original del Asesor Experto.
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>
/// Trades CCI oscillator zero-line crossovers with signal MA smoothing.
/// Originally based on Chaikin Oscillator concept, adapted to use CCI.
/// </summary>
public class ChoSmoothedEaStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _cciPeriod;
private readonly StrategyParam<int> _maPeriod;
private CommodityChannelIndex _cci;
private readonly Queue<decimal> _cciHistory = new();
private decimal? _prevCci;
private decimal? _prevSignal;
/// <summary>
/// Initializes a new instance of the <see cref="ChoSmoothedEaStrategy"/> class.
/// </summary>
public ChoSmoothedEaStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(60).TimeFrame())
.SetDisplay("Candle Type", "Timeframe for signal calculations", "General");
_cciPeriod = Param(nameof(CciPeriod), 20)
.SetGreaterThanZero()
.SetDisplay("CCI Period", "Period for CCI oscillator", "Indicator");
_maPeriod = Param(nameof(MaPeriod), 9)
.SetGreaterThanZero()
.SetDisplay("Signal MA Period", "Period of smoothing moving average on CCI", "Indicator");
}
/// <summary>
/// Candle type used for calculations.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// CCI oscillator period.
/// </summary>
public int CciPeriod
{
get => _cciPeriod.Value;
set => _cciPeriod.Value = value;
}
/// <summary>
/// Period of the smoothing moving average.
/// </summary>
public int MaPeriod
{
get => _maPeriod.Value;
set => _maPeriod.Value = value;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_prevCci = null;
_prevSignal = null;
_cciHistory.Clear();
_cci = new CommodityChannelIndex { Length = CciPeriod };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(_cci, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal cciValue)
{
if (candle.State != CandleStates.Finished)
return;
_cciHistory.Enqueue(cciValue);
while (_cciHistory.Count > MaPeriod)
_cciHistory.Dequeue();
if (!_cci.IsFormed)
return;
if (_cciHistory.Count < MaPeriod)
{
_prevCci = cciValue;
return;
}
// Calculate signal line (SMA of CCI)
var sum = 0m;
var history = _cciHistory.ToArray();
foreach (var v in history)
sum += v;
var signalValue = sum / history.Length;
if (_prevCci is null || _prevSignal is null)
{
_prevCci = cciValue;
_prevSignal = signalValue;
return;
}
var crossUp = _prevCci <= _prevSignal && cciValue > signalValue;
var crossDown = _prevCci >= _prevSignal && cciValue < signalValue;
var volume = Volume;
if (volume <= 0)
volume = 1;
var minSpread = 25m;
if (crossUp && Math.Abs(cciValue - signalValue) >= minSpread)
{
if (Position <= 0)
BuyMarket(Position < 0 ? Math.Abs(Position) + volume : volume);
}
else if (crossDown && Math.Abs(cciValue - signalValue) >= minSpread)
{
if (Position >= 0)
SellMarket(Position > 0 ? Math.Abs(Position) + volume : volume);
}
_prevCci = cciValue;
_prevSignal = signalValue;
}
/// <inheritdoc />
protected override void OnReseted()
{
_prevCci = null;
_prevSignal = null;
_cci = null;
_cciHistory.Clear();
base.OnReseted();
}
}