La Estrategia de Inversor Universal utiliza el cruce entre la Media Móvil Exponencial (EMA) y la Media Móvil Ponderada Lineal (LWMA) para determinar la dirección del mercado. Confirma la fuerza de la tendencia verificando que ambas medias se muevan en la misma dirección.
Lógica
Entrada de compra: LWMA está por encima de EMA y ambas medias están subiendo.
Entrada de venta: LWMA está por debajo de EMA y ambas medias están cayendo.
Salida de compra: LWMA cruza por debajo de EMA.
Salida de venta: LWMA cruza por encima de EMA.
La estrategia reduce el tamaño de la posición tras operaciones perdedoras consecutivas cuando el factor de reducción está habilitado.
Parámetros
Nombre
Descripción
MovingPeriod
Longitud para los cálculos de EMA y LWMA.
DecreaseFactor
Factor de reducción de lotes tras pérdidas (0 desactiva la reducción).
CandleType
Tipo de datos de velas para los cálculos.
Volume
Volumen base de operación desde la configuración de la estrategia.
Notas
Funciona únicamente con velas cerradas.
Utiliza la API de alto nivel de StockSharp con vinculación de indicadores.
No se proporciona versión en Python.
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>
/// Strategy based on EMA and WMA crossover with trend confirmation.
/// </summary>
public class UniversalInvestorStrategy : Strategy
{
private readonly StrategyParam<int> _movingPeriod;
private readonly StrategyParam<DataType> _candleType;
private decimal _prevEma;
private decimal _prevLwma;
private bool _hasPrev;
public int MovingPeriod { get => _movingPeriod.Value; set => _movingPeriod.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public UniversalInvestorStrategy()
{
_movingPeriod = Param(nameof(MovingPeriod), 23)
.SetGreaterThanZero()
.SetDisplay("Moving Period", "Smoothing period for EMA and WMA", "Indicators");
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Type of candles for calculations", "General");
}
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
=> [(Security, CandleType)];
protected override void OnReseted()
{
base.OnReseted();
_prevEma = 0;
_prevLwma = 0;
_hasPrev = false;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var ema = new ExponentialMovingAverage { Length = MovingPeriod };
var lwma = new WeightedMovingAverage { Length = MovingPeriod };
SubscribeCandles(CandleType)
.Bind(ema, lwma, ProcessCandle)
.Start();
}
private void ProcessCandle(ICandleMessage candle, decimal emaValue, decimal lwmaValue)
{
if (candle.State != CandleStates.Finished) return;
if (!_hasPrev)
{
_prevEma = emaValue;
_prevLwma = lwmaValue;
_hasPrev = true;
return;
}
var openBuy = lwmaValue > emaValue && lwmaValue > _prevLwma && emaValue > _prevEma;
var openSell = lwmaValue < emaValue && lwmaValue < _prevLwma && emaValue < _prevEma;
var closeBuy = lwmaValue < emaValue;
var closeSell = lwmaValue > emaValue;
if (Position > 0 && closeBuy)
{
SellMarket();
}
else if (Position < 0 && closeSell)
{
BuyMarket();
}
else if (Position == 0)
{
if (openBuy && !closeBuy)
BuyMarket();
else if (openSell && !closeSell)
SellMarket();
}
_prevEma = emaValue;
_prevLwma = lwmaValue;
}
}
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, WeightedMovingAverage
from StockSharp.Algo.Strategies import Strategy
class universal_investor_strategy(Strategy):
def __init__(self):
super(universal_investor_strategy, self).__init__()
self._moving_period = self.Param("MovingPeriod", 23) \
.SetDisplay("Moving Period", "Smoothing period for EMA and WMA", "Indicators")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Type of candles for calculations", "General")
self._prev_ema = 0.0
self._prev_lwma = 0.0
self._has_prev = False
@property
def moving_period(self):
return self._moving_period.Value
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(universal_investor_strategy, self).OnReseted()
self._prev_ema = 0.0
self._prev_lwma = 0.0
self._has_prev = False
def OnStarted2(self, time):
super(universal_investor_strategy, self).OnStarted2(time)
ema = ExponentialMovingAverage()
ema.Length = self.moving_period
lwma = WeightedMovingAverage()
lwma.Length = self.moving_period
self.SubscribeCandles(self.candle_type).Bind(ema, lwma, self.process_candle).Start()
def process_candle(self, candle, ema_value, lwma_value):
if candle.State != CandleStates.Finished:
return
ev = float(ema_value)
lv = float(lwma_value)
if not self._has_prev:
self._prev_ema = ev
self._prev_lwma = lv
self._has_prev = True
return
open_buy = lv > ev and lv > self._prev_lwma and ev > self._prev_ema
open_sell = lv < ev and lv < self._prev_lwma and ev < self._prev_ema
close_buy = lv < ev
close_sell = lv > ev
if self.Position > 0 and close_buy:
self.SellMarket()
elif self.Position < 0 and close_sell:
self.BuyMarket()
elif self.Position == 0:
if open_buy and not close_buy:
self.BuyMarket()
elif open_sell and not close_sell:
self.SellMarket()
self._prev_ema = ev
self._prev_lwma = lv
def CreateClone(self):
return universal_investor_strategy()