ForexLine-Strategie
Die ForexLine-Strategie ist ein Trendfolge-System, das vom MetaTrader-Indikator "ForexLine" abgeleitet ist. Es wendet zwei Stufen gewichteter gleitender Durchschnitte auf den Kurs an, um schnelle und langsame Linien zu erstellen. Kreuzungen zwischen diesen doppelt geglätteten Linien werden zur Bestimmung von Einstiegssignalen verwendet.
Die Strategie kauft, wenn die schnelle Linie über die langsame Linie kreuzt, und verkauft, wenn die schnelle Linie unter die langsame Linie kreuzt. Jeder gleitende Durchschnitt verwendet einen zweistufigen Glättungsprozess, der hilft, Marktlärm herauszufiltern.
Details
- Einstiegskriterien:
- Long: Schnelle doppelt geglättete WMA kreuzt über die langsame doppelt geglättete WMA.
- Short: Schnelle doppelt geglättete WMA kreuzt unter die langsame doppelt geglättete WMA.
- Long/Short: Beide Seiten.
- Ausstiegskriterien:
- Entgegengesetzte Kreuzung schließt bestehende Position.
- Stops: Nicht enthalten; können extern hinzugefügt werden.
- Standardwerte:
FastLength1= 5FastLength2= 10SlowLength1= 20SlowLength2= 20CandleType= 8-Stunden-Zeitrahmen
- Filter:
- Kategorie: Trendfolge
- Richtung: Beide
- Indikatoren: Gewichtete gleitende Durchschnitte
- Stops: Nein
- Komplexität: Moderat
- Zeitrahmen: Mittelfristig
- Saisonalität: Nein
- Neuronale Netze: Nein
- Divergenz: Nein
- Risikolevel: Mittel
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;
/// <summary>
/// ForexLine: two weighted-moving-average stages for each fast and slow line.
/// Enter on a formed, finished-candle crossover, reversing the entire held side.
/// </summary>
public class ForexLineStrategy : Strategy
{
private readonly StrategyParam<int> _fastLength1;
private readonly StrategyParam<int> _fastLength2;
private readonly StrategyParam<int> _slowLength1;
private readonly StrategyParam<int> _slowLength2;
private readonly StrategyParam<DataType> _candleType;
private WeightedMovingAverage _fastFirst;
private WeightedMovingAverage _fastSecond;
private WeightedMovingAverage _slowFirst;
private WeightedMovingAverage _slowSecond;
private decimal? _previousFast;
private decimal? _previousSlow;
private Order _pendingOrder;
public int FastLength1 { get => _fastLength1.Value; set => _fastLength1.Value = value; }
public int FastLength2 { get => _fastLength2.Value; set => _fastLength2.Value = value; }
public int SlowLength1 { get => _slowLength1.Value; set => _slowLength1.Value = value; }
public int SlowLength2 { get => _slowLength2.Value; set => _slowLength2.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public ForexLineStrategy()
{
_fastLength1 = Param(nameof(FastLength1), 5).SetGreaterThanZero()
.SetDisplay("Fast WMA 1", "First fast smoothing stage", "Indicator");
_fastLength2 = Param(nameof(FastLength2), 10).SetGreaterThanZero()
.SetDisplay("Fast WMA 2", "Second fast smoothing stage", "Indicator");
_slowLength1 = Param(nameof(SlowLength1), 20).SetGreaterThanZero()
.SetDisplay("Slow WMA 1", "First slow smoothing stage", "Indicator");
_slowLength2 = Param(nameof(SlowLength2), 20).SetGreaterThanZero()
.SetDisplay("Slow WMA 2", "Second slow smoothing stage", "Indicator");
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(8).TimeFrame())
.SetDisplay("Candle Type", "Timeframe for candle closes", "General");
}
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities() => [(Security, CandleType)];
protected override void OnReseted()
{
base.OnReseted();
_previousFast = _previousSlow = null;
_pendingOrder = null;
_fastFirst = _fastSecond = _slowFirst = _slowSecond = null;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_previousFast = _previousSlow = null;
_pendingOrder = null;
_fastFirst = new WeightedMovingAverage { Length = FastLength1 };
_fastSecond = new WeightedMovingAverage { Length = FastLength2 };
_slowFirst = new WeightedMovingAverage { Length = SlowLength1 };
_slowSecond = new WeightedMovingAverage { Length = SlowLength2 };
var subscription = SubscribeCandles(CandleType);
subscription.Bind(ProcessCandle).Start();
var area = CreateChartArea();
if (area is not null)
{
DrawCandles(area, subscription);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle)
{
if (candle.State != CandleStates.Finished)
return;
var price = new DecimalIndicatorValue(_fastFirst, candle.ClosePrice, candle.OpenTime) { IsFinal = true };
var fastOne = _fastFirst.Process(price);
var slowOne = _slowFirst.Process(new DecimalIndicatorValue(_slowFirst, candle.ClosePrice, candle.OpenTime) { IsFinal = true });
if (!fastOne.IsFormed || !slowOne.IsFormed)
return;
var fastTwo = _fastSecond.Process(fastOne);
var slowTwo = _slowSecond.Process(slowOne);
if (!fastTwo.IsFormed || !slowTwo.IsFormed)
return;
var fast = fastTwo.GetValue<decimal>();
var slow = slowTwo.GetValue<decimal>();
if (_previousFast is decimal pf && _previousSlow is decimal ps && IsFormedAndOnlineAndAllowTrading()
&& (_pendingOrder is null || _pendingOrder.State is OrderStates.Done or OrderStates.Failed))
{
if (pf <= ps && fast > slow && Position <= 0m)
_pendingOrder = BuyMarket(Volume + Math.Abs(Position));
else if (pf >= ps && fast < slow && Position >= 0m)
_pendingOrder = SellMarket(Volume + Math.Abs(Position));
}
_previousFast = fast;
_previousSlow = slow;
}
}
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, OrderStates
from StockSharp.Algo.Indicators import WeightedMovingAverage
from StockSharp.Algo.Strategies import Strategy
from indicator_extensions import process_float
class forex_line_strategy(Strategy):
"""Cascaded 5/10 fast and 20/20 slow WMA strategy, matching the documented ForexLine."""
def __init__(self):
super(forex_line_strategy, self).__init__()
self._fast_length1 = self.Param("FastLength1", 5).SetDisplay("Fast WMA 1", "First fast smoothing", "Indicator")
self._fast_length2 = self.Param("FastLength2", 10).SetDisplay("Fast WMA 2", "Second fast smoothing", "Indicator")
self._slow_length1 = self.Param("SlowLength1", 20).SetDisplay("Slow WMA 1", "First slow smoothing", "Indicator")
self._slow_length2 = self.Param("SlowLength2", 20).SetDisplay("Slow WMA 2", "Second slow smoothing", "Indicator")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(8))).SetDisplay(
"Candle Type", "Timeframe for price closes", "General")
self._reset_state()
@property
def fast_length1(self): return self._fast_length1.Value
@property
def fast_length2(self): return self._fast_length2.Value
@property
def slow_length1(self): return self._slow_length1.Value
@property
def slow_length2(self): return self._slow_length2.Value
@property
def candle_type(self): return self._candle_type.Value
def _reset_state(self):
self._previous_fast = None
self._previous_slow = None
self._pending_order = None
self._fast_first = self._fast_second = None
self._slow_first = self._slow_second = None
def OnReseted(self):
super(forex_line_strategy, self).OnReseted()
self._reset_state()
def OnStarted2(self, time):
super(forex_line_strategy, self).OnStarted2(time)
self._reset_state()
self._fast_first = WeightedMovingAverage()
self._fast_first.Length = self.fast_length1
self._fast_second = WeightedMovingAverage()
self._fast_second.Length = self.fast_length2
self._slow_first = WeightedMovingAverage()
self._slow_first.Length = self.slow_length1
self._slow_second = WeightedMovingAverage()
self._slow_second.Length = self.slow_length2
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(self.process_candle).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawOwnTrades(area)
def process_candle(self, candle):
if candle.State != CandleStates.Finished:
return
time = candle.OpenTime
fast_first = process_float(self._fast_first, candle.ClosePrice, time, True)
slow_first = process_float(self._slow_first, candle.ClosePrice, time, True)
if not fast_first.IsFormed or not slow_first.IsFormed:
return
fast_second = process_float(self._fast_second, float(fast_first), time, True)
slow_second = process_float(self._slow_second, float(slow_first), time, True)
if not fast_second.IsFormed or not slow_second.IsFormed:
return
fast = float(fast_second)
slow = float(slow_second)
pf = self._previous_fast
ps = self._previous_slow
self._previous_fast = fast
self._previous_slow = slow
if pf is None or ps is None or not self.IsFormedAndOnlineAndAllowTrading():
return
if self._pending_order is not None and self._pending_order.State not in (OrderStates.Done, OrderStates.Failed):
return
if pf <= ps and fast > slow and self.Position <= 0:
self._pending_order = self.BuyMarket(self.Volume + abs(self.Position))
elif pf >= ps and fast < slow and self.Position >= 0:
self._pending_order = self.SellMarket(self.Volume + abs(self.Position))
def CreateClone(self):
return forex_line_strategy()