DeMarker Sign Strategy
This strategy uses the DeMarker oscillator to detect potential trend reversals. On each completed candle (4-hour timeframe by default), the DeMarker value is compared to configurable upper and lower thresholds. When the oscillator rises above the lower threshold (0.3 by default), the strategy enters a long position and closes any short position. When the oscillator falls below the upper threshold (0.7 by default), it enters a short position and closes any long position. Positions are held until an opposite signal appears.
Details
- Entry Criteria:
- Long: DeMarker crosses upward through the lower level.
- Short: DeMarker crosses downward through the upper level.
- Long/Short: Both.
- Exit Criteria: Opposite signal.
- Stops: None by default.
- Filters: None.
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>
/// Strategy based on DeMarker oscillator crossing predefined levels.
/// </summary>
public class DeMarkerSignStrategy : Strategy
{
private readonly StrategyParam<int> _deMarkerPeriod;
private readonly StrategyParam<decimal> _upLevel;
private readonly StrategyParam<decimal> _downLevel;
private readonly StrategyParam<DataType> _candleType;
private decimal? _prevDeMarker;
public int DeMarkerPeriod { get => _deMarkerPeriod.Value; set => _deMarkerPeriod.Value = value; }
public decimal UpLevel { get => _upLevel.Value; set => _upLevel.Value = value; }
public decimal DownLevel { get => _downLevel.Value; set => _downLevel.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public DeMarkerSignStrategy()
{
_deMarkerPeriod = Param(nameof(DeMarkerPeriod), 14)
.SetDisplay("DeMarker Period", "Indicator period", "General");
_upLevel = Param(nameof(UpLevel), 0.7m)
.SetDisplay("Upper Level", "Sell when DeMarker falls below", "General");
_downLevel = Param(nameof(DownLevel), 0.3m)
.SetDisplay("Lower Level", "Buy when DeMarker rises above", "General");
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Timeframe for candles", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevDeMarker = null;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_prevDeMarker = null;
var deMarker = new DeMarker { Length = DeMarkerPeriod };
var subscription = SubscribeCandles(CandleType);
subscription.Bind(deMarker, ProcessCandle).Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, deMarker);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal deMarker)
{
if (candle.State != CandleStates.Finished)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
if (_prevDeMarker is null)
{
_prevDeMarker = deMarker;
return;
}
// DeMarker crosses above lower level -> buy
if (deMarker > DownLevel && _prevDeMarker <= DownLevel && Position <= 0)
BuyMarket();
// DeMarker crosses below upper level -> sell
else if (deMarker < UpLevel && _prevDeMarker >= UpLevel && Position >= 0)
SellMarket();
_prevDeMarker = deMarker;
}
}
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 DeMarker
from StockSharp.Algo.Strategies import Strategy
class de_marker_sign_strategy(Strategy):
def __init__(self):
super(de_marker_sign_strategy, self).__init__()
self._de_marker_period = self.Param("DeMarkerPeriod", 14) \
.SetDisplay("DeMarker Period", "Indicator period", "General")
self._up_level = self.Param("UpLevel", 0.7) \
.SetDisplay("Upper Level", "Sell when DeMarker falls below", "General")
self._down_level = self.Param("DownLevel", 0.3) \
.SetDisplay("Lower Level", "Buy when DeMarker rises above", "General")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Timeframe for candles", "General")
self._prev_de_marker = None
@property
def de_marker_period(self):
return self._de_marker_period.Value
@property
def up_level(self):
return self._up_level.Value
@property
def down_level(self):
return self._down_level.Value
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(de_marker_sign_strategy, self).OnReseted()
self._prev_de_marker = None
def OnStarted2(self, time):
super(de_marker_sign_strategy, self).OnStarted2(time)
self._prev_de_marker = None
de_marker = DeMarker()
de_marker.Length = self.de_marker_period
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(de_marker, self.process_candle).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, de_marker)
self.DrawOwnTrades(area)
def process_candle(self, candle, de_marker):
if candle.State != CandleStates.Finished:
return
de_marker = float(de_marker)
if self._prev_de_marker is None:
self._prev_de_marker = de_marker
return
down_lvl = float(self.down_level)
up_lvl = float(self.up_level)
if de_marker > down_lvl and self._prev_de_marker <= down_lvl and self.Position <= 0:
self.BuyMarket()
elif de_marker < up_lvl and self._prev_de_marker >= up_lvl and self.Position >= 0:
self.SellMarket()
self._prev_de_marker = de_marker
def CreateClone(self):
return de_marker_sign_strategy()