Esta estrategia abre operaciones cuando el precio de mercado cruza un nivel definido por el usuario. Se coloca una orden de compra cuando el precio sube a través del nivel y una orden de venta cuando cae por debajo de él. El sistema puede opcionalmente revertir una posición existente si aparece la señal contraria. También admite distancias opcionales de stop-loss y take-profit medidas en unidades de precio.
La estrategia se suscribe a velas y reacciona únicamente cuando una vela está completamente formada. Todos los cálculos se realizan sobre el precio de cierre de cada vela terminada. Cuando el modo de reversión está activado, la posición actual se cierra y se abre una nueva en la dirección opuesta en la siguiente señal.
Detalles
Criterios de entrada:
Largo: el precio de cierre cruza por encima de LevelPrice.
Corto: el precio de cierre cruza por debajo de LevelPrice.
Largo/Corto: Ambos direcciones.
Reversión: Opcional, controlada por EnableReversal.
Stops: Stop-loss y take-profit opcionales en unidades de precio.
Valores predeterminados:
LevelPrice = 100.
StopLoss = 0 (desactivado).
TakeProfit = 0 (desactivado).
EnableReversal = false.
CandleType = marco temporal de 1 minuto.
Filtros:
Categoría: Ruptura
Dirección: Ambos
Indicadores: Ninguno
Stops: Opcional
Complejidad: Simple
Marco temporal: Corto plazo
Estacionalidad: No
Redes neuronales: No
Divergencia: No
Nivel de riesgo: Medio
using System;
using System.Collections.Generic;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Strategy that opens a position when price crosses a moving average level.
/// Reverses the position when price crosses in the opposite direction.
/// </summary>
public class LevelsWithRevolveStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _maPeriod;
private readonly StrategyParam<decimal> _stopPct;
private readonly StrategyParam<decimal> _takePct;
private decimal _prevPrice;
private decimal _prevMa;
private bool _hasPrev;
private decimal _entryPrice;
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public int MaPeriod
{
get => _maPeriod.Value;
set => _maPeriod.Value = value;
}
public decimal StopPct
{
get => _stopPct.Value;
set => _stopPct.Value = value;
}
public decimal TakePct
{
get => _takePct.Value;
set => _takePct.Value = value;
}
public LevelsWithRevolveStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Candle type", "General");
_maPeriod = Param(nameof(MaPeriod), 50)
.SetDisplay("MA Period", "Moving average period for the level", "Parameters");
_stopPct = Param(nameof(StopPct), 1.5m)
.SetDisplay("Stop %", "Stop loss percent from entry", "Risk");
_takePct = Param(nameof(TakePct), 3m)
.SetDisplay("Take %", "Take profit percent from entry", "Risk");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevPrice = 0;
_prevMa = 0;
_hasPrev = false;
_entryPrice = 0;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_prevPrice = 0;
_prevMa = 0;
_hasPrev = false;
_entryPrice = 0;
var ma = new ExponentialMovingAverage { Length = MaPeriod };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(ma, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, ma);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal maValue)
{
if (candle.State != CandleStates.Finished)
return;
var price = candle.ClosePrice;
// Check stop/take
if (Position > 0 && _entryPrice > 0)
{
var pnlPct = (price - _entryPrice) / _entryPrice * 100m;
if (pnlPct >= TakePct || pnlPct <= -StopPct)
{
SellMarket();
_entryPrice = 0;
}
}
else if (Position < 0 && _entryPrice > 0)
{
var pnlPct = (_entryPrice - price) / _entryPrice * 100m;
if (pnlPct >= TakePct || pnlPct <= -StopPct)
{
BuyMarket();
_entryPrice = 0;
}
}
if (!_hasPrev)
{
_prevPrice = price;
_prevMa = maValue;
_hasPrev = true;
return;
}
// Cross above MA - buy (or reverse short)
if (_prevPrice < _prevMa && price >= maValue)
{
if (Position < 0)
BuyMarket();
if (Position <= 0)
{
BuyMarket();
_entryPrice = price;
}
}
// Cross below MA - sell (or reverse long)
else if (_prevPrice > _prevMa && price <= maValue)
{
if (Position > 0)
SellMarket();
if (Position >= 0)
{
SellMarket();
_entryPrice = price;
}
}
_prevPrice = price;
_prevMa = maValue;
}
}
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 levels_with_revolve_strategy(Strategy):
def __init__(self):
super(levels_with_revolve_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Candle type", "General")
self._ma_period = self.Param("MaPeriod", 50) \
.SetDisplay("MA Period", "Moving average period for the level", "Parameters")
self._stop_pct = self.Param("StopPct", 1.5) \
.SetDisplay("Stop %", "Stop loss percent from entry", "Risk")
self._take_pct = self.Param("TakePct", 3.0) \
.SetDisplay("Take %", "Take profit percent from entry", "Risk")
self._prev_price = 0.0
self._prev_ma = 0.0
self._has_prev = False
self._entry_price = 0.0
@property
def candle_type(self):
return self._candle_type.Value
@property
def ma_period(self):
return self._ma_period.Value
@property
def stop_pct(self):
return self._stop_pct.Value
@property
def take_pct(self):
return self._take_pct.Value
def OnReseted(self):
super(levels_with_revolve_strategy, self).OnReseted()
self._prev_price = 0.0
self._prev_ma = 0.0
self._has_prev = False
self._entry_price = 0.0
def OnStarted2(self, time):
super(levels_with_revolve_strategy, self).OnStarted2(time)
self._prev_price = 0.0
self._prev_ma = 0.0
self._has_prev = False
self._entry_price = 0.0
ma = ExponentialMovingAverage()
ma.Length = self.ma_period
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(ma, self.process_candle).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, ma)
self.DrawOwnTrades(area)
def process_candle(self, candle, ma_value):
if candle.State != CandleStates.Finished:
return
ma_value = float(ma_value)
price = float(candle.ClosePrice)
stop = float(self.stop_pct)
take = float(self.take_pct)
# Check stop/take
if self.Position > 0 and self._entry_price > 0:
pnl_pct = (price - self._entry_price) / self._entry_price * 100.0
if pnl_pct >= take or pnl_pct <= -stop:
self.SellMarket()
self._entry_price = 0.0
elif self.Position < 0 and self._entry_price > 0:
pnl_pct = (self._entry_price - price) / self._entry_price * 100.0
if pnl_pct >= take or pnl_pct <= -stop:
self.BuyMarket()
self._entry_price = 0.0
if not self._has_prev:
self._prev_price = price
self._prev_ma = ma_value
self._has_prev = True
return
# Cross above MA - buy (or reverse short)
if self._prev_price < self._prev_ma and price >= ma_value:
if self.Position < 0:
self.BuyMarket()
if self.Position <= 0:
self.BuyMarket()
self._entry_price = price
# Cross below MA - sell (or reverse long)
elif self._prev_price > self._prev_ma and price <= ma_value:
if self.Position > 0:
self.SellMarket()
if self.Position >= 0:
self.SellMarket()
self._entry_price = price
self._prev_price = price
self._prev_ma = ma_value
def CreateClone(self):
return levels_with_revolve_strategy()