This strategy alternates position direction after each trade, mimicking the "Nevalyashka" toy that flips sides. It uses a martingale approach: if a trade closes at a loss, the stop-loss and take-profit distances for the next trade are multiplied by a coefficient. After a profitable trade, distances reset to their base values and the strategy can optionally stop trading.
Initial direction is short. Every time a position is closed, the new position is opened in the opposite direction with the preconfigured volume.
Details
Entry Criteria:
First trade sells at market.
Subsequent trades always enter in the opposite direction of the previous closed trade.
Long/Short: Both.
Exit Criteria:
Position is closed when price reaches the take-profit or stop-loss distance from entry.
Stops: Yes, fixed stop-loss and take-profit in points. Distances grow by the martingale coefficient after losses.
Default Values:
StopLossPoints = 150
TakeProfitPoints = 50
OrderVolume = 0.1
MartingaleCoeff = 1.5
StopAfterProfit = false
Filters:
Category: Reversal / Martingale
Direction: Both
Indicators: None
Stops: Yes
Complexity: Simple
Timeframe: Any
Seasonality: No
Neural networks: No
Divergence: No
Risk level: High
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()