Martin-Strategie - Verlustfreier Ausstieg V3
Diese Martingale-Mittelungsstrategie fügt einer Long-Position hinzu, wenn der Preis um einen konfigurierten Prozentsatz vom ersten Einstieg fällt. Jede neue Order erhöht den Geldbetrag durch einen Multiplikator und passt den Durchschnittspreis an. Die Position wird geschlossen, wenn das Kerzenhoch den Durchschnittspreis plus den Take-Profit-Prozentsatz erreicht, um Ausstiege nur im Gewinn zu gewährleisten.
Details
- Einstiegskriterien:
- Long:
Flat→ kaufen fürInitial Cash - Hinzufügen:
Price <= EntryPrice * (1 - PriceStep% * orderCount)&&orderCount < MaxOrders
- Long:
- Long/Short: Nur Long
- Ausstiegskriterien:
High >= AvgPrice * (1 + TakeProfit%)
- Stops: Nein
- Standardwerte:
Initial Cash= 100Max Orders= 20Price Step %= 1.5Take Profit %= 1Increase Factor= 1.05
- Filter:
- Kategorie: Mittelung nach unten
- Richtung: Nur Long
- Indikatoren: Keine
- Stops: Nein
- Komplexität: Niedrig
- Zeitrahmen: Beliebig
- Saisonalität: Nein
- Neuronale Netze: Nein
- Divergenz: Nein
- Risikolevel: Hoch
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;
public class MartinNoLossExitV3Strategy : Strategy
{
private readonly StrategyParam<decimal> _priceStepPercent;
private readonly StrategyParam<decimal> _takeProfitPercent;
private readonly StrategyParam<decimal> _increaseFactor;
private readonly StrategyParam<int> _maxOrders;
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _emaLength;
private ExponentialMovingAverage _ema;
private decimal _entryPrice;
private decimal _totalCost;
private decimal _totalQty;
private decimal _lastCash;
private int _orderCount;
private bool _inPosition;
public decimal PriceStepPercent { get => _priceStepPercent.Value; set => _priceStepPercent.Value = value; }
public decimal TakeProfitPercent { get => _takeProfitPercent.Value; set => _takeProfitPercent.Value = value; }
public decimal IncreaseFactor { get => _increaseFactor.Value; set => _increaseFactor.Value = value; }
public int MaxOrders { get => _maxOrders.Value; set => _maxOrders.Value = value; }
public int EmaLength { get => _emaLength.Value; set => _emaLength.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public MartinNoLossExitV3Strategy()
{
_priceStepPercent = Param(nameof(PriceStepPercent), 2.5m);
_takeProfitPercent = Param(nameof(TakeProfitPercent), 2.5m);
_increaseFactor = Param(nameof(IncreaseFactor), 1.10m);
_maxOrders = Param(nameof(MaxOrders), 8);
_emaLength = Param(nameof(EmaLength), 50);
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(15).TimeFrame());
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_ema = null;
_entryPrice = 0m;
_totalCost = 0m;
_totalQty = 0m;
_lastCash = 0m;
_orderCount = 0;
_inPosition = false;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_entryPrice = 0m;
_totalCost = 0m;
_totalQty = 0m;
_lastCash = 0m;
_orderCount = 0;
_inPosition = false;
_ema = new ExponentialMovingAverage { Length = EmaLength };
var subscription = SubscribeCandles(CandleType);
subscription.Bind(_ema, ProcessCandle).Start();
}
private void ProcessCandle(ICandleMessage candle, decimal ema)
{
if (candle.State != CandleStates.Finished)
return;
if (!_ema.IsFormed)
return;
var initialCash = 100m;
if (_inPosition)
{
var avgPrice = _totalQty > 0m ? _totalCost / _totalQty : 0m;
var takeProfitPrice = avgPrice * (1 + TakeProfitPercent / 100m);
if (candle.HighPrice >= takeProfitPrice && Position > 0)
{
SellMarket();
_inPosition = false;
_entryPrice = 0m;
_totalCost = 0m;
_totalQty = 0m;
_lastCash = 0m;
_orderCount = 0;
return;
}
var nextEntryPrice = _entryPrice * (1 - PriceStepPercent / 100m * _orderCount);
if (_orderCount < MaxOrders && candle.ClosePrice <= nextEntryPrice)
{
BuyMarket();
var newCash = _lastCash * IncreaseFactor;
_totalCost += newCash;
_totalQty += newCash / candle.ClosePrice;
_lastCash = newCash;
_orderCount++;
}
}
else
{
if (candle.ClosePrice > ema)
{
BuyMarket();
_entryPrice = candle.ClosePrice;
_totalCost = initialCash;
_totalQty = initialCash / candle.ClosePrice;
_lastCash = initialCash;
_orderCount = 1;
_inPosition = true;
}
}
}
}
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 martin_no_loss_exit_v3_strategy(Strategy):
def __init__(self):
super(martin_no_loss_exit_v3_strategy, self).__init__()
self._price_step_percent = self.Param("PriceStepPercent", 2.5) \
.SetDisplay("Price Step %", "Step percent for martingale", "General")
self._take_profit_percent = self.Param("TakeProfitPercent", 2.5) \
.SetDisplay("Take Profit %", "Take profit percent", "General")
self._increase_factor = self.Param("IncreaseFactor", 1.10) \
.SetDisplay("Increase Factor", "Martingale increase factor", "General")
self._max_orders = self.Param("MaxOrders", 8) \
.SetDisplay("Max Orders", "Maximum martingale orders", "General")
self._ema_length = self.Param("EmaLength", 50) \
.SetDisplay("EMA Length", "EMA trend filter", "General")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(15))) \
.SetDisplay("Candle Type", "Type of candles", "General")
self._entry_price = 0.0
self._total_cost = 0.0
self._total_qty = 0.0
self._last_cash = 0.0
self._order_count = 0
self._in_position = False
@property
def candle_type(self):
return self._candle_type.Value
@candle_type.setter
def candle_type(self, value):
self._candle_type.Value = value
def OnReseted(self):
super(martin_no_loss_exit_v3_strategy, self).OnReseted()
self._entry_price = 0.0
self._total_cost = 0.0
self._total_qty = 0.0
self._last_cash = 0.0
self._order_count = 0
self._in_position = False
def OnStarted2(self, time):
super(martin_no_loss_exit_v3_strategy, self).OnStarted2(time)
self._entry_price = 0.0
self._total_cost = 0.0
self._total_qty = 0.0
self._last_cash = 0.0
self._order_count = 0
self._in_position = False
self._ema = ExponentialMovingAverage()
self._ema.Length = self._ema_length.Value
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(self._ema, self.OnProcess).Start()
def OnProcess(self, candle, ema):
if candle.State != CandleStates.Finished:
return
if not self._ema.IsFormed:
return
ev = float(ema)
close = float(candle.ClosePrice)
high = float(candle.HighPrice)
initial_cash = 100.0
if self._in_position:
avg_price = self._total_cost / self._total_qty if self._total_qty > 0.0 else 0.0
tp_pct = float(self._take_profit_percent.Value) / 100.0
take_profit_price = avg_price * (1.0 + tp_pct)
if high >= take_profit_price and self.Position > 0:
self.SellMarket()
self._in_position = False
self._entry_price = 0.0
self._total_cost = 0.0
self._total_qty = 0.0
self._last_cash = 0.0
self._order_count = 0
return
step_pct = float(self._price_step_percent.Value) / 100.0
next_entry_price = self._entry_price * (1.0 - step_pct * self._order_count)
max_orders = self._max_orders.Value
inc_factor = float(self._increase_factor.Value)
if self._order_count < max_orders and close <= next_entry_price:
self.BuyMarket()
new_cash = self._last_cash * inc_factor
self._total_cost += new_cash
if close > 0.0:
self._total_qty += new_cash / close
self._last_cash = new_cash
self._order_count += 1
else:
if close > ev:
self.BuyMarket()
self._entry_price = close
self._total_cost = initial_cash
self._total_qty = initial_cash / close if close > 0.0 else 0.0
self._last_cash = initial_cash
self._order_count = 1
self._in_position = True
def CreateClone(self):
return martin_no_loss_exit_v3_strategy()