using System;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Trend-following strategy requiring strict moving average alignment
/// and rising volatility (ATR) before entering trades.
/// Exits when alignment is lost.
/// </summary>
public class TrueSort1001Strategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _fastLength;
private readonly StrategyParam<int> _midLength;
private readonly StrategyParam<int> _slowLength;
private readonly StrategyParam<int> _atrLength;
private decimal _prevFast;
private decimal _prevMid;
private decimal _prevSlow;
private decimal _prevAtr;
private decimal _entryPrice;
public TrueSort1001Strategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame())
.SetDisplay("Candle Type", "Timeframe.", "General");
_fastLength = Param(nameof(FastLength), 10)
.SetDisplay("Fast SMA", "Fast SMA period.", "Indicators");
_midLength = Param(nameof(MidLength), 50)
.SetDisplay("Mid SMA", "Medium SMA period.", "Indicators");
_slowLength = Param(nameof(SlowLength), 200)
.SetDisplay("Slow SMA", "Slow SMA period.", "Indicators");
_atrLength = Param(nameof(AtrLength), 14)
.SetDisplay("ATR Length", "ATR period for volatility filter.", "Indicators");
}
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public int FastLength
{
get => _fastLength.Value;
set => _fastLength.Value = value;
}
public int MidLength
{
get => _midLength.Value;
set => _midLength.Value = value;
}
public int SlowLength
{
get => _slowLength.Value;
set => _slowLength.Value = value;
}
public int AtrLength
{
get => _atrLength.Value;
set => _atrLength.Value = value;
}
/// <inheritdoc />
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevFast = 0;
_prevMid = 0;
_prevSlow = 0;
_prevAtr = 0;
_entryPrice = 0;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_prevFast = 0;
_prevMid = 0;
_prevSlow = 0;
_prevAtr = 0;
_entryPrice = 0;
var fast = new SimpleMovingAverage { Length = FastLength };
var mid = new SimpleMovingAverage { Length = MidLength };
var slow = new SimpleMovingAverage { Length = SlowLength };
var atr = new AverageTrueRange { Length = AtrLength };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(fast, mid, slow, atr, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, fast);
DrawIndicator(area, mid);
DrawIndicator(area, slow);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal fastVal, decimal midVal, decimal slowVal, decimal atrVal)
{
if (candle.State != CandleStates.Finished)
return;
if (_prevFast == 0 || _prevMid == 0 || _prevSlow == 0)
{
_prevFast = fastVal;
_prevMid = midVal;
_prevSlow = slowVal;
_prevAtr = atrVal;
return;
}
var close = candle.ClosePrice;
var bullishAligned = fastVal > midVal && midVal > slowVal;
var bearishAligned = fastVal < midVal && midVal < slowVal;
var atrRising = atrVal > _prevAtr;
// Exit on alignment lost
if (Position > 0 && !bullishAligned)
{
SellMarket();
}
else if (Position < 0 && !bearishAligned)
{
BuyMarket();
}
// Entry on alignment + rising ATR
if (Position == 0)
{
if (bullishAligned && atrRising && close > fastVal)
{
_entryPrice = close;
BuyMarket();
}
else if (bearishAligned && atrRising && close < fastVal)
{
_entryPrice = close;
SellMarket();
}
}
_prevFast = fastVal;
_prevMid = midVal;
_prevSlow = slowVal;
_prevAtr = atrVal;
}
}
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.Indicators import SimpleMovingAverage, AverageTrueRange
from StockSharp.Algo.Strategies import Strategy
class true_sort_1001_strategy(Strategy):
"""Trend-following: strict SMA alignment (fast>mid>slow) + rising ATR for entries."""
def __init__(self):
super(true_sort_1001_strategy, self).__init__()
self._fast_len = self.Param("FastLength", 10).SetDisplay("Fast SMA", "Fast SMA period", "Indicators")
self._mid_len = self.Param("MidLength", 50).SetDisplay("Mid SMA", "Medium SMA period", "Indicators")
self._slow_len = self.Param("SlowLength", 200).SetDisplay("Slow SMA", "Slow SMA period", "Indicators")
self._atr_len = self.Param("AtrLength", 14).SetDisplay("ATR Length", "ATR period", "Indicators")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(5))).SetDisplay("Candle Type", "Timeframe", "General")
@property
def CandleType(self): return self._candle_type.Value
@CandleType.setter
def CandleType(self, value): self._candle_type.Value = value
def OnReseted(self):
super(true_sort_1001_strategy, self).OnReseted()
self._prev_fast = 0
self._prev_mid = 0
self._prev_slow = 0
self._prev_atr = 0
def OnStarted2(self, time):
super(true_sort_1001_strategy, self).OnStarted2(time)
self._prev_fast = 0
self._prev_mid = 0
self._prev_slow = 0
self._prev_atr = 0
fast = SimpleMovingAverage()
fast.Length = self._fast_len.Value
mid = SimpleMovingAverage()
mid.Length = self._mid_len.Value
slow = SimpleMovingAverage()
slow.Length = self._slow_len.Value
atr = AverageTrueRange()
atr.Length = self._atr_len.Value
sub = self.SubscribeCandles(self.CandleType)
sub.Bind(fast, mid, slow, atr, self.OnProcess).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, sub)
self.DrawIndicator(area, fast)
self.DrawIndicator(area, mid)
self.DrawIndicator(area, slow)
self.DrawOwnTrades(area)
def OnProcess(self, candle, fast_val, mid_val, slow_val, atr_val):
if candle.State != CandleStates.Finished:
return
fast = float(fast_val)
mid = float(mid_val)
slow = float(slow_val)
atr = float(atr_val)
close = float(candle.ClosePrice)
if self._prev_fast == 0 or self._prev_mid == 0 or self._prev_slow == 0:
self._prev_fast = fast
self._prev_mid = mid
self._prev_slow = slow
self._prev_atr = atr
return
bullish = fast > mid and mid > slow
bearish = fast < mid and mid < slow
atr_rising = atr > self._prev_atr
# Exit on alignment lost
if self.Position > 0 and not bullish:
self.SellMarket()
elif self.Position < 0 and not bearish:
self.BuyMarket()
# Entry
if self.Position == 0:
if bullish and atr_rising and close > fast:
self.BuyMarket()
elif bearish and atr_rising and close < fast:
self.SellMarket()
self._prev_fast = fast
self._prev_mid = mid
self._prev_slow = slow
self._prev_atr = atr
def CreateClone(self):
return true_sort_1001_strategy()