Description
Display fractals in your chart:
- Shows arrows indicating if the fractal is a higher high, higher low, lower high or lower low
- Show lines connecting highs
- Show lines connecting lows
- Show lines connecting highs and lows
- Play notification sounds
- Send email notifications
- Print fractals in multiple timeframes in one chart
Multi timeframe
You can make the indicator calculate and render in any timeframe supported by cTrader. For instance, on a 100 ticks bar chart you can render a 10 minutes based fractal.
For that, give the short name of the timeframe in the "timeframe" input. If no value is given, the indicator will use the Chart's timeframe. Example: m1
That helps comparing the fractals of multiple timeframes on the same chart.
In order to make that possible the renderings have been changed from an IndicatorTimeSeries based to a Chart objects based. That means that you can no longer click the lines to configure its color. That is due to a cTrader limitation that only allows an indicatorseries to render in the chart's timeframe.
So in order to configure the line colors other input fields where added with a select box listing all the values from a color enumeration. It makes a bit harder than before to select a color since you can no longer see the color associated to that name, so you have to try them out.
It is recommended that you add one indicator per timeframe so you can configure them individually. Alternativelly you can add multiple timeframes separated by colon.
Remember to always use the short name of the timeframe. The table below shows the short name and associated full name:
t1 = Tick
t2 = Tick2
t3 = Tick3
t4 = Tick4
t5 = Tick5
t6 = Tick6
t7 = Tick7
t9 = Tick9
t10 = Tick10
t15 = Tick15
t20 = Tick20
t25 = Tick25
t30 = Tick30
t40 = Tick40
t50 = Tick50
t60 = Tick60
t80 = Tick80
t90 = Tick90
t100 = Tick100
t150 = Tick150
t200 = Tick200
t250 = Tick250
t300 = Tick300
t500 = Tick500
t750 = Tick750
t1000 = Tick1000
m1 = Minute
m2 = Minute2
m3 = Minute3
m4 = Minute4
m5 = Minute5
m6 = Minute6
m7 = Minute7
m8 = Minute8
m9 = Minute9
m10 = Minute10
m15 = Minute15
m20 = Minute20
m30 = Minute30
m45 = Minute45
h1 = Hour
h2 = Hour2
h3 = Hour3
h4 = Hour4
h6 = Hour6
h8 = Hour8
h12 = Hour12
D1 = Daily
D2 = Day2
D3 = Day3
W1 = Weekly
Month1 = Monthly
Re1 = Renko1
Re2 = Renko2
Re3 = Renko3
Re4 = Renko4
Re5 = Renko5
Re6 = Renko6
Re7 = Renko7
Re8 = Renko8
Re9 = Renko9
Re10 = Renko10
Re15 = Renko15
Re20 = Renko20
Re25 = Renko25
Re30 = Renko30
Re35 = Renko35
Re40 = Renko40
Re45 = Renko45
Re50 = Renko50
Re100 = Renko100
Re150 = Renko150
Re200 = Renko200
Re300 = Renko300
Re500 = Renko500
Re800 = Renko800
Re1000 = Renko1000
Re2000 = Renko2000
Ra1 = Range1
Ra2 = Range2
Ra3 = Range3
Ra4 = Range4
Ra5 = Range5
Ra8 = Range8
Ra10 = Range10
Ra20 = Range20
Ra30 = Range30
Ra50 = Range50
Ra80 = Range80
Ra100 = Range100
Ra150 = Range150
Ra200 = Range200
Ra300 = Range300
Ra500 = Range500
Ra800 = Range800
Ra1000 = Range1000
Ra2000 = Range2000
Ra5000 = Range5000
Ra7500 = Range7500
Ra10000 = Range10000
Hm1 = HeikinMinute
Hm2 = HeikinMinute2
Hm3 = HeikinMinute3
Hm4 = HeikinMinute4
Hm5 = HeikinMinute5
Hm6 = HeikinMinute6
Hm7 = HeikinMinute7
Hm8 = HeikinMinute8
Hm9 = HeikinMinute9
Hm10 = HeikinMinute10
Hm15 = HeikinMinute15
Hm20 = HeikinMinute20
Hm30 = HeikinMinute30
Hm45 = HeikinMinute45
Hh1 = HeikinHour
Hh2 = HeikinHour2
Hh3 = HeikinHour3
Hh4 = HeikinHour4
Hh6 = HeikinHour6
Hh8 = HeikinHour8
Hh12 = HeikinHour12
HD1 = HeikinDaily
HD2 = HeikinDay2
HD3 = HeikinDay3
HW1 = HeikinWeekly
HMonth1 = HeikinMonthy
Fakes
Fakes are fractals which are triggered but end up not being a valid fractal after a few bars. Consider the following image:
In order to form a high fractal (with period 5) we need to have a bar which is higher than the 2 bars to the left as well as 2 bars to the right.
That happened with that bar marked with the white circle, marking it as a High freactal point. The issue is the next fractal point. Now we are looking for a Low fractal point.
Now in order to have a Low fractal point we need a bar which is lower than the 2 bars to the left and the 2 bars to the right. As you can see in the image that never happes till that last orange circle. Before that happened, another High fractal formed as it is now higher than all previous bars as well as higher than the 2 bars to the right. That High fractal point invalidated the first one which now is marked as a "Fake".
Notifications
To add notification sounds, set in the configuration the path to the sound file, i.e.: C:\Windows\Media\notification.wav
To receive email notifications you neet to configure your email notification settings in cTrader (see https://help.spotware.com/calgo/cbots/email-notifications)
Contribute
Do you want to contribute? Send a pull request on https://github.com/douglascvas/FractalWithLines
Changelog
v 1.5
- Added support for cTrader 4.5.1
- Added support for multiple timeframes
----------------------
v 1.4:
- Added notification sounds
- Added email notification
----------------------
v 1.3:
- Fixed bug that would mark every new fractal as bad fractal
----------------------
v 1.2:
- Added support for choosing line colors
- Added circles to highlight fractals (with option to turn off)
- Changed symbol used to highlight bad fractals
Due to technical limitations on the cTrader platform, it is not possible to choose which color to apply to the circles and arrows.
// **************************************************
Tips for developers:
You can add FullFractal indicator as reference to your project (Robot or Indicator) by clicking in "Manage References" in cAlgo, and use the FractalService class to have the fractals being processed in your application:
FractalService fractalService = new FractalService(MarketSeries, period); fractalService.onFractal(handler);
where handler is a method with following signature:
private void handler(FractalEvent fractalEvent)
The handler will be called whenever you have a new fractal.
In order to process the bars, you need to call
fractalService.processIndex(index)
at each new bar. Example:
public override void Calculate(int index) { // index - 1 because index is not yet closed fractalService.processIndex(index - 1); }
using System;
using System.Collections.Generic;
namespace cAlgo
{
public class Fractal
{
public String prefix { get; set; }
public int index { get; set; }
public double value { get; set; }
public bool high { get; set; }
public bool low
{
get { return !high; }
}
public DateTime dateTime { get; set; }
private Fractal previousFractal { get; set; }
private Fractal nextFractal { get; set; }
public Fractal(int index, DateTime dateTime, double value, bool high, String prefix)
{
this.index = index;
this.value = value;
this.high = high;
this.dateTime = dateTime;
this.prefix = prefix;
}
public bool isHigher()
{
Fractal previousSameSide = getPreviousOfSameSide();
if (previousSameSide == null)
return true;
return previousSameSide.value < value;
}
public Fractal getPrevious(bool filterBest = true)
{
if (!filterBest)
{
return previousFractal;
}
Fractal previous = getFirstOfBlock().previousFractal;
if (previous == null)
return null;
return filterBest ? previous.getBest() : previous;
}
public Fractal getPreviousOfSameSide(bool filterBest = true)
{
Fractal previous = getPrevious();
if (previous == null)
return null;
return previous.getPrevious(filterBest);
}
public Fractal getNext(bool filterBest = true)
{
if (!filterBest)
{
return nextFractal;
}
Fractal next = getBest().nextFractal;
if (next == null)
return null;
return next.getBest();
}
public void addFractal(Fractal fractal)
{
nextFractal = fractal;
fractal.previousFractal = this;
}
public Fractal getFirstOfBlock()
{
Fractal first = this;
while (first.previousFractal != null && first.previousFractal.high == high)
first = first.previousFractal;
return first;
}
public Fractal getBest()
{
Fractal correctFractal = this;
// search previous
Fractal fractal = previousFractal;
while (fractal != null && fractal.high == high)
{
if (fractal.high && fractal.value > correctFractal.value ||
!fractal.high && fractal.value < correctFractal.value)
correctFractal = fractal;
fractal = fractal.previousFractal;
}
// search next
fractal = nextFractal;
while (fractal != null && fractal.high == high)
{
if (fractal.high && fractal.value > correctFractal.value ||
!fractal.high && fractal.value < correctFractal.value)
correctFractal = fractal;
fractal = fractal.nextFractal;
}
return correctFractal;
}
public List<Fractal> getBadFractals()
{
Fractal best = getBest();
List<Fractal> result = new List<Fractal>();
Fractal fractal = best.previousFractal;
// search previous
while (fractal != null && fractal.high == high)
{
result.Add(fractal);
fractal = fractal.previousFractal;
}
// search next
fractal = best.nextFractal;
while (fractal != null && fractal.high == high)
{
result.Add(fractal);
fractal = fractal.nextFractal;
}
return result;
}
public FractalType getFractalType()
{
if (high && isHigher())
return FractalType.HigherHigh;
if (!high && isHigher())
return FractalType.HigherLow;
if (high && !isHigher())
return FractalType.LowerHigh;
return FractalType.LowerLow;
}
public void remove()
{
removeFractal(this);
}
// Remove all of same side
public void removeBlock()
{
// Remove previous
Fractal fractal = this;
while (fractal != null && fractal.high == high)
{
removeFractal(fractal);
fractal = fractal.previousFractal;
}
// Remove next
fractal = nextFractal;
while (fractal != null && fractal.high == high)
{
removeFractal(fractal);
fractal = fractal.nextFractal;
}
}
private void removeFractal(Fractal fractal)
{
Fractal previous = fractal.previousFractal;
Fractal next = fractal.nextFractal;
if (previous != null)
previous.nextFractal = next;
if (next != null)
next.previousFractal = previous;
}
}
}
douglascvas
Joined on 02.01.2018
- Distribution: Free
- Language: C#
- Trading platform: cTrader Automate
- File name: FractalWithLines.algo
- Rating: 5
- Installs: 6768
- Modified: 14/12/2022 11:34
Comments
@Itmfar you can access the "fractalServices" field in the indicator.
It contains a list of FractalServices, one per timeframe you selected.
Using the FractalService you can access the last fractal using the field "lastFractal" and from there traverse to the previous ones using "previousFractal" or "nextFractal"
Take a look at the source code in github
Hey
It works amazing as an indicator, but as a robot, it only will generate future fractals. How I can get previous ones in robot?
Sorry @Mario, I haven't been receiving notifications of comments in this page.
For your question
amazing stuff.. is there however a way to get the last 2 fractals from the same side in a programmable way (like as a vlaue (index number) ?
Yes there is. You can use the function getPreviousOfSameSide()
Fractal lastFractal = fractalService.lastFractal;
Fractal prevFractal1 = lastFractal.getPreviousOfSameSide()
Fractal prevFractal2 = prevFractal1.getPreviousOfSameSide()
amazing stuff.. is there however a way to get the last 2 fractals from the same side in a programmable way (like as a vlaue (index number) ?
w.b.z feel free to use it as you wish. Consider it under MIT license.
Thank Sir.
Hi douglascvas
i would like to use youre fractal code for a new bot of mine, please send me youre terms & conditions, I might sell the bot later on.. if it works as expected.
Cheers
Have you set the path to the sound file? Does the file really exist? Which format is it? .wav?
Ty you are really fast :)
Bad news sound doesn't work for me
I have just added support for sound and email notifications Astroke
Really good jobs clear code. Thank you for sharing.
I've got a suggestion, can you add the sound alerts option?
Thanks again.
The best indicator for trading! Good job!
Please add the ability to change the thickness and color of the lines. It's important!
Best regards!
FractalServices ? and Fractal indicator into fractal.getPrevious()? :
Please Fractal Indicator share you?
I have been a long time,
I can not find a previous fractal.
Hellpp!
Pls.link video