Die Grid Rebalance Strategy ist eine High-Level-StockSharp-Portierung des Expertenberaters „Grid“ von Mission Automate. Die Strategie wechselt zwischen langen und kurzen Grid-Zyklen und behält immer eine Leiter von Limit-Orders in der aktiven Richtung bei. Sobald die Gesamtposition ein gemeinsames Take-Profit-Niveau erreicht, wird der Zyklus geschlossen, alle ausstehenden Aufträge werden entfernt und der nächste Zyklus beginnt in die entgegengesetzte Richtung.
Wie es funktioniert
Zyklusstart – Wenn keine Positionen oder ausstehenden Aufträge vorhanden sind, eröffnet die Strategie eine Marktposition in der durch FirstTradeSide definierten Richtung unter Verwendung von StartVolume-Lots.
Platzierung des Rasters – Nach jeder ausgeführten Order in der aktiven Richtung platziert der Algorithmus eine neue Limit-Order im Abstand von GridStepPoints (vom Instrument in Preis umgewandelt PriceStep). Das Volumen der nächsten Bestellung entspricht dem Volumen der zuletzt ausgeführten Bestellung multipliziert mit LotMultiplier.
Durchschnittsbasierter Take-Profit – Für jede ausgeführte Order wird der gewichtete durchschnittliche Einstiegspreis neu berechnet. Der Take-Profit für den gesamten Korb wird auf den Durchschnittspreis plus/minus TargetPoints gesetzt (auch umgerechnet über PriceStep). Kerzenhochs und -tiefs werden zur Modellierung des maklerseitigen Triggerverhaltens verwendet.
Zyklusabschluss – Wenn das Take-Profit-Niveau erreicht ist, schließt die Strategie die gesamte Position mit einer Marktorder, storniert verbleibende ausstehende Orders, merkt sich die Richtung des abgeschlossenen Zyklus und kehrt die Richtung für den nächsten um.
Parameter
FirstTradeSide – Richtung des ersten Zyklus (Buy oder Sell). Bei jedem abgeschlossenen Zyklus wird die Richtung automatisch umgedreht.
StartVolume – Losgröße der anfänglichen Marktorder in jedem Zyklus.
LotMultiplier – Multiplikator, der bei der Vorbereitung der nächsten Rasterebene auf das zuletzt ausgeführte Auftragsvolumen angewendet wird. Werte größer als eins erzeugen einen Martingal-ähnlichen Verlauf.
GridStepPoints – Abstand zwischen Rasterebenen, ausgedrückt in Punkten. Die Strategie multipliziert ihn mit Security.PriceStep, um die absolute Preisdifferenz zu erhalten.
TargetPoints – Take-Profit-Distanz vom gewichteten durchschnittlichen Einstiegspreis, gemessen in Punkten.
CandleType – Kerzenserie zur Überwachung von Preisextremen zur Auslösung von Ausstiegen.
Risikomanagement und Verhalten
Es wird kein expliziter Stop-Loss verwendet; Das Raster erhöht weiterhin das Engagement, während sich der Markt gegen die Position bewegt.
Es ist jeweils nur eine ausstehende Bestellung aktiv. Sobald die Bestellung ausgeführt ist, wird die nächste Ebene sofort eingeplant.
Der Zyklus kann erst beginnen, wenn sowohl die Position als auch die ausstehende Warteschlange leer sind und das Instrument über einen gültigen PriceStep verfügt.
Durch die Konvertierung bleiben alle Berechnungen innerhalb der Strategie, ohne globale Sammlungen oder Indikatorpuffer zu berühren, und folgen den Projektregeln.
Ausstehende Aufträge werden jedes Mal storniert, wenn ein Zyklus endet, wodurch verwaiste Limits aus früheren Zyklen verhindert werden.
Notizen
Alle punktbasierten Einstellungen werden mit Security.PriceStep in Preise umgewandelt. Wenn der Schritt Null ist, wartet die Strategie, bis das Instrument ihn bereitstellt.
Die Implementierung basiert je nach Bedarf ausschließlich auf der übergeordneten Ebene API (SubscribeCandles, Bind, BuyMarket, SellMarket, BuyLimit, SellLimit).
Eine Python-Version ist in dieser Aufgabe absichtlich nicht enthalten.
using System;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Grid Rebalance strategy: RSI + EMA crossover-based.
/// Buys when close crosses above EMA with RSI confirmation.
/// Sells when close crosses below EMA with RSI confirmation.
/// </summary>
public class GridRebalanceStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _rsiPeriod;
private readonly StrategyParam<int> _emaPeriod;
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public int RsiPeriod
{
get => _rsiPeriod.Value;
set => _rsiPeriod.Value = value;
}
public int EmaPeriod
{
get => _emaPeriod.Value;
set => _emaPeriod.Value = value;
}
public GridRebalanceStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(30).TimeFrame())
.SetDisplay("Candle Type", "Candle timeframe", "General");
_rsiPeriod = Param(nameof(RsiPeriod), 14)
.SetGreaterThanZero()
.SetDisplay("RSI Period", "RSI period", "Indicators");
_emaPeriod = Param(nameof(EmaPeriod), 20)
.SetGreaterThanZero()
.SetDisplay("EMA Period", "EMA period", "Indicators");
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var rsi = new RelativeStrengthIndex { Length = RsiPeriod };
var ema = new ExponentialMovingAverage { Length = EmaPeriod };
decimal? prevClose = null;
decimal? prevEma = null;
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(rsi, ema, (candle, rsiVal, emaVal) =>
{
if (candle.State != CandleStates.Finished)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
var close = candle.ClosePrice;
if (prevClose.HasValue && prevEma.HasValue)
{
var crossUp = prevClose.Value <= prevEma.Value && close > emaVal;
var crossDown = prevClose.Value >= prevEma.Value && close < emaVal;
if (crossUp && rsiVal < 55m && Position <= 0)
BuyMarket();
else if (crossDown && rsiVal > 45m && Position >= 0)
SellMarket();
}
prevClose = close;
prevEma = emaVal;
})
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, ema);
DrawOwnTrades(area);
}
}
}
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 RelativeStrengthIndex, ExponentialMovingAverage
from StockSharp.Algo.Strategies import Strategy
class grid_rebalance_strategy(Strategy):
"""
Grid Rebalance: RSI + EMA crossover strategy.
Buys when close crosses above EMA with RSI < 55.
Sells when close crosses below EMA with RSI > 45.
"""
def __init__(self):
super(grid_rebalance_strategy, self).__init__()
self._rsi_period = self.Param("RsiPeriod", 14) \
.SetDisplay("RSI Period", "RSI period", "Indicators")
self._ema_period = self.Param("EmaPeriod", 20) \
.SetDisplay("EMA Period", "EMA period", "Indicators")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(30))) \
.SetDisplay("Candle Type", "Candle timeframe", "General")
self._prev_close = None
self._prev_ema = None
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(grid_rebalance_strategy, self).OnReseted()
self._prev_close = None
self._prev_ema = None
def OnStarted2(self, time):
super(grid_rebalance_strategy, self).OnStarted2(time)
rsi = RelativeStrengthIndex()
rsi.Length = self._rsi_period.Value
ema = ExponentialMovingAverage()
ema.Length = self._ema_period.Value
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(rsi, ema, self._process_candle).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, ema)
self.DrawOwnTrades(area)
def _process_candle(self, candle, rsi_val, ema_val):
if candle.State != CandleStates.Finished:
return
close = float(candle.ClosePrice)
rsi = float(rsi_val)
ema = float(ema_val)
if self._prev_close is not None and self._prev_ema is not None:
cross_up = self._prev_close <= self._prev_ema and close > ema
cross_down = self._prev_close >= self._prev_ema and close < ema
if cross_up and rsi < 55.0 and self.Position <= 0:
self.BuyMarket()
elif cross_down and rsi > 45.0 and self.Position >= 0:
self.SellMarket()
self._prev_close = close
self._prev_ema = ema
def CreateClone(self):
return grid_rebalance_strategy()