Порт советника MetaTrader 4 GLFX на высокоуровневый API StockSharp. При переносе сохранена ключевая идея — проверять сигналы на старшем таймфрейме и открывать сделки только после серии подтверждений, — при этом громоздкие модули с внешними индикаторами были убраны.
Логика торговли
Стратегия работает на основном таймфрейме (по умолчанию M15) и при необходимости строит подтверждающий таймфрейм, поднимаясь по классической лестнице MetaTrader (M15 → M30 → H1 → H4 → D1 → W1 → MN).
RSI старшего таймфрейма (период 57) отслеживает изменение импульса. Покупка разрешается, когда RSI растёт, но ещё не достиг перекупленности. Для продажи требуется, чтобы RSI снижался и при этом оставался выше уровня перепроданности.
Простое скользящее среднее старшего таймфрейма (период 60) показывает отклонение цены от средней. Бычий сигнал возникает, если средняя растёт и находится выше текущего закрытия (откат в восходящем тренде). Медвежий сигнал зеркален.
Каждый включённый фильтр даёт +1 (покупка) или -1 (продажа). Сумма должна достигнуть количества активных фильтров, чтобы сигнал считался валидным. Счётчики хранят число подряд идущих полных сигналов (SignalsRepeat). Если сила сигнала падает ниже порога и опция SignalsReset включена, счётчики сбрасываются.
При отсутствии позиции и разрешённых направлениях следующая завершённая серия подтверждений открывает рыночный ордер с объёмом Volume. Статический стоп и тейк переводятся из пунктов в цены с учётом шага цены инструмента и передаются в StartProtection().
При наличии позиции сильный встречный сигнал может закрыть её досрочно (AllowLongExit / AllowShortExit). В противном случае выход происходит по стопу или тейку.
В порт не вошли дополнительные фильтры оригинала: Quantum, Twitter Sentiment, корреляция баров, тестирование сетов и сложные блоки манименеджмента — они требовали кастомных индикаторов или файловых зависимостей, отсутствующих в StockSharp.
Параметры
Параметр
Значение по умолчанию
Описание
CandleType
M15
Рабочий таймфрейм, на котором принимаются решения.
HigherTimeFrameShift
1
Количество шагов MT4 для построения подтверждающего таймфрейма. 0 — использовать текущий.
UseRsiSignal
true
Включить фильтр RSI на старшем таймфрейме.
RsiPeriod
57
Период RSI.
RsiUpperThreshold
65
Выше этого значения новые покупки запрещены.
RsiLowerThreshold
25
Ниже этого значения новые продажи запрещены.
UseMaSignal
true
Включить фильтр по скользящей средней.
MaPeriod
60
Период скользящей средней.
SignalsRepeat
1
Сколько подряд полных сигналов требуется для входа.
SignalsReset
true
Сбрасывать счётчики, если сила сигнала снижается.
TakeProfitPips
308
Дистанция тейк-профита в пунктах, 0 — без тейка.
StopLossPips
290
Дистанция стоп-лосса в пунктах, 0 — без стопа.
Volume
0.1
Торговый объём (лоты).
AllowLongEntry / AllowShortEntry
true
Разрешения на открытие длинных / коротких позиций.
AllowLongExit / AllowShortExit
true
Разрешения на автоматическое закрытие позиций встречным сигналом.
Рекомендации по использованию
Выбирайте инструменты с корректным шагом цены — для форекс-пар с 3 или 5 знаками шаг автоматически умножается на 10, чтобы соответствовать понятиям «пунктов» в MetaTrader.
Установите HigherTimeFrameShift = 0, если хотите торговать только по одному таймфрейму. В этом случае индикаторы питаются от основного потока свечей, и лишняя подписка не создаётся.
Чтобы повторить поведение «держим позицию до стопа», отключите флаги Allow*Exit.
Системы наращивания объёма, сложные трейлинг-модули и экзотические фильтры выхода из оригинала здесь отсутствуют и могут быть реализованы поверх данной заготовки при необходимости.
Отличия от оригинального советника
Блок
MetaTrader 4
Порт на StockSharp
Подтверждения
RSI, MA, Quantum, TSI, межрыночная корреляция
Только RSI и MA (основная логика)
Входы
Повтор сигналов + временные фильтры
Повтор сигналов + опциональный сброс
Риск
Статический TP/SL + набор трейлингов
Статический TP/SL через StartProtection()
Манименеджмент
Лесенка объёмов, уменьшение после убытков
Фиксированный объём
Внешние зависимости
Кастомные индикаторы, файлы сетов
Отсутствуют
Таким образом, стратегия остаётся узнаваемой — ждёт подтверждения тренда на старшем таймфрейме и входит только после серии согласованных сигналов — и при этом становится компактной и удобной для дальнейшего расширения в экосистеме StockSharp.
using System;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// GLFX strategy: RSI + SMA confirmation for entry.
/// Requires consecutive confirmations before trading.
/// </summary>
public class GlfxStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _rsiPeriod;
private readonly StrategyParam<decimal> _rsiUpper;
private readonly StrategyParam<decimal> _rsiLower;
private readonly StrategyParam<int> _maPeriod;
private readonly StrategyParam<int> _signalsRepeat;
private decimal _prevRsi;
private decimal _prevMa;
private int _buyCount;
private int _sellCount;
private decimal _entryPrice;
public GlfxStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(30).TimeFrame())
.SetDisplay("Candle Type", "Timeframe.", "General");
_rsiPeriod = Param(nameof(RsiPeriod), 14)
.SetDisplay("RSI Period", "RSI period.", "Indicators");
_rsiUpper = Param(nameof(RsiUpper), 65m)
.SetDisplay("RSI Upper", "Overbought level.", "Indicators");
_rsiLower = Param(nameof(RsiLower), 35m)
.SetDisplay("RSI Lower", "Oversold level.", "Indicators");
_maPeriod = Param(nameof(MaPeriod), 60)
.SetDisplay("MA Period", "SMA period.", "Indicators");
_signalsRepeat = Param(nameof(SignalsRepeat), 2)
.SetDisplay("Signals Repeat", "Consecutive confirmations needed.", "Signals");
}
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public int RsiPeriod
{
get => _rsiPeriod.Value;
set => _rsiPeriod.Value = value;
}
public decimal RsiUpper
{
get => _rsiUpper.Value;
set => _rsiUpper.Value = value;
}
public decimal RsiLower
{
get => _rsiLower.Value;
set => _rsiLower.Value = value;
}
public int MaPeriod
{
get => _maPeriod.Value;
set => _maPeriod.Value = value;
}
public int SignalsRepeat
{
get => _signalsRepeat.Value;
set => _signalsRepeat.Value = value;
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevRsi = 0;
_prevMa = 0;
_buyCount = 0;
_sellCount = 0;
_entryPrice = 0;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var rsi = new RelativeStrengthIndex { Length = RsiPeriod };
var ma = new SimpleMovingAverage { Length = MaPeriod };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(rsi, ma, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, ma);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal rsiVal, decimal maVal)
{
if (candle.State != CandleStates.Finished)
return;
if (_prevRsi == 0 || _prevMa == 0)
{
_prevRsi = rsiVal;
_prevMa = maVal;
return;
}
var close = candle.ClosePrice;
// RSI signal: rising and below upper = bullish, falling and above lower = bearish
var rsiSignal = 0;
if (rsiVal > _prevRsi && rsiVal < RsiUpper)
rsiSignal = 1;
else if (rsiVal < _prevRsi && rsiVal > RsiLower)
rsiSignal = -1;
// MA signal: price above rising MA = bullish, below falling MA = bearish
var maSignal = 0;
if (maVal > _prevMa && close > maVal)
maSignal = 1;
else if (maVal < _prevMa && close < maVal)
maSignal = -1;
// Both signals must agree
if (rsiSignal > 0 && maSignal > 0)
{
_buyCount++;
_sellCount = 0;
}
else if (rsiSignal < 0 && maSignal < 0)
{
_sellCount++;
_buyCount = 0;
}
else
{
_buyCount = 0;
_sellCount = 0;
}
// Exit on opposite signal
if (Position > 0 && _sellCount >= SignalsRepeat)
{
SellMarket();
_entryPrice = 0;
_buyCount = 0;
_sellCount = 0;
}
else if (Position < 0 && _buyCount >= SignalsRepeat)
{
BuyMarket();
_entryPrice = 0;
_buyCount = 0;
_sellCount = 0;
}
// Entry after required confirmations
if (Position == 0)
{
if (_buyCount >= SignalsRepeat)
{
_entryPrice = close;
BuyMarket();
_buyCount = 0;
_sellCount = 0;
}
else if (_sellCount >= SignalsRepeat)
{
_entryPrice = close;
SellMarket();
_buyCount = 0;
_sellCount = 0;
}
}
_prevRsi = rsiVal;
_prevMa = maVal;
}
}