Category Other  Published on 05/01/2022

Economic Events On Chart

Description

This indicator shows the current week economic news events on your charts in form of vertical lines.

It uses ForexFactory for getting news events data.

To see full info of news event right click on its vertical line.

Changelog:

Version 1.1.0

Release Date: January 5, 2022

Added: Show past events parameter

Github: 

 


using System;
using cAlgo.API;
using System.Collections.Generic;
using System.Xml;
using System.Net;
using System.Xml.Serialization;
using System.IO;
using System.Text;
using System.Linq;
using System.Globalization;

namespace cAlgo
{
    [Indicator(IsOverlay = true, TimeZone = TimeZones.UTC, AccessRights = AccessRights.Internet)]
    public class EconomicEventsOnChart : Indicator
    {
        private Color _colorHighImpact, _colorMediumImpact, _colorLowImpact, _colorOthers;

        private TextBlock _textBlock;

        [Parameter("Data URI", DefaultValue = "https://nfs.faireconomy.media/ff_calendar_thisweek.xml", Group = "General")]
        public string DataUri { get; set; }

        [Parameter("Only Symbol Events", DefaultValue = true, Group = "General")]
        public bool OnlySymbolEvents { get; set; }

        [Parameter("Show Past Events", DefaultValue = true, Group = "General")]
        public bool ShowPastEvents { get; set; }

        [Parameter("Show", DefaultValue = true, Group = "High Impact")]
        public bool ShowHighImpact { get; set; }

        [Parameter("Color", DefaultValue = "Red", Group = "High Impact")]
        public string ColorHighImpact { get; set; }

        [Parameter("Style", DefaultValue = LineStyle.Solid, Group = "High Impact")]
        public LineStyle LineStyleHighImpact { get; set; }

        [Parameter("Thickness", DefaultValue = 1, Group = "High Impact")]
        public int ThicknessHighImpact { get; set; }

        [Parameter("Show", DefaultValue = true, Group = "Medium Impact")]
        public bool ShowMediumImpact { get; set; }

        [Parameter("Color", DefaultValue = "Gold", Group = "Medium Impact")]
        public string ColorMediumImpact { get; set; }

        [Parameter("Style", DefaultValue = LineStyle.Solid, Group = "Medium Impact")]
        public LineStyle LineStyleMediumImpact { get; set; }

        [Parameter("Thickness", DefaultValue = 1, Group = "Medium Impact")]
        public int ThicknessMediumImpact { get; set; }

        [Parameter("Show", DefaultValue = true, Group = "Low Impact")]
        public bool ShowLowImpact { get; set; }

        [Parameter("Color", DefaultValue = "Yellow", Group = "Low Impact")]
        public string ColorLowImpact { get; set; }

        [Parameter("Style", DefaultValue = LineStyle.Solid, Group = "Low Impact")]
        public LineStyle LineStyleLowImpact { get; set; }

        [Parameter("Thickness", DefaultValue = 1, Group = "Low Impact")]
        public int ThicknessLowImpact { get; set; }

        [Parameter("Show", DefaultValue = false, Group = "Others")]
        public bool ShowOthers { get; set; }

        [Parameter("Color", DefaultValue = "Gray", Group = "Others")]
        public string ColorOthers { get; set; }

        [Parameter("Style", DefaultValue = LineStyle.Solid, Group = "Others")]
        public LineStyle LineStyleOthers { get; set; }

        [Parameter("Thickness", DefaultValue = 1, Group = "Others")]
        public int ThicknessOthers { get; set; }

        [Parameter("Show", DefaultValue = true, Group = "Text Block")]
        public bool ShowTextBlock { get; set; }

        [Parameter("Background Color", DefaultValue = "#969696", Group = "Text Block")]
        public string TextBlockBackgroundColor { get; set; }

        [Parameter("Color", DefaultValue = "White", Group = "Text Block")]
        public string TextBlockColor { get; set; }

        [Parameter("Horizontal Alignment", DefaultValue = HorizontalAlignment.Center, Group = "Text Block")]
        public HorizontalAlignment TextBlockHorizontalAlignment { get; set; }

        [Parameter("Vertical Alignment", DefaultValue = VerticalAlignment.Bottom, Group = "Text Block")]
        public VerticalAlignment TextBlockVerticalAlignment { get; set; }

        [Parameter("Text Alignment", DefaultValue = TextAlignment.Center, Group = "Text Block")]
        public TextAlignment TextBlockTextAlignment { get; set; }

        [Parameter("Font Weight", DefaultValue = FontWeight.Bold, Group = "Text Block")]
        public FontWeight TextBlockFontWeight { get; set; }

        protected override void Initialize()
        {
            RemoveEventLines();

            if (ShowTextBlock)
            {
                _textBlock = new TextBlock
                {
                    IsVisible = false,
                    HorizontalAlignment = TextBlockHorizontalAlignment,
                    VerticalAlignment = TextBlockVerticalAlignment,
                    BackgroundColor = GetColor(TextBlockBackgroundColor),
                    ForegroundColor = GetColor(TextBlockColor),
                    TextAlignment = TextBlockTextAlignment,
                    FontWeight = TextBlockFontWeight,
                    Padding = 5
                };

                Chart.AddControl(_textBlock);

                Chart.ObjectHoverChanged += Chart_ObjectHoverChanged;
            }

            _colorHighImpact = GetColor(ColorHighImpact);
            _colorMediumImpact = GetColor(ColorMediumImpact);
            _colorLowImpact = GetColor(ColorLowImpact);
            _colorOthers = GetColor(ColorOthers);

            var events = GetNewsEvents();

            DisplayEvents(events);
        }

        private void Chart_ObjectHoverChanged(ChartObjectHoverChangedEventArgs obj)
        {
            if (!obj.IsObjectHovered || obj.ChartObject == null || string.IsNullOrWhiteSpace(obj.ChartObject.Name) || !obj.ChartObject.Name.EndsWith("Event", StringComparison.OrdinalIgnoreCase))
            {
                _textBlock.IsVisible = false;

                return;
            }

            _textBlock.Text = string.Format("{0} | {1}", obj.ChartObject.Name.Replace(" | Event", string.Empty), obj.ChartObject.Comment);

            _textBlock.IsVisible = true;
        }

        public override void Calculate(int index)
        {
        }

        private IEnumerable<NewsEvent> GetNewsEvents()
        {
            using (var webClient = new WebClient())
            {
                var data = webClient.DownloadString(DataUri);

                return GetNewsEventsFromXml(data);
            }
        }

        private IEnumerable<NewsEvent> GetNewsEventsFromXml(string xml)
        {
            var xmlSerializer = new XmlSerializer(typeof(WeeklyEvents));

            var stream = new StringReader(xml);

            var weeklyEvents = xmlSerializer.Deserialize(stream) as WeeklyEvents;

            foreach (var newsEvent in weeklyEvents.Events)
            {
                var timeString = string.Format("{0} {1}", newsEvent.UtcDate, newsEvent.UtcTime);

                DateTimeOffset time;

                if (DateTimeOffset.TryParseExact(timeString, "MM-dd-yyyy h:mmtt", CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal, out time))
                {
                    newsEvent.Time = time;
                }
            }

            return weeklyEvents.Events;
        }

        private void DisplayEvents(IEnumerable<NewsEvent> events)
        {
            foreach (var newsEvent in events)
            {
                if (!newsEvent.Time.HasValue
                    || (newsEvent.Impact == NewsEventImpact.High && !ShowHighImpact)
                    || (newsEvent.Impact == NewsEventImpact.Medium && !ShowMediumImpact)
                    || (newsEvent.Impact == NewsEventImpact.Low && !ShowLowImpact)
                    || ((newsEvent.Impact == NewsEventImpact.None || newsEvent.Impact == NewsEventImpact.Holiday) && !ShowOthers)
                    || (OnlySymbolEvents && !IsEventRelatedToSymbol(newsEvent.Currency))
                    || (!ShowPastEvents && newsEvent.Time < Server.TimeInUtc)) continue;

                var lineSettings = GetLineSettings(newsEvent.Impact);

                var eventLine = Chart.DrawVerticalLine(string.Format("{0} | {1} | {2} | Event", newsEvent.Title, newsEvent.Currency, newsEvent.Impact), newsEvent.Time.Value.UtcDateTime, lineSettings.Color, lineSettings.Thickness, lineSettings.Style);

                var stringBuilder = new StringBuilder();

                if (!string.IsNullOrWhiteSpace(newsEvent.Forecast))
                {
                    stringBuilder.Append(string.Format("Forecast: {0} | ", newsEvent.Forecast));
                }

                if (!string.IsNullOrWhiteSpace(newsEvent.Previous))
                {
                    stringBuilder.Append(string.Format("Previous: {0} | ", newsEvent.Previous));
                }

                if (newsEvent.Time.HasValue)
                {
                    var time = newsEvent.Time.Value.ToOffset(Application.UserTimeOffset);

                    stringBuilder.Append(string.Format("Time: {0:s}", time));
                }

                eventLine.Comment = stringBuilder.ToString();
                eventLine.IsInteractive = true;
                eventLine.IsLocked = true;
            }
        }

        private bool IsEventRelatedToSymbol(string eventCurrency)
        {
            return SymbolName.StartsWith(eventCurrency, StringComparison.OrdinalIgnoreCase) || SymbolName.EndsWith(eventCurrency, StringComparison.OrdinalIgnoreCase);
        }

        private Color GetColor(string colorString, int alpha = 255)
        {
            var color = colorString[0] == '#' ? Color.FromHex(colorString) : Color.FromName(colorString);

            return Color.FromArgb(alpha, color);
        }

        private LineSettings GetLineSettings(NewsEventImpact impact)
        {
            switch (impact)
            {
                case NewsEventImpact.High:
                    return new LineSettings
                    {
                        Color = _colorHighImpact,
                        Style = LineStyleHighImpact,
                        Thickness = ThicknessHighImpact
                    };

                case NewsEventImpact.Medium:
                    return new LineSettings
                    {
                        Color = _colorMediumImpact,
                        Style = LineStyleMediumImpact,
                        Thickness = ThicknessMediumImpact
                    };

                case NewsEventImpact.Low:
                    return new LineSettings
                    {
                        Color = _colorLowImpact,
                        Style = LineStyleLowImpact,
                        Thickness = ThicknessLowImpact
                    };

                default:
                    return new LineSettings
                    {
                        Color = _colorOthers,
                        Style = LineStyleOthers,
                        Thickness = ThicknessOthers
                    };
            }
        }

        private void RemoveEventLines()
        {
            var chartObjects = Chart.Objects.ToArray();

            foreach (var chartObject in chartObjects)
            {
                if (chartObject.ObjectType != ChartObjectType.VerticalLine || !chartObject.IsInteractive || string.IsNullOrEmpty(chartObject.Name) || !chartObject.Name.EndsWith("Event", StringComparison.OrdinalIgnoreCase))
                {
                    continue;
                }

                Chart.RemoveObject(chartObject.Name);
            }
        }
    }

    [XmlRoot("weeklyevents")]
    public class WeeklyEvents
    {
        [XmlElement("event")]
        public List<NewsEvent> Events { get; set; }
    }

    public class NewsEvent
    {
        [XmlElement("title")]
        public string Title { get; set; }

        [XmlElement("country")]
        public string Currency { get; set; }

        [XmlElement("date")]
        public string UtcDate { get; set; }

        [XmlElement("time")]
        public string UtcTime { get; set; }

        [XmlIgnore]
        public DateTimeOffset? Time { get; set; }

        [XmlElement("impact")]
        public NewsEventImpact Impact { get; set; }

        [XmlElement("previous")]
        public string Previous { get; set; }

        [XmlElement("forecast")]
        public string Forecast { get; set; }
    }

    public enum NewsEventImpact
    {
        None,

        High,

        Medium,

        Low,

        Holiday
    }

    public struct LineSettings
    {
        public Color Color { get; set; }

        public LineStyle Style { get; set; }

        public int Thickness { get; set; }
    }
}

Spotware's avatar
Spotware

Joined on 23.09.2013

  • Distribution: Free
  • Language: C#
  • Trading platform: cTrader Automate
  • File name: Economic Events On Chart.algo
  • Rating: 5
  • Installs: 3626
  • Modified: 05/01/2022 09:05
Comments
Log in to add a comment.
CT
ctid6328327 · 1 year ago

Hi there, my cbot is trading only the high-impact news, but the timing I have to set it manually. Could you please help me to implement this into the code so that the cbot is trading automatically? Thank you.

EM
emmanbrownusa · 1 year ago

good

TR
tradex1 · 2 years ago

BuG Report

The show past events option only works when manually changed, therefore all events stay on charts till timeframe is changed on each and every chart or you toggle the option to yes then no everytime.

Feature request:

Audio alerts where a spoken word audio file could be attached would be amazing

Would also be great to have the option of changing the opacity so the events lines don't dominate the chart

Please vote for these features or forever lost

thanks
much appreciated

TR
tradex1 · 2 years ago

When this indicator is installed on 1 chart combined with sync objects on 5 charts/timeframes, the machine (high end) hangs with cpu sitting constantly on 20-25% power usage at "very high" in a loop till ctrader is forced closed through task manager

Would these indicators be able to be run on multiple instruments and multiple charts at the same time?

Already posted a message on sync objects, but seems this indicator pushes it over the edge crashing

Thanks 

TR
traderfxmaster007 · 2 years ago

Hi,  I am not a programmer and have no knowledge about coding but with the help of some google search ???? I am able to make a cbot of my own. Not I would like to copy your code and put it in my cbot, to close all open trades and not to open new trades in the X number of hours before and after news events on a particular pair. Can you please provide an example on how to make it? Tanks.