AIS2 Trading Robot — это стратегия пробоя, перенесённая из оригинального советника MetaTrader 5. Алгоритм анализирует свечи старшего таймфрейма (по умолчанию 15 минут) для определения направления движения и использует младший таймфрейм (по умолчанию 1 минута) для построения адаптивного трейлинг-стопа. Управление позициями, расчёт рисков и логика модификации ордеров повторяют код MQ5, но реализованы поверх высокоуровневого API StockSharp.
Логика входа
Базовая свеча: по каждой завершённой свече основного таймфрейма сохраняются максимум, минимум, закрытие, середина диапазона и сам диапазон.
Условия для покупки:
Закрытие предыдущей свечи выше середины диапазона.
Текущая цена ask должна быть выше предыдущего максимума с учётом текущего спреда.
Работа с позицией: сделка открывается только при отсутствии позиции или при наличии встречной позиции — объём заявки автоматически перекрывает открытую позицию и создаёт новую в нужном направлении.
Управление ордерами
Трейлинг-стоп: диапазон свечи младшего таймфрейма умножается на TrailFactor. Для длинной позиции стоп подтягивается к bid − trailDistance, для короткой — к ask + trailDistance. Обновления игнорируются, если сделка не в прибыли либо предлагаемое изменение меньше минимального шага и заморозки.
Выход по стопу/тейку: как только bid (для лонга) или ask (для шорта) пересекает установленный уровень, позиция закрывается рыночным ордером.
Поток заявок: подписка на стакан цен обеспечивает доступ к актуальным bid/ask и позволяет воспроизвести логику SymbolInfo.Bid/Ask из MQ5.
Управление риском
Резерв счёта (AccountReserve): часть капитала исключается из торговли и служит подушкой безопасности, как в оригинальном советнике.
Лимит на сделку (OrderReserve): оставшийся капитал ограничивает максимальный риск на одну операцию.
Проверки:
Если объём резерва меньше расчётного лимита (Equity × OrderReserve), новые сделки не открываются.
Размер позиции рассчитывается по формуле riskBudget / |entry - stop| и приводится к шагу объёма инструмента. При отсутствии данных по портфелю используется параметр BaseVolume.
Параметры
Параметр
Описание
AccountReserve
Доля капитала, исключаемая из торговли (0–0.95).
OrderReserve
Доля доступного капитала, выделяемая под риск одной сделки (0–1).
PrimaryCandleType
Таймфрейм для расчёта сигналов (по умолчанию 15 минут).
SecondaryCandleType
Таймфрейм для трейлинг-стопа (по умолчанию 1 минута).
TakeFactor
Множитель диапазона основной свечи для тейк-профита.
StopFactor
Множитель диапазона для стоп-лосса.
TrailFactor
Множитель диапазона вторичной свечи для трейлинг-стопа.
BaseVolume
Резервный объём, когда расчёт риска недоступен.
StopBufferTicks
Дополнительный зазор к минимальной дистанции стопа (в тиках).
FreezeBufferTicks
Дополнительный зазор, ограничивающий частые модификации стопа (в тиках).
Подайте в стратегию одновременно потоки свечей обоих таймфреймов и стакан заявок, иначе часть логики не активируется.
Поскольку сигналы используют bid/ask, тестирование только по последней цене может отличаться от результатов на реальном рынке.
При запуске автоматически включается защита позиции, как и в исходной реализации MQ5.
namespace StockSharp.Samples.Strategies;
using System;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.Messages;
/// <summary>
/// AIS2 Trading Robot strategy (simplified).
/// Breakout strategy using candle range with ATR filter.
/// Buys when close is near high of candle and ATR shows volatility.
/// Sells when close is near low of candle.
/// </summary>
public class Ais2TradingRobotStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _atrPeriod;
private readonly StrategyParam<decimal> _breakoutThreshold;
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public int AtrPeriod
{
get => _atrPeriod.Value;
set => _atrPeriod.Value = value;
}
public decimal BreakoutThreshold
{
get => _breakoutThreshold.Value;
set => _breakoutThreshold.Value = value;
}
public Ais2TradingRobotStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Source candles", "General");
_atrPeriod = Param(nameof(AtrPeriod), 14)
.SetGreaterThanZero()
.SetDisplay("ATR Period", "ATR period for volatility", "Indicators");
_breakoutThreshold = Param(nameof(BreakoutThreshold), 0.85m)
.SetDisplay("Breakout Threshold", "Candle body ratio threshold (0-1)", "Signals");
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var subscription = SubscribeCandles(CandleType);
subscription
.Bind((ICandleMessage candle) =>
{
if (candle.State != CandleStates.Finished)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
var range = candle.HighPrice - candle.LowPrice;
if (range <= 0)
return;
var bodyRatio = (candle.ClosePrice - candle.LowPrice) / range;
// Buy on strong bullish candle (close near high)
if (bodyRatio > BreakoutThreshold && candle.ClosePrice > candle.OpenPrice && Position <= 0)
{
BuyMarket();
}
// Sell on strong bearish candle (close near low)
else if (bodyRatio < (1m - BreakoutThreshold) && candle.ClosePrice < candle.OpenPrice && Position >= 0)
{
SellMarket();
}
})
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
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.Strategies import Strategy
class ais2_trading_robot_strategy(Strategy):
def __init__(self):
super(ais2_trading_robot_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Source candles", "General")
self._atr_period = self.Param("AtrPeriod", 14) \
.SetDisplay("ATR Period", "ATR period for volatility", "Indicators")
self._breakout_threshold = self.Param("BreakoutThreshold", 0.85) \
.SetDisplay("Breakout Threshold", "Candle body ratio threshold (0-1)", "Signals")
@property
def CandleType(self):
return self._candle_type.Value
@property
def AtrPeriod(self):
return self._atr_period.Value
@property
def BreakoutThreshold(self):
return self._breakout_threshold.Value
def OnStarted2(self, time):
super(ais2_trading_robot_strategy, self).OnStarted2(time)
subscription = self.SubscribeCandles(self.CandleType)
subscription \
.Bind(self._on_process) \
.Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawOwnTrades(area)
def _on_process(self, candle):
if candle.State != CandleStates.Finished:
return
high = float(candle.HighPrice)
low = float(candle.LowPrice)
close = float(candle.ClosePrice)
open_p = float(candle.OpenPrice)
rng = high - low
if rng <= 0:
return
body_ratio = (close - low) / rng
threshold = float(self.BreakoutThreshold)
if body_ratio > threshold and close > open_p and self.Position <= 0:
self.BuyMarket()
elif body_ratio < (1.0 - threshold) and close < open_p and self.Position >= 0:
self.SellMarket()
def CreateClone(self):
return ais2_trading_robot_strategy()