Synchronized ScrZooing free

by Capt.Z-Fort.Builder in category Other at 10/07/2022
Description

This indicator allows you to synchronize scrolling and zooming in one indicator between your cTrader charts, to use it you just have to attach the indicator on your charts that you want to synchronize. It was merged based on 2 indicators made by Spotware: Synchronized Scrolling  and  Synchronized Zooming

Since I need to sync my charts almost scrolling and zooming at the same time always, so, it is quite useful to me. I hope it can help others as well.

If you are interested in the indicators 'Currency Strength Meter' on the below charts, you can follow the link to download and play.

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 cAlgo.API;
using System.Collections.Concurrent;
using System;
using System.Collections.Generic;
using System.Threading;

namespace cAlgo
{
    [Indicator(IsOverlay = true, TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
    public class SynchronizedScrZoo : Indicator
    {
        private static ConcurrentDictionary<string, IndicatorInstanceContainer<SynchronizedScrZoo, DateTime?>> _indicatorInstances_S = new ConcurrentDictionary<string, IndicatorInstanceContainer<SynchronizedScrZoo, DateTime?>>();
        private static ConcurrentDictionary<string, IndicatorInstanceContainer<SynchronizedScrZoo, int?>>      _indicatorInstances_Z = new ConcurrentDictionary<string, IndicatorInstanceContainer<SynchronizedScrZoo, int?>>();
        private static int _numberOfChartsToScroll;
        private DateTime _lastScrollTime;
        private int _lastZoomLevel;
        private string _chartKey;

        [Parameter("Mode", DefaultValue = Mode.All)] public Mode Mode { get; set; }

        protected override void Initialize()
        {
            _chartKey = GetChartKey(this);
            IndicatorInstanceContainer<SynchronizedScrZoo, DateTime?> oldIndicatorContainer_S;
            IndicatorInstanceContainer<SynchronizedScrZoo, int?> oldIndicatorContainer_Z;

            GetIndicatorInstanceContainer_S(_chartKey, out oldIndicatorContainer_S);
            GetIndicatorInstanceContainer_Z(_chartKey, out oldIndicatorContainer_Z);

            _indicatorInstances_S.AddOrUpdate(_chartKey, new IndicatorInstanceContainer<SynchronizedScrZoo, DateTime?>(this), (key, value) => new IndicatorInstanceContainer<SynchronizedScrZoo, DateTime?>(this));
            _indicatorInstances_Z.AddOrUpdate(_chartKey, new IndicatorInstanceContainer<SynchronizedScrZoo, int?>(this),      (key, value) => new IndicatorInstanceContainer<SynchronizedScrZoo, int?>(this));
            if (oldIndicatorContainer_S != null && oldIndicatorContainer_S.Data.HasValue) { ScrollXTo(oldIndicatorContainer_S.Data.Value); }
            if (oldIndicatorContainer_Z != null && oldIndicatorContainer_Z.Data.HasValue) { ZoomChart(oldIndicatorContainer_Z.Data.Value); }
            
            Chart.ScrollChanged += Chart_ScrollChanged; Chart.ZoomChanged += Chart_ZoomChanged;
        }

        public override void Calculate(int index) {}
        
        public void ScrollXTo(DateTime time)
        {
            IndicatorInstanceContainer<SynchronizedScrZoo, DateTime?> indicatorContainer;
            if (GetIndicatorInstanceContainer_S(_chartKey, out indicatorContainer)) { indicatorContainer.Data = time; }
            if (Bars[0].OpenTime > time) { LoadMoreHistory(); }
            else { Chart.ScrollXTo(time); }
        }
        public void ZoomChart(int zoomLevel)
        {
            IndicatorInstanceContainer<SynchronizedScrZoo, int?> indicatorContainer;
            if (GetIndicatorInstanceContainer_Z(_chartKey, out indicatorContainer)) { indicatorContainer.Data = zoomLevel; }
            Chart.ZoomLevel = zoomLevel;
        }
        
        private void Chart_ScrollChanged(ChartScrollEventArgs obj)
        {
            IndicatorInstanceContainer<SynchronizedScrZoo, DateTime?> indicatorContainer;
 
            if (GetIndicatorInstanceContainer_S(_chartKey, out indicatorContainer)) { indicatorContainer.Data = null; }
 
            if (_numberOfChartsToScroll > 0) { Interlocked.Decrement(ref _numberOfChartsToScroll); return; }
 
            var firstBarTime = obj.Chart.Bars.OpenTimes[obj.Chart.FirstVisibleBarIndex];
 
            if (_lastScrollTime == firstBarTime) return;
 
            _lastScrollTime = firstBarTime;
 
            switch (Mode)
            {
                case Mode.Symbol:       ScrollCharts(firstBarTime, indicator => indicator.SymbolName.Equals(SymbolName, StringComparison.Ordinal)); break;
                case Mode.TimeFrame:    ScrollCharts(firstBarTime, indicator => indicator.TimeFrame == TimeFrame); break;
                default:                ScrollCharts(firstBarTime); break;
            }
        }
        private void Chart_ZoomChanged(ChartZoomEventArgs obj)
        {
            IndicatorInstanceContainer<SynchronizedScrZoo, int?> indicatorContainer;

            if (GetIndicatorInstanceContainer_Z(_chartKey, out indicatorContainer)) { indicatorContainer.Data = null; }

            if (_numberOfChartsToScroll > 0) { Interlocked.Decrement(ref _numberOfChartsToScroll); return; }

            var zoomLevel = obj.Chart.ZoomLevel;

            if (_lastZoomLevel == zoomLevel) return;

            _lastZoomLevel = zoomLevel;

            switch (Mode)
            {
                case Mode.Symbol:       ZoomCharts(zoomLevel, indicator => indicator.SymbolName.Equals(SymbolName, StringComparison.Ordinal)); break;
                case Mode.TimeFrame:    ZoomCharts(zoomLevel, indicator => indicator.TimeFrame == TimeFrame); break;
                default:                ZoomCharts(zoomLevel); break;
            }
        }
        
        private void ScrollCharts(DateTime firstBarTime, Func<Indicator, bool> predicate = null)
        {
            var toScroll = new List<SynchronizedScrZoo>(_indicatorInstances_S.Values.Count);
 
            foreach (var indicatorContianer in _indicatorInstances_S)
            {
                SynchronizedScrZoo indicator;
                if (indicatorContianer.Value.GetIndicator(out indicator) == false || indicator == this || (predicate != null && predicate(indicator) == false)) continue;
                toScroll.Add(indicator);
            }
 
            Interlocked.CompareExchange(ref _numberOfChartsToScroll, toScroll.Count, _numberOfChartsToScroll);
 
            foreach (var indicator in toScroll)
            {
                try { indicator.BeginInvokeOnMainThread(() => indicator.ScrollXTo(firstBarTime)); } 
                catch (Exception) { Interlocked.Decrement(ref _numberOfChartsToScroll); }
            }
        }
        private void ZoomCharts(int zoomLevel, Func<Indicator, bool> predicate = null)
        {
            var toScroll = new List<SynchronizedScrZoo>(_indicatorInstances_Z.Values.Count);

            foreach (var indicatorContianer in _indicatorInstances_Z)
            {
                SynchronizedScrZoo indicator;
                if (indicatorContianer.Value.GetIndicator(out indicator) == false || indicator == this || (predicate != null && predicate(indicator) == false)) continue;
                toScroll.Add(indicator);
            }

            Interlocked.CompareExchange(ref _numberOfChartsToScroll, toScroll.Count, _numberOfChartsToScroll);

            foreach (var indicator in toScroll)
            {
                try { indicator.BeginInvokeOnMainThread(() => indicator.ZoomChart(zoomLevel)); }
                catch (Exception) { Interlocked.Decrement(ref _numberOfChartsToScroll); }
            }
        }

        private void LoadMoreHistory()
        {
            var numberOfLoadedBars = Bars.LoadMoreHistory();
            if (numberOfLoadedBars == 0) { Chart.DrawStaticText("ScrollError", "Synchronized Scrolling: Can't load more data to keep in sync with other charts as more historical data is not available for this chart", VerticalAlignment.Bottom, HorizontalAlignment.Left, Color.Red); }
        }

        private string GetChartKey(SynchronizedScrZoo indicator) { return string.Format("{0}_{1}_{2}", indicator.SymbolName, indicator.TimeFrame, indicator.Chart.ChartType); }
        //private string GetChartKey(SynchronizedScrZoo indicator) { return string.Format("{0}_{1}_{2}", indicator.SymbolName, indicator.TimeFrame, indicator.Chart.ChartType); }
        
        private bool GetIndicatorInstanceContainer_S(string chartKey, out IndicatorInstanceContainer<SynchronizedScrZoo, DateTime?> indicatorContainer)
        {
            if (_indicatorInstances_S.TryGetValue(chartKey, out indicatorContainer)) { return true; }
            indicatorContainer = null;
            return false;
        }
        private bool GetIndicatorInstanceContainer_Z(string chartKey, out IndicatorInstanceContainer<SynchronizedScrZoo, int?> indicatorContainer)
        {
            if (_indicatorInstances_Z.TryGetValue(chartKey, out indicatorContainer)) { return true; }
            indicatorContainer = null;
            return false;
        }
    }

    public enum Mode { All, TimeFrame, Symbol }
 
    public class IndicatorInstanceContainer<T, TData> where T : Indicator
    {
        private readonly WeakReference _indicatorWeakReference;
 
        public IndicatorInstanceContainer(T indicator) { _indicatorWeakReference = new WeakReference(indicator); }
 
        public TData Data { get; set; }
 
        public bool GetIndicator(out T indicator)
        {
            if (_indicatorWeakReference.IsAlive) { indicator = (T)_indicatorWeakReference.Target; return true; }
            indicator = null;
            return false;
        }
    }
}
Comments

imogencaleb - July 15, 2022 @ 09:36

You did a great job and Thank you so much for sharing the project. It is really helpful. Also, you can get the best services from online nursing cv writing service UK which is beneficial, especially for fresh graduates and Experts. 
 

vazquezdudley9711352 - July 18, 2022 @ 04:59

No matter how long it's been since I've been home, I have no qualms about returning. retro bowl game I've learned a lot from this experience. I'm glad I got some good information. 

markericbeatric - July 19, 2022 @ 05:18

The projects and lessons you share are great, it helps students, like stumble guys, it's very entertaining after the lesson

nobit2021 - July 21, 2022 @ 06:27

I would like to express my gratitude to you for sharing this excellent post. I have to say that I am very impressed with your post because the information provided is both comprehensive and simple to grasp. Your subsequent post will receive a lot of attention from me. nytimes crossword

todej16293 - July 29, 2022 @ 16:08

I can't tell you how helpful this has been, it is very useful for the purpose of my work, thank you very much! Best regards, WILLIAM. cheapest insurance rates

katebuilding - August 02, 2022 @ 14:46

Thanks for the post! This is a really good and detailed description. It's a pleasure to use what you write. And I like the modern world for the huge amount of information that can be found at any time of the day or night. I also really like chatroulette live. It is convenient and interesting to communicate with people from different countries.

mark.webb20 - August 03, 2022 @ 20:47

Very useful guide, thank you. I found an interesting article, and I hasten to share it with you https://celltrackingapps.com/how-to-tell-if-a-number-is-cell-phone-or-landline/

davidiesis - August 21, 2022 @ 21:58

Hi, I would like to install the indicator but it requires access to all files in the file system. Since I don't know you, how can I be sure that the code is clean and does no harm to my computer?

Capt.Z-Fort.Builder - August 22, 2022 @ 01:44

davidiesis

This indicator requires no access to your local files. Check code line 9: 'AccessRights = AccessRights.None'

If you still have a problem, please post your question to cTrader forum: https://ctrader.com/forum/indicator-support

davidiesis - August 22, 2022 @ 02:07

Sorry, I was referring to the Currency Strength Meter (Pro) Ver2.04 indicator ....

Capt.Z-Fort.Builder - August 22, 2022 @ 02:18

davidiesis 

Oh, ok.  Don't worry about the file access authority. Check line32: 'AccessRights = AccessRights.FileSystem'; the indicator only requires file access. Because the indicator has a function to 'Import and Display Economic Calendar's Key Events;' which requires the user to download a*.txt file first, then import.

If you are still concerned about safety problems, you can refer to Currency Strength Meter (Basic) version, which requires none access rights to use it.

davidiesis - August 22, 2022 @ 13:02

Thanks, I already tried to install the basic version but it doesn't work. When I try to load it on the chart nothing appears and the candlesticks are being canceled

Capt.Z-Fort.Builder - August 22, 2022 @ 13:48

davidiesis

It's working with no problem, I've just tested it in the latest cTrader 4.3.9 version. I can't give you more information here, join Telegram Group cTrader FOREX Club https://t.me/cTraderFXClub  to get more help.

Thanks.

 

junealexis001 - September 12, 2022 @ 11:47

Great site i love it keep posting more! https://spokanehousepainters.net

junealexis001 - September 12, 2022 @ 12:03

Great site i love it keep posting more!   https://fencingspringfieldmo.com

5