Стратегия Monthly Performance Table
Торгует, когда ADX находится между +DI и -DI, а оба отклонения от ADX превышают настраиваемые пороги.
Детали
- Условия входа:
- Лонг, когда |+DI - ADX| ≥
LongDifferenceи |-DI - ADX| ≥LongDifference, а ADX между +DI и -DI. - Шорт, когда |+DI - ADX| ≥
ShortDifferenceи |-DI - ADX| ≥ShortDifference, а ADX между -DI и +DI.
- Лонг, когда |+DI - ADX| ≥
- Длинные/Короткие: Оба.
- Условия выхода: Обратный сигнал.
- Стопы: Нет.
- Значения по умолчанию:
Length= 14LongDifference= 10ShortDifference= 10CandleType= TimeSpan.FromHours(1)
- Фильтры:
- Категория: Trend
- Направление: Оба
- Индикаторы: ADX, DMI
- Стопы: Нет
- Сложность: Базовая
- Таймфрейм: Любой
- Сезонность: Нет
- Нейросети: Нет
- Дивергенция: Нет
- Риск: Средний
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>
/// Strategy based on ADX and DMI difference thresholds.
/// </summary>
public class MonthlyPerformanceTableStrategy : Strategy
{
private readonly StrategyParam<int> _length;
private readonly StrategyParam<decimal> _longDifference;
private readonly StrategyParam<decimal> _shortDifference;
private readonly StrategyParam<DataType> _candleType;
public int Length { get => _length.Value; set => _length.Value = value; }
public decimal LongDifference { get => _longDifference.Value; set => _longDifference.Value = value; }
public decimal ShortDifference { get => _shortDifference.Value; set => _shortDifference.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public MonthlyPerformanceTableStrategy()
{
_length = Param(nameof(Length), 14)
.SetGreaterThanZero()
.SetDisplay("ADX Period", "Period for DMI/ADX", "General");
_longDifference = Param(nameof(LongDifference), 10m)
.SetDisplay("Long Difference", "Minimum diff for longs", "General");
_shortDifference = Param(nameof(ShortDifference), 10m)
.SetDisplay("Short Difference", "Minimum diff for shorts", "General");
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).TimeFrame())
.SetDisplay("Candle Type", "Working candle timeframe", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var dmi = new DirectionalIndex { Length = Length };
var adx = new AverageDirectionalIndex { Length = Length };
var subscription = SubscribeCandles(CandleType);
subscription
.BindEx(dmi, adx, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, IIndicatorValue dmiValue, IIndicatorValue adxValue)
{
if (candle.State != CandleStates.Finished)
return;
if (dmiValue is not DirectionalIndexValue dmiData ||
adxValue is not AverageDirectionalIndexValue adxData)
return;
if (dmiData.Plus is not decimal diPlus ||
dmiData.Minus is not decimal diMinus ||
adxData.MovingAverage is not decimal adx)
return;
var diff2 = Math.Abs(diPlus - adx);
var diff3 = Math.Abs(diMinus - adx);
var buyCond = diff2 >= LongDifference && diff3 >= LongDifference && adx < diPlus && adx > diMinus;
var sellCond = diff2 >= ShortDifference && diff3 >= ShortDifference && adx > diPlus && adx < diMinus;
if (buyCond && Position <= 0)
BuyMarket(Volume + Math.Abs(Position));
else if (sellCond && Position >= 0)
SellMarket(Volume + Math.Abs(Position));
}
}
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 AverageDirectionalIndex
from StockSharp.Algo.Strategies import Strategy
class monthly_performance_table_strategy(Strategy):
def __init__(self):
super(monthly_performance_table_strategy, self).__init__()
self._length = self.Param("Length", 14) \
.SetGreaterThanZero() \
.SetDisplay("ADX Period", "Period for DMI/ADX", "General")
self._long_difference = self.Param("LongDifference", 10.0) \
.SetDisplay("Long Difference", "Minimum diff for longs", "General")
self._short_difference = self.Param("ShortDifference", 10.0) \
.SetDisplay("Short Difference", "Minimum diff for shorts", "General")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(1))) \
.SetDisplay("Candle Type", "Working candle timeframe", "General")
@property
def candle_type(self):
return self._candle_type.Value
@candle_type.setter
def candle_type(self, value):
self._candle_type.Value = value
def OnReseted(self):
super(monthly_performance_table_strategy, self).OnReseted()
def OnStarted2(self, time):
super(monthly_performance_table_strategy, self).OnStarted2(time)
self._adx = AverageDirectionalIndex()
self._adx.Length = self._length.Value
subscription = self.SubscribeCandles(self.candle_type)
subscription.BindEx(self._adx, self.OnProcess).Start()
def OnProcess(self, candle, adx_value):
if candle.State != CandleStates.Finished:
return
if not self._adx.IsFormed:
return
adx_val = adx_value
adx_mv = adx_val.MovingAverage
di_plus = adx_val.Dx.Plus
di_minus = adx_val.Dx.Minus
if adx_mv is None or di_plus is None or di_minus is None:
return
adx = float(adx_mv)
dip = float(di_plus)
dim = float(di_minus)
diff2 = abs(dip - adx)
diff3 = abs(dim - adx)
ld = float(self._long_difference.Value)
sd = float(self._short_difference.Value)
buy_cond = diff2 >= ld and diff3 >= ld and adx < dip and adx > dim
sell_cond = diff2 >= sd and diff3 >= sd and adx > dip and adx < dim
if buy_cond and self.Position <= 0:
self.BuyMarket()
elif sell_cond and self.Position >= 0:
self.SellMarket()
def CreateClone(self):
return monthly_performance_table_strategy()