La Estrategia VR Overturn implementa una lógica simple de martingala/anti-martingala.
Siempre mantiene una sola posición y, una vez cerrada, abre inmediatamente una nueva
basándose en el resultado de la operación anterior.
Lógica de la estrategia
Abrir la primera posición según StartSide con volumen StartVolume.
Adjuntar stop-loss y take-profit usando desplazamientos en puntos.
Cuando la posición se cierra:
Calcular el beneficio de la última operación.
Para el modo Martingale:
Después de una operación rentable, restablecer el volumen a StartVolume y mantener la misma dirección.
Después de una operación con pérdida, multiplicar el volumen por Multiplier e invertir la dirección.
Para el modo AntiMartingale:
Después de una operación rentable, multiplicar el volumen por Multiplier y mantener la misma dirección.
Después de una operación con pérdida, restablecer el volumen a StartVolume e invertir la dirección.
Abrir la siguiente posición usando la dirección y el volumen calculados.
El proceso se repite indefinidamente mientras la estrategia está en ejecución.
Parámetros
Nombre
Descripción
Mode
Modo de trading: Martingale o AntiMartingale.
StartSide
Lado de la primera operación (Buy o Sell).
TakeProfit
Valor de take-profit en puntos desde el precio de entrada.
StopLoss
Valor de stop-loss en puntos desde el precio de entrada.
StartVolume
Volumen inicial utilizado para la primera orden.
Multiplier
Multiplicador aplicado al volumen después de un beneficio o pérdida.
Notas
Las órdenes de protección se registran como órdenes stop y límite.
En todo momento solo existe una posición.
La estrategia no utiliza ningún indicador de mercado.
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>
/// Overturn strategy using EMA crossover.
/// </summary>
public class VROverturnStrategy : Strategy
{
private readonly StrategyParam<int> _fastPeriod;
private readonly StrategyParam<int> _slowPeriod;
private readonly StrategyParam<DataType> _candleType;
private decimal _prevFast;
private decimal _prevSlow;
private bool _hasPrev;
public int FastPeriod { get => _fastPeriod.Value; set => _fastPeriod.Value = value; }
public int SlowPeriod { get => _slowPeriod.Value; set => _slowPeriod.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public VROverturnStrategy()
{
_fastPeriod = Param(nameof(FastPeriod), 12)
.SetGreaterThanZero()
.SetDisplay("Fast Period", "Fast EMA period", "General");
_slowPeriod = Param(nameof(SlowPeriod), 26)
.SetGreaterThanZero()
.SetDisplay("Slow Period", "Slow EMA period", "General");
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Candle type", "General");
}
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
=> [(Security, CandleType)];
protected override void OnReseted()
{
base.OnReseted();
_prevFast = 0;
_prevSlow = 0;
_hasPrev = false;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var fast = new ExponentialMovingAverage { Length = FastPeriod };
var slow = new ExponentialMovingAverage { Length = SlowPeriod };
SubscribeCandles(CandleType)
.Bind(fast, slow, ProcessCandle)
.Start();
}
private void ProcessCandle(ICandleMessage candle, decimal fastVal, decimal slowVal)
{
if (candle.State != CandleStates.Finished) return;
if (!_hasPrev)
{
_prevFast = fastVal;
_prevSlow = slowVal;
_hasPrev = true;
return;
}
var crossUp = _prevFast <= _prevSlow && fastVal > slowVal;
var crossDown = _prevFast >= _prevSlow && fastVal < slowVal;
if (crossUp && Position <= 0)
{
if (Position < 0) BuyMarket();
BuyMarket();
}
else if (crossDown && Position >= 0)
{
if (Position > 0) SellMarket();
SellMarket();
}
_prevFast = fastVal;
_prevSlow = slowVal;
}
}