Navigation Menu

Skip to content

Instantly share code, notes, and snippets.

@Nicktz
Last active August 13, 2020 08:23
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Nicktz/dddbe80ac427b7a96a58c39ef6e6f0d8 to your computer and use it in GitHub Desktop.
Save Nicktz/dddbe80ac427b7a96a58c39ef6e6f0d8 to your computer and use it in GitHub Desktop.
# Copy the below into your R console and run the code to see illustration of safe return calculation.
# Motivation:
# Depending on your data structure and assumptions - you should choose how to square your return and weight dates.
# I mostly want to merge on the day returns to on the day weights.
# E.g.
# date Stock Returns weights
# 2018-04-01 XXX 0.025 0.05
# This means that weights imply what portion of the stock was held **through the day**
# If a rebalance column is used, the assumption is that the stock was bought up to a weight at COB the previous day.
# Thus your rebalance weight applies to on the day's returns for a stock.
# To achieve this, run:
rets <- tibble::tribble(
~ABG, ~BTI, ~CFR, ~EOH, ~ITU, ~NPN, ~RNI, ~SBK, ~SNV, ~WHL, ~date,
0.0249, 0.0117, -0.0057, 0.0251, -0.0116, 0.0021, 0.0205, 0.0118, -0.0141, 0.0192, "2018-07-03",
0.0196, 0.0105, 0.001, 0.0012, 0.026, -0.002, 0.0055, 0.0187, -0.0057, -0.0265, "2018-07-04",
-0.0078, -0.0211, -0.0184, -0.0176, 0.0081, -0.0056, -0.012, -0.0049, -0.0144, -0.0034, "2018-07-05",
-0.0075, 0.0056, -0.0059, -0.0368, 0.0138, 0.0147, -0.0101, -0.0257, -0.0029, -0.0056, "2018-07-06",
0.0203, 6e-04, 0.0099, 0.001, -0.0147, 0.0208, 0.0193, 0.0302, -0.0235, 0.0139, "2018-07-09",
-0.0146, -0.0055, 0.0113, 0.0284, 3e-04, -0.004, 0.0153, -0.0146, 0.0781, -0.0144, "2018-07-10",
-0.02, -0.0056, -0.0145, -0.0057, -0.0114, -0.016, -0.0134, -0.0104, -0.0529, 0.0055, "2018-07-11",
-0.0013, -0.006, -0.018, 0.0217, -0.0524, 0.0014, -0.002, -0.005, 0, 9e-04, "2018-07-12",
-0.0168, -0.0039, 0.0057, 0.0141, -0.0048, -0.0208, -0.0139, 0.0091, 0.0029, -0.0073, "2018-07-13",
-0.0188, -0.0149, -0.0108, -0.0046, 0.0096, -0.0212, 0.0071, -0.0242, 0.0205, -0.0214, "2018-07-16",
0.0123, -0.0176, 0.0078, 0.0235, 0.0045, 0.0213, -0.0144, 0.0305, 0.0201, -0.0028, "2018-07-17",
0.0108, 8e-04, 0.021, 0.0647, 0.0019, -0.002, -0.0023, 4e-04, -0.0141, -0.0071, "2018-07-18",
-0.018, 0.0105, 0.0159, 0.2156, 0.0032, 0.0068, 0.0033, -0.0042, 0.0286, 0.0053, "2018-07-19",
0.0328, 0.0372, 0.0293, -0.0098, -9e-04, 0.0179, 0.0202, 0.0261, 0.0167, 0.0051, "2018-07-20",
-0.0115, -0.0026, -0.0114, -9e-04, 6e-04, -0.0168, -0.0013, -0.0107, -0.0546, -0.0112, "2018-07-23",
0.0134, -0.0017, -0.0188, 0.0097, 3e-04, 0.0086, 0.0037, 0.0054, 0.0578, -0.018, "2018-07-24",
0.0058, -0.0071, -0.0049, 0.0061, -0.0126, -0.0321, -0.0041, -0.0165, 0.0246, -0.001, "2018-07-25",
0.0199, 0.0587, 0.0106, -0.0202, -0.0909, 0.0016, 0.0346, 0.0145, 0.0213, 0.0012, "2018-07-26",
0.0053, -0.0274, -0.003, -0.0209, 0.0302, 0.0129, -0.0044, 0.0088, 0, -0.004, "2018-07-27",
0.0152, 0.0081, 0.0065, -0.023, 0.0136, -0.0128, -0.0056, 0.0187, 0.0052, -0.0166, "2018-07-30",
0.0118, 0.0143, -0.0101, 0.0298, 0.0101, -0.022, 0.016, 0.0041, 0.0104, 0.0063, "2018-07-31",
-0.0111, -0.0026, 0.005, 0.0217, -0.0353, 0.0084, -0.0155, -0.0038, -0.036, 0.0221, "2018-08-01",
-0.0158, -8e-04, 0.0036, -0.0257, 0.0114, -0.0287, -6e-04, -0.0317, 0.008, -0.0258, "2018-08-02",
0.0237, -0.0011, -0.0015, 0.0039, 0.0068, 0.0191, 8e-04, 0.0071, 0.0317, 0.0188, "2018-08-03",
-0.0298, 0.0019, 0.0083, 0.0318, -0.002, 0.0043, 0.0041, -0.0159, -0.0128, -0.0089, "2018-08-06",
-0.0011, -0.002, 0.0091, 0.0143, 0.001, 0.0243, 0.0017, 0.0046, 0.0026, -0.0037, "2018-08-07",
0.0092, 7e-04, 0.0115, 0.124, 0.0169, 0.0069, -0.004, 6e-04, 0.0881, 0.0029, "2018-08-08",
-0.0307, 0.0287, 0.0273, -0.0211, 0.0033, 0.0059, 0.0042, -0.0401, 0.0429, -0.0261, "2018-08-10",
-0.013, 0.0162, 0.0113, -0.0105, -0.0286, 0.0099, 0.0177, -0.0077, -0.0411, -0.0044, "2018-08-13",
0.0147, -0.0016, -0.0052, -0.026, -0.0014, -0.0206, 0, 0.0142, 0.0357, 0.0223, "2018-08-14",
-0.0345, 0.0025, -8e-04, -0.0506, 0.0123, -0.0822, 0.0017, -0.0264, 0, -0.0024, "2018-08-15",
0.0255, 0.0232, 0.006, 0.0229, 0.0027, 0.0279, 0.0163, 0.0159, -0.0345, 0.003, "2018-08-16",
-0.0175, 0.0184, 0.0093, -0.0163, 0.0094, 0.0108, 0.0206, -0.0182, 0, -0.0114, "2018-08-17",
0.0096, 2e-04, 0.0058, 0.0109, 0.0104, 0.0214, -0.001, 0.0094, -0.0238, 0.0099, "2018-08-20",
-0.0098, -0.0335, -0.0221, 0.0059, -0.0251, 0.0174, -0.0065, 0.0045, 0.0098, 0.0128, "2018-08-21",
0.0086, -0.0082, 0.0065, 0.0045, 0.0112, 0.038, 0.0142, 0.0169, -0.0048, 0, "2018-08-22",
0.004, -0.0169, 0.0063, 0.0022, -0.0134, 0.0032, 0.002, -0.0011, -0.0146, -0.0184, "2018-08-23",
0.0038, -0.0293, 0.0074, -9e-04, -0.0129, 0.0282, -0.0091, -0.0136, -0.0197, -0.0119, "2018-08-24",
0.0353, -0.0017, 0.0023, -0.048, 0.0093, 0.009, -0.0028, 0.0351, 0.0176, 0.026, "2018-08-27",
0.0101, -0.0172, 0.0234, -0.0495, 0.0072, -0.0028, 0.0147, 0.0077, 0.0148, 0.0411, "2018-08-28",
-0.0202, 0.0189, 0.0164, -0.0442, 0.0275, 0.0056, 0.0149, -0.0267, 0.0097, 0.0077, "2018-08-29",
-0.0074, 0.0021, 0.0121, 0.0291, -0.0231, -0.0642, 0.0188, -0.0239, -0.012, -0.0245, "2018-08-30",
-0.0058, -0.0141, -0.015, -2e-04, 0.0132, -0.0251, 0.0243, 0.0072, -0.0049, 0.0328, "2018-08-31",
0.0084, 0.0045, -0.0028, -0.067, 0.0017, -0.0186, -0.0019, 0.0013, 0.0172, 0.0079, "2018-09-03",
-0.042, 0.0237, 0.0165, -0.038, -0.005, -0.0067, 0.0049, -0.0379, -0.012, -0.0289, "2018-09-04",
-0.0193, 0.0103, -0.0073, -0.0404, -0.0057, -0.0402, 0.0015, -0.0306, 0.0122, -0.0107, "2018-09-05",
0.0241, -0.0118, -0.0078, 0.061, 3e-04, 0.0021, -0.0071, 0.0249, -0.0024, -0.0114, "2018-09-06",
-0.0108, -0.0158, -0.0137, 8e-04, -0.0188, 0.0292, -0.01, 0.0149, -0.0024, 0.0039, "2018-09-07",
-0.0096, 6e-04, 0.0068, -0.0033, 0.0171, -0.0109, 0.004, -0.0182, 0.0048, -0.0019, "2018-09-10",
-0.0024, -0.028, -0.0258, -0.0378, 0.0051, -0.0093, -0.0174, -9e-04, -0.0072, 0.006, "2018-09-11",
-0.0287, 0.0526, -0.0029, 0.0476, 0.005, -0.011, 0.0197, -0.0266, -0.0534, -0.025, "2018-09-12",
-0.0138, -0.0262, -0.015, -0.0215, -0.0027, 0.0331, -0.0395, 0.015, 0.0487, 0.0153, "2018-09-13",
0.0161, -0.0028, 0.0168, -0.0161, -0.0027, 0.0094, 0.0116, 0.0041, -0.0269, -0.0087, "2018-09-14",
-0.0273, 0.0018, -0.0064, 0.017, 0.002, 0.0068, -0.0017, -0.0235, -0.0201, -0.0232, "2018-09-17",
0.0075, -0.0237, 0.0018, 0.0069, 0.0107, -0.0083, -0.0073, 0.0152, -0.0026, 4e-04, "2018-09-18",
0.0277, -0.0223, -0.0436, -0.0022, -0.0142, -0.0047, -0.0192, 0.0321, 0.0026, 0.0042, "2018-09-19",
-0.0046, -0.0173, 0.0083, -0.0575, -0.0084, 0.0041, 0.0011, -0.0065, -0.0359, 0.0125, "2018-09-20",
0.0314, 0.0047, -2e-04, 3e-04, -0.0037, 0.0221, 0.0204, 0.0249, -0.0027, 0.0045, "2018-09-21",
-0.0135, -0.0141, -0.0137, 0.0742, -0.0112, -0.0195, -0.004, -0.0399, 0.0133, -0.0141, "2018-09-25",
0.0131, 0.0015, -0.0154, 0.0107, -0.0021, -0.001, -0.0191, 0.0034, -0.0237, 0, "2018-09-26",
-0.0045, -0.0055, -0.0178, 0.0486, -0.0145, -0.0322, -0.0071, 0.0025, 0.0243, -0.001, "2018-09-27",
-0.0157, 0.0067, 0.0073, -0.0281, -0.0066, -0.0089, -0.0065, -0.0124, -0.0289, -0.017, "2018-09-28",
0.0085, -0.0248, 0.0089, -0.0347, -7e-04, 0.0051, -0.0014, -0.0029, 0.0163, 0.0081, "2018-10-01",
-0.0142, 0.016, -0.009, -0.025, -0.006, -0.0219, 0.0045, -0.0238, 0, -0.024, "2018-10-02",
-0.014, -0.0024, 0.0014, -0.0101, 0.0103, -0.01, -0.0087, -0.0186, 0, -0.0133, "2018-10-03",
-0.0178, -0.0034, 0.0047, -0.025, 0.0014, -0.0155, -8e-04, -0.0071, 0.024, -0.0104, "2018-10-04",
-0.0043, 0.0088, -0.0126, -0.0718, 0.2347, -0.0116, -0.0065, -0.0168, -0.0208, -0.0021, "2018-10-05",
0.0052, 1e-04, -0.0171, 0.0711, -0.0028, -0.0017, -0.0094, -0.0013, 0.0239, 0.0217, "2018-10-08",
0.0154, -0.0057, -0.0021, 0.0123, 0.01, -0.0153, 0.0027, 0.0062, -0.0182, 0.0023, "2018-10-09",
-0.0037, 0.0166, -0.0423, -0.0131, -0.0099, -0.0647, -0.0018, -9e-04, -0.0529, -0.006, "2018-10-10",
-0.0232, -0.0176, -0.0202, -0.0638, 0.0014, 0.0091, -0.012, -0.0297, 0.0168, -0.0074, "2018-10-11",
0.0253, -0.0463, -0.0027, 0.0141, -0.0116, 0.0846, -0.0446, 0.0301, -0.0385, 0.0152, "2018-10-12",
-0.0169, -0.0038, -0.0166, -0.0372, -0.0227, -0.0543, -0.0281, -0.0184, -0.0286, -0.007, "2018-10-15",
0.0259, -0.038, 0.0104, 0.0212, 0.0147, 0.0258, 0.0043, 0.0371, 0, 0.0242, "2018-10-16",
-0.0187, 0.0219, -0.0172, 0.0655, -0.0304, -0.0226, -0.0013, -0.0177, -0.0265, -0.0254, "2018-10-17",
-0.0023, 0.0031, -0.0052, 0.0298, -0.006, -0.0117, 0.0034, -0.0042, -0.0272, -0.0068, "2018-10-18",
0.0016, 0.0016, -0.0075, 0, 0.1188, -7e-04, 2e-04, -0.01, 0.0155, -0.0071, "2018-10-19",
-0.0168, 0.0053, -0.01, -0.0244, -0.0024, 0.032, -0.0014, 0.0092, 0.0092, 0.018, "2018-10-22",
-0.0255, 0.0456, -0.0025, -0.0062, -0.0191, -0.0459, 0.0096, -0.0366, -0.0303, -0.0132, "2018-10-23",
0.0176, 0.0159, -6e-04, -0.0281, -0.0036, -0.0396, 0.0042, 0.0096, 0, 0.0044, "2018-10-24",
0.0352, 0.0163, 0.0183, 0.032, 0.0091, 0.0274, 0.0356, 0.0184, -0.0156, 0.0204, "2018-10-25",
-0.0216, -0.0036, 0.0043, -0.003, -8e-04, -0.0327, -0.0086, -0.011, -0.0159, -0.0169, "2018-10-26",
0.0483, -0.0106, 0.0158, 0.0225, -8e-04, -0.0398, -9e-04, 0.0388, 0.029, 0.0394, "2018-10-29",
0.0046, -0.0257, -0.0118, -0.0289, 0.0085, -0.0355, -0.0061, -0.0142, -0.0125, 0, "2018-10-30",
-0.0222, -0.0013, 0.0442, -0.0224, -0.0016, 0.094, 0.007, -9e-04, -0.0476, 0.0156, "2018-10-31",
0.0261, 0.0013, -0.0088, 0.0619, -0.0084, 0.0856, 0.0042, 0.0249, 0.0433, 0.023, "2018-11-01",
0.0375, -0.0287, 0.0166, -0.039, -0.0162, 0.0299, -0.0177, 0.0363, -0.0415, 0.0065, "2018-11-02",
0.0221, 0.0192, -0.02, -0.0373, -0.0042, 0.0093, 0.0151, 0.0173, -0.0233, 0.0227, "2018-11-05",
-0.0173, -0.0423, -0.0073, -0.0059, 0.0084, -0.0054, -0.0234, 0.0039, -0.0171, -0.0082, "2018-11-06",
0.0207, 0.0322, -0.0187, 0.0303, -0.0117, -0.0108, 0.0073, 0.0229, 0.066, 0.0568, "2018-11-07",
-0.0165, -0.014, -0.0042, -0.0161, -0.0017, -0.0286, -0.001, -0.0343, -0.0228, -0.0231, "2018-11-08",
-0.0117, 0.0076, -0.064, -0.0092, 0.0166, -0.0183, 0.0196, -0.0017, -0.0067, 0.0131, "2018-11-09",
-0.0211, -0.113, -0.005, -0.0155, 0.0086, -0.0345, -0.0691, -0.0268, 0.0034, -0.0358, "2018-11-12",
0.0139, -0.0212, 0.0042, -0.0218, -0.0088, -0.019, -0.0061, 0.0128, -0.0201, 0.0192, "2018-11-13",
-0.0127, -0.0208, 0.0068, 0.0523, -0.0036, 0.0425, -0.0261, -0.0134, -0.0137, -0.0176, "2018-11-14",
0.0037, -0.0285, -0.0355, 0.0227, -0.0583, 0.0267, -0.0112, 0.0046, 0.0381, -0.0034, "2018-11-15",
0.0012, -0.0591, 0.0022, 0.0258, -0.0071, -0.0016, -0.067, -5e-04, 0.0067, -0.0118, "2018-11-16",
0.0216, 0.011, -0.0152, 0.0263, -0.0131, 0.0167, 0.0154, 0.0064, -0.0232, 0.0136, "2018-11-19",
-0.0282, 0.0013, -0.0111, 0.0228, 0.0129, -0.0735, -7e-04, -0.0329, 0.0136, -4e-04, "2018-11-20",
-0.0038, -0.0179, 0.0035, -0.0446, 0.011, 0.0377, -0.0108, -0.0042, 0.01, 0.0039, "2018-11-21",
-0.0036, -0.0145, -0.0107, 0.0017, 3e-04, 0.014, -0.039, 0.0163, -0.0232, 0.0089, "2018-11-22",
-0.0067, 0.0244, -0.0058, -0.0154, -0.0047, -0.0133, 0.0257, -0.0108, -0.0508, 0.0026, "2018-11-23",
0.0321, -0.0162, 0.0214, -0.0464, -0.0032, 0.0386, 0.0098, 0.0255, 0.0179, 0.0454, "2018-11-26",
-0.0104, 0.0108, -0.0097, 0.0127, -6e-04, -0.0114, 0.0211, 0.0162, 0.0175, 0.0062, "2018-11-27",
0.0081, 0.0139, 0.0055, -0.0297, 0.0136, 0.0375, 0.0165, 0.0242, -0.0207, -0.0021, "2018-11-28",
0.0115, -0.0042, -0.013, 0.0565, -0.392, -0.0257, -0.0179, 0.0152, 0.0211, -0.0086, "2018-11-29",
-0.0302, -0.0133, -0.0184, -0.0355, -0.0341, -0.0202, -0.0372, -0.0275, 0, -0.0113, "2018-11-30",
0.0224, 0.0086, 0.0356, 0.0059, 0.0065, 0.0454, 0.0069, 0.0251, -0.0345, 0.0234, "2018-12-03",
0.0187, -0.014, -0.0103, -0.0083, -0.0218, 0.0144, 0.0071, 0.0071, 0.0357, 0.0077, "2018-12-04",
-0.0056, 0.007, -0.0099, 0.0068, -0.0051, -0.0196, 0.0107, -0.0121, 0.0276, -0.0125, "2018-12-05",
-0.0336, 0.0162, 0.005, 0.0105, 0.0213, -0.0409, 0.0285, -0.0329, 0.0067, -0.0244, "2018-12-06",
0.0051, -0.0229, -0.0023, -0.0177, 0.006, 0.0214, -0.0043, -0.0069, -0.03, -0.0052, "2018-12-07",
-0.0289, 0.0196, 0.003, -0.0276, 0.003, -0.0227, 0.016, -0.0227, 0.0309, -0.0211, "2018-12-10",
0.0267, 0.0107, 0.0246, 0.022, 0.0375, 0.0368, 0.0489, -0.0035, 0.0333, 0.0033, "2018-12-11",
0.0128, -0.0073, -0.0072, 0.0203, 0.0171, 0.0021, -0.023, 0.0273, -0.0323, 0, "2018-12-12",
0.0169, -0.0131, 0.0018, -0.0144, 0.0136, -0.013, -0.0174, 0.0152, 0, 0.0182, "2018-12-13",
-0.0047, -0.0103, 0.0032, -0.0134, 0.0078, -6e-04, -0.003, -0.0039, 0, -0.0313, "2018-12-14",
-0.026, -0.0213, -0.0175, -0.0441, -0.0151, 0.0019, -0.0131, -0.0162, 0.0133, 0.003, "2018-12-18",
0.0331, -0.0221, -0.0117, 0.0201, -0.0111, -0.0012, -0.0287, 0.0398, 0.0526, 0.0169, "2018-12-19",
-0.0145, 0.0087, -0.0144, 0.0045, -0.0155, -0.0062, -0.0038, -0.006, 0, 0.0029, "2018-12-20",
-0.0155, -0.0108, 0.0162, -0.0354, 0.0014, 0.0277, -0.0127, -0.0093, -0.0031, -0.019, "2018-12-21",
0.0014, -0.0117, 0.0143, -0.0133, 0.0076, 0.0265, 0.0339, 0.0059, -0.0533, 0.0138, "2018-12-24",
0.0087, -0.0025, -0.0223, 0.047, -0.0071, -0.0303, -0.0167, -0.0038, 0.0298, -0.0134, "2018-12-27",
0.02, 0.0435, 0.0366, -0.0155, -0.0029, 0.0116, 0.0497, 0.0171, 0, 0.0126, "2018-12-28",
0.0162, -0.0072, 0.0074, 0.0102, 0.0096, -0.0027, 0.0031, 0.0032, 0, 0.0108, "2018-12-31"
) %>% mutate(date = lubridate::ymd(date))
wts <- tibble::tribble(
~ABG, ~BTI, ~CFR, ~EOH, ~ITU, ~NPN, ~RNI, ~SBK, ~SNV, ~WHL, ~date,
0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, "2018-07-02",
0.075, 0.075, 0.15, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, "2018-08-05",
0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, "2018-09-03"
) %>% mutate(date = lubridate::ymd(date))
# Squaring rebalancing dates with returns series:
# Assumptions applied ::::> when a stock rebalances, it does so at the beginning of the day given.
# Thus this implies - the rebalanced weight should be multiplied by the weight given for the day of rebalancing.
# Thus: wts = date: 20180101 ; stock = X; weight = 0.15 ::: means the weight to use for X to square with 20180101's returns is 15%
# To achieve this, do the following:
xts_rts <- rets %>% gather(Tickers, Ret, -date) %>% tbl_xts(cols_to_xts = "Ret", spread_by = "Tickers")
xts_wts <- wts %>% gather(Tickers, wt, -date) %>% tbl_xts(cols_to_xts = "wt", spread_by = "Tickers")
port <- rmsfuns::Safe_Return.portfolio(R = xts_rts, weights = xts_wts, lag_weights = T, verbose = T)
safeway <- port$returns %>% xts_tbl %>% filter(date == ymd(20180801) ) %>% pull(portfolio.returns)
# which should be the same as:
Should_be <-
left_join(
xts_rts %>% xts_tbl %>% filter(date == ymd(20180801) ) %>% gather(stocks, ret, -date),
xts_wts %>% xts_tbl %>% filter(date == ymd(20180801) ) %>% gather(stocks, weight, -date),
by = c("date", "stocks")
) %>% mutate(port = sum(ret * weight))
all.equal(safeway, unique(Should_be$port))
# Note - this implies the weights used for a day's return calc is given as:
port$BOP.Weight %>% xts_tbl %>% filter(date == ymd(20180806))
# Notice here - I intentionally made the rebalance date on a weekend day (where there were no returns).
# Notice - this function now squares the official rebalance weight (20180805) with the next valid return date - so it doesn't break.
# When using lag_weights, notice that EOP.Weight will not equal the rebalance dates as BOP.weights do...
port$EOP.Weight %>% xts_tbl %>% filter(date == ymd(20180806))
# ...with the above the adjusted end of day weights (given the returns on the day's effect on portfolio weights)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment