Skip to content

Instantly share code, notes, and snippets.

@lequant40
Last active May 28, 2021 09:53
Show Gist options
  • Save lequant40/4779fc816adabd30518a42d2e2a1b140 to your computer and use it in GitHub Desktop.
Save lequant40/4779fc816adabd30518a42d2e2a1b140 to your computer and use it in GitHub Desktop.
Illustration of random portfolios analysis of the Global Equities Momentum (GEM) TAA strategy
// Dependencies
var fs = require('fs');
const axios = require('axios');
const { mean, std } = require('mathjs');
// Definition of the risk free returns, and of the indexes prices
// In sample period
var nbPeriods = 12 * 24; // months of returns data, until 30/12/2012
var rf = [0.67,0.70,0.71,0.68,0.69,0.64,0.63,0.63,0.64,0.63,0.61,0.61,0.62,0.63,0.63,0.63,0.62,0.62,0.60,0.60,0.58,0.57,0.57,0.52,0.50,0.49,0.47,0.45,0.45,0.45,0.45,0.43,0.42,0.39,0.36,0.32,0.31,0.32,0.33,0.30,0.30,0.29,0.26,0.26,0.22,0.24,0.27,0.25,0.24,0.24,0.24,0.24,0.25,0.25,0.25,0.25,0.24,0.25,0.26,0.25,0.24,0.28,0.28,0.32,0.34,0.34,0.35,0.37,0.38,0.41,0.45,0.45,0.47,0.47,0.46,0.46,0.46,0.44,0.44,0.43,0.43,0.43,0.43,0.40,0.40,0.40,0.41,0.41,0.41,0.41,0.42,0.42,0.40,0.41,0.41,0.41,0.41,0.41,0.42,0.42,0.39,0.41,0.42,0.41,0.41,0.41,0.41,0.42,0.41,0.42,0.41,0.40,0.40,0.41,0.40,0.39,0.35,0.34,0.36,0.36,0.36,0.37,0.36,0.36,0.37,0.38,0.38,0.40,0.38,0.40,0.42,0.42,0.45,0.46,0.46,0.46,0.45,0.46,0.49,0.50,0.49,0.50,0.49,0.47,0.39,0.39,0.34,0.31,0.29,0.29,0.28,0.27,0.19,0.17,0.14,0.14,0.14,0.14,0.14,0.14,0.14,0.14,0.14,0.14,0.13,0.12,0.10,0.10,0.10,0.10,0.09,0.09,0.09,0.07,0.08,0.08,0.08,0.08,0.08,0.08,0.07,0.08,0.08,0.08,0.09,0.11,0.12,0.13,0.14,0.15,0.18,0.18,0.20,0.22,0.22,0.23,0.24,0.25,0.27,0.28,0.28,0.31,0.32,0.33,0.36,0.37,0.37,0.38,0.38,0.40,0.40,0.40,0.39,0.40,0.40,0.40,0.41,0.41,0.40,0.39,0.37,0.38,0.39,0.33,0.30,0.31,0.25,0.26,0.15,0.15,0.11,0.11,0.15,0.14,0.14,0.14,0.07,0.04,0.00,0.01,0.02,0.02,0.02,0.01,0.01,0.01,0.01,0.01,0.01,0.00,0.00,0.00,0.01,0.01,0.01,0.01,0.01,0.01,0.01,0.01,0.01,0.01,0.01,0.01,0.01,0.01,0.01,0.00,0.00,0.00,0.01,0.00,0.00,0.00,0.00,0.00,0.00,0.01,0.01,0.01,0.00,0.01,0.01,0.01,0.01,0.01,0.01,0.00];
var sp500 = [623.3995,669.0499,652.3768,667.5958,702.2576,730.6697,726.5255,792.1243,807.6097,804.3327,785.6563,801.6791,820.9313,765.817,775.6812,796.2353,776.371,852.0712,846.3231,843.6089,767.3546,730.0109,726.9019,773.8895,795.4476,830.0895,889.4537,910.9924,913.1483,952.5422,908.9025,951.2658,973.8032,957.5067,970.3799,931.2808,1037.787,1018.448,1031.638,1011.574,1041.275,1046.379,1030.812,1072.923,1050.965,1063.314,1066.988,1103.319,1116.86,1126.197,1141.547,1165.632,1137.458,1167.885,1171.306,1166.594,1210.859,1201.572,1226.428,1214.738,1229.425,1271.222,1236.718,1182.801,1197.969,1217.629,1187.782,1226.786,1277.083,1245.854,1273.843,1227.452,1245.659,1277.963,1327.767,1366.946,1407.198,1463.44,1497.432,1547.091,1550.981,1616.436,1610.658,1681.363,1713.75,1772.079,1788.509,1805.724,1832.347,1879.602,1886.772,1803.415,1841.456,1945.102,1998.75,2149.829,2107.23,2238.881,2256.428,2163.715,2292.885,2432.485,2541.465,2743.683,2589.977,2731.821,2640.585,2762.825,2810.273,2841.357,3046.29,3202.286,3234.503,3178.909,3308.033,3272.807,2799.633,2978.98,3221.295,3416.531,3613.409,3764.508,3647.511,3793.443,3940.345,3847.3,4060.816,3934.018,3914.555,3807.242,4048.167,4130.458,4373.726,4153.979,4075.346,4474.033,4339.428,4250.396,4355.181,4287.092,4553.382,4312.994,4294.759,3956.163,3975.525,4116.573,3741.217,3504.21,3776.524,3801.825,3709.294,3672.779,3442.857,3164.838,3225.188,3472.58,3503.001,3451.881,3385.311,3512.63,3299.666,3275.357,3042.054,2804.913,2823.329,2516.491,2737.982,2899.137,2728.82,2657.33443,2617.464,2642.878,2860.572,3011.289,3049.702,3103.473,3163.997,3130.397,3307.48331,3336.583,3511.569,3576.024,3625.729,3571.03,3514.972,3563.206,3632.492,3512.269,3526.476,3564.67,3619.127,3765.563,3893.7,3798.792,3878.734,3810.049,3737.789,3856.72,3862.195,4005.824,3969.275,4001.423,3934.717,4083.536,4084.957,4193.118,4204.495,4256.831,4313.991,4189.828,4195.508,4221.388,4321.828,4433.201,4577.662,4664.71107,4730.146,4801.681,4707.766,4760.422,4971.287,5144.76,5059.289,4902.426,4975.914,5162.007,5244.119,5024.87981,4990.019,4690.70958,4538.3283,4518.73203,4738.80845,4800.18829,4395.51533,4358.56592,4421.61116,4027.61324,3351.18396,3110.72125,3143.82018,2878.8388,2572.30647,2797.62814,3065.38748,3236.84362,3243.26432,3488.57614,3614.52854,3749.40514,3679.75218,3900.47657,3975.81619,3832.7913,3951.52025,4189.97442,4256.12449,3916.26963,3711.25985,3971.28199,3792.00161,4130.41771,4287.57661,4288.1264,4574.70788,4683.13573,4843.5757,4845.50234,4989.00335,4932.53007,4850.30906,4751.67978,4493.55933,4177.66739,4634.25768,4624.01613,4671.31563,4880.66,5091.71,5259.28,5226.26,4912.16,5114.55,5185.59,5302.38,5439.41,5338.97,5369.94,5418.89];
var acwiexus = [127.897,130.435,131.020,128.777,130.407,123.755,121.435,136.405,130.740,136.774,131.766,138.101,143.286,137.913,128.751,115.699,114.718,127.413,126.361,128.387,116.154,100.671,115.122,108.723,110.708,114.168,126.430,119.472,120.770,122.485,113.966,119.442,117.391,123.364,125.521,119.930,126.156,124.398,120.578,113.286,113.658,120.559,114.741,112.300,118.289,115.862,110.774,111.387,112.317,112.304,115.741,125.271,136.336,139.371,137.703,142.280,149.916,146.834,152.145,140.558,151.521,163.982,162.742,155.288,160.556,160.610,161.749,164.379,169.910,165.704,170.158,161.950,161.571,154.243,153.399,162.066,168.388,167.644,165.325,174.713,168.651,171.533,166.950,170.871,177.627,180.067,180.074,183.426,188.991,186.153,187.097,180.877,181.938,186.456,184.589,191.710,189.490,186.009,189.420,189.023,190.617,202.391,213.558,217.882,200.742,211.595,193.580,191.161,193.361,199.145,212.433,219.773,221.347,217.333,216.516,218.574,187.750,183.784,203.035,213.946,221.317,221.080,216.130,226.565,237.897,226.723,237.141,242.703,243.545,245.192,254.322,264.491,289.716,273.995,281.396,291.986,275.689,268.637,280.075,269.018,272.345,257.238,249.062,237.888,246.012,249.702,229.933,213.680,228.213,221.911,213.400,208.652,203.470,181.884,186.980,195.532,198.051,189.569,190.934,201.306,202.614,204.821,195.977,176.878,176.889,158.144,166.628,174.641,168.999,163.066,159.762,156.663,171.759,182.701,187.758,192.761,198.505,204.063,217.291,222.029,238.980,242.818,248.992,250.524,242.738,243.506,248.784,241.534,243.468,251.296,260.036,278.085,290.025,285.030,299.089,290.976,283.800,285.578,290.953,301.688,309.409,325.369,313.524,324.065,339.657,363.339,362.290,372.813,392.036,373.962,373.589,377.411,388.108,388.360,404.174,418.848,431.901,433.514,436.163,448.452,469.248,482.110,486.216,484.830,477.386,508.999,537.411,513.263,505.844,456.899,470.140,460.002,488.311,496.773,456.055,439.745,419.293,356.439,277.992,262.025,277.004,252.589,229.094,247.589,281.638,320.189,316.757,347.820,360.762,379.369,374.703,385.527,393.734,374.538,374.591,400.267,397.014,355.668,351.198,383.009,372.564,409.715,423.712,407.453,439.420,443.820,455.606,454.742,477.304,464.083,457.500,451.402,412.807,367.011,405.712,385.099,380.862,406.785,429.752,424.057,417.750,370.743,392.775,398.444,406.864,422.207,423.900,432.033,447.090];
var agg = [346.81,351.8,349.25,350.76,358.1,367.51,378.7,386.75,381.02,382.97,392.4,396.14002,397.2,392.48,393.75,394.04,390.43,401.99,408.44,414.09,408.56,411.94,417.17,426.15,432.79,438.14002,441.88,444.92,449.74,452.37,452.14002,458.41,468.33,477.82,483.14002,487.57,502.05,495.22,498.44205,495.634,499.2102,508.63065,515.62921,526.15384,531.47971,537.78497,530.65054,530.7717,539.21249,549.55322,559.16611,561.50494,565.41019,566.12698,576.38586,579.64517,589.81146,591.43094,593.63797,588.59106,591.78113,599.77118,589.35101,574.81918,570.22952,570.15073,568.88913,580.19196,580.9082,572.35922,571.84644,570.57864,574.5239,585.89441,599.82275,603.50021,611.93335,635.61322,640.27185,638.84332,646.54547,652.83978,661.32782,671.23572,680.66003,685.17505,673.26813,668.58618,664.82788,663.48157,672.39386,674.23346,673.10425,684.82593,700.00281,711.9931,705.37195,707.52862,709.28662,701.42535,711.9328,718.66138,727.19434,746.79504,740.43176,751.35474,762.25391,765.76251,773.46826,783.39697,782.80725,785.50061,789.60333,797.08978,803.85168,805.55756,818.66925,837.83563,833.41528,838.13538,840.6557,846.66034,831.87775,836.49329,839.14484,831.79176,829.13535,825.61287,825.19353,834.76928,837.84902,837.79081,833.75123,831.0236,841.07244,852.14575,849.71399,849.32393,866.99273,874.86218,887.54492,893.12402,899.02605,913.72995,930.68371,945.89653,954.13827,958.92641,954.94593,960.71446,964.33876,985.8983,997.19485,1008.8095,1029.9243,1015.72291,1009.26574,1017.43698,1027.29635,1010.21012,1029.80134,1038.54974,1047.53423,1060.16996,1078.06725,1095.53103,1090.53652,1090.24871,1112.76624,1113.71764,1129.13491,1128.26161,1137.57416,1158.78408,1156.48216,1117.60098,1125.01823,1154.79652,1144.03393,1146.76954,1158.43914,1167.76127,1180.3969,1189.24461,1158.298,1153.66096,1160.17932,1171.68056,1194.03308,1197.27043,1207.30916,1197.67942,1208.70134,1216.28535,1209.11182,1202.8963,1219.17543,1232.36524,1239.08557,1227.81498,1243.55492,1230.73515,1220.99908,1226.402,1238.05504,1238.13074,1242.23595,1230.04824,1227.82133,1226.50593,1229.10906,1245.72587,1264.79881,1275.90935,1284.35098,1299.25273,1291.70944,1291.17637,1311.08714,1311.12944,1318.20028,1308.20503,1304.33783,1315.2191,1331.34018,1341.43752,1353.48862,1377.82675,1381.69797,1404.91275,1406.85741,1411.65556,1408.70783,1398.37578,1397.25488,1396.11315,1409.35757,1390.42946,1357.60958,1401.7982,1454.10222,1441.26825,1435.82593,1455.78612,1462.75395,1473.35995,1481.73512,1505.64069,1521.22977,1537.21314,1544.80486,1564.8022,1540.33634,1563.86934,1569.70752,1567.78,1584.10312,1597.42663,1622.47682,1639.79488,1660.89162,1662.66406,1668.58055,1658.98991,1641.10069,1643.0068,1647.11813,1648.02831,1668.95132,1690.73432,1685.78182,1712.53319,1737.55445,1750.19081,1752.07489,1750.55213,1769.79278,1785.3252,1784.91797,1775.13784,1794.82235,1811.05937,1811.76984,1836.7616,1837.96393,1840.48593,1844.10607,1847.01657,1844.38656];
// Out of sample period
//var nbPeriods = 93; // months of returns data, from 01/01/2013 to 31/10/2020
//var rf = [0.01,0.01,0.01,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.01,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.01,0.01,0.01,0.02,0.03,0.02,0.02,0.02,0.02,0.03,0.02,0.02,0.04,0.04,0.04,0.04,0.05,0.06,0.08,0.08,0.09,0.08,0.09,0.09,0.10,0.10,0.11,0.12,0.13,0.15,0.15,0.16,0.16,0.17,0.18,0.19,0.19,0.19,0.20,0.19,0.20,0.20,0.19,0.17,0.17,0.16,0.15,0.12,0.13,0.13,0.12,0.13,0.09,0.01,0.01,0.01,0.01,0.01,0.01,0.01,0.01];
//var sp500 = [5699.56,5776.93,5993.59,6109.06,6251.96,6168.01,6481.86,6294.14,6491.52,6789.92,6996.83,7173.97,6925.93,7242.75,7303.63,7357.62,7530.33,7685.89,7579.90,7883.13,7772.58,7962.43,8176.57,8155.98,7911.14,8365.81,8233.50,8312.49,8419.38,8256.40,8429.38,7920.81,7724.82,8376.44,8401.35,8268.84,7858.51,7847.90,8380.29,8412.78,8563.86,8586.05,8902.60,8915.10,8916.79,8754.14,9078.34,9257.79,9433.38,9807.94,9819.38,9920.22,10059.83,10122.62,10330.76,10362.39,10576.15,10822.94,11154.88,11278.91,11924.67,11485.16,11193.29,11236.24,11506.83,11577.65,12008.50,12399.80,12470.38,11618.02,11854.78,10784.40,11648.62,12022.63,12256.26,12752.51,11942.11,12783.74,12967.48,12762.07,13000.85,13282.44,13764.58,14180.02,14174.46,13007.63,11401.02,12862.57,13475.18,13743.17,14518.08,15561.64,14970.35,14572.24];
//var acwiexus = [465.356,460.545,461.691,479.114,468.468,448.306,468.037,461.674,493.882,512.063,513.028,517.641,494.197,519.154,520.809,528.063,538.871,548.143,542.835,545.940,519.677,514.585,518.373,499.859,499.185,525.938,517.827,544.340,536.319,521.578,520.242,480.568,458.469,492.650,482.544,473.599,441.442,436.530,472.348,485.195,477.473,470.438,493.811,497.029,503.377,496.193,484.780,497.346,515.010,523.300,537.046,548.864,567.243,569.237,590.367,593.587,604.829,616.279,621.372,635.454,670.904,639.380,628.601,639.159,625.054,613.572,628.432,615.402,618.464,568.229,573.696,547.933,589.425,601.022,605.110,621.551,588.860,624.610,617.254,598.314,614.001,635.508,641.206,669.191,651.291,599.900,513.510,552.760,571.130,597.192,624.082,650.916,635.175,621.621];
//var agg = [1831.4869,1840.6713,1842.13979,1860.78446,1827.57711,1799.31218,1801.77106,1792.55603,1809.52672,1824.15524,1817.33237,1807.06176,1833.76207,1843.50773,1840.36778,1855.90279,1877.0275,1877.99718,1873.28602,1893.9676,1881.11385,1899.60057,1913.07631,1914.86554,1955.01875,1936.63691,1945.62976,1938.64861,1933.97976,1912.8924,1926.18918,1923.42311,1936.43366,1936.75521,1931.63877,1925.39644,1951.892,1965.739,1983.774,1991.389,1991.9,2027.69,2040.509,2038.176,2036.982,2021.401,1973.587,1976.371,1980.249,1993.558,1992.513,2007.889,2023.344,2021.308,2030.006,2048.214,2038.459,2039.64,2037.022,2046.371,2022.803,2003.628,2016.477,2001.48,2015.764,2013.285,2013.763,2026.721,2013.67,1997.757,2009.683,2046.603,2068.337,2067.139,2106.832,2107.371,2144.78,2171.715,2176.491,2232.888,2220.996,2227.686,2226.551,2225,2267.819,2308.636,2295.05,2335.847,2346.723,2361.505,2396.779,2377.433,2376.129,2365.519];
// Compute asynchronously the Sharpe Ratios for nbPortfolios randomly-rebalanced portfolios made of
// the three indexes SP500, ACWI ex-US and Barclays Capital US Aggregate Bond.
async function computeRandomPortfolioSharpeRatios(nbPortfolios) {
// Compute random portfolios rebalanced at each period (= monthly rebalancing)
var response;
try {
//
const url = "https://api.portfoliooptimizer.io/v1/portfolio/simulation/rebalancing/random-weight";
//
const data = {
assets: 3,
portfolios: nbPortfolios,
assetsPrices: [sp500, acwiexus, agg]
};
//
const axiosConfig = {
headers: {
'Content-Type': 'application/json',
// 'X-API-Key': '', // Optional
'Accept-Encoding': 'gzip'
}
};
//
response = await axios.post(url, data, axiosConfig);
} catch (error) {
// It would be needed to catch HTTP 429 error here
throw new Error(error);
}
// For each random portfolio...
var sharpeRatios = new Array(nbPortfolios);
for (var i = 0; i < nbPortfolios; ++i) {
// ... compute the random portfolio monthly excess return for each period
var randomPortfolioExcessReturns = new Array(nbPeriods);
for (var j = 0; j < nbPeriods; ++j) {
// Compute the portfolio return for the period
var portfolioReturn = (response.data.portfolios[i].portfolioValues[j+1] - response.data.portfolios[i].portfolioValues[j])/response.data.portfolios[i].portfolioValues[j];
// Compute the portfolio excess return for the period
randomPortfolioExcessReturns[j] = portfolioReturn - rf[j]/100;
}
// ... compute the average portfolio excess return
var portfolioAverageExcessReturn = mean(randomPortfolioExcessReturns);
// ... compute the volatility of portfolio excess returns
var portfolioVolatilityExcessReturn = std(randomPortfolioExcessReturns, 'uncorrected');
// ... compute the Sharpe ratio of the portfolio
sharpeRatios[i] = portfolioAverageExcessReturn / portfolioVolatilityExcessReturn;
}
// Return the computed Sharpe Ratios
return sharpeRatios;
}
// Will hold the Sharpe Ratios of the random portfolios
sharpeRatios = [];
// Start the asynchronous computation of the Sharpe Ratios of the random portfolios
sharpeRatiosPromises = [];
var nbBatches = 100; // Will generate 100 * 100 = 10,000 portfolios
for (var i = 0; i < nbBatches; ++i) {
sharpeRatiosPromises.push(computeRandomPortfolioSharpeRatios(100));
}
// Wait until all the Sharpe Ratios of the random portfolios have been computed
Promise.all(sharpeRatiosPromises).then(function (results) {
//
console.log("All done")
// Merge all the Sharpe Ratios
var idx = 0;
for (var i = 0; i < results.length; ++i) {
for (var j = 0; j < results[i].length; ++j) {
sharpeRatios[idx] = results[i][j] * Math.sqrt(12); // annualized
++idx;
}
}
// Save the Sharpe Ratios into a file for further processing
var file = fs.createWriteStream('/tmp/sr.txt');
file.on('error', function(err) { /* error handling */ });
sharpeRatios.forEach(function(e) { file.write(e + '\n'); });
file.end();
}).catch(error => {
console.log(error)
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment