Стратегия X MAN переносит логику советника MetaTrader X_MAN.mq4 на высокоуровневый API StockSharp. Система торгует пробои, опираясь на комбинацию быстрой и медленной линейно-взвешенных скользящих средних (LWMA), фильтрует сигналы по импульсу старшего таймфрейма и подтверждает направление линиями MACD, рассчитанными на месячных свечах. Цель стратегии — подключаться к продолжению тренда, когда структура цены и импульс согласованы.
Логика торговли
Фильтр тренда — быстрая LWMA на основном таймфрейме должна находиться выше медленной (для покупок) или ниже (для продаж) как минимум на величину параметра DistancePoints.
Импульс старшего таймфрейма — стратегия подписывается на свечи более высокого периода и измеряет отклонение импульса от нейтрального уровня 100. За последние три значения должно появиться отклонение, превышающее MomentumBuyThreshold или MomentumSellThreshold в зависимости от направления сделки.
Подтверждение MACD — на месячных свечах считается стандартный MACD (12, 26, 9). Для покупок линия MACD должна быть выше сигнальной, для продаж — ниже.
Исполнение сделок — при выполнении всех фильтров открываются рыночные ордера. Позиция может быть перевёрнута только если появляется противоположный сигнал.
Параметры
Параметр
Описание
CandleType
Основной таймфрейм для LWMA.
HigherCandleType
Таймфрейм для импульсного фильтра.
MacdCandleType
Таймфрейм для MACD (по умолчанию месяц).
FastMaPeriod
Период быстрой LWMA.
SlowMaPeriod
Период медленной LWMA.
MomentumPeriod
Период расчёта импульса.
MomentumBuyThreshold
Минимальное отклонение импульса для покупок.
MomentumSellThreshold
Минимальное отклонение импульса для продаж.
DistancePoints
Минимальная разница между LWMA в пунктах.
TakeProfitPoints
Дистанция тейк-профита в пунктах (опция).
StopLossPoints
Дистанция стоп-лосса в пунктах (опция).
Все параметры реализованы через StrategyParam<T>, поэтому их можно оптимизировать или настраивать в Designer.
Управление рисками
Если заданы положительные значения TakeProfitPoints или StopLossPoints, активируется встроенный защитный модуль StockSharp с рыночными выходами. Дополнительные алгоритмы безубыточности и трейлинга из исходного советника пока не перенесены.
Отличия от оригинала
В MetaTrader-версии присутствовали эквити-стопы, перенос в безубыток и расширенные схемы управления объёмом. В адаптации оставлена только ключевая логика входа.
Подбор объёма позиций возлагается на окружение запуска; ступенчатое увеличение лота не реализовано.
Отправка писем, уведомлений и ручное сопровождение ордеров отсутствуют.
Такой подход делает стратегию компактной и лучше интегрированной с инфраструктурой StockSharp, сохраняя при этом исходную идею торговли по импульсу и тренду.
namespace StockSharp.Samples.Strategies;
using System;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.Messages;
/// <summary>
/// X-MAN strategy: Stochastic + SMA trend filter.
/// </summary>
public class XManStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _smaPeriod;
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public int SmaPeriod { get => _smaPeriod.Value; set => _smaPeriod.Value = value; }
public XManStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(30).TimeFrame())
.SetDisplay("Candle Type", "Candle timeframe", "General");
_smaPeriod = Param(nameof(SmaPeriod), 20)
.SetGreaterThanZero()
.SetDisplay("SMA Period", "SMA period", "Indicators");
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var sma = new SimpleMovingAverage { Length = SmaPeriod };
var rsi = new RelativeStrengthIndex { Length = 14 };
decimal? prevClose = null;
decimal? prevSma = null;
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(sma, rsi, (candle, smaVal, rsiVal) =>
{
if (candle.State != CandleStates.Finished)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
var close = candle.ClosePrice;
if (prevClose.HasValue && prevSma.HasValue)
{
var crossUp = prevClose.Value <= prevSma.Value && close > smaVal;
var crossDown = prevClose.Value >= prevSma.Value && close < smaVal;
if (crossUp && rsiVal < 70 && Position <= 0)
BuyMarket();
else if (crossDown && rsiVal > 30 && Position >= 0)
SellMarket();
}
prevClose = close;
prevSma = smaVal;
})
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, sma);
DrawOwnTrades(area);
}
}
}
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 SimpleMovingAverage, RelativeStrengthIndex
from StockSharp.Algo.Strategies import Strategy
class x_man_strategy(Strategy):
def __init__(self):
super(x_man_strategy, self).__init__()
self._sma_period = self.Param("SmaPeriod", 20) \
.SetDisplay("SMA Period", "SMA period", "Indicators")
self._sma = None
self._rsi = None
self._prev_close = None
self._prev_sma = None
@property
def sma_period(self):
return self._sma_period.Value
def OnReseted(self):
super(x_man_strategy, self).OnReseted()
self._sma = None
self._rsi = None
self._prev_close = None
self._prev_sma = None
def OnStarted2(self, time):
super(x_man_strategy, self).OnStarted2(time)
self._sma = SimpleMovingAverage()
self._sma.Length = self.sma_period
self._rsi = RelativeStrengthIndex()
self._rsi.Length = 14
subscription = self.SubscribeCandles(DataType.TimeFrame(TimeSpan.FromMinutes(30)))
subscription.Bind(self._sma, self._rsi, self._process_candle)
subscription.Start()
def _process_candle(self, candle, sma_value, rsi_value):
if candle.State != CandleStates.Finished:
return
if not self._sma.IsFormed or not self._rsi.IsFormed:
return
close = float(candle.ClosePrice)
sma_val = float(sma_value)
rsi_val = float(rsi_value)
if self._prev_close is not None and self._prev_sma is not None:
cross_up = self._prev_close <= self._prev_sma and close > sma_val
cross_down = self._prev_close >= self._prev_sma and close < sma_val
if cross_up and rsi_val < 70.0 and self.Position <= 0:
self.BuyMarket()
elif cross_down and rsi_val > 30.0 and self.Position >= 0:
self.SellMarket()
self._prev_close = close
self._prev_sma = sma_val
def CreateClone(self):
return x_man_strategy()