diff --git a/API/2324_RAVI_Histogram/CS/RaviHistogramStrategy.cs b/API/2324_RAVI_Histogram/CS/RaviHistogramStrategy.cs new file mode 100644 index 000000000..172f45c1e --- /dev/null +++ b/API/2324_RAVI_Histogram/CS/RaviHistogramStrategy.cs @@ -0,0 +1,123 @@ +using System; +using System.Collections.Generic; + +using StockSharp.Algo.Indicators; +using StockSharp.Algo.Strategies; +using StockSharp.BusinessEntities; +using StockSharp.Messages; + +namespace StockSharp.Samples.Strategies; + +/// +/// RAVI Histogram trend strategy based on fast and slow EMA difference. +/// +public class RaviHistogramStrategy : Strategy +{ + private readonly StrategyParam _fastLength; + private readonly StrategyParam _slowLength; + private readonly StrategyParam _upLevel; + private readonly StrategyParam _downLevel; + private readonly StrategyParam _buyOpen; + private readonly StrategyParam _sellOpen; + private readonly StrategyParam _buyClose; + private readonly StrategyParam _sellClose; + private readonly StrategyParam _candleType; + + private decimal _prevRavi; + private bool _isFirst = true; + + public int FastLength { get => _fastLength.Value; set => _fastLength.Value = value; } + public int SlowLength { get => _slowLength.Value; set => _slowLength.Value = value; } + public decimal UpLevel { get => _upLevel.Value; set => _upLevel.Value = value; } + public decimal DownLevel { get => _downLevel.Value; set => _downLevel.Value = value; } + public bool BuyOpen { get => _buyOpen.Value; set => _buyOpen.Value = value; } + public bool SellOpen { get => _sellOpen.Value; set => _sellOpen.Value = value; } + public bool BuyClose { get => _buyClose.Value; set => _buyClose.Value = value; } + public bool SellClose { get => _sellClose.Value; set => _sellClose.Value = value; } + public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; } + + public RaviHistogramStrategy() + { + _fastLength = Param(nameof(FastLength), 7) + .SetGreaterThanZero() + .SetDisplay("Fast Length", "Fast EMA length", "General"); + + _slowLength = Param(nameof(SlowLength), 65) + .SetGreaterThanZero() + .SetDisplay("Slow Length", "Slow EMA length", "General"); + + _upLevel = Param(nameof(UpLevel), 0.1m) + .SetDisplay("Upper Level", "Upper threshold for trend", "General"); + + _downLevel = Param(nameof(DownLevel), -0.1m) + .SetDisplay("Lower Level", "Lower threshold for trend", "General"); + + _buyOpen = Param(nameof(BuyOpen), true) + .SetDisplay("Open Long", "Allow opening long positions", "Trading"); + + _sellOpen = Param(nameof(SellOpen), true) + .SetDisplay("Open Short", "Allow opening short positions", "Trading"); + + _buyClose = Param(nameof(BuyClose), true) + .SetDisplay("Close Long", "Allow closing long positions", "Trading"); + + _sellClose = Param(nameof(SellClose), true) + .SetDisplay("Close Short", "Allow closing short positions", "Trading"); + + _candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame()) + .SetDisplay("Candle Type", "Type of candles", "General"); + } + + public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities() + { + return [(Security, CandleType)]; + } + + protected override void OnStarted(DateTimeOffset time) + { + base.OnStarted(time); + + var fast = new EMA { Length = FastLength }; + var slow = new EMA { Length = SlowLength }; + + // Subscribe to candle data and bind indicators. + var subscription = SubscribeCandles(CandleType); + subscription.Bind(fast, slow, ProcessCandle).Start(); + } + + private void ProcessCandle(ICandleMessage candle, decimal fast, decimal slow) + { + if (candle.State != CandleStates.Finished || slow == 0) + return; + + // Calculate RAVI value from EMA difference. + var ravi = 100m * (fast - slow) / slow; + + if (_isFirst) + { + _prevRavi = ravi; + _isFirst = false; + return; + } + + // Handle signals when RAVI crosses thresholds. + if (ravi > UpLevel) + { + if (SellClose && Position < 0) + BuyMarket(); + + if (BuyOpen && _prevRavi <= UpLevel && Position <= 0) + BuyMarket(); + } + else if (ravi < DownLevel) + { + if (BuyClose && Position > 0) + SellMarket(); + + if (SellOpen && _prevRavi >= DownLevel && Position >= 0) + SellMarket(); + } + + _prevRavi = ravi; + } +} diff --git a/API/2324_RAVI_Histogram/README.md b/API/2324_RAVI_Histogram/README.md new file mode 100644 index 000000000..3679f85ec --- /dev/null +++ b/API/2324_RAVI_Histogram/README.md @@ -0,0 +1,22 @@ +# RAVI Histogram Strategy +[Русский](README_ru.md) | [中文](README_cn.md) + +This strategy converts the MetaTrader RAVI Histogram expert to StockSharp. It measures trend strength as the percentage difference between a fast and a slow EMA. The result is compared with upper and lower levels to decide when to trade. + +When the RAVI value rises above the upper level the market is considered bullish. Short positions are closed and, if enabled, a long position is opened. When the value falls below the lower level the strategy closes longs and may open a short. By default it operates on four‑hour candles. + +## Details + +- **Entry Criteria**: + - **Long**: RAVI crosses upward through `UpLevel`. + - **Short**: RAVI crosses downward through `DownLevel`. +- **Long/Short**: Both. +- **Exit Criteria**: + - Opposite RAVI signal closes existing positions. +- **Stops**: None. +- **Filters**: None. +- **Timeframe**: 4‑hour candles by default. +- **Parameters**: + - `FastLength` and `SlowLength` – EMA periods for RAVI calculation. + - `UpLevel` and `DownLevel` – thresholds defining trending zones. + - `BuyOpen`, `SellOpen`, `BuyClose`, `SellClose` – enable or disable operations in each direction. diff --git a/API/2324_RAVI_Histogram/README_cn.md b/API/2324_RAVI_Histogram/README_cn.md new file mode 100644 index 000000000..ae353f879 --- /dev/null +++ b/API/2324_RAVI_Histogram/README_cn.md @@ -0,0 +1,22 @@ +# RAVI Histogram 策略 +[English](README.md) | [Русский](README_ru.md) + +该策略将 MetaTrader 的 RAVI Histogram 专家移植到 StockSharp。RAVI 指标通过比较快 EMA 与慢 EMA 的百分比差异来衡量趋势强度,并与上下阈值比较以决定交易。 + +当 RAVI 高于上限时,被视为多头趋势:若允许,将平掉空头并开多。当 RAVI 低于下限时,策略关闭多头并可开空。默认使用四小时 K 线。 + +## 细节 + +- **入场条件**: + - **多头**:RAVI 向上突破 `UpLevel`。 + - **空头**:RAVI 向下跌破 `DownLevel`。 +- **方向**:可做多也可做空。 +- **出场条件**: + - RAVI 产生相反信号时平仓。 +- **止损**:无。 +- **过滤器**:无。 +- **时间框架**:默认 4 小时。 +- **参数**: + - `FastLength` 与 `SlowLength` — 用于计算 RAVI 的 EMA 周期。 + - `UpLevel` 与 `DownLevel` — 定义趋势区域的阈值。 + - `BuyOpen`、`SellOpen`、`BuyClose`、`SellClose` — 各方向操作的开关。 diff --git a/API/2324_RAVI_Histogram/README_ru.md b/API/2324_RAVI_Histogram/README_ru.md new file mode 100644 index 000000000..149059ca3 --- /dev/null +++ b/API/2324_RAVI_Histogram/README_ru.md @@ -0,0 +1,22 @@ +# Стратегия RAVI Histogram +[English](README.md) | [中文](README_cn.md) + +Эта стратегия представляет собой перенос эксперта MetaTrader RAVI Histogram в StockSharp. Индикатор RAVI измеряет силу тренда как процентное различие между быстрой и медленной EMA. Полученное значение сравнивается с верхним и нижним уровнями для принятия торговых решений. + +Когда RAVI поднимается выше верхнего уровня, рынок считается растущим: короткие позиции закрываются и, при разрешении, открывается длинная. Когда значение опускается ниже нижнего уровня, стратегия закрывает длинные позиции и может открыть короткую. По умолчанию используется четырёхчасовой таймфрейм. + +## Подробности + +- **Условия входа**: + - **Long**: RAVI пересекает `UpLevel` снизу вверх. + - **Short**: RAVI пересекает `DownLevel` сверху вниз. +- **Направления**: длинные и короткие. +- **Условия выхода**: + - Противоположный сигнал RAVI закрывает текущие позиции. +- **Стопы**: отсутствуют. +- **Фильтры**: отсутствуют. +- **Таймфрейм**: по умолчанию 4-часовые свечи. +- **Параметры**: + - `FastLength` и `SlowLength` – периоды EMA для расчёта RAVI. + - `UpLevel` и `DownLevel` – пороги, определяющие зоны тренда. + - `BuyOpen`, `SellOpen`, `BuyClose`, `SellClose` – разрешение операций в каждую сторону.