1 / 53

STAT682 Final Project Group 2

STAT682 Final Project Group 2. Iliya Atanasov Matthew Ginley Aaron Mielke Lisa Stryjewski John Varghese. The Basics. Hold 50 stocks for 1 year Rebalance every year according to fundamentals. Reproducing O’Shaughnessy. Assisted by ClariFI ( backtesting software) Sales / Price

nessa
Download Presentation

STAT682 Final Project Group 2

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. STAT682 Final ProjectGroup 2 IliyaAtanasov Matthew Ginley Aaron Mielke Lisa Stryjewski John Varghese

  2. The Basics • Hold 50 stocks for 1 year • Rebalance every year according to fundamentals

  3. Reproducing O’Shaughnessy • Assisted by ClariFI (backtesting software) • Sales / Price • Earnings Per Share / Price • Book / Price • Dividends Per Share / Price

  4. Our Approach • Created our own backtesting code • Started with Sales / Price • Exhaustive coverage of all Compustat Variables • Reviewed high coverage and high correlation ratios • Selected an additional ratio to complement Sales / Price

  5. Using ClariFI

  6. ClariFI

  7. ClariFI

  8. Results from ClariFI

  9. Sales to Price

  10. Sales to Price

  11. Sales to Price

  12. EPS to Price

  13. EPS to Price

  14. EPS to Price

  15. Book to Price

  16. Book to Price

  17. Book to Price

  18. Dividend Yield

  19. Dividend Yield

  20. Dividend Yield

  21. Writing our Own Simulator C# Source Code

  22. 1. Variables varpriceIndex = Enumerable.Range(0, headers.Length).First(i => headers[i] =="prcc_c"); vardividendIndex = Enumerable.Range(0, headers.Length).First(i => headers[i] =="dvpsx_c"); varyearIndex = Enumerable.Range(0, headers.Length).First(i => headers[i] == "fyear"); varsharesIndex = Enumerable.Range(0, headers.Length).First(i => headers[i] =="CSHO"); varepsIndex = Enumerable.Range(0, headers.Length).First(i => headers[i] == "EPSPX"); varidIndex = Enumerable.Range(0, headers.Length).First(i => headers[i] == "gvkey"); varajexIndex = Enumerable.Range(0, headers.Length).First(i => headers[i] =="adjex_c");

  23. 2. Market Capitalization varmarketCapMinimums = new int[Years]; yearToStocks= Enumerable.Range(0, Years).Select(i => new Dictionary<int, Stock>()).ToArray(); for (var i = 0; i < marketCapMinimums.Length; i++) { var year = i + MinYear; if (year < 1955) marketCapMinimums[i] = 27; else if (year < 1959) marketCapMinimums[i] = 27; else if (year < 1964) marketCapMinimums[i] = 28; else if (year < 1969) marketCapMinimums[i] = 31; else if (year < 1974) marketCapMinimums[i] = 34; else if (year < 1979) marketCapMinimums[i] = 44; else if (year < 1984) marketCapMinimums[i] = 64; else if (year < 1989) marketCapMinimums[i] = 97; else if (year < 1994) marketCapMinimums[i] = 117; else if (year < 1996) marketCapMinimums[i] = 150; elsemarketCapMinimums[i] = 185; }

  24. 3.A Reading Data while ((line = reader.ReadLine()) != null) { if (++count%10000 == 0) Console.WriteLine(count + ": " + (double) reader.BaseStream.Position/(double) reader.BaseStream.Length); var parts = line.Split(','); double price, shares, dividend, eps, ajex; int year; if (double.TryParse(parts[priceIndex], out price) == false || price == 0.0) continue; if (double.TryParse(parts[sharesIndex], out shares) == false) continue; if (double.TryParse(parts[epsIndex], out eps) == false) continue; if (int.TryParse(parts[yearIndex], out year) == false) continue; varmarketCap = price*shares; yearToMarketCaps[year - MinYear].Add(marketCap); varmarketCapMinimum = marketCapMinimums[year - MinYear]; if (marketCap < marketCapMinimum) continue;

  25. 3.B Reading Data double.TryParse(parts[ajexIndex], out ajex); double.TryParse(parts[dividendIndex], out dividend); var id = int.Parse(parts[idIndex]); if (ajex <= 0.0) ajex = 1.0; var values = Enumerable.Range(0, parts.Length).Select(                                          i =>                                          {                                                 double value;                                                 if (double.TryParse(parts[i], out value) == false) value =double.NaN;                                                 return value;                                          }).ToArray(); yearToStocks[year - MinYear].Add(id, new Stock(id, price, shares, dividend, ajex, values)); yearToMeanMarketCap= yearToMarketCaps.Select( marketCaps=> marketCaps.Count == 0 ? 0.0 : marketCaps.Average() ).ToArray(); }

  26. 4. Calculating Returns public void CalculateReturns(Stock nextYears) { if (nextYears == null) return; Return = Ajex * (nextYears.Price + nextYears.Dividend) / Price / nextYears.Ajex - 1.0; }

  27. 5.A Ranking Stocks Func<Func<Stock, double>, List<RanksAndStock>> rankStocks = getTestValue =>                            { varrankAndStock = new List<RanksAndStock>(count);                                   for (var year = 0; year < Years - 1; year++)                                   { vartestSortedStockList = yearToStocks[year].Values.ToArray(); varreturnSortedIndexes = Enumerable.Range(0, testSortedStockList.Length).ToArray(); Array.Sort(testSortedStockList, (x, y) => getTestValue(x).CompareTo(getTestValue(y))); Array.Sort(testSortedStockList.Select(s => s.Return.Value).ToArray(), returnSortedIndexes);

  28. 5.B Ranking Stocks varreturnRanks = GenerateRanks(testSortedStockList.Length, i => testSortedStockList[returnSortedIndexes[i]], stock => stock.Return.Value); vartestRanks = GenerateRanks(testSortedStockList.Length, i => testSortedStockList[i], getTestValue);                                          for (varreturnSortedIndex = 0; returnSortedIndex < returnSortedIndexes.Length; returnSortedIndex++)                                          { vartestSortedIndex = returnSortedIndexes[returnSortedIndex]; var stock = testSortedStockList[testSortedIndex];                                                 if (double.IsNaN(getTestValue(stock))) continue; rankAndStock.Add(new RanksAndStock(testRanks[testSortedIndex], returnRanks[returnSortedIndex], stock)); }                                   }                                    return rankAndStock;                            };

  29. 6. Pearson private static double CalculatePearson(IEnumerable<RanksAndStock> ranksAndStocks) { var n = ranksAndStocks.Count(); varsumReturn = ranksAndStocks.Sum(ranksAndStock => ranksAndStock.ReturnRank); varsumReturnSquared = ranksAndStocks.Sum( ranksAndStock=> ranksAndStock.ReturnRank*ranksAndStock.ReturnRank); varreturnDifferences = ((n*sumReturnSquared) - (sumReturn*sumReturn)); varsumTest = ranksAndStocks.Sum(ranksAndStock => ranksAndStock.TestRank); varsumTestSquared = ranksAndStocks.Sum( ranksAndStock=> ranksAndStock.TestRank*ranksAndStock.TestRank); varsumTestReturn = ranksAndStocks.Sum( ranksAndStock=> ranksAndStock.TestRank*ranksAndStock.ReturnRank); vardenom = Math.Sqrt(returnDifferences*((n*sumTestSquared) - (sumTest*sumTest))); varpearson = (n*sumTestReturn - (sumReturn*sumTest))/denom;                      return pearson; }

  30. 7. Single Values using (var writer = new StreamWriter("singles.csv")) { writer.WriteLine("column,r,%"); Parallel.For( 0, headers.Length, //new ParallelOptions{ MaxDegreeOfParallelism = 1}, header => { Func<Stock, double> getTestValue = stock => stock.Values[header]; varrankAndStock = rankStocks(getTestValue); varpearson = CalculatePearson(rankAndStock); var temp = header + ":" + headers[header] + "," + pearson + "," + ((double) rankAndStock.Count/count); Console.WriteLine(temp); lock (writer) writer.WriteLine(temp); if (double.IsNaN(pearson) == false) lock (validColumns) validColumns.Add(header); }); }

  31. 8.A Ratios using (var writer = new StreamWriter("ratios.csv")) { writer.WriteLine("numerator,denominator,r,%"); Parallel.For( 0, validColumns.Count, //new ParallelOptions{ MaxDegreeOfParallelism = 1}, numeratorIndex => Parallel.For( 0, validColumns.Count, //new ParallelOptions{ MaxDegreeOfParallelism = 1}, denominatorIndex => { try { var numerator = validColumns[numeratorIndex]; var denominator = validColumns[denominatorIndex]; if (numerator == denominator) return;

  32. 8.B Ratios if (System.Threading.Interlocked.Increment(ref progress)%1000 == 0) Console.WriteLine("******* " + progress + "/" + total + "=" + ((double) progress/total) + " *******"); Func<Stock, double> getTestValue = stock => stock.Values[numerator]/stock.Values[denominator]; varrankAndStock = rankStocks(getTestValue); varpearson = CalculatePearson(rankAndStock); vartemp = numerator + ":" + headers[numerator] + "," + denominator + ":" + headers[denominator] + "," + pearson + "," + ((double) rankAndStock.Count/count); Console.WriteLine(temp); lock (writer) writer.WriteLine(temp); } catch (Exception e) { try { using (var errors = new StreamWriter("errors.txt", true)) errors.WriteLine(e.ToString()); } catch {} } })); }

  33. 9.A Multipliers using (var writer = new StreamWriter("multipliers.csv")) { writer.WriteLine("first,second,r,%"); Parallel.For( 0, validColumns.Count, //new ParallelOptions{ MaxDegreeOfParallelism = 1}, firstIndex => Parallel.For( 0, validColumns.Count, //new ParallelOptions{ MaxDegreeOfParallelism = 1}, secondIndex => { try { var first = validColumns[firstIndex]; var second = validColumns[secondIndex]; if (System.Threading.Interlocked.Increment(ref progress)%1000 == 0)Console.WriteLine("******* " + progress + "/" + total + "=” + ((double) progress/total) + " *******");

  34. 9.B Multipliers Func<Stock, double> getTestValue = stock => stock.Values[first]*stock.Values[second]; varrankAndStock = rankStocks(getTestValue); varpearson = CalculatePearson(rankAndStock); vartemp = first + ":" + headers[first] + "," + second + ":" + headers[second] + "," + pearson+ "," + ((double) rankAndStock.Count/count); Console.WriteLine(temp); lock (writer) writer.WriteLine(temp); } catch (Exception e) { try { using (var errors = new StreamWriter("errors.txt", true)) errors.WriteLine(e.ToString()); } catch {} } ]})); }

  35. 10. Strategies varnameToTest = new Dictionary<string, Func<Stock, double>> {                      { "EPS_OVER_Price", stock => -stock.Values[258] / stock.Values[944]},                      { "-EPS_OVER_Price", stock => stock.Values[258] / stock.Values[944]},                      { "EBITDA_over_EV", stock => -stock.Values[250] / (stock.Values[944] * stock.Values[149] + stock.Values[194] + stock.Values[153] - stock.Values[109])},                      { "Sales_OVER_Price", stock => -stock.Values[705] / stock.Values[944]},                      { "Sales_OVER_Price_PLUS_IBCOM_OVER_NI", stock => -stock.Values[705] / stock.Values[944] + -stock.Values[352] / stock.Values[513]},                      { "Dividends_OVER_Price", stock => -stock.Values[943] / stock.Values[944]},                      { "IBCOM_OVER_NI", stock => -stock.Values[352] / stock.Values[513]} };

  36. 11.A Strategy Simulation for (var large = 0; large < 2; large++) { var strategies = nameToTest.ToArray(); for (vari = 0; i < nameToTest.Count; i++) { Func<Stock, double> strategy; string name; if(i < nameToTest.Count) { strategy = strategies[i].Value; name = strategies[i].Key; } else { name = "Combo”; strategy = stock => { return strategies.Select(s => s.Value(stock)).Where(d => double.IsNaN(d) == false).Average(); }; }

  37. 11.B Strategy Simulation varlargeName = large == 0 ? "_large" : string.Empty; using (var writer = new StreamWriter("returns_" + name + largeName + ".csv")) { writer.WriteLine("Year,Average Return"); Parallel.For( 1, Years - 1, new ParallelOptions {MaxDegreeOfParallelism = 1}, year => { vartestSortedStockList = yearToStocks[year - 1].Values.ToArray(); if (large == 0) testSortedStockList= testSortedStockList.Where(s => s.Price * s.Shares >= yearToMeanMarketCap[year]).ToArray(); Array.Sort(testSortedStockList, (x, y) => strategy(x).CompareTo(strategy(y)));

  38. 11.C Strategy Simulation varreturns = new List<double>(); for (var index = 0; index < testSortedStockList.Length && returns.Count < 50; index++) { varlastYearsStock = testSortedStockList[index]; if (double.IsNaN(strategy(lastYearsStock))) continue; Stock thisYearsStock; if (yearToStocks[year].TryGetValue(lastYearsStock.ID, out thisYearsStock) == false) continue; returns.Add(thisYearsStock.Return.Value); } varline = (year + MinYear) + "," + (returns.Count() == 0 ? 0.0 : returns.Average()) + "," + string.Join(",", returns.Select(r => r.ToString())); Console.WriteLine(line); lock (writer) writer.WriteLine(line); }); } } } }

  39. 12.A Unused CRSP Data using (var reader = new StreamReader(@"d:\data\stat\just price2.csv")) { string line; varpriceHeaders = reader.ReadLine().Split(','); varidIndex = Enumerable.Range(0, priceHeaders.Length).First(i => priceHeaders[i] == "gvkey"); vardateIndex = Enumerable.Range(0, priceHeaders.Length).First(i => priceHeaders[i] == "datadate"); varpriceIndex = Enumerable.Range(0, priceHeaders.Length).First(i => priceHeaders[i] == "PRCCM"); count = 0;

  40. 12.B Unused CRSP Data while ((line = reader.ReadLine()) != null) { if (++count%10000 == 0) Console.WriteLine(count + ": " + (double) reader.BaseStream.Position/(double) reader.BaseStream.Length); var parts = line.Split(','); double price; var date = DateTime.ParseExact(parts[dateIndex], "yyyyMMdd”, CultureInfo.InvariantCulture, DateTimeStyles.None); if (date.Month != 12) continue; var id = int.Parse(parts[idIndex]); if (double.TryParse(parts[priceIndex], out price) == false || price == 0.0) continue; yearToStockToPrice[date.Year - MinYear][id] = price; } }

  41. Our Results

  42. Sales to Price (All Stocks)

  43. Sales to Price (All Stocks)

  44. Sales to Price (Large Stocks)

  45. Sales to Price (Large Stocks)

  46. IBCOM to NI (All Stocks)

  47. IBCOM to NI (All Stocks)

  48. IBCOM to NI (Large Stocks)

  49. IBCOM to NI (Large Stocks)

  50. S/P + IBCOM/NI (All Stocks)

More Related