TugbaGold — это сеточный советник из MetaTrader 5, использующий мартингейл и усреднение. Конвертация переносит его логику в StockSharp с применением высокоуровневого API. Стратегия добавляет новые ордера, когда предыдущая свеча закрывается в сторону импульса, и строит сетку позиций с заданным шагом. Закрытие сетки выполняется либо полной фиксацией крайних ордеров, либо частичным закрытием в зависимости от выбранного режима.
Логика работы
Анализируются закрытые свечи типа, заданного параметром CandleType. Для сигналов используется предыдущая свеча, как в оригинале MT5.
Бычья свеча разрешает постановку нового buy-ордера, медвежья — нового sell-ордера.
Новый ордер добавляется только если дистанция до лучшей существующей цены больше PointOrderStepPips.
Первый ордер открывается объёмом StartVolume. Каждый следующий удваивает объём самой выгодной позиции, но не превышает MaxVolume и биржевые ограничения.
Когда в корзине есть минимум два ордера, вычисляются целевые цены с учётом буфера MinimalProfitPips:
Average — средневзвешенное крайних ордеров + буфер прибыли.
Partial — комбинация худшей и лучшей позиций, где худшая использует StartVolume, а лучшая — свой фактический объём.
При достижении цели выполняются соответствующие действия:
Average — полное закрытие обеих крайних позиций.
Partial — полное закрытие худшей позиции и частичное (StartVolume) закрытие лучшей.
Если в рынке всего один ордер, применяется тейк-профит TakeProfitPips.
Параметры
Параметр
Описание
TakeProfitPips
Дистанция тейк-профита для одиночной позиции. 0 — отключить.
StartVolume
Начальный объём первого ордера сетки.
MaxVolume
Максимальный объём ордера. 0 — без ограничения.
CloseMode
Режим закрытия: Average (две крайние позиции) или Partial (частичное + полное).
PointOrderStepPips
Минимальная дистанция между усредняющими ордерами.
MinimalProfitPips
Дополнительный буфер прибыли для выхода.
CandleType
Тип свечей, используемых для сигналов.
Управление позицией
Шаг цены берётся из Security.PriceStep, иначе используется значение 0.0001.
Объёмы нормализуются по минимальному, максимальному и шаговому ограничению инструмента.
Состояние корзины хранится внутри стратегии; при закрытиях отправляются рыночные заявки BuyMarket / SellMarket.
В OnStarted автоматически вызывается StartProtection().
Особенности и ограничения
Предполагается мгновенное исполнение рыночных заявок, аналогично торговому терминалу MT5.
Для корректного расчёта целей требуются актуальные котировки bid/ask (данные Level1).
Стоп-лоссы из оригинального эксперта не восстанавливаются — закрытие полностью управляется логикой стратегии.
Мартингейл быстро увеличивает объём позиций, поэтому необходим строгий риск-менеджмент.
Детали конвертации
Формулы усреднения и перераспределения объёмов повторяют исходный код.
Выбор лучших/худших ордеров реализован через отслеживание максимальной и минимальной цены входа в каждой стороне.
Вся логика работает внутри подписки на свечи и использует только высокоуровневые методы StockSharp.
namespace StockSharp.Samples.Strategies;
using System;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.Messages;
/// <summary>
/// TugbaGold strategy: candle direction + EMA trend filter with martingale-style averaging.
/// Buys on bullish candle above EMA, sells on bearish candle below EMA.
/// </summary>
public class TugbaGoldStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _emaPeriod;
private bool _wasBullishSignal;
private bool _hasPrevSignal;
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public int EmaPeriod { get => _emaPeriod.Value; set => _emaPeriod.Value = value; }
public TugbaGoldStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(60).TimeFrame())
.SetDisplay("Candle Type", "Candle timeframe", "General");
_emaPeriod = Param(nameof(EmaPeriod), 50)
.SetGreaterThanZero()
.SetDisplay("EMA Period", "EMA trend filter period", "Indicators");
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_wasBullishSignal = false;
_hasPrevSignal = false;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_wasBullishSignal = false;
_hasPrevSignal = false;
var ema = new ExponentialMovingAverage { Length = EmaPeriod };
var subscription = SubscribeCandles(CandleType);
subscription.Bind(ema, ProcessCandle).Start();
}
private void ProcessCandle(ICandleMessage candle, decimal emaValue)
{
if (candle.State != CandleStates.Finished) return;
var bullish = candle.ClosePrice > candle.OpenPrice;
var bearish = candle.ClosePrice < candle.OpenPrice;
var bullishSignal = bullish && candle.ClosePrice > emaValue;
var bearishSignal = bearish && candle.ClosePrice < emaValue;
var crossedUp = bullishSignal && (!_hasPrevSignal || !_wasBullishSignal);
var crossedDown = bearishSignal && (!_hasPrevSignal || _wasBullishSignal);
if (crossedUp && Position <= 0)
BuyMarket();
else if (crossedDown && Position >= 0)
SellMarket();
if (bullishSignal || bearishSignal)
{
_wasBullishSignal = bullishSignal;
_hasPrevSignal = true;
}
}
}
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 tugba_gold_strategy(Strategy):
def __init__(self):
super(tugba_gold_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(60)))
self._ema_period = self.Param("EmaPeriod", 50)
self._was_bullish_signal = False
self._has_prev_signal = False
@property
def CandleType(self):
return self._candle_type.Value
@CandleType.setter
def CandleType(self, value):
self._candle_type.Value = value
@property
def EmaPeriod(self):
return self._ema_period.Value
@EmaPeriod.setter
def EmaPeriod(self, value):
self._ema_period.Value = value
def OnReseted(self):
super(tugba_gold_strategy, self).OnReseted()
self._was_bullish_signal = False
self._has_prev_signal = False
def OnStarted2(self, time):
super(tugba_gold_strategy, self).OnStarted2(time)
self._was_bullish_signal = False
self._has_prev_signal = False
ema = ExponentialMovingAverage()
ema.Length = self.EmaPeriod
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(ema, self._process_candle).Start()
def _process_candle(self, candle, ema_value):
if candle.State != CandleStates.Finished:
return
close = float(candle.ClosePrice)
open_price = float(candle.OpenPrice)
ema_val = float(ema_value)
bullish = close > open_price
bearish = close < open_price
bullish_signal = bullish and close > ema_val
bearish_signal = bearish and close < ema_val
crossed_up = bullish_signal and (not self._has_prev_signal or not self._was_bullish_signal)
crossed_down = bearish_signal and (not self._has_prev_signal or self._was_bullish_signal)
if crossed_up and self.Position <= 0:
self.BuyMarket()
elif crossed_down and self.Position >= 0:
self.SellMarket()
if bullish_signal or bearish_signal:
self._was_bullish_signal = bullish_signal
self._has_prev_signal = True
def CreateClone(self):
return tugba_gold_strategy()