Diese Strategie emuliert den Charles Expert Advisor, indem sie exponentielle gleitende Durchschnitte (EMA) mit einem RSI-Filter und einem Trailing Stop kombiniert. Sie handelt in beide Richtungen und schützt Positionen dynamisch.
Das System überwacht einen schnellen und einen langsamen EMA im gewählten Zeitrahmen. Wenn der schnelle EMA den langsamen EMA nach oben kreuzt und der RSI 55 überschreitet, eröffnet die Strategie eine Long-Position. Umgekehrt, wenn der schnelle EMA den langsamen EMA nach unten kreuzt und der RSI unter 45 fällt, wird eine Short-Position eröffnet. Nach dem Einstieg folgt ein Trailing Stop dem Preis, um Gewinne zu sichern, während ein fester Take Profit und Stop Loss durch den integrierten Positionsschutz verwaltet werden.
Details
Einstiegskriterien:
Long: Schneller EMA kreuzt über langsamen EMA und RSI > 55.
Short: Schneller EMA kreuzt unter langsamen EMA und RSI < 45.
Long/Short: Beide.
Ausstiegskriterien:
Trailing Stop.
Stop Loss oder Take Profit.
Stops: Verwendet integrierten Schutz mit Trailing.
Standardwerte:
FastPeriod = 18
SlowPeriod = 60
RsiPeriod = 14
TakeProfit = 0.02
StopLoss = 0.008
TrailStart = 0.006
TrailOffset = 0.003
Filter:
Kategorie: Trendfolge
Richtung: Beide
Indikatoren: Mehrere
Stops: Ja
Komplexität: Mittel
Zeitrahmen: Standardmäßig 1 Stunde
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>
/// Charles strategy: EMA crossover with RSI filter.
/// </summary>
public class CharlesStrategy : Strategy
{
private readonly StrategyParam<int> _fastPeriod;
private readonly StrategyParam<int> _slowPeriod;
private readonly StrategyParam<int> _rsiPeriod;
private readonly StrategyParam<DataType> _candleType;
private bool _wasFastBelowSlow;
private bool _isInitialized;
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 DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public CharlesStrategy()
{
_fastPeriod = Param(nameof(FastPeriod), 18)
.SetGreaterThanZero()
.SetDisplay("Fast EMA", "Period of the fast EMA", "Indicators");
_slowPeriod = Param(nameof(SlowPeriod), 60)
.SetGreaterThanZero()
.SetDisplay("Slow EMA", "Period of the slow EMA", "Indicators");
_rsiPeriod = Param(nameof(RsiPeriod), 14)
.SetGreaterThanZero()
.SetDisplay("RSI Period", "RSI calculation length", "Indicators");
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Time frame for candles", "General");
}
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
=> [(Security, CandleType)];
protected override void OnReseted()
{
base.OnReseted();
_wasFastBelowSlow = false;
_isInitialized = false;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var fast = new ExponentialMovingAverage { Length = FastPeriod };
var slow = new ExponentialMovingAverage { Length = SlowPeriod };
var rsi = new RelativeStrengthIndex { Length = RsiPeriod };
SubscribeCandles(CandleType)
.Bind(fast, slow, rsi, ProcessCandle)
.Start();
}
private void ProcessCandle(ICandleMessage candle, decimal fastValue, decimal slowValue, decimal rsiValue)
{
if (candle.State != CandleStates.Finished) return;
if (!_isInitialized)
{
_wasFastBelowSlow = fastValue < slowValue;
_isInitialized = true;
return;
}
var isFastBelowSlow = fastValue < slowValue;
// Long signal: fast crosses above slow + RSI > 55
if (_wasFastBelowSlow && !isFastBelowSlow && rsiValue > 55 && Position <= 0)
{
if (Position < 0) BuyMarket();
BuyMarket();
}
// Short signal: fast crosses below slow + RSI < 45
else if (!_wasFastBelowSlow && isFastBelowSlow && rsiValue < 45 && Position >= 0)
{
if (Position > 0) SellMarket();
SellMarket();
}
_wasFastBelowSlow = isFastBelowSlow;
}
}
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, RelativeStrengthIndex
from StockSharp.Algo.Strategies import Strategy
class charles_strategy(Strategy):
def __init__(self):
super(charles_strategy, self).__init__()
self._fast_period = self.Param("FastPeriod", 18) \
.SetDisplay("Fast EMA", "Period of the fast EMA", "Indicators")
self._slow_period = self.Param("SlowPeriod", 60) \
.SetDisplay("Slow EMA", "Period of the slow EMA", "Indicators")
self._rsi_period = self.Param("RsiPeriod", 14) \
.SetDisplay("RSI Period", "RSI calculation length", "Indicators")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Time frame for candles", "General")
self._was_fast_below_slow = False
self._is_initialized = False
@property
def fast_period(self):
return self._fast_period.Value
@property
def slow_period(self):
return self._slow_period.Value
@property
def rsi_period(self):
return self._rsi_period.Value
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(charles_strategy, self).OnReseted()
self._was_fast_below_slow = False
self._is_initialized = False
def OnStarted2(self, time):
super(charles_strategy, self).OnStarted2(time)
fast = ExponentialMovingAverage()
fast.Length = self.fast_period
slow = ExponentialMovingAverage()
slow.Length = self.slow_period
rsi = RelativeStrengthIndex()
rsi.Length = self.rsi_period
self.SubscribeCandles(self.candle_type).Bind(fast, slow, rsi, self.process_candle).Start()
def process_candle(self, candle, fast_value, slow_value, rsi_value):
if candle.State != CandleStates.Finished:
return
fv = float(fast_value)
sv = float(slow_value)
rv = float(rsi_value)
if not self._is_initialized:
self._was_fast_below_slow = fv < sv
self._is_initialized = True
return
is_fast_below_slow = fv < sv
if self._was_fast_below_slow and not is_fast_below_slow and rv > 55 and self.Position <= 0:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
elif not self._was_fast_below_slow and is_fast_below_slow and rv < 45 and self.Position >= 0:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
self._was_fast_below_slow = is_fast_below_slow
def CreateClone(self):
return charles_strategy()