Chart Overview free
Description
Chart Overview control.
Feel free to make your suggestions to improve this indicator!
Demo:
Settings:
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
using System; using System.Collections.Generic; using System.Linq; using cAlgo.API; namespace cAlgo { [Indicator(IsOverlay = false, TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)] public class ChartOverview : Indicator { private const int YAxisWidth = 45; private const int YAxisMargin = 10; private Polygon _cloudControl; private Rectangle _viewportControl; private double _dragOffset; private int _lastBarsTotal; [Parameter()] public DataSeries Input { get; set; } [Parameter("Cloud opacity", DefaultValue = 0.2, MaxValue = 1, MinValue = 0.0, Group = "Cloud")] public double CloudOpacity { get; set; } [Parameter("Cloud color", DefaultValue = "#FFADD8E6", Group = "Cloud")] public string CloudColor { get; set; } [Parameter("Viewport opacity", DefaultValue = 0.2, MaxValue = 1, MinValue = 0.0, Group = "Viewport")] public double ViewportOpacity { get; set; } [Parameter("Viewport color", DefaultValue = "#FFFFFFE0", Group = "Viewport")] public string ViewportColor { get; set; } [Parameter("Density", DefaultValue = 1, MinValue = 0.1, MaxValue = 100)] public double Density { get; set; } protected override void Initialize() { InitializeControls(); UpdateCloud(); UpdateViewport(); IndicatorArea.ScrollChanged += OnIndicatorAreaScrollChanged; IndicatorArea.SizeChanged += OnIndicatorAreaSizeChanged; IndicatorArea.MouseDown += OnIndicatorAreaMouseDown; IndicatorArea.DragStart += OnIndicatorAreaDragStart; IndicatorArea.DragEnd += OnIndicatorAreaDragEnd; IndicatorArea.Drag += OnIndicatorAreaDrag; _lastBarsTotal = Chart.BarsTotal; Print("Initialized"); } public override void Calculate(int index) { if (!IsLastBar) return; if (_lastBarsTotal != Chart.BarsTotal) { UpdateCloud(); UpdateViewport(); _lastBarsTotal = Chart.BarsTotal; } } private void InitializeControls() { var cloudColor = Color.FromHex(CloudColor); var viewportColor = Color.FromHex(ViewportColor); _cloudControl = new Polygon { StrokeThickness = 1, StrokeColor = cloudColor, FillColor = Color.FromArgb((int) (cloudColor.A * CloudOpacity), cloudColor), IsHitTestVisible = false }; _viewportControl = new Rectangle { StrokeThickness = 1, StrokeColor = viewportColor, FillColor = Color.FromArgb((int) (viewportColor.A * ViewportOpacity), viewportColor), IsHitTestVisible = false }; var canvas = new Canvas { BackgroundColor = Color.Transparent, VerticalAlignment = VerticalAlignment.Stretch, HorizontalAlignment = HorizontalAlignment.Stretch, Margin = 0, IsHitTestVisible = false }; canvas.AddChild(_cloudControl); canvas.AddChild(_viewportControl); var border = new Border { BorderThickness = 0, BackgroundColor = Chart.ColorSettings.BackgroundColor, VerticalAlignment = VerticalAlignment.Stretch, HorizontalAlignment = HorizontalAlignment.Stretch, Child = canvas, IsHitTestVisible = false, Margin = string.Format("0 0 -{0} 0", YAxisWidth) }; IndicatorArea.AddControl(border); } private void OnIndicatorAreaDragStart(ChartDragEventArgs args) { Chart.IsScrollingEnabled = false; } private void OnIndicatorAreaDragEnd(ChartDragEventArgs args) { Chart.IsScrollingEnabled = true; } private void OnIndicatorAreaDrag(ChartDragEventArgs args) { var selectedBarIndex = TransformXToBarIndex(0, IndicatorArea.Width + YAxisWidth, args.MouseX); ScrollTo(selectedBarIndex); } private void OnIndicatorAreaMouseDown(ChartMouseEventArgs args) { var selectedBarIndex = TransformXToBarIndex(0, IndicatorArea.Width + YAxisWidth, args.MouseX); if (selectedBarIndex >= Chart.FirstVisibleBarIndex && selectedBarIndex <= Chart.LastVisibleBarIndex) _dragOffset = Chart.FirstVisibleBarIndex - selectedBarIndex; else _dragOffset = -Chart.MaxVisibleBars / 2.0; ScrollTo(selectedBarIndex); } private void OnIndicatorAreaSizeChanged(ChartSizeEventArgs args) { UpdateCloud(); UpdateViewport(); } private void OnIndicatorAreaScrollChanged(ChartScrollEventArgs args) { if (args.BarsDelta != 0) UpdateViewport(); if (Chart.IsScrollingEnabled) return; var min = double.MaxValue; var max = double.MinValue; for (var i = Chart.FirstVisibleBarIndex; i <= Chart.LastVisibleBarIndex; i++) { if (MarketSeries.Low[i] < min) min = MarketSeries.Low[i]; if (MarketSeries.High[i] > max) max = MarketSeries.High[i]; } Chart.SetYRange(min - Symbol.PipSize * 10, max + Symbol.PipSize * 10); } private void UpdateViewport() { _viewportControl.Left = TransformBarIndexToX(0, Chart.BarsTotal, Chart.FirstVisibleBarIndex) - 1; _viewportControl.Width = TransformBarIndexToX(0, Chart.BarsTotal, Chart.LastVisibleBarIndex + 1) - TransformBarIndexToX(0, Chart.BarsTotal, Chart.FirstVisibleBarIndex) + 2; _viewportControl.Top = -10; _viewportControl.Height = IndicatorArea.Height + 20; } private void UpdateCloud() { _cloudControl.Points = GeneratePoints().ToArray(); } private IEnumerable<Point> GeneratePoints() { var density = 1 / Density; var series = Input; var high = series.Maximum(series.Count) + Symbol.PipSize; var low = series.Minimum(series.Count) - Symbol.PipSize; yield return new Point(0, IndicatorArea.Height); var lastGroupX = 0.0; var lastGroupY = 0.0; for (var i = 0; i < series.Count; i++) { var x = TransformBarIndexToX(0, series.Count - 1, i); var y = TransformPriceToY(low, high, series[i]); if (Math.Abs(lastGroupX - x) >= density) { yield return new Point(lastGroupX, lastGroupY); lastGroupX = x; } lastGroupY = y; } yield return new Point(IndicatorArea.Width + YAxisWidth, IndicatorArea.Height); } private void ScrollTo(double barIndex) { var newBarIndex = (int)Math.Round(barIndex + _dragOffset, MidpointRounding.AwayFromZero); if (newBarIndex < 0) newBarIndex = 0; if (newBarIndex >= Chart.BarsTotal) newBarIndex = Chart.BarsTotal - 1; Chart.ScrollXTo(newBarIndex); } private double TransformPriceToY(double min, double max, double val) { var height = IndicatorArea.Height - YAxisMargin * 2; var y = height - (val - min) / (max - min) * height; if (double.IsNaN(y)) y = IndicatorArea.Height; if (double.IsInfinity(y)) y = 0; return y + YAxisMargin; } private double TransformBarIndexToX(double min, double max, double val) { var x = (val - min) / (max - min) * (IndicatorArea.Width + YAxisWidth); if (double.IsNaN(x)) x = 0; if (double.IsInfinity(x)) x = IndicatorArea.Width + YAxisWidth; return x; } private double TransformXToBarIndex(double min, double max, double val) { var barIndex = (val - min) / (max - min) * (Chart.BarsTotal - 1); if (double.IsNaN(barIndex)) barIndex = 0; if (double.IsInfinity(barIndex)) barIndex = Chart.BarsTotal - 1; return barIndex; } } }
Comments