When Portfolio.CurrentValue exists, the strategy multiplies it by RiskFraction (default 0.00002, equivalent to the MQL formula FreeMargin * 0.02 / 1000).
After more than one losing exit, the volume is reduced by volume * losses / 3, exactly like the LotsOptimized routine.
Volume is rounded down to Security.VolumeStep and dropped to zero if it cannot satisfy Security.MinVolume.
Parameters
Parameter
Default
Description
FastPeriod
24
Length of the fastest shifted SMA.
MediumPeriod
60
Length of the medium shifted SMA.
SlowPeriod
120
Length of the slow shifted SMA.
TakeProfitPoints
150
Distance in price points between the entry price and the take profit.
StopLossPoints
100
Distance in price points between the entry price and the stop loss.
TrailingStopPoints
100
Optional trailing stop distance in points (set to 0 to disable).
BaseVolume
0.1
Fallback trade size and minimum volume after reductions.
RiskFraction
0.00002
Fraction of the portfolio value used to compute dynamic volume.
CandleType
1 hour time frame
Candle series used to feed indicators.
Conversion Notes
The strategy uses the high-level API (SubscribeCandles + Bind) and avoids manual history buffers.
Indicator values are stored between calls to mimic the shift parameter without direct index access.
Protective exits are executed with market commands at the detected price level to stay compatible with the StockSharp abstraction.
All inline comments are written in English, complying with project guidelines.
Usage
Attach the strategy to a security and portfolio in StockSharp Designer or code.
Select a candle series (CandleType) that matches your MT4 timeframe (H1 by default).
Review the point-based risk parameters to align with the instrument tick size (e.g., 0.0001 for most Forex pairs).
Set TrailingStopPoints to zero when trailing is not required.
Monitor logs for messages such as "Enter long" and "Exit short" that mirror the MQL diagnostics.
Repository Structure
API/3924/
├── CS/Up3x1ShiftedSmaStrategy.cs # Converted C# strategy with English comments
├── README.md # English documentation (this file)
├── README_zh.md # Chinese translation
└── README_ru.md # Russian translation
Disclaimer
Trading involves significant risk. The strategy is provided for educational purposes and must be validated on historical and simulated data before live trading.
using System;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
public class Up3x1ShiftedSmaStrategy : 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;
private int _cooldown;
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 Up3x1ShiftedSmaStrategy()
{
_fastPeriod = Param(nameof(FastPeriod), 8).SetDisplay("Fast WMA", "Fast WMA period", "Indicators");
_slowPeriod = Param(nameof(SlowPeriod), 24).SetDisplay("Slow WMA", "Slow WMA period", "Indicators");
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(15).TimeFrame()).SetDisplay("Candle Type", "Candle timeframe", "General");
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevFast = default;
_prevSlow = default;
_hasPrev = default;
_cooldown = default;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_hasPrev = false;
var fast = new SimpleMovingAverage { Length = FastPeriod };
var slow = new SimpleMovingAverage { 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 (!IsFormedAndOnlineAndAllowTrading()) return;
if (!_hasPrev) { _prevFast = fast; _prevSlow = slow; _hasPrev = true; return; }
if (_cooldown > 0)
{
_cooldown--;
_prevFast = fast;
_prevSlow = slow;
return;
}
if (_prevFast <= _prevSlow && fast > slow && Position <= 0)
{
var volume = Volume + Math.Abs(Position);
BuyMarket(volume);
_cooldown = 2;
}
else if (_prevFast >= _prevSlow && fast < slow && Position >= 0)
{
var volume = Volume + Math.Abs(Position);
SellMarket(volume);
_cooldown = 2;
}
_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
from StockSharp.Messages import DataType, CandleStates
from StockSharp.Algo.Indicators import SimpleMovingAverage
from StockSharp.Algo.Strategies import Strategy
from datatype_extensions import *
from indicator_extensions import *
class up_3x1_shifted_sma_strategy(Strategy):
"""Simple SMA crossover (fast/slow) with cooldown between trades."""
def __init__(self):
super(up_3x1_shifted_sma_strategy, self).__init__()
self._fast_period = self.Param("FastPeriod", 8).SetDisplay("Fast SMA", "Fast SMA period", "Indicators")
self._slow_period = self.Param("SlowPeriod", 24).SetDisplay("Slow SMA", "Slow SMA period", "Indicators")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(15))).SetDisplay("Candle Type", "Timeframe", "General")
@property
def CandleType(self): return self._candle_type.Value
@CandleType.setter
def CandleType(self, value): self._candle_type.Value = value
def OnReseted(self):
super(up_3x1_shifted_sma_strategy, self).OnReseted()
self._prev_fast = 0
self._prev_slow = 0
self._has_prev = False
self._cooldown = 0
def OnStarted2(self, time):
super(up_3x1_shifted_sma_strategy, self).OnStarted2(time)
self._prev_fast = 0
self._prev_slow = 0
self._has_prev = False
self._cooldown = 0
fast = SimpleMovingAverage()
fast.Length = self._fast_period.Value
slow = SimpleMovingAverage()
slow.Length = self._slow_period.Value
sub = self.SubscribeCandles(self.CandleType)
sub.Bind(fast, slow, self.OnProcess).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, sub)
self.DrawIndicator(area, fast)
self.DrawIndicator(area, slow)
self.DrawOwnTrades(area)
def OnProcess(self, candle, fast_val, slow_val):
if candle.State != CandleStates.Finished:
return
if not self.IsFormedAndOnlineAndAllowTrading():
return
fv = float(fast_val)
sv = float(slow_val)
if not self._has_prev:
self._prev_fast = fv
self._prev_slow = sv
self._has_prev = True
return
if self._cooldown > 0:
self._cooldown -= 1
self._prev_fast = fv
self._prev_slow = sv
return
if self._prev_fast <= self._prev_slow and fv > sv and self.Position <= 0:
volume = self.Volume + abs(self.Position)
self.BuyMarket(volume)
self._cooldown = 2
elif self._prev_fast >= self._prev_slow and fv < sv and self.Position >= 0:
volume = self.Volume + abs(self.Position)
self.SellMarket(volume)
self._cooldown = 2
self._prev_fast = fv
self._prev_slow = sv
def CreateClone(self):
return up_3x1_shifted_sma_strategy()