This strategy replicates the MetaTrader expert "Exp_SilverTrend_CrazyChart" using the StockSharp high-level API. It trades both s
ides of the market by comparing two buffers of the custom SilverTrend CrazyChart indicator. When the delayed band crosses the cur
rent band it opens a position in the direction of the newly dominant band and closes any opposite exposure.
Details
Entry Criteria:
Long: The previous finished signal bar shows the current band above the delayed band, and on the evaluated bar the curren
t band falls below or touches the delayed band. Long entries can be disabled with AllowBuyEntry.
Short: The previous finished signal bar shows the current band below the delayed band, and on the evaluated bar the curre
nt band rises above or touches the delayed band. Short entries can be disabled with AllowSellEntry.
Long/Short: Both directions.
Exit Criteria:
Long positions close when the delayed band overtakes the current band (AllowBuyExit) or when stop-loss/take-profit limits a
re triggered.
Short positions close when the current band overtakes the delayed band (AllowSellExit) or when stop-loss/take-profit limits
are triggered.
Stops: Uses absolute price offsets specified by StopLossPoints and TakeProfitPoints. If either value is set to zero, tha
t limit is ignored.
Filters:
SignalBar selects how many completed candles back the crossing logic is evaluated.
CandleType controls the timeframe used for all calculations.
Parameters
CandleType – Candle series used for the indicator (default: 1-hour candles).
Length – Swing period (SSP) passed to the SilverTrend CrazyChart indicator.
KMin – Lower channel coefficient controlling the distance of the delayed band.
KMax – Upper channel coefficient controlling the distance of the current band.
SignalBar – Number of finished candles back used for evaluating the cross (equivalent to the original SignalBar).
AllowBuyExit / AllowSellExit – Toggle closing of existing long/short positions.
StopLossPoints – Absolute price distance from entry for long stop-loss and short take-profit.
TakeProfitPoints – Absolute price distance from entry for long take-profit and short stop-loss.
Volume – Inherited strategy volume that defines the base order size.
Indicator Logic
The bundled SilverTrendCrazyChartIndicator reproduces the original MQL buffers:
Length, KMin, and KMax compute a swing channel from the highest high and lowest low over the lookback window.
The "current" band corresponds to buffer 0 in MetaTrader and reacts immediately to the latest bar.
The "delayed" band is buffer 1, which shifts the current band by Length + 1 bars to match the original drawing logic.
A buy is triggered when the delayed band, acting as the trend filter, crosses above the current band, while a sell appears when t
he relationship inverts. The SignalBar parameter ensures only completed candles participate in the decision, matching the behav
ior of the source expert.
using System;
using System.Collections.Generic;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// SilverTrend CrazyChart strategy (simplified).
/// Uses Highest/Lowest channel inversions for entries.
/// </summary>
public class SilverTrendCrazyChartStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _length;
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public int Length
{
get => _length.Value;
set => _length.Value = value;
}
public SilverTrendCrazyChartStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Candles", "General");
_length = Param(nameof(Length), 14)
.SetGreaterThanZero()
.SetDisplay("Length", "Channel length", "Indicators");
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var highest = new Highest { Length = Length };
var lowest = new Lowest { Length = Length };
decimal prevHigh = 0, prevLow = 0;
bool hasPrev = false;
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(highest, lowest, (ICandleMessage candle, decimal highValue, decimal lowValue) =>
{
if (candle.State != CandleStates.Finished)
return;
if (!hasPrev)
{
prevHigh = highValue;
prevLow = lowValue;
hasPrev = true;
return;
}
if (!IsFormedAndOnlineAndAllowTrading())
{
prevHigh = highValue;
prevLow = lowValue;
return;
}
var close = candle.ClosePrice;
var mid = (highValue + lowValue) / 2m;
var prevMid = (prevHigh + prevLow) / 2m;
// Price crosses above channel midpoint
if (close > mid && candle.OpenPrice <= prevMid && Position <= 0)
{
BuyMarket();
}
// Price crosses below channel midpoint
else if (close < mid && candle.OpenPrice >= prevMid && Position >= 0)
{
SellMarket();
}
prevHigh = highValue;
prevLow = lowValue;
})
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, highest);
DrawIndicator(area, lowest);
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 Highest, Lowest
from StockSharp.Algo.Strategies import Strategy
class silver_trend_crazy_chart_strategy(Strategy):
def __init__(self):
super(silver_trend_crazy_chart_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Candles", "General")
self._length = self.Param("Length", 14) \
.SetDisplay("Length", "Channel length", "Indicators")
self._prev_high = 0.0
self._prev_low = 0.0
self._has_prev = False
@property
def CandleType(self):
return self._candle_type.Value
@property
def Length(self):
return self._length.Value
def OnReseted(self):
super(silver_trend_crazy_chart_strategy, self).OnReseted()
self._prev_high = 0.0
self._prev_low = 0.0
self._has_prev = False
def OnStarted2(self, time):
super(silver_trend_crazy_chart_strategy, self).OnStarted2(time)
self._prev_high = 0.0
self._prev_low = 0.0
self._has_prev = False
highest = Highest()
highest.Length = self.Length
lowest = Lowest()
lowest.Length = self.Length
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(highest, lowest, self._on_process).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, highest)
self.DrawIndicator(area, lowest)
self.DrawOwnTrades(area)
def _on_process(self, candle, high_value, low_value):
if candle.State != CandleStates.Finished:
return
hv = float(high_value)
lv = float(low_value)
if not self._has_prev:
self._prev_high = hv
self._prev_low = lv
self._has_prev = True
return
close = float(candle.ClosePrice)
open_p = float(candle.OpenPrice)
mid = (hv + lv) / 2.0
prev_mid = (self._prev_high + self._prev_low) / 2.0
if close > mid and open_p <= prev_mid and self.Position <= 0:
self.BuyMarket()
elif close < mid and open_p >= prev_mid and self.Position >= 0:
self.SellMarket()
self._prev_high = hv
self._prev_low = lv
def CreateClone(self):
return silver_trend_crazy_chart_strategy()