using System;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// GLFX strategy: RSI + SMA confirmation for entry.
/// Requires consecutive confirmations before trading.
/// </summary>
public class GlfxStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _rsiPeriod;
private readonly StrategyParam<decimal> _rsiUpper;
private readonly StrategyParam<decimal> _rsiLower;
private readonly StrategyParam<int> _maPeriod;
private readonly StrategyParam<int> _signalsRepeat;
private decimal _prevRsi;
private decimal _prevMa;
private int _buyCount;
private int _sellCount;
private decimal _entryPrice;
public GlfxStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(30).TimeFrame())
.SetDisplay("Candle Type", "Timeframe.", "General");
_rsiPeriod = Param(nameof(RsiPeriod), 14)
.SetDisplay("RSI Period", "RSI period.", "Indicators");
_rsiUpper = Param(nameof(RsiUpper), 65m)
.SetDisplay("RSI Upper", "Overbought level.", "Indicators");
_rsiLower = Param(nameof(RsiLower), 35m)
.SetDisplay("RSI Lower", "Oversold level.", "Indicators");
_maPeriod = Param(nameof(MaPeriod), 60)
.SetDisplay("MA Period", "SMA period.", "Indicators");
_signalsRepeat = Param(nameof(SignalsRepeat), 2)
.SetDisplay("Signals Repeat", "Consecutive confirmations needed.", "Signals");
}
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public int RsiPeriod
{
get => _rsiPeriod.Value;
set => _rsiPeriod.Value = value;
}
public decimal RsiUpper
{
get => _rsiUpper.Value;
set => _rsiUpper.Value = value;
}
public decimal RsiLower
{
get => _rsiLower.Value;
set => _rsiLower.Value = value;
}
public int MaPeriod
{
get => _maPeriod.Value;
set => _maPeriod.Value = value;
}
public int SignalsRepeat
{
get => _signalsRepeat.Value;
set => _signalsRepeat.Value = value;
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevRsi = 0;
_prevMa = 0;
_buyCount = 0;
_sellCount = 0;
_entryPrice = 0;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var rsi = new RelativeStrengthIndex { Length = RsiPeriod };
var ma = new SimpleMovingAverage { Length = MaPeriod };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(rsi, ma, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, ma);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal rsiVal, decimal maVal)
{
if (candle.State != CandleStates.Finished)
return;
if (_prevRsi == 0 || _prevMa == 0)
{
_prevRsi = rsiVal;
_prevMa = maVal;
return;
}
var close = candle.ClosePrice;
// RSI signal: rising and below upper = bullish, falling and above lower = bearish
var rsiSignal = 0;
if (rsiVal > _prevRsi && rsiVal < RsiUpper)
rsiSignal = 1;
else if (rsiVal < _prevRsi && rsiVal > RsiLower)
rsiSignal = -1;
// MA signal: price above rising MA = bullish, below falling MA = bearish
var maSignal = 0;
if (maVal > _prevMa && close > maVal)
maSignal = 1;
else if (maVal < _prevMa && close < maVal)
maSignal = -1;
// Both signals must agree
if (rsiSignal > 0 && maSignal > 0)
{
_buyCount++;
_sellCount = 0;
}
else if (rsiSignal < 0 && maSignal < 0)
{
_sellCount++;
_buyCount = 0;
}
else
{
_buyCount = 0;
_sellCount = 0;
}
// Exit on opposite signal
if (Position > 0 && _sellCount >= SignalsRepeat)
{
SellMarket();
_entryPrice = 0;
_buyCount = 0;
_sellCount = 0;
}
else if (Position < 0 && _buyCount >= SignalsRepeat)
{
BuyMarket();
_entryPrice = 0;
_buyCount = 0;
_sellCount = 0;
}
// Entry after required confirmations
if (Position == 0)
{
if (_buyCount >= SignalsRepeat)
{
_entryPrice = close;
BuyMarket();
_buyCount = 0;
_sellCount = 0;
}
else if (_sellCount >= SignalsRepeat)
{
_entryPrice = close;
SellMarket();
_buyCount = 0;
_sellCount = 0;
}
}
_prevRsi = rsiVal;
_prevMa = maVal;
}
}
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
from StockSharp.Algo.Indicators import RelativeStrengthIndex, SimpleMovingAverage
class glfx_strategy(Strategy):
def __init__(self):
super(glfx_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(30))) \
.SetDisplay("Candle Type", "Timeframe", "General")
self._rsi_period = self.Param("RsiPeriod", 14) \
.SetDisplay("RSI Period", "RSI period", "Indicators")
self._rsi_upper = self.Param("RsiUpper", 65.0) \
.SetDisplay("RSI Upper", "Overbought level", "Indicators")
self._rsi_lower = self.Param("RsiLower", 35.0) \
.SetDisplay("RSI Lower", "Oversold level", "Indicators")
self._ma_period = self.Param("MaPeriod", 60) \
.SetDisplay("MA Period", "SMA period", "Indicators")
self._signals_repeat = self.Param("SignalsRepeat", 2) \
.SetDisplay("Signals Repeat", "Consecutive confirmations needed", "Signals")
self._prev_rsi = 0.0
self._prev_ma = 0.0
self._buy_count = 0
self._sell_count = 0
self._entry_price = 0.0
@property
def CandleType(self):
return self._candle_type.Value
@property
def RsiPeriod(self):
return self._rsi_period.Value
@property
def RsiUpper(self):
return self._rsi_upper.Value
@property
def RsiLower(self):
return self._rsi_lower.Value
@property
def MaPeriod(self):
return self._ma_period.Value
@property
def SignalsRepeat(self):
return self._signals_repeat.Value
def OnStarted2(self, time):
super(glfx_strategy, self).OnStarted2(time)
self._prev_rsi = 0.0
self._prev_ma = 0.0
self._buy_count = 0
self._sell_count = 0
self._entry_price = 0.0
self._rsi = RelativeStrengthIndex()
self._rsi.Length = self.RsiPeriod
self._ma = SimpleMovingAverage()
self._ma.Length = self.MaPeriod
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(self._rsi, self._ma, self.ProcessCandle).Start()
def ProcessCandle(self, candle, rsi_val, ma_val):
if candle.State != CandleStates.Finished:
return
rv = float(rsi_val)
mv = float(ma_val)
if self._prev_rsi == 0 or self._prev_ma == 0:
self._prev_rsi = rv
self._prev_ma = mv
return
close = float(candle.ClosePrice)
rsi_upper = float(self.RsiUpper)
rsi_lower = float(self.RsiLower)
# RSI signal
rsi_signal = 0
if rv > self._prev_rsi and rv < rsi_upper:
rsi_signal = 1
elif rv < self._prev_rsi and rv > rsi_lower:
rsi_signal = -1
# MA signal
ma_signal = 0
if mv > self._prev_ma and close > mv:
ma_signal = 1
elif mv < self._prev_ma and close < mv:
ma_signal = -1
# Both signals must agree
if rsi_signal > 0 and ma_signal > 0:
self._buy_count += 1
self._sell_count = 0
elif rsi_signal < 0 and ma_signal < 0:
self._sell_count += 1
self._buy_count = 0
else:
self._buy_count = 0
self._sell_count = 0
signals_needed = self.SignalsRepeat
# Exit on opposite signal
if self.Position > 0 and self._sell_count >= signals_needed:
self.SellMarket()
self._entry_price = 0.0
self._buy_count = 0
self._sell_count = 0
elif self.Position < 0 and self._buy_count >= signals_needed:
self.BuyMarket()
self._entry_price = 0.0
self._buy_count = 0
self._sell_count = 0
# Entry after required confirmations
if self.Position == 0:
if self._buy_count >= signals_needed:
self._entry_price = close
self.BuyMarket()
self._buy_count = 0
self._sell_count = 0
elif self._sell_count >= signals_needed:
self._entry_price = close
self.SellMarket()
self._buy_count = 0
self._sell_count = 0
self._prev_rsi = rv
self._prev_ma = mv
def OnReseted(self):
super(glfx_strategy, self).OnReseted()
self._prev_rsi = 0.0
self._prev_ma = 0.0
self._buy_count = 0
self._sell_count = 0
self._entry_price = 0.0
def CreateClone(self):
return glfx_strategy()