Skip to content

Commit f730470

Browse files
authored
Add ADX DMI crossover strategy (#2271)
1 parent f22b80a commit f730470

File tree

4 files changed

+234
-0
lines changed

4 files changed

+234
-0
lines changed

API/2303_ADX_DMI/CS/AdxDmiStrategy.cs

Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,156 @@
1+
namespace StockSharp.Samples.Strategies;
2+
3+
using System;
4+
using System.Collections.Generic;
5+
6+
using StockSharp.Algo;
7+
using StockSharp.Algo.Indicators;
8+
using StockSharp.Algo.Strategies;
9+
using StockSharp.BusinessEntities;
10+
using StockSharp.Messages;
11+
12+
/// <summary>
13+
/// Directional Movement Index crossover strategy.
14+
/// </summary>
15+
public class AdxDmiStrategy : Strategy
16+
{
17+
private readonly StrategyParam<DataType> _candleTypeParam;
18+
private readonly StrategyParam<int> _dmiPeriod;
19+
private readonly StrategyParam<bool> _allowLong;
20+
private readonly StrategyParam<bool> _allowShort;
21+
private readonly StrategyParam<bool> _closeLong;
22+
private readonly StrategyParam<bool> _closeShort;
23+
24+
private DirectionalIndex _dmi = null!;
25+
private decimal? _prevPlus;
26+
private decimal? _prevMinus;
27+
28+
public AdxDmiStrategy()
29+
{
30+
_candleTypeParam = Param(nameof(CandleType), TimeSpan.FromHours(8).TimeFrame())
31+
.SetDisplay("Candle Type", "Time frame for strategy calculation", "General");
32+
33+
_dmiPeriod = Param(nameof(DmiPeriod), 14)
34+
.SetDisplay("DMI Period", "Directional Movement Index period", "Indicators")
35+
.SetGreaterThanZero();
36+
37+
_allowLong = Param(nameof(AllowLong), true)
38+
.SetDisplay("Allow Long", "Enable long entries", "Trading");
39+
40+
_allowShort = Param(nameof(AllowShort), true)
41+
.SetDisplay("Allow Short", "Enable short entries", "Trading");
42+
43+
_closeLong = Param(nameof(CloseLong), true)
44+
.SetDisplay("Close Long", "Close long positions on opposite signal", "Trading");
45+
46+
_closeShort = Param(nameof(CloseShort), true)
47+
.SetDisplay("Close Short", "Close short positions on opposite signal", "Trading");
48+
}
49+
50+
public DataType CandleType
51+
{
52+
get => _candleTypeParam.Value;
53+
set => _candleTypeParam.Value = value;
54+
}
55+
56+
public int DmiPeriod
57+
{
58+
get => _dmiPeriod.Value;
59+
set => _dmiPeriod.Value = value;
60+
}
61+
62+
public bool AllowLong
63+
{
64+
get => _allowLong.Value;
65+
set => _allowLong.Value = value;
66+
}
67+
68+
public bool AllowShort
69+
{
70+
get => _allowShort.Value;
71+
set => _allowShort.Value = value;
72+
}
73+
74+
public bool CloseLong
75+
{
76+
get => _closeLong.Value;
77+
set => _closeLong.Value = value;
78+
}
79+
80+
public bool CloseShort
81+
{
82+
get => _closeShort.Value;
83+
set => _closeShort.Value = value;
84+
}
85+
86+
/// <inheritdoc />
87+
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
88+
=> [(Security, CandleType)];
89+
90+
/// <inheritdoc />
91+
protected override void OnStarted(DateTimeOffset time)
92+
{
93+
base.OnStarted(time);
94+
95+
_dmi = new DirectionalIndex
96+
{
97+
Length = DmiPeriod
98+
};
99+
100+
var subscription = SubscribeCandles(CandleType);
101+
subscription
102+
.BindEx(_dmi, ProcessCandle)
103+
.Start();
104+
105+
var area = CreateChartArea();
106+
if (area != null)
107+
{
108+
DrawCandles(area, subscription);
109+
DrawIndicator(area, _dmi);
110+
DrawOwnTrades(area);
111+
}
112+
}
113+
114+
private void ProcessCandle(ICandleMessage candle, IIndicatorValue dmiValue)
115+
{
116+
if (candle.State != CandleStates.Finished)
117+
return;
118+
119+
var dmi = (DirectionalIndexValue)dmiValue;
120+
121+
if (dmi.Plus is not decimal currentPlus ||
122+
dmi.Minus is not decimal currentMinus)
123+
return;
124+
125+
if (_prevPlus is null || _prevMinus is null)
126+
{
127+
_prevPlus = currentPlus;
128+
_prevMinus = currentMinus;
129+
return;
130+
}
131+
132+
var buySignal = _prevMinus > _prevPlus && currentMinus <= currentPlus;
133+
var sellSignal = _prevPlus > _prevMinus && currentPlus <= currentMinus;
134+
135+
if (buySignal)
136+
{
137+
if (CloseShort && Position < 0)
138+
BuyMarket(Math.Abs(Position));
139+
140+
if (AllowLong && Position <= 0)
141+
BuyMarket(Volume);
142+
}
143+
144+
if (sellSignal)
145+
{
146+
if (CloseLong && Position > 0)
147+
SellMarket(Position);
148+
149+
if (AllowShort && Position >= 0)
150+
SellMarket(Volume);
151+
}
152+
153+
_prevPlus = currentPlus;
154+
_prevMinus = currentMinus;
155+
}
156+
}

API/2303_ADX_DMI/README.md

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
# ADX DMI Strategy
2+
[Русский](README_ru.md) | [中文](README_cn.md)
3+
4+
Uses the Directional Movement Index (DMI) to trade crossovers between the +DI and -DI lines. When -DI moves above +DI and then drops below it, the strategy opens a long position. When +DI rises above -DI and then falls back below, it opens a short position. Opposite signals can optionally close existing positions.
5+
6+
## Details
7+
8+
- **Entry Criteria**:
9+
- **Long**: -DI was above +DI on the previous bar and crosses below it on the latest bar.
10+
- **Short**: +DI was above -DI on the previous bar and crosses below it on the latest bar.
11+
- **Exit Criteria**:
12+
- Reverse crossover if corresponding close option is enabled.
13+
- **Indicators**:
14+
- Directional Index (period 14 by default)
15+
- **Stops**: none by default.
16+
- **Default Values**:
17+
- `DmiPeriod` = 14
18+
- `AllowLong` = true
19+
- `AllowShort` = true
20+
- `CloseLong` = true
21+
- `CloseShort` = true
22+
- **Filters**:
23+
- Works on any timeframe
24+
- Indicators: DMI
25+
- Stops: optional via external risk management
26+
- Complexity: basic

API/2303_ADX_DMI/README_cn.md

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
# ADX DMI 策略
2+
[English](README.md) | [Русский](README_ru.md)
3+
4+
使用方向移动指数(DMI)交易 +DI 与 -DI 线的交叉。当上一根K线的 -DI 高于 +DI 而当前K线跌破 +DI 时,策略开多仓。上一根K线的 +DI 高于 -DI 而当前K线跌破 -DI 时,策略开空仓。反向信号可选择性关闭已有仓位。
5+
6+
## 详情
7+
8+
- **入场条件**
9+
- **多头**:上一根 -DI > +DI,当前 -DI 下穿 +DI。
10+
- **空头**:上一根 +DI > -DI,当前 +DI 下穿 -DI。
11+
- **出场条件**
12+
- 反向交叉(若启用相应的平仓选项)。
13+
- **指标**
14+
- Directional Index(默认周期 14)
15+
- **止损**:默认无。
16+
- **默认值**
17+
- `DmiPeriod` = 14
18+
- `AllowLong` = true
19+
- `AllowShort` = true
20+
- `CloseLong` = true
21+
- `CloseShort` = true
22+
- **过滤条件**
23+
- 适用于任何时间周期
24+
- 指标:DMI
25+
- 止损:可通过外部风控模块设置
26+
- 复杂度:基础

API/2303_ADX_DMI/README_ru.md

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
# Стратегия ADX DMI
2+
[English](README.md) | [中文](README_cn.md)
3+
4+
Использует Directional Movement Index (DMI) для торговли пересечениями линий +DI и -DI. Когда -DI находился выше +DI на предыдущей свече и опускается ниже на текущей, стратегия открывает длинную позицию. Когда +DI был выше -DI и опускается ниже, открывается короткая позиция. Обратные сигналы по желанию закрывают открытые позиции.
5+
6+
## Детали
7+
8+
- **Условия входа**:
9+
- **Лонг**: -DI был выше +DI на предыдущей свече и пересекает её сверху вниз на текущей.
10+
- **Шорт**: +DI был выше -DI на предыдущей свече и пересекает её сверху вниз на текущей.
11+
- **Условия выхода**:
12+
- Обратное пересечение при включённой соответствующей опции закрытия.
13+
- **Индикаторы**:
14+
- Directional Index (период по умолчанию 14)
15+
- **Стопы**: отсутствуют по умолчанию.
16+
- **Значения по умолчанию**:
17+
- `DmiPeriod` = 14
18+
- `AllowLong` = true
19+
- `AllowShort` = true
20+
- `CloseLong` = true
21+
- `CloseShort` = true
22+
- **Фильтры**:
23+
- Работает на любых таймфреймах
24+
- Индикаторы: DMI
25+
- Стопы: опционально через внешнее управление рисками
26+
- Сложность: базовая

0 commit comments

Comments
 (0)