Exp Posición de Precio
La estrategia Exp Price Position adapta el asesor experto original de MetaTrader que combina la ubicación del precio y un filtro de tendencia escalonada. Evalúa la relación entre dos medias móviles medianas para localizar el último nivel de oscilación y luego verifica un par de medias móviles suavizadas rápida y lenta para determinar la dirección de la tendencia. Las órdenes se abren solo cuando tanto la posición del precio como la tendencia escalonada concuerdan con la estructura de la vela actual.
La estrategia está diseñada para mercados donde los cambios de tendencia ocurren después de que el precio retrocede a un nivel mediano dinámico. Se aplica un stop dinámico y una relación de toma de beneficios para gestionar el riesgo.
Detalles
- Criterios de entrada: Precio por encima del último nivel de oscilación con tendencia escalonada alcista para operaciones largas; por debajo con tendencia escalonada bajista para operaciones cortas.
- Largo/Corto: Ambas direcciones.
- Criterios de salida: Señal opuesta o stop de protección.
- Stops: Sí, mediante trailing stop con relación de toma de beneficios.
- Valores predeterminados:
FastPeriod= 2SlowPeriod= 30MedianFastPeriod= 26MedianSlowPeriod= 20TpSlRatio= 3mTrailingStopPips= 10mCandleType= TimeSpan.FromHours(1)
- Filtros:
- Categoría: Seguimiento de tendencia
- Dirección: Ambos
- Indicadores: Smoothed Moving Average, Simple Moving Average
- Stops: Trailing
- Complejidad: Intermedio
- Marco temporal: Intradía
- Estacionalidad: No
- Redes neuronales: No
- Divergencia: No
- Nivel de riesgo: Medio
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>
/// Port of the ExpPricePosition MetaTrader expert.
/// Combines price position with a step trend filter based on smoothed moving averages.
/// </summary>
public class ExpPricePositionStrategy : Strategy
{
private readonly StrategyParam<int> _fastPeriod;
private readonly StrategyParam<int> _slowPeriod;
private readonly StrategyParam<int> _medianFastPeriod;
private readonly StrategyParam<int> _medianSlowPeriod;
private readonly StrategyParam<decimal> _tpSlRatio;
private readonly StrategyParam<decimal> _trailingStopPips;
private readonly StrategyParam<bool> _useTrailingStop;
private readonly StrategyParam<DataType> _candleType;
private decimal? _prevFast;
private decimal? _prevSlow;
private decimal _lastCrossLevel;
private bool _hasCrossLevel;
/// <summary>
/// Fast smoothed moving average period (default: 2).
/// </summary>
public int FastPeriod
{
get => _fastPeriod.Value;
set => _fastPeriod.Value = value;
}
/// <summary>
/// Slow smoothed moving average period (default: 30).
/// </summary>
public int SlowPeriod
{
get => _slowPeriod.Value;
set => _slowPeriod.Value = value;
}
/// <summary>
/// Median SMMA period used for price position (default: 26).
/// </summary>
public int MedianFastPeriod
{
get => _medianFastPeriod.Value;
set => _medianFastPeriod.Value = value;
}
/// <summary>
/// Median SMA period used for price position (default: 20).
/// </summary>
public int MedianSlowPeriod
{
get => _medianSlowPeriod.Value;
set => _medianSlowPeriod.Value = value;
}
/// <summary>
/// Take profit to stop loss ratio (default: 3).
/// </summary>
public decimal TpSlRatio
{
get => _tpSlRatio.Value;
set => _tpSlRatio.Value = value;
}
/// <summary>
/// Trailing stop value in points (default: 10).
/// </summary>
public decimal TrailingStopPips
{
get => _trailingStopPips.Value;
set => _trailingStopPips.Value = value;
}
/// <summary>
/// Use trailing stop protection.
/// </summary>
public bool UseTrailingStop
{
get => _useTrailingStop.Value;
set => _useTrailingStop.Value = value;
}
/// <summary>
/// Candle type for subscription.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Initializes <see cref="ExpPricePositionStrategy"/>.
/// </summary>
public ExpPricePositionStrategy()
{
_fastPeriod = Param(nameof(FastPeriod), 2)
.SetDisplay("Fast Period", "Fast SMMA period", "Parameters")
.SetGreaterThanZero();
_slowPeriod = Param(nameof(SlowPeriod), 30)
.SetDisplay("Slow Period", "Slow SMMA period", "Parameters")
.SetGreaterThanZero();
_medianFastPeriod = Param(nameof(MedianFastPeriod), 26)
.SetDisplay("Median Fast Period", "Median SMMA period", "Parameters")
.SetGreaterThanZero();
_medianSlowPeriod = Param(nameof(MedianSlowPeriod), 20)
.SetDisplay("Median Slow Period", "Median SMA period", "Parameters")
.SetGreaterThanZero();
_tpSlRatio = Param(nameof(TpSlRatio), 3m)
.SetDisplay("TP/SL Ratio", "Take profit to stop loss ratio", "Risk");
_trailingStopPips = Param(nameof(TrailingStopPips), 10m)
.SetDisplay("Trailing Stop", "Trailing stop value in points", "Risk");
_useTrailingStop = Param(nameof(UseTrailingStop), true)
.SetDisplay("Use Trailing Stop", "Enable trailing stop", "Risk");
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).TimeFrame())
.SetDisplay("Candle Type", "Timeframe for candles", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevFast = null;
_prevSlow = null;
_lastCrossLevel = 0m;
_hasCrossLevel = false;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
if (UseTrailingStop)
{
StartProtection(
stopLoss: new Unit(TrailingStopPips, UnitTypes.Absolute),
takeProfit: new Unit(TrailingStopPips * TpSlRatio, UnitTypes.Absolute));
}
var fast = new SmoothedMovingAverage { Length = FastPeriod };
var slow = new SmoothedMovingAverage { Length = SlowPeriod };
var medianFast = new SmoothedMovingAverage { Length = MedianFastPeriod };
var medianSlow = new SMA { Length = MedianSlowPeriod };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(fast, slow, medianFast, medianSlow, ProcessCandle)
.Start();
}
private void ProcessCandle(ICandleMessage candle,
decimal fast, decimal slow, decimal medianFast, decimal medianSlow)
{
if (candle.State != CandleStates.Finished)
return;
var signal = (medianFast + medianSlow) / 2m;
if (candle.OpenPrice <= signal && candle.ClosePrice > signal)
{
_lastCrossLevel = candle.LowPrice;
_hasCrossLevel = true;
}
else if (candle.OpenPrice >= signal && candle.ClosePrice < signal)
{
_lastCrossLevel = candle.HighPrice;
_hasCrossLevel = true;
}
if (!_hasCrossLevel)
{
_prevFast = fast;
_prevSlow = slow;
return;
}
if (_prevFast is null || _prevSlow is null)
{
_prevFast = fast;
_prevSlow = slow;
return;
}
var pricePos = candle.ClosePrice > _lastCrossLevel ? 1 : -1;
var stepUp = fast > slow && fast > _prevFast && _prevFast > _prevSlow;
var stepDown = fast < slow && fast < _prevFast && _prevFast < _prevSlow;
if (pricePos > 0 && stepUp && candle.ClosePrice > candle.OpenPrice && candle.LowPrice < fast && Position <= 0)
BuyMarket();
else if (pricePos < 0 && stepDown && candle.ClosePrice < candle.OpenPrice && candle.HighPrice > fast && Position >= 0)
SellMarket();
_prevFast = fast;
_prevSlow = slow;
}
}
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.Indicators import SmoothedMovingAverage, SimpleMovingAverage
from StockSharp.Algo.Strategies import Strategy
class exp_price_position_strategy(Strategy):
"""
Price position with step trend filter based on smoothed moving averages.
Combines SMMA crossover with price position relative to signal level.
"""
def __init__(self):
super(exp_price_position_strategy, self).__init__()
self._fast_period = self.Param("FastPeriod", 2) \
.SetDisplay("Fast Period", "Fast SMMA period", "Parameters")
self._slow_period = self.Param("SlowPeriod", 30) \
.SetDisplay("Slow Period", "Slow SMMA period", "Parameters")
self._median_fast_period = self.Param("MedianFastPeriod", 26) \
.SetDisplay("Median Fast Period", "Median SMMA period", "Parameters")
self._median_slow_period = self.Param("MedianSlowPeriod", 20) \
.SetDisplay("Median Slow Period", "Median SMA period", "Parameters")
self._tp_sl_ratio = self.Param("TpSlRatio", 3.0) \
.SetDisplay("TP/SL Ratio", "Take profit to stop loss ratio", "Risk")
self._trailing_stop_pips = self.Param("TrailingStopPips", 10.0) \
.SetDisplay("Trailing Stop", "Trailing stop in points", "Risk")
self._use_trailing = self.Param("UseTrailingStop", True) \
.SetDisplay("Use Trailing Stop", "Enable trailing stop", "Risk")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(1))) \
.SetDisplay("Candle Type", "Timeframe", "General")
self._prev_fast = None
self._prev_slow = None
self._last_cross_level = 0.0
self._has_cross_level = False
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(exp_price_position_strategy, self).OnReseted()
self._prev_fast = None
self._prev_slow = None
self._last_cross_level = 0.0
self._has_cross_level = False
def OnStarted2(self, time):
super(exp_price_position_strategy, self).OnStarted2(time)
if self._use_trailing.Value:
ts = float(self._trailing_stop_pips.Value)
ratio = float(self._tp_sl_ratio.Value)
self.StartProtection(
Unit(float(ts * ratio), UnitTypes.Absolute),
Unit(float(ts), UnitTypes.Absolute)
)
fast = SmoothedMovingAverage()
fast.Length = self._fast_period.Value
slow = SmoothedMovingAverage()
slow.Length = self._slow_period.Value
median_fast = SmoothedMovingAverage()
median_fast.Length = self._median_fast_period.Value
median_slow = SimpleMovingAverage()
median_slow.Length = self._median_slow_period.Value
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(fast, slow, median_fast, median_slow, self._process_candle).Start()
def _process_candle(self, candle, fast_val, slow_val, mf_val, ms_val):
if candle.State != CandleStates.Finished:
return
fast_val = float(fast_val)
slow_val = float(slow_val)
mf_val = float(mf_val)
ms_val = float(ms_val)
close = float(candle.ClosePrice)
open_p = float(candle.OpenPrice)
signal = (mf_val + ms_val) / 2.0
if open_p <= signal and close > signal:
self._last_cross_level = float(candle.LowPrice)
self._has_cross_level = True
elif open_p >= signal and close < signal:
self._last_cross_level = float(candle.HighPrice)
self._has_cross_level = True
if not self._has_cross_level:
self._prev_fast = fast_val
self._prev_slow = slow_val
return
if self._prev_fast is None or self._prev_slow is None:
self._prev_fast = fast_val
self._prev_slow = slow_val
return
price_pos = 1 if close > self._last_cross_level else -1
step_up = fast_val > slow_val and fast_val > self._prev_fast and self._prev_fast > self._prev_slow
step_down = fast_val < slow_val and fast_val < self._prev_fast and self._prev_fast < self._prev_slow
if (price_pos > 0 and step_up and close > open_p and
float(candle.LowPrice) < fast_val and self.Position <= 0):
self.BuyMarket()
elif (price_pos < 0 and step_down and close < open_p and
float(candle.HighPrice) > fast_val and self.Position >= 0):
self.SellMarket()
self._prev_fast = fast_val
self._prev_slow = slow_val
def CreateClone(self):
return exp_price_position_strategy()