The Forex Line strategy is a trend-following system derived from the MetaTrader indicator "ForexLine". It applies two stages of weighted moving averages to the price to build fast and slow lines. Crossovers between these double-smoothed lines are used to determine entry signals.
The strategy buys when the fast line crosses above the slow line and sells when the fast line crosses below the slow line. Each moving average uses a two-step smoothing process that helps filter market noise.
Details
Entry Criteria:
Long: Fast double-smoothed WMA crosses above the slow double-smoothed WMA.
Short: Fast double-smoothed WMA crosses below the slow double-smoothed WMA.
Long/Short: Both sides.
Exit Criteria:
Opposite crossover closes existing position.
Stops: Not included; can be added externally.
Default Values:
FastLength1 = 5
FastLength2 = 10
SlowLength1 = 20
SlowLength2 = 20
CandleType = 8 hour timeframe
Filters:
Category: Trend following
Direction: Both
Indicators: Weighted moving averages
Stops: No
Complexity: Moderate
Timeframe: Medium-term
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;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Forex Line strategy using fast/slow WMA crossover.
/// </summary>
public class ForexLineStrategy : Strategy
{
private readonly StrategyParam<int> _fastLength;
private readonly StrategyParam<int> _slowLength;
private readonly StrategyParam<DataType> _candleType;
private decimal? _prevFast;
private decimal? _prevSlow;
public int FastLength { get => _fastLength.Value; set => _fastLength.Value = value; }
public int SlowLength { get => _slowLength.Value; set => _slowLength.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public ForexLineStrategy()
{
_fastLength = Param(nameof(FastLength), 10)
.SetGreaterThanZero()
.SetDisplay("Fast WMA Length", "Fast line period", "Parameters");
_slowLength = Param(nameof(SlowLength), 30)
.SetGreaterThanZero()
.SetDisplay("Slow WMA Length", "Slow line period", "Parameters");
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Type of candles to analyze", "General");
}
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
=> [(Security, CandleType)];
protected override void OnReseted()
{
base.OnReseted();
_prevFast = _prevSlow = null;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var fast = new WeightedMovingAverage { Length = FastLength };
var slow = new WeightedMovingAverage { Length = SlowLength };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(fast, slow, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, fast);
DrawIndicator(area, slow);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal fast, decimal slow)
{
if (candle.State != CandleStates.Finished)
return;
if (!IsFormedAndOnlineAndAllowTrading())
{
_prevFast = fast;
_prevSlow = slow;
return;
}
if (_prevFast is decimal pf && _prevSlow is decimal ps)
{
if (pf <= ps && fast > slow && Position <= 0)
BuyMarket();
else if (pf >= ps && fast < slow && Position >= 0)
SellMarket();
}
_prevFast = fast;
_prevSlow = slow;
}
}
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 WeightedMovingAverage
from StockSharp.Algo.Strategies import Strategy
class forex_line_strategy(Strategy):
def __init__(self):
super(forex_line_strategy, self).__init__()
self._fast_length = self.Param("FastLength", 10).SetDisplay("Fast WMA Length", "Fast line period", "Parameters")
self._slow_length = self.Param("SlowLength", 30).SetDisplay("Slow WMA Length", "Slow line period", "Parameters")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))).SetDisplay("Candle Type", "Type of candles to analyze", "General")
self._prev_fast = None
self._prev_slow = None
@property
def fast_length(self): return self._fast_length.Value
@property
def slow_length(self): return self._slow_length.Value
@property
def candle_type(self): return self._candle_type.Value
def OnReseted(self):
super(forex_line_strategy, self).OnReseted()
self._prev_fast = None
self._prev_slow = None
def OnStarted2(self, time):
super(forex_line_strategy, self).OnStarted2(time)
fast = WeightedMovingAverage()
fast.Length = self.fast_length
slow = WeightedMovingAverage()
slow.Length = self.slow_length
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, slow):
if candle.State != CandleStates.Finished: return
f = float(fast)
s = float(slow)
if self._prev_fast is not None and self._prev_slow is not None:
if self._prev_fast <= self._prev_slow and f > s and self.Position <= 0:
self.BuyMarket()
elif self._prev_fast >= self._prev_slow and f < s and self.Position >= 0:
self.SellMarket()
self._prev_fast = f
self._prev_slow = s
def CreateClone(self): return forex_line_strategy()