/// <summary>
        /// Downloads and processes historical data for given stock symbol.
        /// </summary>
        /// <param name="symbol">stock symbol, e.g. "msft"</param>
        /// <param name="numYearsOfHistory">years of history > 0, e.g. 10</param>
        private static void ProcessStockSymbol(string symbol, int numYearsOfHistory)
        {
            try
            {
                StockData data = DownloadData.GetHistoricalData(symbol, numYearsOfHistory);

                int N = data.Prices.Count;

                Task <decimal> T_min = Task.Factory.StartNew <decimal>(() =>
                {
                    return(data.Prices.Min());
                }
                                                                       );

                Task <decimal> T_max = Task.Factory.StartNew <decimal>(() =>
                {
                    return(data.Prices.Max());
                }
                                                                       );

                Task <decimal> T_avg = Task.Factory.StartNew <decimal>(() =>
                {
                    return(data.Prices.Average());
                }
                                                                       );

                Task <double> T_stddev = Task.Factory.StartNew(() =>
                {
                    // Standard deviation:
                    double sum    = 0.0;
                    decimal l_avg = data.Prices.Average();

                    foreach (decimal value in data.Prices)
                    {
                        sum += Math.Pow(Convert.ToDouble(value - l_avg), 2.0);
                    }

                    //
                    // NOTE: want to test exception handling?  Uncomment the following to trigger
                    // divide-by-zero, and notice you get 2 task exceptions, one from this code
                    // and one from the continuation task (stderr) that fails because we fail.
                    //
                    //int abc = 0;
                    //int x = 1000 / abc;

                    return(Math.Sqrt(sum / N));
                }
                                                               );

                Task <double> T_stderr = T_stddev.ContinueWith((antecedent) =>
                {
                    return(antecedent.Result / Math.Sqrt(N));
                }
                                                               );

                //
                // Wait and harvest results when done:
                //
                // NOTE: even though WaitAll is not required for correctness (calls to .Result do
                // an implicit .Wait), we use WaitAll for efficiency so that we process tasks in
                // order as they finish (versus an arbitrary order implied by calls to .Result).
                //
                try
                {
                    Task.WaitAll(new Task[] { T_min, T_max, T_avg, T_stddev, T_stderr });
                }
                catch (AggregateException)      // tasking errors:
                {
                    throw;                      // re-throw, output error messages below:
                }

                decimal min    = T_min.Result;
                decimal max    = T_max.Result;
                decimal avg    = T_avg.Result;
                double  stddev = T_stddev.Result;
                double  stderr = T_stderr.Result;

                //
                // Output:
                //
                // NOTE: we build a single output string and then write to the console in one op.
                // Otherwise, if we output one value at a time, our output might get intermixed
                // with the output from another, parallel task.  Note that Console class is thread-
                // safe, so this works as long as we make only a single call for our output.
                //
                string output = string.Format("\n** {0} **", symbol);
                output = string.Format("{0}\n   Data source:  '{1}'", output, data.DataSource);
                output = string.Format("{0}\n   Data points:   {1:#,##0}", output, N);
                output = string.Format("{0}\n   Min price:    {1:C}", output, min);
                output = string.Format("{0}\n   Max price:    {1:C}", output, max);
                output = string.Format("{0}\n   Avg price:    {1:C}", output, avg);
                output = string.Format("{0}\n   Std dev/err:   {1:0.000} / {2:0.000}", output, stddev, stderr);

                Console.WriteLine(output);
            }
            catch (AggregateException ae)
            {
                string output = string.Format("\n** {0} **", symbol);

                ae = ae.Flatten(); // could have a tree of exceptions, so flatten first:
                foreach (Exception ex in ae.InnerExceptions)
                {
                    output = string.Format("{0}\nError: {1}", output, ex.Message);
                }

                Console.WriteLine(output);
            }
            catch (Exception ex)
            {
                string output = string.Format("\n** {0} **\nError: {1}", symbol, ex.Message);
                Console.WriteLine(output);
            }
        }
Beispiel #2
0
        /// <summary>
        /// Downloads and processes historical data for given stock symbol.
        /// </summary>
        /// <param name="symbol">stock symbol, e.g. "msft"</param>
        /// <param name="numYearsOfHistory">years of history > 0, e.g. 10</param>
        private static void ProcessStockSymbol(string symbol, int numYearsOfHistory)
        {
            try
            {
                StockData data = DownloadData.GetHistoricalData(symbol, numYearsOfHistory);

                int N = data.Prices.Count;

                Task <decimal> T_min = Task.Factory.StartNew <decimal>(() =>
                {
                    return(data.Prices.Min());
                }
                                                                       );

                Task <decimal> T_max = Task.Factory.StartNew <decimal>(() =>
                {
                    return(data.Prices.Max());
                }
                                                                       );

                Task <decimal> T_avg = Task.Factory.StartNew <decimal>(() =>
                {
                    return(data.Prices.Average());
                }
                                                                       );

                Task <double> T_stddev = Task.Factory.StartNew(() =>
                {
                    // Standard deviation:
                    double sum    = 0.0;
                    decimal l_avg = data.Prices.Average();

                    foreach (decimal value in data.Prices)
                    {
                        sum += Math.Pow(Convert.ToDouble(value - l_avg), 2.0);
                    }

                    //
                    // NOTE: want to test exception handling?  Uncomment the following to trigger
                    // divide-by-zero, and notice you get 2 task exceptions, one from this code
                    // and one from the continuation task (stderr) that fails because we fail.
                    //
                    //int abc = 0;
                    //int x = 1000 / abc;

                    return(Math.Sqrt(sum / N));
                }
                                                               );

                Task <double> T_stderr = T_stddev.ContinueWith((antecedent) =>
                {
                    return(antecedent.Result / Math.Sqrt(N));
                }
                                                               );

                //
                // Wait and harvest results when done:
                //
                // NOTE: even though WaitAll is not required for correctness (calls to .Result do
                // an implicit .Wait), we use WaitAll for efficiency so that we process tasks in
                // order as they finish (versus an arbitrary order implied by calls to .Result).
                //
                Task.WaitAll(new Task[] { T_min, T_max, T_avg, T_stddev, T_stderr });

                decimal min    = T_min.Result;
                decimal max    = T_max.Result;
                decimal avg    = T_avg.Result;
                double  stddev = T_stddev.Result;
                double  stderr = T_stderr.Result;

                //
                // Output:
                //
                Console.WriteLine();
                Console.WriteLine("** {0} **", symbol);
                Console.WriteLine("   Data source:  '{0}'", data.DataSource);
                Console.WriteLine("   Data points:   {0:#,##0}", N);
                Console.WriteLine("   Min price:    {0:C}", min);
                Console.WriteLine("   Max price:    {0:C}", max);
                Console.WriteLine("   Avg price:    {0:C}", avg);
                Console.WriteLine("   Std dev/err:   {0:0.000} / {1:0.000}", stddev, stderr);
            }
            catch (Exception ex)
            {
                Console.WriteLine();
                Console.WriteLine("** {0} **", symbol);
                Console.WriteLine("Error: {0}", ex.Message);
            }
        }
Beispiel #3
0
        /// <summary>
        /// Downloads and processes historical data for given stock symbol.
        /// </summary>
        /// <param name="symbol">stock symbol, e.g. "msft"</param>
        /// <param name="numYearsOfHistory">years of history > 0, e.g. 10</param>
        private static void ProcessStockSymbol(string symbol, int numYearsOfHistory)
        {
            try
            {
                StockData data = DownloadData.GetHistoricalData(symbol, numYearsOfHistory);

                int N = data.Prices.Count;

                decimal min = 0, max = 0, avg = 0;
                Task    t_min = Task.Run(() =>
                {
                    min = data.Prices.Min();
                });

                Task t_max = Task.Run(() =>
                {
                    max = data.Prices.Max();
                });

                Task t_avg = Task.Run(() =>
                {
                    avg = data.Prices.Average();
                });


                // Standard deviation:
                double sum = 0.0;

                foreach (decimal value in data.Prices)
                {
                    sum += Math.Pow(Convert.ToDouble(value - avg), 2.0);
                }

                double stddev = Math.Sqrt(sum / N);

                // Standard error:
                double stderr = stddev / Math.Sqrt(N);

                //
                // Output:
                //
                Console.WriteLine();
                Console.WriteLine("** {0} **", symbol);
                Console.WriteLine("   Data source:  '{0}'", data.DataSource);
                Console.WriteLine("   Data points:   {0:#,##0}", N);

                t_min.Wait();
                Console.WriteLine("   Min price:    {0:C}", min);

                t_max.Wait();
                Console.WriteLine("   Max price:    {0:C}", max);

                t_avg.Wait();
                Console.WriteLine("   Avg price:    {0:C}", avg);
                Console.WriteLine("   Std dev/err:   {0:0.000} / {1:0.000}", stddev, stderr);
            }
            catch (Exception ex)
            {
                Console.WriteLine();
                Console.WriteLine("** {0} **", symbol);
                Console.WriteLine("Error: {0}", ex.Message);
            }
        }
        /// <summary>
        /// Tries to download historial data from 3 different web sites, and takes the data
        /// from the first site that responds.  Sites used:  nasdaq, yahoo, and msn (although
        /// msn only provides a year of weekly data, so others are preferred).
        ///
        /// NOTE: we use the async web methods BeginGetResponse and EndGetResponse to access
        /// the web sites asynchronously, with a Task-based facade on top.  This has the advantages
        /// that (1) worker thread is not dedicated to request (i.e. different threads can
        /// initiate vs. handle callback), and (2) easier to cancel outstanding requests.
        /// </summary>
        /// <param name="symbol"></param>
        /// <param name="numYearsOfHistory"></param>
        /// <returns></returns>
        private static StockData GetDataFromInternet(string symbol, int numYearsOfHistory)
        {
            //
            // initiate web requests:
            //
            Task <StockData> t_yahoo  = GetDataFromYahooAsync(symbol, numYearsOfHistory);
            Task <StockData> t_nasdaq = GetDataFromNasdaqAsync(symbol, numYearsOfHistory);
            Task <StockData> t_msn    = GetDataFromMsnAsync(symbol, numYearsOfHistory);

            //
            // Now wait for the first one to successfully return data (the others we'll cancel):
            //
            List <Task <StockData> > tasks = new List <Task <StockData> >();

            tasks.Add(t_yahoo);
            tasks.Add(t_nasdaq);
            tasks.Add(t_msn);

            //
            // WaitOneByOne pattern: first one that returns without exception
            //
            StockData result = null;

            while (tasks.Count > 0)
            {
                int timeout = 15 * 1000;                              // 15 secs:
                int winner  = Task.WaitAny(tasks.ToArray(), timeout); // no task-based exception thrown here:

                if (winner < 0)                                       // timeout!
                {
                    break;
                }

                // was task successful?  Check exception here:
                if (tasks[winner].Exception == null)                  // success!
                {
                    result = tasks[winner].Result;
                    tasks.RemoveAt(winner);
                    break;
                }

                // else this task failed, wait for next to finish:
                tasks.RemoveAt(winner);
            }

            //
            // did we succeed or fail?  Either way, first cancel any unfinished requests,
            // and then return result or throw exception...
            //
            foreach (Task t in tasks)              // cancel outstanding requests:
            {
                (t.AsyncState as RequestState).Request.Abort();
            }

            if (result != null)              // success!
            {
                return(result);
            }
            else
            {
                throw new ApplicationException("all web sites failed");
            }
        }
Beispiel #5
0
        /// <summary>
        /// Downloads and processes historical data for given stock symbol.
        /// </summary>
        /// <param name="symbol">stock symbol, e.g. "msft"</param>
        /// <param name="numYearsOfHistory">years of history > 0, e.g. 10</param>
        private static void ProcessStockSymbol(string symbol, int numYearsOfHistory)
        {
            try
            {
                Task t_error = Task.Factory.StartNew(() =>
                {
                    int i = 10;
                    int j = 10 / i;
                });

                StockData data = DownloadData.GetHistoricalData(symbol, numYearsOfHistory);

                int N = data.Prices.Count;

                Task <decimal> t_min = Task.Factory.StartNew(() =>
                {
                    decimal min = data.Prices.Min();
                    return(min);
                });
                Task <decimal> t_max = Task.Factory.StartNew(() =>
                {
                    decimal max = data.Prices.Max();
                    return(max);
                });
                Task <decimal> t_avg = Task.Factory.StartNew(() =>
                {
                    decimal avg = data.Prices.Average();
                    return(avg);
                });

                // Standard deviation:

                Task <double> t_stddev = Task.Factory.StartNew(() =>
                {
                    double sum    = 0.0;
                    decimal l_avg = data.Prices.Average();
                    foreach (decimal value in data.Prices)
                    {
                        sum += Math.Pow(Convert.ToDouble(value - l_avg), 2.0);
                    }
                    int i = 10;
                    int j = 10 / i;

                    double stddev = Math.Sqrt(sum / N);
                    return(stddev);
                });

                // Standard error:
                Task <double> t_stderr = t_stddev.ContinueWith((antecedent) =>
                {
                    //t_stddev.Wait();
                    double stderr = antecedent.Result / Math.Sqrt(N);
                    return(stderr);
                });
                //
                // Output:
                //
                //t_min.Wait();
                //t_max.Wait();
                //t_avg.Wait();
                //t_stddev.Wait();
                //t_stderr.Wait();
                Task[] tasks = { t_min, t_max, t_avg, t_stddev, t_stderr, t_error };
                Task.WaitAll(tasks);
                //lock (Console.Out)
                //{
                //    Console.WriteLine();
                //    Console.WriteLine("** {0} **", symbol);
                //    Console.WriteLine("   Data source:  '{0}'", data.DataSource);
                //    Console.WriteLine("   Data points:   {0:#,##0}", N);
                //    Console.WriteLine("   Min price:    {0:C}", t_min.Result);
                //    Console.WriteLine("   Max price:    {0:C}", t_max.Result);
                //    Console.WriteLine("   Avg price:    {0:C}", t_avg.Result);
                //    Console.WriteLine("   Std dev/err:   {0:0.000} / {1:0.000}", t_stddev.Result, t_stderr.Result);
                //}

                decimal min0    = t_min.Result;
                decimal max0    = t_max.Result;
                decimal avg0    = t_avg.Result;
                double  stddev0 = t_stddev.Result;
                double  stderr0 = t_stderr.Result;

                //
                // Output:
                //
                // NOTE: we build a single output string and then write to the console in one op.
                // Otherwise, if we output one value at a time, our output might get intermixed
                // with the output from another, parallel task.  Note that Console class is thread-
                // safe, so this works as long as we make only a single call for our output.
                //
                string output = string.Format("\n** {0} **", symbol);
                output = string.Format("{0}\n   Data source:  '{1}'", output, data.DataSource);
                output = string.Format("{0}\n   Data points:   {1:#,##0}", output, N);
                output = string.Format("{0}\n   Min price:    {1:C}", output, min0);
                output = string.Format("{0}\n   Max price:    {1:C}", output, max0);
                output = string.Format("{0}\n   Avg price:    {1:C}", output, avg0);
                output = string.Format("{0}\n   Std dev/err:   {1:0.000} / {2:0.000}", output, stddev0, stderr0);

                Console.WriteLine(output);
            }
            catch (AggregateException ae)
            {
                //lock (Console.Out)
                //{
                //    Console.WriteLine();
                //    ae = ae.Flatten();
                //    foreach (var ex in ae.InnerExceptions)
                //    {
                //        Console.WriteLine("Tasking Error: {0}", ex.Message);
                //    }
                //}
                string output = string.Format("\n** {0} **", symbol);

                ae = ae.Flatten();          // could have a tree of exceptions, so flatten first:
                foreach (Exception ex in ae.InnerExceptions)
                {
                    output = string.Format("{0}\nError: {1}", output, ex.Message);
                }

                Console.WriteLine(output);
            }
            catch (Exception ex)
            {
                //lock (Console.Out)
                //{
                //    Console.WriteLine();
                //    Console.WriteLine("** {0} **", symbol);
                //    Console.WriteLine("Error: {0}", ex.Message);
                //}
                string output = string.Format("\n** {0} **\nError: {1}", symbol, ex.Message);
                Console.WriteLine(output);
            }
        }
Beispiel #6
0
        /// <summary>
        /// Tries to download historial data from 3 different web sites, and takes the data
        /// from the first site that responds.  Sites used:  nasdaq, yahoo, and msn (although
        /// msn only provides a year of weekly data, so others are preferred).
        ///
        /// NOTE: we use the async web methods BeginGetResponse and EndGetResponse to access
        /// the web sites asynchronously, with a Task-based facade on top.  This has the advantages
        /// that (1) worker thread is not dedicated to request (i.e. different threads can
        /// initiate vs. handle callback), and (2) easier to cancel outstanding requests.
        /// </summary>
        /// <param name="symbol"></param>
        /// <param name="numYearsOfHistory"></param>
        /// <returns></returns>
        private static StockData GetDataFromInternet(string symbol, int numYearsOfHistory)
        {
            IAsyncResult[] iars    = new IAsyncResult[3];
            WaitHandle[]   handles = new WaitHandle[3];

            //
            // initiate web requests:
            //
            Task <StockData> t_yahoo = Task.Factory.StartNew(() =>
            {
                StockData yahoo = GetDataFromYahoo(symbol, numYearsOfHistory);
                return(yahoo);
            });
            Task <StockData> t_nasdaq = Task.Factory.StartNew(() =>
            {
                StockData nasdaq = GetDataFromNasdaq(symbol, numYearsOfHistory);
                return(nasdaq);
            });
            Task <StockData> t_msn = Task.Factory.StartNew(() =>
            {
                StockData msn = GetDataFromMsn(symbol, numYearsOfHistory);
                return(msn);
            });

            List <Task <StockData> > tasks = new List <Task <StockData> >();

            tasks.Add(t_yahoo);
            tasks.Add(t_nasdaq);
            tasks.Add(t_msn);
            //Task<StockData>[] tasks = {t_yahoo, t_nasdaq, t_msn};

            //WaitOneByOne pattern: first one that returns without exception

            StockData result = null;

            while (tasks.Count > 0)
            {
                int timeout = 15 * 1000;         //15 secs;
                int winner  = Task.WaitAny(tasks.ToArray(), timeout);
                if (winner < 0)
                {
                    break;                     // timeout!
                }
                Task <StockData> finished = tasks[winner];
                if (finished.Exception == null)
                {
                    result = finished.Result;
                    tasks.RemoveAt(winner);
                    break;
                }
                tasks.RemoveAt(winner);
                //tasks = tasks.Where(t => t != finished).ToArray();
            }
            //
            // did we succeed or fail?  Either way, first cancel any unfinished requests,
            // and then return result or throw exception...
            //
            foreach (Task t in tasks)          // cancel outstanding requests:
            {
                (t.AsyncState as RequestState)?.Request.Abort();
            }

            if (result != null)          // success!
            {
                return(result);
            }
            else
            {
                throw new ApplicationException("all web sites failed");
            }

            // if we get here, all tasks failed:
            // throw new ApplicationException("all web sites timed out");

            //
            // wait for first to finish:
            //
            //for (int i = 0; i < iars.Length; i++)
            //	handles[i] = (iars[i].AsyncState as RequestState).Done;

            //int index = WaitHandle.WaitAny(handles, 15 * 1000 /*15 secs*/);
            //int index = Task.WaitAny(new Task[] {t_yahoo, t_nasdaq, t_msn});

            ////
            //// did *all* the requests timeout?
            ////
            //if (index == WaitHandle.WaitTimeout)  // if so, cancel and throw exception:
            //{
            //	foreach (IAsyncResult iar in iars)
            //		(iar.AsyncState as RequestState).Request.Abort();

            //	throw new ApplicationException("all web sites timed out");
            //}

            ////
            //// Otherwise we have a winning request, cancel the others:
            ////
            //IAsyncResult winner = iars[index];

            //foreach (IAsyncResult iar in iars)  // cancel others:
            //	if (iar != winner)
            //		(iar.AsyncState as RequestState).Request.Abort();

            ////
            //// And return the winner's result:
            ////
            //RequestState state = winner.AsyncState as RequestState;

            //if (state.Exception == null)  // success!
            //	return state.Result;
            //else
            //	throw state.Exception;
        }
Beispiel #7
0
        /// <summary>
        /// Downloads and processes historical data for given stock symbol.
        /// </summary>
        /// <param name="symbol">stock symbol, e.g. "msft"</param>
        /// <param name="numYearsOfHistory">years of history > 0, e.g. 10</param>
        private static void ProcessStockSymbol(string symbol, int numYearsOfHistory)
        {
            try
            {
                StockData data = DownloadData.GetHistoricalData(symbol, numYearsOfHistory);

                int N = data.Prices.Count;


                double stddev, stderr;
                stddev = stderr = 0.0;


                Task <decimal> t_min = Task.Factory.StartNew(() =>
                {
                    decimal min = data.Prices.Min();
                    return(min);
                }
                                                             );
                Task <decimal> t_max = Task.Factory.StartNew(() =>
                {
                    decimal max = data.Prices.Max();
                    return(max);
                }
                                                             );

                Task <decimal> t_avg = Task.Factory.StartNew(() =>
                {
                    decimal avg = data.Prices.Average();
                    return(avg);
                }
                                                             );

                // Standard deviation:
                Task <double> t_stddev = Task.Factory.StartNew(() =>
                {
                    double sum    = 0.0;
                    decimal l_avg = data.Prices.Average();

                    foreach (decimal value in data.Prices)
                    {
                        sum += Math.Pow(Convert.ToDouble(value - l_avg), 2.0);
                    }
                    stddev = Math.Sqrt(sum / N);
                    return(stddev);
                }
                                                               );

                // Standard error:
                Task <double> t_stderr = Task.Factory.StartNew(() =>
                {
                    stderr = t_stddev.Result / Math.Sqrt(N);
                    return(stderr);
                }
                                                               );
                //
                // Output:
                //
                Console.WriteLine();
                Console.WriteLine("** {0} **", symbol);
                Console.WriteLine("   Data source:  '{0}'", data.DataSource);
                Console.WriteLine("   Data points:   {0:#,##0}", N);
                t_min.Wait();
                Console.WriteLine("   Min price:    {0:C}", t_min.Result);
                t_max.Wait();
                Console.WriteLine("   Max price:    {0:C}", t_max.Result);
                Console.WriteLine("   Avg price:    {0:C}", t_avg.Result);
                Console.WriteLine("   Std dev/err:   {0:0.000} / {1:0.000}", t_stddev.Result, t_stderr.Result);
            }
            catch (Exception ex)
            {
                Console.WriteLine();
                Console.WriteLine("** {0} **", symbol);
                Console.WriteLine("Error: {0}", ex.Message);
            }
        }
        /// <summary>
        /// Downloads and processes historical data for given stock symbol.
        /// </summary>
        /// <param name="symbol">stock symbol, e.g. "msft"</param>
        /// <param name="numYearsOfHistory">years of history > 0, e.g. 10</param>
        private static void ProcessStockSymbol(string symbol, int numYearsOfHistory)
        {
            try
            {
                //Create .Net exception
                //Task t_error = Task.Factory.StartNew(() =>
                //{
                //    int i = 0;
                //    int j = 1000 / i;
                //});

                StockData data = DownloadData.GetHistoricalData(symbol, numYearsOfHistory);

                int N = data.Prices.Count;

                //decimal min = 0, max = 0, avg = 0;

                //Create parallel tasks
                Task <decimal> t_Min = Task.Factory.StartNew(() => {
                    return(data.Prices.Min());
                });

                //decimal min = t_Min.Result;

                Task <decimal> t_Max = Task.Factory.StartNew(() => {
                    return(data.Prices.Max());
                });

                Task <decimal> t_Avg = Task.Factory.StartNew(() => {
                    return(data.Prices.Average());
                });

                // Standard deviation:
                //double sum = 0.0, stddev = 0.0, stderr = 0.0;

                Task <double> t_stddev = Task.Factory.StartNew(() => {
                    //Use local calculated average value instead of waiting for the global value
                    decimal local_avg = data.Prices.Average();
                    double sum        = 0;

                    foreach (decimal value in data.Prices)
                    {
                        sum += Math.Pow(Convert.ToDouble(value - local_avg), 2.0);
                    }

                    return(Math.Sqrt(sum / N));
                });

                // double stddev = t_stddev.Result;

                // Standard error:
                //Task<double> t_stderr = Task.Factory.StartNew(() => {
                Task <double> t_stderr = t_stddev.ContinueWith((t) => {
                    //t_stddev.Wait(); //Wait until task is finished
                    return(t.Result / Math.Sqrt(N));
                });

                //Array of tasks
                Task[] tasks = { t_Min, t_Max, t_Avg, t_stddev, t_stderr };

                //Wait for completion of all tasks
                Task.WaitAll(tasks);

                //
                // Output:
                //
                Console.WriteLine();
                Console.WriteLine("** {0} **", symbol);
                Console.WriteLine("   Data source:  '{0}'", data.DataSource);
                Console.WriteLine("   Data points:   {0:#,##0}", N);

                //t_Min.Wait(); //Wait until task is finished
                Console.WriteLine("   Min price:    {0:C}", t_Min.Result);

                //t_Max.Wait(); //Wait until task is finished
                Console.WriteLine("   Max price:    {0:C}", t_Max.Result);

                //t_Avg.Wait(); //Wait until task is finished
                Console.WriteLine("   Avg price:    {0:C}", t_Avg.Result);

                //t_stderr.Wait(); //Wait until task is finished
                Console.WriteLine("   Std dev/err:   {0:0.000} / {1:0.000}", t_stddev.Result, t_stderr.Result);
            }
            catch (AggregateException ae)
            {
                Console.WriteLine();
                //Console.WriteLine("Tasking Error: {0}", ae.InnerException.Message);

                //Flatten all exceptions since there could be many of them
                ae = ae.Flatten();

                foreach (var err in ae.InnerExceptions)
                {
                    Console.WriteLine("Tasking Error: {0}", err.Message);
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine();
                Console.WriteLine("** {0} **", symbol);
                Console.WriteLine("Error: {0}", ex.Message);
            }
        }