Expotest — это перенос оригинального советника Expotest.mq5 на платформу StockSharp. Стратегия торгует одним инструментом, использует индикатор Parabolic SAR и простое правило управления объёмом по принципу мартингейла. В рынке находится только одна позиция, выход осуществляется по заданным уровням стоп-лосса и тейк-профита.
Логика торговли
Индикатор: Parabolic SAR на выбранном типе свечей. Параметры ускорения (SarStep) и максимального ускорения (SarMaximum) настраиваются.
Вход в рынок: анализируется только последняя закрытая свеча и только при отсутствии позиции.
Если значение SAR ниже либо равно цене закрытия, открывается длинная позиция.
Если значение SAR выше либо равно цене закрытия, открывается короткая позиция.
Выход из позиции: стоп-лосс и тейк-профит рассчитываются от цены входа на фиксированное количество шагов цены. На каждой новой свече проверяется, достиг ли диапазон свечи заданных уровней. Тип выхода (прибыль/убыток) запоминается для расчёта объёма следующей сделки.
Управление объёмом
Базовый объём: определяется параметром FixedVolume, если он больше нуля. В противном случае объём вычисляется исходя из текущей стоимости портфеля, параметров RiskPercent и StopLossPoints. Если расчёт невозможен, используется стандартное значение Strategy.Volume.
Двойной шаг: после убыточной сделки объём следующей позиции удваивается по сравнению с объёмом убыточной. После прибыльного выхода стратегия возвращается к базовому объёму.
Настраиваемые параметры
CandleType – тип данных для построения свечей (например, таймфрейм).
StopLossPoints – расстояние до стоп-лосса в шагах цены.
TakeProfitPoints – расстояние до тейк-профита в шагах цены.
RiskPercent – доля капитала, которой стратегия рискует в одной сделке при динамическом расчёте объёма.
FixedVolume – фиксированный торговый объём; значение 0 включает риск-менеджмент на основе процента.
Дополнительные замечания
Стратегия обрабатывает только закрытые свечи, что позволяет максимально приблизиться к исходной логике MQL и корректно работать с подписками StockSharp.
Стоп-уровни хранятся внутри стратегии, без регистрации отдельных стоп/лимит заявок, что упрощает тестирование.
По запросу заказчика Python-версия и соответствующая папка не создавались.
namespace StockSharp.Samples.Strategies;
using System;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.Messages;
/// <summary>
/// Parabolic SAR based strategy converted from the Expotest MQL expert advisor.
/// Enters long when SAR is below price, short when SAR is above price.
/// </summary>
public class ExpotestStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<decimal> _sarStep;
private readonly StrategyParam<decimal> _sarMaximum;
private bool _prevSarBelow;
private bool _initialized;
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public decimal SarStep
{
get => _sarStep.Value;
set => _sarStep.Value = value;
}
public decimal SarMaximum
{
get => _sarMaximum.Value;
set => _sarMaximum.Value = value;
}
public ExpotestStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).TimeFrame())
.SetDisplay("Candle Type", "Candle type for signal generation", "General");
_sarStep = Param(nameof(SarStep), 0.02m)
.SetDisplay("SAR Step", "Acceleration factor for Parabolic SAR", "Indicators");
_sarMaximum = Param(nameof(SarMaximum), 0.2m)
.SetDisplay("SAR Maximum", "Maximum acceleration factor for Parabolic SAR", "Indicators");
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevSarBelow = false;
_initialized = false;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_prevSarBelow = false;
_initialized = false;
var sar = new ParabolicSar
{
Acceleration = SarStep,
AccelerationMax = SarMaximum
};
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(sar, OnProcess)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, sar);
DrawOwnTrades(area);
}
}
private void OnProcess(ICandleMessage candle, decimal sarValue)
{
if (candle.State != CandleStates.Finished)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
var sarBelow = sarValue < candle.ClosePrice;
if (!_initialized)
{
_prevSarBelow = sarBelow;
_initialized = true;
return;
}
// SAR flipped from above to below price => Buy signal
if (sarBelow && !_prevSarBelow && Position <= 0)
{
BuyMarket();
}
// SAR flipped from below to above price => Sell signal
else if (!sarBelow && _prevSarBelow && Position >= 0)
{
SellMarket();
}
_prevSarBelow = sarBelow;
}
}
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 ParabolicSar
from StockSharp.Algo.Strategies import Strategy
class expotest_strategy(Strategy):
def __init__(self):
super(expotest_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(1))) \
.SetDisplay("Candle Type", "Candle type for signal generation", "General")
self._sar_step = self.Param("SarStep", 0.02) \
.SetDisplay("SAR Step", "Acceleration factor for Parabolic SAR", "Indicators")
self._sar_maximum = self.Param("SarMaximum", 0.2) \
.SetDisplay("SAR Maximum", "Maximum acceleration factor for Parabolic SAR", "Indicators")
self._prev_sar_below = False
self._initialized = False
@property
def CandleType(self):
return self._candle_type.Value
@property
def SarStep(self):
return self._sar_step.Value
@property
def SarMaximum(self):
return self._sar_maximum.Value
def OnReseted(self):
super(expotest_strategy, self).OnReseted()
self._prev_sar_below = False
self._initialized = False
def OnStarted2(self, time):
super(expotest_strategy, self).OnStarted2(time)
self._prev_sar_below = False
self._initialized = False
sar = ParabolicSar()
sar.Acceleration = self.SarStep
sar.AccelerationMax = self.SarMaximum
subscription = self.SubscribeCandles(self.CandleType)
subscription \
.Bind(sar, self._on_process) \
.Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, sar)
self.DrawOwnTrades(area)
def _on_process(self, candle, sar_value):
if candle.State != CandleStates.Finished:
return
sv = float(sar_value)
sar_below = sv < float(candle.ClosePrice)
if not self._initialized:
self._prev_sar_below = sar_below
self._initialized = True
return
if sar_below and not self._prev_sar_below and self.Position <= 0:
self.BuyMarket()
elif not sar_below and self._prev_sar_below and self.Position >= 0:
self.SellMarket()
self._prev_sar_below = sar_below
def CreateClone(self):
return expotest_strategy()