Vector-Strategie
Überblick
Die Vector-Strategie ist ein Multi-Währungs-Trendfolgesystem, das vom MetaTrader 5 "Vector"-Experten konvertiert wurde. Es handelt vier große Forex-Paare — EURUSD, GBPUSD, USDCHF und USDJPY — gleichzeitig. Die Strategie berechnet geglättete gleitende Durchschnitte auf dem Medianpreis jedes Paares und öffnet synchronisierte Positionen, wenn der kombinierte Trend in dieselbe Richtung weist. Ein dynamisches Pip-Ziel basierend auf der Vier-Stunden-Volatilität und Gewinn- und Verlust-Schwellenwerte auf Portfolioebene steuern die Ausstiege.
Kernideen
- Geglättete gleitende Durchschnitte (SMMA) auf Medianpreisen verwenden, um die Richtung jedes Währungspaares zu messen.
- Die schnellen und langsamen Durchschnitte aller Instrumente summieren, um eine gemeinsame bullische oder bearische Ausrichtung zu bestimmen.
- Eine einzige Marktorder pro Paar eingeben, wenn die globale Ausrichtung und der lokale Schnell-/Langsam-Crossover übereinstimmen.
- Positionen mit einem gleitenden Pip-Ziel verwalten, das aus dem durchschnittlichen Bereich von 50 abgeschlossenen 4-Stunden-Kerzen auf EURUSD abgeleitet wird.
- Alle Trades gleichzeitig schließen, wenn der gleitende Gewinn oder Verlust den konfigurierten Prozentsatz des Startguthabens erreicht.
Parameter
| Parameter |
Beschreibung |
| Fast MA |
Länge des geglätteten gleitenden Durchschnitts für den schnellen Trend jedes Paares. |
| Slow MA |
Länge des geglätteten gleitenden Durchschnitts für den langsamen Trend jedes Paares. |
| MA Shift |
Zusätzliche Anzahl abgeschlossener Kerzen, die benötigt werden, bevor Signale ausgewertet werden, entsprechend der Shift-Einstellung im ursprünglichen EA. |
| Equity Take Profit % |
Gleitender Gewinnprozentsatz, der das Schließen aller offenen Positionen auslöst. |
| Equity Stop Loss % |
Gleitender Verlustprozentsatz, der einen Notausstieg für alle Trades auslöst. |
| Signal Timeframe |
Kerzen-Zeitrahmen für die geglätteten gleitenden Durchschnitte (Standard 15 Minuten). |
| Range Timeframe |
Kerzen-Zeitrahmen für die Volatilitätsmittelung (Standard 4 Stunden). |
| Range Period |
Anzahl höherer Zeitrahmen-Kerzen für die Berechnung des durchschnittlichen Pip-Ziels. |
| EURUSD / GBPUSD / USDCHF / USDJPY |
Wertpapiere, die den einzelnen gehandelten Instrumenten entsprechen. |
Alle Parameter unterstützen Optimierungsbereiche identisch zum ursprünglichen Expert Advisor, wo anwendbar.
Handelslogik
- Indikatoraktualisierung — Jede abgeschlossene Kerze auf einem Trading-Zeitrahmen aktualisiert die schnellen und langsamen geglätteten gleitenden Durchschnitte für das entsprechende Paar. Werte werden erst nach Abschluss des konfigurierten Aufwärmens (MA Shift) berücksichtigt.
- Bias-Berechnung — Die Strategie summiert die letzten schnellen Durchschnitte aller Paare und subtrahiert die Summe der langsamen Durchschnitte. Ein positives Ergebnis deutet auf bullischen Druck hin, ein negatives auf bearischen Druck.
- Einstiegsbedingungen — Wenn für ein Paar keine Position existiert, gibt die Strategie eine Kauforder ein, wenn die globale Ausrichtung bullisch ist und der schnelle Durchschnitt des Paares über dem langsamen liegt. In umgekehrtem Fall wird eine Verkaufsorder eröffnet.
- Pip-Ziel-Ausstieg — Das EURUSD-Vier-Stunden-Abonnement berechnet den durchschnittlichen Kerzenbereich über den konfigurierten Zeitraum. Das aktuelle Pip-Ziel ist das größere dieses Durchschnitts und 13 Pips. Longs schließen, sobald der Preis mindestens die Zielanzahl an Pips gewinnt, und Shorts schließen nach einer entsprechenden günstigen Bewegung.
- Kapitalschutz — Wenn der gleitende Gewinn den Take-Profit-Prozentsatz überschreitet oder der gleitende Verlust den Stop-Loss-Prozentsatz überschreitet, schließt die Strategie sofort alle verwalteten Positionen.
Verwendungshinweise
- Fügen Sie die Strategie einem Portfolio hinzu, das Zugang zu allen vier Forex-Instrumenten bietet, und setzen Sie jeden Sicherheitsparameter explizit.
- Der Standard-Signal-Zeitrahmen ist 15 Minuten; stellen Sie sicher, dass passende Kerzen für jedes Währungspaar verfügbar sind.
- Pro Paar wird jederzeit nur eine offene Position gehalten. Der Volumenparameter der Basisstrategie wird für jeden Einstieg verwendet.
- Da Ausstiege auf dem gleitenden G/V beruhen, ist die Strategie für den Dauerbetrieb und nicht nur für Kerzen-für-Kerzen-Backtesting gedacht.
- Das dynamische Pip-Ziel verwendet die EURUSD-Volatilität entsprechend der ursprünglichen Implementierung. Passen Sie den Range-Zeitrahmen oder den Zeitraum an, wenn Sie das Ziel an eine andere Marktumgebung anpassen möchten.
using System;
using System.Linq;
using System.Collections.Generic;
using Ecng.Common;
using Ecng.Collections;
using Ecng.Serialization;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Trend strategy using smoothed moving averages. Simplified from multi-currency Vector.
/// </summary>
public class VectorStrategy : Strategy
{
private readonly StrategyParam<int> _fastMaPeriod;
private readonly StrategyParam<int> _slowMaPeriod;
private readonly StrategyParam<int> _maShift;
private readonly StrategyParam<decimal> _profitPercent;
private readonly StrategyParam<decimal> _lossPercent;
private readonly StrategyParam<DataType> _candleType;
private SmoothedMovingAverage _fastMa;
private SmoothedMovingAverage _slowMa;
private decimal _entryPrice;
private decimal _initialBalance;
private int _processedBars;
/// <summary>
/// Fast smoothed moving average period.
/// </summary>
public int FastMaPeriod
{
get => _fastMaPeriod.Value;
set => _fastMaPeriod.Value = value;
}
/// <summary>
/// Slow smoothed moving average period.
/// </summary>
public int SlowMaPeriod
{
get => _slowMaPeriod.Value;
set => _slowMaPeriod.Value = value;
}
/// <summary>
/// Additional warm-up shift in bars.
/// </summary>
public int MaShift
{
get => _maShift.Value;
set => _maShift.Value = value;
}
/// <summary>
/// Floating profit target percent of balance.
/// </summary>
public decimal ProfitPercent
{
get => _profitPercent.Value;
set => _profitPercent.Value = value;
}
/// <summary>
/// Floating loss limit percent of balance.
/// </summary>
public decimal LossPercent
{
get => _lossPercent.Value;
set => _lossPercent.Value = value;
}
/// <summary>
/// Candle type for signals.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Initializes strategy parameters.
/// </summary>
public VectorStrategy()
{
_fastMaPeriod = Param(nameof(FastMaPeriod), 3)
.SetGreaterThanZero()
.SetDisplay("Fast MA", "Fast smoothed moving average period", "Indicators")
.SetOptimize(3, 15, 1);
_slowMaPeriod = Param(nameof(SlowMaPeriod), 7)
.SetGreaterThanZero()
.SetDisplay("Slow MA", "Slow smoothed moving average period", "Indicators")
.SetOptimize(5, 25, 1);
_maShift = Param(nameof(MaShift), 8)
.SetNotNegative()
.SetDisplay("MA Shift", "Additional warm-up bars before signals", "Indicators");
_profitPercent = Param(nameof(ProfitPercent), 0.5m)
.SetNotNegative()
.SetDisplay("Equity TP %", "Close all when floating profit reaches this percent", "Risk");
_lossPercent = Param(nameof(LossPercent), 30m)
.SetNotNegative()
.SetDisplay("Equity SL %", "Close all when floating loss reaches this percent", "Risk");
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Signal Timeframe", "Timeframe for moving averages", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
yield return (Security, CandleType);
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_fastMa = null;
_slowMa = null;
_entryPrice = 0m;
_initialBalance = 0m;
_processedBars = 0;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_fastMa = new SmoothedMovingAverage { Length = FastMaPeriod };
_slowMa = new SmoothedMovingAverage { Length = SlowMaPeriod };
_initialBalance = Portfolio?.CurrentValue ?? 0m;
SubscribeCandles(CandleType)
.Bind(_fastMa, _slowMa, ProcessCandle)
.Start();
}
private void ProcessCandle(ICandleMessage candle, decimal fastValue, decimal slowValue)
{
if (candle.State != CandleStates.Finished)
return;
_processedBars++;
if (!IsFormed)
return;
if (_processedBars <= MaShift)
return;
// Check equity thresholds
if (Position != 0 && _initialBalance > 0m)
{
var equity = Portfolio?.CurrentValue ?? 0m;
var floating = equity - _initialBalance;
var profitThreshold = _initialBalance * ProfitPercent / 100m;
var lossThreshold = _initialBalance * LossPercent / 100m;
if ((profitThreshold > 0m && floating >= profitThreshold) ||
(lossThreshold > 0m && floating <= -lossThreshold))
{
if (Position > 0) SellMarket();
else if (Position < 0) BuyMarket();
_entryPrice = 0m;
return;
}
}
// Entry/exit logic
if (fastValue > slowValue && Position <= 0)
{
if (Position < 0)
BuyMarket();
BuyMarket();
_entryPrice = candle.ClosePrice;
}
else if (fastValue < slowValue && Position >= 0)
{
if (Position > 0)
SellMarket();
SellMarket();
_entryPrice = candle.ClosePrice;
}
}
}
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.Strategies import Strategy
from StockSharp.Algo.Indicators import SmoothedMovingAverage
class vector_strategy(Strategy):
"""Trend strategy using smoothed moving averages with equity-based exit."""
def __init__(self):
super(vector_strategy, self).__init__()
self._fast_ma_period = self.Param("FastMaPeriod", 3) \
.SetGreaterThanZero() \
.SetDisplay("Fast MA", "Fast smoothed moving average period", "Indicators")
self._slow_ma_period = self.Param("SlowMaPeriod", 7) \
.SetGreaterThanZero() \
.SetDisplay("Slow MA", "Slow smoothed moving average period", "Indicators")
self._ma_shift = self.Param("MaShift", 8) \
.SetNotNegative() \
.SetDisplay("MA Shift", "Additional warm-up bars before signals", "Indicators")
self._profit_percent = self.Param("ProfitPercent", 0.5) \
.SetNotNegative() \
.SetDisplay("Equity TP %", "Close all when floating profit reaches this percent", "Risk")
self._loss_percent = self.Param("LossPercent", 30.0) \
.SetNotNegative() \
.SetDisplay("Equity SL %", "Close all when floating loss reaches this percent", "Risk")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Signal Timeframe", "Timeframe for moving averages", "General")
self._entry_price = 0.0
self._initial_balance = 0.0
self._processed_bars = 0
@property
def FastMaPeriod(self):
return self._fast_ma_period.Value
@property
def SlowMaPeriod(self):
return self._slow_ma_period.Value
@property
def MaShift(self):
return self._ma_shift.Value
@property
def ProfitPercent(self):
return self._profit_percent.Value
@property
def LossPercent(self):
return self._loss_percent.Value
@property
def CandleType(self):
return self._candle_type.Value
def OnStarted2(self, time):
super(vector_strategy, self).OnStarted2(time)
fast = SmoothedMovingAverage()
fast.Length = self.FastMaPeriod
slow = SmoothedMovingAverage()
slow.Length = self.SlowMaPeriod
portfolio = self.Portfolio
self._initial_balance = float(portfolio.CurrentValue) if portfolio is not None and portfolio.CurrentValue is not None else 0.0
subscription = self.SubscribeCandles(self.CandleType)
subscription \
.Bind(fast, slow, self.process_candle) \
.Start()
def process_candle(self, candle, fast_val, slow_val):
if candle.State != CandleStates.Finished:
return
self._processed_bars += 1
if not self.IsFormed:
return
if self._processed_bars <= self.MaShift:
return
fast = float(fast_val)
slow = float(slow_val)
# Check equity thresholds
if self.Position != 0 and self._initial_balance > 0:
portfolio = self.Portfolio
equity = float(portfolio.CurrentValue) if portfolio is not None and portfolio.CurrentValue is not None else 0.0
floating = equity - self._initial_balance
profit_threshold = self._initial_balance * float(self.ProfitPercent) / 100.0
loss_threshold = self._initial_balance * float(self.LossPercent) / 100.0
if (profit_threshold > 0 and floating >= profit_threshold) or \
(loss_threshold > 0 and floating <= -loss_threshold):
if self.Position > 0:
self.SellMarket()
elif self.Position < 0:
self.BuyMarket()
self._entry_price = 0.0
return
# Entry/exit logic
if fast > slow and self.Position <= 0:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
self._entry_price = float(candle.ClosePrice)
elif fast < slow and self.Position >= 0:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
self._entry_price = float(candle.ClosePrice)
def OnReseted(self):
super(vector_strategy, self).OnReseted()
self._entry_price = 0.0
self._initial_balance = 0.0
self._processed_bars = 0
def CreateClone(self):
return vector_strategy()