Die Trend Is Your Friend-Strategie ist ein Multi-Timeframe-Trendfolge-System, inspiriert vom ursprünglichen MetaTrader-Expertenberater. Es richtet Intraday-Momentum mit einem MACD-Filter des höheren Zeitrahmens aus, während das Risiko durch Bollinger-Bänder-Ausstiege, klassische Stop-Loss- und Take-Profit-Ziele, eine optionale Break-Even-Sperre und Trailing-Stop-Management verwaltet wird.
Die Strategie arbeitet auf einem konfigurierbaren Basis-Zeitrahmen (Standard: 1 Stunde) und analysiert die Kerzenstruktur für ein kurzfristiges Momentum-Muster: eine bärische Kerze gefolgt von einer stärkeren bullischen Kerze für Long-Trades oder das Gegenteil für Short-Trades. Diese Muster müssen mit einem gleitenden Durchschnitts-Trendfilter und einem monatlichen MACD-Signal übereinstimmen, bevor eine Position eröffnet wird.
Einstiegslogik
Eine schnelle EMA und eine langsame LWMA auf dem Einstiegs-Zeitrahmen berechnen.
Die letzten zwei abgeschlossenen Kerzen verfolgen, um ein Momentum-Muster zu bilden:
Long-Setup: die Kerze vor zwei Bars ist bärisch, die vorherige Kerze ist bullisch und größer in der Magnitude.
Short-Setup: die Kerze vor zwei Bars ist bullisch, die vorherige Kerze ist bärisch und kleiner in der Magnitude.
Das Setup mit dem gleitenden Durchschnitts-Trendfilter bestätigen (schnelle MA über langsamer MA für Long-Trades, darunter für Short-Trades).
Den langfristigen Trend mit einem MACD-Signal bestätigen, das auf dem höheren Zeitrahmen berechnet wird (Standard: monatlich). Die MACD-Linie muss für Long-Trades über der Signallinie liegen und darunter für Short-Trades.
Wenn alle Filter übereinstimmen, eine Position zum Markt mit dem konfigurierten Volumen eröffnen.
Ausstiegslogik
Bollinger-Bänder-Ausstieg: Long-Positionen werden geschlossen, wenn der Preis über das obere Band schließt; Short-Positionen, wenn der Preis unter das untere Band schließt.
Take-Profit / Stop-Loss: optionale feste Abstände in Pips. Die Implementierung konvertiert Pips über den Wertpapier-Preisschritt in Preisabstand.
Break-Even: optional, verschiebt den Schutz-Stop auf (oder über) den Einstiegspreis, nachdem eine konfigurierbare Gewinnschwelle erreicht wurde.
Trailing Stop: optional, wird nach einem Gewinnschwellenwert aktiviert und verfolgt den Preis um eine feste Pip-Distanz. Der Trailing Stop teilt denselben Speicher mit dem Break-Even-Niveau.
Parameter
Name
Beschreibung
Standard
Entry Candle
Kerzentyp für Einstiegslogik
1 Stunde
MACD Candle
Höherer Zeitrahmen für MACD-Filter
30 Tage
Fast MA
Schnelle EMA-Länge
8
Slow MA
Langsame LWMA-Länge
20
Bollinger Length
Bollinger-Bänder-Periode
20
Bollinger Width
Standardabweichungs-Multiplikator der Bollinger-Bänder
2.0
Stop Loss (pips)
Schutz-Stop-Distanz
20
Take Profit (pips)
Gewinnziel-Distanz
50
Use Break-Even
Break-Even-Anpassung aktivieren
true
Break-Even Trigger
Gewinn (Pips) zum Verschieben des Stops erforderlich
10
Break-Even Offset
Offset am Break-Even-Stop angewendet
5
Use Trailing
Trailing Stop aktivieren
true
Trailing Activation
Gewinn (Pips) zum Aktivieren des Trailings erforderlich
40
Trailing Distance
Distanz (Pips) vom Trailing Stop gehalten
40
Hinweise
Die Strategie speichert nur die letzten zwei abgeschlossenen Kerzen, um schwere historische Buffer zu vermeiden.
MACD-Daten werden vom konfigurierten höheren Zeitrahmen mit aktivierter Aggregation abonniert, was ermöglicht, dass monatliche Signale aus Tagesdaten aufgebaut werden, wenn nötig.
Die Pip-zu-Preis-Konvertierung verwendet den Wertpapier-Preisschritt. Instrumente mit nicht-standardmäßigen Pip-Definitionen können eine Parameter-Anpassung erfordern.
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 TrendIsYourFriendStrategy : 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 TrendIsYourFriendStrategy()
{
_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 trend_is_your_friend_strategy(Strategy):
def __init__(self):
super(trend_is_your_friend_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(trend_is_your_friend_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(trend_is_your_friend_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 trend_is_your_friend_strategy()