Start
/
Strategie-Beispiele
Auf GitHub ansehen
Ilan 1.6 Dynamic Grid-Strategie
Die Ilan 1.6 Dynamic-Strategie ist ein klassischer Grid- und Martingale-Expertenberater. Sie eröffnet einen ersten Trade in einer gewählten Richtung und platziert zusätzliche Orders, sobald sich der Preis um einen festen Schritt gegen die Position bewegt. Das Volumen neuer Orders wächst geometrisch nach einem Lot-Exponenten. Alle Positionen im Korb werden geschlossen, wenn der Preis zum durchschnittlichen Einstiegspreis zuzüglich einer Take-Profit-Distanz zurückkehrt. Ein Trailing-Stop kann optional Gewinne schützen, wenn der Preis weit genug in die günstige Richtung läuft.
Der Algorithmus beruht ausschließlich auf Kursbewegungen und verwendet keine Indikatoren. Da die Positionsgröße nach jeder negativen Bewegung zunimmt, trägt das System ein hohes Risiko, kann aber schnelle Gegenbewegungen einfangen.
Details
Einstieg
Die erste Order wird in der konfigurierten Richtung eröffnet.
Zusätzliche Orders werden alle PipStep Punkte gegen die aktuelle Position hinzugefügt, bis zu MaxTrades.
Volumen jeder neuen Order = InitialVolume * LotExponent^N.
Ausstieg
Alle schließen, wenn der Preis AveragePrice ± TakeProfit berührt.
Optionaler Trailing-Stop startet nach TrailStart Punkten Gewinn und folgt dem Preis im Abstand von TrailStop.
Positionsverwaltung
Nur Long- oder nur Short-Serie zur gleichen Zeit.
Nach dem Schließen des Korbs startet die Strategie erneut in die Ausgangsrichtung.
Parameter
InitialVolume – Volumen der ersten Order (Standard 1).
LotExponent – Multiplikator für nachfolgende Ordergrößen (Standard 1.6).
PipStep – Abstand in Punkten zwischen Grid-Ebenen (Standard 30).
TakeProfit – Gewinnziel vom Durchschnittspreis in Punkten (Standard 10).
MaxTrades – Maximale Anzahl aktiver Orders (Standard 10).
StartLong – Ersten Trade als Long eröffnen, wenn true (Standard true).
UseTrailingStop – Trailing-Stop aktivieren (Standard false).
TrailStart – Gewinn in Punkten zum Starten des Trailings (Standard 10).
TrailStop – Trailing-Abstand in Punkten (Standard 10).
CandleType – Zeitrahmen der Kerzen (Standard 1 Minute).
Filter
Kategorie: Grid
Richtung: Beide
Indikatoren: Keine
Stops: Optional
Komplexität: Moderat
Zeitrahmen: Intraday
Saisonalität: Nein
Neuronale Netze: Nein
Divergenz: Nein
Risikolevel: Hoch
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>
/// Grid averaging strategy based on the Ilan 1.6 Dynamic expert advisor.
/// Adds positions when price moves against the current one and closes the
/// whole basket on a take profit.
/// Each grid level trades 1 unit; closing flattens via multiple market orders.
/// </summary>
public class Ilan16DynamicStrategy : Strategy
{
private readonly StrategyParam<decimal> _pipStep;
private readonly StrategyParam<decimal> _takeProfit;
private readonly StrategyParam<int> _maxTrades;
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<bool> _startLong;
private int _tradeCount;
private decimal _lastEntryPrice;
private decimal _avgPrice;
private bool _isLong;
/// <summary>
/// Distance in price steps between grid levels.
/// </summary>
public decimal PipStep { get => _pipStep.Value; set => _pipStep.Value = value; }
/// <summary>
/// Profit target from average price in price steps.
/// </summary>
public decimal TakeProfit { get => _takeProfit.Value; set => _takeProfit.Value = value; }
/// <summary>
/// Maximum number of averaging entries.
/// </summary>
public int MaxTrades { get => _maxTrades.Value; set => _maxTrades.Value = value; }
/// <summary>
/// Type of candles to process.
/// </summary>
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
/// <summary>
/// Open first trade as long if true.
/// </summary>
public bool StartLong { get => _startLong.Value; set => _startLong.Value = value; }
/// <summary>
/// Constructor.
/// </summary>
public Ilan16DynamicStrategy()
{
_pipStep = Param(nameof(PipStep), 50000m)
.SetGreaterThanZero()
.SetDisplay("Pip Step", "Distance in price steps between grid levels", "Trading")
.SetOptimize(10000m, 100000m, 10000m);
_takeProfit = Param(nameof(TakeProfit), 30000m)
.SetGreaterThanZero()
.SetDisplay("Take Profit", "Profit target from average price in price steps", "Trading")
.SetOptimize(10000m, 100000m, 10000m);
_maxTrades = Param(nameof(MaxTrades), 3)
.SetGreaterThanZero()
.SetDisplay("Max Trades", "Maximum number of averaging entries", "Trading")
.SetOptimize(2, 10, 1);
_startLong = Param(nameof(StartLong), true)
.SetDisplay("Start Long", "Open first trade as long", "General");
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).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();
ResetState();
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_isLong = StartLong;
var subscription = SubscribeCandles(CandleType);
subscription.Bind(ProcessCandle).Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle)
{
if (candle.State != CandleStates.Finished)
return;
var step = Security.PriceStep ?? 1m;
var price = candle.ClosePrice;
// No position - open initial entry
if (Position == 0)
{
if (_isLong)
BuyMarket();
else
SellMarket();
_tradeCount = 1;
_lastEntryPrice = price;
_avgPrice = price;
return;
}
// Check take profit: close entire basket
if (_isLong && price >= _avgPrice + TakeProfit * step)
{
CloseAll();
return;
}
else if (!_isLong && price <= _avgPrice - TakeProfit * step)
{
CloseAll();
return;
}
// Check for grid averaging entry (price moved against us)
if (_isLong && _tradeCount < MaxTrades && _lastEntryPrice - price >= PipStep * step)
{
BuyMarket();
_tradeCount++;
_avgPrice = (_avgPrice * (_tradeCount - 1) + price) / _tradeCount;
_lastEntryPrice = price;
}
else if (!_isLong && _tradeCount < MaxTrades && price - _lastEntryPrice >= PipStep * step)
{
SellMarket();
_tradeCount++;
_avgPrice = (_avgPrice * (_tradeCount - 1) + price) / _tradeCount;
_lastEntryPrice = price;
}
}
private void CloseAll()
{
var pos = Position;
if (pos > 0)
{
// Close long: sell abs(pos) times
for (var i = 0; i < (int)Math.Abs(pos); i++)
SellMarket();
}
else if (pos < 0)
{
// Close short: buy abs(pos) times
for (var i = 0; i < (int)Math.Abs(pos); i++)
BuyMarket();
}
ResetState();
}
private void ResetState()
{
_tradeCount = 0;
_lastEntryPrice = 0m;
_avgPrice = 0m;
_isLong = StartLong;
}
}
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
from StockSharp.Messages import DataType, CandleStates
from StockSharp.Algo.Strategies import Strategy
class ilan_16_dynamic_strategy(Strategy):
def __init__(self):
super(ilan_16_dynamic_strategy, self).__init__()
self._pip_step = self.Param("PipStep", 50000.0) \
.SetGreaterThanZero() \
.SetDisplay("Pip Step", "Distance in price steps between grid levels", "Trading") \
.SetOptimize(10000.0, 100000.0, 10000.0)
self._take_profit = self.Param("TakeProfit", 30000.0) \
.SetGreaterThanZero() \
.SetDisplay("Take Profit", "Profit target from average price in price steps", "Trading") \
.SetOptimize(10000.0, 100000.0, 10000.0)
self._max_trades = self.Param("MaxTrades", 3) \
.SetGreaterThanZero() \
.SetDisplay("Max Trades", "Maximum number of averaging entries", "Trading") \
.SetOptimize(2, 10, 1)
self._start_long = self.Param("StartLong", True) \
.SetDisplay("Start Long", "Open first trade as long", "General")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Type of candles to use", "General")
self._trade_count = 0
self._last_entry_price = 0.0
self._avg_price = 0.0
self._is_long = True
@property
def pip_step(self):
return self._pip_step.Value
@property
def take_profit(self):
return self._take_profit.Value
@property
def max_trades(self):
return self._max_trades.Value
@property
def start_long(self):
return self._start_long.Value
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(ilan_16_dynamic_strategy, self).OnReseted()
self._reset_state()
def _reset_state(self):
self._trade_count = 0
self._last_entry_price = 0.0
self._avg_price = 0.0
self._is_long = self.start_long
def OnStarted2(self, time):
super(ilan_16_dynamic_strategy, self).OnStarted2(time)
self._is_long = self.start_long
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(self.process_candle).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawOwnTrades(area)
def process_candle(self, candle):
if candle.State != CandleStates.Finished:
return
step = self.Security.PriceStep if self.Security.PriceStep is not None else 1.0
step = float(step)
price = float(candle.ClosePrice)
# No position - open initial entry
if self.Position == 0:
if self._is_long:
self.BuyMarket()
else:
self.SellMarket()
self._trade_count = 1
self._last_entry_price = price
self._avg_price = price
return
# Check take profit: close entire basket
if self._is_long and price >= self._avg_price + float(self.take_profit) * step:
self._close_all()
return
elif not self._is_long and price <= self._avg_price - float(self.take_profit) * step:
self._close_all()
return
# Check for grid averaging entry (price moved against us)
if self._is_long and self._trade_count < self.max_trades and self._last_entry_price - price >= float(self.pip_step) * step:
self.BuyMarket()
self._trade_count += 1
self._avg_price = (self._avg_price * (self._trade_count - 1) + price) / self._trade_count
self._last_entry_price = price
elif not self._is_long and self._trade_count < self.max_trades and price - self._last_entry_price >= float(self.pip_step) * step:
self.SellMarket()
self._trade_count += 1
self._avg_price = (self._avg_price * (self._trade_count - 1) + price) / self._trade_count
self._last_entry_price = price
def _close_all(self):
pos = self.Position
if pos > 0:
for i in range(int(abs(pos))):
self.SellMarket()
elif pos < 0:
for i in range(int(abs(pos))):
self.BuyMarket()
self._reset_state()
def CreateClone(self):
return ilan_16_dynamic_strategy()