Главная
/
Примеры стратегий
Открыть на GitHub
Стратегия Wedge Pattern
Обзор
Wedge Pattern Strategy — это перенос советника MetaTrader Wedge pattern.mq4 на высокоуровневый API StockSharp. Стратегия находит симметричные «клины», построенные по фракталам Билла Вильямса, и торгует их пробой при совпадении трендовых и моментум-фильтров.
Высокоуровневая реализация сохраняет логику принятия решений, но использует стандартные механизмы StockSharp:
Трендовый фильтр — сравнение быстрой и медленной LWMA по типичной цене.
Фильтр моментума — проверка абсолютного отклонения 14-периодного индикатора Momentum от уровня 100; из трёх последних значений хотя бы одно должно превышать порог.
MACD-подтверждение — для покупок линия MACD должна быть выше сигнальной, для продаж ниже.
Определение клина по фракталам — последние два верхних и нижних фрактала образуют сходящиеся трендовые линии; сигнал появляется при закрытии свечи за пределами линий плюс буфер подтверждения.
Риск-менеджмент — фиксированные стоп и тейк, автоматический переход в безубыток и последующий трейлинг стопа.
Алгоритм работы
Подписка на свечи с периодом, указанным в параметре CandleType.
После закрытия каждой свечи пересчитываются индикаторы и обновляются буферы максимумов/минимумов для поиска новых фракталов.
Из двух последних фракталов по максимумам и минимумам строятся линии клина. Учитываются только сходящиеся конструкции (понижающиеся хай и повышающийся лой).
Покупка выполняется, если:
Быстрая LWMA выше медленной.
Линия MACD выше сигнальной.
Хотя бы одно из трёх последних значений Momentum превышает порог.
Закрытие свечи выше верхней линии клина на величину буфера.
Условия для продаж зеркальны.
После входа выставляются стоп-лосс и тейк-профит; далее стоп может быть переведён в безубыток и подтягивается трейлингом.
Параметры
Параметр
Описание
CandleType
Используемый таймфрейм.
FastMaPeriod / SlowMaPeriod
Периоды быстрых и медленных LWMA.
MomentumPeriod
Период индикатора Momentum.
MomentumThreshold
Минимальное требуемое отклонение Momentuм от 100.
MacdFastPeriod / MacdSlowPeriod / MacdSignalPeriod
Настройки MACD.
FractalDepth
Количество баров по обе стороны для подтверждения фрактала.
StopLossPips / TakeProfitPips
Размеры стопа и тейка в пунктах.
UseBreakeven, BreakevenTriggerPips, BreakevenOffsetPips
Параметры перевода в безубыток.
UseTrailing, TrailingActivationPips, TrailingDistancePips, TrailingStepPips
Настройки трейлинг-стопа.
BreakoutBufferPips
Дополнительный буфер для подтверждения пробоя.
Все значения в пунктах автоматически переводятся в ценовые расстояния с учётом шага цены инструмента, включая дробные котировки (3 или 5 знаков).
Рекомендации по использованию
Выберите инструмент и задайте соответствующий таймфрейм через CandleType (например, 15-минутные свечи).
Настройте размер позиции через свойство Strategy.Volume.
При необходимости адаптируйте фильтры и уровни риска под волатильность инструмента.
Запустите стратегию — она подпишется на данные, отрисует график и начнёт торговать пробои клиньев.
Используются методы SubscribeCandles и привязка индикаторов вместо ручной обработки тиков.
Управление защитными ордерами реализовано через SetStopLoss/SetTakeProfit, что упрощает интеграцию с защитными механизмами StockSharp.
Поддерживается только одна совокупная позиция; в MQL-версии допускалось наращивание серии сделок.
Убраны сервисные уведомления (Alert, Email, Push); при необходимости их можно реализовать отдельно.
В остальном логика входов и сопровождения позиций соответствует оригинальному советнику, но реализована средствами StockSharp.
using System;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Wedge Pattern strategy: WMA crossover + Momentum.
/// Buys when fast WMA crosses above slow WMA and momentum > 100.
/// Sells on cross below with momentum < 100.
/// </summary>
public class WedgePatternStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _fastPeriod;
private readonly StrategyParam<int> _slowPeriod;
private readonly StrategyParam<int> _momPeriod;
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public int FastPeriod
{
get => _fastPeriod.Value;
set => _fastPeriod.Value = value;
}
public int SlowPeriod
{
get => _slowPeriod.Value;
set => _slowPeriod.Value = value;
}
public int MomPeriod
{
get => _momPeriod.Value;
set => _momPeriod.Value = value;
}
public WedgePatternStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(15).TimeFrame())
.SetDisplay("Candle Type", "Candle timeframe", "General");
_fastPeriod = Param(nameof(FastPeriod), 14)
.SetGreaterThanZero()
.SetDisplay("Fast WMA", "Fast WMA period", "Indicators");
_slowPeriod = Param(nameof(SlowPeriod), 40)
.SetGreaterThanZero()
.SetDisplay("Slow WMA", "Slow WMA period", "Indicators");
_momPeriod = Param(nameof(MomPeriod), 14)
.SetGreaterThanZero()
.SetDisplay("Momentum", "Momentum period", "Indicators");
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var fast = new WeightedMovingAverage { Length = FastPeriod };
var slow = new WeightedMovingAverage { Length = SlowPeriod };
var mom = new Momentum { Length = MomPeriod };
decimal? prevFast = null;
decimal? prevSlow = null;
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(fast, slow, mom, (candle, fastVal, slowVal, momVal) =>
{
if (candle.State != CandleStates.Finished)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
if (prevFast.HasValue && prevSlow.HasValue)
{
var crossUp = prevFast.Value <= prevSlow.Value && fastVal > slowVal;
var crossDown = prevFast.Value >= prevSlow.Value && fastVal < slowVal;
if (crossUp && momVal > 100m && Position <= 0)
BuyMarket();
else if (crossDown && momVal < 100m && Position >= 0)
SellMarket();
}
prevFast = fastVal;
prevSlow = slowVal;
})
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, fast);
DrawIndicator(area, slow);
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 WeightedMovingAverage, Momentum
from StockSharp.Algo.Strategies import Strategy
class wedge_pattern_strategy(Strategy):
def __init__(self):
super(wedge_pattern_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(15))) \
.SetDisplay("Candle Type", "Candle timeframe", "General")
self._fast_period = self.Param("FastPeriod", 14) \
.SetGreaterThanZero() \
.SetDisplay("Fast WMA", "Fast WMA period", "Indicators")
self._slow_period = self.Param("SlowPeriod", 40) \
.SetGreaterThanZero() \
.SetDisplay("Slow WMA", "Slow WMA period", "Indicators")
self._mom_period = self.Param("MomPeriod", 14) \
.SetGreaterThanZero() \
.SetDisplay("Momentum", "Momentum period", "Indicators")
self._prev_fast = None
self._prev_slow = None
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(wedge_pattern_strategy, self).OnReseted()
self._prev_fast = None
self._prev_slow = None
def OnStarted2(self, time):
super(wedge_pattern_strategy, self).OnStarted2(time)
self._fast_ind = WeightedMovingAverage()
self._fast_ind.Length = self._fast_period.Value
self._slow_ind = WeightedMovingAverage()
self._slow_ind.Length = self._slow_period.Value
self._mom_ind = Momentum()
self._mom_ind.Length = self._mom_period.Value
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(self._fast_ind, self._slow_ind, self._mom_ind, self._process_candle).Start()
def _process_candle(self, candle, fast_value, slow_value, mom_value):
if candle.State != CandleStates.Finished:
return
if not self.IsFormedAndOnlineAndAllowTrading():
return
fast_val = float(fast_value)
slow_val = float(slow_value)
mom_val = float(mom_value)
if self._prev_fast is not None and self._prev_slow is not None:
cross_up = self._prev_fast <= self._prev_slow and fast_val > slow_val
cross_down = self._prev_fast >= self._prev_slow and fast_val < slow_val
if cross_up and mom_val > 100.0 and self.Position <= 0:
self.BuyMarket()
elif cross_down and mom_val < 100.0 and self.Position >= 0:
self.SellMarket()
self._prev_fast = fast_val
self._prev_slow = slow_val
def CreateClone(self):
return wedge_pattern_strategy()