Эта стратегия чередует направление позиции после каждой сделки, подобно игрушке "Неваляшка". При закрытии сделки с убытком дистанции стоп-лосса и тейк-профита для следующей сделки умножаются на коэффициент мартингейла. После прибыльной сделки дистанции возвращаются к базовым значениям, стратегия может опционально остановиться.
Начальное направление — короткая позиция. После закрытия позиции новая позиция открывается в противоположную сторону с заданным объёмом.
Детали
Критерии входа:
Первая сделка продаёт по рынку.
Далее вход всегда в сторону, противоположную предыдущей закрытой сделке.
Длинные/короткие: обе стороны.
Критерии выхода:
Позиция закрывается при достижении ценой расстояния тейк-профита или стоп-лосса от цены входа.
Стопы: да, фиксированные в пунктах. После убыточных сделок дистанции увеличиваются на коэффициент.
Значения по умолчанию:
StopLossPoints = 150
TakeProfitPoints = 50
OrderVolume = 0.1
MartingaleCoeff = 1.5
StopAfterProfit = false
Фильтры:
Категория: Разворот / Мартингейл
Направление: оба
Индикаторы: нет
Стопы: да
Сложность: простая
Таймфрейм: любой
Сезонность: нет
Нейросети: нет
Дивергенция: нет
Уровень риска: высокий
using System;
using System.Collections.Generic;
using Ecng.Common;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Alternating martingale strategy.
/// Opens opposite direction after each trade and increases
/// stop loss and take profit distances after losses.
/// </summary>
public class NevalyashkaStopupStrategy : Strategy
{
private readonly StrategyParam<decimal> _stopLoss;
private readonly StrategyParam<decimal> _takeProfit;
private readonly StrategyParam<decimal> _martingaleCoeff;
private readonly StrategyParam<DataType> _candleType;
private decimal _entryPrice;
private decimal _currentStopLoss;
private decimal _currentTakeProfit;
private bool _nextIsBuy;
public decimal StopLoss { get => _stopLoss.Value; set => _stopLoss.Value = value; }
public decimal TakeProfit { get => _takeProfit.Value; set => _takeProfit.Value = value; }
public decimal MartingaleCoeff { get => _martingaleCoeff.Value; set => _martingaleCoeff.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public NevalyashkaStopupStrategy()
{
_stopLoss = Param(nameof(StopLoss), 500m)
.SetGreaterThanZero()
.SetDisplay("Stop Loss", "Stop loss in price units", "General");
_takeProfit = Param(nameof(TakeProfit), 200m)
.SetGreaterThanZero()
.SetDisplay("Take Profit", "Take profit in price units", "General");
_martingaleCoeff = Param(nameof(MartingaleCoeff), 1.5m)
.SetGreaterThanZero()
.SetDisplay("Martingale Coeff", "Multiplier applied after loss", "Risk");
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Type of candles", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_entryPrice = 0;
_currentStopLoss = 0;
_currentTakeProfit = 0;
_nextIsBuy = true;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_currentStopLoss = StopLoss;
_currentTakeProfit = TakeProfit;
_nextIsBuy = true;
_entryPrice = 0;
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 closePrice = candle.ClosePrice;
// Open first position
if (Position == 0)
{
if (_nextIsBuy)
BuyMarket();
else
SellMarket();
_entryPrice = closePrice;
return;
}
// Check SL/TP for long
if (Position > 0)
{
if (candle.LowPrice <= _entryPrice - _currentStopLoss)
{
SellMarket();
OnTradeClosed(false);
}
else if (candle.HighPrice >= _entryPrice + _currentTakeProfit)
{
SellMarket();
OnTradeClosed(true);
}
}
// Check SL/TP for short
else if (Position < 0)
{
if (candle.HighPrice >= _entryPrice + _currentStopLoss)
{
BuyMarket();
OnTradeClosed(false);
}
else if (candle.LowPrice <= _entryPrice - _currentTakeProfit)
{
BuyMarket();
OnTradeClosed(true);
}
}
}
private void OnTradeClosed(bool wasProfit)
{
if (wasProfit)
{
_currentStopLoss = StopLoss;
_currentTakeProfit = TakeProfit;
}
else
{
_currentStopLoss *= MartingaleCoeff;
_currentTakeProfit *= MartingaleCoeff;
}
_nextIsBuy = !_nextIsBuy;
}
}
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.Strategies import Strategy
class nevalyashka_stopup_strategy(Strategy):
def __init__(self):
super(nevalyashka_stopup_strategy, self).__init__()
self._stop_loss = self.Param("StopLoss", 500.0).SetGreaterThanZero().SetDisplay("Stop Loss", "Stop loss in price units", "General")
self._take_profit = self.Param("TakeProfit", 200.0).SetGreaterThanZero().SetDisplay("Take Profit", "Take profit in price units", "General")
self._martingale_coeff = self.Param("MartingaleCoeff", 1.5).SetGreaterThanZero().SetDisplay("Martingale Coeff", "Multiplier applied after loss", "Risk")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))).SetDisplay("Candle Type", "Type of candles", "General")
@property
def CandleType(self): return self._candle_type.Value
@CandleType.setter
def CandleType(self, value): self._candle_type.Value = value
def OnReseted(self):
super(nevalyashka_stopup_strategy, self).OnReseted()
self._entry_price = 0
self._current_sl = 0
self._current_tp = 0
self._next_is_buy = True
def OnStarted2(self, time):
super(nevalyashka_stopup_strategy, self).OnStarted2(time)
self._current_sl = self._stop_loss.Value
self._current_tp = self._take_profit.Value
self._next_is_buy = True
self._entry_price = 0
sub = self.SubscribeCandles(self.CandleType)
sub.Bind(self.OnProcess).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, sub)
self.DrawOwnTrades(area)
def OnProcess(self, candle):
if candle.State != CandleStates.Finished:
return
close = candle.ClosePrice
if self.Position == 0:
if self._next_is_buy:
self.BuyMarket()
else:
self.SellMarket()
self._entry_price = close
return
if self.Position > 0:
if candle.LowPrice <= self._entry_price - self._current_sl:
self.SellMarket()
self._on_trade_closed(False)
elif candle.HighPrice >= self._entry_price + self._current_tp:
self.SellMarket()
self._on_trade_closed(True)
elif self.Position < 0:
if candle.HighPrice >= self._entry_price + self._current_sl:
self.BuyMarket()
self._on_trade_closed(False)
elif candle.LowPrice <= self._entry_price - self._current_tp:
self.BuyMarket()
self._on_trade_closed(True)
def _on_trade_closed(self, was_profit):
if was_profit:
self._current_sl = self._stop_loss.Value
self._current_tp = self._take_profit.Value
else:
self._current_sl *= self._martingale_coeff.Value
self._current_tp *= self._martingale_coeff.Value
self._next_is_buy = not self._next_is_buy
def CreateClone(self):
return nevalyashka_stopup_strategy()