ST
    
        
            Email notificatons: how to amend email message subject
            
                 05 Jan 2018, 16:45
            
                    
Hi,
Thanks to Paul Hayes, Clickalgo for the following code which triggers an alert based on volatility settings. I have included a line to send an email once the alert is triggered but cannot work out how to amend the email subject to include which symbol has triggered the alert.
Secondly, I want to restrict the emails to just 1 per bar (or some other restriction) since my current method sends an email on each tick if triggered (yet I do want the alert to continue to monitor each tick).
Can anyone help?
// -------
// PURPOSE
// -------
// Alerts user when there is high volatility in the market over a period of seconds.
// Userful signal when not looking at charts or when not at computer, configurable audible sound alerts for each currency.
// Good for scalping.
// Author: Paul Hayes    
// Date:   24/12/2015
// Version 1.5
//
// Coding Guidlines: https://github.com/dotnet/corefx/wiki/Framework-Design-Guidelines-Digest
//
// Bug fix: display formatting issue.
using System;
using cAlgo.API;
using cAlgo.API.Internals;
using cAlgo.API.Indicators;
namespace cAlgo
{
    [Indicator(IsOverlay = true, TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
    public class ScalpersBuddy : Indicator
    {
        #region user defined parameters
        [Parameter("Alert ON", DefaultValue = true)]
        public bool AlertOn { get; set; }
        [Parameter("Sound ON", DefaultValue = true)]
        public bool PlaySound { get; set; }
        [Parameter("Volatility Pips", DefaultValue = 10, MaxValue = 200000, MinValue = 1)]
        public int VolatilityPips { get; set; }
        [Parameter("Media File", DefaultValue = "c:\\windows\\media\\notify.wav")]
        public string MediaFile { get; set; }
        [Parameter("Display Position, 1-8", DefaultValue = 2, MinValue = 1, MaxValue = 3)]
        public int WarningPostion { get; set; }
        [Parameter("Warning Color", DefaultValue = "Red")]
        public string WarningColor { get; set; }
        [Parameter("Show Volatility", DefaultValue = true)]
        public bool ShowVolatility { get; set; }
        [Parameter("Show Spread", DefaultValue = true)]
        public bool ShowSpread { get; set; }
        [Parameter("Show Depth of Market", DefaultValue = true)]
        public bool ShowDepthOfMarket { get; set; }
        [Parameter("Spread Color", DefaultValue = "White")]
        public string SpreadColor { get; set; }
        #endregion
        #region Private properties
        private MarketSeries mSeries;
        private StaticPosition position;
        private Colors warningTextColor;
        private Colors spreadTextColor;
        private bool errorOccured = false;
        private string lowerPosition = string.Empty;
        private MarketDepth marketDepth;
        #endregion
        const string errorMsg = "\n\n\n\n\n Scalpers Buddy Indicator: An error has occurred, view log events window for more information.";
        #region cTrader Events
        protected override void Initialize()
        {
            try
            {
                // Get the time-frame series of data
                mSeries = MarketData.GetSeries(Symbol, TimeFrame.Minute);
                warningTextColor = (Colors)Enum.Parse(typeof(Colors), WarningColor, true);
                spreadTextColor = (Colors)Enum.Parse(typeof(Colors), SpreadColor, true);
                if (ShowDepthOfMarket)
                {
                    //  Get Market Depth
                    marketDepth = MarketData.GetMarketDepth(Symbol);
                    // subscribe to event Updated
                    marketDepth.Updated += MarketDepthUpdated;
                }
            } catch (Exception e)
            {
                errorOccured = true;
                Print("Scalpers Buddy: " + e.Message);
            }
            // position alert message on screen
            switch (WarningPostion)
            {
                case 1:
                    position = StaticPosition.TopLeft;
                    break;
                case 2:
                    position = StaticPosition.TopCenter;
                    break;
                case 3:
                    position = StaticPosition.TopRight;
                    break;
                case 4:
                    position = StaticPosition.Right;
                    lowerPosition = "\n\n";
                    break;
                case 5:
                    position = StaticPosition.BottomRight;
                    lowerPosition = "\n\n";
                    break;
                case 6:
                    position = StaticPosition.BottomCenter;
                    lowerPosition = "\n\n";
                    break;
                case 7:
                    position = StaticPosition.BottomLeft;
                    lowerPosition = "\n\n";
                    break;
                case 8:
                    position = StaticPosition.Left;
                    lowerPosition = "\n\n";
                    break;
                default:
                    position = StaticPosition.TopLeft;
                    break;
            }
        }
        public override void Calculate(int index)
        {
            if (errorOccured)
            {
                ChartObjects.DrawText("error-label", errorMsg, StaticPosition.TopCenter, Colors.Red);
                return;
            }
            // get the last highest price value
            double high = (mSeries.High.LastValue);
            // get the last lowest price value
            double low = (mSeries.Low.LastValue);
            // difference between high and low divided by the current instruments pip size = sudden movement in pips
            double pips = (high - low) / Symbol.PipSize;
            string pipsVolatility = "(Bar h-l: " + pips.ToString("0.00") + " pips)";
            // display error message to screen.
            if (ShowVolatility)
            {
                ChartObjects.DrawText("volatilityMsg", pipsVolatility += lowerPosition, position, spreadTextColor);
            }
            // if pip movement > volatility setting 
            if (Math.Ceiling(pips) > VolatilityPips)
            {
                if (AlertOn)
                {
                    ChartObjects.DrawText("alertMsg", pipsVolatility, position, warningTextColor);
                    Notifications.SendEmail("xxx@hotmail.com", "xxx@gmail.com", "Symbol name here", "Volatility trigger hit");
                }
                if (PlaySound)
                {
                    if (MediaFile != string.Empty)
                        Notifications.PlaySound(MediaFile);
                }
            }
            else
            {
                ChartObjects.RemoveObject("alertMsg");
            }
            // if user wants to see the current bid/ask spread size, * feature separate from volatility alert.
            if (ShowSpread)
            {
                var spread = Math.Round(Symbol.Spread / Symbol.PipSize, 2);
                string s = string.Format("{0:N2}", spread);
                ChartObjects.DrawText("spreadMsg", "\nSpread: " + s, position, spreadTextColor);
            }
        }
        #endregion
        #region market depth
        private void MarketDepthUpdated()
        {
            double bidVolume = 0;
            double askVolume = 0;
            foreach (var entry in marketDepth.BidEntries)
            {
                double dVolume = Math.Round(entry.Volume / 1000000.0, 2);
                bidVolume += dVolume;
            }
            foreach (var entry in marketDepth.AskEntries)
            {
                double dVolume = Math.Round(entry.Volume / 1000000.0, 2);
                askVolume += dVolume;
            }
        }
        #endregion
    }
}

Stokes Bay
08 Jan 2018, 18:53
here is the answer below for those interested:
// ------- // PURPOSE // ------- // Alerts user when there is high volatility in the market over a period of seconds. // Userful signal when not looking at charts or when not at computer, configurable audible sound alerts for each currency. // Good for scalping. // Author: Paul Hayes // Date: 24/12/2015 // Version 1.5 // // Coding Guidlines: https://github.com/dotnet/corefx/wiki/Framework-Design-Guidelines-Digest // // Bug fix: display formatting issue. using System; using cAlgo.API; using cAlgo.API.Internals; using cAlgo.API.Indicators; namespace cAlgo { [Indicator(IsOverlay = true, TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)] public class ScalpersBuddy : Indicator { #region user defined parameters [Parameter("Alert ON", DefaultValue = true)] public bool AlertOn { get; set; } [Parameter("Sound ON", DefaultValue = true)] public bool PlaySound { get; set; } [Parameter("Volatility Pips", DefaultValue = 10, MaxValue = 200000, MinValue = 1)] public int VolatilityPips { get; set; } [Parameter("Media File", DefaultValue = "c:\\windows\\media\\notify.wav")] public string MediaFile { get; set; } [Parameter("Display Position, 1-8", DefaultValue = 2, MinValue = 1, MaxValue = 3)] public int WarningPostion { get; set; } [Parameter("Warning Color", DefaultValue = "Red")] public string WarningColor { get; set; } [Parameter("Show Volatility", DefaultValue = true)] public bool ShowVolatility { get; set; } [Parameter("Show Spread", DefaultValue = true)] public bool ShowSpread { get; set; } [Parameter("Show Depth of Market", DefaultValue = true)] public bool ShowDepthOfMarket { get; set; } [Parameter("Spread Color", DefaultValue = "White")] public string SpreadColor { get; set; } #endregion #region Private properties private MarketSeries mSeries; private StaticPosition position; private Colors warningTextColor; private Colors spreadTextColor; private bool errorOccured = false; private string lowerPosition = string.Empty; private MarketDepth marketDepth; #endregion const string errorMsg = "\n\n\n\n\n Scalpers Buddy Indicator: An error has occurred, view log events window for more information."; #region cTrader Events protected override void Initialize() { try { // Get the time-frame series of data mSeries = MarketData.GetSeries(Symbol, TimeFrame.Minute); warningTextColor = (Colors)Enum.Parse(typeof(Colors), WarningColor, true); spreadTextColor = (Colors)Enum.Parse(typeof(Colors), SpreadColor, true); if (ShowDepthOfMarket) { // Get Market Depth marketDepth = MarketData.GetMarketDepth(Symbol); // subscribe to event Updated marketDepth.Updated += MarketDepthUpdated; } } catch (Exception e) { errorOccured = true; Print("Scalpers Buddy: " + e.Message); } // position alert message on screen switch (WarningPostion) { case 1: position = StaticPosition.TopLeft; break; case 2: position = StaticPosition.TopCenter; break; case 3: position = StaticPosition.TopRight; break; case 4: position = StaticPosition.Right; lowerPosition = "\n\n"; break; case 5: position = StaticPosition.BottomRight; lowerPosition = "\n\n"; break; case 6: position = StaticPosition.BottomCenter; lowerPosition = "\n\n"; break; case 7: position = StaticPosition.BottomLeft; lowerPosition = "\n\n"; break; case 8: position = StaticPosition.Left; lowerPosition = "\n\n"; break; default: position = StaticPosition.TopLeft; break; } } public override void Calculate(int index) { if (errorOccured) { ChartObjects.DrawText("error-label", errorMsg, StaticPosition.TopCenter, Colors.Red); return; } // get the last highest price value double high = (mSeries.High.LastValue); // get the last lowest price value double low = (mSeries.Low.LastValue); // difference between high and low divided by the current instruments pip size = sudden movement in pips double pips = (high - low) / Symbol.PipSize; string pipsVolatility = "(Bar h-l: " + pips.ToString("0.00") + " pips)"; // display error message to screen. if (ShowVolatility) { ChartObjects.DrawText("volatilityMsg", pipsVolatility += lowerPosition, position, spreadTextColor); } // if pip movement > volatility setting if (Math.Ceiling(pips) > VolatilityPips) { if (AlertOn) { ChartObjects.DrawText("alertMsg", pipsVolatility, position, warningTextColor); Notifications.SendEmail("xxx@hotmail.com", "xxx@gmail.com", Symbol.Code + " Volatility trigger hit", "Volatility trigger hit"); } if (PlaySound) { if (MediaFile != string.Empty) Notifications.PlaySound(MediaFile); } } else { ChartObjects.RemoveObject("alertMsg"); } // if user wants to see the current bid/ask spread size, * feature separate from volatility alert. if (ShowSpread) { var spread = Math.Round(Symbol.Spread / Symbol.PipSize, 2); string s = string.Format("{0:N2}", spread); ChartObjects.DrawText("spreadMsg", "\nSpread: " + s, position, spreadTextColor); } } #endregion #region market depth private void MarketDepthUpdated() { double bidVolume = 0; double askVolume = 0; foreach (var entry in marketDepth.BidEntries) { double dVolume = Math.Round(entry.Volume / 1000000.0, 2); bidVolume += dVolume; } foreach (var entry in marketDepth.AskEntries) { double dVolume = Math.Round(entry.Volume / 1000000.0, 2); askVolume += dVolume; } } #endregion } }@Stokes Bay