The ExpICustomV1 Strategy is a StockSharp port of the MetaTrader expert exp_iCustom_v1. The strategy reads trade signals from a configurable indicator instance and reacts to non-zero values in the selected buffers. When the buy buffer is non-zero the strategy opens a long position, while the sell buffer triggers a short entry. Protective stop-loss, take-profit, trailing and break-even logic reproduce the money-management options of the original expert.
Note: Only the C# implementation is provided. A Python version is not available yet.
Trading Logic
Subscribe to the primary timeframe specified by Candle Type and process closed candles only.
Instantiate the indicator defined by Indicator Name and apply the slash-separated Indicator Parameters (supports both Name=Value pairs and ordered numeric values).
Store final indicator outputs in a history buffer so that any shift can be accessed on later candles.
When the buy buffer value at Indicator Shift is not zero the strategy opens/maintains a long position. When the sell buffer is non-zero the strategy opens/maintains a short position.
If both buffers return non-zero values simultaneously the signals cancel each other to avoid ambiguous entries.
Optional Close On Reverse exits the current position before reacting to the opposite signal.
Sleep logic enforces a minimum number of bars between consecutive entries in the same direction. The timer can be cancelled when the opposite signal fires if Cancel Sleeping is enabled.
Positions are protected by stop-loss, take-profit, optional trailing stop and break-even locking. All distances are expressed in price points.
Indicator configuration
Indicator Name – Full type name or short StockSharp indicator name (for example SMA, MACD, BollingerBands).
Indicator Parameters – Slash-separated list applied to the indicator. Both Length=14/Width=2 and ordered values like 14/2/0.7 are supported.
Override blocks – Up to five replacements let you adjust parameter values by index during optimisation, similar to the Opt_X inputs in the original expert. Indexes are zero-based.
Risk & money management
Base Volume – Amount sent with each market order.
Stop Loss / Take Profit – Absolute distances in points from the entry price.
Trailing Stop – Activates after the specified profit and maintains the configured distance from the extreme price.
Break Even – Moves the stop towards the entry price after the specified profit and optionally locks additional points.
Parameter reference
Parameter
Description
Candle Type
Timeframe used for the indicator and signal evaluation.
Indicator Name
Type name of the indicator instance.
Indicator Parameters
Slash-separated list of indicator parameters.
Buy Buffer / Sell Buffer
Buffer indexes that contain the buy/sell markers.
Indicator Shift
Historical shift applied when reading indicator buffers.
Override blocks
Replace specific parameter positions during runtime.
Sleep Bars
Minimum bars between entries in the same direction.
Cancel Sleeping
Reset the sleep timer after an opposite signal.
Close On Reverse
Close existing position when the opposite signal appears.
Max Orders / Max Buy / Max Sell
Soft caps that limit the number of simultaneous positions.
Stop Loss / Take Profit
Distance in points for protective orders.
Trailing Stop settings
Parameters controlling the trailing stop activation and distance.
Break Even settings
Parameters controlling break-even activation and lock distance.
Base Volume
Volume of each market entry.
Usage
Add the strategy to your strategy container and set the Security and Portfolio.
Configure Indicator Name and Indicator Parameters to match the target custom indicator.
Adjust risk settings (stop, take, trailing, break even) and the base order volume.
Run the strategy. It will subscribe to the chosen timeframe, evaluate the indicator buffers and send market orders when conditions are met.
Limitations
The indicator must be available as a StockSharp indicator type. Binary MetaTrader indicators cannot be loaded directly.
Money-management modes that depend on broker-side free margin are simplified to a fixed base volume.
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>
/// ExpICustomV1 - custom indicator signal strategy.
/// Uses fast/slow EMA crossover to generate entry/exit signals.
/// Reverses position on opposite crossover.
/// </summary>
public class ExpICustomV1Strategy : Strategy
{
private readonly StrategyParam<int> _fastPeriod;
private readonly StrategyParam<int> _slowPeriod;
private readonly StrategyParam<DataType> _candleType;
private decimal _prevFast;
private decimal _prevSlow;
private bool _hasPrev;
public int FastPeriod { get => _fastPeriod.Value; set => _fastPeriod.Value = value; }
public int SlowPeriod { get => _slowPeriod.Value; set => _slowPeriod.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public ExpICustomV1Strategy()
{
_fastPeriod = Param(nameof(FastPeriod), 10)
.SetDisplay("Fast EMA", "Fast EMA period", "Indicators");
_slowPeriod = Param(nameof(SlowPeriod), 21)
.SetDisplay("Slow EMA", "Slow EMA period", "Indicators");
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Candle timeframe", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevFast = 0m;
_prevSlow = 0m;
_hasPrev = false;
}
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)
{
_prevFast = fast;
_prevSlow = slow;
_hasPrev = true;
return;
}
var bullCross = _prevFast <= _prevSlow && fast > slow;
var bearCross = _prevFast >= _prevSlow && fast < slow;
if (bullCross && Position <= 0)
{
if (Position < 0)
BuyMarket();
BuyMarket();
}
else if (bearCross && Position >= 0)
{
if (Position > 0)
SellMarket();
SellMarket();
}
_prevFast = fast;
_prevSlow = slow;
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
from System import TimeSpan, Math
from StockSharp.Messages import DataType, CandleStates
from StockSharp.Algo.Indicators import ExponentialMovingAverage
from StockSharp.Algo.Strategies import Strategy
class exp_i_custom_v1_strategy(Strategy):
"""Fast/slow EMA crossover strategy. Reverses position on opposite crossover."""
def __init__(self):
super(exp_i_custom_v1_strategy, self).__init__()
self._fast_period = self.Param("FastPeriod", 10) \
.SetDisplay("Fast EMA", "Fast EMA period", "Indicators")
self._slow_period = self.Param("SlowPeriod", 21) \
.SetDisplay("Slow EMA", "Slow EMA period", "Indicators")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Candle timeframe", "General")
self._prev_fast = 0.0
self._prev_slow = 0.0
self._has_prev = False
@property
def CandleType(self):
return self._candle_type.Value
@CandleType.setter
def CandleType(self, value):
self._candle_type.Value = value
@property
def FastPeriod(self):
return self._fast_period.Value
@property
def SlowPeriod(self):
return self._slow_period.Value
def OnReseted(self):
super(exp_i_custom_v1_strategy, self).OnReseted()
self._prev_fast = 0.0
self._prev_slow = 0.0
self._has_prev = False
def OnStarted2(self, time):
super(exp_i_custom_v1_strategy, self).OnStarted2(time)
self._has_prev = False
fast = ExponentialMovingAverage()
fast.Length = self.FastPeriod
slow = ExponentialMovingAverage()
slow.Length = self.SlowPeriod
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(fast, slow, self._process_candle).Start()
def _process_candle(self, candle, fast, slow):
if candle.State != CandleStates.Finished:
return
fast_val = float(fast)
slow_val = float(slow)
if not self._has_prev:
self._prev_fast = fast_val
self._prev_slow = slow_val
self._has_prev = True
return
bull_cross = self._prev_fast <= self._prev_slow and fast_val > slow_val
bear_cross = self._prev_fast >= self._prev_slow and fast_val < slow_val
if bull_cross and self.Position <= 0:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
elif bear_cross and self.Position >= 0:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
self._prev_fast = fast_val
self._prev_slow = slow_val
def CreateClone(self):
return exp_i_custom_v1_strategy()