Need help to send email only once

Created at 20 Jul 2018, 00:21
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!
VI

Vince

Joined 04.12.2017

Need help to send email only once
20 Jul 2018, 00:21


{
                var value = MarketSeries.Close[index - 1];
                if (Functions.HasCrossedBelow(_downBufferlong, value, 1))
                {
                    var name = "SellLong";
                    var low = MarketSeries.Low[index - 1];
                    var text = low.ToString();
                    var xPos = index - 1;
                    var yPos = low;
                    var vAlign = VerticalAlignment.Bottom;
                    var hAlign = HorizontalAlignment.Center;
                    ChartObjects.DrawText(name, text, xPos, yPos, vAlign, hAlign, Colors.PeachPuff);
                    {
                        var lowemail = MarketSeries.Low[index - 1];
                        var subject = lowemail.ToString();
                        Notifications.SendEmail("from@email", "to@email", "Up " + Symbol.Code + " " + subject, "Up " + Symbol.Code + " " + subject);
                    }
                }
}

I am trying to get only 1 email send if the MarketSeries.Close has crossed above the DataSeries. Now it will keep sending me emails on every tick. The Chartobjects.Drawtext displays just fine and only once.

I tried switchinging the DataSeries, but it gave an error.

I just can't figure out how to get only 1 email.

Thanks in advance.

 

 


@Vince
Replies

PanagiotisCharalampous
20 Jul 2018, 09:24

Hi Vince,

In this case, you can raise a flag when the email is sent and reset it on each bar change. If you post the full cBot code, I can show you how to do it.

Best Regards,

Panagiotis


@PanagiotisCharalampous

Vince
20 Jul 2018, 16:28

Hi Panagiotis,

Thank you for your swift reply. Below you will find the full code.

Basicly this is a modified version of the Supertrend indicator from spka111 to display the Supertrend, but with different settings. I added a DrawText option to display the High or Low of the closed candle that has crossed the Supertrend, which displays just fine.

I also tried to add a Sendemail option which would notify me of the above described event. This works, but instead of getting just 1 email, it will continue to send emails for every tick during the following period. That is the last problem I am trying to solve: to only send 1 email of the High or Low of the closed candle that has crossed the Supertrend.

Kind Regards,

Vince

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

namespace cAlgo.Indicators
{
    [Indicator(IsOverlay = true, AccessRights = AccessRights.None)]
    public class SupertrendCompleteTestEmail : Indicator
    {
        [Parameter(DefaultValue = 50)]
        public int LongPeriod { get; set; }

        [Parameter(DefaultValue = 10.0)]
        public double LongMultiplier { get; set; }

        [Parameter(DefaultValue = 20)]
        public int ShortPeriod { get; set; }

        [Parameter(DefaultValue = 5.0)]
        public double ShortMultiplier { get; set; }

        [Output("UpTrendLong", Color = Colors.Green, PlotType = PlotType.Points, Thickness = 3)]
        public IndicatorDataSeries UpTrendLong { get; set; }

        [Output("DownTrendLong", Color = Colors.Red, PlotType = PlotType.Points, Thickness = 3)]
        public IndicatorDataSeries DownTrendLong { get; set; }

        [Output("UpTrendShort", Color = Colors.Green, PlotType = PlotType.Points, Thickness = 3)]
        public IndicatorDataSeries UpTrendShort { get; set; }

        [Output("DownTrendShort", Color = Colors.Red, PlotType = PlotType.Points, Thickness = 3)]
        public IndicatorDataSeries DownTrendShort { get; set; }

        private IndicatorDataSeries _upBufferlong;
        private IndicatorDataSeries _downBufferlong;
        private IndicatorDataSeries _upBuffershort;
        private IndicatorDataSeries _downBuffershort;
        private AverageTrueRange _averageTrueRangelong;
        private AverageTrueRange _averageTrueRangeshort;
        private int[] _trendlong;
        private int[] _trendshort;
        private bool _changeofTrendlong;
        private bool _changeofTrendshort;

        protected override void Initialize()
        {

            _trendlong = new int[1];
            _trendshort = new int[1];
            _upBufferlong = CreateDataSeries();
            _downBufferlong = CreateDataSeries();
            _upBuffershort = CreateDataSeries();
            _downBuffershort = CreateDataSeries();
            _averageTrueRangelong = Indicators.AverageTrueRange(LongPeriod, MovingAverageType.WilderSmoothing);
            _averageTrueRangeshort = Indicators.AverageTrueRange(ShortPeriod, MovingAverageType.WilderSmoothing);
        }

        public override void Calculate(int index)
        {
            // Init
            UpTrendLong[index] = double.NaN;
            DownTrendLong[index] = double.NaN;
            UpTrendShort[index] = double.NaN;
            DownTrendShort[index] = double.NaN;

            double median = (MarketSeries.High[index] + MarketSeries.Low[index]) / 2;
            double atrlong = _averageTrueRangelong.Result[index];
            double atrshort = _averageTrueRangeshort.Result[index];

            _upBufferlong[index] = median + LongMultiplier * atrlong;
            _downBufferlong[index] = median - LongMultiplier * atrlong;
            _upBuffershort[index] = median + ShortMultiplier * atrshort;
            _downBuffershort[index] = median - ShortMultiplier * atrshort;


            if (index < 1)
            {
                _trendlong[index] = 1;
                return;
            }

            Array.Resize(ref _trendlong, _trendlong.Length + 1);

            // Main Logic
            if (MarketSeries.Close[index] > _upBufferlong[index - 1])
            {
                _trendlong[index] = 1;
                if (_trendlong[index - 1] == -1)
                    _changeofTrendlong = true;
            }
            else if (MarketSeries.Close[index] < _downBufferlong[index - 1])
            {
                _trendlong[index] = -1;
                if (_trendlong[index - 1] == -1)
                    _changeofTrendlong = true;
            }
            else if (_trendlong[index - 1] == 1)
            {
                _trendlong[index] = 1;
                _changeofTrendlong = false;
            }
            else if (_trendlong[index - 1] == -1)
            {
                _trendlong[index] = -1;
                _changeofTrendlong = false;
            }

            if (_trendlong[index] < 0 && _trendlong[index - 1] > 0)
                _upBufferlong[index] = median + (LongMultiplier * atrlong);
            else if (_trendlong[index] < 0 && _upBufferlong[index] > _upBufferlong[index - 1])
                _upBufferlong[index] = _upBufferlong[index - 1];

            if (_trendlong[index] > 0 && _trendlong[index - 1] < 0)
                _downBufferlong[index] = median - (LongMultiplier * atrlong);
            else if (_trendlong[index] > 0 && _downBufferlong[index] < _downBufferlong[index - 1])
                _downBufferlong[index] = _downBufferlong[index - 1];

            // Draw Indicator
            if (_trendlong[index] == 1)
            {

                UpTrendLong[index] = _downBufferlong[index];
                if (_changeofTrendlong)
                {
                    UpTrendLong[index - 1] = DownTrendLong[index - 1];
                    _changeofTrendlong = false;
                }
            }
            else if (_trendlong[index] == -1)
            {

                DownTrendLong[index] = _upBufferlong[index];
                if (_changeofTrendlong)
                {
                    DownTrendLong[index - 1] = UpTrendLong[index - 1];
                    _changeofTrendlong = false;
                }

            }

            if (index < 1)
            {
                _trendshort[index] = 1;
                return;
            }

            Array.Resize(ref _trendshort, _trendshort.Length + 1);

            // Main Logic
            if (MarketSeries.Close[index] > _upBuffershort[index - 1])
            {
                _trendshort[index] = 1;
                if (_trendshort[index - 1] == -1)
                    _changeofTrendshort = true;
            }
            else if (MarketSeries.Close[index] < _downBuffershort[index - 1])
            {
                _trendshort[index] = -1;
                if (_trendshort[index - 1] == -1)
                    _changeofTrendshort = true;
            }
            else if (_trendshort[index - 1] == 1)
            {
                _trendshort[index] = 1;
                _changeofTrendshort = false;
            }
            else if (_trendshort[index - 1] == -1)
            {
                _trendshort[index] = -1;
                _changeofTrendshort = false;
            }

            if (_trendshort[index] < 0 && _trendshort[index - 1] > 0)
                _upBuffershort[index] = median + (ShortMultiplier * atrshort);
            else if (_trendshort[index] < 0 && _upBuffershort[index] > _upBuffershort[index - 1])
                _upBuffershort[index] = _upBuffershort[index - 1];

            if (_trendshort[index] > 0 && _trendshort[index - 1] < 0)
                _downBuffershort[index] = median - (ShortMultiplier * atrshort);
            else if (_trendshort[index] > 0 && _downBuffershort[index] < _downBuffershort[index - 1])
                _downBuffershort[index] = _downBuffershort[index - 1];

            // Draw Indicator
            if (_trendshort[index] == 1)
            {

                UpTrendShort[index] = _downBuffershort[index];
                if (_changeofTrendshort)
                {
                    UpTrendShort[index - 1] = DownTrendShort[index - 1];
                    _changeofTrendshort = false;
                }
            }
            else if (_trendshort[index] == -1)
            {

                DownTrendShort[index] = _upBuffershort[index];
                if (_changeofTrendshort)
                {
                    DownTrendShort[index - 1] = UpTrendShort[index - 1];
                    _changeofTrendshort = false;
                }
            }

            // Test Notifications on chart
            {
                var value = MarketSeries.Close[index - 1];
                if (Functions.HasCrossedAbove(_upBufferlong, value, 1))
                {
                    var name = "BuyLong";
                    var high = MarketSeries.High[index - 1];
                    var text = high.ToString();
                    var xPos = index - 1;
                    var yPos = high;
                    var vAlign = VerticalAlignment.Top;
                    var hAlign = HorizontalAlignment.Center;
                    ChartObjects.DrawText(name, text, xPos, yPos, vAlign, hAlign, Colors.Lime);

                    {
                        var highemail = MarketSeries.High[index - 1];
                        var subject = highemail.ToString();
                        Notifications.SendEmail("email", "email", "Buy Long " + Symbol.Code + " " + subject, Symbol.Code + " " + subject);
                    }
                }
            }

            {
                var value = MarketSeries.Close[index - 1];
                if (Functions.HasCrossedBelow(_downBufferlong, value, 1))
                {
                    var name = "SellLong";
                    var low = MarketSeries.Low[index - 1];
                    var text = low.ToString();
                    var xPos = index - 1;
                    var yPos = low;
                    var vAlign = VerticalAlignment.Bottom;
                    var hAlign = HorizontalAlignment.Center;
                    ChartObjects.DrawText(name, text, xPos, yPos, vAlign, hAlign, Colors.PeachPuff);
                    {
                        var lowemail = MarketSeries.Low[index - 1];
                        var subject = lowemail.ToString();
                        Notifications.SendEmail("email", "email", "Buy Long " + Symbol.Code + " " + subject, Symbol.Code + " " + subject);
                    }
                }
            }

            // Test Notifications on chart
            {
                var value = MarketSeries.Close[index - 1];
                if (Functions.HasCrossedAbove(_upBuffershort, value, 1))
                {
                    var name = "BuyShort";
                    var high = MarketSeries.High[index - 1];
                    var text = high.ToString();
                    var xPos = index - 1;
                    var yPos = high;
                    var vAlign = VerticalAlignment.Top;
                    var hAlign = HorizontalAlignment.Center;
                    ChartObjects.DrawText(name, text, xPos, yPos, vAlign, hAlign, Colors.Green);
                    {
                        var highemail = MarketSeries.High[index - 1];
                        var subject = highemail.ToString();
                        Notifications.SendEmail("email", "email", "Buy Long " + Symbol.Code + " " + subject, Symbol.Code + " " + subject);
                    }
                }
            }

            {
                var value = MarketSeries.Close[index - 1];
                if (Functions.HasCrossedBelow(_downBuffershort, value, 1))
                {
                    var name = "SellShort";
                    var low = MarketSeries.Low[index - 1];
                    var text = low.ToString();
                    var xPos = index - 1;
                    var yPos = low;
                    var vAlign = VerticalAlignment.Bottom;
                    var hAlign = HorizontalAlignment.Center;
                    ChartObjects.DrawText(name, text, xPos, yPos, vAlign, hAlign, Colors.Red);
                    {

                        var lowemail = MarketSeries.Low[index - 1];
                        var subject = lowemail.ToString();
                        Notifications.SendEmail("email", "email", "Buy Long " + Symbol.Code + " " + subject, Symbol.Code + " " + subject);
                    }
                }
            }

        }
    }
}

 


@Vince

... Deleted by UFO ...

PanagiotisCharalampous
20 Jul 2018, 16:50

Hi Vince,

Thanks for the indicator, I thought this was a cBot. I would not put all this logic in an indicator but in a cBot that reads the indication values. In the cBot I would sent a notification whenever the conditions are met and then raise a flag so that the notification is not sent again at least within the same bar. When the bar changes, I would reset the flag. See below

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 int Periods { get; set; }

        private Supertrend _supertrend;
        private bool _notificationSent;
        protected override void OnStart()
        {
            _supertrend = Indicators.GetIndicator<Supertrend>(Periods);
        }

        protected override void OnTick()
        {
            var sendNotification = false;
            //  Make all your indicator checks here
            //   .
            //   .
            //   .
            if (sendNotification && !_notificationSent)
            {
                Notifications.SendEmail("email", "email", "Subject","Text");
                _notificationSent = true;
            }
        }
        protected override void OnBar()
        {
            _notificationSent = false;
        }
        protected override void OnStop()
        {
            // Put your deinitialization logic here
        }
    }
}

You can modify the above example accordingly.

Best Regards,

Panagiotis


@PanagiotisCharalampous

Vince
24 Jul 2018, 23:54

Hi Panagiotis,

I am trying to make the Indicator work as a Cbot. I have tried different things:

1) Only referencing to the Indicator in the Onstart() section. Including the Parameters. This resulted in an error, saying the Parameters do not exist in the current context. 

Error CS0103: The name 'LongPeriod' does not exist in the current context

protected override void OnStart()
        {
            _supertrend = Indicators.GetIndicator<SupertrendCompletenoemail>(LongPeriod, LongMultiplier, ShortPeriod, ShortMultiplier);
        }

So I figured the Cbot needs more info for referencing.

2) I replaced the default Parameter with all Parameters from the Indicator. This resulted in a 'Build succeeded'. I added the check in the OnTick() section that would trigger the Notification. Which resulted in an error, saying _upBufferlong does not exist. Error CS0103: The name '_upBufferlong' does not exist in the current context

protected override void OnTick()
        {
            var sendNotification = false;
            //  Make all your indicator checks here
            //   .
            //   .
            //   .
            var value = MarketSeries.Close;
            if (Functions.HasCrossedAbove(_upBufferlong, value, 1))
            {
                if (sendNotification && !_notificationSent)
                {
                    Notifications.SendEmail("email", "email", "Subject", "Text");
                    _notificationSent = true;
                }
            }
        }

At this point I decided that I would convert the Indicator to the Cbot 1 on 1, that is the whole Initialize() section to the OnStart(), the whole Calculate() section to the OnTick() section, etc. This was partly succesful except I got the error that 'index' does not exist. Because of the OnTick() method, I thought it maybe would not need an [index] reference since it would be calculated according the OnTick() method.

3) I tried to remove the [index] which resulted in an error saying Error CS0029: Cannot implicitly convert type 'double' to 'cAlgo.API.IndicatorDataSeries'.

At this point I would not know what else I could do to make it work and would appreciate some pointers ;) The only thing I could think of is to somehow declare each variable in an earlier stage?? Below you will find the code that I finished with before removing the [index] :

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 Supertrend : Robot
    {
        [Parameter(DefaultValue = 50)]
        public int LongPeriod { get; set; }

        [Parameter(DefaultValue = 10.0)]
        public double LongMultiplier { get; set; }

        [Parameter(DefaultValue = 20)]
        public int ShortPeriod { get; set; }

        [Parameter(DefaultValue = 5.0)]
        public double ShortMultiplier { get; set; }

        [Output("UpTrendLong", Color = Colors.Green, PlotType = PlotType.Points, Thickness = 3)]
        public IndicatorDataSeries UpTrendLong { get; set; }

        [Output("DownTrendLong", Color = Colors.Red, PlotType = PlotType.Points, Thickness = 3)]
        public IndicatorDataSeries DownTrendLong { get; set; }

        [Output("UpTrendShort", Color = Colors.Green, PlotType = PlotType.Points, Thickness = 3)]
        public IndicatorDataSeries UpTrendShort { get; set; }

        [Output("DownTrendShort", Color = Colors.Red, PlotType = PlotType.Points, Thickness = 3)]
        public IndicatorDataSeries DownTrendShort { get; set; }

        private IndicatorDataSeries _upBufferlong;
        private IndicatorDataSeries _downBufferlong;
        private IndicatorDataSeries _upBuffershort;
        private IndicatorDataSeries _downBuffershort;
        private AverageTrueRange _averageTrueRangelong;
        private AverageTrueRange _averageTrueRangeshort;
        private int[] _trendlong;
        private int[] _trendshort;
        private bool _changeofTrendlong;
        private bool _changeofTrendshort;

        private SupertrendCompletenoemail _supertrend;
        private bool _notificationSent;
        protected override void OnStart()
        {
            _supertrend = Indicators.GetIndicator<SupertrendCompletenoemail>(LongPeriod, LongMultiplier, ShortPeriod, ShortMultiplier);
            _trendlong = new int[1];
            _trendshort = new int[1];
            _upBufferlong = CreateDataSeries();
            _downBufferlong = CreateDataSeries();
            _upBuffershort = CreateDataSeries();
            _downBuffershort = CreateDataSeries();
            _averageTrueRangelong = Indicators.AverageTrueRange(LongPeriod, MovingAverageType.WilderSmoothing);
            _averageTrueRangeshort = Indicators.AverageTrueRange(ShortPeriod, MovingAverageType.WilderSmoothing);
        }

        protected override void OnTick()
        {
            var sendNotification = false;
            //  Make all your indicator checks here
            //   .
            //   .
            //   .

            // Init
            {
                UpTrendLong[index] = double.NaN;
                DownTrendLong[index] = double.NaN;
                UpTrendShort[index] = double.NaN;
                DownTrendShort[index] = double.NaN;

                double median = (MarketSeries.High[index] + MarketSeries.Low[index]) / 2;
                double atrlong = _averageTrueRangelong.Result[index];
                double atrshort = _averageTrueRangeshort.Result[index];

                _upBufferlong = median + LongMultiplier * atrlong;
                _downBufferlong[index] = median - LongMultiplier * atrlong;
                _upBuffershort[index] = median + ShortMultiplier * atrshort;
                _downBuffershort[index] = median - ShortMultiplier * atrshort;


                if (index < 1)
                {
                    _trendlong[index] = 1;
                    return;
                }

                Array.Resize(ref _trendlong, _trendlong.Length + 1);

                // Main Logic
                if (MarketSeries.Close[index] > _upBufferlong[index - 1])
                {
                    _trendlong[index] = 1;
                    if (_trendlong[index - 1] == -1)
                        _changeofTrendlong = true;
                }
                else if (MarketSeries.Close[index] < _downBufferlong[index - 1])
                {
                    _trendlong[index] = -1;
                    if (_trendlong[index - 1] == -1)
                        _changeofTrendlong = true;
                }
                else if (_trendlong[index - 1] == 1)
                {
                    _trendlong[index] = 1;
                    _changeofTrendlong = false;
                }
                else if (_trendlong[index - 1] == -1)
                {
                    _trendlong[index] = -1;
                    _changeofTrendlong = false;
                }

                if (_trendlong[index] < 0 && _trendlong[index - 1] > 0)
                    _upBufferlong[index] = median + (LongMultiplier * atrlong);
                else if (_trendlong[index] < 0 && _upBufferlong[index] > _upBufferlong[index - 1])
                    _upBufferlong[index] = _upBufferlong[index - 1];

                if (_trendlong[index] > 0 && _trendlong[index - 1] < 0)
                    _downBufferlong[index] = median - (LongMultiplier * atrlong);
                else if (_trendlong[index] > 0 && _downBufferlong[index] < _downBufferlong[index - 1])
                    _downBufferlong[index] = _downBufferlong[index - 1];

                // Draw Indicator
                if (_trendlong[index] == 1)
                {

                    UpTrendLong[index] = _downBufferlong[index];
                    if (_changeofTrendlong)
                    {
                        UpTrendLong[index - 1] = DownTrendLong[index - 1];
                        _changeofTrendlong = false;
                    }
                }
                else if (_trendlong[index] == -1)
                {

                    DownTrendLong[index] = _upBufferlong[index];
                    if (_changeofTrendlong)
                    {
                        DownTrendLong[index - 1] = UpTrendLong[index - 1];
                        _changeofTrendlong = false;
                    }

                }

                if (index < 1)
                {
                    _trendshort[index] = 1;
                    return;
                }

                Array.Resize(ref _trendshort, _trendshort.Length + 1);

                // Main Logic
                if (MarketSeries.Close[index] > _upBuffershort[index - 1])
                {
                    _trendshort[index] = 1;
                    if (_trendshort[index - 1] == -1)
                        _changeofTrendshort = true;
                }
                else if (MarketSeries.Close[index] < _downBuffershort[index - 1])
                {
                    _trendshort[index] = -1;
                    if (_trendshort[index - 1] == -1)
                        _changeofTrendshort = true;
                }
                else if (_trendshort[index - 1] == 1)
                {
                    _trendshort[index] = 1;
                    _changeofTrendshort = false;
                }
                else if (_trendshort[index - 1] == -1)
                {
                    _trendshort[index] = -1;
                    _changeofTrendshort = false;
                }

                if (_trendshort[index] < 0 && _trendshort[index - 1] > 0)
                    _upBuffershort[index] = median + (ShortMultiplier * atrshort);
                else if (_trendshort[index] < 0 && _upBuffershort[index] > _upBuffershort[index - 1])
                    _upBuffershort[index] = _upBuffershort[index - 1];

                if (_trendshort[index] > 0 && _trendshort[index - 1] < 0)
                    _downBuffershort[index] = median - (ShortMultiplier * atrshort);
                else if (_trendshort[index] > 0 && _downBuffershort[index] < _downBuffershort[index - 1])
                    _downBuffershort[index] = _downBuffershort[index - 1];

                // Draw Indicator
                if (_trendshort[index] == 1)
                {

                    UpTrendShort[index] = _downBuffershort[index];
                    if (_changeofTrendshort)
                    {
                        UpTrendShort[index - 1] = DownTrendShort[index - 1];
                        _changeofTrendshort = false;
                    }
                }
                else if (_trendshort[index] == -1)
                {

                    DownTrendShort[index] = _upBuffershort[index];
                    if (_changeofTrendshort)
                    {
                        DownTrendShort[index - 1] = UpTrendShort[index - 1];
                        _changeofTrendshort = false;
                    }
                }
            }


            if (sendNotification && !_notificationSent)
            {
                Notifications.SendEmail("email", "email", "Subject", "Text");
                _notificationSent = true;
            }

        }
        protected override void OnBar()
        {
            _notificationSent = false;
        }
        protected override void OnStop()
        {
            // Put your deinitialization logic here
        }
    }
}

Kind regards,

Vince


@Vince

PanagiotisCharalampous
25 Jul 2018, 09:20

Hi Vince,

I don't think getting rid of the indicator is a good idea. Keep the indicator and just move the notification sending part into the cBot. The indicator should keep working as is does and the cBot should just read the values of the indicator and send the emails whenever necessary.

Best Regards,

Panagiotis


@PanagiotisCharalampous

Vince
25 Jul 2018, 12:07

Hi Panagiotis,

I understand what you are saying and that is what I am trying to do. The problem I encounter is that the Cbot somehow does not read some of the values of the indicator. Do you have any idea why this is?

For example, if I make a reference to the indicator and only put in the notification sending part, it will produce an error saying that a value does not exist in the current context, see '2)' of my previous reply.

I saw that hibba7rain has a similar question, so I will read your replies on his topic as well and will try implementing your suggestions there as well.

 

Kind regards,

Vince


@Vince