Стратегия E-Friday повторяет классического эксперта MetaTrader, который торгует только по пятницам. Алгоритм анализирует предыдущую дневную свечу и в заданный час пятницы открывает позицию. Направление противоположно движению предыдущего дня: если свеча была медвежьей (закрылась ниже открытия) — совершается покупка, если свеча бычья — совершается продажа. Позиция ведётся внутри дня: её можно закрывать автоматически в заданный час либо по защитным ордерам.
Правила торговли
Подписываемся на дневные свечи (по умолчанию 1 день), чтобы получить данные об открытии и закрытии предыдущей сессии.
В пятницу отслеживаем внутридневные свечи (по умолчанию 1 минута), чтобы определить нужный час входа.
С началом первой свечи выбранного часа:
Покупаем, если предыдущий день закрылся ниже открытия.
Продаём, если предыдущий день закрылся выше открытия.
Пропускаем сигнал, если свеча-дожи (открытие равно закрытию).
При достижении заданного часа закрытия позиция может быть автоматически закрыта.
Управление сделкой осуществляется через стоп-лосс, тейк-профит и опциональный трейлинг-стоп, полностью повторяющий логику оригинального эксперта (активация по прибыли и минимальный шаг подтягивания).
Особенности реализации
Используется высокоуровневый API StockSharp: отдельные подписки на дневные и внутридневные свечи.
Параметры риска в «пунктах» из MQL переводятся в абсолютные ценовые смещения с учётом минимального шага цены инструмента.
Трейлинг-стоп ведётся в коде: на каждой завершённой свече проверяются экстремумы и при необходимости позиция закрывается рыночной заявкой.
Ведётся учёт состояния, чтобы по пятницам открывалась не более одной позиции.
Поддерживаются длинные и короткие позиции; как и в оригинале, стратегия рассчитана на один инструмент на экземпляр.
Параметры
Имя
Описание
Значение по умолчанию
Volume
Объём сделки в лотах/контрактах.
0.1
StopLossPoints
Дистанция стоп-лосса в шагах цены (0 отключает).
75
TakeProfitPoints
Дистанция тейк-профита в шагах цены (0 отключает).
0
HourOpen
Час (0-23), когда открывается позиция.
7
UseClosePositions
Закрывать ли позицию после заданного часа.
true
HourClose
Час (0-23), после которого позиция закрывается.
19
UseTrailing
Включить управление трейлинг-стопом.
true
ProfitTrailing
Требовать превышения прибыли над дистанцией трейлинга перед его активацией.
true
TrailingStopPoints
Дистанция трейлинг-стопа в шагах цены.
60
TrailingStepPoints
Дополнительные шаги перед очередным подтягиванием стопа.
5
IntradayCandleType
Тип свечей для внутридневного тайминга (по умолчанию 1 минута).
TimeSpan.FromMinutes(1)
DailyCandleType
Тип свечей для анализа предыдущего дня (по умолчанию 1 день).
TimeSpan.FromDays(1)
Рекомендации по использованию
Убедитесь, что торговая сессия инструмента позволяет открыть сделку в выбранный час пятницы.
Значения стопов и трейлинга задавайте в «пунктах» исходя из минимального шага цены, чтобы максимально приблизиться к поведению MetaTrader.
Стратегия рассчитана на одну сделку в пятницу. Для торговли несколькими инструментами запустите отдельные экземпляры стратегии.
Отличия от оригинального эксперта
Решения принимаются по завершённым свечам, тогда как оригинал проверял условия на каждом тике.
Защитные ордера исполняются рыночными заявками при достижении уровней внутри свечи, поэтому возможны небольшие расхождения во времени выхода.
Все параметры оформлены через систему StrategyParam, что позволяет использовать оптимизацию и интеграцию с UI StockSharp.
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>
/// E-Friday Session strategy - candle body direction with EMA filter.
/// Buys when previous candle was bearish and current closes above EMA (reversal).
/// Sells when previous candle was bullish and current closes below EMA (reversal).
/// </summary>
public class EFridaySessionStrategy : Strategy
{
private readonly StrategyParam<int> _emaPeriod;
private readonly StrategyParam<DataType> _candleType;
private decimal _prevOpen;
private decimal _prevClose;
private bool _hasPrev;
public int EmaPeriod { get => _emaPeriod.Value; set => _emaPeriod.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public EFridaySessionStrategy()
{
_emaPeriod = Param(nameof(EmaPeriod), 20)
.SetDisplay("EMA Period", "EMA trend filter", "Indicators");
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Candle timeframe", "General");
}
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities() => [(Security, CandleType)];
protected override void OnReseted() { base.OnReseted(); _prevOpen = 0m; _prevClose = 0m; _hasPrev = false; }
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_hasPrev = false;
var ema = new ExponentialMovingAverage { Length = EmaPeriod };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(ema, ProcessCandle)
.Start();
}
private void ProcessCandle(ICandleMessage candle, decimal ema)
{
if (candle.State != CandleStates.Finished)
return;
var close = candle.ClosePrice;
if (!_hasPrev)
{
_prevOpen = candle.OpenPrice;
_prevClose = close;
_hasPrev = true;
return;
}
var prevBearish = _prevClose < _prevOpen;
var prevBullish = _prevClose > _prevOpen;
// Previous bearish + close above EMA = buy reversal
if (prevBearish && close > ema && Position <= 0)
{
if (Position < 0)
BuyMarket();
BuyMarket();
}
// Previous bullish + close below EMA = sell reversal
else if (prevBullish && close < ema && Position >= 0)
{
if (Position > 0)
SellMarket();
SellMarket();
}
_prevOpen = candle.OpenPrice;
_prevClose = close;
}
}
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 ExponentialMovingAverage
from StockSharp.Algo.Strategies import Strategy
class e_friday_session_strategy(Strategy):
def __init__(self):
super(e_friday_session_strategy, self).__init__()
self._ema_period = self.Param("EmaPeriod", 20).SetDisplay("EMA Period", "EMA trend filter", "Indicators")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))).SetDisplay("Candle Type", "Candle timeframe", "General")
self._prev_open = 0.0
self._prev_close = 0.0
self._has_prev = False
@property
def ema_period(self): return self._ema_period.Value
@property
def candle_type(self): return self._candle_type.Value
def OnReseted(self):
super(e_friday_session_strategy, self).OnReseted()
self._prev_open = 0.0; self._prev_close = 0.0; self._has_prev = False
def OnStarted2(self, time):
super(e_friday_session_strategy, self).OnStarted2(time)
self._has_prev = False
ema = ExponentialMovingAverage()
ema.Length = self.ema_period
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(ema, self.process_candle).Start()
def process_candle(self, candle, ema):
if candle.State != CandleStates.Finished: return
close = float(candle.ClosePrice)
ema_val = float(ema)
if not self._has_prev:
self._prev_open = float(candle.OpenPrice); self._prev_close = close; self._has_prev = True; return
prev_bearish = self._prev_close < self._prev_open
prev_bullish = self._prev_close > self._prev_open
if prev_bearish and close > ema_val and self.Position <= 0:
if self.Position < 0: self.BuyMarket()
self.BuyMarket()
elif prev_bullish and close < ema_val and self.Position >= 0:
if self.Position > 0: self.SellMarket()
self.SellMarket()
self._prev_open = float(candle.OpenPrice); self._prev_close = close
def CreateClone(self): return e_friday_session_strategy()