Esta estrategia alterna la dirección de posición después de cada operación, imitando el juguete "Nevalyashka" que cambia de lado. Utiliza un enfoque martingala: si una operación se cierra con pérdida, las distancias de stop-loss y take-profit para la siguiente operación se multiplican por un coeficiente. Después de una operación rentable, las distancias vuelven a sus valores base y la estrategia puede opcionalmente detener el trading.
La dirección inicial es corta. Cada vez que se cierra una posición, se abre la nueva posición en dirección opuesta con el volumen preconfigurado.
Detalles
Criterios de entrada:
La primera operación vende a mercado.
Las operaciones siguientes siempre entran en la dirección opuesta a la última operación cerrada.
Largo/Corto: Ambos.
Criterios de salida:
La posición se cierra cuando el precio alcanza la distancia de take-profit o stop-loss desde la entrada.
Stops: Sí, stop-loss y take-profit fijos en puntos. Las distancias aumentan por el coeficiente martingala tras pérdidas.
Valores predeterminados:
StopLossPoints = 150
TakeProfitPoints = 50
OrderVolume = 0.1
MartingaleCoeff = 1.5
StopAfterProfit = false
Filtros:
Categoría: Reversión / Martingala
Dirección: Ambos
Indicadores: Ninguno
Stops: Sí
Complejidad: Simple
Marco temporal: Cualquiera
Estacionalidad: No
Redes neuronales: No
Divergencia: No
Nivel de riesgo: Alto
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()