Estratégia MESA Stochastic Multi Length
Esta estratégia utiliza quatro osciladores MESA Stochastic com diferentes comprimentos de retrospectiva. Uma posição comprada é aberta quando todos os quatro osciladores estão acima de seu gatilho de média móvel. Uma posição vendida é aberta quando todos os quatro osciladores caem abaixo de seus gatilhos.
Parâmetros
Length1– retrospectiva do primeiro oscilador.Length2– retrospectiva do segundo oscilador.Length3– retrospectiva do terceiro oscilador.Length4– retrospectiva do quarto oscilador.TriggerLength– período de suavização para as médias móveis gatilho.CandleType– período de tempo das 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()