Ein wöchentliches konträres System, das vom ursprünglichen Expertenratgeber MQL „Contrarian_trade_MA“ umgewandelt wurde. Die Strategie analysiert wöchentliche Kerzenextreme zusammen mit einem einfachen gleitenden Durchschnitt, um gestreckte Bewegungen zu Beginn einer neuen Woche auszublenden.
Handelslogik
Datenquelle: Wöchentliche Kerzen, bereitgestellt durch den Parameter CandleType (standardmäßig ein 7-Tage-Zeitrahmen).
Historische Extremwerte: Die Indikatoren Highest und Lowest verfolgen die Höchst- und Tiefstwerte der letzten CalcPeriod abgeschlossenen Wochen, mit Ausnahme der aktuell bewerteten Kerze.
Filter für gleitenden Durchschnitt: Ein einfacher gleitender Durchschnitt der Länge MaPeriod, der auf wöchentliche Schlusskurse angewendet wird, fungiert als Richtungsfilter.
Teilnahmebedingungen:
Kaufen, wenn der Schlusskurs der Vorwoche über dem verfolgten Höchststand (highest < previousClose) liegt oder wenn der gleitende Durchschnitt über dem aktuellen Wocheneröffnungskurs liegt.
Verkaufen, wenn der Schlusskurs der Vorwoche unter dem verfolgten Tief (lowest > previousClose) liegt oder wenn der gleitende Durchschnitt unter dem aktuellen wöchentlichen Eröffnungskurs liegt.
Es kann immer nur eine Position offen sein; Gegensignale werden ignoriert, bis der bestehende Handel geschlossen wird.
Ausgangsregeln:
Die Position wird unabhängig von der Richtung nach sieben Tagen (604.800 Sekunden) geschlossen.
Bei jeder abgeschlossenen wöchentlichen Kerze wird ein Schutzstopp ausgewertet. Die Stoppdistanz wird aus StopLossPoints * PriceStep berechnet (fällt auf 1 zurück, wenn in den Metadaten des Instruments kein Schritt angegeben ist).
Parameter
Name
Standard
Beschreibung
CalcPeriod
4
Anzahl der abgeschlossenen Wochen, anhand derer das höchste Hoch und das niedrigste Tief berechnet werden.
MaPeriod
7
Zeitraum des einfachen gleitenden Durchschnitts, der auf wöchentliche Abschlüsse angewendet wird.
StopLossPoints
300
Abstand vom Einstiegspreis zum Stop-Loss, gemessen in Preisschritten. Auf 0 setzen, um den Stopp zu deaktivieren.
Volume
0.5
Bestellgröße in Losen, eingereicht von BuyMarket/SellMarket.
CandleType
7 days
Zeitrahmen für die Kerzen, die alle Berechnungen steuern.
Zusätzliche Hinweise
Die Strategie ruft den Preisschritt automatisch von Security.PriceStep ab. Geben Sie diesen Wert in den Metadaten des Instruments an, um eine genaue Stop-Loss-Platzierung zu gewährleisten.
StartProtection() ist aktiviert, um unerwartete Positionsänderungen zu verfolgen, die außerhalb der Strategie durchgeführt werden.
Da die Logik auf abgeschlossenen wöchentlichen Kerzen basiert, werden Füllungen beim wöchentlichen Schluss der Signalleiste im Testmodus simuliert.
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>
/// Contrarian MA strategy - mean reversion around SMA.
/// Buys when price crosses below SMA (contrarian dip buy).
/// Sells when price crosses above SMA (contrarian top sell).
/// Uses Highest/Lowest as extreme confirmation.
/// </summary>
public class ContrarianTradeMaWeeklyStrategy : Strategy
{
private readonly StrategyParam<int> _maPeriod;
private readonly StrategyParam<int> _channelPeriod;
private readonly StrategyParam<DataType> _candleType;
private decimal _prevClose;
private decimal _prevSma;
private bool _hasPrev;
public int MaPeriod { get => _maPeriod.Value; set => _maPeriod.Value = value; }
public int ChannelPeriod { get => _channelPeriod.Value; set => _channelPeriod.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public ContrarianTradeMaWeeklyStrategy()
{
_maPeriod = Param(nameof(MaPeriod), 14)
.SetDisplay("SMA Period", "SMA period", "Indicators");
_channelPeriod = Param(nameof(ChannelPeriod), 10)
.SetDisplay("Channel Period", "Highest/Lowest lookback", "Indicators");
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Candle timeframe", "General");
}
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities() => [(Security, CandleType)];
protected override void OnReseted() { base.OnReseted(); _prevClose = 0m; _prevSma = 0m; _hasPrev = false; }
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_hasPrev = false;
var sma = new SimpleMovingAverage { Length = MaPeriod };
var highest = new Highest { Length = ChannelPeriod };
var lowest = new Lowest { Length = ChannelPeriod };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(sma, highest, lowest, ProcessCandle)
.Start();
}
private void ProcessCandle(ICandleMessage candle, decimal sma, decimal highest, decimal lowest)
{
if (candle.State != CandleStates.Finished)
return;
var close = candle.ClosePrice;
if (!_hasPrev)
{
_prevClose = close;
_prevSma = sma;
_hasPrev = true;
return;
}
var mid = (highest + lowest) / 2;
// Contrarian buy: price crosses below SMA and is near the low
if (_prevClose >= _prevSma && close < sma && close < mid && Position <= 0)
{
if (Position < 0)
BuyMarket();
BuyMarket();
}
// Contrarian sell: price crosses above SMA and is near the high
else if (_prevClose <= _prevSma && close > sma && close > mid && Position >= 0)
{
if (Position > 0)
SellMarket();
SellMarket();
}
_prevClose = close;
_prevSma = sma;
}
}
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 SimpleMovingAverage, Highest, Lowest
from StockSharp.Algo.Strategies import Strategy
class contrarian_trade_ma_weekly_strategy(Strategy):
def __init__(self):
super(contrarian_trade_ma_weekly_strategy, self).__init__()
self._ma_period = self.Param("MaPeriod", 14) \
.SetDisplay("SMA Period", "SMA period", "Indicators")
self._channel_period = self.Param("ChannelPeriod", 10) \
.SetDisplay("Channel Period", "Highest/Lowest lookback", "Indicators")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Candle timeframe", "General")
self._prev_close = 0.0
self._prev_sma = 0.0
self._has_prev = False
@property
def ma_period(self):
return self._ma_period.Value
@property
def channel_period(self):
return self._channel_period.Value
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(contrarian_trade_ma_weekly_strategy, self).OnReseted()
self._prev_close = 0.0
self._prev_sma = 0.0
self._has_prev = False
def OnStarted2(self, time):
super(contrarian_trade_ma_weekly_strategy, self).OnStarted2(time)
self._has_prev = False
sma = SimpleMovingAverage()
sma.Length = self.ma_period
highest = Highest()
highest.Length = self.channel_period
lowest = Lowest()
lowest.Length = self.channel_period
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(sma, highest, lowest, self.process_candle).Start()
def process_candle(self, candle, sma, highest, lowest):
if candle.State != CandleStates.Finished:
return
close = float(candle.ClosePrice)
sma_val = float(sma)
high_val = float(highest)
low_val = float(lowest)
if not self._has_prev:
self._prev_close = close
self._prev_sma = sma_val
self._has_prev = True
return
mid = (high_val + low_val) / 2.0
if self._prev_close >= self._prev_sma and close < sma_val and close < mid and self.Position <= 0:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
elif self._prev_close <= self._prev_sma and close > sma_val and close > mid and self.Position >= 0:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
self._prev_close = close
self._prev_sma = sma_val
def CreateClone(self):
return contrarian_trade_ma_weekly_strategy()