This strategy uses the UltraFATL oscillator to detect shifts in trend strength. The indicator outputs discrete levels from 0 to 8. A long position is opened when the previous value is above level 4 and the current value falls below 5 while staying positive. A short position is opened when the previous value is below 5 but above zero and the current value rises above 4. The algorithm works on 4‑hour candles by default but the timeframe can be adjusted.
The approach expects trend continuation after a pullback from extreme UltraFATL readings. Positions are reversed when the opposite condition appears.
Details
Entry Criteria:
Long: UltraFATL(prev) > 4 and UltraFATL(curr) < 5 and UltraFATL(curr) != 0.
Short: UltraFATL(prev) < 5 and UltraFATL(prev) != 0 and UltraFATL(curr) > 4.
Long/Short: Both sides.
Exit Criteria: Opposite signal reverses the position.
Stops: Not used by default.
Default Values:
Candle Type = 4‑hour candles.
Length = 3.
Signal Bar = 1 (use previous bar for signals).
Filters:
Category: Trend following
Direction: Both
Indicators: Single (UltraFATL)
Stops: No
Complexity: Medium
Timeframe: Medium-term
Seasonality: No
Neural networks: No
Divergence: No
Risk level: Moderate
using System;
using System.Collections.Generic;
using Ecng.Common;
using Ecng.Serialization;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Strategy based on UltraFATL-style threshold signals.
/// </summary>
public class UltraFatlStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _length;
private readonly StrategyParam<int> _signalBar;
private decimal _prevValue;
private bool _isInitialized;
/// <summary>
/// Candle type.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Smoothing period.
/// </summary>
public int Length
{
get => _length.Value;
set => _length.Value = value;
}
/// <summary>
/// Bar index used for signal calculation.
/// </summary>
public int SignalBar
{
get => _signalBar.Value;
set => _signalBar.Value = value;
}
/// <summary>
/// Initialize the UltraFATL strategy.
/// </summary>
public UltraFatlStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Type of candles", "General");
_length = Param(nameof(Length), 8)
.SetDisplay("Length", "Smoothing period", "UltraFATL")
.SetOptimize(4, 20, 1);
_signalBar = Param(nameof(SignalBar), 1)
.SetDisplay("Signal Bar", "Bar index for signal calculation", "UltraFATL");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevValue = 0m;
_isInitialized = false;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var rsi = new RelativeStrengthIndex { Length = Length };
var subscription = SubscribeCandles(CandleType);
subscription.Bind(rsi, ProcessCandle).Start();
}
private void ProcessCandle(ICandleMessage candle, decimal rsiValue)
{
if (candle.State != CandleStates.Finished)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
// Map RSI to the 0..8 discrete UltraFATL-style scale.
var current = Math.Max(0m, Math.Min(8m, rsiValue / 12.5m));
if (!_isInitialized)
{
_prevValue = current;
_isInitialized = true;
return;
}
var previous = _prevValue;
_prevValue = current;
var isBuySignal = previous >= 5m && current < 5m && current > 0m;
var isSellSignal = previous <= 4m && current > 4m;
if (isBuySignal && Position <= 0)
BuyMarket(Volume + Math.Abs(Position));
else if (isSellSignal && Position >= 0)
SellMarket(Volume + Math.Abs(Position));
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
from System import TimeSpan, Math
from StockSharp.Messages import DataType, CandleStates
from StockSharp.Algo.Indicators import RelativeStrengthIndex
from StockSharp.Algo.Strategies import Strategy
class ultra_fatl_strategy(Strategy):
def __init__(self):
super(ultra_fatl_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Type of candles", "General")
self._length = self.Param("Length", 8) \
.SetDisplay("Length", "Smoothing period", "UltraFATL")
self._signal_bar = self.Param("SignalBar", 1) \
.SetDisplay("Signal Bar", "Bar index for signal calculation", "UltraFATL")
self._prev_value = 0.0
self._is_initialized = False
@property
def CandleType(self):
return self._candle_type.Value
@CandleType.setter
def CandleType(self, value):
self._candle_type.Value = value
@property
def Length(self):
return self._length.Value
@Length.setter
def Length(self, value):
self._length.Value = value
@property
def SignalBar(self):
return self._signal_bar.Value
@SignalBar.setter
def SignalBar(self, value):
self._signal_bar.Value = value
def OnStarted2(self, time):
super(ultra_fatl_strategy, self).OnStarted2(time)
rsi = RelativeStrengthIndex()
rsi.Length = self.Length
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(rsi, self.ProcessCandle).Start()
def ProcessCandle(self, candle, rsi_value):
if candle.State != CandleStates.Finished:
return
rsi = float(rsi_value)
current = max(0.0, min(8.0, rsi / 12.5))
if not self._is_initialized:
self._prev_value = current
self._is_initialized = True
return
previous = self._prev_value
self._prev_value = current
is_buy_signal = previous >= 5.0 and current < 5.0 and current > 0.0
is_sell_signal = previous <= 4.0 and current > 4.0
pos = self.Position
if is_buy_signal and pos <= 0:
self.BuyMarket(self.Volume + abs(pos))
elif is_sell_signal and pos >= 0:
self.SellMarket(self.Volume + abs(pos))
def OnReseted(self):
super(ultra_fatl_strategy, self).OnReseted()
self._prev_value = 0.0
self._is_initialized = False
def CreateClone(self):
return ultra_fatl_strategy()