Freeman-Strategie
Freeman ist eine Intraday-Strategie, die mehrere Momentum-Filter überlagert, um schrittweise in Trends einzusteigen. Sie verwendet zwei RSI-"Lehrer", die von gleitenden Durchschnitten auf dem Handelszeitrahmen angetrieben werden, zusammen mit einem höheren Zeitrahmen-Gleitender-Durchschnitt-Filter. Das Risiko wird durch ATR-basierte Stop-Loss- und Take-Profit-Ziele sowie einen pip-basierten Trailing-Stop kontrolliert.
Strategie-Überblick
- Funktioniert auf beliebigen Zeitrahmen-Kerzen, die durch den Parameter
CandleType ausgewählt werden (standardmäßig 15 Minuten).
- Verwendet einen stündlichen Filter (
FilterCandleType), um Trends zu qualifizieren, bevor Signale akzeptiert werden.
- Erstellt Long- und Short-Signale aus zwei RSI-Blöcken, die aktuelle und vorherige Werte in Kombination mit Gleitender-Durchschnitt-Neigungen vergleichen.
- Erlaubt Pyramiding, wenn der Markt sich weiter bewegt, mit der Option, die nächste Order nach einem Verlustaustieg zu vergrößern.
Handelslogik
Long-Bedingungen
- Der höhere Zeitrahmen-Filter ist optional. Wenn aktiviert, muss der stündliche gleitende Durchschnitt aufwärts geneigt sein.
- RSI Lehrer #1 ist aktiv, wenn:
- RSI #1 auf dem vorherigen Balken unter
RsiSellLevel lag und auf dem aktuellen Balken steigt.
- Der schnelle gleitende Durchschnitt steigt.
- Der stündliche RSI (Periode 14) unter
RsiBuyLevel bleibt, um zu bestätigen, dass der höhere Zeitrahmen nicht überkauft ist.
- RSI Lehrer #2 ist aktiv, wenn:
- RSI #2 unter
RsiSellLevel2 lag und nach oben dreht.
- Der langsame gleitende Durchschnitt steigt.
- Der stündliche RSI unter
RsiBuyLevel2 bleibt.
- Ein Long-Einstieg wird genommen, wenn mindestens ein Lehrer aktiv ist und der Trendfilter (wenn aktiviert) übereinstimmt.
- Weitere Long-Einstiege erfordern, dass sich der Schlusskurs mehr als
DistancePips (umgerechnet durch den Preisschritt des Instruments) vom letzten Long-Fill entfernt. Wenn der letzte Long-Ausstieg ein Verlust war, wird das Volumen mit LockCoefficient multipliziert, um das MT5-Sperrverhalten nachzuahmen.
Short-Bedingungen
Spiegelt die Long-Logik mit invertierten Vergleichen:
- Der höhere Zeitrahmen-Gleitende-Durchschnitt muss sinken, wenn der Filter aktiviert ist.
- RSI Lehrer #1 benötigt RSI #1 über
RsiBuyLevel, der nach unten dreht, den schnellen MA fallend und den stündlichen RSI über RsiSellLevel.
- RSI Lehrer #2 benötigt RSI #2 über
RsiBuyLevel2, der nach unten dreht, den langsamen MA fallend und den stündlichen RSI über RsiSellLevel2.
- Weitere Short-Einstiege folgen denselben Abstands- und Sperrregeln.
Positionsmanagement
- Stop-Loss und Take-Profit werden für jeden Einstieg aus dem aktuellen ATR-Wert unter Verwendung von
StopLossAtrFactor und TakeProfitAtrFactor neu berechnet.
- Der Trailing-Stop aktiviert sich, sobald der Preis über
TrailingStopPips + TrailingStepPips hinausgeht, und sichert dann Gewinne, indem der Stop TrailingStopPips vom letzten Schluss entfernt gehalten wird.
- Ausstiege werden mit Marktorders ausgeführt, sobald das Hoch/Tief der Kerze die berechneten Stop- oder Zielniveaus durchbricht.
- Der Parameter
PositionsMaximum begrenzt die Gesamtzahl der ausgeführten Einstiege (Long plus Short). Ein Wert von null entfernt die Begrenzung.
Zeitfilter
- Der Handel an Freitagen kann durch
TradeOnFriday deaktiviert werden.
StartHour und EndHour definieren ein optionales Sitzungsfenster in Börsenzeit; Nullwerte halten den Markt den ganzen Tag geöffnet.
Parameter
| Name |
Beschreibung |
CandleType |
Handelszeitrahmen für die Hauptsignallogik. |
FilterCandleType |
Höherer Zeitrahmen für den Gleitender-Durchschnitt- und RSI-Filter (Standard 1 Stunde). |
FirstMaPeriod / SecondMaPeriod |
Perioden für die schnellen und langsamen gleitenden Durchschnitte, die die RSI-Lehrer speisen. |
FilterMaPeriod |
Länge des höheren Zeitrahmen-Gleitender-Durchschnitts. |
MaType |
Gleitender-Durchschnitt-Typ (SMA, EMA, SMMA oder WMA). |
RsiFirstPeriod / RsiSecondPeriod |
Perioden der beiden RSI-Lehrer. |
RsiSellLevel, RsiBuyLevel, RsiSellLevel2, RsiBuyLevel2 |
RSI-Schwellenwerte zur Steuerung der Lehrerblöcke. |
UseRsiTeacher1, UseRsiTeacher2, UseTrendFilter |
Schalter für jede Komponente. |
StopLossAtrFactor, TakeProfitAtrFactor |
ATR-Multiplikatoren für Stop-Loss- und Take-Profit-Abstände. |
TrailingStopPips, TrailingStepPips |
Pip-Offsets für die Trailing-Stop-Engine. |
PositionsMaximum |
Maximale Anzahl kombinierter Einstiege; null = unbegrenzt. |
DistancePips |
Mindest-Pip-Abstand vor dem Hinzufügen zu einer Position. |
TradeOnFriday |
Signale an Freitagen aktivieren oder deaktivieren. |
StartHour, EndHour |
Optionale Handelssitzungslimits. |
LockCoefficient |
Volumen-Multiplikator nach einem Verlustausstieg beim Stapeln in dieselbe Richtung. |
SignalShift |
Offset beim Lesen von Indikatorwerten (0 = aktueller fertiger Balken). |
Implementierungshinweise
- Der StockSharp-Port verarbeitet nur fertige Kerzen und entspricht dem MT5-"Bars Control"-Verhalten, auch wenn das Original Tick-basierten Handel ermöglichte.
- In Pips ausgedrückte Preisabstände werden mit dem
PriceStep des Instruments umgerechnet.
- Die Schutzlogik (Stop, Ziel, Trailing) schließt Positionen mit Marktorders, da High-Level-API-Bindings anstelle einzelner MT5-Positionsmodifikationen verwendet werden.
- Die Strategie führt aggregierte Long- und Short-Volumen; einmal geschlossen, setzt die Verlustverfolgung zurück, sodass das nächste Signal wie die ursprünglichen Sperrregeln funktioniert.
Verwenden Sie geeignete Risikokontrollen und testen Sie gründlich, bevor Sie an Live-Märkten handeln.
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>
/// Freeman strategy using dual MA crossover with RSI filter.
/// </summary>
public class FreemanStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _fastPeriod;
private readonly StrategyParam<int> _slowPeriod;
private readonly StrategyParam<int> _rsiPeriod;
private readonly StrategyParam<decimal> _rsiBuyLevel;
private readonly StrategyParam<decimal> _rsiSellLevel;
private decimal? _prevFast;
private decimal? _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 int RsiPeriod
{
get => _rsiPeriod.Value;
set => _rsiPeriod.Value = value;
}
public decimal RsiBuyLevel
{
get => _rsiBuyLevel.Value;
set => _rsiBuyLevel.Value = value;
}
public decimal RsiSellLevel
{
get => _rsiSellLevel.Value;
set => _rsiSellLevel.Value = value;
}
public FreemanStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).TimeFrame())
.SetDisplay("Candle Type", "Timeframe", "General");
_fastPeriod = Param(nameof(FastPeriod), 10)
.SetGreaterThanZero()
.SetDisplay("Fast Period", "Fast SMA period", "Indicators");
_slowPeriod = Param(nameof(SlowPeriod), 30)
.SetGreaterThanZero()
.SetDisplay("Slow Period", "Slow SMA period", "Indicators");
_rsiPeriod = Param(nameof(RsiPeriod), 14)
.SetGreaterThanZero()
.SetDisplay("RSI Period", "RSI period for filter", "Indicators");
_rsiBuyLevel = Param(nameof(RsiBuyLevel), 55m)
.SetDisplay("RSI Buy Level", "RSI below which buys are allowed", "Levels");
_rsiSellLevel = Param(nameof(RsiSellLevel), 45m)
.SetDisplay("RSI Sell Level", "RSI above which sells are allowed", "Levels");
}
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(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 fastSma = new SimpleMovingAverage { Length = FastPeriod };
var slowSma = new SimpleMovingAverage { Length = SlowPeriod };
var rsi = new RelativeStrengthIndex { Length = RsiPeriod };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(fastSma, slowSma, rsi, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, fastSma);
DrawIndicator(area, slowSma);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal fast, decimal slow, decimal rsiValue)
{
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;
// MA crossover
if (!prevAbove && currAbove)
{
if (Position < 0)
BuyMarket();
if (Position <= 0)
BuyMarket();
}
else if (prevAbove && !currAbove)
{
if (Position > 0)
SellMarket();
if (Position >= 0)
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 SimpleMovingAverage, RelativeStrengthIndex
from StockSharp.Algo.Strategies import Strategy
class freeman_strategy(Strategy):
def __init__(self):
super(freeman_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", 10) \
.SetDisplay("Fast Period", "Fast SMA period", "Indicators")
self._slow_period = self.Param("SlowPeriod", 30) \
.SetDisplay("Slow Period", "Slow SMA period", "Indicators")
self._rsi_period = self.Param("RsiPeriod", 14) \
.SetDisplay("RSI Period", "RSI period for filter", "Indicators")
self._rsi_buy_level = self.Param("RsiBuyLevel", 55.0) \
.SetDisplay("RSI Buy Level", "RSI below which buys are allowed", "Levels")
self._rsi_sell_level = self.Param("RsiSellLevel", 45.0) \
.SetDisplay("RSI Sell Level", "RSI above which sells are allowed", "Levels")
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
@property
def RsiPeriod(self):
return self._rsi_period.Value
@property
def RsiBuyLevel(self):
return self._rsi_buy_level.Value
@property
def RsiSellLevel(self):
return self._rsi_sell_level.Value
def OnReseted(self):
super(freeman_strategy, self).OnReseted()
self._prev_fast = None
self._prev_slow = None
def OnStarted2(self, time):
super(freeman_strategy, self).OnStarted2(time)
self._prev_fast = None
self._prev_slow = None
fast_sma = SimpleMovingAverage()
fast_sma.Length = self.FastPeriod
slow_sma = SimpleMovingAverage()
slow_sma.Length = self.SlowPeriod
rsi = RelativeStrengthIndex()
rsi.Length = self.RsiPeriod
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(fast_sma, slow_sma, rsi, self._on_process).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, fast_sma)
self.DrawIndicator(area, slow_sma)
self.DrawOwnTrades(area)
def _on_process(self, candle, fast_value, slow_value, rsi_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
# MA crossover
if not prev_above and curr_above:
if self.Position < 0:
self.BuyMarket()
if self.Position <= 0:
self.BuyMarket()
elif prev_above and not curr_above:
if self.Position > 0:
self.SellMarket()
if self.Position >= 0:
self.SellMarket()
def CreateClone(self):
return freeman_strategy()