Exp Preisposition
Die Exp Price Position-Strategie adaptiert den ursprünglichen MetaTrader-Expertenberater, der die Preislage mit einem Stufentrendfilter kombiniert. Sie bewertet die Beziehung zwischen zwei medianen gleitenden Durchschnitten, um das letzte Swing-Niveau zu ermitteln, und prüft dann ein schnelles und langsames geglättetes gleitendes Durchschnittspaar, um die Trendrichtung zu bestimmen. Orders werden nur eröffnet, wenn sowohl die Preisposition als auch der Stufentrend mit der aktuellen Kerzenstruktur übereinstimmen.
Die Strategie ist für Märkte konzipiert, in denen Trendwechsel auftreten, nachdem der Preis auf ein dynamisches medianes Niveau zurückgezogen hat. Ein Trailing-Stop und eine Take-Profit-Ratio werden zur Risikoverwaltung eingesetzt.
Details
- Einstiegskriterien: Preis über dem letzten Swing-Niveau mit bullishem Stufentrend für Long-Trades; darunter mit bärischem Stufentrend für Short-Trades.
- Long/Short: Beide Richtungen.
- Ausstiegskriterien: Gegensignal oder Schutz-Stop.
- Stops: Ja, über Trailing-Stop mit Take-Profit-Ratio.
- Standardwerte:
FastPeriod= 2SlowPeriod= 30MedianFastPeriod= 26MedianSlowPeriod= 20TpSlRatio= 3mTrailingStopPips= 10mCandleType= TimeSpan.FromHours(1)
- Filter:
- Kategorie: Trendfolge
- Richtung: Beide
- Indikatoren: Smoothed Moving Average, Simple Moving Average
- Stops: Trailing
- Komplexität: Mittel
- Zeitrahmen: Intraday
- Saisonalität: Nein
- Neuronale Netze: Nein
- Divergenz: Nein
- Risikolevel: Mittel
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()