Description
Sync Objects Tool for cTrader 3.8+.
Latest version: https://ctrader.com/algos/indicators/show/2063
This tool synchronizes objects between several charts with the same symbol.
How to use: just add it as a regular indicator.
Feel free to make your suggestions to improve this indicator!
Demo:
using System;
using cAlgo.API;
using System.Collections.Generic;
using System.Linq;
namespace devman
{
[Indicator(IsOverlay = true, TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
public class SyncObjectsInstance : Indicator
{
protected override void Initialize()
{
Synchronizer.Instance.Register(this);
Timer.Start(Synchronizer.HeartbeatRate);
}
protected override void OnTimer()
{
Synchronizer.Instance.Heartbeat(this);
}
public override void Calculate(int index)
{
// do nothing
}
}
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.Chart.ObjectAdded -= OnObjectAdded;
expiredInstance.Chart.ObjectRemoved -= OnObjectRemoved;
expiredInstance.Chart.ObjectUpdated -= OnObjectUpdated;
_instanceHeartbeats.Remove(expiredInstance);
_instances[expiredInstance.SymbolName].Remove(expiredInstance);
instance.Print(string.Format("Expired {0}", expiredInstance.SymbolName));
}
}
}
private void OnObjectAdded(ChartObjectAddedEventArgs args)
{
lock (Sync)
{
HashSet<SyncObjectsInstance> symbolInstances;
if (!_instances.TryGetValue(args.Chart.SymbolName, out symbolInstances))
return;
foreach (var instance in symbolInstances)
{
if (instance.Chart == args.Chart)
continue;
instance.BeginInvokeOnMainThread(() => RestoreObject(instance, args.ChartObject));
}
}
}
private void OnObjectUpdated(ChartObjectUpdatedEventArgs args)
{
lock (Sync)
{
HashSet<SyncObjectsInstance> symbolInstances;
if (!_instances.TryGetValue(args.Chart.SymbolName, out symbolInstances))
return;
foreach (var instance in symbolInstances)
{
if (instance.Chart == args.Chart)
continue;
instance.BeginInvokeOnMainThread(() => RestoreObject(instance, args.ChartObject));
}
}
}
private void OnObjectRemoved(ChartObjectRemovedEventArgs args)
{
lock (Sync)
{
HashSet<SyncObjectsInstance> symbolInstances;
if (!_instances.TryGetValue(args.Chart.SymbolName, out symbolInstances))
return;
var objectNames = new[]
{
args.ChartObject.Name
};
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.SymbolName, out symbolInstances))
{
symbolInstances = new HashSet<SyncObjectsInstance>();
_instances.Add(sender.SymbolName, symbolInstances);
}
var senderObjects = sender.Chart.Objects.ToArray();
foreach (var instance in symbolInstances)
instance.BeginInvokeOnMainThread(() => RestoreObjects(instance, senderObjects));
sender.Chart.ObjectAdded += OnObjectAdded;
sender.Chart.ObjectRemoved += OnObjectRemoved;
sender.Chart.ObjectUpdated += OnObjectUpdated;
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;
}
}
}
devman
Joined on 22.10.2019
- Distribution: Free
- Language: C#
- Trading platform: cTrader Automate
- File name: Sync Objects [3.8].algo
- Rating: 0
- Installs: 2325
- Modified: 13/10/2021 09:55
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.
not working ctrader 4.8