using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using TradeIdeas.MiscSupport;
using TradeIdeas.TIProData;
using TradeIdeas.TIProData.Interfaces;
using TradeIdeas.XML;
namespace TradeIdeas.TIProGUI.LimitAlerts
{
public partial class LimitAlertCreateForm : Form, TopListRequest.Listener
{
public string Id { get; set; }
public DateTime? Creation { get; set; }
public DateTime? Updated { get; set; }
private WatermarkTextBox _textBoxSymbol = new WatermarkTextBox();
// NEW SYMBOL LOOKUP
SymbolLookupB _symbolLookup;
private string Symbol
{
get { return _symbolLookup.GetSymbol(); }
}
public double Price
{
get
{
double toReturn = -1;
if (double.TryParse(textBoxPrice.Text, out toReturn))
return toReturn;
return -1;
}
set { textBoxPrice.Text = value.ToString(); }
}
///
/// From below = true, from above = false
///
public bool IsLong
{
get { return checkBoxIsLong.Checked; }
set { checkBoxIsLong.Checked = value; }
}
///
/// After the order triggers are we predicting the price to go up (true) or down (false)
///
public bool LongAfter
{
get { return radioButtonSideLong.Checked; }
set
{
radioButtonSideLong.Checked = value;
radioButtonSideShort.Checked = !value;
}
}
public double? InvalidPrice
{
get
{
double toReturn = -1;
if (double.TryParse(textBoxInvalidPrice.Text, out toReturn))
return toReturn;
return null;
}
set { textBoxInvalidPrice.Text = value.ToString(); }
}
///
/// Trigger price alerts after hours
///
public bool AfterHours
{
get { return checkBoxAfterHours.Checked; }
set { checkBoxAfterHours.Checked = value; }
}
public DateTime? Expires
{
get
{
if (checkBoxExpiration.Checked)
{
DateTime expires = new DateTime(dateTimePickerExpirationDate.Value.Year, dateTimePickerExpirationDate.Value.Month, dateTimePickerExpirationDate.Value.Day,
dateTimePickerExpirationTime.Value.Hour, dateTimePickerExpirationTime.Value.Minute, dateTimePickerExpirationTime.Value.Second);
return expires;
}
else
return null;
}
set
{
if (value.HasValue)
{
checkBoxExpiration.Checked = true;
dateTimePickerExpirationDate.Value = value.Value;
dateTimePickerExpirationTime.Value = value.Value;
UpdateEnabledStatus();
}
}
}
public string Notes
{
get { return _notesTextBox.Text; }
set { _notesTextBox.Text = value; }
}
public string WindowName
{
get { return Text; }
set { Text = value; }
}
public LimitAlert LimitAlert
{
get { return GetLimitAlertFromGui(); }
}
WatermarkTextBox _notesTextBox = new WatermarkTextBox();
private TopListRequest.Token _liveData;
///
/// This automatically ignores the request if the symbol didn't change.
///
/// null or "" means to stop the data.
private void FollowSymbol(string symbol)
{
if (null != symbol)
symbol = symbol.Trim();
if ((null != _liveData) && (_liveData.GetRequest().SingleSymbol == symbol))
// No change.
return;
if (null != _liveData)
_liveData.Cancel();
_currentPrice = null;
UpdateCurrentPrice();
UpdateEnabledStatus();
if ((null == symbol) || ("" == symbol))
_liveData = null;
else
{
TopListRequest request = new TopListRequest();
request.OutsideMarketHours = false;
request.SingleSymbol = symbol;
request.Streaming = true;
request.UseDatabase = false;
request.AddExtraColumn("Price");
// A previous revision of the code requested this data, extracted it into a local variable,
// then ignored it. Now we're not requesting it at all.
//request.AddExtraColumn("D_Name");
_liveData = request.Send(_sendManager, this);
}
}
///
/// Last price received by SymbolDetails
///
private double? _currentPrice = null;
private readonly ISendManager _sendManager = GuiEnvironment.FindConnectionMaster("").SendManager;
private FontManager _fontManager;
private const float DEFAULT_FONT_SIZE = 8.25F;
///
///
///
/// May be null
public LimitAlertCreateForm(string initialSymbol)
{
InitializeComponent();
Icon = GuiEnvironment.Icon;
MinimizeBox = false;
_notesTextBox.WatermarkText = "Notes";
_notesTextBox.Multiline = true;
_notesTextBox.Dock = DockStyle.Fill;
tableLayoutPanelGrid.Controls.Add(_notesTextBox, 1, 7);
_fontManager = new FontManager(this, DEFAULT_FONT_SIZE);
_fontManager.selectTheFont();
// NEW SYMBOL LOOKUP
//if (GuiEnvironment.DevelopmentMode)
//{
string apiURL = GuiEnvironment.AppConfig.Node("SYMBOL_LOOKUP").Property("API_URL", "");
int symbolLimit = GuiEnvironment.AppConfig.Node("SYMBOL_LOOKUP").Property("SYMBOL_LIMIT", -1);
int keystrokePause = GuiEnvironment.AppConfig.Node("SYMBOL_LOOKUP").Property("KEYSTROKE_PAUSE", -1);
_symbolLookup = new SymbolLookupTextBox() {
ApiUrl = apiURL,
SymbolLimit = symbolLimit,
KeyStrokePause = keystrokePause,
FontSize = this.Font.SizeInPoints,
TextBoxFont = Font,
};
tableLayoutPanelGrid.Controls.Add(_symbolLookup, 1, 0);
_symbolLookup.Size = new Size(60, 20);
_symbolLookup.Margin = new Padding(3, 3, 3, 3);
_symbolLookup.AutoSetHeight();
//_symbolLookup.Location = new Point(14, 12); // new Point(300, 12);
//_symbolLookup.Anchor = AnchorStyles.Top | AnchorStyles.Left;
_symbolLookup.symbolSelected += SetSymbol;
if (null != initialSymbol)
_symbolLookup.SetSymbol(initialSymbol);
//}
//else
//{
// _textBoxSymbol.WatermarkText = "Symbol";
// _textBoxSymbol.Size = new Size(60, 20);
// _textBoxSymbol.TextChanged += _textBoxSymbol_TextChanged;
// _textBoxSymbol.CharacterCasing = CharacterCasing.Upper;
// tableLayoutPanelGrid.Controls.Add(_textBoxSymbol, 1, 0);
// if (null != initialSymbol)
// _textBoxSymbol.Text = initialSymbol;
//}
UpdateEnabledStatus();
FixStatusLabel();
Resize += LimitAlertCreateForm_Resize;
FormClosing += LimitAlertCreateForm_FormClosing;
SetDefaultExpirationTime();
StartPosition = FormStartPosition.CenterParent;
textBoxPrice.Select();
SetTabOrder();
}
private void SetTabOrder()
{
// NEW SYMBOL LOOKUP
//if (GuiEnvironment.DevelopmentMode)
_symbolLookup.TabIndex = 0;
//else
// _textBoxSymbol.TabIndex = 0;
flowLayoutPanelAlertPrice.TabIndex = 1;
checkBoxIsLong.TabIndex = 2;
flowLayoutPanelSide.TabIndex = 3;
flowLayoutPanelExpiration.TabIndex = 4;
textBoxInvalidPrice.TabIndex = 5;
_notesTextBox.TabIndex = 6;
flowLayoutPanelButtons.TabIndex = 7;
}
void LimitAlertCreateForm_FormClosing(object sender, FormClosingEventArgs e)
{
// NEW SYMBOL LOOKUP
//if (GuiEnvironment.DevelopmentMode)
//{
_symbolLookup.symbolSelected -= SetSymbol;
_symbolLookup.UnsubscribeEvents();
//}
FollowSymbol(null);
}
void _textBoxSymbol_TextChanged(object sender, EventArgs e)
{
UpdateEnabledStatus();
FollowSymbol(Symbol);
}
private void SetSymbol(string symbol)
{
UpdateEnabledStatus();
FollowSymbol(Symbol);
}
private void QuoteTickReceived(RowData data)
{
double price = data.GetPrice();
if (price <= 0.0)
_currentPrice = null;
else
_currentPrice = price;
UpdateEnabledStatus();
}
private void UpdateCurrentPrice()
{
if (_currentPrice.HasValue)
{ // TODO normlly we display 4 digits if the price is less than $1.
labelCurrentPrice.Text = "Currently: " + _currentPrice.Value.ToString("N2");
if (Price != -1)
{
double difference = Price - _currentPrice.Value;
string plus = "+";
if (difference < 0)
plus = "";
labelCurrentPrice.Text = labelCurrentPrice.Text + " (" + plus + difference.ToString("N2") + ")";
}
}
else
labelCurrentPrice.Text = "";
}
///
/// Sets default expiration time for expires field.
///
private void SetDefaultExpirationTime()
{
DateTime marketClose = GuiEnvironment.GetMarketCloseLocalTime();
DateTime now = ServerFormats.Now;
DateTime expiration = marketClose.AddMinutes(-5);
if (now > expiration)
{
if (now.DayOfWeek == DayOfWeek.Friday)
expiration = expiration.AddDays(3);
else if (now.DayOfWeek == DayOfWeek.Saturday)
expiration = expiration.AddDays(2);
else
expiration = expiration.AddDays(1);
}
dateTimePickerExpirationDate.Value = expiration;
dateTimePickerExpirationTime.Value = expiration;
}
void LimitAlertCreateForm_Resize(object sender, EventArgs e)
{
FixStatusLabel();
}
private void FixStatusLabel()
{
labelStatus.MaximumSize = new Size(tableLayoutPanelGrid.Width, 0);
labelStatus.AutoSize = true;
}
private void buttonCancel_Click(object sender, EventArgs e)
{
DialogResult = System.Windows.Forms.DialogResult.Cancel;
Close();
}
private void buttonSave_Click(object sender, EventArgs e)
{
DialogResult = System.Windows.Forms.DialogResult.OK;
Close();
}
private LimitAlert GetLimitAlertFromGui()
{
LimitAlert limitAlert = new LimitAlert();
limitAlert.Symbol = Symbol;
limitAlert.Price = Price;
limitAlert.InvalidPrice = InvalidPrice;
limitAlert.IsLong = IsLong;
limitAlert.LongAfter = LongAfter;
limitAlert.Expires = Expires;
limitAlert.AfterHours = AfterHours;
limitAlert.Notes = Notes;
limitAlert.Id = Id;
if (Creation.HasValue)
limitAlert.Created = Creation.Value;
if (Updated.HasValue)
limitAlert.Updated = Updated.Value;
return limitAlert;
}
private void checkBoxExpiration_CheckedChanged(object sender, EventArgs e)
{
UpdateEnabledStatus();
}
private void UpdateEnabledStatus()
{
dateTimePickerExpirationDate.Enabled = checkBoxExpiration.Checked;
dateTimePickerExpirationTime.Enabled = checkBoxExpiration.Checked;
if (FormIsValid())
{
if (IsLong)
{
checkBoxIsLong.Text = "(Price of " + Symbol + " rises to $" + Price.ToString("N2") + ")";
labelStatus.Text = "Alert if price of " + Symbol + " rises to $" + Price.ToString("N2");
if (Expires.HasValue)
labelStatus.Text += " before " + Expires.Value.ToString("yyyy-MM-dd hh:mm:ss tt");
if (InvalidPrice.HasValue)
labelStatus.Text += " unless price falls to $" + InvalidPrice.Value.ToString("N2") + " first";
}
else
{
checkBoxIsLong.Text = "(Price of " + Symbol + " falls to $" + Price.ToString("N2") + ")";
labelStatus.Text = "Alert if price of " + Symbol + " falls to $" + Price.ToString("N2");
if (Expires.HasValue)
labelStatus.Text += " before " + Expires.Value.ToString("yyyy-MM-dd hh:mm:ss tt");
if (InvalidPrice.HasValue)
labelStatus.Text += " unless price rises to $" + InvalidPrice.Value.ToString("N2") + " first";
}
AddPriceWarningIfRequired();
}
else if (Price == -1)
{
checkBoxIsLong.Text = "Error - update Price field to valid value.";
labelStatus.Text = "Error - update Price field to valid value.";
}
else
{
checkBoxIsLong.Text = "Error - update Symbol field to valid value.";
labelStatus.Text = "Error - update Symbol field to valid value.";
}
buttonSave.Enabled = FormIsValid();
}
///
/// Determines whether the current limit alert would be immediately triggered.
///
private void AddPriceWarningIfRequired()
{
if ((_currentPrice > Price && IsLong) || (_currentPrice < Price && !IsLong))
labelStatus.Text = labelStatus.Text + " - WARNING: alert might trigger immediately since price is currently " + _currentPrice.Value.ToString("N2");
}
private bool FormIsValid()
{
return Price != -1 && Symbol != "";
}
private void textBoxPrice_TextChanged(object sender, EventArgs e)
{ // UpdateCurrentPrice() includes the difference between the stock price and
// the alert price. Call it if either input changes.
UpdateCurrentPrice();
UpdateEnabledStatus();
}
private void dateTimePickerExpirationDate_ValueChanged(object sender, EventArgs e)
{
UpdateEnabledStatus();
}
private void dateTimePickerExpirationTime_ValueChanged(object sender, EventArgs e)
{
UpdateEnabledStatus();
}
private void textBoxInvalidPrice_TextChanged(object sender, EventArgs e)
{
UpdateEnabledStatus();
}
private void checkBoxIsLong_CheckedChanged(object sender, EventArgs e)
{
UpdateEnabledStatus();
}
///
/// This could be called from any thread.
///
///
///
///
///
void TopListRequest.Listener.OnRowData(List rows, DateTime? start, DateTime? end, TopListRequest.Token token)
{
this.BeginInvokeIfRequired((MethodInvoker)delegate
{
if (token != _liveData)
// Old request, don't care.
return;
token.GetRequest().LastUpdate = DateTime.Now;
if (rows.Count != 1)
// Probably asked for an invalid symbol.
return;
QuoteTickReceived(rows[0]);
UpdateCurrentPrice();
});
}
///
/// This could be called from any thread.
///
///
void TopListRequest.Listener.OnMetaData(TopListRequest.Token token)
{
// Ignore it. We should never get this.
}
///
/// This could be called from any thread.
///
///
void TopListRequest.Listener.OnDisconnect(TopListRequest.Token token)
{
this.BeginInvokeIfRequired((MethodInvoker)delegate
{
if (token != _liveData)
// old request, don't care
return;
// Resend the same request.
_liveData = token.GetRequest().Send(_sendManager, this);
});
}
}
}