ForexProfitBoost-Strategie
Überblick
Die ForexProfitBoost-Strategie ist ein reversal-basiertes Handelssystem, das einen schnellen Exponential Moving Average (EMA) und einen langsamen Simple Moving Average (SMA) kombiniert. Die Strategie wartet darauf, dass der schnelle EMA den langsamen SMA kreuzt, und handelt dann entgegen der Kreuzungsrichtung in Erwartung einer Preiskorrektur. Optionale Stop-Loss- und Take-Profit-Niveaus in absoluten Preispunkten können für das Risikomanagement konfiguriert werden.
Indikatoren
- EMA (schnell): Standardperiode 7.
- SMA (langsam): Standardperiode 21.
Handelsregeln
- Abonnieren des ausgewählten Kerzen-Zeitrahmens.
- Berechnung von EMA und SMA auf jeder abgeschlossenen Kerze.
- Wenn der schnelle EMA den langsamen SMA nach unten kreuzt:
- Short-Positionen schließen.
- Neue Long-Position öffnen.
- Wenn der schnelle EMA den langsamen SMA nach oben kreuzt:
- Long-Positionen schließen.
- Neue Short-Position öffnen.
- Stop-Loss- und Take-Profit-Niveaus relativ zum Einstiegspreis anwenden, sofern angegeben.
Parameter
| Name | Beschreibung | Standard |
|---|---|---|
FastPeriod |
Periode für den schnellen EMA. | 7 |
SlowPeriod |
Periode für den langsamen SMA. | 21 |
StopLoss |
Stop-Loss-Abstand in Preispunkten. | 1000 |
TakeProfit |
Take-Profit-Abstand in Preispunkten. | 2000 |
CandleType |
Zeitrahmen für Berechnungen. | 1 Stunde |
Hinweise
- Die Strategie verwendet die High-Level StockSharp API und speichert keine historischen Sammlungen.
- Trades werden ausschließlich mit Marktaufträgen nach Abschluss einer Kerze ausgeführt.
- Alle Kommentare im Quellcode sind auf Englisch verfasst, wie gefordert.
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>
/// Forex Profit Boost reversal strategy.
/// Opens long when fast EMA crosses below slow SMA.
/// Opens short when fast EMA crosses above slow SMA.
/// Uses optional stop-loss and take-profit in price points.
/// </summary>
public class ForexProfitBoostStrategy : Strategy
{
private static readonly TimeSpan _signalCooldown = TimeSpan.FromHours(18);
private readonly StrategyParam<int> _fastPeriod;
private readonly StrategyParam<int> _slowPeriod;
private readonly StrategyParam<decimal> _stopLoss;
private readonly StrategyParam<decimal> _takeProfit;
private readonly StrategyParam<DataType> _candleType;
private bool? _wasFastAboveSlow;
private decimal _entryPrice;
private bool _isLongPosition;
private DateTime _lastSignalTime;
/// <summary>
/// Fast EMA period.
/// </summary>
public int FastPeriod
{
get => _fastPeriod.Value;
set => _fastPeriod.Value = value;
}
/// <summary>
/// Slow SMA period.
/// </summary>
public int SlowPeriod
{
get => _slowPeriod.Value;
set => _slowPeriod.Value = value;
}
/// <summary>
/// Stop loss distance in price points.
/// </summary>
public decimal StopLoss
{
get => _stopLoss.Value;
set => _stopLoss.Value = value;
}
/// <summary>
/// Take profit distance in price points.
/// </summary>
public decimal TakeProfit
{
get => _takeProfit.Value;
set => _takeProfit.Value = value;
}
/// <summary>
/// The type of candles used for strategy calculations.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Initializes a new instance of <see cref="ForexProfitBoostStrategy"/>.
/// </summary>
public ForexProfitBoostStrategy()
{
_fastPeriod = Param(nameof(FastPeriod), 7)
.SetGreaterThanZero()
.SetDisplay("Fast EMA Period", "Period of the fast EMA", "Parameters")
.SetOptimize(5, 15, 1);
_slowPeriod = Param(nameof(SlowPeriod), 21)
.SetGreaterThanZero()
.SetDisplay("Slow SMA Period", "Period of the slow SMA", "Parameters")
.SetOptimize(10, 40, 5);
_stopLoss = Param(nameof(StopLoss), 1000m)
.SetDisplay("Stop Loss", "Stop loss distance in price points", "Risk Management")
.SetOptimize(500m, 2000m, 100m);
_takeProfit = Param(nameof(TakeProfit), 2000m)
.SetDisplay("Take Profit", "Take profit distance in price points", "Risk Management")
.SetOptimize(1000m, 4000m, 100m);
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame())
.SetDisplay("Candle Type", "Type of candles to use", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_wasFastAboveSlow = null;
_entryPrice = 0m;
_isLongPosition = false;
_lastSignalTime = default;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var fastEma = new ExponentialMovingAverage { Length = FastPeriod };
var slowSma = new SimpleMovingAverage { Length = SlowPeriod };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(fastEma, slowSma, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, fastEma);
DrawIndicator(area, slowSma);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal fastValue, decimal slowValue)
{
if (candle.State != CandleStates.Finished)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
var isFastAboveSlow = fastValue > slowValue;
if (_wasFastAboveSlow is null)
{
_wasFastAboveSlow = isFastAboveSlow;
return;
}
var isBullishSignal = _wasFastAboveSlow == true && !isFastAboveSlow;
var isBearishSignal = _wasFastAboveSlow == false && isFastAboveSlow;
if ((isBullishSignal || isBearishSignal) && _lastSignalTime != default && candle.CloseTime < _lastSignalTime + _signalCooldown)
{
_wasFastAboveSlow = isFastAboveSlow;
CheckRisk(candle.ClosePrice);
return;
}
// Detect crossover and trade against the direction (reversal)
if (isBullishSignal)
{
// Fast EMA crossed below slow SMA -> open long
if (Position <= 0)
{
var volume = Position < 0 ? Math.Abs(Position) + Volume : Volume;
BuyMarket(volume);
_entryPrice = candle.ClosePrice;
_isLongPosition = true;
_lastSignalTime = candle.CloseTime;
}
}
else if (isBearishSignal)
{
// Fast EMA crossed above slow SMA -> open short
if (Position >= 0)
{
var volume = Position > 0 ? Position + Volume : Volume;
SellMarket(volume);
_entryPrice = candle.ClosePrice;
_isLongPosition = false;
_lastSignalTime = candle.CloseTime;
}
}
// Update crossover state
_wasFastAboveSlow = isFastAboveSlow;
// Check stop loss and take profit
CheckRisk(candle.ClosePrice);
}
private void CheckRisk(decimal currentPrice)
{
if (Position == 0 || _entryPrice == 0)
return;
if (_isLongPosition)
{
if (_stopLoss.Value > 0m && currentPrice <= _entryPrice - _stopLoss.Value)
{
SellMarket(Position);
_entryPrice = 0m;
return;
}
if (_takeProfit.Value > 0m && currentPrice >= _entryPrice + _takeProfit.Value)
{
SellMarket(Position);
_entryPrice = 0m;
}
}
else
{
if (_stopLoss.Value > 0m && currentPrice >= _entryPrice + _stopLoss.Value)
{
BuyMarket(Math.Abs(Position));
_entryPrice = 0m;
return;
}
if (_takeProfit.Value > 0m && currentPrice <= _entryPrice - _takeProfit.Value)
{
BuyMarket(Math.Abs(Position));
_entryPrice = 0m;
}
}
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
from System import TimeSpan, Math, DateTime
from StockSharp.Messages import DataType, CandleStates
from StockSharp.Algo.Indicators import ExponentialMovingAverage, SimpleMovingAverage
from StockSharp.Algo.Strategies import Strategy
class forex_profit_boost_strategy(Strategy):
def __init__(self):
super(forex_profit_boost_strategy, self).__init__()
self._fast_period = self.Param("FastPeriod", 7) \
.SetDisplay("Fast EMA Period", "Period of the fast EMA", "Parameters")
self._slow_period = self.Param("SlowPeriod", 21) \
.SetDisplay("Slow SMA Period", "Period of the slow SMA", "Parameters")
self._stop_loss = self.Param("StopLoss", 1000.0) \
.SetDisplay("Stop Loss", "Stop loss distance in price points", "Risk Management")
self._take_profit = self.Param("TakeProfit", 2000.0) \
.SetDisplay("Take Profit", "Take profit distance in price points", "Risk Management")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(5))) \
.SetDisplay("Candle Type", "Type of candles to use", "General")
self._was_fast_above_slow = None
self._entry_price = 0.0
self._is_long_position = False
self._last_signal_time = DateTime.MinValue
self._signal_cooldown = TimeSpan.FromHours(18)
@property
def FastPeriod(self):
return self._fast_period.Value
@FastPeriod.setter
def FastPeriod(self, value):
self._fast_period.Value = value
@property
def SlowPeriod(self):
return self._slow_period.Value
@SlowPeriod.setter
def SlowPeriod(self, value):
self._slow_period.Value = value
@property
def StopLoss(self):
return self._stop_loss.Value
@StopLoss.setter
def StopLoss(self, value):
self._stop_loss.Value = value
@property
def TakeProfit(self):
return self._take_profit.Value
@TakeProfit.setter
def TakeProfit(self, value):
self._take_profit.Value = value
@property
def CandleType(self):
return self._candle_type.Value
@CandleType.setter
def CandleType(self, value):
self._candle_type.Value = value
def _check_risk(self, current_price):
if self.Position == 0 or self._entry_price == 0.0:
return
if self._is_long_position:
if self.StopLoss > 0.0 and current_price <= self._entry_price - self.StopLoss:
self.SellMarket(self.Position)
self._entry_price = 0.0
return
if self.TakeProfit > 0.0 and current_price >= self._entry_price + self.TakeProfit:
self.SellMarket(self.Position)
self._entry_price = 0.0
else:
if self.StopLoss > 0.0 and current_price >= self._entry_price + self.StopLoss:
self.BuyMarket(abs(self.Position))
self._entry_price = 0.0
return
if self.TakeProfit > 0.0 and current_price <= self._entry_price - self.TakeProfit:
self.BuyMarket(abs(self.Position))
self._entry_price = 0.0
def OnStarted2(self, time):
super(forex_profit_boost_strategy, self).OnStarted2(time)
fast_ema = ExponentialMovingAverage()
fast_ema.Length = self.FastPeriod
slow_sma = SimpleMovingAverage()
slow_sma.Length = self.SlowPeriod
subscription = self.SubscribeCandles(self.CandleType)
subscription \
.Bind(fast_ema, slow_sma, self.ProcessCandle) \
.Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, fast_ema)
self.DrawIndicator(area, slow_sma)
self.DrawOwnTrades(area)
def ProcessCandle(self, candle, fast_value, slow_value):
if candle.State != CandleStates.Finished:
return
fast_val = float(fast_value)
slow_val = float(slow_value)
is_fast_above_slow = fast_val > slow_val
if self._was_fast_above_slow is None:
self._was_fast_above_slow = is_fast_above_slow
return
is_bullish_signal = self._was_fast_above_slow and not is_fast_above_slow
is_bearish_signal = not self._was_fast_above_slow and is_fast_above_slow
if ((is_bullish_signal or is_bearish_signal)
and self._last_signal_time != DateTime.MinValue
and candle.CloseTime < self._last_signal_time + self._signal_cooldown):
self._was_fast_above_slow = is_fast_above_slow
self._check_risk(float(candle.ClosePrice))
return
if is_bullish_signal:
if self.Position <= 0:
volume = abs(self.Position) + self.Volume if self.Position < 0 else self.Volume
self.BuyMarket(volume)
self._entry_price = float(candle.ClosePrice)
self._is_long_position = True
self._last_signal_time = candle.CloseTime
elif is_bearish_signal:
if self.Position >= 0:
volume = self.Position + self.Volume if self.Position > 0 else self.Volume
self.SellMarket(volume)
self._entry_price = float(candle.ClosePrice)
self._is_long_position = False
self._last_signal_time = candle.CloseTime
self._was_fast_above_slow = is_fast_above_slow
self._check_risk(float(candle.ClosePrice))
def OnReseted(self):
super(forex_profit_boost_strategy, self).OnReseted()
self._was_fast_above_slow = None
self._entry_price = 0.0
self._is_long_position = False
self._last_signal_time = DateTime.MinValue
def CreateClone(self):
return forex_profit_boost_strategy()