using System; using System.Collections.Generic; using System.ComponentModel; using System.Linq; using System.Text; using System.Xml; using TradeIdeas.XML; using TradeIdeas.MiscSupport; namespace TradeIdeas.TIProGUI.LimitAlerts { /// /// Class that represents a Limit Alert. LimitAlertsMessageManager is responsible for converting XML from the limit alert server into these objects. /// public class LimitAlert { private string _id = ""; /// /// This is the identifier assigned by the limit alerts server. These are only created on the limit alert server. /// [Browsable(false)] public string Id { get { return _id; } set { _id = value; } } private string _clientId = ""; /// /// This is the identifier assigned by the client. The server should know to not create a new alert if the client id already exists on the server. /// [Browsable(false)] public string ClientId { get { return _clientId; } set { _clientId = value; } } private string _symbol = ""; public string Symbol { get { return _symbol; } set { _symbol = value; } } private double _price; /// /// The limit alert price. /// [ColumnInfoAttribute(DisplayName = "Alert Price", Format="2", SizeHint = "XXXXX.XX")] public double Price { get { return _price; } set { _price = value; } } private bool _isLong = true; /// /// The direction of the limit alert. True = from below (price must rise to the alert price to fire), False = from above (price must fall to the alert price to fire) /// [ColumnInfoAttribute(DisplayName = "From Above/Below", Format="limitalertdirection", SizeHint = "FROM ABOVEXXX")] public bool IsLong { get { return _isLong; } set { _isLong = value; } } private bool _longAfter = true; /// /// The direction of the limit alert after triggering. True = long, False = short /// [ColumnInfoAttribute(DisplayName = "Side", Format = "longshort", SizeHint = "SHORTXXX")] public bool LongAfter { get { return _longAfter; } set { _longAfter = value; } } private string _status = ""; /// /// Current status of this limit alert. Can be WORKING (blue 64,114,232), INVALIDATED (red 255,0,0), EXPIRED (purple 176,64,190), TRIGGERED (green 0,255,0) /// [ColumnInfoAttribute(DisplayName = "Status", SizeHint = "INVALIDATEDXXX", Format = "limitalertstatus")] public string Status { get { return _status; } set { _status = value; } } private DateTime? _triggered = null; /// /// Triggered date/time if limit alert has been triggered. /// [ColumnInfoAttribute(DisplayName = "Triggered", Format="t", SizeHint = "XX/XX/XXXX XX:XX:XX")] public DateTime? Triggered { get { return _triggered; } set { _triggered = value; } } private DateTime? _expires = null; /// /// Time datetime after which this limit alert should "expire" if it hasn't triggered or been invalidated first. /// [ColumnInfoAttribute(DisplayName = "Expires", Format="t", SizeHint = "XX/XX/XXXX XX:XX:XX")] public DateTime? Expires { get { return _expires; } set { _expires = value; } } private bool _afterHours = true; /// /// The direction of the limit alert. True = from below (price must rise to the alert price to fire), False = from above (price must fall to the alert price to fire) /// [ColumnInfoAttribute(DisplayName = "After Hours", Format = "onoff", SizeHint = "ONOFFXXX")] public bool AfterHours { get { return _afterHours; } set { _afterHours = value; } } private DateTime _created = ServerFormats.Now; /// /// Creation time of this alert. /// [ColumnInfoAttribute(DisplayName = "Created", Format="t", SizeHint = "XX/XX/XXXX XX:XX:XX")] public DateTime Created { get { return _created; } set { _created = value; } } private DateTime _updated = ServerFormats.Now; /// /// Last updated time of this alert. /// [ColumnInfoAttribute(DisplayName = "Updated", Format="t", SizeHint = "XX/XX/XXXX XX:XX:XX")] public DateTime Updated { get { return _updated; } set { _updated = value; } } private double? _invalidPrice = null; /// /// Price at which this limit alert becomes invalid and converts to the INVALIDATED status. /// [ColumnInfoAttribute(DisplayName = "Invalid Price", Format="2", SizeHint = "XXXXX.XX")] public double? InvalidPrice { get { return _invalidPrice; } set { _invalidPrice = value; } } private string _notes = ""; /// /// User entered notes that are stored with the alert on the server. /// [ColumnInfoAttribute(DisplayName = "Notes", SizeHint = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXX")] public string Notes { get { return _notes; } set { _notes = value; } } private double? _currentPrice = null; /// /// This is the current price for the symbol. /// [ColumnInfoAttribute(DisplayName = "Current Price", Format="2", SizeHint = "XXXXX.XX")] public double? CurrentPrice { get { return _currentPrice; } set { _currentPrice = value; } } /// /// Distance from alert price /// [ColumnInfoAttribute(DisplayName = "Dollars from Alert", Format="2", SizeHint = "XXXXX.XX", RealTimeUpdates = true)] public double? DistanceFromAlert { get { if (_currentPrice.HasValue) { if (_isLong) return _price - _currentPrice.Value; else return _currentPrice.Value - _price; } else return null; } } /// /// Dollars difference from triggered price - sort of like P&L /// [ColumnInfoAttribute(DisplayName = "Dollars Since Triggered", Format="2", SizeHint = "XXXXX.XX", RealTimeUpdates = true)] public double? DollarsSinceTriggered { get { if (_triggered.HasValue) { if (_currentPrice.HasValue) { if (_longAfter) return _currentPrice.Value - _price; else return _price - _currentPrice.Value; } } return null; } } /// /// Percent from triggered price /// [ColumnInfoAttribute(DisplayName = "Percent Since Triggered", Format="2", SizeHint = "XXXXX.XX", RealTimeUpdates = true)] public double? PercentSinceTriggered { get { if (_triggered.HasValue) return DollarsSinceTriggered / _price * 100; else return null; } } /// /// Percent from alert price /// [ColumnInfoAttribute(DisplayName = "Percent from Alert", Format="2", SizeHint = "XXXXX.XX", RealTimeUpdates = true)] public double? PercentFromAlert { get { if (DistanceFromAlert.HasValue) return DistanceFromAlert / _price * 100; else return null; } } /// /// Volatility units from alert price /// [ColumnInfoAttribute(DisplayName = "Volatility Bars from Alert", Format="2", SizeHint = "XXXXX.XX")] public double? VolatilityBarsFromAlert { get { if (DistanceFromAlert.HasValue && _volatility.HasValue) return DistanceFromAlert / _volatility; else return null; } } private double? _volatility = null; /// /// Volatility as read from a top list. /// [ColumnInfoAttribute(DisplayName = "Volatility", Format="2", SizeHint = "XXXXX.XX", MaxForColor = 0.5, MinForColor = -1, MidForColor = 0)] public double? Volatility { get { return _volatility; } set { _volatility = value; } } private double? _relativeVolume = null; /// /// Relative Volume as read from a top list. /// [ColumnInfoAttribute(DisplayName = "Relative Volume", Format="2", SizeHint = "XXXXX.XX", MaxForColor = 3, MinForColor = -1, MidForColor = 0)] public double? RelativeVolume { get { return _relativeVolume; } set { _relativeVolume = value; } } private int? _todayVolume = null; /// /// Relative Volume as read from a top list. /// [ColumnInfoAttribute(DisplayName = "Today Volume", Format="0", SizeHint = "XXX,XXX,XXX")] public int? TodayVolume { get { return _todayVolume; } set { _todayVolume = value; } } private double? _changeFromTheClose = null; /// /// Today Change as read from a top list. /// [ColumnInfoAttribute(DisplayName = "Change from the Close $", Units="$", Format="2", SizeHint = "XXXXX.XX", MaxForColor = 1, MinForColor = -1, MidForColor = 0)] public double? ChangeFromTheClose { get { return _changeFromTheClose; } set { _changeFromTheClose = value; } } private double? _changeFromTheClosePercent = null; /// /// Today Change Percent as read from a top list. /// [ColumnInfoAttribute(DisplayName = "Change from the Close %", Units="%", Format="2", SizeHint = "XXXXX.XX", MaxForColor = 4, MinForColor = -4, MidForColor = 0)] public double? ChangeFromTheClosePercent { get { return _changeFromTheClosePercent; } set { _changeFromTheClosePercent = value; } } private string _companyName = ""; /// /// Company name of the symbol /// [ColumnInfoAttribute(DisplayName = "Company Name", SizeHint = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXX")] public string CompanyName { get { return _companyName; } set { _companyName = value; } } /// /// Daily performance thermograph /// [ColumnInfoAttribute(DisplayName = "Daily Performance", SizeHint = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXX", Format = "thermograph", RealTimeUpdates = true)] public Thermograph DailyPerformance { get; set; } /// /// Intraday performance thermograph /// [ColumnInfoAttribute(DisplayName = "Intraday Performance", SizeHint = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXX", Format = "thermograph", RealTimeUpdates = true)] public Thermograph IntradayPerformance { get; set; } public LimitAlert() { } /// /// Converts this Limit Alert object to RowData. /// /// RowData object representing this Limit Alert. public RowData ToRowData() { RowData rowData = new RowData(); rowData.Data.Add("Symbol", _symbol); rowData.Data.Add("Price", _price); rowData.Data.Add("IsLong", _isLong); rowData.Data.Add("LongAfter", _longAfter); rowData.Data.Add("AfterHours", _afterHours); rowData.Data.Add("Expires", _expires); rowData.Data.Add("InvalidPrice", _invalidPrice); rowData.Data.Add("Triggered", _triggered); rowData.Data.Add("Created", _created); rowData.Data.Add("Updated", _updated); rowData.Data.Add("Status", _status); rowData.Data.Add("Notes", _notes); rowData.Data.Add("CurrentPrice", _currentPrice); rowData.Data.Add("DistanceFromAlert", DistanceFromAlert); rowData.Data.Add("DollarsSinceTriggered", DollarsSinceTriggered); rowData.Data.Add("PercentSinceTriggered", PercentSinceTriggered); rowData.Data.Add("PercentFromAlert", PercentFromAlert); rowData.Data.Add("Volatility", Volatility); rowData.Data.Add("VolatilityBarsFromAlert", VolatilityBarsFromAlert); rowData.Data.Add("RelativeVolume", RelativeVolume); rowData.Data.Add("TodayVolume", TodayVolume); rowData.Data.Add("ChangeFromTheClose", ChangeFromTheClose); rowData.Data.Add("ChangeFromTheClosePercent", ChangeFromTheClosePercent); rowData.Data.Add("CompanyName", _companyName); rowData.Data.Add("IntradayPerformance", IntradayPerformance); rowData.Data.Add("DailyPerformance", DailyPerformance); rowData.Data.Add("Id", _id); rowData.Data.Add("object", this); return rowData; } /// /// Save this object to XML /// /// public void Save(XmlNode description) { description.SetProperty("SYMBOL", _symbol); description.SetProperty("PRICE", _price); description.SetProperty("IS_LONG", _isLong); description.SetProperty("LONG_AFTER", _longAfter); description.SetProperty("AFTER_HOURS", _afterHours); if (_expires.HasValue) description.SetProperty("EXPIRES", ServerFormats.ToTimeT(_expires.Value)); if (_invalidPrice.HasValue) description.SetProperty("INVALID_PRICE", _invalidPrice.Value); if (_triggered.HasValue) description.SetProperty("TRIGGERED", ServerFormats.ToTimeT(_triggered.Value)); description.SetProperty("CREATED", ServerFormats.ToTimeT(_created)); description.SetProperty("UPDATED", ServerFormats.ToTimeT(_updated)); description.SetProperty("STATUS", _status); description.SetProperty("NOTES", _notes); } /// /// Restore from XML to this object. /// /// public void Restore(XmlNode description) { _symbol = description.Property("SYMBOL", ""); _price = description.Property("PRICE", 0.0); _isLong = description.Property("IS_LONG", true); _longAfter = description.Property("LONG_AFTER", true); _afterHours = description.Property("AFTER_HOURS", true); if (description.Property("EXPIRES", 0) != 0) { int time_t = description.Property("EXPIRES", 0); if (time_t > 0) _expires = ServerFormats.FromTimeT(time_t); } if (description.Property("INVALID_PRICE", 0.0) != 0.0) _invalidPrice = description.Property("INVALID_PRICE", 0.0); if (description.Property("CREATED", 0) != 0) { int time_t = description.Property("CREATED", 0); if (time_t > 0) { DateTime? created = ServerFormats.FromTimeT(time_t); if (created.HasValue) _created = created.Value; } } if (description.Property("UPDATED", 0) != 0) { int time_t = description.Property("UPDATED", 0); if (time_t > 0) { DateTime? updated = ServerFormats.FromTimeT(time_t); if (updated.HasValue) _updated = updated.Value; } } if (description.Property("TRIGGERED", 0) != 0) { int time_t = description.Property("TRIGGERED", 0); if (time_t > 0) _triggered = ServerFormats.FromTimeT(time_t); } _notes = description.Property("NOTES", ""); _status = description.Property("STATUS", ""); } public override bool Equals(System.Object obj) { // If parameter is null return false. if (obj == null) return false; // If parameter cannot be cast to Point return false. LimitAlert c = obj as LimitAlert; if ((System.Object)c == null) return false; // Return true if the fields match: return (Id == c.Id); } public bool Equals(LimitAlert c) { // If parameter is null return false: if ((object)c == null) return false; // Return true if the fields match: return (Id == c.Id); } public override int GetHashCode() { return Id.GetHashCode(); } /// /// Returns friendly string suitable for a long description. /// /// internal string ToFriendlyString() { string toReturn = ""; if (_isLong) { toReturn = "Alert (" + (_longAfter ? "Long": "Short") + ") if price of " + Symbol + " rises to $" + Price.ToString("N2"); if (Expires.HasValue) toReturn += " before " + Expires.Value.ToString("yyyy-MM-dd hh:mm:ss tt"); if (InvalidPrice.HasValue) toReturn += " unless price falls to $" + InvalidPrice.Value.ToString("N2") + " first"; } else { toReturn = "Alert (" + (_longAfter ? "Long": "Short") + ") if price of " + Symbol + " falls to $" + Price.ToString("N2"); if (Expires.HasValue) toReturn += " before " + Expires.Value.ToString("yyyy-MM-dd hh:mm:ss tt"); if (InvalidPrice.HasValue) toReturn += " unless price rises to $" + InvalidPrice.Value.ToString("N2") + " first"; } toReturn += " (" + Status + ")"; return toReturn; } } }