fork download
  1. #include <iostream>
  2. #include <vector>
  3. #include <cmath>
  4. #include <algorithm>
  5. #include <iomanip>
  6. #include <tuple>
  7.  
  8. using namespace std;
  9.  
  10. using Portfolio = vector<int>; // weights in percent, size = 5
  11.  
  12. double percentile15(vector<double>& data) {
  13. sort(data.begin(), data.end());
  14. size_t index = static_cast<size_t>(floor(0.15 * data.size()));
  15. if (index >= data.size()) index = data.size() - 1;
  16. return data[index];
  17. }
  18.  
  19. double lumpSumCAGR(const vector<double>& returns) {
  20. double compound = 1.0;
  21. for (double r : returns) {
  22. compound *= (1.0 + r);
  23. }
  24. return pow(compound, 1.0 / returns.size()) - 1.0;
  25. }
  26.  
  27. double portfolioReturn(const vector<vector<double>>& assets, const Portfolio& weights, int year) {
  28. double result = 0.0;
  29. for (int i = 0; i < 5; ++i) {
  30. result += (weights[i] / 100.0) * assets[i][year];
  31. }
  32. return result;
  33. }
  34.  
  35. void generatePortfolios(vector<Portfolio>& portfolios, Portfolio current, int pos, int totalWeight, int maxAssets) {
  36. if (pos == 5) {
  37. if (totalWeight == 100) {
  38. int nonZero = count_if(current.begin(), current.end(), [](int w) { return w > 0; });
  39. if (nonZero <= maxAssets) {
  40. portfolios.push_back(current);
  41. }
  42. }
  43. return;
  44. }
  45. for (int w = 0; w <= 100 - totalWeight; w += 5) {
  46. current[pos] = w;
  47. generatePortfolios(portfolios, current, pos + 1, totalWeight + w, maxAssets);
  48. }
  49. }
  50.  
  51. int main() {
  52. const int numAssets = 5;
  53. const int maxAssets = 4;
  54. const int step = 5;
  55. const int duration = 15;
  56.  
  57. // Asset names
  58. vector<string> assetNames = {"scv60Lcg15", "scv95", "vti", "11all", "33gld"};
  59.  
  60. // Replace these with actual return data for each asset
  61. vector<vector<double>> assets = {
  62. // Asset 1
  63. {-0.04,0.14,0.15,-0.14,-0.19,0.26,0.28,0.04,0.08,0.28,0.08,-0.06,0.24,0.22,-0.01,0.26,0.14,-0.02,0.14,0.16,
  64. -0.16,0.29,0.15,0.18,-0.03,0.20,0.13,0.20,0.02,0.08,-0.04,0.04,-0.07,0.33,0.12,0.06,0.15,0.01,-0.26,0.31,
  65. 0.22,-0.03,0.15,0.19,0.08,-0.06,0.16,0.13,-0.11,0.21,0.13,0.12,-0.18,0.15,0.12},
  66.  
  67. // Asset 2
  68. {-0.03,0.13,0.06,-0.29,-0.31,0.43,0.46,0.08,0.07,0.21,0.12,0.06,0.31,0.38,0.02,0.31,0.12,-0.08,0.23,0.14,
  69. -0.22,0.37,0.24,0.19,-0.02,0.24,0.17,0.31,-0.06,0.02,0.04,0.11,-0.13,0.41,0.17,0.04,0.15,-0.09,-0.32,0.33,
  70. 0.23,-0.06,0.18,0.32,0.09,-0.06,0.23,0.09,-0.15,0.20,0.03,0.19,-0.16,0.11,0.08},
  71.  
  72. // Asset 3
  73. {-0.02,0.11,0.12,-0.25,-0.36,0.30,0.21,-0.11,-0.01,0.05,0.16,-0.11,0.19,0.19,0.01,0.28,0.15,-0.02,0.12,0.24,
  74. -0.10,0.29,0.06,0.08,-0.01,0.34,0.19,0.30,0.24,0.19,-0.13,-0.09,-0.25,0.30,0.08,0.02,0.12,0.01,-0.37,0.26,
  75. 0.16,-0.02,0.14,0.31,0.12,0.00,0.11,0.19,-0.07,0.28,0.19,0.18,-0.24,0.22,0.20},
  76.  
  77. // Asset 4
  78. {-0.02,0.12,0.14,-0.13,-0.19,0.22,0.26,0.04,0.06,0.19,0.07,-0.07,0.20,0.20,0.03,0.26,0.19,0.00,0.14,0.15,
  79. -0.16,0.24,0.10,0.20,-0.02,0.19,0.12,0.17,0.01,0.05,0.01,0.02,-0.06,0.32,0.14,0.07,0.17,-0.01,-0.25,0.25,
  80. 0.20,0.00,0.14,0.15,0.11,-0.04,0.13,0.12,-0.10,0.20,0.07,0.12,-0.19,0.10,0.08},
  81.  
  82. // Asset 5 (new)
  83. {-0.01,0.11,0.19,0.03,-0.05,0.13,0.23,0.07,0.10,0.44,0.08,-0.13,0.20,0.14,-0.04,0.19,0.16,0.02,0.06,0.08,
  84. -0.15,0.17,0.08,0.16,-0.03,0.17,0.11,0.12,0.00,0.02,-0.01,0.02,-0.02,0.30,0.11,0.07,0.19,0.03,-0.21,0.25,
  85. 0.23,0.00,0.13,0.08,0.09,-0.06,0.13,0.10,-0.08,0.20,0.10,0.11,-0.14,0.11,0.14}
  86. };
  87.  
  88. int numYears = assets[0].size();
  89. vector<Portfolio> portfolios;
  90. generatePortfolios(portfolios, Portfolio(5, 0), 0, 0, maxAssets);
  91.  
  92. vector<tuple<Portfolio, double>> portfolioResults;
  93.  
  94. for (const Portfolio& p : portfolios) {
  95. vector<double> cagrList;
  96.  
  97. for (int start = 0; start <= numYears - duration; ++start) {
  98. vector<double> subReturns;
  99. for (int i = 0; i < duration; ++i) {
  100. double portRet = portfolioReturn(assets, p, start + i);
  101. subReturns.push_back(portRet);
  102. }
  103. double cagr = lumpSumCAGR(subReturns);
  104. cagrList.push_back(cagr);
  105. }
  106.  
  107. double bottom15 = percentile15(cagrList);
  108. portfolioResults.emplace_back(p, bottom15);
  109. }
  110.  
  111. sort(portfolioResults.begin(), portfolioResults.end(),
  112. [](const auto& a, const auto& b) {
  113. return get<1>(a) > get<1>(b);
  114. });
  115.  
  116. cout << fixed << setprecision(2);
  117. for (int i = 0; i < 2 && i < portfolioResults.size(); ++i) {
  118. auto [weights, cagr] = portfolioResults[i];
  119. cout << "Portfolio " << i+1 << ":\n";
  120. for (int j = 0; j < numAssets; ++j) {
  121. if (weights[j] > 0)
  122. cout << " " << assetNames[j] << ": " << weights[j] << "%\n";
  123. }
  124. cout << " Bottom 15th Percentile CAGR: " << cagr * 100 << "%\n\n";
  125. }
  126.  
  127. return 0;
  128. }
  129.  
Success #stdin #stdout 0.15s 5292KB
stdin
Standard input is empty
stdout
Portfolio 1:
  scv60Lcg15: 90%
  scv95: 10%
  Bottom 15th Percentile CAGR: 7.21%

Portfolio 2:
  scv60Lcg15: 85%
  scv95: 5%
  33gld: 10%
  Bottom 15th Percentile CAGR: 7.20%