Diese Strategie repliziert den MetaTrader "Freeman"-Expert Advisor mit der High-Level-API von StockSharp. Sie schichtet mehrere Marktpositionen, während ein durch eine Steigung des gleitenden Durchschnitts gemessener Trend mit einer RSI-Bestätigung übereinstimmt. Jeder Einstiegs- und Ausstiegsabstand ist in Pips definiert und wird mit der Tick-Größe des Instruments in Preiseinheiten umgerechnet, damit das Verhalten der ursprünglichen Forex-Implementierung entspricht.
Handelslogik
Eine einzelne Kerzenserie (konfigurierbarer Zeitrahmen) abonnieren und die ATR-, gleitenden Durchschnitts- und RSI-Indikatoren bei jeder abgeschlossenen Kerze aktualisieren.
Ein direktionales Signal erzeugen wenn:
Die Steigung des gleitenden Durchschnitts positiv oder negativ ist, indem der neueste Wert mit dem vorherigen Bar verglichen wird (optionaler Trendfilter).
Der Preis weit genug vom gleitenden Durchschnitt entfernt ist, um Einstiege direkt auf der Linie zu vermeiden.
Der RSI den oberen oder unteren Schwellenwert kreuzt, wenn der RSI-Filter aktiviert ist. Die MetaTrader-Logik bleibt intakt, einschließlich der Eigenheit, wo eine RSI-Verkaufsbestätigung -11 zurückgibt, daher bevorzugen beide aktivierten Filter nur Long-Trades.
Die maximale Anzahl gleichzeitig offener Positionen respektieren. Zusätzliche Einstiege in dieselbe Richtung sind nur erlaubt, wenn der Preis um die konfigurierte Pip-Distanz gegen die letzte Füllung bewegt hat, wodurch effektiv ein Grid aufgebaut wird.
Jeder Einstieg verwendet ATR-basierte Stop-Loss- und Take-Profit-Niveaus. Trailing Stops verschärfen den schützenden Stop, sobald sich der Preis um den Trailing-Schritt plus Trailing-Stop-Distanz bewegt.
Ausstiege werden über entgegengesetzte Marktorders ausgeführt, wenn der Kerzenbereich das Stop-, Ziel- oder Trailing-Niveau erreicht.
Risikomanagement
ATR-Multiplikatoren steuern die festen Stop-Loss- und Take-Profit-Abstände. Einen Multiplikator auf null setzen deaktiviert diesen Schutz.
Trailing Stops sind optional und werden durch zwei Pip-Parameter definiert: die tatsächliche Trailing-Distanz und der zusätzliche Schritt, der erforderlich ist, bevor der Stop erneut bewegt wird.
Die Strategie verlässt sich auf die Basis-Volume-Eigenschaft für die Größenbestimmung; kein automatisiertes Geldmanagement wird über das Positionslimit hinaus angewendet.
Parameter
Name
Beschreibung
CandleType
Zeitrahmen für Indikatorberechnungen.
MaxPositions
Maximale Anzahl gleichzeitig offener Positionen (Summe von Long und Short).
DistancePips
Mindest-Pip-Abstand zwischen aufeinanderfolgenden Einstiegen in dieselbe Richtung.
AtrPeriod
Mittelungsperiode für den ATR-Indikator.
AtrStopLossMultiplier
ATR-Multiplikator für den Schutz-Stop. 0 deaktiviert den Stop.
AtrTakeProfitMultiplier
ATR-Multiplikator für das Gewinnziel. 0 deaktiviert das Ziel.
UseTrendFilter
Aktiviert den Filter für die Steigung des gleitenden Durchschnitts.
DistanceFromMaPips
Mindest-Pip-Abstand zwischen Preis und gleitendem Durchschnitt bei aktivem Trendfilter.
MaPeriod, MaShift, MaMethod, MaPriceType
Gleitende-Durchschnitts-Parameter entsprechend den MetaTrader-Eingaben.
UseRsiFilter
Aktiviert den RSI-Bestätigungsfilter.
RsiLevelUp, RsiLevelDown, RsiPeriod, RsiPriceType
RSI-Konfiguration mit Preisquellenauswahl.
TrailingStopPips, TrailingStepPips
Trailing-Stop-Distanz und Schritt in Pips gemessen.
CurrentBarOffset
Versatz beim Lesen von Indikatorwerten, emuliert die CurrentBar-Eingabe des Expert Advisors.
Hinweise
Die Pip-Umrechnung multipliziert den Instrument-PriceStep mit 10, wenn das Instrument 3 oder 5 Dezimalstellen hat, um die Punkt-zu-Pip-Anpassung von MetaTrader zu reproduzieren.
Die Strategie verwendet ein Netting-Positionsmodell; entgegengesetzte Signale schließen bestehende Positionen, bevor Trades in der neuen Richtung eröffnet werden.
Der Startschutz wird beim Start aktiviert, um gegen unerwartete Wiederverbindungen zu schützen, bevor Trades platziert werden.
using System;
using System.Collections.Generic;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
public class FreemanAtrMaRsiGridStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _fastPeriod;
private readonly StrategyParam<int> _slowPeriod;
private decimal? _prevFast, _prevSlow;
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public int FastPeriod { get => _fastPeriod.Value; set => _fastPeriod.Value = value; }
public int SlowPeriod { get => _slowPeriod.Value; set => _slowPeriod.Value = value; }
public FreemanAtrMaRsiGridStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).TimeFrame()).SetDisplay("Candle Type", "Timeframe", "General");
_fastPeriod = Param(nameof(FastPeriod), 8).SetGreaterThanZero().SetDisplay("Fast EMA", "Fast EMA period", "Indicators");
_slowPeriod = Param(nameof(SlowPeriod), 21).SetGreaterThanZero().SetDisplay("Slow EMA", "Slow EMA period", "Indicators");
}
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities() => [(Security, CandleType)];
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevFast = null;
_prevSlow = null;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_prevFast = null; _prevSlow = null;
var fast = new ExponentialMovingAverage { Length = FastPeriod };
var slow = new ExponentialMovingAverage { Length = SlowPeriod };
var subscription = SubscribeCandles(CandleType);
subscription.Bind(fast, slow, ProcessCandle).Start();
var area = CreateChartArea();
if (area != null) { DrawCandles(area, subscription); DrawIndicator(area, fast); DrawIndicator(area, slow); DrawOwnTrades(area); }
}
private void ProcessCandle(ICandleMessage candle, decimal fast, decimal slow)
{
if (candle.State != CandleStates.Finished) return;
if (!IsFormedAndOnlineAndAllowTrading()) { _prevFast = fast; _prevSlow = slow; return; }
if (_prevFast == null || _prevSlow == null) { _prevFast = fast; _prevSlow = slow; return; }
var prevAbove = _prevFast.Value > _prevSlow.Value;
var currAbove = fast > slow;
_prevFast = fast; _prevSlow = slow;
if (!prevAbove && currAbove && Position <= 0) { if (Position < 0) BuyMarket(); BuyMarket(); }
else if (prevAbove && !currAbove && Position >= 0) { if (Position > 0) SellMarket(); SellMarket(); }
}
}
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 freeman_atr_ma_rsi_grid_strategy(Strategy):
def __init__(self):
super(freeman_atr_ma_rsi_grid_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(1))) \
.SetDisplay("Candle Type", "Timeframe", "General")
self._fast_period = self.Param("FastPeriod", 8) \
.SetDisplay("Fast EMA", "Fast EMA period", "Indicators")
self._slow_period = self.Param("SlowPeriod", 21) \
.SetDisplay("Slow EMA", "Slow EMA period", "Indicators")
self._prev_fast = None
self._prev_slow = None
@property
def CandleType(self):
return self._candle_type.Value
@property
def FastPeriod(self):
return self._fast_period.Value
@property
def SlowPeriod(self):
return self._slow_period.Value
def OnReseted(self):
super(freeman_atr_ma_rsi_grid_strategy, self).OnReseted()
self._prev_fast = None
self._prev_slow = None
def OnStarted2(self, time):
super(freeman_atr_ma_rsi_grid_strategy, self).OnStarted2(time)
self._prev_fast = None
self._prev_slow = None
fast = ExponentialMovingAverage()
fast.Length = self.FastPeriod
slow = ExponentialMovingAverage()
slow.Length = self.SlowPeriod
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(fast, slow, self._on_process).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, fast)
self.DrawIndicator(area, slow)
self.DrawOwnTrades(area)
def _on_process(self, candle, fast_value, slow_value):
if candle.State != CandleStates.Finished:
return
fv = float(fast_value)
sv = float(slow_value)
if self._prev_fast is None or self._prev_slow is None:
self._prev_fast = fv
self._prev_slow = sv
return
prev_above = self._prev_fast > self._prev_slow
curr_above = fv > sv
self._prev_fast = fv
self._prev_slow = sv
if not prev_above and curr_above and self.Position <= 0:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
elif prev_above and not curr_above and self.Position >= 0:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
def CreateClone(self):
return freeman_atr_ma_rsi_grid_strategy()