Estrategia 2Mars OKX
Esta estrategia combina un cruce de medias móviles con un filtro SuperTrend. Las Bollinger Bands proporcionan objetivos de beneficio mientras que un stop loss basado en ATR limita el riesgo.
Reglas
- Largo: La EMA de señal cruza por encima de la EMA base y el precio está por encima del SuperTrend.
- Corto: La EMA de señal cruza por debajo de la EMA base y el precio está por debajo del SuperTrend.
- Salida: Toma de ganancias en la banda superior o inferior de Bollinger, o stop loss en ATR multiplicado por un factor.
Indicadores
- EMA
- SuperTrend
- Bollinger Bands
- Average True Range
namespace StockSharp.Samples.Strategies;
using System;
using System.Collections.Generic;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
/// <summary>
/// 2Mars OKX Strategy.
/// Uses dual EMA crossover confirmed by SuperTrend.
/// Exits at BB bands or ATR-based stop loss.
/// </summary>
public class TwoMarsOkxStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _basisLength;
private readonly StrategyParam<int> _signalLength;
private readonly StrategyParam<int> _supertrendPeriod;
private readonly StrategyParam<decimal> _supertrendMultiplier;
private readonly StrategyParam<int> _bbLength;
private readonly StrategyParam<decimal> _bbWidth;
private readonly StrategyParam<int> _cooldownBars;
private ExponentialMovingAverage _basisMa;
private ExponentialMovingAverage _signalMa;
private SuperTrend _supertrend;
private BollingerBands _bb;
private decimal _prevBasis;
private decimal _prevSignal;
private bool _hasPrev;
private decimal _entryPrice;
private int _cooldownRemaining;
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public int BasisLength
{
get => _basisLength.Value;
set => _basisLength.Value = value;
}
public int SignalLength
{
get => _signalLength.Value;
set => _signalLength.Value = value;
}
public int SupertrendPeriod
{
get => _supertrendPeriod.Value;
set => _supertrendPeriod.Value = value;
}
public decimal SupertrendMultiplier
{
get => _supertrendMultiplier.Value;
set => _supertrendMultiplier.Value = value;
}
public int BbLength
{
get => _bbLength.Value;
set => _bbLength.Value = value;
}
public decimal BbWidth
{
get => _bbWidth.Value;
set => _bbWidth.Value = value;
}
public int CooldownBars
{
get => _cooldownBars.Value;
set => _cooldownBars.Value = value;
}
public TwoMarsOkxStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(30).TimeFrame())
.SetDisplay("Candle Type", "Type of candles to use", "General");
_basisLength = Param(nameof(BasisLength), 30)
.SetGreaterThanZero()
.SetDisplay("Basis MA Length", "Basis EMA period", "MA");
_signalLength = Param(nameof(SignalLength), 20)
.SetGreaterThanZero()
.SetDisplay("Signal MA Length", "Signal EMA period", "MA");
_supertrendPeriod = Param(nameof(SupertrendPeriod), 20)
.SetGreaterThanZero()
.SetDisplay("SuperTrend Period", "SuperTrend ATR period", "Trend");
_supertrendMultiplier = Param(nameof(SupertrendMultiplier), 4m)
.SetDisplay("SuperTrend Multiplier", "SuperTrend ATR multiplier", "Trend");
_bbLength = Param(nameof(BbLength), 30)
.SetGreaterThanZero()
.SetDisplay("BB Length", "Bollinger Bands period", "BB");
_bbWidth = Param(nameof(BbWidth), 3m)
.SetDisplay("BB Width", "Bollinger Bands width", "BB");
_cooldownBars = Param(nameof(CooldownBars), 10)
.SetDisplay("Cooldown Bars", "Bars between trades", "Risk");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
=> [(Security, CandleType)];
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_basisMa = null;
_signalMa = null;
_supertrend = null;
_bb = null;
_prevBasis = 0;
_prevSignal = 0;
_hasPrev = false;
_entryPrice = 0;
_cooldownRemaining = 0;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_basisMa = new ExponentialMovingAverage { Length = BasisLength };
_signalMa = new ExponentialMovingAverage { Length = SignalLength };
_supertrend = new SuperTrend { Length = SupertrendPeriod, Multiplier = SupertrendMultiplier };
_bb = new BollingerBands { Length = BbLength, Width = BbWidth };
var subscription = SubscribeCandles(CandleType);
subscription
.BindEx(_basisMa, _signalMa, _supertrend, _bb, OnProcess)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, _basisMa);
DrawIndicator(area, _signalMa);
DrawIndicator(area, _bb);
DrawOwnTrades(area);
}
}
private void OnProcess(ICandleMessage candle, IIndicatorValue basisVal, IIndicatorValue signalVal, IIndicatorValue stVal, IIndicatorValue bbVal)
{
if (candle.State != CandleStates.Finished)
return;
if (!_basisMa.IsFormed || !_signalMa.IsFormed || !_supertrend.IsFormed || !_bb.IsFormed)
return;
if (basisVal.IsEmpty || signalVal.IsEmpty || stVal.IsEmpty || bbVal.IsEmpty)
return;
var basis = basisVal.ToDecimal();
var signal = signalVal.ToDecimal();
var stTyped = (SuperTrendIndicatorValue)stVal;
var uptrend = stTyped.IsUpTrend;
var bb = (BollingerBandsValue)bbVal;
if (bb.UpBand is not decimal upper || bb.LowBand is not decimal lower)
return;
if (!IsFormedAndOnlineAndAllowTrading())
{
_prevBasis = basis;
_prevSignal = signal;
_hasPrev = true;
return;
}
if (!_hasPrev)
{
_prevBasis = basis;
_prevSignal = signal;
_hasPrev = true;
return;
}
if (_cooldownRemaining > 0)
{
_cooldownRemaining--;
_prevBasis = basis;
_prevSignal = signal;
return;
}
var crossUp = _prevSignal < _prevBasis && signal >= basis;
var crossDown = _prevSignal > _prevBasis && signal <= basis;
// Entry long: signal crosses above basis + uptrend
if (crossUp && uptrend && Position <= 0)
{
if (Position < 0)
BuyMarket(Math.Abs(Position));
BuyMarket(Volume);
_entryPrice = candle.ClosePrice;
_cooldownRemaining = CooldownBars;
}
// Entry short: signal crosses below basis + downtrend
else if (crossDown && !uptrend && Position >= 0)
{
if (Position > 0)
SellMarket(Math.Abs(Position));
SellMarket(Volume);
_entryPrice = candle.ClosePrice;
_cooldownRemaining = CooldownBars;
}
// Exit long at upper BB
else if (Position > 0 && candle.ClosePrice >= upper)
{
SellMarket(Math.Abs(Position));
_cooldownRemaining = CooldownBars;
}
// Exit short at lower BB
else if (Position < 0 && candle.ClosePrice <= lower)
{
BuyMarket(Math.Abs(Position));
_cooldownRemaining = CooldownBars;
}
_prevBasis = basis;
_prevSignal = signal;
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
from System import TimeSpan, Math
from StockSharp.Messages import DataType, CandleStates
from StockSharp.Algo.Indicators import ExponentialMovingAverage, SuperTrend, BollingerBands, IndicatorHelper
from StockSharp.Algo.Strategies import Strategy
class two_mars_okx_strategy(Strategy):
"""2Mars OKX Strategy."""
def __init__(self):
super(two_mars_okx_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(30))) \
.SetDisplay("Candle Type", "Type of candles to use", "General")
self._basis_length = self.Param("BasisLength", 30) \
.SetDisplay("Basis MA Length", "Basis EMA period", "MA")
self._signal_length = self.Param("SignalLength", 20) \
.SetDisplay("Signal MA Length", "Signal EMA period", "MA")
self._supertrend_period = self.Param("SupertrendPeriod", 20) \
.SetDisplay("SuperTrend Period", "SuperTrend ATR period", "Trend")
self._supertrend_multiplier = self.Param("SupertrendMultiplier", 4.0) \
.SetDisplay("SuperTrend Multiplier", "SuperTrend ATR multiplier", "Trend")
self._bb_length = self.Param("BbLength", 30) \
.SetDisplay("BB Length", "Bollinger Bands period", "BB")
self._bb_width = self.Param("BbWidth", 3.0) \
.SetDisplay("BB Width", "Bollinger Bands width", "BB")
self._cooldown_bars = self.Param("CooldownBars", 10) \
.SetDisplay("Cooldown Bars", "Bars between trades", "Risk")
self._basis_ma = None
self._signal_ma = None
self._supertrend = None
self._bb = None
self._prev_basis = 0.0
self._prev_signal = 0.0
self._has_prev = False
self._entry_price = 0.0
self._cooldown_remaining = 0
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(two_mars_okx_strategy, self).OnReseted()
self._basis_ma = None
self._signal_ma = None
self._supertrend = None
self._bb = None
self._prev_basis = 0.0
self._prev_signal = 0.0
self._has_prev = False
self._entry_price = 0.0
self._cooldown_remaining = 0
def OnStarted2(self, time):
super(two_mars_okx_strategy, self).OnStarted2(time)
self._basis_ma = ExponentialMovingAverage()
self._basis_ma.Length = int(self._basis_length.Value)
self._signal_ma = ExponentialMovingAverage()
self._signal_ma.Length = int(self._signal_length.Value)
self._supertrend = SuperTrend()
self._supertrend.Length = int(self._supertrend_period.Value)
self._supertrend.Multiplier = float(self._supertrend_multiplier.Value)
self._bb = BollingerBands()
self._bb.Length = int(self._bb_length.Value)
self._bb.Width = float(self._bb_width.Value)
subscription = self.SubscribeCandles(self.candle_type)
subscription.BindEx(self._basis_ma, self._signal_ma, self._supertrend, self._bb, self._on_process).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, self._basis_ma)
self.DrawIndicator(area, self._signal_ma)
self.DrawIndicator(area, self._bb)
self.DrawOwnTrades(area)
def _on_process(self, candle, basis_val, signal_val, st_val, bb_val):
if candle.State != CandleStates.Finished:
return
if not self._basis_ma.IsFormed or not self._signal_ma.IsFormed or not self._supertrend.IsFormed or not self._bb.IsFormed:
return
if basis_val.IsEmpty or signal_val.IsEmpty or st_val.IsEmpty or bb_val.IsEmpty:
return
basis = float(IndicatorHelper.ToDecimal(basis_val))
signal = float(IndicatorHelper.ToDecimal(signal_val))
uptrend = st_val.IsUpTrend
if bb_val.UpBand is None or bb_val.LowBand is None:
return
upper = float(bb_val.UpBand)
lower = float(bb_val.LowBand)
if not self.IsFormedAndOnlineAndAllowTrading():
self._prev_basis = basis
self._prev_signal = signal
self._has_prev = True
return
if not self._has_prev:
self._prev_basis = basis
self._prev_signal = signal
self._has_prev = True
return
if self._cooldown_remaining > 0:
self._cooldown_remaining -= 1
self._prev_basis = basis
self._prev_signal = signal
return
cooldown = int(self._cooldown_bars.Value)
cross_up = self._prev_signal < self._prev_basis and signal >= basis
cross_down = self._prev_signal > self._prev_basis and signal <= basis
if cross_up and uptrend and self.Position <= 0:
if self.Position < 0:
self.BuyMarket(Math.Abs(self.Position))
self.BuyMarket(self.Volume)
self._entry_price = float(candle.ClosePrice)
self._cooldown_remaining = cooldown
elif cross_down and not uptrend and self.Position >= 0:
if self.Position > 0:
self.SellMarket(Math.Abs(self.Position))
self.SellMarket(self.Volume)
self._entry_price = float(candle.ClosePrice)
self._cooldown_remaining = cooldown
elif self.Position > 0 and float(candle.ClosePrice) >= upper:
self.SellMarket(Math.Abs(self.Position))
self._cooldown_remaining = cooldown
elif self.Position < 0 and float(candle.ClosePrice) <= lower:
self.BuyMarket(Math.Abs(self.Position))
self._cooldown_remaining = cooldown
self._prev_basis = basis
self._prev_signal = signal
def CreateClone(self):
return two_mars_okx_strategy()