Description
This indicator shows the trend direction based on major swing levels (higher lows on uptrend, lower highs on down trend) and switches direction when they get broken. A pullback starts when price went at least a certain amount back (ATR x multi) and lasts for a minimum of bars.
using System;
using cAlgo.API;
using cAlgo.API.Internals;
using cAlgo.API.Indicators;
using cAlgo.Indicators;
namespace cAlgo
{
[Cloud("Continuation", "Stop", Opacity = 0.1, FirstColor = "Green", SecondColor = "Red")]
[Indicator(IsOverlay = true, TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
public class KingMarketStructure : Indicator
{
[Parameter("ATR Period", DefaultValue = 14)]
public int ATRPeriod { get; set; }
[Parameter("ATR Multiplier", DefaultValue = 2.0)]
public double ATRMulti { get; set; }
[Parameter("ATR MA Type", DefaultValue = MovingAverageType.WilderSmoothing)]
public MovingAverageType ATRMaType { get; set; }
[Parameter("Min Pullback Bars", DefaultValue = 5)]
public int MinPullbackBars { get; set; }
[Parameter("Colorize Bars", DefaultValue = true)]
public bool ColorizeBars { get; set; }
[Output("Continuation", LineColor = "Blue", Thickness = 2)]
public IndicatorDataSeries Continuation { get; set; }
[Output("Middle", LineColor = "Gray", Thickness = 2)]
public IndicatorDataSeries Middle { get; set; }
[Output("Stop", LineColor = "Red", Thickness = 2)]
public IndicatorDataSeries Stop { get; set; }
[Output("ZigZag", LineColor = "Yellow", Thickness = 3)]
public IndicatorDataSeries ZigZag { get; set; }
private enum Direction
{
Up,
Down,
Pullback,
Undefined
}
private double lastLow, lastHigh;
private int lastLowIndex, lastHighIndex;
private Direction direction, lastDir;
private AverageTrueRange atr;
protected override void Initialize()
{
lastLow = double.MaxValue;
lastLowIndex = 0;
lastHigh = double.MinValue;
lastHighIndex = 0;
direction = Direction.Undefined;
lastDir = Direction.Undefined;
atr = Indicators.AverageTrueRange(ATRPeriod, ATRMaType);
}
public override void Calculate(int index)
{
if (index > 50)
{
Continuation[index] = Continuation[index - 1];
Stop[index] = Stop[index - 1];
double high = Bars.HighPrices[index];
double low = Bars.LowPrices[index];
double close = Bars.ClosePrices[index];
double open = Bars.OpenPrices[index];
double deviationUp = lastLow + atr.Result[index] * ATRMulti;
double deviationDown = lastHigh - atr.Result[index] * ATRMulti;
if (direction == Direction.Up)
{
if (lastDir == Direction.Down)
{
double temp = Continuation[index];
Continuation[index] = Stop[index];
Stop[index] = temp;
}
lastDir = Direction.Up;
if (high > lastHigh)
{
if (lastHighIndex > lastLowIndex)
{
ZigZag[lastHighIndex] = double.NaN;
}
ZigZag[index] = high;
lastHighIndex = index;
lastHigh = high;
}
else if (close <= deviationDown)
{
direction = Direction.Pullback;
Continuation[index] = lastHigh;
ZigZag[index] = low;
lastLowIndex = index;
lastLow = low;
}
else if (close < Stop[index])
{
direction = Direction.Down;
Continuation[index] = Stop[index];
Stop[index] = lastHigh;
}
}
else if (direction == Direction.Down)
{
if (lastDir == Direction.Up)
{
double temp = Continuation[index];
Continuation[index] = Stop[index];
Stop[index] = temp;
}
lastDir = Direction.Down;
if (low < lastLow)
{
if (lastLowIndex > lastHighIndex)
{
ZigZag[lastLowIndex] = double.NaN;
}
ZigZag[index] = low;
lastLowIndex = index;
lastLow = low;
}
else if (close >= deviationUp)
{
direction = Direction.Pullback;
Continuation[index] = lastLow;
ZigZag[index] = high;
lastHighIndex = index;
lastHigh = high;
}
else if (close > Stop[index])
{
direction = Direction.Up;
}
}
if (direction == Direction.Pullback)
{
if (high > lastHigh && lastDir == Direction.Down)
{
ZigZag[lastHighIndex] = double.NaN;
ZigZag[index] = high;
lastHighIndex = index;
lastHigh = high;
}
else if (low < lastLow && lastDir == Direction.Up)
{
ZigZag[lastLowIndex] = double.NaN;
ZigZag[index] = low;
lastLowIndex = index;
lastLow = low;
}
if (close < Stop[index] && lastDir == Direction.Up || close < Continuation[index] && lastDir == Direction.Down)
{
direction = Direction.Down;
if (lastHighIndex > lastLowIndex)
{
if (index - lastLowIndex > MinPullbackBars)
{
Stop[index] = lastHigh;
}
else
{
ZigZag[lastLowIndex] = double.NaN;
ZigZag[lastHighIndex] = double.NaN;
}
if (low < lastLow)
{
ZigZag[index] = low;
lastLowIndex = index;
lastLow = low;
}
}
}
else if (close > Stop[index] && lastDir == Direction.Down || close > Continuation[index] && lastDir == Direction.Up)
{
direction = Direction.Up;
if (lastLowIndex > lastHighIndex)
{
if (index - lastHighIndex > MinPullbackBars)
{
Stop[index] = lastLow;
}
else
{
ZigZag[lastLowIndex] = double.NaN;
ZigZag[lastHighIndex] = double.NaN;
}
if (high > lastHigh)
{
ZigZag[index] = high;
lastHighIndex = index;
lastHigh = high;
}
}
}
}
else
{
if (close > lastHigh)
{
direction = Direction.Up;
Continuation[index] = lastHigh;
Stop[index] = lastLow;
}
else if (close < lastLow)
{
direction = Direction.Down;
Continuation[index] = lastLow;
Stop[index] = lastHigh;
}
}
Middle[index] = (Continuation[index] + Stop[index]) / 2.0;
if (ColorizeBars && RunningMode != RunningMode.Optimization)
{
bool up = close > open;
switch (direction)
{
case Direction.Up:
if (up)
Chart.SetBarColor(index, Color.LimeGreen);
else if (!up)
Chart.SetBarColor(index, Color.DarkGreen);
break;
case Direction.Down:
if (!up)
Chart.SetBarColor(index, Color.Crimson);
else if (up)
Chart.SetBarColor(index, Color.Tomato);
break;
case Direction.Pullback:
if (lastDir == Direction.Up && up)
Chart.SetBarColor(index, Color.LimeGreen);
else if (lastDir == Direction.Up && !up)
Chart.SetBarColor(index, Color.DarkGreen);
else if (lastDir == Direction.Down && !up)
Chart.SetBarColor(index, Color.Crimson);
else if (lastDir == Direction.Down && up)
Chart.SetBarColor(index, Color.Tomato);
break;
}
}
}
else
{
double high = Bars.HighPrices[index];
double low = Bars.LowPrices[index];
Continuation[index] = Continuation[index - 1];
Stop[index] = Stop[index - 1];
if (lastLow > low)
{
lastLow = low;
lastLowIndex = index;
}
if (lastHigh < high)
{
lastHigh = high;
lastHighIndex = index;
}
}
}
private int getLowest(int startIndex, int endIndex, DataSeries series)
{
double min = series[startIndex];
int index = startIndex;
for (int i = startIndex + 1; i <= endIndex; i++)
{
if (series[i] < min)
{
min = series[i];
index = i;
}
}
return index;
}
private int getHighest(int startIndex, int endIndex, DataSeries series)
{
double max = series[startIndex];
int index = startIndex;
for (int i = startIndex + 1; i <= endIndex; i++)
{
if (series[i] > max)
{
max = series[i];
index = i;
}
}
return index;
}
}
}
CW
cW22Trader
Joined on 16.03.2021
- Distribution: Free
- Language: C#
- Trading platform: cTrader Automate
- File name: King Market Structure.algo
- Rating: 5
- Installs: 2856
- Modified: 22/01/2022 16:18
Note that publishing copyrighted material is strictly prohibited. If you believe there is copyrighted material in this section, please use the Copyright Infringement Notification form to submit a claim.
Comments
Log in to add a comment.
YE
Hi, Collaboration ?
IA
Could you put an example using the indicator in a cBot? I am trying to do that but I can´t. Thank you!
SH
Absolutely great for traders who dwell on price action trading. I had a hard time determining the market trend before I found this indicator. The added ATR functionality helps in increasing the overall profitability. Recommended.
I forget to say “Champion” !