Estrategia de Reversión del Cuerpo de Vela Go
Estrategia basada en el indicador Go que promedia el tamaño del cuerpo de la vela. Abre una posición larga cuando el cuerpo suavizado de la vela cruza por debajo de cero después de ser positivo y abre una posición corta en el cruce opuesto. Las posiciones existentes se cierran con señales opuestas.
Detalles
- Criterios de entrada: cambio de signo del SMA del cuerpo (positivo a negativo para largo, negativo a positivo para corto)
- Largo/Corto: Ambos
- Criterios de salida: cambio de signo opuesto del SMA del cuerpo
- Stops: No
- Valores predeterminados:
Period= 174CandleType= 1 hora
- Filtros:
- Categoría: Reversión
- Dirección: Largo y Corto
- Indicadores: SMA
- Stops: No
- 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.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Counter-trend reversal on the sign of the simple moving average of candle bodies.
/// A positive-to-negative sign change buys; a negative-to-positive change sells.
/// </summary>
public class GoCandleBodyReversalStrategy : Strategy
{
private readonly StrategyParam<int> _period;
private readonly StrategyParam<DataType> _candleType;
private readonly Queue<decimal> _bodies = new();
private decimal _bodySum;
private int _prevNonzeroSign;
public int Period { get => _period.Value; set => _period.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public GoCandleBodyReversalStrategy()
{
_period = Param(nameof(Period), 174)
.SetGreaterThanZero()
.SetDisplay("Period", "SMA period for candle body", "Parameters");
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).TimeFrame())
.SetDisplay("Candle Type", "Type of candles", "Parameters");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
=> [(Security, CandleType)];
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_bodies.Clear();
_bodySum = 0m;
_prevNonzeroSign = 0;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_bodies.Clear();
_bodySum = 0m;
_prevNonzeroSign = 0;
var subscription = SubscribeCandles(CandleType);
subscription.Bind(ProcessCandle).Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle)
{
if (candle.State != CandleStates.Finished)
return;
var body = candle.ClosePrice - candle.OpenPrice;
_bodies.Enqueue(body);
_bodySum += body;
if (_bodies.Count > Period)
_bodySum -= _bodies.Dequeue();
if (_bodies.Count < Period)
return;
var sign = Math.Sign(_bodySum); // Dividing by positive Period does not change the SMA sign.
if (sign == 0)
return; // Retain the last nonzero sign across exact-zero SMA readings.
var previous = _prevNonzeroSign;
_prevNonzeroSign = sign;
if (previous == 0 || previous == sign || !IsFormedAndOnlineAndAllowTrading())
return;
var position = Position;
if (previous > 0 && sign < 0 && position <= 0m)
{
if (position < 0m)
BuyMarket(-position);
BuyMarket(Volume);
}
else if (previous < 0 && sign > 0 && position >= 0m)
{
if (position > 0m)
SellMarket(position);
SellMarket(Volume);
}
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Strategies")
from System import TimeSpan, Decimal
from StockSharp.Messages import DataType, CandleStates
from StockSharp.Algo.Strategies import Strategy
class go_candle_body_reversal_strategy(Strategy):
"""Buy on body SMA crossing from positive to negative; sell on reverse."""
def __init__(self):
super(go_candle_body_reversal_strategy, self).__init__()
self._period = self.Param("Period", 174) \
.SetDisplay("Period", "SMA period for candle body", "Parameters")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(1))) \
.SetDisplay("Candle Type", "Type of candles", "Parameters")
self._bodies = []
self._body_sum = Decimal.Zero
self._prev_nonzero_sign = 0
@property
def Period(self):
return self._period.Value
@Period.setter
def Period(self, value):
self._period.Value = value
@property
def CandleType(self):
return self._candle_type.Value
@CandleType.setter
def CandleType(self, value):
self._candle_type.Value = value
def OnReseted(self):
super(go_candle_body_reversal_strategy, self).OnReseted()
self._bodies = []
self._body_sum = Decimal.Zero
self._prev_nonzero_sign = 0
def OnStarted2(self, time):
super(go_candle_body_reversal_strategy, self).OnStarted2(time)
self._bodies = []
self._body_sum = Decimal.Zero
self._prev_nonzero_sign = 0
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(self.process_candle).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawOwnTrades(area)
def process_candle(self, candle):
if candle.State != CandleStates.Finished:
return
body = candle.ClosePrice - candle.OpenPrice
self._bodies.append(body)
self._body_sum += body
length = int(self.Period)
if length <= 0:
raise ValueError('Period must be positive')
if len(self._bodies) > length:
self._body_sum -= self._bodies.pop(0)
if len(self._bodies) < length:
return
sign = (self._body_sum > Decimal.Zero) - (self._body_sum < Decimal.Zero)
if sign == 0:
return
previous = self._prev_nonzero_sign
self._prev_nonzero_sign = sign
if previous == 0 or previous == sign or not self.IsFormedAndOnlineAndAllowTrading():
return
position = self.Position
if previous > 0 and sign < 0 and position <= 0:
if position < 0:
self.BuyMarket(-position)
self.BuyMarket(self.Volume)
elif previous < 0 and sign > 0 and position >= 0:
if position > 0:
self.SellMarket(position)
self.SellMarket(self.Volume)
def CreateClone(self):
return go_candle_body_reversal_strategy()