Стратегия Above Below MA повторяет логику советника MetaTrader Above Below MA (barabashkakvn's edition). Она оценивает, насколько далеко текущая цена находится по «неправильную» сторону от настраиваемой скользящей средней, и допускает сделки только если цена удалена от средней не меньше заданного порога и сама средняя разворачивается в ожидаемом направлении. Реализация использует высокоуровневый API StockSharp и работает исключительно по завершённым свечам.
Общая информация
Рынки: Инструменты, склонные возвращаться к скользящей средней перед продолжением тренда.
Инструменты: Любые, поддерживаемые подключением StockSharp. Наибольшую пользу получают валютные пары, так как исходная версия измеряла расстояние в пунктах.
Таймфрейм: Настраивается параметром Candle Type (по умолчанию минутные свечи).
Направления: Разрешены длинные и короткие позиции, но одновременно может существовать только одна чистая позиция.
Логика работы
Рассчитывается скользящая средняя по выбранной серии свечей. Тип усреднения (SMA, EMA, SMMA, WMA), источник цены (close, open, high, low, median, typical, weighted) и смещение полностью повторяют параметры MetaTrader.
Минимальная дистанция в пунктах переводится в цену через PriceStep инструмента. Если шаг цены недоступен, фильтр автоматически отключается.
Для каждой завершённой свечи выполняются проверки:
Сигнал на покупку:
Цена открытия и закрытия свечи находятся не ближе заданной дистанции ниже смещённой средней.
Текущее значение средней выше предыдущего (средняя растёт).
Сигнал на продажу:
Открытие и закрытие располагаются минимум на заданную дистанцию выше смещённой средней.
Текущее значение средней ниже предыдущего (средняя снижается).
Перед открытием новой сделки стратегия закрывает противоположную позицию и отправляет рыночный ордер в направлении сигнала.
Все решения принимаются только по закрытым свечам, чтобы исключить многократные входы внутри формирующегося бара. Заявки отправляются методами BuyMarket и SellMarket с установленным объёмом.
Параметры
Параметр
Описание
MaPeriod
Период скользящей средней. По умолчанию 6.
MaShift
Смещение средней вперёд на n свечей. 0 — текущее значение, n — значение n свечей назад. По умолчанию 0.
MaMethod
Тип средней: Simple, Exponential, Smoothed, Weighted. По умолчанию Exponential.
AppliedPrice
Источник цены: close, open, high, low, median, typical или weighted. По умолчанию Typical.
MinimumDistancePips
Минимальная дистанция в пунктах между ценой свечи и средней. Переводится через PriceStep. По умолчанию 5.
CandleType
Тип свечей, по которым выполняются расчёты. По умолчанию минутные свечи.
TradeVolume
Объём новой позиции. По умолчанию 1.
Дополнительные замечания
В стратегию не встроены стоп-лосс и тейк-профит. Управление рисками следует реализовывать отдельными механизмами.
Буфер для смещения средней хранит только необходимые значения и не нарушает требование «без собственных коллекций».
Если PriceStep отсутствует, фильтр по дистанции игнорируется, и решения принимаются только по наклону и положению средней.
При наличии окна графика отображаются свечи, сама скользящая средняя и сделки стратегии.
using System;
using System.Collections.Generic;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Above/Below MA strategy. Trades when price crosses above or below a moving average.
/// </summary>
public class AboveBelowMaStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _maPeriod;
private decimal? _prevClose;
private decimal? _prevMa;
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public int MaPeriod
{
get => _maPeriod.Value;
set => _maPeriod.Value = value;
}
public AboveBelowMaStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame())
.SetDisplay("Candle Type", "Timeframe", "General");
_maPeriod = Param(nameof(MaPeriod), 20)
.SetGreaterThanZero()
.SetDisplay("MA Period", "Moving average period", "Indicators");
}
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevClose = null;
_prevMa = null;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_prevClose = null;
_prevMa = null;
var sma = new SimpleMovingAverage { Length = MaPeriod };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(sma, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, sma);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal maVal)
{
if (candle.State != CandleStates.Finished)
return;
var close = candle.ClosePrice;
if (!IsFormedAndOnlineAndAllowTrading())
{
_prevClose = close;
_prevMa = maVal;
return;
}
if (_prevClose == null || _prevMa == null)
{
_prevClose = close;
_prevMa = maVal;
return;
}
// Price crosses above MA → buy
if (_prevClose.Value <= _prevMa.Value && close > maVal && Position <= 0)
{
if (Position < 0)
BuyMarket();
BuyMarket();
}
// Price crosses below MA → sell
else if (_prevClose.Value >= _prevMa.Value && close < maVal && Position >= 0)
{
if (Position > 0)
SellMarket();
SellMarket();
}
_prevClose = close;
_prevMa = maVal;
}
}
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 CandleStates
from StockSharp.Algo.Indicators import SimpleMovingAverage
from StockSharp.Algo.Strategies import Strategy
from datatype_extensions import *
class above_below_ma_strategy(Strategy):
"""
Above/Below MA strategy. Trades when price crosses above or below a moving average.
"""
def __init__(self):
super(above_below_ma_strategy, self).__init__()
self._candle_type = self.Param("CandleType", tf(5)) \
.SetDisplay("Candle Type", "Timeframe", "General")
self._ma_period = self.Param("MaPeriod", 20) \
.SetGreaterThanZero() \
.SetDisplay("MA Period", "Moving average period", "Indicators")
self._prev_close = None
self._prev_ma = None
@property
def CandleType(self):
return self._candle_type.Value
@CandleType.setter
def CandleType(self, value):
self._candle_type.Value = value
@property
def MaPeriod(self):
return self._ma_period.Value
@MaPeriod.setter
def MaPeriod(self, value):
self._ma_period.Value = value
def OnReseted(self):
super(above_below_ma_strategy, self).OnReseted()
self._prev_close = None
self._prev_ma = None
def OnStarted2(self, time):
super(above_below_ma_strategy, self).OnStarted2(time)
self._prev_close = None
self._prev_ma = None
sma = SimpleMovingAverage()
sma.Length = self.MaPeriod
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(sma, self.ProcessCandle).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, sma)
self.DrawOwnTrades(area)
def ProcessCandle(self, candle, ma_val):
if candle.State != CandleStates.Finished:
return
close = float(candle.ClosePrice)
if self._prev_close is None or self._prev_ma is None:
self._prev_close = close
self._prev_ma = ma_val
return
# Price crosses above MA -> buy
if self._prev_close <= self._prev_ma and close > ma_val and self.Position <= 0:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
# Price crosses below MA -> sell
elif self._prev_close >= self._prev_ma and close < ma_val and self.Position >= 0:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
self._prev_close = close
self._prev_ma = ma_val
def CreateClone(self):
"""!! REQUIRED!! Creates a new instance of the strategy."""
return above_below_ma_strategy()