MasterMind 3 Strategy
This strategy trades extreme reversals using four Williams %R indicators with different periods. When all indicators drop to deep oversold values, the strategy enters a long position. When all indicators rise to strong overbought values, it enters a short position.
Trading Logic
- Subscribe to candles of the selected timeframe.
- Calculate four Williams %R indicators with periods 26, 27, 29 and 30.
- Buy when all indicators are below
-99.99. - Sell when all indicators are above
-0.01. - Signals are processed only on finished candles.
The volume of the order is taken from the strategy Volume property. Existing opposite positions are closed automatically by sending a market order with the required size.
Parameters
| Name | Description | Default |
|---|---|---|
WprPeriod1 |
Length of the first Williams %R indicator | 26 |
WprPeriod2 |
Length of the second Williams %R indicator | 27 |
WprPeriod3 |
Length of the third Williams %R indicator | 29 |
WprPeriod4 |
Length of the fourth Williams %R indicator | 30 |
CandleType |
Type and timeframe of candles | 1 minute candles |
Notes
- The strategy uses high-level API with
Bindfor indicator processing. - No stop-loss or take-profit levels are included; position is reversed on opposite signals.
using System;
using System.Linq;
using System.Collections.Generic;
using Ecng.Common;
using Ecng.Collections;
using Ecng.Serialization;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Williams %R based extreme reversals.
/// Enters long when all indicators show deep oversold.
/// Enters short when all indicators show strong overbought.
/// </summary>
public class MasterMind3Strategy : Strategy
{
private readonly StrategyParam<int> _rsiPeriod1;
private readonly StrategyParam<int> _rsiPeriod2;
private readonly StrategyParam<int> _rsiPeriod3;
private readonly StrategyParam<int> _rsiPeriod4;
private readonly StrategyParam<DataType> _candleType;
private bool _wasOversold;
private bool _wasOverbought;
/// <summary>
/// Period for the first Williams %R indicator.
/// </summary>
public int RsiPeriod1
{
get => _rsiPeriod1.Value;
set => _rsiPeriod1.Value = value;
}
/// <summary>
/// Period for the second Williams %R indicator.
/// </summary>
public int RsiPeriod2
{
get => _rsiPeriod2.Value;
set => _rsiPeriod2.Value = value;
}
/// <summary>
/// Period for the third Williams %R indicator.
/// </summary>
public int RsiPeriod3
{
get => _rsiPeriod3.Value;
set => _rsiPeriod3.Value = value;
}
/// <summary>
/// Period for the fourth Williams %R indicator.
/// </summary>
public int RsiPeriod4
{
get => _rsiPeriod4.Value;
set => _rsiPeriod4.Value = value;
}
/// <summary>
/// The type of candles to use for calculations.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Initializes strategy parameters.
/// </summary>
public MasterMind3Strategy()
{
_rsiPeriod1 = Param(nameof(RsiPeriod1), 26)
.SetGreaterThanZero()
.SetDisplay("RSI Period 1", "Length of the first RSI indicator", "RSI")
.SetOptimize(10, 50, 5);
_rsiPeriod2 = Param(nameof(RsiPeriod2), 27)
.SetGreaterThanZero()
.SetDisplay("RSI Period 2", "Length of the second RSI indicator", "RSI")
.SetOptimize(10, 50, 5);
_rsiPeriod3 = Param(nameof(RsiPeriod3), 29)
.SetGreaterThanZero()
.SetDisplay("RSI Period 3", "Length of the third RSI indicator", "RSI")
.SetOptimize(10, 50, 5);
_rsiPeriod4 = Param(nameof(RsiPeriod4), 30)
.SetGreaterThanZero()
.SetDisplay("RSI Period 4", "Length of the fourth RSI indicator", "RSI")
.SetOptimize(10, 50, 5);
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(15).TimeFrame())
.SetDisplay("Candle Type", "Type of candles for the strategy", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_wasOversold = false;
_wasOverbought = false;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var rsi1 = new RelativeStrengthIndex { Length = RsiPeriod1 };
var rsi2 = new RelativeStrengthIndex { Length = RsiPeriod2 };
var rsi3 = new RelativeStrengthIndex { Length = RsiPeriod3 };
var rsi4 = new RelativeStrengthIndex { Length = RsiPeriod4 };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(rsi1, rsi2, rsi3, rsi4, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, rsi1);
DrawIndicator(area, rsi2);
DrawIndicator(area, rsi3);
DrawIndicator(area, rsi4);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal rsi1, decimal rsi2, decimal rsi3, decimal rsi4)
{
if (candle.State != CandleStates.Finished)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
var isOversold = rsi1 <= 35m && rsi2 <= 35m && rsi3 <= 35m && rsi4 <= 35m;
var isOverbought = rsi1 >= 65m && rsi2 >= 65m && rsi3 >= 65m && rsi4 >= 65m;
var isBuySignal = isOversold && !_wasOversold;
var isSellSignal = isOverbought && !_wasOverbought;
if (isBuySignal && Position <= 0)
{
BuyMarket(Volume + Math.Abs(Position));
}
else if (isSellSignal && Position >= 0)
{
SellMarket(Volume + Math.Abs(Position));
}
_wasOversold = isOversold;
_wasOverbought = isOverbought;
}
}
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, Unit, UnitTypes
from StockSharp.Algo.Indicators import RelativeStrengthIndex
from StockSharp.Algo.Strategies import Strategy
class master_mind3_strategy(Strategy):
def __init__(self):
super(master_mind3_strategy, self).__init__()
self._rsi_period1 = self.Param("RsiPeriod1", 26)
self._rsi_period2 = self.Param("RsiPeriod2", 27)
self._rsi_period3 = self.Param("RsiPeriod3", 29)
self._rsi_period4 = self.Param("RsiPeriod4", 30)
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(15)))
self._was_oversold = False
self._was_overbought = False
@property
def RsiPeriod1(self):
return self._rsi_period1.Value
@RsiPeriod1.setter
def RsiPeriod1(self, value):
self._rsi_period1.Value = value
@property
def RsiPeriod2(self):
return self._rsi_period2.Value
@RsiPeriod2.setter
def RsiPeriod2(self, value):
self._rsi_period2.Value = value
@property
def RsiPeriod3(self):
return self._rsi_period3.Value
@RsiPeriod3.setter
def RsiPeriod3(self, value):
self._rsi_period3.Value = value
@property
def RsiPeriod4(self):
return self._rsi_period4.Value
@RsiPeriod4.setter
def RsiPeriod4(self, value):
self._rsi_period4.Value = value
@property
def CandleType(self):
return self._candle_type.Value
@CandleType.setter
def CandleType(self, value):
self._candle_type.Value = value
def OnStarted2(self, time):
super(master_mind3_strategy, self).OnStarted2(time)
self._was_oversold = False
self._was_overbought = False
rsi1 = RelativeStrengthIndex()
rsi1.Length = self.RsiPeriod1
rsi2 = RelativeStrengthIndex()
rsi2.Length = self.RsiPeriod2
rsi3 = RelativeStrengthIndex()
rsi3.Length = self.RsiPeriod3
rsi4 = RelativeStrengthIndex()
rsi4.Length = self.RsiPeriod4
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(rsi1, rsi2, rsi3, rsi4, self.ProcessCandle).Start()
def ProcessCandle(self, candle, rsi1_val, rsi2_val, rsi3_val, rsi4_val):
if candle.State != CandleStates.Finished:
return
if not self.IsFormedAndOnlineAndAllowTrading():
return
r1 = float(rsi1_val)
r2 = float(rsi2_val)
r3 = float(rsi3_val)
r4 = float(rsi4_val)
is_oversold = r1 <= 35.0 and r2 <= 35.0 and r3 <= 35.0 and r4 <= 35.0
is_overbought = r1 >= 65.0 and r2 >= 65.0 and r3 >= 65.0 and r4 >= 65.0
buy_signal = is_oversold and not self._was_oversold
sell_signal = is_overbought and not self._was_overbought
if buy_signal and self.Position <= 0:
self.BuyMarket()
elif sell_signal and self.Position >= 0:
self.SellMarket()
self._was_oversold = is_oversold
self._was_overbought = is_overbought
def OnReseted(self):
super(master_mind3_strategy, self).OnReseted()
self._was_oversold = False
self._was_overbought = False
def CreateClone(self):
return master_mind3_strategy()