The Histo Scalper Strategy is a C# port of the MetaTrader expert advisor HistoScalperEA v1.0. The algorithm fuses eight histogram-style indicators (ADX, ATR, Bollinger Bands, Bulls/Bears Power, CCI, MACD, RSI, and Stochastic) and requires unanimous agreement from all enabled filters before opening a trade. A second requirement is that at least one filter reported the opposite direction on the previous bar, which prevents the strategy from entering during flat markets and mimics the original "two bar" confirmation logic.
Signal Generation
ADX filter – checks whether +DI is greater than −DI. Optionally invert the decision.
ATR filter – compares the current ATR with an SMA baseline and measures the percentage deviation. Long trades require a positive deviation above AtrPositiveThreshold; short trades require a negative deviation below AtrNegativeThreshold.
Bollinger breakout – expects the close price to break the upper/lower band.
Bulls/Bears power – uses Bulls Power for long entries and Bears Power magnitude for short entries.
CCI – triggers when the CCI value crosses configured oversold/overbought levels.
MACD histogram – measures the distance between MACD and its signal line.
RSI – uses classic oversold/overbought zones.
Stochastic – reads the %K line and compares it to configured bounds.
If any enabled filter produces a neutral value the strategy aborts processing for the current candle. The historical state of each filter is stored to enforce the "previous bar opposite" rule.
Risk Management
Market entries use the TradeVolume parameter.
Optional pyramiding adds to open positions; otherwise the strategy only flips direction when the signal changes.
Take-profit and stop-loss levels are expressed in instrument price steps and are applied immediately after order submission via SetTakeProfit and SetStopLoss.
A session filter (UseTimeFilter, SessionStart, SessionEnd) can disable trading outside the configured hours.
Parameters
Parameter
Description
TradeVolume
Base volume for new trades.
AllowPyramiding
Allows stacking additional trades while already positioned.
CloseOnOppositeSignal
Closes existing positions when the aggregated signal flips.
UseTimeFilter, SessionStart, SessionEnd
Restricts trading to a custom daily window.
UseTakeProfit, TakeProfitPoints
Enables and configures take profit in price steps.
UseStopLoss, StopLossPoints
Enables and configures stop loss in price steps.
UseIndicator1 … UseIndicator8
Enable individual filters.
ModeIndicatorX
Switch between straight and inverted logic for each filter.
Indicator-specific settings
Periods, thresholds, and levels that replicate the original expert advisor inputs.
Differences from the MQL Expert
Basket profit/loss management, sound alerts, and grid order management are intentionally omitted.
Risk automation (auto lot sizing, break-even and trailing logic) is not included; use the risk parameters above instead.
Spread checks and broker-specific protections are not ported.
Usage Notes
Set the Security and Portfolio before starting the strategy.
Adjust the candle type (CandleType) to match the desired timeframe.
Configure indicator thresholds to fit the target instrument’s volatility.
Enable or disable filters individually to simplify optimisation.
Use AllowPyramiding and CloseOnOppositeSignal to control exposure during fast markets.
namespace StockSharp.Samples.Strategies;
using System;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.Messages;
/// <summary>
/// Multi-indicator scalping strategy combining MACD, RSI, and CCI filters.
/// Buys when all indicators agree on bullish signal. Sells on bearish agreement.
/// </summary>
public class HistoScalperStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _rsiPeriod;
private readonly StrategyParam<int> _cciPeriod;
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public int RsiPeriod
{
get => _rsiPeriod.Value;
set => _rsiPeriod.Value = value;
}
public int CciPeriod
{
get => _cciPeriod.Value;
set => _cciPeriod.Value = value;
}
public HistoScalperStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(30).TimeFrame())
.SetDisplay("Candle Type", "Candle timeframe", "General");
_rsiPeriod = Param(nameof(RsiPeriod), 14)
.SetGreaterThanZero()
.SetDisplay("RSI Period", "RSI period", "Indicators");
_cciPeriod = Param(nameof(CciPeriod), 14)
.SetGreaterThanZero()
.SetDisplay("CCI Period", "CCI period", "Indicators");
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var macd = new MovingAverageConvergenceDivergence();
var rsi = new RelativeStrengthIndex { Length = RsiPeriod };
var cci = new CommodityChannelIndex { Length = CciPeriod };
decimal? prevMacd = null;
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(macd, rsi, cci, (candle, macdLine, rsiVal, cciVal) =>
{
if (candle.State != CandleStates.Finished)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
if (prevMacd.HasValue)
{
if (prevMacd.Value <= 0 && macdLine > 0 && rsiVal < 70m && cciVal > -100m && Position <= 0)
BuyMarket();
else if (prevMacd.Value >= 0 && macdLine < 0 && rsiVal > 30m && cciVal < 100m && Position >= 0)
SellMarket();
}
prevMacd = macdLine;
})
.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.Indicators import MovingAverageConvergenceDivergence, RelativeStrengthIndex, CommodityChannelIndex
from StockSharp.Algo.Strategies import Strategy
class histo_scalper_strategy(Strategy):
def __init__(self):
super(histo_scalper_strategy, self).__init__()
self._rsi_period = self.Param("RsiPeriod", 14) \
.SetDisplay("RSI Period", "RSI period", "Indicators")
self._cci_period = self.Param("CciPeriod", 14) \
.SetDisplay("CCI Period", "CCI period", "Indicators")
self._macd = None
self._rsi = None
self._cci = None
self._prev_macd = None
@property
def rsi_period(self):
return self._rsi_period.Value
@property
def cci_period(self):
return self._cci_period.Value
def OnReseted(self):
super(histo_scalper_strategy, self).OnReseted()
self._macd = None
self._rsi = None
self._cci = None
self._prev_macd = None
def OnStarted2(self, time):
super(histo_scalper_strategy, self).OnStarted2(time)
self._macd = MovingAverageConvergenceDivergence()
self._rsi = RelativeStrengthIndex()
self._rsi.Length = self.rsi_period
self._cci = CommodityChannelIndex()
self._cci.Length = self.cci_period
subscription = self.SubscribeCandles(DataType.TimeFrame(TimeSpan.FromMinutes(30)))
subscription.Bind(self._macd, self._rsi, self._cci, self._process_candle)
subscription.Start()
def _process_candle(self, candle, macd_value, rsi_value, cci_value):
if candle.State != CandleStates.Finished:
return
if not self._macd.IsFormed or not self._rsi.IsFormed or not self._cci.IsFormed:
return
macd_line = float(macd_value)
rsi_val = float(rsi_value)
cci_val = float(cci_value)
if self._prev_macd is not None:
if self._prev_macd <= 0.0 and macd_line > 0.0 and rsi_val < 70.0 and cci_val > -100.0 and self.Position <= 0:
self.BuyMarket()
elif self._prev_macd >= 0.0 and macd_line < 0.0 and rsi_val > 30.0 and cci_val < 100.0 and self.Position >= 0:
self.SellMarket()
self._prev_macd = macd_line
def CreateClone(self):
return histo_scalper_strategy()