This strategy monitors a simple moving average (MA) and automatically closes any open position when the candle close crosses the MA line. It is designed for traders who manage entries manually or with other systems but want an automated exit once the trend reverses.
The logic tracks the relationship between the close price and the MA. When a new finished candle crosses from one side of the MA to the other, the strategy sends a market order to flatten the position. No new positions are opened.
Details
Entry Criteria: None. Positions must be opened externally.
Exit Criteria:
Long: Previous close above MA and current close below MA triggers a sell to close.
Short: Previous close below MA and current close above MA triggers a buy to close.
Long/Short: Both directions are supported.
Stops: Not used. The MA cross acts as the exit signal.
Default Values:
MA Period = 50.
Candle Type = Time frame of 1 minute.
Filters:
Category: Trend following
Direction: Both
Indicators: Single
Stops: No
Complexity: Simple
Timeframe: Any
Seasonality: No
Neural networks: No
Divergence: No
Risk level: Moderate
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;
/// <summary>
/// Price cross MA strategy.
/// </summary>
public class CloseCrossMaStrategy : Strategy
{
private readonly StrategyParam<int> _maPeriod;
private readonly StrategyParam<DataType> _candleType;
private decimal _prevDiff;
private bool _hasPrev;
public int MaPeriod { get => _maPeriod.Value; set => _maPeriod.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public CloseCrossMaStrategy()
{
_maPeriod = Param(nameof(MaPeriod), 50)
.SetGreaterThanZero()
.SetDisplay("MA Period", "EMA period", "Parameters");
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Candle type", "General");
}
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
=> [(Security, CandleType)];
protected override void OnReseted()
{
base.OnReseted();
_prevDiff = 0;
_hasPrev = false;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var ema = new ExponentialMovingAverage { Length = MaPeriod };
SubscribeCandles(CandleType)
.Bind(ema, ProcessCandle)
.Start();
}
private void ProcessCandle(ICandleMessage candle, decimal emaVal)
{
if (candle.State != CandleStates.Finished) return;
var diff = candle.ClosePrice - emaVal;
if (!_hasPrev)
{
_prevDiff = diff;
_hasPrev = true;
return;
}
// Price crosses above EMA
if (_prevDiff <= 0 && diff > 0 && Position <= 0)
{
if (Position < 0) BuyMarket();
BuyMarket();
}
// Price crosses below EMA
else if (_prevDiff >= 0 && diff < 0 && Position >= 0)
{
if (Position > 0) SellMarket();
SellMarket();
}
_prevDiff = diff;
}
}
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 close_cross_ma_strategy(Strategy):
def __init__(self):
super(close_cross_ma_strategy, self).__init__()
self._ma_period = self.Param("MaPeriod", 50) \
.SetDisplay("MA Period", "EMA period", "Parameters")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Candle type", "General")
self._prev_diff = 0.0
self._has_prev = False
@property
def ma_period(self):
return self._ma_period.Value
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(close_cross_ma_strategy, self).OnReseted()
self._prev_diff = 0.0
self._has_prev = False
def OnStarted2(self, time):
super(close_cross_ma_strategy, self).OnStarted2(time)
ema = ExponentialMovingAverage()
ema.Length = self.ma_period
self.SubscribeCandles(self.candle_type).Bind(ema, self.process_candle).Start()
def process_candle(self, candle, ema_val):
if candle.State != CandleStates.Finished:
return
diff = float(candle.ClosePrice) - float(ema_val)
if not self._has_prev:
self._prev_diff = diff
self._has_prev = True
return
if self._prev_diff <= 0 and diff > 0 and self.Position <= 0:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
elif self._prev_diff >= 0 and diff < 0 and self.Position >= 0:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
self._prev_diff = diff
def CreateClone(self):
return close_cross_ma_strategy()