Esta estrategia coloca órdenes límite pareadas por encima y por debajo del precio de mercado actual. Cada operación usa una distancia de paso configurable y un dimensionamiento de posición martingala opcional para recuperar pérdidas anteriores.
Parámetros
Step – distancia en pips entre el precio de mercado y las órdenes límite pendientes.
Stop Loss – tamaño del stop protector en pips para posiciones abiertas.
Take Profit – tamaño del objetivo de ganancia en pips para posiciones abiertas.
Use Martingale – habilita el incremento de volumen tras una operación perdedora.
Loss Limit – número máximo de operaciones perdedoras consecutivas antes de restablecer el volumen.
Volume – volumen inicial de la orden.
Use MegaLot – duplica el volumen en lugar de agregar el volumen base cuando el martingala está activo.
Candle Type – tipo de datos de velas usado para el procesamiento.
Lógica de operación
Cuando no hay posición abierta ni orden activa, la estrategia coloca una orden Buy Limit por debajo del último cierre y una orden Sell Limit por encima, ambas a la distancia Step especificada.
Tras la ejecución de una orden, la orden pendiente opuesta permanece, permitiendo solo una posición activa a la vez.
La posición se cierra cuando se alcanza el nivel de stop loss o take profit.
Tras una operación perdedora, el volumen de posición puede incrementarse según la configuración del martingala.
Notas
La estrategia utiliza la API de alto nivel de StockSharp con el enfoque Bind para el manejo de datos de velas.
Todos los comentarios dentro del código están escritos en inglés para cumplir las convenciones del repositorio.
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;
/// <summary>
/// Simple martingale strategy with RSI-based entries.
/// Buys when RSI is oversold, sells when overbought.
/// </summary>
public class LimitsMartinStrategy : Strategy
{
private readonly StrategyParam<int> _rsiPeriod;
private readonly StrategyParam<decimal> _oversold;
private readonly StrategyParam<decimal> _overbought;
private readonly StrategyParam<DataType> _candleType;
public int RsiPeriod { get => _rsiPeriod.Value; set => _rsiPeriod.Value = value; }
public decimal Oversold { get => _oversold.Value; set => _oversold.Value = value; }
public decimal Overbought { get => _overbought.Value; set => _overbought.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public LimitsMartinStrategy()
{
_rsiPeriod = Param(nameof(RsiPeriod), 14)
.SetGreaterThanZero()
.SetDisplay("RSI Period", "Period for RSI", "Indicators");
_oversold = Param(nameof(Oversold), 30m)
.SetDisplay("Oversold", "RSI oversold level", "Indicators");
_overbought = Param(nameof(Overbought), 70m)
.SetDisplay("Overbought", "RSI overbought level", "Indicators");
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Type of candles", "General");
}
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var rsi = new RelativeStrengthIndex { Length = RsiPeriod };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(rsi, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, rsi);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal rsiValue)
{
if (candle.State != CandleStates.Finished)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
if (rsiValue < Oversold && Position <= 0)
BuyMarket();
else if (rsiValue > Overbought && Position >= 0)
SellMarket();
}
}
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 RelativeStrengthIndex
from StockSharp.Algo.Strategies import Strategy
class limits_martin_strategy(Strategy):
def __init__(self):
super(limits_martin_strategy, self).__init__()
self._rsi_period = self.Param("RsiPeriod", 14) \
.SetDisplay("RSI Period", "Period for RSI", "Indicators")
self._oversold = self.Param("Oversold", 30.0) \
.SetDisplay("Oversold", "RSI oversold level", "Indicators")
self._overbought = self.Param("Overbought", 70.0) \
.SetDisplay("Overbought", "RSI overbought level", "Indicators")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Type of candles", "General")
@property
def rsi_period(self):
return self._rsi_period.Value
@property
def oversold(self):
return self._oversold.Value
@property
def overbought(self):
return self._overbought.Value
@property
def candle_type(self):
return self._candle_type.Value
def OnStarted2(self, time):
super(limits_martin_strategy, self).OnStarted2(time)
rsi = RelativeStrengthIndex()
rsi.Length = self.rsi_period
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(rsi, self.process_candle).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, rsi)
self.DrawOwnTrades(area)
def process_candle(self, candle, rsi_value):
if candle.State != CandleStates.Finished:
return
rsi_value = float(rsi_value)
if rsi_value < float(self.oversold) and self.Position <= 0:
self.BuyMarket()
elif rsi_value > float(self.overbought) and self.Position >= 0:
self.SellMarket()
def CreateClone(self):
return limits_martin_strategy()