XAUUSD Trend Strategy
This strategy trades XAUUSD using EMA crossovers, RSI extremes and Bollinger Bands. A long position is opened when the fast EMA crosses above the slow EMA, RSI is below the oversold level and price closes above the upper Bollinger Band. Short positions are opened on the opposite conditions. Risk management sets stop-loss and take-profit levels based on portfolio risk percentage and a take-profit to stop-loss ratio.
Details
- Entry:
- Long: fast EMA crossover up, RSI < oversold, close > upper band.
- Short: fast EMA crossover down, RSI > overbought, close < lower band.
- Exit: stop-loss or take-profit calculated from risk settings.
- Indicators: EMA, RSI, Bollinger Bands.
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>
/// XAUUSD trend strategy using dual EMA crossover, RSI filter, and Bollinger band breakout.
/// Uses StdDev-based stops and take-profit levels.
/// </summary>
public class XauusdTrendStrategy : Strategy
{
private readonly StrategyParam<int> _emaShort;
private readonly StrategyParam<int> _emaLong;
private readonly StrategyParam<int> _rsiLength;
private readonly StrategyParam<decimal> _rsiOverbought;
private readonly StrategyParam<decimal> _rsiOversold;
private readonly StrategyParam<decimal> _stopPct;
private readonly StrategyParam<decimal> _tpRiskRatio;
private readonly StrategyParam<DataType> _candleType;
private decimal _stopPrice;
private decimal _takePrice;
private decimal _entryPrice;
public int EmaShort { get => _emaShort.Value; set => _emaShort.Value = value; }
public int EmaLong { get => _emaLong.Value; set => _emaLong.Value = value; }
public int RsiLength { get => _rsiLength.Value; set => _rsiLength.Value = value; }
public decimal RsiOverbought { get => _rsiOverbought.Value; set => _rsiOverbought.Value = value; }
public decimal RsiOversold { get => _rsiOversold.Value; set => _rsiOversold.Value = value; }
public decimal StopPct { get => _stopPct.Value; set => _stopPct.Value = value; }
public decimal TpRiskRatio { get => _tpRiskRatio.Value; set => _tpRiskRatio.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public XauusdTrendStrategy()
{
_emaShort = Param(nameof(EmaShort), 20)
.SetGreaterThanZero()
.SetDisplay("EMA Short", "Fast EMA period", "Indicators");
_emaLong = Param(nameof(EmaLong), 50)
.SetGreaterThanZero()
.SetDisplay("EMA Long", "Slow EMA period", "Indicators");
_rsiLength = Param(nameof(RsiLength), 14)
.SetGreaterThanZero()
.SetDisplay("RSI Length", "RSI period", "Indicators");
_rsiOverbought = Param(nameof(RsiOverbought), 70m)
.SetDisplay("RSI Overbought", "Overbought level", "Indicators");
_rsiOversold = Param(nameof(RsiOversold), 30m)
.SetDisplay("RSI Oversold", "Oversold level", "Indicators");
_stopPct = Param(nameof(StopPct), 1.5m)
.SetGreaterThanZero()
.SetDisplay("Stop %", "Stop loss percent", "Risk");
_tpRiskRatio = Param(nameof(TpRiskRatio), 2m)
.SetGreaterThanZero()
.SetDisplay("TP/SL Ratio", "Take profit to stop ratio", "Risk");
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame())
.SetDisplay("Candle Type", "Type of candles", "General");
}
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
protected override void OnReseted()
{
base.OnReseted();
_stopPrice = 0;
_takePrice = 0;
_entryPrice = 0;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var emaFast = new ExponentialMovingAverage { Length = EmaShort };
var emaSlow = new ExponentialMovingAverage { Length = EmaLong };
var rsi = new RelativeStrengthIndex { Length = RsiLength };
var stdDev = new StandardDeviation { Length = 20 };
_stopPrice = 0;
_takePrice = 0;
_entryPrice = 0;
var sub = SubscribeCandles(CandleType);
sub.Bind(emaFast, emaSlow, rsi, stdDev, ProcessCandle).Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, sub);
DrawIndicator(area, emaFast);
DrawIndicator(area, emaSlow);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal emaFastVal, decimal emaSlowVal, decimal rsiVal, decimal stdVal)
{
if (candle.State != CandleStates.Finished)
return;
// TP/SL management
if (Position > 0 && _entryPrice > 0)
{
if (candle.ClosePrice <= _stopPrice || candle.ClosePrice >= _takePrice)
{
SellMarket();
_entryPrice = 0;
return;
}
}
else if (Position < 0 && _entryPrice > 0)
{
if (candle.ClosePrice >= _stopPrice || candle.ClosePrice <= _takePrice)
{
BuyMarket();
_entryPrice = 0;
return;
}
}
if (stdVal <= 0)
return;
// EMA trend + RSI filter + price above/below band
var upperBand = emaSlowVal + 2m * stdVal;
var lowerBand = emaSlowVal - 2m * stdVal;
var longCond = emaFastVal > emaSlowVal && rsiVal < RsiOversold;
var shortCond = emaFastVal < emaSlowVal && rsiVal > RsiOverbought;
if (longCond && Position <= 0)
{
BuyMarket();
_entryPrice = candle.ClosePrice;
var sl = _entryPrice * StopPct / 100m;
_stopPrice = _entryPrice - sl;
_takePrice = _entryPrice + sl * TpRiskRatio;
}
else if (shortCond && Position >= 0)
{
SellMarket();
_entryPrice = candle.ClosePrice;
var sl = _entryPrice * StopPct / 100m;
_stopPrice = _entryPrice + sl;
_takePrice = _entryPrice - sl * TpRiskRatio;
}
}
}
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 ExponentialMovingAverage, RelativeStrengthIndex, StandardDeviation
from StockSharp.Algo.Strategies import Strategy
class xauusd_trend_strategy(Strategy):
def __init__(self):
super(xauusd_trend_strategy, self).__init__()
self._ema_short = self.Param("EmaShort", 20) \
.SetDisplay("EMA Short", "Fast EMA period", "Indicators")
self._ema_long = self.Param("EmaLong", 50) \
.SetDisplay("EMA Long", "Slow EMA period", "Indicators")
self._rsi_length = self.Param("RsiLength", 14) \
.SetDisplay("RSI Length", "RSI period", "Indicators")
self._rsi_overbought = self.Param("RsiOverbought", 70) \
.SetDisplay("RSI Overbought", "Overbought level", "Indicators")
self._rsi_oversold = self.Param("RsiOversold", 30) \
.SetDisplay("RSI Oversold", "Oversold level", "Indicators")
self._stop_pct = self.Param("StopPct", 1.5) \
.SetDisplay("Stop %", "Stop loss percent", "Risk")
self._tp_risk_ratio = self.Param("TpRiskRatio", 2) \
.SetDisplay("TP/SL Ratio", "Take profit to stop ratio", "Risk")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(5))) \
.SetDisplay("Candle Type", "Type of candles", "General")
self._stop_price = 0.0
self._take_price = 0.0
self._entry_price = 0.0
@property
def ema_short(self):
return self._ema_short.Value
@property
def ema_long(self):
return self._ema_long.Value
@property
def rsi_length(self):
return self._rsi_length.Value
@property
def rsi_overbought(self):
return self._rsi_overbought.Value
@property
def rsi_oversold(self):
return self._rsi_oversold.Value
@property
def stop_pct(self):
return self._stop_pct.Value
@property
def tp_risk_ratio(self):
return self._tp_risk_ratio.Value
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(xauusd_trend_strategy, self).OnReseted()
self._stop_price = 0.0
self._take_price = 0.0
self._entry_price = 0.0
def OnStarted2(self, time):
super(xauusd_trend_strategy, self).OnStarted2(time)
ema_fast = ExponentialMovingAverage()
ema_fast.Length = self.ema_short
ema_slow = ExponentialMovingAverage()
ema_slow.Length = self.ema_long
rsi = RelativeStrengthIndex()
rsi.Length = self.rsi_length
std_dev = StandardDeviation()
std_dev.Length = 20
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(ema_fast, ema_slow, rsi, std_dev, self.on_process).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, ema_fast)
self.DrawIndicator(area, ema_slow)
self.DrawOwnTrades(area)
def on_process(self, candle, ema_fast_val, ema_slow_val, rsi_val, std_val):
if candle.State != CandleStates.Finished:
return
# TP/SL management
if self.Position > 0 and self._entry_price > 0:
if candle.ClosePrice <= self._stop_price or candle.ClosePrice >= self._take_price:
self.SellMarket()
self._entry_price = 0
return
elif self.Position < 0 and self._entry_price > 0:
if candle.ClosePrice >= self._stop_price or candle.ClosePrice <= self._take_price:
self.BuyMarket()
self._entry_price = 0
return
if std_val <= 0:
return
# EMA trend + RSI filter + price above/below band
upper_band = ema_slow_val + 2 * std_val
lower_band = ema_slow_val - 2 * std_val
long_cond = ema_fast_val > ema_slow_val and rsi_val < self.rsi_oversold
short_cond = ema_fast_val < ema_slow_val and rsi_val > self.rsi_overbought
if long_cond and self.Position <= 0:
self.BuyMarket()
self._entry_price = candle.ClosePrice
sl = self._entry_price * self.stop_pct / 100
self._stop_price = self._entry_price - sl
self._take_price = self._entry_price + sl * self.tp_risk_ratio
elif short_cond and self.Position >= 0:
self.SellMarket()
self._entry_price = candle.ClosePrice
sl = self._entry_price * self.stop_pct / 100
self._stop_price = self._entry_price + sl
self._take_price = self._entry_price - sl * self.tp_risk_ratio
def CreateClone(self):
return xauusd_trend_strategy()