Day Trading Indicator Fusion Strategy
The strategy trades 5-minute candles using Parabolic SAR, MACD (12,26,9), Stochastic Oscillator (5,3,3) and Momentum (14). It requires all indicators to align before entering a position.
- Long entry: SAR below price with previous SAR above current, Momentum < 100, MACD line below signal line, Stochastic %K < 35.
- Short entry: SAR above price with previous SAR below current, Momentum > 100, MACD line above signal line, Stochastic %K > 60.
Positions are closed when the opposite conditions occur. Risk management uses a trailing stop and optional take profit.
Parameters
- Volume – order volume.
- Take Profit – target profit in points.
- Trailing Stop – trailing stop distance in points.
- Candle Type – candle subscription type (default 5-minute).
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>
/// Day trading strategy using Parabolic SAR, MACD, Stochastic, and Momentum indicators.
/// Enters long when multiple indicators confirm upward move and short when they confirm downward move.
/// Applies trailing stop and take profit.
/// </summary>
public class DayTradingIndicatorFusionStrategy : Strategy
{
private readonly StrategyParam<decimal> _tradeVolume;
private readonly StrategyParam<decimal> _takeProfit;
private readonly StrategyParam<decimal> _trailingStop;
private readonly StrategyParam<DataType> _candleType;
private decimal _prevSar;
/// <summary>
/// Order volume.
/// </summary>
public decimal TradeVolume
{
get => _tradeVolume.Value;
set => _tradeVolume.Value = value;
}
/// <summary>
/// Take profit in points.
/// </summary>
public decimal TakeProfit
{
get => _takeProfit.Value;
set => _takeProfit.Value = value;
}
/// <summary>
/// Trailing stop distance in points.
/// </summary>
public decimal TrailingStop
{
get => _trailingStop.Value;
set => _trailingStop.Value = value;
}
/// <summary>
/// Candle type for strategy calculations.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Initializes a new instance of <see cref="DayTradingIndicatorFusionStrategy"/>.
/// </summary>
public DayTradingIndicatorFusionStrategy()
{
_tradeVolume = Param(nameof(TradeVolume), 1m)
.SetGreaterThanZero()
.SetDisplay("Volume", "Order volume", "General");
_takeProfit = Param(nameof(TakeProfit), 50m)
.SetDisplay("Take Profit", "Take profit in points", "Risk");
_trailingStop = Param(nameof(TrailingStop), 25m)
.SetDisplay("Trailing Stop", "Trailing stop in points", "Risk");
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame())
.SetDisplay("Candle Type", "Type of candles", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevSar = 0m;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var macd = new MovingAverageConvergenceDivergenceSignal();
macd.Macd.ShortMa.Length = 12;
macd.Macd.LongMa.Length = 26;
macd.SignalMa.Length = 9;
var stochastic = new StochasticOscillator();
stochastic.K.Length = 5;
stochastic.D.Length = 3;
var parabolicSar = new ParabolicSar
{
Acceleration = 0.02m,
AccelerationMax = 0.2m
};
var subscription = SubscribeCandles(CandleType);
subscription
.BindEx(macd, stochastic, parabolicSar, ProcessCandle)
.Start();
var pip = Security?.PriceStep ?? 1m;
StartProtection(
takeProfit: TakeProfit > 0 ? new Unit(TakeProfit * pip, UnitTypes.Absolute) : default,
stopLoss: TrailingStop > 0 ? new Unit(TrailingStop * pip, UnitTypes.Absolute) : default,
isStopTrailing: TrailingStop > 0
);
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, parabolicSar);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, IIndicatorValue macdValue, IIndicatorValue stochValue, IIndicatorValue sarValue)
{
if (candle.State != CandleStates.Finished)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
var macdTyped = (MovingAverageConvergenceDivergenceSignalValue)macdValue;
if (macdTyped.Macd is not decimal macd || macdTyped.Signal is not decimal macdSignal)
return;
var stochTyped = (StochasticOscillatorValue)stochValue;
if (stochTyped.K is not decimal stochK || stochTyped.D is not decimal stochD)
return;
var sar = sarValue.ToDecimal();
var isBuying = sar <= candle.ClosePrice && _prevSar > sar && macd < macdSignal && stochK < 35m;
var isSelling = sar >= candle.ClosePrice && _prevSar < sar && macd > macdSignal && stochK > 60m;
_prevSar = sar;
if (isBuying && Position <= 0)
{
BuyMarket();
}
else if (isSelling && Position >= 0)
{
SellMarket();
}
}
}
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 (
MovingAverageConvergenceDivergenceSignal,
StochasticOscillator,
ParabolicSar,
)
from StockSharp.Algo.Strategies import Strategy
class day_trading_indicator_fusion_strategy(Strategy):
def __init__(self):
super(day_trading_indicator_fusion_strategy, self).__init__()
self._trade_volume = self.Param("TradeVolume", 1.0)
self._take_profit = self.Param("TakeProfit", 50.0)
self._trailing_stop = self.Param("TrailingStop", 25.0)
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(5)))
self._prev_sar = 0.0
@property
def TradeVolume(self):
return self._trade_volume.Value
@TradeVolume.setter
def TradeVolume(self, value):
self._trade_volume.Value = value
@property
def TakeProfit(self):
return self._take_profit.Value
@TakeProfit.setter
def TakeProfit(self, value):
self._take_profit.Value = value
@property
def TrailingStop(self):
return self._trailing_stop.Value
@TrailingStop.setter
def TrailingStop(self, value):
self._trailing_stop.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(day_trading_indicator_fusion_strategy, self).OnStarted2(time)
macd = MovingAverageConvergenceDivergenceSignal()
macd.Macd.ShortMa.Length = 12
macd.Macd.LongMa.Length = 26
macd.SignalMa.Length = 9
stochastic = StochasticOscillator()
stochastic.K.Length = 5
stochastic.D.Length = 3
parabolic_sar = ParabolicSar()
parabolic_sar.Acceleration = 0.02
parabolic_sar.AccelerationMax = 0.2
subscription = self.SubscribeCandles(self.CandleType)
subscription.BindEx(macd, stochastic, parabolic_sar, self.ProcessCandle).Start()
pip = float(self.Security.PriceStep) if self.Security is not None and self.Security.PriceStep is not None else 1.0
tp = Unit(float(self.TakeProfit) * pip, UnitTypes.Absolute) if self.TakeProfit > 0 else Unit()
sl = Unit(float(self.TrailingStop) * pip, UnitTypes.Absolute) if self.TrailingStop > 0 else Unit()
self.StartProtection(
takeProfit=tp,
stopLoss=sl,
isStopTrailing=self.TrailingStop > 0)
def ProcessCandle(self, candle, macd_value, stoch_value, sar_value):
if candle.State != CandleStates.Finished:
return
if not self.IsFormedAndOnlineAndAllowTrading():
return
try:
macd_v = float(macd_value.Macd)
macd_signal = float(macd_value.Signal)
except:
return
try:
stoch_k = float(stoch_value.K)
stoch_d = float(stoch_value.D)
except:
return
try:
sar = float(sar_value)
except:
return
is_buying = sar <= float(candle.ClosePrice) and self._prev_sar > sar and macd_v < macd_signal and stoch_k < 35.0
is_selling = sar >= float(candle.ClosePrice) and self._prev_sar < sar and macd_v > macd_signal and stoch_k > 60.0
self._prev_sar = sar
if is_buying and self.Position <= 0:
self.BuyMarket()
elif is_selling and self.Position >= 0:
self.SellMarket()
def OnReseted(self):
super(day_trading_indicator_fusion_strategy, self).OnReseted()
self._prev_sar = 0.0
def CreateClone(self):
return day_trading_indicator_fusion_strategy()