La Estrategia JS MA Day opera basándose en una media móvil simple calculada sobre velas diarias usando el precio mediano. La estrategia compara la posición de la media móvil relativa al precio de apertura de cada día y abre posiciones cuando la tendencia de la media móvil confirma un cruce del precio de apertura.
Indicadores
Media Móvil Simple (precio mediano)
Parámetros
Nombre
Descripción
Predeterminado
MaPeriod
Período de la media móvil simple.
3
Reverse
Invierte las señales de negociación. Cuando está habilitado, las señales de compra se convierten en señales de venta y viceversa.
false
CandleType
Tipo de vela usado para los cálculos. Por defecto son velas de marco temporal diario.
TimeFrame(1 day)
Reglas de entrada
Evalúa la media móvil simple (SMA) diaria y los precios de apertura diarios.
Comprar cuando:
La SMA actual está por debajo de la SMA anterior.
La SMA actual está por encima del precio de apertura de hoy.
La SMA anterior está por debajo de la SMA de hace dos días.
La SMA anterior está por encima del precio de apertura del día anterior.
Vender cuando:
La SMA actual está por encima de la SMA anterior.
La SMA actual está por debajo del precio de apertura de hoy.
La SMA anterior está por encima de la SMA de hace dos días.
La SMA anterior está por debajo del precio de apertura del día anterior.
Si Reverse está habilitado, las condiciones de compra y venta se invierten.
Reglas de salida
Las posiciones se cierran llamando a StartProtection, que permite configurar órdenes de protección como stop loss o take profit a través de la configuración de la plataforma.
Notas
La estrategia procesa solo velas completadas.
El volumen de las órdenes está definido por la propiedad Volume de la clase base.
Todavía no existe una versión de esta estrategia en Python.
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>
/// Daily SMA strategy comparing moving average to open price.
/// Opens position when the moving average crosses daily open in trend direction.
/// </summary>
public class JsMaDayStrategy : Strategy
{
private readonly StrategyParam<int> _maPeriod;
private readonly StrategyParam<bool> _reverse;
private readonly StrategyParam<DataType> _candleType;
private readonly List<decimal> _prices = new();
private decimal? _prevMa;
private decimal? _prevOpen;
/// <summary>
/// Moving average period.
/// </summary>
public int MaPeriod
{
get => _maPeriod.Value;
set => _maPeriod.Value = value;
}
/// <summary>
/// Reverse trading signals.
/// </summary>
public bool Reverse
{
get => _reverse.Value;
set => _reverse.Value = value;
}
/// <summary>
/// Candle type used for calculations.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Constructor.
/// </summary>
public JsMaDayStrategy()
{
_maPeriod = Param(nameof(MaPeriod), 5)
.SetGreaterThanZero()
.SetDisplay("MA Period", "SMA period on daily candles", "Parameters")
.SetOptimize(2, 20, 1);
_reverse = Param(nameof(Reverse), false)
.SetDisplay("Reverse Signals", "Reverse entry direction", "Parameters");
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Type of candles for moving average", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prices.Clear();
_prevMa = null;
_prevOpen = null;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
SubscribeCandles(CandleType)
.Bind(ProcessCandle)
.Start();
StartProtection(
new Unit(2000m, UnitTypes.Absolute),
new Unit(1000m, UnitTypes.Absolute));
}
private void ProcessCandle(ICandleMessage candle)
{
if (candle.State != CandleStates.Finished)
return;
_prices.Add(candle.ClosePrice);
if (_prices.Count > MaPeriod)
_prices.RemoveAt(0);
if (_prices.Count < MaPeriod)
return;
var sum = 0m;
foreach (var price in _prices)
sum += price;
var ma = sum / _prices.Count;
var open = candle.OpenPrice;
if (_prevMa is decimal prevMa && _prevOpen is decimal prevOpen)
{
var buyCondition = ma > open && prevMa <= prevOpen;
var sellCondition = ma < open && prevMa >= prevOpen;
if (buyCondition)
{
if (!Reverse && Position <= 0)
BuyMarket();
else if (Reverse && Position >= 0)
SellMarket();
}
else if (sellCondition)
{
if (!Reverse && Position >= 0)
SellMarket();
else if (Reverse && Position <= 0)
BuyMarket();
}
}
_prevMa = ma;
_prevOpen = open;
}
}
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, Unit, UnitTypes
from StockSharp.Algo.Strategies import Strategy
class js_ma_day_strategy(Strategy):
"""
Daily SMA strategy comparing manual moving average to open price.
Trades when MA crosses daily open. Uses StartProtection for SL/TP.
"""
def __init__(self):
super(js_ma_day_strategy, self).__init__()
self._ma_period = self.Param("MaPeriod", 5) \
.SetDisplay("MA Period", "SMA period on daily candles", "Parameters")
self._reverse = self.Param("Reverse", False) \
.SetDisplay("Reverse Signals", "Reverse entry direction", "Parameters")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Type of candles for moving average", "General")
self._prices = []
self._prev_ma = None
self._prev_open = None
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(js_ma_day_strategy, self).OnReseted()
self._prices = []
self._prev_ma = None
self._prev_open = None
def OnStarted2(self, time):
super(js_ma_day_strategy, self).OnStarted2(time)
self.StartProtection(
Unit(2000.0, UnitTypes.Absolute),
Unit(1000.0, UnitTypes.Absolute))
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(self._process_candle).Start()
def _process_candle(self, candle):
if candle.State != CandleStates.Finished:
return
close = float(candle.ClosePrice)
open_price = float(candle.OpenPrice)
period = self._ma_period.Value
self._prices.append(close)
if len(self._prices) > period:
self._prices.pop(0)
if len(self._prices) < period:
return
ma = sum(self._prices) / len(self._prices)
if self._prev_ma is not None and self._prev_open is not None:
buy_cond = ma > open_price and self._prev_ma <= self._prev_open
sell_cond = ma < open_price and self._prev_ma >= self._prev_open
reverse = self._reverse.Value
if buy_cond:
if not reverse and self.Position <= 0:
self.BuyMarket()
elif reverse and self.Position >= 0:
self.SellMarket()
elif sell_cond:
if not reverse and self.Position >= 0:
self.SellMarket()
elif reverse and self.Position <= 0:
self.BuyMarket()
self._prev_ma = ma
self._prev_open = open_price
def CreateClone(self):
return js_ma_day_strategy()