Diese Strategie ist eine StockSharp-Implementierung des MetaTrader-Gittersystems "VR---SETKAa3hM". Sie eröffnet eine Abfolge von Kauf- oder Verkaufsorders basierend auf der prozentualen Abweichung vom Tagesbereich und erhöht optional das Volumen mithilfe eines Martingale-Multiplikators. Der durchschnittliche Einstiegspreis aller offenen Orders wird verfolgt, um ein einheitliches Take-Profit-Ziel zu setzen.
Parameter
Distance: Preisabstand in Punkten zwischen den Gitterniveaus.
TakeProfit: Gewinnziel in Punkten für die Erstorder.
Correction: Zusätzlicher Gewinn in Punkten, der zum Durchschnittspreis addiert wird, wenn mehr als eine Order offen ist.
SignalPercent: Prozentschwelle zur Erkennung der Abweichung vom Tagesbereich.
UseMartingale: Volumen mit der Anzahl offener Orders multiplizieren.
CandleType: Kerzen-Zeitrahmen für Signalberechnungen.
Logik
Wenn eine abgeschlossene Kerze erscheint, wird der aktuelle Schlusskurs in Relation zum Tageshoch und -tief berechnet.
Wenn die vorherige Kerze bullisch war und der Schlusskurs ausreichend unter dem Tageshoch liegt, wird ein Kaufgitter gestartet oder fortgesetzt.
Wenn die vorherige Kerze bärisch war und der Schlusskurs ausreichend über dem Tagestief liegt, wird ein Verkaufsgitter gestartet oder fortgesetzt.
Zusätzliche Orders werden platziert, wenn der Preis um Distance Punkte gegen die Position läuft.
Sobald der Preis zum durchschnittlichen Einstiegspreis plus Correction für Käufe oder minus Correction für Verkäufe zurückkehrt, werden alle Positionen mit einer Market-Order geschlossen.
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>
/// EMA trend + candle direction strategy (converted from grid).
/// </summary>
public class VrSetkaGridStrategy : Strategy
{
private readonly StrategyParam<int> _emaPeriod;
private readonly StrategyParam<DataType> _candleType;
private decimal _prevEma;
private decimal _prevClose;
private bool _hasPrev;
public int EmaPeriod { get => _emaPeriod.Value; set => _emaPeriod.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public VrSetkaGridStrategy()
{
_emaPeriod = Param(nameof(EmaPeriod), 20)
.SetGreaterThanZero()
.SetDisplay("EMA Period", "EMA period for trend", "Indicators");
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Base candle series", "General");
}
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
=> [(Security, CandleType)];
protected override void OnReseted()
{
base.OnReseted();
_prevEma = 0;
_prevClose = 0;
_hasPrev = false;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var ema = new ExponentialMovingAverage { Length = EmaPeriod };
SubscribeCandles(CandleType)
.Bind(ema, ProcessCandle)
.Start();
}
private void ProcessCandle(ICandleMessage candle, decimal emaValue)
{
if (candle.State != CandleStates.Finished) return;
var close = candle.ClosePrice;
if (!_hasPrev)
{
_prevEma = emaValue;
_prevClose = close;
_hasPrev = true;
return;
}
var crossUp = _prevClose <= _prevEma && close > emaValue;
var crossDown = _prevClose >= _prevEma && close < emaValue;
if (crossUp && Position <= 0)
{
if (Position < 0) BuyMarket();
BuyMarket();
}
else if (crossDown && Position >= 0)
{
if (Position > 0) SellMarket();
SellMarket();
}
_prevEma = emaValue;
_prevClose = close;
}
}
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 vr_setka_grid_strategy(Strategy):
def __init__(self):
super(vr_setka_grid_strategy, self).__init__()
self._ema_period = self.Param("EmaPeriod", 20) \
.SetDisplay("EMA Period", "EMA period for trend", "Indicators")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Base candle series", "General")
self._prev_ema = 0.0
self._prev_close = 0.0
self._has_prev = False
@property
def ema_period(self):
return self._ema_period.Value
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(vr_setka_grid_strategy, self).OnReseted()
self._prev_ema = 0.0
self._prev_close = 0.0
self._has_prev = False
def OnStarted2(self, time):
super(vr_setka_grid_strategy, self).OnStarted2(time)
ema = ExponentialMovingAverage()
ema.Length = self.ema_period
self.SubscribeCandles(self.candle_type).Bind(ema, self.process_candle).Start()
def process_candle(self, candle, ema_value):
if candle.State != CandleStates.Finished:
return
close = float(candle.ClosePrice)
ev = float(ema_value)
if not self._has_prev:
self._prev_ema = ev
self._prev_close = close
self._has_prev = True
return
cross_up = self._prev_close <= self._prev_ema and close > ev
cross_down = self._prev_close >= self._prev_ema and close < ev
if cross_up and self.Position <= 0:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
elif cross_down and self.Position >= 0:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
self._prev_ema = ev
self._prev_close = close
def CreateClone(self):
return vr_setka_grid_strategy()