using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Xml;
using System.IO;
using System.Web;
using System.Windows.Forms;
using System.Windows.Forms.DataVisualization.Charting;
using TradeIdeas.TIProData;
using TradeIdeas.XML;
namespace TradeIdeas.TIProGUI.CompareCount
{
public partial class CompareCount : Form, ISaveLayout
{
private string _fileNameSaved;
private readonly ConnectionMaster _connectionMaster;
private const int MAXCOUNT = 2000; //At the 5 second interval this is about 2.7 hours. At 120 seconds interval this is about 2.7 days.
public CompareCount(ConnectionMaster connectionMaster)
{
_connectionMaster = connectionMaster;
InitializeComponent();
if (!IsHandleCreated)
CreateHandle();
WindowIconCache.SetIcon(this);
// TODO: Add to Common.xml the title name
this.Text = "Compare Count";
_bullishSeries = new ConfigManager(this, connectionMaster);
_bearishSeries = new ConfigManager(this, connectionMaster);
Settings = Settings.DecentSample();
//Update legend
UpdateLegend();
//Allow scrolling and zooming of the x-axis
chart1.ChartAreas[0].CursorX.IsUserSelectionEnabled = true;
chart1.ChartAreas[0].CursorX.IsUserEnabled = true;
// Set scrollbar colors
chart1.ChartAreas[0].AxisX.ScrollBar.BackColor = Color.White;
chart1.ChartAreas[0].AxisX.ScrollBar.ButtonColor = Color.FromArgb(224, 224, 224);
chart1.ChartAreas[0].AxisX.ScrollBar.LineColor = Color.Black;
}
private Settings _settings;
public Settings Settings
{
get
{
_settings.BearConfigString = _bearishSeries.Settings;
_settings.BullConfigString = _bullishSeries.Settings;
return _settings.Clone();
}
set
{
_settings = value.Clone();
_bullishSeries.Settings = _settings.BullConfigString;
_bullishSeries.ResetSeries();
_bullishSeries.Add(chart1.Series[0], _settings.FastRecentWeight);
_bullishSeries.Add(chart1.Series[1], _settings.SlowRecentWeight);
_bearishSeries.Settings = _settings.BearConfigString;
_bearishSeries.ResetSeries();
_bearishSeries.Add(chart1.Series[2], _settings.FastRecentWeight);
_bearishSeries.Add(chart1.Series[3], _settings.SlowRecentWeight);
timer1.Interval = _settings.SecondsPerDataPoint * 1000;
}
}
private ConfigManager _bullishSeries;
private ConfigManager _bearishSeries;
///
/// Standard cleanup. Stop requesting data!
///
/// Unused.
/// Unused.
private void CompareCount_FormClosed(object sender, FormClosedEventArgs e)
{
_bullishSeries.Settings = null;
_bearishSeries.Settings = null;
}
private class ConfigManager
{
private readonly Control _invoker;
private readonly ConnectionMaster _connectionMaster;
private StreamingAlerts _dataProvider;
private int _recentCount;
private String _settings;
private class SeriesDescription
{
public Series Series { get; private set; }
public double RecentWeight { get; private set; }
private double? _previousCount;
private bool _recentHasBeenCreated;
public SeriesDescription(Series series, double recentWeight)
{
Series = series;
RecentWeight = recentWeight;
}
public void UpdateLastPoint(int recentCount, bool freeze)
{
double currentValue;
if (_previousCount.HasValue)
currentValue = recentCount * RecentWeight + _previousCount.Value * (1 - RecentWeight);
else
currentValue = recentCount;
double [] valueList = { currentValue };
if (_recentHasBeenCreated)
{
// TODO we are not updating the scale! It should automatically update.
/*When we've cleared data points with the clear function, this method
UpdateLastPoint will still be called during the timer_Tick event.
As a result, there will be a time where the point will be 0, which
will cause an exception...*/
if (Series.Points.Count != 0)
{
Series.Points[Series.Points.Count - 1].YValues = valueList;
}
else
{
return;
}
}
else
{
//Remove oldest data once we reach MAXCOUNT
if (Series.Points.Count == MAXCOUNT)
Series.Points.RemoveAt(0);
Series.Points.Add(valueList);
if (Series.Points.Count == 1)
// A line chart with only one data point seems to be inivisble. So we switch
// to this mode to make it visible.
Series.ChartType = SeriesChartType.Point;
else
Series.ChartType = SeriesChartType.Line;
}
if (freeze)
{ // Freeze this data point as is. Start a new data point the next time we get data.
_recentHasBeenCreated = false;
_previousCount = currentValue;
}
else
// Overwrite this data point next time.
_recentHasBeenCreated = true;
}
}
public ConfigManager(Control invoker, ConnectionMaster connectionMaster)
{
_invoker = invoker;
_connectionMaster = connectionMaster;
}
void dataProvider_StreamingAlertsData(List data, StreamingAlerts source)
{
if (_invoker.InvokeRequired)
_invoker.Invoke((MethodInvoker)delegate { dataProvider_StreamingAlertsData(data, source); });
else if (source == _dataProvider)
{
int count = 0;
foreach (var rowData in data)
if (rowData.GetAsString("HISTORICAL") != "1")
count++;
if (count > 0)
{
_recentCount += data.Count;
foreach (var series in _allSeries)
series.UpdateLastPoint(_recentCount, false);
}
}
}
public void StartNewDataPoint()
{
foreach (var series in _allSeries)
series.UpdateLastPoint(_recentCount, true);
_recentCount = 0;
}
void dataProvider_StreamingAlertsConfig(StreamingAlerts source)
{
if (_invoker.InvokeRequired)
_invoker.Invoke((MethodInvoker)delegate { dataProvider_StreamingAlertsConfig(source); });
else if (source == _dataProvider)
{
// This might be a good place to update the legend.
_settings = source.Config;
}
}
public string Settings
{
get { return _settings; }
set
{
_settings = value;
if (null != _dataProvider)
_dataProvider.Stop();
if (null == value)
_dataProvider = null;
else
{
_dataProvider = _connectionMaster.StreamingAlertsManager.GetAlerts(_settings);
_dataProvider.StreamingAlertsConfig += new StreamingAlertsConfig(dataProvider_StreamingAlertsConfig);
_dataProvider.StreamingAlertsData += new StreamingAlertsData(dataProvider_StreamingAlertsData);
_dataProvider.Start();
}
}
}
private readonly List _allSeries = new List();
public void ResetSeries()
{
_allSeries.Clear();
_recentCount = 0;
}
private static readonly double[] STARTING_POINT = { 0.0 };
public void Add(Series series, double recentWeight)
{
System.Diagnostics.Debug.Assert(null != series);
_allSeries.Add(new SeriesDescription(series, recentWeight));
series.Points.Clear();
}
}
private void timer1_Tick(object sender, EventArgs e)
{
_bullishSeries.StartNewDataPoint();
_bearishSeries.StartNewDataPoint();
}
private const string FORM_TYPE = "COMPARE_COUNT_WINDOW";
static public void RegisterLayout()
{
LayoutManager.Instance().AddRestoreRule(FORM_TYPE, (RestoreLayout)delegate(XmlNode description, bool ignorePosition, bool cascadePosition)
{
ConnectionMaster connectionMaster = GuiEnvironment.FindConnectionMaster(description.Property("CONNECTION"));
if (null == connectionMaster)
{
// We could report an error here, but it's simpler just to do nothing. Any error message we tried to
// report would probably be confusing at best to the user.
}
else
{
CompareCount form = new CompareCount(connectionMaster);
LayoutManager.RestoreBase(description, form, ignorePosition, cascadePosition);
form._settings.Load(description);
form.Settings = form._settings;
// Update legend
form.UpdateLegend();
}
});
}
public static readonly WindowIconCache WindowIconCache = new WindowIconCache("COMPARE_COUNT");
void ISaveLayout.SaveLayout(XmlNode parent)
{
XmlNode description = LayoutManager.SaveBase(parent, this, FORM_TYPE);
_settings.Save(description);
}
private void toolStripMenuItemDuplicate_Click(object sender, EventArgs e)
{
LayoutManager.Instance().Duplicate(this);
}
private void toolStripMenuItemSaveAs_Click(object sender, EventArgs e)
{
LayoutManager layoutManager = LayoutManager.Instance();
SaveFileDialog dialog = new SaveFileDialog();
if (null != layoutManager.Directory)
dialog.InitialDirectory = layoutManager.Directory;
dialog.Filter = GuiEnvironment.XmlConfig.Node("COMPARE_COUNT").Node("PHRASES").Node("WINDOW_FILTER").PropertyForCulture("TEXT", "***");
dialog.DefaultExt = "*.WTI";
string fileName = "";
if (_fileNameSaved == null)
{
fileName = GuiEnvironment.XmlConfig.Node("COMPARE_COUNT").Node("PHRASES").Node("FILE_PREFIX").PropertyForCulture("TEXT", "***") + "Test"; // +_shortWindowName;
}
else
{
fileName = _fileNameSaved;
}
dialog.FileName = FileNameMethod.QuoteFileName(fileName);
if (dialog.ShowDialog() == DialogResult.OK)
{
layoutManager.SaveOne(this, dialog.FileName);
_fileNameSaved = Path.GetFileName(dialog.FileName);
}
dialog.Dispose();
}
private void toolStripMenuItemConfigure_Click(object sender, EventArgs e)
{
Settings clonedSettings = _settings.Clone();
CompareCountConfig form = new CompareCountConfig(_connectionMaster, clonedSettings);
form.ShowDialog();
if (form.DialogResult == System.Windows.Forms.DialogResult.OK)
{
clearAllPoints();
_settings = clonedSettings;
//Update legend.
UpdateLegend();
}
form.Dispose();
}
///
/// Updates the legend by obtaining the window name from the config string. If the name is empty do not show that entry in the legend.
///
private void UpdateLegend()
{
chart1.Series[0].LegendText = getThatWindowName(_settings.BullConfigString);
chart1.Series[2].LegendText = getThatWindowName(_settings.BearConfigString);
// Hide legend entry of window name is empty
chart1.Series[0].IsVisibleInLegend = chart1.Series[0].LegendText != "";
chart1.Series[2].IsVisibleInLegend = chart1.Series[2].LegendText != "";
}
///
/// Returns the windowname embedded in the config string.
///
///
///
/// The window name as a string.
///
private string getThatWindowName(string config)
{
string[] firstPass = config.Split(new string[] { "&WN=" }, StringSplitOptions.RemoveEmptyEntries); //we'll want segment [1]
if (firstPass.Length == 1)
{
//This scenario happens when the user enters
//nothing for the window name (e.g. "" ), thus no
//window name identifier would appear in the
//the config string.
return "";
}
string[] lastPass = firstPass[1].Split('&');
return HttpUtility.UrlDecode(lastPass[0]);
}
WindowIconCache ISaveLayout.WindowIconCache
{
get { return WindowIconCache; }
}
private void toolStripMenuItemClear_Click(object sender, EventArgs e)
{
clearAllPoints();
}
private void clearAllPoints() //clears all points for series..restarts again
{
chart1.Series[0].Points.Clear();
chart1.Series[1].Points.Clear();
chart1.Series[2].Points.Clear();
chart1.Series[3].Points.Clear();
Settings = _settings;
}
}
public class Settings
{
public String BullConfigString;
public String BearConfigString;
public int SecondsPerDataPoint;
public double FastRecentWeight;
public double SlowRecentWeight;
// public String BullConfigString { get; set; }
///
/// This is mostly aimed at testing, before the config window works.
///
public static Settings DecentSample()
{
Settings result = new Settings();
result.BullConfigString = "O=a000000000000000000000000000001_7dd_0&MinPrice=1&MaxPrice=250&MinVol5D=10000&col_ver=1&show0=D_Type"; //fed to config window when you click on "Config" for Green Data /save layout
result.BearConfigString = "O=14000000000000000000000000000002_7dd_0&MinPrice=1&MaxPrice=250&MinVol5D=10000&col_ver=1&show0=D_Type";//fed to config window when you click on "Config" for Red Data /save layout
result.SecondsPerDataPoint = 10;
result.FastRecentWeight = 0.9;
result.SlowRecentWeight = 0.1;
return result;
}
public Settings Clone()
{
return (Settings)MemberwiseClone();
}
///
/// Load saved settings. Use values defined in DecentSample as defaults
///
///
public void Load(XmlNode source)
{
DecentSample();
XmlNode description = source.Node("SETTINGS");
BullConfigString = description.Property("BULLISH", BullConfigString);
BearConfigString = description.Property("BEARISH", BearConfigString);
try
{
SecondsPerDataPoint = Convert.ToInt32(description.Property("SECONDS", SecondsPerDataPoint));
FastRecentWeight = Convert.ToDouble(description.Property("FAST_WEIGHT", FastRecentWeight));
SlowRecentWeight = Convert.ToDouble(description.Property("SLOW_WEIGHT", SlowRecentWeight));
}
catch
{ }
}
///
/// Save all settings
///
///
public void Save(XmlNode destination)
{
XmlNode settings = destination.NewNode("SETTINGS");
settings.SetProperty("BULLISH", BullConfigString);
settings.SetProperty("BEARISH", BearConfigString);
settings.SetProperty("SECONDS", SecondsPerDataPoint.ToString());
settings.SetProperty("FAST_WEIGHT", FastRecentWeight.ToString());
settings.SetProperty("SLOW_WEIGHT", SlowRecentWeight.ToString());
}
}
}