Sync Objects free

by devman in category Other at 04/12/2019
Description

Sync Objects Tool for cTrader 4.0+. 

Previous version (3.8): https://ctrader.com/algos/indicators/show/2556

This tool synchronizes objects between several charts with the same symbol.
How to use: just add it as a regular indicator.

Parameters

Feel free to make your suggestions to improve this indicator!

What's new

[06.05.2021]

  • Allow to temporarily disable indicator.
  • Allow customizing synchronization group.
  • Show status icon and allow customizing it.

[01.02.2021]

  •  Support multiple objects operations for 4.0.

Demo:

 

Notification Publishing copyrighted material is strictly prohibited. If you believe there is copyrighted material in this section you may use the Copyright Infringement Notification form to submit a claim.
Formula / Source Code
Language: C#
Trading Platform: cAlgocTrader
´╗┐using System;
using System.Collections.Generic;
using System.Linq;
using cAlgo.API;

namespace devman
{
    [Indicator(IsOverlay = true, TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
    public class SyncObjectsInstance : Indicator
    {
        [Parameter("Enabled", DefaultValue = true)]
        public bool Enabled { get; set; }

        [Parameter("Custom Group", DefaultValue = "")]
        public string CustomGroup { get; set; }

        [Parameter("Visible", Group = "Icon", DefaultValue = true)]
        public bool IconVisible { get; set; }

        [Parameter("Color", Group = "Icon", DefaultValue = " Auto")]
        public string IconColor { get; set; }

        [Parameter("Vertical Alignment", Group = "Icon", DefaultValue = VerticalAlignment.Top)]
        public VerticalAlignment IconVerticalAlignment { get; set; }

        [Parameter("Horizontal Alignment", Group = "Icon", DefaultValue = HorizontalAlignment.Right)]
        public HorizontalAlignment IconHorizontalAlignment { get; set; }

        public string GroupName { get; private set; }

        public event Action<SyncObjectsInstance, ChartObjectsAddedEventArgs> ObjectsAdded; 
        public event Action<SyncObjectsInstance, ChartObjectsRemovedEventArgs> ObjectsRemoved; 
        public event Action<SyncObjectsInstance, ChartObjectsUpdatedEventArgs> ObjectsUpdated; 

        protected override void Initialize()
        {
            GroupName = CalculateGroupName();

            if (IconVisible)
                DrawStatusIcon();

            if (Enabled)
            {
                Chart.ObjectsAdded += OnObjectsAdded;
                Chart.ObjectsRemoved += OnObjectsRemoved;
                Chart.ObjectsUpdated += OnObjectsUpdated;

                Synchronizer.Instance.Register(this);

                if (Enabled)
                    Timer.Start(Synchronizer.HeartbeatRate);
            }
        }

        private void OnObjectsAdded(ChartObjectsAddedEventArgs args)
        {
            if (ObjectsAdded != null)
                ObjectsAdded.Invoke(this, args);
        }

        private void OnObjectsRemoved(ChartObjectsRemovedEventArgs args)
        {
            if (ObjectsRemoved != null)
                ObjectsRemoved.Invoke(this, args);
        }

        private void OnObjectsUpdated(ChartObjectsUpdatedEventArgs args)
        {
            if (ObjectsUpdated != null)
                ObjectsUpdated.Invoke(this, args);
        }

        protected override void OnTimer()
        {
            Synchronizer.Instance.Heartbeat(this);
        }

        public override void Calculate(int index)
        {
            // do nothing
        }

        private string CalculateGroupName()
        {
            if (string.IsNullOrWhiteSpace(CustomGroup))
                return SymbolName;

            return CustomGroup;
        }

        private Color CalculateColor()
        {
            Color color = IconColor;

            if (color != Color.Empty)
                return color;

            int hashCode = 0;

            unchecked
            {
                for (var index = 0; index < GroupName.Length; index++)
                {
                    hashCode ^= (GroupName[index] + index) * 46811987;
                }
            }

            var hex = hashCode.ToString("X6");

            if (hex.Length > 6)
                hex = hex.Substring(hex.Length - 6);

            return Color.FromHex(hex);
        }

        private void DrawStatusIcon()
        {
            var color = CalculateColor();

            Chart
                .DrawStaticText(
                    "_sync_group", Enabled ? Icons.EnabledIcon : Icons.DisabledIcon,
                    IconVerticalAlignment, IconHorizontalAlignment,
                    color)
                .IsInteractive = false;
        }
    }

    public class Synchronizer
    {
        public static readonly TimeSpan HeartbeatTimeout = TimeSpan.FromSeconds(5);
        public static readonly TimeSpan HeartbeatRate = TimeSpan.FromSeconds(4);

        private static readonly object Sync = new object();
        private static Synchronizer _instance;

        public static Synchronizer Instance
        {
            get
            {
                if (_instance != null)
                    return _instance;

                lock (Sync)
                {
                    var instance = new Synchronizer();

                    if (_instance == null)
                        _instance = instance;
                }

                return _instance;
            }
        }

        private readonly Dictionary<string, HashSet<SyncObjectsInstance>> _instances;
        private readonly Dictionary<SyncObjectsInstance, DateTime> _instanceHeartbeats;

        public Synchronizer()
        {
            _instances = new Dictionary<string, HashSet<SyncObjectsInstance>>(StringComparer.OrdinalIgnoreCase);
            _instanceHeartbeats = new Dictionary<SyncObjectsInstance, DateTime>();
        }

        public void Register(SyncObjectsInstance instance)
        {
            lock (Sync)
            {
                Restore(instance);
            }
        }

        public void Heartbeat(SyncObjectsInstance instance)
        {
            instance.Print("Heartbeat");

            lock (Sync)
            {
                var now = DateTime.Now;

                _instanceHeartbeats[instance] = now;

                var expiredInstances = _instanceHeartbeats.Where(hb => now - hb.Value > HeartbeatTimeout).Select(hb => hb.Key).ToArray();

                foreach (var expiredInstance in expiredInstances)
                {
                    expiredInstance.ObjectsAdded -= OnObjectsAdded;
                    expiredInstance.ObjectsRemoved -= OnObjectsRemoved;
                    expiredInstance.ObjectsUpdated -= OnObjectsUpdated;

                    _instanceHeartbeats.Remove(expiredInstance);
                    _instances[expiredInstance.GroupName].Remove(expiredInstance);

                    instance.Print(string.Format("Expired {0}", expiredInstance.GroupName));
                }
            }
        }

        private void OnObjectsAdded(SyncObjectsInstance sender, ChartObjectsAddedEventArgs args)
        {
            lock (Sync)
            {
                HashSet<SyncObjectsInstance> symbolInstances;

                if (!_instances.TryGetValue(sender.GroupName, out symbolInstances))
                    return;

                foreach (var instance in symbolInstances)
                {
                    if (instance.Chart == args.Chart)
                        continue;

                    instance.BeginInvokeOnMainThread(() => RestoreObjects(instance, args.ChartObjects));
                }
            }
        }

        private void OnObjectsUpdated(SyncObjectsInstance sender, ChartObjectsUpdatedEventArgs args)
        {
            lock (Sync)
            {
                HashSet<SyncObjectsInstance> symbolInstances;

                if (!_instances.TryGetValue(sender.GroupName, out symbolInstances))
                    return;

                foreach (var instance in symbolInstances)
                {
                    if (instance.Chart == args.Chart)
                        continue;

                    instance.BeginInvokeOnMainThread(() => RestoreObjects(instance, args.ChartObjects));
                }
            }
        }

        private void OnObjectsRemoved(SyncObjectsInstance sender, ChartObjectsRemovedEventArgs args)
        {
            lock (Sync)
            {
                HashSet<SyncObjectsInstance> symbolInstances;

                if (!_instances.TryGetValue(sender.GroupName, out symbolInstances))
                    return;

                var objectNames = args.ChartObjects.Select(c => c.Name).ToArray();

                foreach (var instance in symbolInstances)
                {
                    if (instance.Chart == args.Chart)
                        continue;

                    instance.BeginInvokeOnMainThread(() => RemoveObjects(instance, objectNames));
                }
            }
        }

        private void Restore(SyncObjectsInstance sender)
        {
            HashSet<SyncObjectsInstance> symbolInstances;

            if (!_instances.TryGetValue(sender.GroupName, out symbolInstances))
            {
                symbolInstances = new HashSet<SyncObjectsInstance>();
                _instances.Add(sender.GroupName, symbolInstances);
            }

            var senderObjects = sender.Chart.Objects.ToArray();

            foreach (var instance in symbolInstances)
                instance.BeginInvokeOnMainThread(() => RestoreObjects(instance, senderObjects));

            sender.ObjectsAdded += OnObjectsAdded;
            sender.ObjectsRemoved += OnObjectsRemoved;
            sender.ObjectsUpdated += OnObjectsUpdated;

            symbolInstances.Add(sender);
            _instanceHeartbeats[sender] = DateTime.Now;
        }

        private static void RemoveObjects(SyncObjectsInstance targetInstance, IEnumerable<string> sourceObjects)
        {
            foreach (var sourceObject in sourceObjects)
                targetInstance.Chart.RemoveObject(sourceObject);
        }

        private static void RestoreObjects(SyncObjectsInstance targetInstance, IEnumerable<ChartObject> sourceObjects)
        {
            foreach (var sourceObject in sourceObjects)
                RestoreObject(targetInstance, sourceObject);
        }

        private static void RestoreObject(SyncObjectsInstance targetInstance, ChartObject sourceObject)
        {
            var targetChart = targetInstance.Chart;

            if (sourceObject is ChartAndrewsPitchfork)
            {
                RestoreAndrewsPitchfork(targetChart, (ChartAndrewsPitchfork)sourceObject);
                return;
            }

            if (sourceObject is ChartEllipse)
            {
                RestoreEllipse(targetChart, (ChartEllipse)sourceObject);
                return;
            }

            if (sourceObject is ChartEquidistantChannel)
            {
                RestoreEquidistantChannel(targetChart, (ChartEquidistantChannel)sourceObject);
                return;
            }

            if (sourceObject is ChartFibonacciExpansion)
            {
                RestoreFibonacciExpansion(targetChart, (ChartFibonacciExpansion)sourceObject);
                return;
            }

            if (sourceObject is ChartFibonacciFan)
            {
                RestoreFibonacciFan(targetChart, (ChartFibonacciFan)sourceObject);
                return;
            }

            if (sourceObject is ChartFibonacciRetracement)
            {
                RestoreFibonacciRetracement(targetChart, (ChartFibonacciRetracement)sourceObject);
                return;
            }

            if (sourceObject is ChartHorizontalLine)
            {
                RestoreHorizontalLine(targetChart, (ChartHorizontalLine)sourceObject);
                return;
            }

            if (sourceObject is ChartIcon)
            {
                RestoreIcon(targetChart, (ChartIcon)sourceObject);
                return;
            }

            if (sourceObject is ChartRectangle)
            {
                RestoreRectangle(targetChart, (ChartRectangle)sourceObject);
                return;
            }

            if (sourceObject is ChartText)
            {
                RestoreText(targetChart, (ChartText)sourceObject);
                return;
            }

            if (sourceObject is ChartTrendLine)
            {
                RestoreTrendLine(targetChart, (ChartTrendLine)sourceObject);
                return;
            }

            if (sourceObject is ChartTriangle)
            {
                RestoreTriangle(targetChart, (ChartTriangle)sourceObject);
                return;
            }

            if (sourceObject is ChartVerticalLine)
            {
                RestoreVerticalLine(targetChart, (ChartVerticalLine)sourceObject);
                return;
            }

            targetInstance.Print(string.Format("Type \"{0}\" is not supported.", sourceObject.GetType().Name));
        }

        private static void RestoreTrendLine(Chart targetChart, ChartTrendLine sourceObject)
        {
            var targetObject = targetChart.DrawTrendLine(sourceObject.Name, sourceObject.Time1, sourceObject.Y1, sourceObject.Time2, sourceObject.Y2, sourceObject.Color, sourceObject.Thickness, sourceObject.LineStyle);

            targetObject.IsInteractive = true;
            targetObject.ExtendToInfinity = sourceObject.ExtendToInfinity;
        }

        private static void RestoreVerticalLine(Chart targetChart, ChartVerticalLine sourceObject)
        {
            var targetObject = targetChart.DrawVerticalLine(sourceObject.Name, sourceObject.Time, sourceObject.Color, sourceObject.Thickness, sourceObject.LineStyle);

            targetObject.IsInteractive = true;
        }

        private static void RestoreTriangle(Chart targetChart, ChartTriangle sourceObject)
        {
            var targetObject = targetChart.DrawTriangle(sourceObject.Name, sourceObject.Time1, sourceObject.Y1, sourceObject.Time2, sourceObject.Y2, sourceObject.Time3, sourceObject.Y3, sourceObject.Color, sourceObject.Thickness, sourceObject.LineStyle);

            targetObject.IsInteractive = true;
            targetObject.IsFilled = sourceObject.IsFilled;
        }

        private static void RestoreText(Chart targetChart, ChartText sourceObject)
        {
            var targetObject = targetChart.DrawText(sourceObject.Name, sourceObject.Text, sourceObject.Time, sourceObject.Y, sourceObject.Color);

            targetObject.IsInteractive = true;
            targetObject.HorizontalAlignment = sourceObject.HorizontalAlignment;
            targetObject.VerticalAlignment = sourceObject.VerticalAlignment;
        }

        private static void RestoreRectangle(Chart targetChart, ChartRectangle sourceObject)
        {
            var targetObject = targetChart.DrawRectangle(sourceObject.Name, sourceObject.Time1, sourceObject.Y1, sourceObject.Time2, sourceObject.Y2, sourceObject.Color, sourceObject.Thickness, sourceObject.LineStyle);

            targetObject.IsInteractive = true;
            targetObject.IsFilled = sourceObject.IsFilled;
        }

        private static void RestoreIcon(Chart targetChart, ChartIcon sourceObject)
        {
            var targetObject = targetChart.DrawIcon(sourceObject.Name, sourceObject.IconType, sourceObject.Time, sourceObject.Y, sourceObject.Color);

            targetObject.IsInteractive = true;
        }

        private static void RestoreHorizontalLine(Chart targetChart, ChartHorizontalLine sourceObject)
        {
            var targetObject = targetChart.DrawHorizontalLine(sourceObject.Name, sourceObject.Y, sourceObject.Color, sourceObject.Thickness, sourceObject.LineStyle);

            targetObject.IsInteractive = true;
        }

        private static void RestoreFibonacciRetracement(Chart targetChart, ChartFibonacciRetracement sourceObject)
        {
            var targetObject = targetChart.DrawFibonacciRetracement(sourceObject.Name, sourceObject.Time1, sourceObject.Y1, sourceObject.Time2, sourceObject.Y2, sourceObject.Color, sourceObject.Thickness, sourceObject.LineStyle);

            targetObject.IsInteractive = true;
            targetObject.DisplayPrices = sourceObject.DisplayPrices;

            for (int i = 0; i < targetObject.FibonacciLevels.Count; i++)
            {
                targetObject.FibonacciLevels[i].IsVisible = sourceObject.FibonacciLevels[i].IsVisible;
                targetObject.FibonacciLevels[i].PercentLevel = sourceObject.FibonacciLevels[i].PercentLevel;
            }
        }

        private static void RestoreFibonacciFan(Chart targetChart, ChartFibonacciFan sourceObject)
        {
            var targetObject = targetChart.DrawFibonacciFan(sourceObject.Name, sourceObject.Time1, sourceObject.Y1, sourceObject.Time2, sourceObject.Y2, sourceObject.Color, sourceObject.Thickness, sourceObject.LineStyle);

            targetObject.IsInteractive = true;
            targetObject.DisplayPrices = sourceObject.DisplayPrices;

            for (int i = 0; i < targetObject.FibonacciLevels.Count; i++)
            {
                targetObject.FibonacciLevels[i].IsVisible = sourceObject.FibonacciLevels[i].IsVisible;
                targetObject.FibonacciLevels[i].PercentLevel = sourceObject.FibonacciLevels[i].PercentLevel;
            }
        }

        private static void RestoreFibonacciExpansion(Chart targetChart, ChartFibonacciExpansion sourceObject)
        {
            var targetObject = targetChart.DrawFibonacciExpansion(sourceObject.Name, sourceObject.Time1, sourceObject.Y1, sourceObject.Time2, sourceObject.Y2, sourceObject.Time3, sourceObject.Y3, sourceObject.Color, sourceObject.Thickness, sourceObject.LineStyle);

            targetObject.IsInteractive = true;
            targetObject.DisplayPrices = sourceObject.DisplayPrices;

            for (int i = 0; i < targetObject.FibonacciLevels.Count; i++)
            {
                targetObject.FibonacciLevels[i].IsVisible = sourceObject.FibonacciLevels[i].IsVisible;
                targetObject.FibonacciLevels[i].PercentLevel = sourceObject.FibonacciLevels[i].PercentLevel;
            }
        }

        private static void RestoreEquidistantChannel(Chart targetChart, ChartEquidistantChannel sourceObject)
        {
            var targetObject = targetChart.DrawEquidistantChannel(sourceObject.Name, sourceObject.Time1, sourceObject.Y1, sourceObject.Time2, sourceObject.Y2, sourceObject.ChannelHeight, sourceObject.Color, sourceObject.Thickness, sourceObject.LineStyle);

            targetObject.IsInteractive = true;
            targetObject.ExtendToInfinity = sourceObject.ExtendToInfinity;
            targetObject.ShowAngle = sourceObject.ShowAngle;
        }

        private static void RestoreEllipse(Chart targetChart, ChartEllipse sourceObject)
        {
            var targetObject = targetChart.DrawEllipse(sourceObject.Name, sourceObject.Time1, sourceObject.Y1, sourceObject.Time2, sourceObject.Y2, sourceObject.Color, sourceObject.Thickness, sourceObject.LineStyle);

            targetObject.IsInteractive = true;
            targetObject.IsFilled = sourceObject.IsFilled;
        }

        private static void RestoreAndrewsPitchfork(Chart targetChart, ChartAndrewsPitchfork sourceObject)
        {
            var targetObject = targetChart.DrawAndrewsPitchfork(sourceObject.Name, sourceObject.Time1, sourceObject.Y1, sourceObject.Time2, sourceObject.Y2, sourceObject.Time3, sourceObject.Y3, sourceObject.Color, sourceObject.Thickness, sourceObject.LineStyle);

            targetObject.IsInteractive = true;
        }
    }
}
Comments

farzadmontazer - December 06, 2019 @ 05:30

It's great indicator.Thank you so much. 

farzadmontazer - December 06, 2019 @ 10:33

Is it possible to alter this indicator to work on all workspaces?

devman - December 12, 2019 @ 15:28

Yes, it is. I will improve it in the near future. Stay tuned for updates in the community group: https://t.me/cTraderCommunity

fladsonlima - December 13, 2019 @ 01:14

I have been experiencing a problem on the Ctrader platform lately and have found that the Sync Objects indicator may be the cause.

Occasionally, when I draw any object (trend line, for example) and try to duplicate it, the duplicate object keeps flashing and disappearing. From there I cannot select the new object. The problem only resolves after restarting the platform. Has anyone else been through this?

shourov.deadline - June 04, 2020 @ 09:13

When i draw something on Audusd Its also Duplicate OBject in Another symbol how to fix this ?

camilojavier212 - August 18, 2020 @ 20:13

Enormemente agradecido por este indicador. simplifica mucho la tarea de graficar objetos. 

tim.saenen - September 25, 2020 @ 01:19

Oh my lord you are a lifesaver !!! I've been looking for this function for ages !!! Thanks so much !!!

jenny484 - September 26, 2020 @ 07:57

This doesnt work!

intracables - October 15, 2020 @ 20:14

Thanks a lot for filling this void in cTrader.

cranmer767 - November 24, 2020 @ 14:05

Excellent indicator. Thanks for adding this capability for something the people at cTrader to lazy to

incorporate amongst.

cranmer767 - November 30, 2020 @ 14:24

Update to my previous comment. It still has the capability of being an excellent indicator and definitely fills a much needed function neglected by cTrader. However, there is a problem with it. When I have 2 charts open of the same pair it will not draw the indicator on both charts unless I first change the symbol on both charts to something different and change back again. Only after doing this will it sync objects between charts of the same pair. Not sure why it is doing this but it is very irritating and wastes time. Until this glitch is fixed there is not much use to it as an indicator since you may as well just draw the object you want on both charts separately to start with. Hopefully this will be fixed soon.

winsonet - January 04, 2021 @ 14:48

That's great!!!

Thanks!!

0000000 - January 26, 2021 @ 08:01

THAT"S AMAZINGGGGG

 

THNAKS!!

5509aj - February 01, 2021 @ 19:10

Cant get this to work. Added to the charts but cannot sync drawings. Any ideas ? Thanks.

devman - February 01, 2021 @ 21:39

Try previous version. Link in description.

web_wizard_chris - April 14, 2021 @ 16:51

I'm surprised this isn't built into cTRADER by default, many other trading packages have it... hhmmmm

web_wizard_chris - April 14, 2021 @ 16:51

Seems like their is an update from you, I'll have to try and see if it works for me, thanks!

ctid1825000 - April 21, 2021 @ 18:08

Hello,

it´s a good idea.

I tried to use this. But it´s not possible.
I use cTrader 4.0 with Roboforex.
I start plugin...I open two charts (XAUUSD)... I create a trendline... cTrader freezes...why?

I tried th previous (3.8) also...no chance

Could you help, please?!

 

moore.s.lukas - May 03, 2021 @ 17:44

This is almost perfect, but theres a HUDGE problem with this unfortunatly. 

So I like having one monitor dedicated to all the currency pairs I trade, so i get a general sense of what everythings doing. My second monitor is where I do all my technical analysis. The drawings on that monitor (where I do my drawings) only appear on my second monitor (where I have my diffrent currency pairs) when I select that specific currency pair. So in other words the drawings only appear on my second monitor when i select that specific symbol from my watchlist. Basically i have 6 charts with 6 diffrent symbols and id like to see all my drawings at once rather than only seing the drawings for the selected symbol. 

That being said Id still like to thank you for putting in the work for this. Really its much appreciated <3

Happy Trading :)

 

mikesplan - July 11, 2021 @ 22:37

Dear Devman, 
This is excellent! Thank you for such a fantastic tool!

For people who failed to get this to work, it may be that they are unfamiliar with cTrader's requirement that the indicator be put on each chart that the user wants the objects to appear upon. 

In other applications, such as JForex, there are solutions for this that run at the system level and apply across all open charts. Also, in TradingView, there is a selection that applies across charts. With cTrader, the template needs to be applied to each individual chart. 

Question: 
Is there a way to make the objects visible on only certain timeframes? 
Thanks!
Mike T
North Carolina

focusONanalysis - October 10, 2021 @ 12:25

Hi. First, a great indicator. Thank you for sharing it.

How can I solve the following problem?

Example: I'm using H1, M30, M15, M5, M1.

If I draw a line in H1, it will be transferred to all subordinate charts and TFs. That is correct.

But, when I draw a line in M15, it is also drawn in M5 and in M1, but it shouldn't be drawn in M30 and in H1.

So too many small lines collect in M30 and H1 and you no longer have a good view in the higher-level chart TFs.

I tried to create a group with several synch indicators like in the following example. But if I place more like one synch indicator on a chart, then the cTrader freezes and crashes.
H1 = a
M30 = a, b
M15 = a, b, c
M5 = a, b, c, d
M1 = a, b, c, d, e

Looking forward to your answers.

zarkos12 - January 14, 2022 @ 01:09

Absolute GOLD my friend! 

klintcabornay - February 24, 2022 @ 05:12

Hello, can it persist beyond workspace?

fcarabat - May 23, 2022 @ 06:48

thank you for this indicator! finally, one that works! 

tradex1 - May 31, 2022 @ 01:45

Hi Devman

I upgraded from the previous version sync objects 3.8 some months ago in the hope indicator would stop crashing but the same indicator still crashes with ctrader removing it from all charts on newer 4x version.

error dialogue box:
"Sync Objects" indicator causes serious performance issues and can lead to application freeze.
The indicator was removed from all charts

I am running a high end machine with clean Windows10 & ctrader 4.1 but suspect sync objects 4x can't handle running on multiple instruments looking on multiple timeframes?

The machine isn't short on resources so If there is a limitation of how many instances can be run, could that be increased or application enhanced to stop crashing.

OR could this essential feature be part of the ctrader core given its essential when running multiple charts.

Thanks
much appreciated

fcarabat - June 01, 2022 @ 23:10

well, now is the time to take back my comment from the 23rd..  this indicator is unstable, and making my computer crash everytime i add the indicator.  before that, i was getting an error in ctrader saying there is something wrong with this indicator and causing instability, it then removed the indicator from all charts automatically.  

beware.

tradex1 - June 03, 2022 @ 07:07

fcarabat says

"beware"

I wouldn't say that as this developer has selflessly coded this app for the community free of charge

Yes Its got a serious crashing problem and may have been since ctrader 4.1 the problem is more apparent but I'm sure he will look into it when he realises its become unstable.

Though do think this sync of charts functionality along with global crosshairs should be built directly into the core app as not having these stable features makes trading all the more harder on ctrader.

There have been few people to talk about these features on thins forum but its not an active community so the voting system for features to be considered doesn't work

Its a real shame because there are so many great ctrader features that are leaps ahead of old metatrader4/5 but its real competition is tradingview today   

nutriplan042016 - September 02, 2022 @ 11:09

One should constantly buy such heading programming that is sensible to his subject. Click https://www.checkpunctuation.com/ to get it going on time, the liberal assessment should be blended toward tracking down the most head and reasonable to satisfy your illuminating necessities.

nutriplan042016 - September 02, 2022 @ 11:11

There are different sources and references open for self-train arranging. Fundamentally view https://www.commaplacementchecker.com/ for additional subtleties. I genuinely need to see that you will like it. There are clear edifying books, sorts out, visual embellishments, and robotized books introduced at the tip of your fingers through the web.

nutriplan042016 - September 02, 2022 @ 12:17

Thankful for naming a zone that I can consider for hair move clinical new turn of events. Try this www.semicolonchecker.com it will assist you with a stunning system. I would have the decision to get out all hair fall issues.

eynt - October 06, 2022 @ 14:01

Unfortunately the indicator stopped working on .Net6. It throws the following error:

nable to invoke target method in current thread. Use `BeginInvokeOnMainThread` method to prevent this error.

Any solution?

 

 

ciaraveum008 - October 08, 2022 @ 15:27

I think crossing that we are sending any fire get-together to a spot to butcher the fire then, notwithstanding, to be prepared. Visit http://www.grammarcheckonline.net/common-rules-in-english-grammar-error-correction/ for additional encounters concerning making. Again soon, who will assist them with building those houses.

ciaraveum008 - October 08, 2022 @ 15:39

There are various packs for educators who need to look for a directorate in their own nation or abroad. Visit best free punctuation checker for extra assessments. You can get your proposed course or doctorate keep up in any field even while fixing.

5