Die Ang Zad C Time MM Recovery-Strategie ist ein C#-Port des MetaTrader 5-Expertenberaters Exp_Ang_Zad_C_Tm_MMRec. Die Strategie kombiniert den benutzerdefinierten Ang_Zad_C-Kanal-Indikator mit einem konfigurierbaren Handelssitzungsfilter und einem adaptiven Positionsgrößenmodell, das das Risiko nach einer konfigurierbaren Anzahl von Verlust-Trades reduziert.
Indikatorlogik
Der Ang_Zad_C-Indikator baut zwei adaptive Hüllen um den Preis auf. Jede Hülle wird aktualisiert, indem der gewählte angewendete Preis der aktuellen und vorherigen Kerze verglichen wird und sich mit dem Glättungsfaktor Ki in Richtung des neuen Preises bewegt. Die obere und untere Linie werden auf historischen Balken ausgewertet, die durch Signal Bar definiert sind, um nicht auf unfertigen Kerzen zu handeln.
Trading-Regeln
Long-Einstieg – Wenn die obere Linie auf dem vorherigen Referenzbalken über der unteren Linie war und auf dem aktuellsten Referenzbalken darunter kreuzt oder die untere Linie berührt. Wenn dies passiert, wird jede offene Short-Position geschlossen, bevor eine neue Long-Position geöffnet wird (wenn aktiviert).
Short-Einstieg – Wenn die obere Linie auf dem vorherigen Referenzbalken unter der unteren Linie war und auf dem aktuellsten Referenzbalken darüber kreuzt oder die untere Linie berührt. Jede offene Long-Position wird geschlossen, bevor eine neue Short-Position geöffnet wird (wenn aktiviert).
Long-Ausstieg – Wenn die obere Linie auf dem vorherigen Referenzbalken unter der unteren Linie liegt. Der Ausstieg kann über Enable Long Exit deaktiviert werden.
Short-Ausstieg – Wenn die obere Linie auf dem vorherigen Referenzbalken über der unteren Linie liegt. Der Ausstieg kann über Enable Short Exit deaktiviert werden.
Money-Management und Schutzmaßnahmen
Handel ist nur innerhalb des konfigurierten Zeitfensters erlaubt, wenn Use Time Filter aktiviert ist. Zuvor geöffnete Positionen werden geschlossen, sobald die Sitzung endet.
Das Trade-Volumen wird zwischen Normal Volume und Small Volume ausgewählt, abhängig davon, wie viele Verlust-Trades für jede Seite aufgetreten sind. Nach Buy Loss Trigger verlierenden Long-Trades (oder Sell Loss Trigger verlierenden Short-Trades) wird das reduzierte Volumen verwendet, bis ein profitabler Trade den Zähler zurücksetzt.
Optionale Stop-Loss- und Take-Profit-Levels werden mit Preisschrittabständen registriert, die durch Stop Loss Steps und Take Profit Steps definiert werden.
Parameter
Name
Beschreibung
Candle Type
Zeitrahmen der vom Indikator und Signalen verwendeten Kerzen.
Ki
Glättungskoeffizient der Ang_Zad_C-Hüllen.
Applied Price
Welcher Kerzenkurs in den Indikator eingespeist wird.
Signal Bar
Wie viele Balken zurück für die Signalauswertung verwendet werden (1 = vorheriger geschlossener Balken).
Use Time Filter / Trade Start / Trade End
Sitzungsbasiertes Trading aktivieren und Start- und Endzeit der Sitzung festlegen.
Enable Long/Short Entry
Öffnung neuer Long- oder Short-Trades erlauben.
Enable Long/Short Exit
Der Strategie erlauben, Positionen bei Indikatorumkehr zu schließen.
Buy/Sell Loss Trigger
Anzahl der Verlust-Trades, bevor das reduzierte Volumen angewendet wird.
Small Volume / Normal Volume
Ordergrößen für reduziertes und normales Risiko.
Stop Loss Steps / Take Profit Steps
Abstand für Schutzorders ausgedrückt in Preisschritten.
Konvertierungshinweise
Die Logik folgt dem ursprünglichen MQL5-Code, einschließlich der direktionalen Kreuzprüfungen und des Zeitfensterverhaltens.
Das adaptive Money-Management wird implementiert, indem realisierter Gewinn und Verlust pro Richtung verfolgt und nach der konfigurierten Anzahl von Verlusten auf das reduzierte Volumen umgeschaltet wird.
Indikatorberechnungen vermeiden jeden direkten Pufferzugriff und werden auf fertigen Kerzen unter Verwendung der StockSharp-API auf hoher Ebene verarbeitet.
using System;
using System.Collections.Generic;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Ang_Zad_C adaptive channel strategy.
/// Trades when the upper/lower lines cross, indicating trend reversal.
/// </summary>
public class AngZadCTimeMMRecoveryStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<decimal> _ki;
private bool _hasState;
private decimal _upperLine;
private decimal _lowerLine;
private decimal _previousPrice;
private decimal? _prevUp;
private decimal? _prevDn;
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public decimal Ki
{
get => _ki.Value;
set => _ki.Value = value;
}
public AngZadCTimeMMRecoveryStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).TimeFrame())
.SetDisplay("Candle Type", "Timeframe", "General");
_ki = Param(nameof(Ki), 4.000001m)
.SetDisplay("Ki", "Smoothing coefficient", "Indicator")
.SetGreaterThanZero();
}
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_hasState = false;
_upperLine = 0m;
_lowerLine = 0m;
_previousPrice = 0m;
_prevUp = null;
_prevDn = null;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_hasState = false;
_prevUp = null;
_prevDn = null;
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle)
{
if (candle.State != CandleStates.Finished)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
var price = candle.ClosePrice;
var (upper, lower) = UpdateIndicator(price);
if (_prevUp == null || _prevDn == null)
{
_prevUp = upper;
_prevDn = lower;
return;
}
var prevUp = _prevUp.Value;
var prevDn = _prevDn.Value;
// Buy signal: previous upper was below lower, now crossing above
if (prevUp <= prevDn && upper > lower)
{
if (Position < 0)
BuyMarket();
if (Position <= 0)
BuyMarket();
}
// Sell signal: previous upper was above lower, now crossing below
else if (prevUp >= prevDn && upper < lower)
{
if (Position > 0)
SellMarket();
if (Position >= 0)
SellMarket();
}
_prevUp = upper;
_prevDn = lower;
}
private (decimal Up, decimal Down) UpdateIndicator(decimal price)
{
if (!_hasState)
{
_upperLine = price;
_lowerLine = price;
_previousPrice = price;
_hasState = true;
return (_upperLine, _lowerLine);
}
var ki = Ki;
if (price > _upperLine && price > _previousPrice)
_upperLine += (price - _upperLine) / ki;
if (price < _upperLine && price < _previousPrice)
_upperLine += (price - _upperLine) / ki;
if (price > _lowerLine && price < _previousPrice)
_lowerLine += (price - _lowerLine) / ki;
if (price < _lowerLine && price > _previousPrice)
_lowerLine += (price - _lowerLine) / ki;
_previousPrice = price;
return (_upperLine, _lowerLine);
}
}
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.Strategies import Strategy
class ang_zad_c_time_mm_recovery_strategy(Strategy):
def __init__(self):
super(ang_zad_c_time_mm_recovery_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(1))) \
.SetDisplay("Candle Type", "Timeframe", "General")
self._ki = self.Param("Ki", 4.000001) \
.SetDisplay("Ki", "Smoothing coefficient", "Indicator")
self._has_state = False
self._upper_line = 0.0
self._lower_line = 0.0
self._previous_price = 0.0
self._prev_up = None
self._prev_dn = None
@property
def CandleType(self):
return self._candle_type.Value
@property
def Ki(self):
return self._ki.Value
def OnReseted(self):
super(ang_zad_c_time_mm_recovery_strategy, self).OnReseted()
self._has_state = False
self._upper_line = 0.0
self._lower_line = 0.0
self._previous_price = 0.0
self._prev_up = None
self._prev_dn = None
def OnStarted2(self, time):
super(ang_zad_c_time_mm_recovery_strategy, self).OnStarted2(time)
self._has_state = False
self._prev_up = None
self._prev_dn = None
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(self._on_process).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawOwnTrades(area)
def _update_indicator(self, price):
if not self._has_state:
self._upper_line = price
self._lower_line = price
self._previous_price = price
self._has_state = True
return (self._upper_line, self._lower_line)
ki = float(self.Ki)
if price > self._upper_line and price > self._previous_price:
self._upper_line += (price - self._upper_line) / ki
if price < self._upper_line and price < self._previous_price:
self._upper_line += (price - self._upper_line) / ki
if price > self._lower_line and price < self._previous_price:
self._lower_line += (price - self._lower_line) / ki
if price < self._lower_line and price > self._previous_price:
self._lower_line += (price - self._lower_line) / ki
self._previous_price = price
return (self._upper_line, self._lower_line)
def _on_process(self, candle):
if candle.State != CandleStates.Finished:
return
price = float(candle.ClosePrice)
upper, lower = self._update_indicator(price)
if self._prev_up is None or self._prev_dn is None:
self._prev_up = upper
self._prev_dn = lower
return
prev_up = self._prev_up
prev_dn = self._prev_dn
# Buy signal: previous upper was below lower, now crossing above
if prev_up <= prev_dn and upper > lower:
if self.Position < 0:
self.BuyMarket()
if self.Position <= 0:
self.BuyMarket()
# Sell signal: previous upper was above lower, now crossing below
elif prev_up >= prev_dn and upper < lower:
if self.Position > 0:
self.SellMarket()
if self.Position >= 0:
self.SellMarket()
self._prev_up = upper
self._prev_dn = lower
def CreateClone(self):
return ang_zad_c_time_mm_recovery_strategy()