Estrategia de Media Móvil
La estrategia entra en una posición larga cuando una media móvil corta cruza por encima de una media móvil larga del tipo de precio seleccionado. La posición se cierra cuando la media corta vuelve a cruzar por debajo de la larga.
Detalles
- Criterios de entrada: La MA corta cruza por encima de la MA larga.
- Criterios de salida: La MA corta cruza por debajo de la MA larga.
- Indicadores: SMA, EMA, DEMA, TEMA, WMA, VWMA.
- Fuente de precio: Close, High, Open, Low, Typical, Center.
- Stops: Ninguno.
- Valores predeterminados:
MaType= EMAShortLength= 1LongLength= 20PriceType= TypicalCandleType= 1 minute
- Filtros:
- Categoría: Seguimiento de tendencia
- Dirección: Solo largos
- Indicadores: Media móvil
- Stops: No
- Complejidad: Simple
- Nivel de riesgo: Medio
using System;
using System.Linq;
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>
/// Moving average crossover strategy.
/// </summary>
public class MovingAverageStrategy : Strategy
{
private readonly StrategyParam<int> _shortLength;
private readonly StrategyParam<int> _longLength;
private readonly StrategyParam<int> _cooldownBars;
private readonly StrategyParam<DataType> _candleType;
private decimal _prevFast;
private decimal _prevSlow;
private bool _initialized;
private int _barIndex;
private int _lastTradeBar = -1000000;
public int ShortLength { get => _shortLength.Value; set => _shortLength.Value = value; }
public int LongLength { get => _longLength.Value; set => _longLength.Value = value; }
public int CooldownBars { get => _cooldownBars.Value; set => _cooldownBars.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public MovingAverageStrategy()
{
_shortLength = Param(nameof(ShortLength), 6).SetGreaterThanZero();
_longLength = Param(nameof(LongLength), 21).SetGreaterThanZero();
_cooldownBars = Param(nameof(CooldownBars), 50).SetGreaterThanZero();
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame());
}
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_initialized = false;
_barIndex = 0;
_lastTradeBar = -1000000;
var fastMa = new EMA { Length = ShortLength };
var slowMa = new EMA { Length = LongLength };
var subscription = SubscribeCandles(CandleType);
subscription.Bind(fastMa, slowMa, ProcessCandle).Start();
}
private void ProcessCandle(ICandleMessage candle, decimal fast, decimal slow)
{
if (candle.State != CandleStates.Finished)
return;
_barIndex++;
if (!_initialized)
{
_prevFast = fast;
_prevSlow = slow;
_initialized = true;
return;
}
var canTrade = _barIndex - _lastTradeBar >= CooldownBars;
if (canTrade && _prevFast < _prevSlow && fast >= slow && Position <= 0)
{
BuyMarket();
_lastTradeBar = _barIndex;
}
else if (canTrade && _prevFast >= _prevSlow && fast < slow && Position > 0)
{
SellMarket();
_lastTradeBar = _barIndex;
}
_prevFast = fast;
_prevSlow = slow;
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevFast = 0m;
_prevSlow = 0m;
_initialized = false;
_barIndex = 0;
_lastTradeBar = -1000000;
}
}
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 moving_average_strategy(Strategy):
"""
Moving average crossover: fast/slow EMA cross with cooldown.
"""
def __init__(self):
super(moving_average_strategy, self).__init__()
self._short_length = self.Param("ShortLength", 6).SetDisplay("Fast", "Fast EMA", "Indicators")
self._long_length = self.Param("LongLength", 21).SetDisplay("Slow", "Slow EMA", "Indicators")
self._cooldown_bars = self.Param("CooldownBars", 50).SetDisplay("Cooldown", "Min bars between entries", "Risk")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(5))).SetDisplay("Candle Type", "Candles", "General")
self._prev_fast = 0.0
self._prev_slow = 0.0
self._initialized = False
self._bar_index = 0
self._last_trade_bar = -1000000
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(moving_average_strategy, self).OnReseted()
self._prev_fast = 0.0
self._prev_slow = 0.0
self._initialized = False
self._bar_index = 0
self._last_trade_bar = -1000000
def OnStarted2(self, time):
super(moving_average_strategy, self).OnStarted2(time)
fast = ExponentialMovingAverage()
fast.Length = self._short_length.Value
slow = ExponentialMovingAverage()
slow.Length = self._long_length.Value
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(fast, slow, self._process_candle).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, fast)
self.DrawIndicator(area, slow)
self.DrawOwnTrades(area)
def _process_candle(self, candle, fast_val, slow_val):
if candle.State != CandleStates.Finished:
return
fast = float(fast_val)
slow = float(slow_val)
self._bar_index += 1
if not self._initialized:
self._prev_fast = fast
self._prev_slow = slow
self._initialized = True
return
can_trade = self._bar_index - self._last_trade_bar >= self._cooldown_bars.Value
if can_trade and self._prev_fast < self._prev_slow and fast >= slow and self.Position <= 0:
self.BuyMarket()
self._last_trade_bar = self._bar_index
elif can_trade and self._prev_fast >= self._prev_slow and fast < slow and self.Position > 0:
self.SellMarket()
self._last_trade_bar = self._bar_index
self._prev_fast = fast
self._prev_slow = slow
def CreateClone(self):
return moving_average_strategy()