Estrategia MESA Stochastic Multi Length
Esta estrategia utiliza cuatro osciladores MESA Stochastic con diferentes longitudes de retrospección. Se abre una posición larga cuando los cuatro osciladores están por encima de su disparador de media móvil. Se abre una posición corta cuando los cuatro osciladores caen por debajo de sus disparadores.
Parámetros
Length1– retrospección del primer oscilador.Length2– retrospección del segundo oscilador.Length3– retrospección del tercer oscilador.Length4– retrospección del cuarto oscilador.TriggerLength– período de suavizado para las medias móviles disparadoras.CandleType– marco temporal de las velas.
using System;
using System.Linq;
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;
public class MesaStochasticMultiLengthStrategy : Strategy
{
private readonly StrategyParam<int> _length1;
private readonly StrategyParam<int> _length2;
private readonly StrategyParam<decimal> _upperLevel;
private readonly StrategyParam<decimal> _lowerLevel;
private readonly StrategyParam<int> _signalCooldownBars;
private readonly StrategyParam<DataType> _candleType;
private readonly List<decimal> _prices = new();
private decimal _prevStoch1;
private decimal _prevStoch2;
private int _barsFromSignal;
public int Length1 { get => _length1.Value; set => _length1.Value = value; }
public int Length2 { get => _length2.Value; set => _length2.Value = value; }
public decimal UpperLevel { get => _upperLevel.Value; set => _upperLevel.Value = value; }
public decimal LowerLevel { get => _lowerLevel.Value; set => _lowerLevel.Value = value; }
public int SignalCooldownBars { get => _signalCooldownBars.Value; set => _signalCooldownBars.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public MesaStochasticMultiLengthStrategy()
{
_length1 = Param(nameof(Length1), 50)
.SetGreaterThanZero()
.SetDisplay("Length 1", "Primary stochastic length", "General");
_length2 = Param(nameof(Length2), 14)
.SetGreaterThanZero()
.SetDisplay("Length 2", "Secondary stochastic length", "General");
_upperLevel = Param(nameof(UpperLevel), 0.60m)
.SetDisplay("Upper Level", "Upper signal level", "General");
_lowerLevel = Param(nameof(LowerLevel), 0.40m)
.SetDisplay("Lower Level", "Lower signal level", "General");
_signalCooldownBars = Param(nameof(SignalCooldownBars), 10)
.SetGreaterThanZero()
.SetDisplay("Signal Cooldown Bars", "Minimum bars between entries", "General");
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(15).TimeFrame())
.SetDisplay("Candle Type", "Candles timeframe", "General");
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prices.Clear();
_prevStoch1 = 0.5m;
_prevStoch2 = 0.5m;
_barsFromSignal = 0;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
StartProtection(null, null);
_prices.Clear();
_prevStoch1 = 0.5m;
_prevStoch2 = 0.5m;
_barsFromSignal = SignalCooldownBars;
var subscription = SubscribeCandles(CandleType);
subscription.Bind(ProcessCandle).Start();
}
private void ProcessCandle(ICandleMessage candle)
{
if (candle.State != CandleStates.Finished)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
var price = (candle.HighPrice + candle.LowPrice) / 2m;
_prices.Add(price);
var maxLen = Math.Max(Length1, Length2);
if (_prices.Count > maxLen + 10)
_prices.RemoveAt(0);
if (_prices.Count < maxLen)
return;
var stoch1 = CalcStochastic(_prices, Length1);
var stoch2 = CalcStochastic(_prices, Length2);
var up = stoch1 > UpperLevel && stoch2 > UpperLevel && _prevStoch1 <= UpperLevel;
var down = stoch1 < LowerLevel && stoch2 < LowerLevel && _prevStoch1 >= LowerLevel;
_barsFromSignal++;
if (_barsFromSignal >= SignalCooldownBars && up && Position <= 0)
{
BuyMarket();
_barsFromSignal = 0;
}
else if (_barsFromSignal >= SignalCooldownBars && down && Position >= 0)
{
SellMarket();
_barsFromSignal = 0;
}
_prevStoch1 = stoch1;
_prevStoch2 = stoch2;
}
private static decimal CalcStochastic(List<decimal> prices, int length)
{
var count = prices.Count;
if (count < length) return 0.5m;
var high = decimal.MinValue;
var low = decimal.MaxValue;
for (int i = count - length; i < count; i++)
{
if (prices[i] > high) high = prices[i];
if (prices[i] < low) low = prices[i];
}
if (high == low) return 0.5m;
return (prices[count - 1] - low) / (high - low);
}
}
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 mesa_stochastic_multi_length_strategy(Strategy):
def __init__(self):
super(mesa_stochastic_multi_length_strategy, self).__init__()
self._length1 = self.Param("Length1", 50) \
.SetGreaterThanZero() \
.SetDisplay("Length 1", "Primary stochastic length", "General")
self._length2 = self.Param("Length2", 14) \
.SetGreaterThanZero() \
.SetDisplay("Length 2", "Secondary stochastic length", "General")
self._upper_level = self.Param("UpperLevel", 0.60) \
.SetDisplay("Upper Level", "Upper signal level", "General")
self._lower_level = self.Param("LowerLevel", 0.40) \
.SetDisplay("Lower Level", "Lower signal level", "General")
self._signal_cooldown_bars = self.Param("SignalCooldownBars", 10) \
.SetGreaterThanZero() \
.SetDisplay("Signal Cooldown Bars", "Minimum bars between entries", "General")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(15))) \
.SetDisplay("Candle Type", "Candles timeframe", "General")
self._prices = []
self._prev_stoch1 = 0.5
self._prev_stoch2 = 0.5
self._bars_from_signal = 0
@property
def candle_type(self):
return self._candle_type.Value
@candle_type.setter
def candle_type(self, value):
self._candle_type.Value = value
def OnReseted(self):
super(mesa_stochastic_multi_length_strategy, self).OnReseted()
self._prices = []
self._prev_stoch1 = 0.5
self._prev_stoch2 = 0.5
self._bars_from_signal = 0
def OnStarted2(self, time):
super(mesa_stochastic_multi_length_strategy, self).OnStarted2(time)
self._prices = []
self._prev_stoch1 = 0.5
self._prev_stoch2 = 0.5
self._bars_from_signal = self._signal_cooldown_bars.Value
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(self.OnProcess).Start()
def _calc_stochastic(self, prices, length):
count = len(prices)
if count < length:
return 0.5
high = -999999999.0
low = 999999999.0
start = count - length
for i in range(start, count):
if prices[i] > high:
high = prices[i]
if prices[i] < low:
low = prices[i]
if high == low:
return 0.5
return (prices[count - 1] - low) / (high - low)
def OnProcess(self, candle):
if candle.State != CandleStates.Finished:
return
price = (float(candle.HighPrice) + float(candle.LowPrice)) / 2.0
self._prices.append(price)
max_len = max(self._length1.Value, self._length2.Value)
if len(self._prices) > max_len + 10:
self._prices.pop(0)
if len(self._prices) < max_len:
return
stoch1 = self._calc_stochastic(self._prices, self._length1.Value)
stoch2 = self._calc_stochastic(self._prices, self._length2.Value)
ul = float(self._upper_level.Value)
ll = float(self._lower_level.Value)
up = stoch1 > ul and stoch2 > ul and self._prev_stoch1 <= ul
down = stoch1 < ll and stoch2 < ll and self._prev_stoch1 >= ll
self._bars_from_signal += 1
cd = self._signal_cooldown_bars.Value
if self._bars_from_signal >= cd and up and self.Position <= 0:
self.BuyMarket()
self._bars_from_signal = 0
elif self._bars_from_signal >= cd and down and self.Position >= 0:
self.SellMarket()
self._bars_from_signal = 0
self._prev_stoch1 = stoch1
self._prev_stoch2 = stoch2
def CreateClone(self):
return mesa_stochastic_multi_length_strategy()