Multi Currency Template Strategy — порт MetaTrader 4 советника Multi Currency Template v4 на высокоуровневый API StockSharp. Стратегия сохраняет логику пересечения EMA для входов, поддерживает мартингейл-доливки, стопы и тейк-профиты в пунктах, а также управление плавающим трейлинг-стопом. По умолчанию используется таймфрейм 5 минут, но его можно настроить параметром.
Логика торговли
На каждой завершённой свече выбранного таймфрейма рассчитываются две экспоненциальные скользящие средние (EMA 20 и EMA 50).
Сигнал на покупку возникает, когда EMA 20 закрывается выше EMA 50. Сигнал на продажу появляется при обратном пересечении.
Параметр Order Method ограничивает торговлю обеими сторонами, только покупками или только продажами.
Стратегия работает с чистой позицией. При появлении сигнала противоположного направления текущая позиция закрывается и затем открывается новая.
Управление позицией
Стоп-лосс / Тейк-профит — вводятся в метатрейдеровских пунктах. Значения автоматически пересчитываются в цену через минимальный шаг цены инструмента, что корректно работает для 4- и 5-знаковых валютных котировок.
Трейлинг-стоп — активируется после движения в прибыль на Trailing Stop (pts) и подтягивается при каждом дополнительном улучшении на Trailing Step (pts).
Мартингейл-доливки — при включении стратегия добавляет рыночные ордера каждые Step (pts) против позиции. Объём каждого нового ордера умножается на Lot Multiplier, пока позиция не будет закрыта.
Усреднённый тейк-профит — при наличии двух и более доливок целевой уровень может рассчитываться от средневзвешенной цены позиции плюс Average TP Offset (pts), копируя поведение TP Average в исходном советнике.
Параметры
Параметр
Описание
Значение по умолчанию
Order Method
Направление торговли (оба направления / только лонг / только шорт).
Buy & Sell
Volume (lots)
Базовый объём первой сделки в лотах.
0.01
Stop Loss (pips)
Размер стоп-лосса в пунктах MetaTrader.
50
Take Profit (pips)
Размер тейк-профита в пунктах MetaTrader.
100
Trailing Stop (pts)
Прибыль в пунктах для активации трейлинг-стопа.
15
Trailing Step (pts)
Минимальный шаг подтягивания трейлинга.
5
Enable Martingale
Включает доливки по мартингейлу.
true
Lot Multiplier
Множитель объёма следующей доливки.
1.2
Step (pts)
Расстояние между доливками в пунктах MetaTrader.
150
Average Take Profit
Использовать ли усреднённый тейк-профит при нескольких ордерах.
true
Average TP Offset (pts)
Смещение усреднённого тейк-профита относительно средней цены.
20
Candle Type
Тип свечей (таймфрейм) для расчётов индикаторов.
5-минутные свечи
Отличия от оригинального советника
StockSharp оперирует чистой позицией, а не отдельными тикетами. Мартингейл увеличивает общий объём позиции и не управляет индивидуальными стопами/тейками.
Встроенного мультивалютного цикла нет: для торговли несколькими инструментами нужно запускать несколько экземпляров стратегии.
Проверки доступности средств и брокерские ограничения (CheckMoneyForTrade, CheckVolumeValue) заменены встроенными механизмами проверки заявок в StockSharp.
Рекомендации по использованию
Убедитесь, что у инструмента корректно настроены PriceStep и количество знаков, чтобы пересчёт пунктов в цену был точным.
Встроенное управление позицией работает на закрытии свечей. Для более частого контроля можно дополнительно обрабатывать поток заявок или сделок.
Стратегия использует рыночные ордера, поэтому контроль проскальзывания зависит от брокера или режима тестирования.
namespace StockSharp.Samples.Strategies;
using System;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.Messages;
/// <summary>
/// Multi Currency Template strategy: EMA crossover with trend confirmation.
/// Buys when fast EMA crosses above slow EMA, sells on the opposite cross.
/// </summary>
public class MultiCurrencyTemplateStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _fastPeriod;
private readonly StrategyParam<int> _slowPeriod;
private decimal _prevFast;
private decimal _prevSlow;
private bool _hasPrev;
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public int FastPeriod { get => _fastPeriod.Value; set => _fastPeriod.Value = value; }
public int SlowPeriod { get => _slowPeriod.Value; set => _slowPeriod.Value = value; }
public MultiCurrencyTemplateStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame())
.SetDisplay("Candle Type", "Candle timeframe", "General");
_fastPeriod = Param(nameof(FastPeriod), 20)
.SetGreaterThanZero()
.SetDisplay("Fast Period", "Fast EMA period", "Indicators");
_slowPeriod = Param(nameof(SlowPeriod), 50)
.SetGreaterThanZero()
.SetDisplay("Slow Period", "Slow EMA period", "Indicators");
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevFast = 0m;
_prevSlow = 0m;
_hasPrev = false;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_hasPrev = false;
var fast = new ExponentialMovingAverage { Length = FastPeriod };
var slow = new ExponentialMovingAverage { Length = SlowPeriod };
var subscription = SubscribeCandles(CandleType);
subscription.Bind(fast, slow, ProcessCandle).Start();
}
private void ProcessCandle(ICandleMessage candle, decimal fast, decimal slow)
{
if (candle.State != CandleStates.Finished) return;
if (_hasPrev)
{
if (_prevFast <= _prevSlow && fast > slow && Position <= 0) BuyMarket();
else if (_prevFast >= _prevSlow && fast < slow && Position >= 0) SellMarket();
}
_prevFast = fast;
_prevSlow = slow;
_hasPrev = 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 multi_currency_template_strategy(Strategy):
"""
Multi Currency Template: fast/slow EMA crossover.
"""
def __init__(self):
super(multi_currency_template_strategy, self).__init__()
self._fast_period = self.Param("FastPeriod", 20).SetDisplay("Fast", "Fast EMA", "Indicators")
self._slow_period = self.Param("SlowPeriod", 50).SetDisplay("Slow", "Slow EMA", "Indicators")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(5))).SetDisplay("Candle Type", "Candles", "General")
self._prev_fast = 0.0
self._prev_slow = 0.0
self._has_prev = False
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(multi_currency_template_strategy, self).OnReseted()
self._prev_fast = 0.0
self._prev_slow = 0.0
self._has_prev = False
def OnStarted2(self, time):
super(multi_currency_template_strategy, self).OnStarted2(time)
fast = ExponentialMovingAverage()
fast.Length = self._fast_period.Value
slow = ExponentialMovingAverage()
slow.Length = self._slow_period.Value
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(fast, slow, self._process_candle).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, fast)
self.DrawIndicator(area, slow)
self.DrawOwnTrades(area)
def _process_candle(self, candle, fast_val, slow_val):
if candle.State != CandleStates.Finished:
return
fast = float(fast_val)
slow = float(slow_val)
if not self._has_prev:
self._prev_fast = fast
self._prev_slow = slow
self._has_prev = True
return
if self._prev_fast <= self._prev_slow and fast > slow and self.Position <= 0:
self.BuyMarket()
elif self._prev_fast >= self._prev_slow and fast < slow and self.Position >= 0:
self.SellMarket()
self._prev_fast = fast
self._prev_slow = slow
def CreateClone(self):
return multi_currency_template_strategy()