OnMouse Over

Created at 07 Mar 2019, 08:40
How’s your experience with the cTrader Platform?
Your feedback is crucial to cTrader's development. Please take a few seconds to share your opinion and help us improve your trading experience. Thanks!
lec0456's avatar

lec0456

Joined 14.11.2012

OnMouse Over
07 Mar 2019, 08:40


I would like to have some text appear on the chart when the mouse rolls over a chart object such as a Chart.DrawVerticalLine.

Is there a way to program this behavior?

Basically, I would think that there is some sort of event that couls be triggered to display a box of text.

The indicators do this by default now.  When you rollover a chart object it displays a small popup that has the name of the indicator, its settings and its current value.


@lec0456
Replies

PanagiotisCharalampous
07 Mar 2019, 09:57

Hi lec0456,

There is no direct way to do this but with a bit of code in Chart.Mouse move event I believe this is achievable. See below

        protected override void Initialize()
        {
            Chart.MouseMove += Chart_MouseMove;
        }

        private void Chart_MouseMove(ChartMouseEventArgs obj)
        {
           
        }

in the Chart_MouseMove() function you can monitor the obj.TimeValue and obj.YValue, and if they are in proximity to the relevant object, display your pop up.

Best Regards,

Panagiotis


@PanagiotisCharalampous

lec0456
07 Mar 2019, 13:18

How would I test for the TimeValue of a previously drawn vertical line? if I asign a drawverticle line to a variable like this

var divLine = Chart.DrawVerticalLine("Dayend" + index, index, Color.Orange, 1, LineStyle.DotsRare);

I get an error:

Error CS1023: Embedded statement cannot be a declaration or labeled statement


@lec0456

... Deleted by UFO ...

PanagiotisCharalampous
07 Mar 2019, 13:53

Hi lec0456,

I have no problem running the code below

using System;
using cAlgo.API;
using cAlgo.API.Internals;
using cAlgo.API.Indicators;
using cAlgo.Indicators;

namespace cAlgo
{
    [Indicator(IsOverlay = false, TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
    public class NewIndicator : Indicator
    {
        [Parameter(DefaultValue = 0.0)]
        public double Parameter { get; set; }

        [Output("Main")]
        public IndicatorDataSeries Result { get; set; }


        protected override void Initialize()
        {
            // Initialize and create nested indicators
        }

        public override void Calculate(int index)
        {
            var divLine = Chart.DrawVerticalLine("Dayend" + index, index, Color.Orange, 1, LineStyle.DotsRare);
            Print(divLine.Time);
        }
    }
}

Besr Regards,

Panagiotis


@PanagiotisCharalampous

bart1
07 Mar 2019, 14:04

RE:

lec0456 said:

I would like to have some text appear on the chart when the mouse rolls over a chart object such as a Chart.DrawVerticalLine.

Is there a way to program this behavior?

Basically, I would think that there is some sort of event that couls be triggered to display a box of text.

The indicators do this by default now.  When you rollover a chart object it displays a small popup that has the name of the indicator, its settings and its current value.

protected override void OnStart()
{
    Chart.ObjectHoverChanged += OnChartObjectHoverChanged;
}

void OnChartObjectHoverChanged(ChartObjectHoverChangedEventArgs obj)
{
    if (obj.IsObjectHovered)
        Chart.DrawStaticText("hoverText", obj.ChartObject.Name, VerticalAlignment.Top, HorizontalAlignment.Left, Chart.ColorSettings.ForegroundColor);
    else
        Chart.RemoveObject("hoverText");
}

 


@bart1

bart1
07 Mar 2019, 14:16

Btw there is a bug in API. When a new object is added to a chart bot receive hover event and object is null in the event args.

So you need to check a null check in the example above.


@bart1

PanagiotisCharalampous
07 Mar 2019, 14:19

RE: RE:

bart1 said:

lec0456 said:

I would like to have some text appear on the chart when the mouse rolls over a chart object such as a Chart.DrawVerticalLine.

Is there a way to program this behavior?

Basically, I would think that there is some sort of event that couls be triggered to display a box of text.

The indicators do this by default now.  When you rollover a chart object it displays a small popup that has the name of the indicator, its settings and its current value.

protected override void OnStart()
{
    Chart.ObjectHoverChanged += OnChartObjectHoverChanged;
}

void OnChartObjectHoverChanged(ChartObjectHoverChangedEventArgs obj)
{
    if (obj.IsObjectHovered)
        Chart.DrawStaticText("hoverText", obj.ChartObject.Name, VerticalAlignment.Top, HorizontalAlignment.Left, Chart.ColorSettings.ForegroundColor);
    else
        Chart.RemoveObject("hoverText");
}

 

Hi Bart,

That could work as well but you still need to distinguish which exact object is hovered, either by location or by name or any other unique property.

Best Regards,

Panagiotis


@PanagiotisCharalampous

lec0456
07 Mar 2019, 21:20

oK, I created a sample indicator but i can't get it to do anything. Not even print hello.

using System;
using cAlgo.API;
using cAlgo.API.Internals;
using cAlgo.API.Indicators;
using cAlgo.Indicators;
 
namespace cAlgo
{
    [Indicator(IsOverlay = false, TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
    public class NewIndicator : Indicator
    {
        [Parameter(DefaultValue = 0.0)]
        public double Parameter { get; set; }
 
        [Output("Main")]
        public IndicatorDataSeries Result { get; set; }
 
 
        protected override void Initialize()
        {
            Chart.MouseMove += Chart_MouseMove;
            Chart.ObjectHoverChanged += OnChartObjectHoverChanged;
        }
 
        public override void Calculate(int index)
        {
            var divLine = Chart.DrawVerticalLine("Dayend" + index, index, Color.Orange, 1, LineStyle.DotsRare);
            Print(divLine.Time);
        }
        
        private void Chart_MouseMove(ChartMouseEventArgs obj)
        {
    
        }
        
        void OnChartObjectHoverChanged(ChartObjectHoverChangedEventArgs obj)
        {           
            if (obj.IsObjectHovered)
            {     
                if(Chart!=null)Chart.DrawStaticText("hoverText", obj.ChartObject.Name, VerticalAlignment.Top, HorizontalAlignment.Left, Chart.ColorSettings.ForegroundColor);
            }
            else
                Chart.RemoveObject("hoverText");
        }
    }
}

 


@lec0456

lec0456
08 Mar 2019, 03:00

I have been trying all kinds of stuff without any success.

 

The OnChartObjectHoverChanged won't fire at all. i used the mouse move to test but there does not seem to be a way to get the time value from the chart object in order to compare it to the mouseMoveEventArgs.

 

        private void Chart_MouseMove(ChartMouseEventArgs obj)
        {
            Print("objects:"+obj.Chart.Objects.Count);
            Print("name:{0} Type:{1} Z:{2}", obj.ChartArea.Objects[0].Name, obj.ChartArea.Objects[0].ObjectType, Chart.Objects[0].ZIndex);
            obj.ChartArea.
            Print("Barindex:{0} Timevalue:{1} YValue:{2}",obj.BarIndex,obj.TimeValue,obj.YValue);
            foreach (object _object in obj.Chart.Objects)
            Print("obj:"+_object.ToString());
            
        }

 


@lec0456

lec0456
08 Mar 2019, 03:18

Well, I figured out why the onHover is not working: DrawVerticalLine is not interactive.  So which objects are?

Isinteractive: Defines whether the instance is interactive. The non-interactive chart objects cannot be selected, have no hover effect and cannot be searched. Available only to the current cBot or Indicator and will be removed when the cBot/Indicator stops TBD


@lec0456

lec0456
08 Mar 2019, 03:24

Ok, so i got the ObjectHoverChanged to fire.  you have to set the interactive property, like so...

                var divLine = Chart.DrawVerticalLine("Dayend" + index, index, Color.Orange, 1, LineStyle.DotsRare);
                divLine.IsInteractive=true;

 

So, now the question remains, whether the On mouseMove can get the coordinates of an object that is not interactive?


@lec0456

lec0456
08 Mar 2019, 05:50

Well, the DrawVerticleLine allows the user to move the line, so this is not the behavior I want.

 

Bottom line is that I can find no way to get the indexbar, time or y-value of the chartobjects. I can get the char object name and the list of objects but not the other properties.


@lec0456

lec0456
08 Mar 2019, 08:38

Ok! Well, I figured it out! It may not be optimal, if there is a way to get the VerticalLine index returned to the MouseMove event. But since I could not figure out how to get that information I crated my own list with the data for the ojects. Here is the code.

 

using System;
using cAlgo.API;
using cAlgo.API.Internals;
using cAlgo.API.Indicators;
using cAlgo.Indicators;
using System.Collections.Generic;
using System.Linq;
 
namespace cAlgo
{
    [Indicator(IsOverlay = true, TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
    public class NewIndicator : Indicator
    {
        [Parameter(DefaultValue = 0.0)]
        public double Parameter { get; set; }
 
        [Output("Main")]
        public IndicatorDataSeries Result { get; set; }
        
        public class VerticalLine : ChartVerticalLine
        {
            public DateTime Time{ get; set;}
            public int Thickness{ get; set; }
            public LineStyle LineStyle{ get; set; }
            public Color Color{ get; set; }
            public string Name { get; set; }
            public string Comment { get; set; }
            public bool IsInteractive { get; set; }
            public bool  IsAlive { get; set; }
            public ChartObjectType ObjectType { get; set; }
            public int ZIndex { get; set; }
            public int Index { get; set;}            
            
            public  VerticalLine (string _name, int _index, DateTime _datetime, string _comment)
            {
                Name=_name;
                Index=_index;
                Time=_datetime;
                Comment=_comment;
            }
        }
        
        List<VerticalLine> AllVerticelLines; 
        
        protected override void Initialize()
        {
            AllVerticelLines = new List<VerticalLine>();
            Chart.MouseMove += Chart_MouseMove;
            Chart.ObjectHoverChanged += OnChartObjectHoverChanged;
            Chart.MouseDown += Chart_MouseDown;
            Chart.MouseUp += Chart_MouseUp;
        }

        public override void Calculate(int index)
        {
            //Just creates some sample Verticle lines for testing
            if(MarketSeries.OpenTime[index].Hour == 8 && MarketSeries.OpenTime[index]>Convert.ToDateTime("2/1/2019"))
            {
                var divLine = Chart.DrawVerticalLine("Dayend" + index, index, Color.Orange, 1, LineStyle.DotsRare);
                divLine.Comment="This is news: " + index;
                AllVerticelLines.Add(new VerticalLine(divLine.Name, index, divLine.Time,divLine.Comment));
            }
        }
        
        private void Chart_MouseMove(ChartMouseEventArgs obj)
        {
            List<VerticalLine> OnScreenVerticleLines = AllVerticelLines.Where(x=> x.Index>=obj.Chart.FirstVisibleBarIndex && x.Index<=obj.Chart.LastVisibleBarIndex).ToList();
            for (var i = 0; i < OnScreenVerticleLines.Count; i++)
            {    
                if(obj.TimeValue==OnScreenVerticleLines[i].Time)
                {
                    var newsText = Chart.DrawText("NewsText", AllVerticelLines[i].Comment, obj.TimeValue, obj.YValue, Color.White);
                    newsText.VerticalAlignment = VerticalAlignment.Center;
                    newsText.HorizontalAlignment = HorizontalAlignment.Center;
                }                    
            }
            
            //*** For testing purposes ***           
            //Print("Alllines:{0} Onscreen:{1}",OnScreenVerticleLines.Count,AllVerticelLines.Count);
            //Chart.RemoveObject("hoverText");
            //Print(MarketSeries.OpenTime[obj.Chart.FirstVisibleBarIndex].ToString("MM/dd/yyyy HH:mm"));
            //Print(MarketSeries.OpenTime[obj.Chart.LastVisibleBarIndex].ToString("MM/dd/yyyy HH:mm"));
            //Print(obj.Chart.LastVisibleBarIndex);                    
            //Print("objects:"+obj.Chart.Objects.Count);
            //Print("Name:{0} Type:{1} Z:{2} InterAct:{3}", obj.ChartArea.Objects[0].Name, obj.ChartArea.Objects[0].ObjectType, Chart.Objects[0].ZIndex, Chart.Objects[0].IsInteractive);
            //Print("Barindex:{0} Timevalue:{1} YValue:{2}",obj.BarIndex,obj.TimeValue,obj.YValue);
            //foreach (object _object in obj.Chart.Objects)
            //    Print("obj:"+_object.ToString());
        }
        
        private void Chart_MouseDown(ChartMouseEventArgs obj)
        {
            Chart.RemoveObject("NewsText");
        }
        
        //*** Not Used here but left here as an example
        void OnChartObjectHoverChanged(ChartObjectHoverChangedEventArgs obj)
        {           
            if (obj.IsObjectHovered)
            {
                Chart.DrawStaticText("NewsText", obj.ChartObject.Name, VerticalAlignment.Bottom, HorizontalAlignment.Left, Color.White);
            }
            else
            {
                Chart.RemoveObject("NewsText");
            }
        }
        
        private void Chart_MouseUp(ChartMouseEventArgs obj)
        {
            
        }
    }
}

 


@lec0456

lec0456
08 Mar 2019, 08:43 ( Updated at: 21 Dec 2023, 09:21 )

Here is an example


@lec0456

PanagiotisCharalampous
08 Mar 2019, 10:17

Hi lec0456,

ObjectHoverChanged works for non interactive objects as well. See below how to get the index of the hovered line

using System;
using System.Linq;
using cAlgo.API;
using cAlgo.API.Indicators;
using cAlgo.API.Internals;
using cAlgo.Indicators;

namespace cAlgo.Robots
{
    [Robot(TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
    public class NewcBot : Robot
    {
        [Parameter(DefaultValue = 0.0)]
        public double Parameter { get; set; }

        protected override void OnStart()
        {
            Chart.ObjectHoverChanged += OnChartObjectHoverChanged;
            var divLine = Chart.DrawVerticalLine("Dayend", Server.Time, Color.Orange, 1, LineStyle.DotsRare);
        }

        void OnChartObjectHoverChanged(ChartObjectHoverChangedEventArgs obj)
        {
            if (obj.IsObjectHovered)
            {
                if (Chart != null)
                    Chart.DrawStaticText("hoverText", obj.ChartObject.Name, VerticalAlignment.Top, HorizontalAlignment.Left, Chart.ColorSettings.ForegroundColor);
                if (obj.ChartObject is ChartVerticalLine)
                    Print("Index " + (obj.ChartObject as ChartVerticalLine).Time);
            }
            else
                Chart.RemoveObject("hoverText");
        }

        protected override void OnTick()
        {
            // Put your core logic here
        }

        protected override void OnStop()
        {
            // Put your deinitialization logic here
        }
    }
}

Best Regards,

Panagiotis


@PanagiotisCharalampous

lec0456
08 Mar 2019, 11:15

I see what you have done. It looked promising but i can't get it to work. It looks like this is a Robot not an indicator.  I copied it exactly as above but it does not print the index and does not show the line. Are you sure this works?

I tried revising it like below but still no luck.

using System;
using System.Linq;
using cAlgo.API;
using cAlgo.API.Indicators;
using cAlgo.API.Internals;
using cAlgo.Indicators;
 
namespace cAlgo
{
    [Indicator(IsOverlay = true, TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
    public class NewIndicator : Indicator
    {
        [Parameter(DefaultValue = 0.0)]
        public double Parameter { get; set; }
 
        protected override void Initialize()
        {
            Chart.ObjectHoverChanged += OnChartObjectHoverChanged;
        }
        
        public override void Calculate(int index)
        {
            if(MarketSeries.OpenTime[index].Hour == 8 && MarketSeries.OpenTime[index]>Convert.ToDateTime("2/1/2019"))
            {
                var divLine = Chart.DrawVerticalLine("Dayend" + index, index, Color.Orange, 1, LineStyle.DotsRare);
                divLine.Comment="This is news: " + index;
                //AllVerticelLines.Add(new VerticalLine(divLine.Name, index, divLine.Time,divLine.Comment));
            }
        }
        void OnChartObjectHoverChanged(ChartObjectHoverChangedEventArgs obj)
        {
            if (obj.IsObjectHovered)
            {
                if (Chart != null)
                    Chart.DrawStaticText("hoverText", obj.ChartObject.Name, VerticalAlignment.Top, HorizontalAlignment.Left, Chart.ColorSettings.ForegroundColor);
                if (obj.ChartObject is ChartVerticalLine)
                    Print("Index " + (obj.ChartObject as ChartVerticalLine).Time);
            }
            else
                Chart.RemoveObject("hoverText");
        }
 
    }
}

 


@lec0456

PanagiotisCharalampous
08 Mar 2019, 11:47

Hi lec0456,

Sorry, my mistake, it does not work for non interactive objects. But we will add this feature in an upcoming update.

Best Regards,

Panagiotis


@PanagiotisCharalampous

lec0456
08 Mar 2019, 12:28

This will be great however, let me mention that even if it worked as you suggested, We would still be missing the YValue of the Hover Object.  With the Mouse move I can ge tthe YValue but no ChartObject is returned only the whole list of ChartObjects. I could iterate through the chart objects and find one with the same Time value and ChartObject type to trigger a Drawtext  but this could be inefficient and expensive. There is no way to limit the objects returned by the mousemove event, so you have to iterate through all objects from the begining of the chart.  

So, for the OnChartHover Changed to be complete all you need to do is add the non-interactive chart objects and return the Yvalue of where you hovered over.

 


@lec0456