using System; using System.Collections.Generic; using System.ComponentModel; using System.Drawing; using System.Data; using System.Linq; using System.Text; using System.Windows.Forms; using TradeIdeas.TIProData; using TradeIdeas.TIProData.Configuration; using System.Windows.Forms.DataVisualization.Charting; using TradeIdeas.TIProGUI; namespace TradeIdeas.TIProGUI.CBT { [ToolboxItem(false)] public partial class ConfigDemoUpFromTheCloseBars : UserControl,IChild { struct BarSize { public string Name; public double todayBarSize; public double yesterdayBarSize; } string IChild.Name { get { return "Chart"; } } Control IChild.Body { get { return this; } } bool IChild.CanShowExample { get { return false; } } void IChild.OnShow() { // If exactly one value exists, show it. This helps us when we are // *displaying* a value which was set on a different tab page. if (_container.MinValue.HasValue && !_container.MaxValue.HasValue) minRadioButton.Checked = true; else if (_container.MaxValue.HasValue && !_container.MinValue.HasValue) maxRadioButton.Checked = true; // Otherwise keep it where it was. } private readonly IContainer _container; private readonly MinMaxSummary _minMaxSummary; private bool _userHasMadeChange = false; private Instrument _stock; private List _barsize = new List(); private double _symbolBarsizeInUse; private static readonly Instrument DELL = new Instrument("DELL", "DELL Inc.", @"Jul 31, 2012 11.86 11.97 11.85 11.89 1,397,000 11.85 Jul 30, 2012 12.03 12.05 11.81 11.85 14,086,700 11.85 Jul 27, 2012 11.96 12.12 11.88 12.03 17,802,200 12.03 Jul 26, 2012 11.69 11.91 11.66 11.83 21,524,400 11.83 Jul 25, 2012 11.57 11.73 11.43 11.49 23,542,300 11.49 Jul 24, 2012 11.85 11.89 11.47 11.57 21,406,300 11.57 Jul 23, 2012 11.78 11.87 11.52 11.80 24,638,300 11.80 Jul 20, 2012 12.22 12.28 12.00 12.01 14,004,300 12.01 Jul 19, 2012 12.15 12.30 12.11 12.23 13,252,300 12.23 Jul 18, 2012 12.07 12.29 12.02 12.07 25,957,000 12.07 Jul 17, 2012 12.24 12.30 12.02 12.12 19,459,000 12.12 Jul 16, 2012 12.27 12.42 12.17 12.19 12,668,000 12.19 Jul 13, 2012 12.11 12.36 12.07 12.32 12,399,300 12.32 Jul 12, 2012 12.16 12.22 12.00 12.13 12,314,100 12.13 Jul 11, 2012 12.32 12.41 12.16 12.28 18,566,300 12.28 Jul 10, 2012 12.27 12.49 12.15 12.30 20,876,900 12.30 Jul 9, 2012 12.51 12.60 12.16 12.27 17,265,700 12.27 Jul 6, 2012 12.58 12.63 12.35 12.56 15,414,700 12.56 Jul 5, 2012 12.67 12.73 12.55 12.63 11,150,400 12.63 Jul 3, 2012 12.42 12.69 12.35 12.68 10,696,800 12.68"); private static readonly Instrument MSFT = new Instrument("MSFT", "Microsoft Corporation", @"Aug 1, 2012 29.58 29.64 29.21 29.41 31,254,700 29.41 Jul 31, 2012 29.48 29.71 29.33 29.47 37,620,900 29.47 Jul 30, 2012 29.75 29.82 29.46 29.64 28,905,000 29.64 Jul 27, 2012 29.48 29.85 29.18 29.76 44,242,600 29.76 Jul 26, 2012 29.23 29.50 29.09 29.16 45,301,400 29.16 Jul 25, 2012 29.24 29.33 28.78 28.83 45,579,500 28.83 Jul 24, 2012 29.24 29.36 28.90 29.15 47,723,300 29.15 Jul 23, 2012 29.57 29.58 29.01 29.28 55,151,900 29.28 Jul 20, 2012 31.00 31.05 30.05 30.12 64,021,700 30.12 Jul 19, 2012 30.51 30.80 30.38 30.67 46,663,200 30.67 Jul 18, 2012 29.60 30.45 29.46 30.45 41,090,400 30.45 Jul 17, 2012 29.64 29.86 29.20 29.66 33,771,300 29.66 Jul 16, 2012 29.48 29.53 29.04 29.44 27,900,600 29.44 Jul 13, 2012 28.76 29.48 28.72 29.39 39,085,000 29.39 Jul 12, 2012 29.15 29.18 28.54 28.63 63,523,600 28.63 Jul 11, 2012 29.71 29.74 29.11 29.30 39,184,900 29.30 Jul 10, 2012 30.08 30.22 29.51 29.74 37,534,100 29.74 Jul 9, 2012 30.12 30.23 29.78 30.00 30,680,800 30.00 Jul 6, 2012 30.61 30.70 29.95 30.19 38,294,800 30.19 Jul 5, 2012 30.59 30.78 30.38 30.70 28,801,900 30.70"); private static readonly Instrument AMZN = new Instrument("AMZN", "Amazon Inc.", @"Aug 1, 2012 234.05 234.05 230.72 232.09 2,517,800 232.09 Jul 31, 2012 235.10 236.30 231.61 233.30 3,453,600 233.30 Jul 30, 2012 237.00 240.74 234.07 236.09 3,736,400 236.09 Jul 27, 2012 225.25 238.34 224.50 237.32 11,313,900 237.32 Jul 26, 2012 220.00 221.45 214.95 220.01 6,906,900 220.01 Jul 25, 2012 222.00 222.50 215.91 217.05 3,646,700 217.05 Jul 24, 2012 226.27 226.61 221.23 223.04 5,008,700 223.04 Jul 23, 2012 224.72 226.58 221.54 226.01 5,515,100 226.01 Jul 20, 2012 225.36 229.39 225.29 228.29 4,170,000 228.29 Jul 19, 2012 220.73 227.50 220.69 226.17 5,449,400 226.17 Jul 18, 2012 216.15 218.67 215.71 217.47 2,093,000 217.47 Jul 17, 2012 217.45 217.94 213.96 216.93 1,987,000 216.93 Jul 16, 2012 216.60 218.31 214.46 216.01 2,004,200 216.01 Jul 13, 2012 215.63 219.31 213.88 218.39 2,221,900 218.39 Jul 12, 2012 216.61 217.30 212.61 215.36 2,616,200 215.36 Jul 11, 2012 218.95 221.74 215.34 218.37 2,734,700 218.37 Jul 10, 2012 226.25 227.14 218.28 219.50 2,982,100 219.50 Jul 9, 2012 225.00 226.00 223.45 225.05 1,922,000 225.05 Jul 6, 2012 226.35 228.90 224.18 225.05 3,203,200 225.05 Jul 5, 2012 228.62 230.50 226.53 227.06 2,682,300 227.06"); private static readonly Instrument AAPL = new Instrument("AAPL","Apple Inc.",@"Jul 31, 2012 603.23 611.70 602.72 610.76 16,511,700 608.15 Jul 30, 2012 590.92 599.44 587.82 595.03 13,540,800 592.49 Jul 27, 2012 575.01 585.83 571.59 585.16 14,426,300 582.66 Jul 26, 2012 579.76 580.40 570.36 574.88 14,522,600 572.42 Jul 25, 2012 574.46 580.80 570.00 574.97 31,332,600 572.51 Jul 24, 2012 607.38 609.68 598.51 600.92 20,183,300 598.35 Jul 23, 2012 594.40 605.90 587.71 603.83 17,427,700 601.25 Jul 20, 2012 613.03 614.44 603.70 604.30 14,195,400 601.72 Jul 19, 2012 611.28 615.35 606.00 614.32 15,602,200 611.69 Jul 18, 2012 606.59 608.34 603.56 606.26 9,025,000 603.67 Jul 17, 2012 610.79 611.50 603.15 606.94 10,486,600 604.35 Jul 16, 2012 605.12 611.62 605.02 606.91 10,759,300 604.32 Jul 13, 2012 602.95 607.19 600.00 604.97 11,122,400 602.38 Jul 12, 2012 600.24 603.47 592.68 598.90 15,287,200 596.34 Jul 11, 2012 606.12 607.66 597.22 604.43 16,761,500 601.85 Jul 10, 2012 617.97 619.87 605.31 608.21 18,284,200 605.61 Jul 9, 2012 605.30 613.90 604.11 613.89 13,550,200 611.27 Jul 6, 2012 607.09 608.44 601.58 605.88 14,961,800 603.29 Jul 5, 2012 600.56 614.34 599.65 609.94 17,299,400 607.33 Jul 3, 2012 594.88 600.00 594.00 599.41 8,632,600 596.85"); private static readonly Instrument IBM = new Instrument("IBM","International Business Machines Corp",@"Jul 31, 2012 196.50 197.58 195.88 195.98 3,507,000 195.15 Jul 30, 2012 196.32 197.84 195.92 196.68 2,787,000 195.84 Jul 27, 2012 195.10 197.41 193.95 196.39 4,177,300 195.56 Jul 26, 2012 193.49 194.95 192.57 193.95 3,282,900 193.13 Jul 25, 2012 190.31 192.77 189.32 191.08 3,833,800 190.27 Jul 24, 2012 190.92 191.32 188.56 190.34 3,597,100 189.53 Jul 23, 2012 189.78 191.30 188.20 190.83 3,904,500 190.02 Jul 20, 2012 194.09 194.90 192.17 192.45 4,789,700 191.63 Jul 19, 2012 193.40 196.85 192.97 195.34 10,395,400 194.51 Jul 18, 2012 184.15 188.59 183.55 188.25 8,019,500 187.45 Jul 17, 2012 185.73 186.29 183.20 183.65 5,158,600 182.87 Jul 16, 2012 185.58 186.10 184.58 184.79 3,144,400 184.00 Jul 13, 2012 183.46 186.33 183.03 186.01 3,933,000 185.22 Jul 12, 2012 184.25 184.39 181.85 183.09 4,931,300 182.31 Jul 11, 2012 186.22 187.36 183.51 185.25 5,456,100 184.46 Jul 10, 2012 190.30 191.14 185.60 186.26 4,690,300 185.47 Jul 9, 2012 190.76 191.00 188.05 189.67 3,988,100 188.86 Jul 6, 2012 193.92 193.94 189.74 191.41 4,952,900 190.60 Jul 5, 2012 194.88 196.85 193.63 195.29 2,690,200 194.46 Jul 3, 2012 195.46 196.34 194.91 195.93 1,450,400 195.10"); private readonly Instrument[] STOCK_SAMPLES = new Instrument[] { DELL, MSFT, AMZN, AAPL, IBM }; private readonly Random _random = new Random(); private Instrument RANDOM_SAMPLE { get { return STOCK_SAMPLES[_random.Next() % STOCK_SAMPLES.Length]; } } private const double LARGE = 1.0E5; //Larger value causes the line to display incorrectly private bool _internalTrackBarChange = false; public ConfigDemoUpFromTheCloseBars(IContainer container) { loadBarsizes(); _container = container; _stock = DELL; _symbolBarsizeInUse = getCurrentSymbolsBarSize(_stock); InitializeComponent(); int initialHeight = stockSymbolLabel.Height; stockSymbolLabel.Font = new Font(stockSymbolLabel.Font.FontFamily, stockSymbolLabel.Font.SizeInPoints * 2, stockSymbolLabel.Font.Style); stockDescriptionLabel.Top += stockSymbolLabel.Height - initialHeight; _minMaxSummary = new MinMaxSummary(chart2); UpdateChart(); _container.MinTextBox.TextChanged += new EventHandler(MinTextBox_TextChanged); _container.MaxTextBox.TextChanged += new EventHandler(MaxTextBox_TextChanged); minPictureBox.Image = container.ConnectionMaster.ImageCacheManager.GetFilter("Min" + _container.InternalCode); maxPictureBox.Image = container.ConnectionMaster.ImageCacheManager.GetFilter("Max" + _container.InternalCode); } private void loadBarsizes() { _barsize.Clear(); /*Bar sizes ("volatility") were looked up on the TI website using the most recent date listed for each of the stocks in the hard-coded "Instrument" data above...*/ BarSize d; d.Name = DELL.Symbol; d.todayBarSize = 0.0548; d.yesterdayBarSize = 0.0551; BarSize m; m.Name = MSFT.Symbol; m.todayBarSize = 0.1073; m.yesterdayBarSize = 0.1069; BarSize a; a.Name = AMZN.Symbol; a.todayBarSize = 0.8763; a.yesterdayBarSize = 0.8721; BarSize i; i.Name = IBM.Symbol; i.todayBarSize = 0.5239; i.yesterdayBarSize = 0.5234; BarSize ap; ap.Name = AAPL.Symbol; ap.todayBarSize = 1.8447; ap.yesterdayBarSize = 1.8236; _barsize.Add(d); _barsize.Add(m); _barsize.Add(a); _barsize.Add(i); _barsize.Add(ap); } private double getCurrentSymbolsBarSize(Instrument ins) { double retVal = 0; foreach (BarSize b in _barsize) { if (ins.Symbol == b.Name) { retVal = b.yesterdayBarSize; break; } } return retVal; } void MaxTextBox_TextChanged(object sender, EventArgs e) { if (maxRadioButton.Checked) UpdateTrackBar(); UpdateChart(); ScaleChart(); } void MinTextBox_TextChanged(object sender, EventArgs e) { if (minRadioButton.Checked) UpdateTrackBar(); UpdateChart(); ScaleChart(); } private void UpdateTrackBar() { if (_internalTrackBarChange) // A change is already in progress. return; _internalTrackBarChange = true; _userHasMadeChange = true; double? value = GetRelevantValue(); if (null == value) { // We have no way to express "no value" on the track bar. // (The histograms say that either extreme on the track bar means no value. // I tried that here and it didn't work as well.) // So I just igore this and do nothing. The user already gets good feedback // somewhere else. } else { double rounded = Math.Round(value.Value); if (rounded > trackBar1.Maximum) // This is higher than the highest value the track bar can represent. // So set the track bar to its highest value. trackBar1.Value = trackBar1.Maximum; else if (rounded < trackBar1.Minimum) trackBar1.Value = trackBar1.Minimum; else trackBar1.Value = (int)rounded; } _internalTrackBarChange = false; } private void UpdateChart() { /*populate the series again immediately, before other calculations * (e.g. getting yesterdayclose) (otherwise a bug appears when getting a value * from the series when it hasn't been refreshed with the new data for another symbol*/ Bar bar = updateSeries(); double upFromCloseBar = trackBar1.Value; double? yesterdaysClose = getYesterdaysClose(); // if (null == yesterdaysClose) { return; } //get *today's close* for the y-value ; when given a trackbar value( which is a bar UpFromClose) double value = yesterdaysClose.Value + (upFromCloseBar * _symbolBarsizeInUse); if (_userHasMadeChange) DrawChart(value, bar); else DrawChart(); _minMaxSummary.MinValue = FilterToSummary(_container.MinValue); _minMaxSummary.MaxValue = FilterToSummary(_container.MaxValue); _minMaxSummary.Update(); ScaleChart(); } private void ScaleChart() { Axis yAxis = chart2.ChartAreas[0].AxisY; double? yClose = getYesterdaysClose(); if (null == yClose) return; double maxValue = MaxValueOnChart(); double minValue = MinValueOnChart(); double heightWithoutPadding = maxValue - minValue; double padding = 0.10 * heightWithoutPadding; maxValue = maxValue + padding; minValue = minValue - padding; if (maxValue != yAxis.Maximum) yAxis.Maximum = maxValue; if (minValue != yAxis.Minimum) yAxis.Minimum = minValue; } private double MaxValueOnChart() { double maxValue = double.NegativeInfinity; foreach (Series series in chart2.Series) { if (series.Points.Count > 0) { double seriesMax = series.Points.Max(x => x.YValues.Max()); if (seriesMax > maxValue) maxValue = seriesMax; } } Axis yAxis = chart2.ChartAreas[0].AxisY; return maxValue; } private double MinValueOnChart() { double minValue = double.PositiveInfinity; foreach (Series series in chart2.Series) { if (series.Points.Count > 0) { double seriesMin = series.Points.Min(x => x.YValues.Min()); if (seriesMin != 0 && seriesMin < minValue) minValue = seriesMin; } } Axis yAxis = chart2.ChartAreas[0].AxisY; return minValue; } private void UpdateTrackbar() { if (_internalTrackBarChange) // A change is already in progress. return; _internalTrackBarChange = true; _userHasMadeChange = true; double? value = GetRelevantValue(); if (null == value) { // We have no way to express "no value" on the track bar. // (The histograms say that either extreme on the track bar means no value. // I tried that here and it didn't work as well.) // So I just igore this and do nothing. The user already gets good feedback // somewhere else. } else { double rounded = Math.Round(value.Value); if (rounded > trackBar1.Maximum) // This is higher than the highest value the track bar can represent. // So set the track bar to its highest value. trackBar1.Value = trackBar1.Maximum; else if (rounded < trackBar1.Minimum) trackBar1.Value = trackBar1.Minimum; else trackBar1.Value = (int)rounded; } _internalTrackBarChange = false; } private double? getYesterdaysClose() { int members = chart2.Series[0].Points.Count; return chart2.Series[0].Points[members - 2].YValues[2]; //y-values[2} represents close } private void DrawChart(double value = 0, Bar lastBar = null) { stockSymbolLabel.Text = _stock.Symbol; stockDescriptionLabel.Text = _stock.Description; int tally = chart2.Series[0].Points.Count; DataPoint lastPoint = chart2.Series[0].Points[tally - 1]; //move last point to reflect movement if (value > 0 && null != lastBar && null != lastPoint) { double diff = (value - lastBar.Close); lastPoint.YValues = new double[] { lastBar.High + diff, lastBar.Low + diff, lastBar.Close + diff, lastBar.Open + diff }; } _minMaxSummary.X = chart2.Series[0].Points.Count; if (chart2.Series[1] != null) //this is the default "column" chart that is present when one uses a chart control... chart2.Series[1].IsVisibleInLegend = false; } private Bar updateSeries() { Series bars = chart2.Series[0]; bars.Points.Clear(); DataPoint lastPoint = null; Bar lastBar = null; foreach (Bar bar in _stock.Bars) { DataPoint point = new DataPoint(); point.AxisLabel = bar.DisplayDate; point.YValues = bar.Values; bars.Points.Add(point); point.Color = bar.Color(); lastPoint = point; lastBar = bar; } return lastBar; } private double FilterToChartPosition(double fromFilter) //"fromFilter" represents a "up-from-the-close (bars)" { double? yesterdayClosingValue = getYesterdaysClose(); if (null != yesterdayClosingValue) return yesterdayClosingValue.Value + (fromFilter * _symbolBarsizeInUse); return 0; } private double? FilterToSummary(double? fromFilter) { if (null == fromFilter) return null; return FilterToChartPosition(fromFilter.Value); } private double? GetRelevantValue() { double largeNumber = LARGE; double? value = null; if (minRadioButton.Checked) { value = _container.MinValue; } else { value = _container.MaxValue; } if (value == null) return value; largeNumber = largeNumber * Math.Sign((double)value); return (Math.Abs((double)value) > LARGE) ? largeNumber : value; } private void trackBar1_Scroll(object sender, EventArgs e) { _userHasMadeChange = true; if (_internalTrackBarChange) // We changed the trackbar to match the text boxes. return; // The user directly moved the track bar. _internalTrackBarChange = true; // Don't allow an echo! TextBox toChange = minRadioButton.Checked ? _container.MinTextBox : _container.MaxTextBox; toChange.Text = trackBar1.Value.ToString(); _internalTrackBarChange = false; } private void minRadioButton_CheckedChanged(object sender, EventArgs e) { UpdateTrackBar(); UpdateChart(); ScaleChart(); } private void maxRadioButton_CheckedChanged(object sender, EventArgs e) { UpdateTrackBar(); UpdateChart(); ScaleChart(); } //pub private void timer1_Tick(object sender, EventArgs e) { _stock = RANDOM_SAMPLE; _symbolBarsizeInUse = getCurrentSymbolsBarSize(_stock); UpdateTrackBar(); UpdateChart(); ScaleChart(); _minMaxSummary.Update(); } } }