Relative Currency Strength
Relative Currency Strength compares a currency pair to a basket of major currencies. It buys when the traded pair outperforms the average of other majors and sells when it underperforms. The comparison is based on percentage change from the start of the session.
Details
- Entry Criteria: Main pair strength exceeds average by threshold.
- Long/Short: Both directions.
- Exit Criteria: Strength falls below average by threshold.
- Stops: No.
- Default Values:
Threshold= 0.01mCandleType= TimeSpan.FromMinutes(5)
- Filters:
- Category: Trend
- Direction: Both
- Indicators: Price change
- Stops: No
- Complexity: Intermediate
- Timeframe: Intraday
- Seasonality: No
- Neural Networks: No
- Divergence: No
- Risk Level: Medium
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;
using Ecng.ComponentModel;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Strategy that trades based on relative currency strength among major pairs.
/// It buys when the traded pair outperforms the average of other majors and sells when it underperforms.
/// </summary>
public class RelativeCurrencyStrengthStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<decimal> _threshold;
private readonly StrategyParam<Security> _audUsd;
private readonly StrategyParam<Security> _nzdUsd;
private readonly StrategyParam<Security> _usdJpy;
private readonly StrategyParam<Security> _usdChf;
private readonly StrategyParam<Security> _usdCad;
private readonly StrategyParam<Security> _gbpUsd;
private readonly StrategyParam<Security> _eurUsd;
private readonly StrategyParam<Security> _xauUsd;
private decimal? _mainStart;
private decimal _mainStrength;
private decimal? _audUsdStart;
private decimal _audUsdStrength;
private decimal? _nzdUsdStart;
private decimal _nzdUsdStrength;
private decimal? _usdJpyStart;
private decimal _usdJpyStrength;
private decimal? _usdChfStart;
private decimal _usdChfStrength;
private decimal? _usdCadStart;
private decimal _usdCadStrength;
private decimal? _gbpUsdStart;
private decimal _gbpUsdStrength;
private decimal? _eurUsdStart;
private decimal _eurUsdStrength;
private decimal? _xauUsdStart;
private decimal _xauUsdStrength;
/// <summary>
/// Type of candles used for calculations.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Strength difference needed for entry signal.
/// </summary>
public decimal Threshold
{
get => _threshold.Value;
set => _threshold.Value = value;
}
/// <summary>
/// AUD/USD security.
/// </summary>
public Security AudUsd
{
get => _audUsd.Value;
set => _audUsd.Value = value;
}
/// <summary>
/// NZD/USD security.
/// </summary>
public Security NzdUsd
{
get => _nzdUsd.Value;
set => _nzdUsd.Value = value;
}
/// <summary>
/// USD/JPY security.
/// </summary>
public Security UsdJpy
{
get => _usdJpy.Value;
set => _usdJpy.Value = value;
}
/// <summary>
/// USD/CHF security.
/// </summary>
public Security UsdChf
{
get => _usdChf.Value;
set => _usdChf.Value = value;
}
/// <summary>
/// USD/CAD security.
/// </summary>
public Security UsdCad
{
get => _usdCad.Value;
set => _usdCad.Value = value;
}
/// <summary>
/// GBP/USD security.
/// </summary>
public Security GbpUsd
{
get => _gbpUsd.Value;
set => _gbpUsd.Value = value;
}
/// <summary>
/// EUR/USD security.
/// </summary>
public Security EurUsd
{
get => _eurUsd.Value;
set => _eurUsd.Value = value;
}
/// <summary>
/// XAU/USD security.
/// </summary>
public Security XauUsd
{
get => _xauUsd.Value;
set => _xauUsd.Value = value;
}
/// <summary>
/// Initializes a new instance of the strategy.
/// </summary>
public RelativeCurrencyStrengthStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame())
.SetDisplay("Candle Type", "Type of candles", "Data");
_threshold = Param(nameof(Threshold), 0.01m)
.SetDisplay("Threshold", "Strength difference for signal", "Parameters")
.SetOptimize(0.005m, 0.05m, 0.005m);
_audUsd = Param<Security>(nameof(AudUsd))
.SetDisplay("AUDUSD", "AUD/USD pair", "Data")
.SetRequired();
_nzdUsd = Param<Security>(nameof(NzdUsd))
.SetDisplay("NZDUSD", "NZD/USD pair", "Data")
.SetRequired();
_usdJpy = Param<Security>(nameof(UsdJpy))
.SetDisplay("USDJPY", "USD/JPY pair", "Data")
.SetRequired();
_usdChf = Param<Security>(nameof(UsdChf))
.SetDisplay("USDCHF", "USD/CHF pair", "Data")
.SetRequired();
_usdCad = Param<Security>(nameof(UsdCad))
.SetDisplay("USDCAD", "USD/CAD pair", "Data")
.SetRequired();
_gbpUsd = Param<Security>(nameof(GbpUsd))
.SetDisplay("GBPUSD", "GBP/USD pair", "Data")
.SetRequired();
_eurUsd = Param<Security>(nameof(EurUsd))
.SetDisplay("EURUSD", "EUR/USD pair", "Data")
.SetRequired();
_xauUsd = Param<Security>(nameof(XauUsd))
.SetDisplay("XAUUSD", "Gold pair", "Data")
.SetRequired();
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return
[
(Security, CandleType),
(AudUsd, CandleType),
(NzdUsd, CandleType),
(UsdJpy, CandleType),
(UsdChf, CandleType),
(UsdCad, CandleType),
(GbpUsd, CandleType),
(EurUsd, CandleType),
(XauUsd, CandleType)
];
}
protected override void OnReseted()
{
base.OnReseted();
_mainStart = null;
_mainStrength = 0;
_audUsdStart = null;
_audUsdStrength = 0;
_nzdUsdStart = null;
_nzdUsdStrength = 0;
_usdJpyStart = null;
_usdJpyStrength = 0;
_usdChfStart = null;
_usdChfStrength = 0;
_usdCadStart = null;
_usdCadStrength = 0;
_gbpUsdStart = null;
_gbpUsdStrength = 0;
_eurUsdStart = null;
_eurUsdStrength = 0;
_xauUsdStart = null;
_xauUsdStrength = 0;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
SubscribeCandles(CandleType)
.Bind(ProcessMain)
.Start();
SubscribeCandles(CandleType, security: AudUsd)
.Bind(ProcessAudUsd)
.Start();
SubscribeCandles(CandleType, security: NzdUsd)
.Bind(ProcessNzdUsd)
.Start();
SubscribeCandles(CandleType, security: UsdJpy)
.Bind(ProcessUsdJpy)
.Start();
SubscribeCandles(CandleType, security: UsdChf)
.Bind(ProcessUsdChf)
.Start();
SubscribeCandles(CandleType, security: UsdCad)
.Bind(ProcessUsdCad)
.Start();
SubscribeCandles(CandleType, security: GbpUsd)
.Bind(ProcessGbpUsd)
.Start();
SubscribeCandles(CandleType, security: EurUsd)
.Bind(ProcessEurUsd)
.Start();
SubscribeCandles(CandleType, security: XauUsd)
.Bind(ProcessXauUsd)
.Start();
}
private void ProcessAudUsd(ICandleMessage candle)
{
if (candle.State != CandleStates.Finished)
return;
if (_audUsdStart is null)
{
_audUsdStart = candle.ClosePrice;
return;
}
_audUsdStrength = candle.ClosePrice / _audUsdStart.Value - 1m;
}
private void ProcessNzdUsd(ICandleMessage candle)
{
if (candle.State != CandleStates.Finished)
return;
if (_nzdUsdStart is null)
{
_nzdUsdStart = candle.ClosePrice;
return;
}
_nzdUsdStrength = candle.ClosePrice / _nzdUsdStart.Value - 1m;
}
private void ProcessUsdJpy(ICandleMessage candle)
{
if (candle.State != CandleStates.Finished)
return;
if (_usdJpyStart is null)
{
_usdJpyStart = candle.ClosePrice;
return;
}
_usdJpyStrength = candle.ClosePrice / _usdJpyStart.Value - 1m;
}
private void ProcessUsdChf(ICandleMessage candle)
{
if (candle.State != CandleStates.Finished)
return;
if (_usdChfStart is null)
{
_usdChfStart = candle.ClosePrice;
return;
}
_usdChfStrength = candle.ClosePrice / _usdChfStart.Value - 1m;
}
private void ProcessUsdCad(ICandleMessage candle)
{
if (candle.State != CandleStates.Finished)
return;
if (_usdCadStart is null)
{
_usdCadStart = candle.ClosePrice;
return;
}
_usdCadStrength = candle.ClosePrice / _usdCadStart.Value - 1m;
}
private void ProcessGbpUsd(ICandleMessage candle)
{
if (candle.State != CandleStates.Finished)
return;
if (_gbpUsdStart is null)
{
_gbpUsdStart = candle.ClosePrice;
return;
}
_gbpUsdStrength = candle.ClosePrice / _gbpUsdStart.Value - 1m;
}
private void ProcessEurUsd(ICandleMessage candle)
{
if (candle.State != CandleStates.Finished)
return;
if (_eurUsdStart is null)
{
_eurUsdStart = candle.ClosePrice;
return;
}
_eurUsdStrength = candle.ClosePrice / _eurUsdStart.Value - 1m;
}
private void ProcessXauUsd(ICandleMessage candle)
{
if (candle.State != CandleStates.Finished)
return;
if (_xauUsdStart is null)
{
_xauUsdStart = candle.ClosePrice;
return;
}
_xauUsdStrength = candle.ClosePrice / _xauUsdStart.Value - 1m;
}
private void ProcessMain(ICandleMessage candle)
{
if (candle.State != CandleStates.Finished)
return;
if (_mainStart is null)
{
_mainStart = candle.ClosePrice;
return;
}
_mainStrength = candle.ClosePrice / _mainStart.Value - 1m;
if (!IsFormedAndOnlineAndAllowTrading())
return;
if (_audUsdStart is null || _nzdUsdStart is null || _usdJpyStart is null || _usdChfStart is null || _usdCadStart is null || _gbpUsdStart is null || _eurUsdStart is null || _xauUsdStart is null)
return;
var sum = _audUsdStrength + _nzdUsdStrength + _usdJpyStrength + _usdChfStrength + _usdCadStrength + _gbpUsdStrength + _eurUsdStrength + _xauUsdStrength;
var average = sum / 8m;
if (Position <= 0 && _mainStrength - average > Threshold)
BuyMarket(Volume);
else if (Position >= 0 && average - _mainStrength > Threshold)
SellMarket(Volume);
}
}
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
from StockSharp.Algo.Strategies import Strategy
class relative_currency_strength_strategy(Strategy):
def __init__(self):
super(relative_currency_strength_strategy, self).__init__()
self._slow_length = self.Param("SlowLength", 40) \
.SetGreaterThanZero() \
.SetDisplay("Slow Length", "Slow EMA period", "General")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(5))) \
.SetDisplay("Candle Type", "Candle type", "General")
self._prev_f = 0.0
self._prev_s = 0.0
self._init = False
self._last_signal_ticks = 0
@property
def slow_length(self):
return self._slow_length.Value
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(relative_currency_strength_strategy, self).OnReseted()
self._prev_f = 0.0
self._prev_s = 0.0
self._init = False
self._last_signal_ticks = 0
def OnStarted2(self, time):
super(relative_currency_strength_strategy, self).OnStarted2(time)
self._fast = ExponentialMovingAverage()
self._fast.Length = 14
self._slow = ExponentialMovingAverage()
self._slow.Length = self.slow_length
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(self._fast, self._slow, self.on_candle).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, self._fast)
self.DrawIndicator(area, self._slow)
self.DrawOwnTrades(area)
def on_candle(self, candle, f, s):
if candle.State != CandleStates.Finished:
return
if not self._fast.IsFormed or not self._slow.IsFormed:
return
f = float(f)
s = float(s)
if not self._init:
self._prev_f = f
self._prev_s = s
self._init = True
return
cooldown_ticks = TimeSpan.FromMinutes(360).Ticks
current_ticks = candle.OpenTime.Ticks
if current_ticks - self._last_signal_ticks >= cooldown_ticks:
if self._prev_f <= self._prev_s and f > s and self.Position <= 0:
self.BuyMarket()
self._last_signal_ticks = current_ticks
elif self._prev_f >= self._prev_s and f < s and self.Position >= 0:
self.SellMarket()
self._last_signal_ticks = current_ticks
self._prev_f = f
self._prev_s = s
def CreateClone(self):
return relative_currency_strength_strategy()