Esta estrategia opera cruzamientos entre una Media Móvil Simple (SMA) rápida y una lenta.
Opcionalmente evita realizar pérdidas moviendo las posiciones perdedoras al punto de equilibrio cuando aparece la señal opuesta.
Cómo Funciona
Indicadores
SMA rápida
SMA lenta
Entradas
Largo cuando SMA rápida > SMA lenta y la dirección actual no es larga.
Corto cuando SMA rápida < SMA lenta y la dirección actual no es corta.
Se permiten entradas adicionales si Close Losses está deshabilitado y el número de operaciones abiertas está por debajo de Max Deals.
Salidas
En un cruzamiento opuesto.
Si Close Losses está habilitado, la posición se cierra inmediatamente.
Si Close Losses está deshabilitado y la operación está en pérdida, se coloca una orden limitada al precio de entrada para salir en el punto de equilibrio.
Parámetros
Nombre
Descripción
Predeterminado
FastLength
Período de la SMA rápida.
10
SlowLength
Período de la SMA lenta.
30
MaxDeals
Número máximo de operaciones simultáneas.
5
CloseLosses
Cerrar operaciones con pérdidas inmediatamente.
true
Volume
Volumen de la orden.
1
CandleType
Velas para los cálculos.
1-minute
Notas
La estrategia utiliza órdenes de mercado para entradas y salidas. Cuando CloseLosses está deshabilitado, intenta proteger las posiciones colocando una orden limitada al precio de entrada en lugar de cerrar con pérdida.
using System;
using System.Linq;
using System.Collections.Generic;
using Ecng.Common;
using Ecng.Collections;
using Ecng.Serialization;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Lossless Moving Average strategy.
/// Trades fast and slow SMA crossovers.
/// </summary>
public class LosslessMaStrategy : Strategy
{
private readonly StrategyParam<int> _fastLength;
private readonly StrategyParam<int> _slowLength;
private readonly StrategyParam<DataType> _candleType;
private decimal? _prevFast;
private decimal? _prevSlow;
/// <summary>
/// Fast SMA period.
/// </summary>
public int FastLength { get => _fastLength.Value; set => _fastLength.Value = value; }
/// <summary>
/// Slow SMA period.
/// </summary>
public int SlowLength { get => _slowLength.Value; set => _slowLength.Value = value; }
/// <summary>
/// Type of candles used for calculations.
/// </summary>
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
/// <summary>
/// Constructor.
/// </summary>
public LosslessMaStrategy()
{
_fastLength = Param(nameof(FastLength), 10)
.SetGreaterThanZero()
.SetDisplay("Fast MA", "Fast SMA length", "Parameters");
_slowLength = Param(nameof(SlowLength), 30)
.SetGreaterThanZero()
.SetDisplay("Slow MA", "Slow SMA length", "Parameters");
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Candles for strategy", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevFast = _prevSlow = null;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var fastMa = new ExponentialMovingAverage { Length = FastLength };
var slowMa = new ExponentialMovingAverage { Length = SlowLength };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(fastMa, slowMa, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, fastMa);
DrawIndicator(area, slowMa);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal fastValue, decimal slowValue)
{
if (candle.State != CandleStates.Finished)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
var prevFast = _prevFast;
var prevSlow = _prevSlow;
_prevFast = fastValue;
_prevSlow = slowValue;
if (prevFast is null || prevSlow is null)
return;
// Bullish crossover
if (prevFast <= prevSlow && fastValue > slowValue && Position <= 0)
{
if (Position < 0)
BuyMarket();
BuyMarket();
}
// Bearish crossover
if (prevFast >= prevSlow && fastValue < slowValue && Position >= 0)
{
if (Position > 0)
SellMarket();
SellMarket();
}
}
}
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
from StockSharp.Algo.Indicators import ExponentialMovingAverage
from StockSharp.Algo.Strategies import Strategy
class lossless_ma_strategy(Strategy):
def __init__(self):
super(lossless_ma_strategy, self).__init__()
self._fast_length = self.Param("FastLength", 10) \
.SetDisplay("Fast MA", "Fast SMA length", "Parameters")
self._slow_length = self.Param("SlowLength", 30) \
.SetDisplay("Slow MA", "Slow SMA length", "Parameters")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Candles for strategy", "General")
self._prev_fast = None
self._prev_slow = None
@property
def fast_length(self):
return self._fast_length.Value
@property
def slow_length(self):
return self._slow_length.Value
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(lossless_ma_strategy, self).OnReseted()
self._prev_fast = None
self._prev_slow = None
def OnStarted2(self, time):
super(lossless_ma_strategy, self).OnStarted2(time)
fast_ma = ExponentialMovingAverage()
fast_ma.Length = self.fast_length
slow_ma = ExponentialMovingAverage()
slow_ma.Length = self.slow_length
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(fast_ma, slow_ma, self.process_candle).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, fast_ma)
self.DrawIndicator(area, slow_ma)
self.DrawOwnTrades(area)
def process_candle(self, candle, fast_value, slow_value):
if candle.State != CandleStates.Finished:
return
f = float(fast_value)
s = float(slow_value)
if self._prev_fast is not None and self._prev_slow is not None:
# Bullish crossover
if self._prev_fast <= self._prev_slow and f > s and self.Position <= 0:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
# Bearish crossover
if self._prev_fast >= self._prev_slow and f < s and self.Position >= 0:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
self._prev_fast = f
self._prev_slow = s
def CreateClone(self):
return lossless_ma_strategy()