This strategy trades a selected forex pair using the momentum of the 2-year yield spread between its currencies. The momentum is measured as the difference between the spread and its moving average. Bollinger Bands applied to the momentum define overbought and oversold zones. Positions are closed after a fixed number of bars.
Key Features
Uses 2-year yield spread momentum for signals.
Bollinger Bands on momentum identify extreme conditions.
Optional reversal of entry logic.
Closes positions after a specified number of bars.
Parameters
Name
Description
YieldASecurity
First yield security.
YieldBSecurity
Second yield security.
CandleType
Candle timeframe for analysis.
MomentumLength
Period for yield spread average.
BollingerLength
Period for Bollinger Bands.
BollingerStdDev
Standard deviation multiplier for bands.
HoldPeriods
Bars to hold a position.
ReverseLogic
Invert long and short conditions.
Complexity
Beginner
using System;
using System.Collections.Generic;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
public class ForexPairYieldMomentumStrategy : Strategy
{
private readonly StrategyParam<int> _fastEmaPeriod;
private readonly StrategyParam<int> _slowEmaPeriod;
private readonly StrategyParam<DataType> _candleType;
private decimal _prevFastEma;
private decimal _prevSlowEma;
public int FastEmaPeriod { get => _fastEmaPeriod.Value; set => _fastEmaPeriod.Value = value; }
public int SlowEmaPeriod { get => _slowEmaPeriod.Value; set => _slowEmaPeriod.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public ForexPairYieldMomentumStrategy()
{
_fastEmaPeriod = Param(nameof(FastEmaPeriod), 120)
.SetGreaterThanZero()
.SetDisplay("Fast EMA", "Fast EMA period", "Indicators");
_slowEmaPeriod = Param(nameof(SlowEmaPeriod), 450)
.SetGreaterThanZero()
.SetDisplay("Slow EMA", "Slow EMA period", "Indicators");
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(1).TimeFrame())
.SetDisplay("Candle Type", "Type of candles to use", "General");
}
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
protected override void OnReseted()
{
base.OnReseted();
_prevFastEma = 0m;
_prevSlowEma = 0m;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var fastEma = new ExponentialMovingAverage { Length = FastEmaPeriod };
var slowEma = new ExponentialMovingAverage { Length = SlowEmaPeriod };
var subscription = SubscribeCandles(CandleType);
subscription.Bind(fastEma, slowEma, ProcessCandle).Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, fastEma);
DrawIndicator(area, slowEma);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal fastEmaValue, decimal slowEmaValue)
{
if (candle.State != CandleStates.Finished) return;
if (_prevFastEma == 0m || _prevSlowEma == 0m)
{
_prevFastEma = fastEmaValue;
_prevSlowEma = slowEmaValue;
return;
}
if (_prevFastEma <= _prevSlowEma && fastEmaValue > slowEmaValue && Position <= 0)
BuyMarket();
else if (_prevFastEma >= _prevSlowEma && fastEmaValue < slowEmaValue && Position >= 0)
SellMarket();
_prevFastEma = fastEmaValue;
_prevSlowEma = slowEmaValue;
}
}
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 forex_pair_yield_momentum_strategy(Strategy):
"""
ForexPairYieldMomentum: EMA crossover strategy.
Buys when fast EMA crosses above slow EMA, sells on reverse.
"""
def __init__(self):
super(forex_pair_yield_momentum_strategy, self).__init__()
self._fast_period = self.Param("FastPeriod", 120) .SetDisplay("Fast EMA", "Fast EMA period", "Indicator")
self._slow_period = self.Param("SlowPeriod", 450) .SetDisplay("Slow EMA", "Slow EMA period", "Indicator")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(1))) .SetDisplay("Candle Type", "Time frame for candles", "General")
self._prev_fast = 0.0
self._prev_slow = 0.0
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(forex_pair_yield_momentum_strategy, self).OnReseted()
self._prev_fast = 0.0
self._prev_slow = 0.0
def OnStarted2(self, time):
super(forex_pair_yield_momentum_strategy, self).OnStarted2(time)
fast = ExponentialMovingAverage()
fast.Length = self._fast_period.Value
slow = ExponentialMovingAverage()
slow.Length = self._slow_period.Value
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(fast, slow, self._process_candle).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, fast)
self.DrawIndicator(area, slow)
self.DrawOwnTrades(area)
def _process_candle(self, candle, fast_val, slow_val):
if candle.State != CandleStates.Finished:
return
fast_v = float(fast_val)
slow_v = float(slow_val)
if self._prev_fast <= self._prev_slow and fast_val > slow_val and self.Position <= 0:
self.BuyMarket()
elif self._prev_fast >= self._prev_slow and fast_val < slow_val and self.Position >= 0:
self.SellMarket()
self._prev_fast = fast_val
self._prev_slow = slow_val
def CreateClone(self):
return forex_pair_yield_momentum_strategy()