// 04-gtk/01-basics using System; using System.Text; using System.IO; using System.Net; using Gtk; //requires mcs -pkg:gtk-sharp class MainClass { public static void Main (string[ ] args) { Application.Init ( ); Window w = new Window ("S&P 500 Stocks"); Button bDownloadSP = new Button("DownloadSP"); Button bDownload = new Button ("Download Stock Data"); Button bMakePage = new Button ("Make Stock Pages"); Button bGenIndexPage = new Button ("Generate Index Page"); Button bGraph = new Button ("Graph"); Button bExit = new Button("Exit"); ButtonBox buttonBox; buttonBox = new VButtonBox(); // set up event handling: verbose to illustrate // the use of delegates. w.DeleteEvent += new DeleteEventHandler (Window_Delete); bDownloadSP.Clicked += new EventHandler (bDownloadSP_Click); bDownload.Clicked += new EventHandler (bDownload_Click); bMakePage.Clicked += new EventHandler (bMakePage_Click); bGenIndexPage.Clicked += new EventHandler (bGenIndexPage_Click); bGraph.Clicked += new EventHandler (bGraph_Click); bExit.Clicked += new EventHandler (bExit_Click); // initialize the GUI w.Add (buttonBox); buttonBox.Add(bDownloadSP); buttonBox.Add(bDownload); buttonBox.Add(bMakePage); buttonBox.Add(bGenIndexPage); buttonBox.Add(bGraph); buttonBox.Add(bExit); w.SetDefaultSize (300, 200); w.ShowAll ( ); Application.Run ( ); } static void Window_Delete (object o, DeleteEventArgs args) { Application.Quit ( ); args.RetVal = true; } /// /// Downloads a group of market data files from the Internet /// and saves them to a file. /// static void downloadWebPage() { StringBuilder URL,path; WebRequest request; Stream responseStream; string currentLine,symbol; StreamReader sr; bool atEnd=false; int nStk=0; string stockList="./data/SP500.txt"; //Find out how many lines are in the stock list file. sr=new StreamReader(stockList); //Download one web page for each stock symbol in the StockList. path=new StringBuilder(); URL=new StringBuilder(); do { symbol=sr.ReadLine(); if(symbol==""||symbol==null) atEnd=true; else { System.Console.WriteLine(symbol); nStk+=1; path.Remove(0,path.Length); URL.Remove(0,URL.Length); path.Append(@"./data/"); path.Append(symbol+".bin"); //Find out when file was last updated. DateTime lastUpdate; if(File.Exists(path.ToString())) { Stream oldFile=File.OpenRead(path.ToString()); BinaryReader br=new BinaryReader(oldFile); br.BaseStream.Seek(-32,SeekOrigin.End); int month=br.ReadInt32(); int day=br.ReadInt32(); int year=br.ReadInt32(); lastUpdate=new DateTime(year,month,day); oldFile.Close(); br.Close(); } else { lastUpdate=new DateTime(1990,1,1); DateTime today=DateTime.Today; if (lastUpdate.Day==today.Day && lastUpdate.Month==today.Month && lastUpdate.Year==today.Year) return; //Download data starting from the day after the last update. URL.Append("http://table.finance.yahoo.com/table.csv?a=" + lastUpdate.Month + "&b=" + lastUpdate.Day+1 + "&c="+lastUpdate.Year+"&d=" + today.Month + "&e=" + today.Day + "&f=" + today.Year + "&s="); URL.Append(symbol+"&y=0&g=d&ignore=.csv"); //System.Console.WriteLine("URL: " + URL.ToString()); request=WebRequest.Create(URL.ToString()); responseStream = request.GetResponse().GetResponseStream(); //Save to disk. writeBinary(responseStream,path.ToString()); //progressBar1.Value++; } } } while(!atEnd); sr.Close(); //progressBar1.Value=0; } /// /// Writes a binary file from a Stream of market data. /// /// Stream of market data from the Internet. static void writeBinary(Stream dataStream,string path) { //Create array of strings from data Stream. StreamReader sr=new StreamReader(dataStream); bool atEnd=false; string[][] data; string[] line=new string [10000]; int numberOfLines=0; int x=0; sr.ReadLine(); //First line not needed. while(!atEnd) { line[x]=sr.ReadLine(); if(line[x]==null) atEnd=true; else { numberOfLines++; x++; } } sr.Close(); data=new String [numberOfLines][]; for(int i=0; i /// Reads a .csv file and stores the data in an array. /// /// The path of the file /// to be read. /// Returns a two-dimensional array /// of the .csv data in string format. static string[,] readFile(string fileName) { Stream dataStream=File.OpenRead(fileName); BinaryReader br=new BinaryReader(dataStream); //Find out how many lines of data there are. int rows=br.ReadInt32(); DateTime[] date=new DateTime[rows]; float[] open=new float[rows]; float[] high=new float[rows]; float[] low=new float[rows]; float[] close=new float[rows]; int[] volume=new int[rows]; //Read file. int month,day,year; for(int i=0; i /// Draws a line graph of close data and saves it as a .gif file. /// /// Array of DateTimes that will be used for /// the x-axis. /// Array of floats used for the y-axis. /// Indicates where the image /// will be saved and the filename of the image. /// Number of yData points between big ticks. /// Number of yData points between small ticks. /// Interval between tick marks on x-axis. If 0, one /// tick every month. If 1, one tick every year. /// The color of the graph. /// If true, values will be made smaller by dividing /// by 1 million. If this method causes an infinite loop, set this /// parameter to true. /// The label of the y-axis. /// The title of the graph. /// The number of decimal places in the /// ySmallInterval parameter. The precision parameter must /// be set correctly to avoid an infinite loop. static void drawGraph(DateTime[] dates,float[] yData,string fileName, // float yBigInterval,float ySmallInterval,int xInterval,Color color,bool reduce, float yBigInterval,float ySmallInterval,int xInterval,bool reduce, string yAxisLabel,string title,int precision) { // call plotting program /* TimeSpan dateRange,fromStart; int numberOfDays; int yHighInt,yLowInt; decimal yLabel; decimal yHigh=0,yLow,yRange; decimal scaleX,scaleY; decimal tickInterval,posit; DateTime dateLabel,date; Pen axisPen=new Pen(Color.Black,2); //Pen graphPen=new Pen(color); Pen graphPen = new Pen(Color.Red,1); Pen tickPen=new Pen(Color.Black,1); Point origin,xEnd,yEnd,newPoint,oldPoint,tickPoint,textPoint; Font font=new Font("Times New Roman",7); Font titleFont=new Font("Times New Roman",30,FontStyle.Bold); Font labelFont=new Font("Times New Roman",12,FontStyle.Bold); SolidBrush brush=new SolidBrush(Color.Black); SolidBrush titleBrush=new SolidBrush(Color.FromArgb(75,Color.Black)); string dateLabelString; Bitmap graph; Graphics g; int n=(int)numericUpDown1.Value; //Remove data that should not be graphed. if(cbUseAllData.Checked==false) { dates=removeData(dates); yData=removeData(yData); } int rows=dates.Length; DateTime latest=dates[0]; DateTime earliest=dates[rows-1]; decimal[,] pointCoord=new decimal[rows,2]; //Make values smaller if bool reduce is true if(reduce) { for(int i=0; i(decimal)yData[i] && yData[i]!=-999) yLow=(decimal)yData[i]; } yLowInt=roundToInt(yLow); yHighInt=roundToInt(yHigh); yRange=yHigh-yLow; dateRange=latest-earliest; numberOfDays=dateRange.Days; scaleY=400/yRange; scaleX=500/(decimal)numberOfDays; //Find how many pixels above and to the right of //the origin each point should go. for(int i=0; i=yEnd.Y) { j=Math.Round(j,precision); if (((yLowInt+j)%yBigInterval)==0) { drawTick(g,tickPen,tickPoint,false,6); drawTick(g,tickPen,tickPoint2,false,6); textPoint.X=tickPoint.X-27; textPoint.Y=tickPoint.Y-5; textPoint2.X=tickPoint2.X+10; textPoint2.Y=tickPoint2.Y-5; yLabel=(decimal)(yLowInt+j); g.DrawString(yLabel.ToString(),font,brush,textPoint); g.DrawString(yLabel.ToString(),font,brush,textPoint2); } else { drawTick(g,tickPen,tickPoint,false,3); drawTick(g,tickPen,tickPoint2,false,3); } j+=ySmallInterval; posit+=tickInterval; tickPoint.Y=origin.Y-roundToInt(posit); tickPoint2.Y=tickPoint.Y; tickPoint2.X=tickPoint.X + 500; } tickPoint.X=yEnd.X; tickPoint.Y=yEnd.Y; tickPoint2.X=yEnd2.X; tickPoint2.Y=yEnd2.Y; drawTick(g,tickPen,tickPoint,false,6); drawTick(g,tickPen,tickPoint2,false,6); g.DrawString(yHigh.ToString(),font,brush,10,5); g.DrawString(yHigh.ToString(),font,brush,yEnd2.X+30,yEnd2.Y-5); //Draw x-axis tick marks and labels. //One tick every month. posit=0; j=0; tickPoint.X=origin.X; tickPoint.Y=origin.Y; tickInterval=1.0M*scaleX; while(origin.X+posit<=xEnd.X) { dateLabel=earliest.AddDays(j); if(dateLabel.Day==1) { if(dateLabel.Month==1) { this.drawTick(g,tickPen,tickPoint,true,6); textPoint.X=tickPoint.X-15; textPoint.Y=tickPoint.Y+25; dateLabelString=dateLabel.Month.ToString()+"/"+ dateLabel.Day.ToString()+"/"+ dateLabel.Year.ToString(); g.DrawString(dateLabelString,font,brush,textPoint); } else { if(xInterval==0) { drawTick(g,tickPen,tickPoint,true,3); textPoint.X=tickPoint.X-7; textPoint.Y=tickPoint.Y+10; dateLabelString=dateLabel.Month.ToString()+"/"+ dateLabel.Day.ToString(); g.DrawString(dateLabelString,font,brush,textPoint); } } } j++; posit+=tickInterval; tickPoint.X=origin.X+roundToInt(posit); } //Draw graph. for(int i=0; i= 0) { symb = symb.Substring(0, dotIndex); } sw.WriteLine(symb); //Console.WriteLine(data[i][0] + " " + dotIndex + " " + symb); } } sw.Close(); Console.WriteLine("Done. We have the list!"); } static string[][] getSPData(bool download) { //Download and save page. if(download==true) { //Console.WriteLine("download the data"); WebRequest request=WebRequest.Create("http://www2.standardandpoors.com/spf/csv/index/sp500.csv"); Stream responseStream=request.GetResponse().GetResponseStream(); StreamReader sr2=new StreamReader(responseStream); string responseString=sr2.ReadToEnd(); sr2.Close(); StreamWriter sw=new StreamWriter (@"./data/SPData.csv"); sw.Write(responseString); sw.Close(); } //Get stock symbols. String[][] symbols=new String[600][]; bool atEnd=false; string line; int i=0; //Console.WriteLine("init the symbols"); // initialize symbols (in case the S&P500 has < 500 stocks) line="NULL,Company,20,Industrials,2010,Goods,201050,Conglomerates,20105010,Conglomerates"; for (int k=0; k<500; k++) { symbols[k]=csvSplit(line); } StreamReader sr=new StreamReader(@"./data/SPData.csv"); for(int j=0; j<5; j++) //First 5 lines are not needed. { sr.ReadLine(); } while(atEnd==false) { line=sr.ReadLine(); if(line==null) atEnd=true; else symbols[i]=csvSplit(line); i++; } sr.Close(); return symbols; } static string[] csvSplit(string s) { StringReader sr=new StringReader(s); string[] array=new string[100]; int i=0; bool atEnd=false,endQuote=false; char c,d; while(!atEnd) { c=(char)sr.Read(); //Read() returns -1 if it reaches the end of the string. //-1 as a character is a question mark. if(c=='?' || c==(char)65535) atEnd=true; else { switch(c) { case '"': while(!endQuote) { d=(char)sr.Read(); if(d == '"') { endQuote=true; } else { array[i]+=d; } } break; case ',': i++; break; default: array[i]+=c; break; } } } return array; } // Generate stock index page static void bGenIndexPage_Click(object sender, System.EventArgs e) { generateSPPage(); } static void generateSPPage() { /* //Generate color scale. Color[] colors=new Color[400]; //Start with full red,no blue, and increasing green. for(int i=0; i<100; i++) { colors[i]=Color.FromArgb(100,255,roundToInt(2.55*i),0); } //Continue with max green, no blue, and decreasing red. for(int i=100; i<200; i++) { colors[i]=Color.FromArgb(100, 255 - roundToInt(2.55*(i-100)),255,0); } //Next 100 colors have no red, max green, and increasing blue. for(int i=200; i<300; i++) { colors[i]=Color.FromArgb(100,0,255,roundToInt(2.55*(i-200))); } //Last 100 colors have no red, max blue, and decreasing green. for(int i=300; i<400; i++) { colors[i]=Color.FromArgb(100,0,255 - roundToInt(2.55*(i-300)),255); } //Make color scale image. Bitmap colorScale=new Bitmap(100,400); Graphics g=Graphics.FromImage(colorScale); g.Clear(Color.White); for(int i=0; i<400; i++) { g.DrawLine(new Pen(colors[i],1),0,i,30,i); } g.DrawLine(new Pen(Color.Black,1),0,200,30,200); g.DrawString("100 % Gain",new Font("Times New Roman",10), new SolidBrush(Color.Black),35,0); g.DrawString("0 % Gain",new Font("Times New Roman",10), new SolidBrush(Color.Black),35,190); g.DrawString("100 % Loss",new Font("Times New Roman",10), new SolidBrush(Color.Black),35,380); g.Dispose(); colorScale.Save(@"./Web/colorScale.jpg", ImageFormat.Jpeg); //Pick the right background color for each stock symbol. Color[] bgColors=new Color[500]; */ int[] bgColors = new int[500]; float gain; // call Form1_closing to create colorStats.txt colorStats(); StreamReader sr=new StreamReader( @"./data/colorStats.txt"); for(int i=0; i<500; i++) { try { gain=float.Parse(sr.ReadLine()); } catch // exit if < 500 stocks in the list { break; } //Round to nearest half. /* if(Math.Abs(gain-(int)gain)<0.25) gain=(int)gain; if(Math.Abs(gain-(int)gain)>=0.25 && Math.Abs(gain-(int)gain)<0.75) { if(gain>0) gain=(int)gain+0.5F; if(gain<0) gain=(int)gain-0.5F; } if(Math.Abs(gain-(int)gain)>=0.75) { if(gain>0) gain=(int)gain+1; if(gain<0) gain=(int)gain-1; } */ if(gain>=1) bgColors[i]=1; //colors[0]; if(gain <= -1) bgColors[i]=-1; //colors[400]; if(gain > -1 && gain < 1) bgColors[i]=0; //colors[200-(int)(gain*2)]; } sr.Close(); //Web page. sr=new StreamReader(@"./data/SP500.txt"); StreamWriter sw=new StreamWriter (@"./Web/SP500.html"); string symbol; sw.WriteLine("S&P 500 Components"); sw.WriteLine("

S&P 500 Components

"); sw.WriteLine(""); for(int j=0; j<10; j++) { string bg; if (bgColors[colorIndex] == 1) { bg = "lime"; } else { if (bgColors[colorIndex] == -1) { bg = "red"; } else { bg = "yellow"; } } symbol=sr.ReadLine(); // sw.WriteLine(""); colorIndex++; } sw.WriteLine(""); } sw.WriteLine("
" +symbol+ "
"); // sw.WriteLine(""); sw.WriteLine(""); sw.Close(); sr.Close(); } static void bMakePage_Click(object sender, System.EventArgs e) { string stockList=""; bool atEnd=false; string currentLine=""; int numberOfLines=0; string symbol=""; StringBuilder path=new StringBuilder(), fileName=new StringBuilder(); stockList=@"./data/SP500.txt"; //Find out how many lines are in the stock list file. StreamReader sr=new StreamReader(stockList); do { currentLine=sr.ReadLine(); if(currentLine==""||currentLine==null) atEnd=true; else numberOfLines+=1; } while(!atEnd); // progressBar1.Maximum=numberOfLines; //Reset file pointer to the beginning. sr.BaseStream.Seek(0, SeekOrigin.Begin); sr.BaseStream.Position = 0; //Generate one web page for each stock symbol. for(int i=0; i"); sw.WriteLine(""); sw.WriteLine("mathematicalanalysis.com"); sw.WriteLine("S&P 500 Components"); if(previous!="") sw.WriteLine("Previous"); if(next!="") sw.WriteLine("Next"); sw.WriteLine("
"); //Title sw.WriteLine("Market Data for " +symbol+ ""); string title="",industry=""; string[][] info = getSPData(false); for (int i=0; i<500; i++) { if (info[i][0]==symbol) { title=info[i][1]; industry=info[i][9]; break; } } sw.WriteLine("

" + symbol + " - " + title + "

"); sw.WriteLine("

[" + industry + "]

"); //Table of stats sw.WriteLine(""); sw.WriteLine(" "); sw.WriteLine(""); sw.WriteLine(""); sw.WriteLine(""); sw.WriteLine(""); float change=0,volAvg=0,volSum=0; if(data.GetLength(0)>5) { change=(float.Parse(data[0,4])-float.Parse(data[4,4])) / float.Parse(data[4,4]) * 100; change=(float)Math.Round(change,1); for(int i=0; i<5; i++) { volSum+=float.Parse(data[i,5]); } volAvg=volSum / 5; sw.WriteLine(""); } else sw.WriteLine(""); sw.WriteLine(""); if(data.GetLength(0)>21) { change=(float.Parse(data[0,4])-float.Parse(data[20,4])) / float.Parse(data[20,4]) * 100; change=(float)Math.Round(change,1); volSum=0; for(int i=0; i<21; i++) { volSum+=float.Parse(data[i,5]); } volAvg=volSum / 21; sw.WriteLine(""); } else sw.WriteLine(""); sw.WriteLine(""); if(data.GetLength(0)>63) { change=(float.Parse(data[0,4])-float.Parse(data[62,4])) / float.Parse(data[62,4]) * 100; change=(float)Math.Round(change,1); volSum=0; for(int i=0; i<63; i++) { volSum+=float.Parse(data[i,5]); } volAvg=volSum / 63; sw.WriteLine(""); } else sw.WriteLine(""); sw.WriteLine(""); if(data.GetLength(0)>253) { change=(float.Parse(data[0,4])-float.Parse(data[252,4])) / float.Parse(data[252,4]) * 100; change=(float)Math.Round(change,1); volSum=0; for(int i=0; i<253; i++) { volSum+=float.Parse(data[i,5]); } volAvg=volSum / 253; sw.WriteLine(""); } else sw.WriteLine(""); sw.WriteLine(""); if(data.GetLength(0)>758) { change=(float.Parse(data[0,4])-float.Parse(data[757,4])) / float.Parse(data[757,4]) * 100; change=(float)Math.Round(change,1); volSum=0; for(int i=0; i<758; i++) { volSum+=float.Parse(data[i,5]); } volAvg=volSum / 758; sw.WriteLine(""); } else sw.WriteLine(""); sw.WriteLine(""); if(data.GetLength(0)>2525) { change=(float.Parse(data[0,4])-float.Parse(data[2524,4])) / float.Parse(data[2524,4]) * 100; change=(float)Math.Round(change,1); volSum=0; for(int i=0; i<2525; i++) { volSum+=float.Parse(data[i,5]); } volAvg=volSum / 2525; sw.WriteLine(""); } else sw.WriteLine(""); sw.WriteLine("
As of " + DateTime.Parse(data[0,0]).ToShortDateString() + "
PerformanceAverage Volume
Current Price" + data[0,4] + "
Past Week"+change.ToString()+"%"+volAvg+"
N/AN/A
Past Month"+change.ToString()+"%"+volAvg.ToString() +"
N/AN/A
Past Quarter"+change.ToString()+"%"+volAvg.ToString() +"
N/AN/A
Past Year"+change.ToString()+"%"+volAvg.ToString() +"
N/AN/A
Past 3 Years"+change.ToString()+"%"+volAvg.ToString() +"
N/AN/A
Past 10 Years"+change.ToString()+"%"+volAvg.ToString() +"
N/AN/A
"); //Graphs sw.WriteLine( "Yahoo! Finance " + title + " Basic Chart"); // image src='"+symbol+"close.gif'>"); // sw.WriteLine( // ""); sw.WriteLine(""); sw.Close(); } static float[][] calculateStats(string[,] data) { float[] closeHigh=new float[1], closeAve=new float[1], volHigh=new float[1]; float volSum=0,closeSum=0; float[] volLow=new float[1], closeLow=new float[1],volAve=new float[1];; float val1,val2; float[][] stats=new float[9][]; float[] rVol=new float[data.GetLength(0)]; //check if there was an error reading the file. if (data[0,0]=="error") { stats[0][0]=-1; return stats; } /**calculate high, low, and sum close *and volume data**/ closeLow[0]=float.Parse(data[0,4]); volLow[0]=float.Parse(data[0,5]); closeHigh[0]=0; volHigh[0]=0; volAve[0]=0; closeAve[0]=0; for (int i=0; i float.Parse(data[i,4])) closeLow[0] = float.Parse(data[i,4]); if (volHigh[0]float.Parse(data[i,5])) volLow[0]=float.Parse(data[i,5]); closeSum+=float.Parse(data[i,4]); volSum+=float.Parse(data[i,5]); } closeAve[0]=closeSum/data.GetLength(0); volAve[0]=volSum/data.GetLength(0); //Calculate volatility. int n=21; //(int)numericUpDown1.Value; float[] closeData=new float[data.GetLength(0)]; for (int i=0; i=0; i--) { rVol[i]=-999; } Array.Reverse(rVol); //Calculate gain/loss. int rows=data.GetLength(0),lossDays=0,gainDays=0; bool[] loss=new bool[rows]; float open,close,afterLoss=0,afterGain=0; float[] change=new float[rows],changePercent=new float[rows]; for(int i=0; i0) sign1='+'; else sign1='-'; if(percentChange[i-1]>0) sign2='+'; else sign2='-'; if(sign1==sign2) index[i]=Math.Abs(percentChange[i]); else index[i]= -Math.Abs(percentChange[i]); } float[] average=new float[index.Length]; float[] sum=new float[index.Length]; int maxDays=(int)63; //numericUpDown3.Value; for(int i=maxDays; i