Esta estratégia opera cruzamentos entre uma Média Móvel Simples (SMA) rápida e uma lenta.
Opcionalmente evita realizar perdas movendo posições perdedoras para o ponto de equilíbrio quando o sinal oposto aparece.
Como Funciona
Indicadores
SMA rápida
SMA lenta
Entradas
Comprado quando SMA rápida > SMA lenta e a direção atual não é comprada.
Vendido quando SMA rápida < SMA lenta e a direção atual não é vendida.
Entradas adicionais são permitidas se Close Losses estiver desabilitado e o número de operações abertas estiver abaixo de Max Deals.
Saídas
Em um cruzamento oposto.
Se Close Losses estiver habilitado, a posição é fechada imediatamente.
Se Close Losses estiver desabilitado e a operação estiver com prejuízo, uma ordem limitada é colocada no preço de entrada para sair no ponto de equilíbrio.
Parâmetros
Nome
Descrição
Padrão
FastLength
Período da SMA rápida.
10
SlowLength
Período da SMA lenta.
30
MaxDeals
Número máximo de operações simultâneas.
5
CloseLosses
Fechar operações com prejuízo imediatamente.
true
Volume
Volume da ordem.
1
CandleType
Candles para cálculos.
1-minute
Observações
A estratégia utiliza ordens de mercado para entradas e saídas. Quando CloseLosses está desabilitado, tenta proteger as posições colocando uma ordem limitada no preço de entrada em vez de fechar com prejuízo.
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()