Little EA — это эксперт по пересечению скользящей средней, изначально созданный для MetaTrader. Стратегия анализирует свечу, выбранную параметром OHLC bar index, и реагирует, когда эта свеча пересекает смещённую скользящую среднюю снизу вверх или сверху вниз. Порт на StockSharp сохраняет идею многошагового входа и позволяет накапливать несколько траншей в каждом направлении при условии соблюдения настраиваемого лимита по объёму.
Логика торговли
Подписаться на свечной поток выбранного таймфрейма и подавать в скользящую среднюю выбранного типа нужный источник цены (close, open, high, low, median, typical или weighted).
Сохранять завершённые свечи, чтобы иметь доступ к свече с индексом OhlcBarIndex (значение по умолчанию 1 — последняя полностью закрытая свеча).
Применить параметр MaShift, считывая значение скользящей средней несколько баров назад, тем самым повторяя визуальный сдвиг из MetaTrader.
Если опорная свеча закрывается выше смещённой средней, фиксируется бычий сигнал; если ниже — медвежий сигнал.
При бычьем сигнале:
если текущий короткий объём уже достиг лимита, закрыть всю короткую позицию;
иначе, пока длинная позиция меньше лимита, добавить один транш объёмом TradeVolume.
При медвежьем сигнале:
если длинная позиция уже на предельном объёме, полностью закрыть лонг;
иначе увеличить шорт на один транш TradeVolume, если лимит ещё не исчерпан.
Такой подход к ограничению объёма имитирует параметр Int_Max_Pos оригинального советника, но с учётом неттингового учёта позиций в StockSharp.
Параметры
Название
Тип
Значение по умолчанию
Описание
CandleType
DataType
таймфрейм 1 минута
Основной временной интервал для расчёта сигналов и индикатора.
OhlcBarIndex
int
1
Индекс исторической свечи, по которой оценивается пересечение (0 = текущая формирующаяся свеча, 1 = последняя закрытая).
MaxPositionsPerSide
int
15
Максимальное количество траншей TradeVolume, которое допускается накапливать в одном направлении.
MaPeriod
int
64
Длина скользящей средней.
MaShift
int
0
Количество баров, на которое значение скользящей средней смещается назад при проверке сигнала.
MaType
MovingAverageType
Smoothed
Тип скользящей (Simple, Exponential, Smoothed, Weighted).
AppliedPrice
AppliedPriceType
Close
Источник цены для расчёта индикатора.
TradeVolume
decimal
1
Объём каждой новой сделки или добавления к позиции.
Отличия от оригинального советника MetaTrader
Управление капиталом упрощено: реализована только работа с фиксированным объёмом, процентный риск из оригинала не поддерживается.
В StockSharp используется неттинг, поэтому противоположные позиции закрываются перед набором новой экспозиции. Ограничение MaxPositionsPerSide применяется к чистому объёму в лотах.
Обработка индикатора и исторических данных выполнена через высокоуровневую подписку на свечи, что заменяет ручное копирование буферов в MQL.
Рекомендации по использованию
До старта стратегии установите TradeVolume в соответствии с шагом лота инструмента; в конструкторе это значение также присваивается Strategy.Volume, поэтому стандартные методы заявок используют нужный объём по умолчанию.
Комбинируйте MaShift и OhlcBarIndex, чтобы при необходимости добиться визуального совпадения с графиком MetaTrader.
Рекомендуется запускать стратегию вместе с графиком, чтобы видеть свечи, наложенную скользящую и совершённые сделки для проверки сигналов.
Индикаторы
Одна настраиваемая скользящая средняя (Simple, Exponential, Smoothed или Weighted).
using System;
using System.Collections.Generic;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
public class LittleEaStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _momentumPeriod;
private decimal? _prevMom;
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public int MomentumPeriod { get => _momentumPeriod.Value; set => _momentumPeriod.Value = value; }
public LittleEaStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame()).SetDisplay("Candle Type", "Timeframe", "General");
_momentumPeriod = Param(nameof(MomentumPeriod), 10).SetGreaterThanZero().SetDisplay("Momentum Period", "Momentum lookback", "Indicators");
}
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities() => [(Security, CandleType)];
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevMom = null;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_prevMom = null;
var mom = new Momentum { Length = MomentumPeriod };
var subscription = SubscribeCandles(CandleType);
subscription.Bind(mom, ProcessCandle).Start();
var area = CreateChartArea();
if (area != null) { DrawCandles(area, subscription); DrawOwnTrades(area); }
}
private void ProcessCandle(ICandleMessage candle, decimal momVal)
{
if (candle.State != CandleStates.Finished) return;
if (!IsFormedAndOnlineAndAllowTrading()) { _prevMom = momVal; return; }
if (_prevMom == null) { _prevMom = momVal; return; }
if (_prevMom.Value < 100m && momVal >= 100m && Position <= 0) { if (Position < 0) BuyMarket(); BuyMarket(); }
else if (_prevMom.Value > 100m && momVal <= 100m && Position >= 0) { if (Position > 0) SellMarket(); SellMarket(); }
_prevMom = momVal;
}
}
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 Momentum
from StockSharp.Algo.Strategies import Strategy
class little_ea_strategy(Strategy):
def __init__(self):
super(little_ea_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Timeframe", "General")
self._momentum_period = self.Param("MomentumPeriod", 10) \
.SetDisplay("Momentum Period", "Momentum lookback", "Indicators")
self._prev_mom = None
@property
def CandleType(self):
return self._candle_type.Value
@property
def MomentumPeriod(self):
return self._momentum_period.Value
def OnReseted(self):
super(little_ea_strategy, self).OnReseted()
self._prev_mom = None
def OnStarted2(self, time):
super(little_ea_strategy, self).OnStarted2(time)
self._prev_mom = None
mom = Momentum()
mom.Length = self.MomentumPeriod
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(mom, self._on_process).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawOwnTrades(area)
def _on_process(self, candle, mom_value):
if candle.State != CandleStates.Finished:
return
mv = float(mom_value)
if not self.IsFormedAndOnlineAndAllowTrading():
self._prev_mom = mv
return
if self._prev_mom is None:
self._prev_mom = mv
return
if self._prev_mom < 100.0 and mv >= 100.0 and self.Position <= 0:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
elif self._prev_mom > 100.0 and mv <= 100.0 and self.Position >= 0:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
self._prev_mom = mv
def CreateClone(self):
return little_ea_strategy()