Start
/
Strategie-Beispiele
Auf GitHub ansehen
Price Action Fractal-Strategie
Diese Strategie ist ein C#-Port des MetaTrader-Expert-Advisors „PRICE_ACTION". Sie kombiniert Williams-Fractals mit gewichteten gleitenden Durchschnitten, Momentum- und MACD-Filtern, um Ausbrüche zu handeln, die durch Preisaktion im gewählten Zeitrahmen bestätigt werden.
Idee
Ausschließlich abgeschlossene Kerzen analysieren; jede Entscheidung wird beim Barschluss des konfigurierten Zeitrahmens getroffen.
Neue bullische oder bärische Fractals mit einem 5-Kerzen-Fenster erkennen. Ein neues Down-Fractal signalisiert potenzielle Unterstützung, ein neues Up-Fractal potenzielle Resistance.
Den direktionalen Bias mit zwei linear gewichteten gleitenden Durchschnitten (LWMA) bestätigen. Long-Trades erfordern den schnellen LWMA über dem langsamen; Short-Trades erfordern das Gegenteil.
Momentum durch Prüfung der absoluten Abweichung des Momentum-Indikators vom neutralen 100er-Level im höheren Zeitrahmen validieren.
Einen MACD-Filter (12,26,9 Standard) verwenden: Bullische Setups verlangen MACD über seiner Signallinie, bärische Setups verlangen MACD unter der Signallinie.
Sobald alle Filter übereinstimmen, in Ausbruchsrichtung einsteigen und die Position mit festen Stops, einem Trailing-Stop und optionalem Break-Even-Shift verwalten.
Einstiegsregeln
Long-Einstieg
Ein neues Down-Fractal bildet sich auf der aktuellen Kerze (Fünf-Balken-Muster).
Fast LWMA > Slow LWMA.
abs(Momentum - 100) ≥ MomentumThreshold.
MACD-Hauptlinie > MACD-Signallinie.
Die Positionsgröße basiert auf dem Strategievolumen und ist durch MaxPositionUnits begrenzt.
Short-Einstieg
Ein neues Up-Fractal bildet sich auf der aktuellen Kerze.
Fast LWMA < Slow LWMA.
abs(Momentum - 100) ≥ MomentumThreshold.
MACD-Hauptlinie < MACD-Signallinie.
Ausstiegsregeln
Fester Stop-Loss (StopLossPoints) und fester Take-Profit (TakeProfitPoints) in Preisschritten.
Optionaler Trailing-Stop (TrailingStopPoints), der dem günstigsten Preis folgt, sobald die Position mindestens die Trailing-Distanz gewonnen hat.
Optionaler Break-Even-Schutz: nach Erreichen von BreakEvenTriggerPoints wird der Stop auf EntryPrice ± BreakEvenOffsetPoints verschoben.
Ausstiege werden mit Marktorders ausgeführt; alle Berechnungen basieren auf Kerzenhochs/-tiefs zur Stop-Erkennung.
Positionsmanagement
Die Strategie hält eine einzelne aggregierte Position pro Symbol.
Volume definiert die Basisordergröße. Bei Umkehrung schließt die Strategie zunächst die entgegengesetzte Exposition und eröffnet dann eine neue Position mit der gewünschten Größe.
MaxPositionUnits begrenzt den absoluten Positionswert, um Übergrößen zu vermeiden.
Parameter
CandleType – Zeitrahmen für alle Indikatoren und Entscheidungen (äquivalent zur MQL-Variable T).
FastMaPeriod / SlowMaPeriod – Längen der gewichteten gleitenden Durchschnitte (FastMA, SlowMA).
MomentumPeriod – Momentum-Rückblicklänge (im MQL-Skript auf 14 festgelegt).
MomentumThreshold – minimale absolute Abweichung von 100 zur Momentum-Bestätigung (Mom_Buy/Mom_Sell).
MacdFastPeriod, MacdSlowPeriod, MacdSignalPeriod – MACD-Konfiguration (12/26/9 Standard).
StopLossPoints, TakeProfitPoints – Preisschritt-Abstände für Schutzorders (Stop_Loss, Take_Profit).
TrailingStopPoints – Trailing-Stop-Abstand (TrailingStop).
BreakEvenTriggerPoints, BreakEvenOffsetPoints – Break-Even-Auslöser und Offset (WHENTOMOVETOBE, PIPSTOMOVESL).
FractalLifetime – Anzahl der Kerzen, die ein erkanntes Fractal gültig bleibt (CandlesToRetrace).
MaxPositionUnits – maximale absolute Positionsgröße (Constraint Max_Trades in Lot-Einheiten).
EnableTrailing, EnableBreakEven, UseStopLoss, UseTakeProfit – Schalter für die jeweiligen Ausstiegsmechanismen.
Unterschiede zum Original-EA
Portfolioweite Funktionen wie geldbasierter Take-Profit, Eigenkapital-Stop und E-Mail-/Benachrichtigungsalarme sind nicht implementiert.
Lot-Optimierungsroutinen aus MetaTrader sind vereinfacht; die Strategie verwendet die StockSharp-Volumenormalisierung.
Schutzorders werden mit Marktausstiegen statt mit ausstehenden Ordermodifikationen ausgeführt, da StockSharp das Risikomanagement anders handhabt.
Dateien
CS/PriceActionFractalStrategy.cs – Strategieimplementierung in C#.
Python-Version ist noch nicht verfügbar.
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;
public class PriceActionFractalStrategy : Strategy
{
private readonly StrategyParam<int> _fastPeriod;
private readonly StrategyParam<int> _slowPeriod;
private readonly StrategyParam<int> _stopLossPoints;
private readonly StrategyParam<int> _takeProfitPoints;
private ExponentialMovingAverage _fast;
private ExponentialMovingAverage _slow;
private decimal _prevFast;
private decimal _prevSlow;
private decimal _entryPrice;
private int _cooldown;
public int FastPeriod { get => _fastPeriod.Value; set => _fastPeriod.Value = value; }
public int SlowPeriod { get => _slowPeriod.Value; set => _slowPeriod.Value = value; }
public int StopLossPoints { get => _stopLossPoints.Value; set => _stopLossPoints.Value = value; }
public int TakeProfitPoints { get => _takeProfitPoints.Value; set => _takeProfitPoints.Value = value; }
public PriceActionFractalStrategy()
{
_fastPeriod = Param(nameof(FastPeriod), 14).SetGreaterThanZero().SetDisplay("Fast Period", "Fast EMA period", "Indicator");
_slowPeriod = Param(nameof(SlowPeriod), 50).SetGreaterThanZero().SetDisplay("Slow Period", "Slow EMA period", "Indicator");
_stopLossPoints = Param(nameof(StopLossPoints), 200).SetNotNegative().SetDisplay("Stop Loss", "Stop-loss in price steps", "Risk");
_takeProfitPoints = Param(nameof(TakeProfitPoints), 400).SetNotNegative().SetDisplay("Take Profit", "Take-profit in price steps", "Risk");
}
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
yield return (Security, TimeSpan.FromMinutes(5).TimeFrame());
}
protected override void OnReseted()
{
base.OnReseted();
_fast = null; _slow = null;
_prevFast = 0; _prevSlow = 0; _entryPrice = 0; _cooldown = 0;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_fast = new ExponentialMovingAverage { Length = FastPeriod };
_slow = new ExponentialMovingAverage { Length = SlowPeriod };
var subscription = SubscribeCandles(TimeSpan.FromMinutes(5).TimeFrame());
subscription.Bind(_fast, _slow, ProcessCandle);
subscription.Start();
}
private void ProcessCandle(ICandleMessage candle, decimal fastValue, decimal slowValue)
{
if (candle.State != CandleStates.Finished) return;
if (!_fast.IsFormed || !_slow.IsFormed) { _prevFast = fastValue; _prevSlow = slowValue; return; }
if (_cooldown > 0) { _cooldown--; _prevFast = fastValue; _prevSlow = slowValue; return; }
var close = candle.ClosePrice;
var step = Security?.PriceStep ?? 1m;
if (Position > 0 && _entryPrice > 0)
{
if (StopLossPoints > 0 && close <= _entryPrice - StopLossPoints * step) { SellMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
if (TakeProfitPoints > 0 && close >= _entryPrice + TakeProfitPoints * step) { SellMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
}
else if (Position < 0 && _entryPrice > 0)
{
if (StopLossPoints > 0 && close >= _entryPrice + StopLossPoints * step) { BuyMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
if (TakeProfitPoints > 0 && close <= _entryPrice - TakeProfitPoints * step) { BuyMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
}
if (_prevFast <= _prevSlow && fastValue > slowValue && Position <= 0)
{ if (Position < 0) BuyMarket(); BuyMarket(); _entryPrice = close; _cooldown = 100; }
else if (_prevFast >= _prevSlow && fastValue < slowValue && Position >= 0)
{ if (Position > 0) SellMarket(); SellMarket(); _entryPrice = close; _cooldown = 100; }
_prevFast = fastValue; _prevSlow = slowValue;
}
}
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 price_action_fractal_strategy(Strategy):
def __init__(self):
super(price_action_fractal_strategy, self).__init__()
self._fast_period = self.Param("FastPeriod", 14) \
.SetDisplay("Fast Period", "Fast MA period", "Indicator")
self._slow_period = self.Param("SlowPeriod", 50) \
.SetDisplay("Slow Period", "Slow MA period", "Indicator")
self._stop_loss_points = self.Param("StopLossPoints", 200) \
.SetDisplay("Stop Loss", "Stop-loss in price steps", "Risk")
self._take_profit_points = self.Param("TakeProfitPoints", 400) \
.SetDisplay("Take Profit", "Take-profit in price steps", "Risk")
self._fast = None
self._slow = None
self._prev_fast = 0.0
self._prev_slow = 0.0
self._entry_price = 0.0
self._cooldown = 0
@property
def fast_period(self):
return self._fast_period.Value
@property
def slow_period(self):
return self._slow_period.Value
@property
def stop_loss_points(self):
return self._stop_loss_points.Value
@property
def take_profit_points(self):
return self._take_profit_points.Value
def OnReseted(self):
super(price_action_fractal_strategy, self).OnReseted()
self._fast = None
self._slow = None
self._prev_fast = 0.0
self._prev_slow = 0.0
self._entry_price = 0.0
self._cooldown = 0
def OnStarted2(self, time):
super(price_action_fractal_strategy, self).OnStarted2(time)
self._fast = ExponentialMovingAverage()
self._fast.Length = self.fast_period
self._slow = ExponentialMovingAverage()
self._slow.Length = self.slow_period
subscription = self.SubscribeCandles(DataType.TimeFrame(TimeSpan.FromMinutes(5)))
subscription.Bind(self._fast, self._slow, self._process_candle)
subscription.Start()
def _process_candle(self, candle, fast_value, slow_value):
if candle.State != CandleStates.Finished:
return
fast_val = float(fast_value)
slow_val = float(slow_value)
if not self._fast.IsFormed or not self._slow.IsFormed:
self._prev_fast = fast_val
self._prev_slow = slow_val
return
if self._cooldown > 0:
self._cooldown -= 1
self._prev_fast = fast_val
self._prev_slow = slow_val
return
close = float(candle.ClosePrice)
step = float(self.Security.PriceStep) if self.Security is not None and self.Security.PriceStep is not None else 1.0
if self.Position > 0 and self._entry_price > 0:
if self.stop_loss_points > 0 and close <= self._entry_price - self.stop_loss_points * step:
self.SellMarket()
self._entry_price = 0.0
self._cooldown = 100
self._prev_fast = fast_val
self._prev_slow = slow_val
return
if self.take_profit_points > 0 and close >= self._entry_price + self.take_profit_points * step:
self.SellMarket()
self._entry_price = 0.0
self._cooldown = 100
self._prev_fast = fast_val
self._prev_slow = slow_val
return
elif self.Position < 0 and self._entry_price > 0:
if self.stop_loss_points > 0 and close >= self._entry_price + self.stop_loss_points * step:
self.BuyMarket()
self._entry_price = 0.0
self._cooldown = 100
self._prev_fast = fast_val
self._prev_slow = slow_val
return
if self.take_profit_points > 0 and close <= self._entry_price - self.take_profit_points * step:
self.BuyMarket()
self._entry_price = 0.0
self._cooldown = 100
self._prev_fast = fast_val
self._prev_slow = slow_val
return
if self._prev_fast <= self._prev_slow and fast_val > slow_val and self.Position <= 0:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
self._entry_price = close
self._cooldown = 100
elif self._prev_fast >= self._prev_slow and fast_val < slow_val and self.Position >= 0:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
self._entry_price = close
self._cooldown = 100
self._prev_fast = fast_val
self._prev_slow = slow_val
def CreateClone(self):
return price_action_fractal_strategy()