MacdChart
MACD from closing prices: the MACD and signal lines and the histogram between them, under a price chart or on its own.
Demo
| Time | Close | MACD | Signal | Histogram |
|---|---|---|---|---|
| Mar 16, 2026 | $308.36 | — | — | — |
| Mar 17, 2026 | $305.02 | — | — | — |
| Mar 18, 2026 | $303.38 | — | — | — |
| Mar 19, 2026 | $304.73 | — | — | — |
| Mar 20, 2026 | $302.74 | — | — | — |
| Mar 23, 2026 | $301.49 | — | — | — |
| Mar 24, 2026 | $305.59 | — | — | — |
| Mar 25, 2026 | $308.12 | — | — | — |
| Mar 26, 2026 | $305.03 | — | — | — |
| Mar 27, 2026 | $307.03 | — | — | — |
| Mar 30, 2026 | $305.82 | — | — | — |
| Mar 31, 2026 | $310.51 | — | — | — |
| Apr 1, 2026 | $313.01 | — | — | — |
| Apr 2, 2026 | $312.74 | — | — | — |
| Apr 3, 2026 | $308.09 | — | — | — |
| Apr 6, 2026 | $305.90 | — | — | — |
| Apr 7, 2026 | $311.02 | — | — | — |
| Apr 8, 2026 | $312.47 | — | — | — |
| Apr 9, 2026 | $312.37 | — | — | — |
| Apr 10, 2026 | $311.58 | — | — | — |
| Apr 13, 2026 | $316.64 | — | — | — |
| Apr 14, 2026 | $319.87 | — | — | — |
| Apr 15, 2026 | $317.10 | — | — | — |
| Apr 16, 2026 | $317.51 | — | — | — |
| Apr 17, 2026 | $321.75 | — | — | — |
| Apr 20, 2026 | $316.94 | 4.9847 | — | — |
| Apr 21, 2026 | $319.10 | 4.9290 | — | — |
| Apr 22, 2026 | $318.60 | 4.7893 | — | — |
| Apr 23, 2026 | $323.73 | 5.0345 | — | — |
| Apr 24, 2026 | $325.21 | 5.2873 | — | — |
| Apr 27, 2026 | $322.23 | 5.1874 | — | — |
| Apr 28, 2026 | $327.69 | 5.4855 | — | — |
| Apr 29, 2026 | $326.92 | 5.5952 | — | — |
| Apr 30, 2026 | $321.65 | 5.1969 | 5.1655 | 0.0314 |
| May 1, 2026 | $322.59 | 4.9007 | 5.1126 | -0.2119 |
| May 4, 2026 | $326.56 | 4.9294 | 5.0759 | -0.1465 |
| May 5, 2026 | $323.83 | 4.6780 | 4.9963 | -0.3183 |
| May 6, 2026 | $328.24 | 4.7795 | 4.9530 | -0.1735 |
| May 7, 2026 | $330.93 | 5.0191 | 4.9662 | 0.0529 |
| May 8, 2026 | $334.04 | 5.3978 | 5.0525 | 0.3452 |
| May 11, 2026 | $328.18 | 5.1654 | 5.0751 | 0.0903 |
| May 12, 2026 | $325.77 | 4.7323 | 5.0065 | -0.2742 |
| May 13, 2026 | $321.74 | 4.0175 | 4.8087 | -0.7912 |
| May 14, 2026 | $323.68 | 3.5665 | 4.5603 | -0.9938 |
| May 15, 2026 | $326.11 | 3.3664 | 4.3215 | -0.9552 |
| May 18, 2026 | $325.86 | 3.1512 | 4.0875 | -0.9362 |
| May 19, 2026 | $330.19 | 3.2922 | 3.9284 | -0.6362 |
| May 20, 2026 | $326.09 | 3.0380 | 3.7503 | -0.7123 |
| May 21, 2026 | $328.03 | 2.9590 | 3.5921 | -0.6330 |
| May 22, 2026 | $334.35 | 3.3676 | 3.5472 | -0.1796 |
| May 25, 2026 | $328.22 | 3.1603 | 3.4698 | -0.3095 |
| May 26, 2026 | $323.79 | 2.6085 | 3.2975 | -0.6890 |
| May 27, 2026 | $328.70 | 2.5381 | 3.1457 | -0.6075 |
| May 28, 2026 | $323.88 | 2.0696 | 2.9304 | -0.8609 |
| May 29, 2026 | $324.93 | 1.7626 | 2.6969 | -0.9342 |
| Jun 1, 2026 | $324.95 | 1.5037 | 2.4582 | -0.9546 |
| Jun 2, 2026 | $324.73 | 1.2661 | 2.2198 | -0.9537 |
| Jun 3, 2026 | $323.97 | 1.0049 | 1.9768 | -0.9719 |
| Jun 4, 2026 | $324.00 | 0.7912 | 1.7397 | -0.9485 |
| Jun 5, 2026 | $322.58 | 0.5015 | 1.4921 | -0.9906 |
| Jun 8, 2026 | $321.92 | 0.2161 | 1.2369 | -1.0207 |
| Jun 9, 2026 | $323.25 | 0.0962 | 1.0087 | -0.9125 |
| Jun 10, 2026 | $326.66 | 0.2732 | 0.8616 | -0.5885 |
| Jun 11, 2026 | $328.48 | 0.5539 | 0.8001 | -0.2462 |
| Jun 12, 2026 | $324.34 | 0.4372 | 0.7275 | -0.2903 |
| Jun 15, 2026 | $326.37 | 0.5028 | 0.6826 | -0.1797 |
| Jun 16, 2026 | $324.76 | 0.4200 | 0.6301 | -0.2100 |
| Jun 17, 2026 | $320.16 | -0.0166 | 0.5007 | -0.5173 |
| Jun 18, 2026 | $323.64 | -0.0808 | 0.3844 | -0.4653 |
| Jun 19, 2026 | $325.35 | 0.0061 | 0.3088 | -0.3026 |
| Jun 22, 2026 | $320.41 | -0.3199 | 0.1830 | -0.5029 |
| Jun 23, 2026 | $319.69 | -0.6291 | 0.0206 | -0.6497 |
| Jun 24, 2026 | $323.04 | -0.5969 | -0.1029 | -0.4940 |
| Jun 25, 2026 | $322.86 | -0.5793 | -0.1982 | -0.3811 |
| Jun 26, 2026 | $322.36 | -0.5987 | -0.2783 | -0.3205 |
| Jun 29, 2026 | $319.38 | -0.8449 | -0.3916 | -0.4533 |
| Jun 30, 2026 | $321.95 | -0.8231 | -0.4779 | -0.3452 |
| Jul 1, 2026 | $319.26 | -1.0112 | -0.5846 | -0.4267 |
| Jul 2, 2026 | $315.46 | -1.4502 | -0.7577 | -0.6925 |
| Jul 3, 2026 | $311.43 | -2.0992 | -1.0260 | -1.0732 |
| Jul 6, 2026 | $310.50 | -2.6578 | -1.3524 | -1.3055 |
| Jul 7, 2026 | $308.41 | -3.2320 | -1.7283 | -1.5037 |
| Jul 8, 2026 | $312.55 | -3.3147 | -2.0456 | -1.2691 |
| Jul 9, 2026 | $310.92 | -3.4718 | -2.3308 | -1.1410 |
| Jul 10, 2026 | $310.38 | -3.5984 | -2.5843 | -1.0140 |
| Jul 13, 2026 | $309.07 | -3.7610 | -2.8197 | -0.9414 |
| Jul 14, 2026 | $309.04 | -3.8480 | -3.0253 | -0.8227 |
| Jul 15, 2026 | $305.63 | -4.1443 | -3.2491 | -0.8952 |
| Jul 16, 2026 | $307.49 | -4.1809 | -3.4355 | -0.7454 |
| Jul 17, 2026 | $310.80 | -3.8978 | -3.5279 | -0.3699 |
| Jul 20, 2026 | $315.63 | -3.2463 | -3.4716 | 0.2253 |
| Jul 21, 2026 | $318.79 | -2.4468 | -3.2667 | 0.8198 |
| Jul 22, 2026 | $315.09 | -2.0877 | -3.0309 | 0.9432 |
| Jul 23, 2026 | $313.55 | -1.9054 | -2.8058 | 0.9004 |
| Jul 24, 2026 | $315.69 | -1.5702 | -2.5587 | 0.9885 |
| Jul 27, 2026 | $319.64 | -0.9745 | -2.2418 | 1.2673 |
| Jul 28, 2026 | $323.18 | -0.2143 | -1.8363 | 1.6220 |
| Jul 29, 2026 | $327.21 | 0.7052 | -1.3280 | 2.0332 |
| Jul 30, 2026 | $324.12 | 1.1711 | -0.8282 | 1.9993 |
| Jul 31, 2026 | $328.53 | 1.8745 | -0.2877 | 2.1622 |
| Aug 3, 2026 | $329.18 | 2.4562 | 0.2611 | 2.1950 |
| Aug 4, 2026 | $335.40 | 3.3800 | 0.8849 | 2.4951 |
| Aug 5, 2026 | $337.63 | 4.2432 | 1.5566 | 2.6867 |
| Aug 6, 2026 | $343.20 | 5.3155 | 2.3084 | 3.0072 |
| Aug 7, 2026 | $342.72 | 6.0568 | 3.0580 | 2.9987 |
| Aug 10, 2026 | $349.60 | 7.1173 | 3.8699 | 3.2474 |
| Aug 11, 2026 | $344.65 | 7.4723 | 4.5904 | 2.8819 |
| Aug 12, 2026 | $343.48 | 7.5719 | 5.1867 | 2.3852 |
| Aug 13, 2026 | $348.64 | 7.9752 | 5.7444 | 2.2308 |
| Aug 14, 2026 | $349.02 | 8.2307 | 6.2416 | 1.9890 |
| Aug 17, 2026 | $353.58 | 8.7008 | 6.7335 | 1.9673 |
| Aug 18, 2026 | $350.98 | 8.7625 | 7.1393 | 1.6233 |
| Aug 19, 2026 | $355.88 | 9.1020 | 7.5318 | 1.5701 |
| Aug 20, 2026 | $357.79 | 9.4165 | 7.9088 | 1.5078 |
| Aug 21, 2026 | $357.18 | 9.5070 | 8.2284 | 1.2786 |
| Aug 24, 2026 | $363.16 | 9.9466 | 8.5720 | 1.3745 |
| Aug 25, 2026 | $360.07 | 9.9311 | 8.8439 | 1.0873 |
| Aug 26, 2026 | $358.64 | 9.6918 | 9.0134 | 0.6783 |
| Aug 27, 2026 | $357.79 | 9.3260 | 9.0759 | 0.2500 |
| Aug 28, 2026 | $352.90 | 8.5430 | 8.9694 | -0.4263 |
| Aug 31, 2026 | $357.81 | 8.2240 | 8.8203 | -0.5963 |
| Sep 1, 2026 | $359.93 | 8.0494 | 8.6661 | -0.6167 |
| Sep 2, 2026 | $357.21 | 7.6038 | 8.4536 | -0.8498 |
| Sep 3, 2026 | $357.13 | 7.1618 | 8.1953 | -1.0335 |
| Sep 4, 2026 | $362.64 | 7.1733 | 7.9909 | -0.8176 |
| Sep 7, 2026 | $361.52 | 7.0113 | 7.7950 | -0.7837 |
| Sep 8, 2026 | $359.00 | 6.6034 | 7.5567 | -0.9532 |
| Sep 9, 2026 | $365.03 | 6.6896 | 7.3833 | -0.6936 |
| Sep 10, 2026 | $360.41 | 6.3124 | 7.1691 | -0.8567 |
| Sep 11, 2026 | $359.62 | 5.8819 | 6.9116 | -1.0297 |
| Time | Close | MACD | Signal | Histogram |
|---|---|---|---|---|
| Mar 16, 2026 | 308.36 | — | — | — |
| Mar 17, 2026 | 305.02 | — | — | — |
| Mar 18, 2026 | 303.38 | — | — | — |
| Mar 19, 2026 | 304.73 | — | — | — |
| Mar 20, 2026 | 302.74 | — | — | — |
| Mar 23, 2026 | 301.49 | — | — | — |
| Mar 24, 2026 | 305.59 | — | — | — |
| Mar 25, 2026 | 308.12 | — | — | — |
| Mar 26, 2026 | 305.03 | — | — | — |
| Mar 27, 2026 | 307.03 | — | — | — |
| Mar 30, 2026 | 305.82 | — | — | — |
| Mar 31, 2026 | 310.51 | — | — | — |
| Apr 1, 2026 | 313.01 | — | — | — |
| Apr 2, 2026 | 312.74 | — | — | — |
| Apr 3, 2026 | 308.09 | — | — | — |
| Apr 6, 2026 | 305.90 | — | — | — |
| Apr 7, 2026 | 311.02 | — | — | — |
| Apr 8, 2026 | 312.47 | — | — | — |
| Apr 9, 2026 | 312.37 | — | — | — |
| Apr 10, 2026 | 311.58 | — | — | — |
| Apr 13, 2026 | 316.64 | — | — | — |
| Apr 14, 2026 | 319.87 | — | — | — |
| Apr 15, 2026 | 317.10 | — | — | — |
| Apr 16, 2026 | 317.51 | — | — | — |
| Apr 17, 2026 | 321.75 | — | — | — |
| Apr 20, 2026 | 316.94 | — | — | — |
| Apr 21, 2026 | 319.10 | — | — | — |
| Apr 22, 2026 | 318.60 | — | — | — |
| Apr 23, 2026 | 323.73 | — | — | — |
| Apr 24, 2026 | 325.21 | — | — | — |
| Apr 27, 2026 | 322.23 | — | — | — |
| Apr 28, 2026 | 327.69 | — | — | — |
| Apr 29, 2026 | 326.92 | — | — | — |
| Apr 30, 2026 | 321.65 | — | — | — |
| May 1, 2026 | 322.59 | 9.9019 | — | — |
| May 4, 2026 | 326.56 | 10.2288 | — | — |
| May 5, 2026 | 323.83 | 9.4869 | — | — |
| May 6, 2026 | 328.24 | 10.0691 | — | — |
| May 7, 2026 | 330.93 | 10.9964 | 10.1366 | 0.8598 |
| May 8, 2026 | 334.04 | 12.2405 | 10.8379 | 1.4026 |
| May 11, 2026 | 328.18 | 11.1694 | 10.9484 | 0.2210 |
| May 12, 2026 | 325.77 | 9.6187 | 10.5052 | -0.8865 |
| May 13, 2026 | 321.74 | 7.3447 | 9.4517 | -2.1069 |
| May 14, 2026 | 323.68 | 6.3159 | 8.4064 | -2.0905 |
| May 15, 2026 | 326.11 | 6.2261 | 7.6797 | -1.4535 |
| May 18, 2026 | 325.86 | 5.9849 | 7.1147 | -1.1299 |
| May 19, 2026 | 330.19 | 6.9249 | 7.0515 | -0.1265 |
| May 20, 2026 | 326.09 | 6.2497 | 6.7842 | -0.5345 |
| May 21, 2026 | 328.03 | 6.2477 | 6.6053 | -0.3577 |
| May 22, 2026 | 334.35 | 7.8863 | 7.0323 | 0.8539 |
| May 25, 2026 | 328.22 | 7.0691 | 7.0446 | 0.0246 |
| May 26, 2026 | 323.79 | 5.1932 | 6.4275 | -1.2343 |
| May 27, 2026 | 328.70 | 5.2798 | 6.0449 | -0.7651 |
| May 28, 2026 | 323.88 | 3.8976 | 5.3291 | -1.4315 |
| May 29, 2026 | 324.93 | 3.2469 | 4.6350 | -1.3882 |
| Jun 1, 2026 | 324.95 | 2.7826 | 4.0175 | -1.2350 |
| Jun 2, 2026 | 324.73 | 2.3776 | 3.4709 | -1.0933 |
| Jun 3, 2026 | 323.97 | 1.8674 | 2.9364 | -1.0690 |
| Jun 4, 2026 | 324.00 | 1.5200 | 2.4643 | -0.9443 |
| Jun 5, 2026 | 322.58 | 0.8786 | 1.9357 | -1.0571 |
| Jun 8, 2026 | 321.92 | 0.2752 | 1.3822 | -1.1070 |
| Jun 9, 2026 | 323.25 | 0.2596 | 1.0080 | -0.7484 |
| Jun 10, 2026 | 326.66 | 1.1922 | 1.0694 | 0.1228 |
| Jun 11, 2026 | 328.48 | 2.2629 | 1.4673 | 0.7957 |
| Jun 12, 2026 | 324.34 | 1.7451 | 1.5599 | 0.1852 |
| Jun 15, 2026 | 326.37 | 1.9507 | 1.6902 | 0.2605 |
| Jun 16, 2026 | 324.76 | 1.5968 | 1.6590 | -0.0623 |
| Jun 17, 2026 | 320.16 | 0.0666 | 1.1282 | -1.0616 |
| Jun 18, 2026 | 323.64 | 0.0686 | 0.7750 | -0.7064 |
| Jun 19, 2026 | 325.35 | 0.5436 | 0.6979 | -0.1543 |
| Jun 22, 2026 | 320.41 | -0.5397 | 0.2854 | -0.8250 |
| Jun 23, 2026 | 319.69 | -1.4117 | -0.2803 | -1.1314 |
| Jun 24, 2026 | 323.04 | -1.0041 | -0.5216 | -0.4825 |
| Jun 25, 2026 | 322.86 | -0.7788 | -0.6073 | -0.1715 |
| Jun 26, 2026 | 322.36 | -0.7615 | -0.6587 | -0.1028 |
| Jun 29, 2026 | 319.38 | -1.5642 | -0.9605 | -0.6037 |
| Jun 30, 2026 | 321.95 | -1.3268 | -1.0826 | -0.2442 |
| Jul 1, 2026 | 319.26 | -1.8999 | -1.3551 | -0.5449 |
| Jul 2, 2026 | 315.46 | -3.2812 | -1.9971 | -1.2841 |
| Jul 3, 2026 | 311.43 | -5.2096 | -3.0679 | -2.1416 |
| Jul 6, 2026 | 310.50 | -6.5856 | -4.2405 | -2.3451 |
| Jul 7, 2026 | 308.41 | -7.9105 | -5.4638 | -2.4467 |
| Jul 8, 2026 | 312.55 | -7.4483 | -6.1253 | -1.3230 |
| Jul 9, 2026 | 310.92 | -7.4721 | -6.5742 | -0.8979 |
| Jul 10, 2026 | 310.38 | -7.4987 | -6.8824 | -0.6163 |
| Jul 13, 2026 | 309.07 | -7.7405 | -7.1684 | -0.5721 |
| Jul 14, 2026 | 309.04 | -7.7577 | -7.3649 | -0.3929 |
| Jul 15, 2026 | 305.63 | -8.5721 | -7.7673 | -0.8048 |
| Jul 16, 2026 | 307.49 | -8.4095 | -7.9814 | -0.4281 |
| Jul 17, 2026 | 310.80 | -7.2319 | -7.7315 | 0.4996 |
| Jul 20, 2026 | 315.63 | -5.0149 | -6.8260 | 1.8111 |
| Jul 21, 2026 | 318.79 | -2.6483 | -5.4334 | 2.7851 |
| Jul 22, 2026 | 315.09 | -2.1370 | -4.3346 | 2.1976 |
| Jul 23, 2026 | 313.55 | -2.2033 | -3.6242 | 1.4209 |
| Jul 24, 2026 | 315.69 | -1.6098 | -2.9527 | 1.3429 |
| Jul 27, 2026 | 319.64 | -0.1090 | -2.0048 | 1.8958 |
| Jul 28, 2026 | 323.18 | 1.8212 | -0.7295 | 2.5507 |
| Jul 29, 2026 | 327.21 | 4.1223 | 0.8878 | 3.2345 |
| Jul 30, 2026 | 324.12 | 4.6365 | 2.1373 | 2.4991 |
| Jul 31, 2026 | 328.53 | 6.0993 | 3.4580 | 2.6413 |
| Aug 3, 2026 | 329.18 | 7.0880 | 4.6680 | 2.4200 |
| Aug 4, 2026 | 335.40 | 9.3070 | 6.2143 | 3.0927 |
| Aug 5, 2026 | 337.63 | 11.1512 | 7.8600 | 3.2913 |
| Aug 6, 2026 | 343.20 | 13.6532 | 9.7910 | 3.8621 |
| Aug 7, 2026 | 342.72 | 14.8423 | 11.4748 | 3.3675 |
| Aug 10, 2026 | 349.60 | 17.2272 | 13.3923 | 3.8350 |
| Aug 11, 2026 | 344.65 | 17.0348 | 14.6064 | 2.4284 |
| Aug 12, 2026 | 343.48 | 16.2732 | 15.1620 | 1.1112 |
| Aug 13, 2026 | 348.64 | 16.9257 | 15.7499 | 1.1758 |
| Aug 14, 2026 | 349.02 | 17.1286 | 16.2095 | 0.9191 |
| Aug 17, 2026 | 353.58 | 18.2059 | 16.8749 | 1.3309 |
| Aug 18, 2026 | 350.98 | 17.8247 | 17.1915 | 0.6332 |
| Aug 19, 2026 | 355.88 | 18.6158 | 17.6663 | 0.9495 |
| Aug 20, 2026 | 357.79 | 19.2997 | 18.2108 | 1.0889 |
| Aug 21, 2026 | 357.18 | 19.2035 | 18.5417 | 0.6618 |
| Aug 24, 2026 | 363.16 | 20.4484 | 19.1772 | 1.2711 |
| Aug 25, 2026 | 360.07 | 19.9952 | 19.4499 | 0.5453 |
| Aug 26, 2026 | 358.64 | 18.9423 | 19.2807 | -0.3384 |
| Aug 27, 2026 | 357.79 | 17.6925 | 18.7513 | -1.0588 |
| Aug 28, 2026 | 352.90 | 15.2197 | 17.5741 | -2.3544 |
| Aug 31, 2026 | 357.81 | 14.7447 | 16.6310 | -1.8863 |
| Sep 1, 2026 | 359.93 | 14.7615 | 16.0078 | -1.2463 |
| Sep 2, 2026 | 357.21 | 13.7431 | 15.2529 | -1.5098 |
| Sep 3, 2026 | 357.13 | 12.8252 | 14.4437 | -1.6184 |
| Sep 4, 2026 | 362.64 | 13.5404 | 14.1426 | -0.6022 |
| Sep 7, 2026 | 361.52 | 13.4288 | 13.9046 | -0.4759 |
| Sep 8, 2026 | 359.00 | 12.4098 | 13.4064 | -0.9966 |
| Sep 9, 2026 | 365.03 | 13.2134 | 13.3420 | -0.1286 |
| Sep 10, 2026 | 360.41 | 12.1914 | 12.9585 | -0.7671 |
| Sep 11, 2026 | 359.62 | 11.1027 | 12.3399 | -1.2372 |
Histogram bars are paler while they shrink; hover for the MACD, signal and histogram.
Get it
It needs theme.qwe, as every component does; or take the whole kit, quillo-ui.qwe. Each component brings its own styles to the pages that show it.
$ curl -O https://quillolang.org/components/ui/theme.qwe$ curl -O https://quillolang.org/components/ui/macd_chart.qwemain.qwe
import ui/theme.qwe use theme_cssuse ui/macd_chart.qweroute GET / = <html><head><style>{theme_css}</style></head><body class="ui-root">...</body></html>Example
The code of the preview above.
demos/macd_chart.qwe
// Prices from a seeded random walk (Park–Miller), the same on every render: `count`// candles from the day `from` on, skipping weekends, daily or hourly (10:00 to 16:00),// rounded to `places` decimals.fn macd_chart_demo_walk(seed: int, count: int, start: num, from: str, hourly: bool = false, places: int = 2) -> list { let s = seed let rnd = () => { s = s * 16807 % 2147483647 s / 2147483647 } let scale = pow(10, places) let cut = (v) => round(v * scale) / scale let p = start let day = from let hour = 10 let out = [] while len(out) < count { if date.weekday(day) <= 5 { let open = cut(p * (1 + (rnd() - 0.5) * 0.006)) let close = cut(open * (1 + (rnd() - 0.485) * (hourly ? 0.012 : 0.035))) let high = cut(max([open, close]) * (1 + rnd() * 0.01)) let low = cut(min([open, close]) * (1 - rnd() * 0.01)) let volume = round((hourly ? 90000 : 900000) * (1 + rnd() * 1.5 + abs(close - open) * 30 / open)) out = out | push({ time: hourly ? `${day}T${hour < 10 ? "0" : ""}${hour}:00:00Z` : day, open, high, low, close, volume }) p = close } if hourly && hour < 16 && date.weekday(day) <= 5 { hour += 1 } else { hour = 10 day = date.add_days(day, 1) } } out}let macd_chart_demo_daily = macd_chart_demo_walk(47, 130, 312.6, "2026-03-16")view MacdChartDemo() = <div.demo-stack> <div id="macd_chart-demo-price"> <MacdChart label="Wayne Enterprises, MACD 12 26 9" show_label={true} candles={macd_chart_demo_daily} prefix="$"/> </div> <div id="macd_chart-demo-alone"> <MacdChart label="MACD 5 35 5, on its own" show_label={true} candles={macd_chart_demo_daily} fast={5} slow={35} signal={5} price={false} macd_height={110}/> </div> <p.demo-note>Histogram bars are paler while they shrink; hover for the MACD, signal and histogram.</p> </div>Source
ui/macd_chart.qwe
// MacdChart: the MACD of closing prices: the MACD line (the fast EMA less the slow// one), its signal line (an EMA of the MACD) and the histogram of the gap between// them, green above zero and red below, paler while it shrinks. Under a price chart// by default, or on its own. CSS only: hovering shows the close, MACD, signal and// histogram at that time, and screen readers get the numbers as a table.//// <MacdChart label="ACME, MACD 12 26 9" candles={bars} prefix="$"/>// <MacdChart label="MACD 5 35 5" candles={bars} fast={5} slow={35} signal={5} price={false}/>//// candles: a list of { time, close } (OHLC candles do), oldest first, time a date or a// date-time; or closes: the numbers alone, with labels for the axis if wanted.// fast, slow and signal: the periods of the two EMAs and of the signal line (12, 26// and 9); the MACD starts at the slow-th close, the signal and histogram signal - 1// closes later. price: the price chart above (true); height: its height in pixels// (200); macd_height: the MACD pane's (130). prefix and suffix: around every price// shown ("$"); decimals: digits after the point of prices (2), and of the MACD's// values, two more. label: what the chart shows; it names it for screen readers and// captions their table. show_label also writes it above the chart.import ui/theme.qwe use ui_clslet macd_chart_css = css`.ui-macd { --ui-macd-price: light-dark(#2a78d6, #3987e5); --ui-macd-line: light-dark(#2a78d6, #3987e5); --ui-macd-signal: light-dark(#eb6834, #d95926); display: grid; gap: 10px; min-width: 0; margin: 0; font: 12px/1.3 var(--ui-font); color: var(--ui-fg); }.ui-macd-title { margin: 0; font-size: 14px; font-weight: 600; }.ui-macd-legend { display: flex; flex-wrap: wrap; gap: 4px 16px; margin: 0; padding: 0; list-style: none; color: var(--ui-muted); font-size: 13px; }.ui-macd-legend li { display: inline-flex; align-items: center; gap: 6px; }.ui-macd-key { width: 14px; height: 3px; border-radius: 2px; background: var(--c); }.ui-macd-kh { width: 10px; height: 10px; border-radius: 2px; background: linear-gradient(90deg, var(--ui-success) 50%, var(--ui-danger) 50%); }.ui-macd-cl { --c: var(--ui-macd-line); } .ui-macd-cs { --c: var(--ui-macd-signal); } .ui-macd-cp { --c: var(--ui-macd-price); }.ui-macd-up { --k: var(--ui-success); } .ui-macd-down { --k: var(--ui-danger); }.ui-macd-frame { display: grid; grid-template-columns: minmax(0, 1fr) auto; column-gap: 8px; padding-top: 8px; }.ui-macd-plot { position: relative; }.ui-macd-pane, .ui-macd-yp { position: relative; height: var(--h); }.ui-macd-ipane, .ui-macd-yi { position: relative; height: var(--ih); }.ui-macd-pane + .ui-macd-ipane, .ui-macd-yp + .ui-macd-yi { margin-top: 18px; }.ui-macd-name { position: absolute; z-index: 1; top: 2px; left: 4px; color: var(--ui-muted); font-size: 11px; font-weight: 600; pointer-events: none; }.ui-macd-grid { position: absolute; left: 0; right: 0; height: 1px; background: color-mix(in srgb, var(--ui-border) 70%, transparent); }.ui-macd-zero { background: var(--ui-strong); }.ui-macd-svg { position: absolute; z-index: 1; inset: 0; width: 100%; height: 100%; overflow: visible; pointer-events: none; }.ui-macd-svg path { fill: none; stroke: var(--c); stroke-width: 1.75; stroke-linejoin: round; stroke-linecap: round; }.ui-macd-svg .ui-macd-fill { fill: var(--ui-macd-price); stroke: none; opacity: .08; }.ui-macd-cols { position: absolute; inset: 0; display: flex; }.ui-macd-col { position: relative; flex: 1; min-width: 0; }.ui-macd-col::before { content: ""; position: absolute; top: 0; bottom: 0; left: 50%; width: 1px; background: var(--ui-strong); opacity: 0; }.ui-macd-col:hover::before { opacity: .9; }.ui-macd-hist { position: absolute; left: 18%; right: 18%; min-height: 1px; background: var(--k); }.ui-macd-fade { opacity: .45; }.ui-macd-dot { position: absolute; left: 50%; display: none; width: 7px; height: 7px; margin: -3.5px 0 0 -3.5px; border-radius: 50%; background: var(--c); box-shadow: 0 0 0 2px var(--ui-bg); }.ui-macd-col:hover .ui-macd-dot { display: block; }.ui-macd-tip { position: absolute; z-index: 20; top: 0; left: calc(50% + 10px); display: none; min-width: 150px; padding: 7px 10px; border: 1px solid var(--ui-border); border-radius: var(--ui-radius-sm); background: var(--ui-surface); box-shadow: var(--ui-shadow); color: var(--ui-fg); font-size: 12px; pointer-events: none; }.ui-macd-flip .ui-macd-tip { left: auto; right: calc(50% + 10px); }.ui-macd-col:hover .ui-macd-tip { display: block; }.ui-macd-tip strong { display: block; margin-bottom: 3px; font-weight: 600; white-space: nowrap; }.ui-macd-tip p { display: flex; align-items: center; gap: 6px; margin: 2px 0 0; color: var(--ui-muted); white-space: nowrap; }.ui-macd-tip b { margin-left: auto; padding-left: 12px; color: var(--ui-fg); font-weight: 600; font-variant-numeric: tabular-nums; }.ui-macd-tip .ui-macd-hv b { color: var(--k); }.ui-macd-y span { position: absolute; left: 0; transform: translateY(-50%); color: var(--ui-muted); font-variant-numeric: tabular-nums; white-space: nowrap; }.ui-macd-y .ui-macd-tag { z-index: 1; left: -4px; padding: 1px 4px; border-radius: 3px; background: var(--c); color: var(--ui-bg); font-weight: 600; }.ui-macd-x { position: relative; height: 16px; margin-top: 6px; }.ui-macd-x span { position: absolute; top: 0; transform: translateX(-50%); color: var(--ui-muted); white-space: nowrap; }.ui-macd-x .ui-macd-first { transform: none; }.ui-macd-x .ui-macd-end { transform: translateX(-100%); }`// n (a whole number, 0 or more) with at least `width` digits.fn macd_chart_pad(n: int, width: int) -> str { let s = str(n) len(s) < width ? repeat("0", width - len(s)) + s : s}// A whole number with commas: 1234567 is "1,234,567".fn macd_chart_group(n: int) -> str = n < 1000 ? str(n) : macd_chart_group(floor(n / 1000)) + "," + macd_chart_pad(n % 1000, 3)// A value as it reads, with commas and `places` digits after the point (up to two as// needed when that is null): 48210.5 is "48,210.50" with 2. Worked out in whole// numbers, so the server and the browser write the same text.fn macd_chart_num(v: num, places: int? = null) -> str { let digits = places == null ? 2 : (places < 0 ? 0 : (places > 6 ? 6 : places)) let scale = [1, 10, 100, 1000, 10000, 100000, 1000000][digits] let units = round(abs(v) * scale) let frac = units % scale let tail = digits == 0 || (places == null && frac == 0) ? "" : (places == null && frac % 10 == 0 ? `.${floor(frac / 10)}` : `.${macd_chart_pad(frac, digits)}`) `${v < 0 && units > 0 ? "-" : ""}${macd_chart_group(floor(units / scale))}${tail}`}// A large number, short: 1500 is "1.5k", 2000000 is "2M", 0.25 is "0.25".fn macd_chart_short(v: num) -> str { let a = abs(v) let unit = a >= 1000000000 ? 1000000000 : (a >= 1000000 ? 1000000 : (a >= 1000 ? 1000 : 1)) let tenths = round(a * 10 / unit) let mark = unit == 1000000000 ? "B" : (unit == 1000000 ? "M" : "k") unit == 1 ? macd_chart_num(v) : `${v < 0 ? "-" : ""}${macd_chart_group(floor(tenths / 10))}${tenths % 10 != 0 ? `.${tenths % 10}` : ""}${mark}`}// A change in percent, signed, to two decimals: "+1.25%", "-0.40%".fn macd_chart_signed(p: num) -> str = `${p > 0 ? "+" : (p < 0 && round(abs(p) * 100) > 0 ? "-" : "")}${macd_chart_num(abs(p), 2)}%`// A coordinate out of 100 (or a length), to two decimals.fn macd_chart_pct(n: num) -> str { let r = round(n * 100) / 100 r == floor(r) ? str(floor(r)) : str(r)}// The axis from lo to hi, widened to round ticks: about `steps` steps of 1, 2, 2.5 or 5 x 10^n.fn macd_chart_scale(lo: num, hi: num, steps: int = 5) -> map { let span = hi - lo == 0 ? (lo == 0 ? 1 : abs(lo) / 10) : hi - lo let raw = span / steps let mag = 1 while mag * 10 <= raw { mag = mag * 10 } while mag > raw { mag = mag / 10 } let r = raw / mag let step = (r <= 1 ? 1 : (r <= 2 ? 2 : (r <= 2.5 ? 2.5 : (r <= 5 ? 5 : 10)))) * mag let a = floor(lo / step + 0.000001) let b0 = ceil(hi / step - 0.000001) let b = b0 == a ? a + 1 : b0 { lo: a * step, hi: b * step, ticks: for i in range(b - a + 1) => (a + i) * step }}// A candle's time as it reads: "Mar 2, 2026" for a date, "Mar 2, 14:30" for a date-time.fn macd_chart_when(t) -> str = type_of(t) != "str" || !date.valid(t) ? str(t) : (len(t) > 10 ? date.format(t, "MMM D, HH:mm") : date.format(t, "MMM D, YYYY"))// Where the time axis is labelled: about `limit` of { i, text }, at the starts of years,// months or days when the times cross them ("2026", "Mar", "Mar 2"), else every few// candles ("14:30", "Mar 2").fn macd_chart_ticks(times: list, limit: int) -> list { let n = len(times) let thin = (idx: list) => { let step = ceil(len(idx) / limit) range(len(idx)) | filter((k) => k % step == 0) | map((k) => idx[k]) } let spaced = (fmt_at) => { let step = ceil(n / limit) range(n) | filter((i) => i % step == floor(step / 2)) | map((i) => { i, text: fmt_at(i) }) } if n == 0 { return [] } if !all(times, (t) => type_of(t) == "str" && date.valid(t)) { return spaced((i) => str(times[i])) } let days = times | map((t) => slice(t, 0, 10)) let changes = (keys: list) => range(1, n) | filter((i) => keys[i] != keys[i - 1]) let day_starts = changes(days) let month_starts = changes(days | map((d) => slice(d, 0, 7))) let year_starts = changes(days | map((d) => slice(d, 0, 4))) let picked = if any(times, (t) => len(t) > 10) { len(day_starts) >= 3 ? thin(day_starts) | map((i) => { i, text: date.format(days[i], "MMM D") }) : spaced((i) => index_of(day_starts, i) != null ? date.format(days[i], "MMM D") : date.format(times[i], "HH:mm")) } else if len(year_starts) >= 3 && len(month_starts) > limit * 2 { thin(year_starts) | map((i) => { i, text: slice(days[i], 0, 4) }) } else if len(month_starts) >= 2 { thin(month_starts) | map((i) => { i, text: index_of(year_starts, i) != null ? slice(days[i], 0, 4) : date.format(days[i], "MMM") }) } else { spaced((i) => date.format(days[i], "MMM D")) } // Starts that fall close together (a short month) keep the first. let gap = n / (limit * 1.5) reduce(picked, [], (kept, t) => len(kept) == 0 || t.i - kept[-1].i >= gap ? kept + [t] : kept)}// The simple moving average of `period` values, null until there are that many.fn macd_chart_sma(xs: list, period: int) -> list { let out = [] let total = 0 for i in range(len(xs)) { total += xs[i] if i >= period { total -= xs[i - period] } out = out | push(i + 1 >= period ? total / period : null) } out}// The exponential moving average of `period` values (k = 2 / (period + 1)), started// from the simple average of the first `period`; null before that.fn macd_chart_ema(xs: list, period: int) -> list { let k = 2 / (period + 1) let out = [] let prev = null for i in range(len(xs)) { if i + 1 == period { prev = sum(take(xs, period)) / period } else if i + 1 > period { prev = xs[i] * k + prev * (1 - k) } out = out | push(prev) } out}// The MACD of the closes: { macd, signal, hist }, three lists with null until each starts.fn macd_chart_macd(xs: list, fast: int, slow: int, signal: int) -> map { let a = macd_chart_ema(xs, fast) let b = macd_chart_ema(xs, slow) let macd = for i in range(len(xs)) => a[i] == null || b[i] == null ? null : a[i] - b[i] let start = index_of(macd | map((v) => v != null), true) let sig0 = start == null ? [] : macd_chart_ema(drop(macd, start), signal) let sig = for i in range(len(xs)) => start == null || i < start ? null : sig0[i - start] let hist = for i in range(len(xs)) => macd[i] == null || sig[i] == null ? null : macd[i] - sig[i] { macd, signal: sig, hist }}view MacdChart(candles: list = [], closes: list? = null, labels: list? = null, fast: int = 12, slow: int = 26, signal: int = 9, price: bool = true, height: int = 200, macd_height: int = 130, prefix: str = "", suffix: str = "", decimals: int = 2, label: str = "MACD chart", show_label: bool = false, class: str? = null) { style global macd_chart_css let vals = closes ?? (candles | map((c) => c.close)) let times = closes != null ? (labels ?? []) : (candles | map((c) => c.time)) let n = len(vals) let m = macd_chart_macd(vals, fast, slow, signal) let sc = macd_chart_scale(n == 0 ? 0 : min(vals), n == 0 ? 1 : max(vals), 4) let y = (v) => (sc.hi - v) * 100 / (sc.hi - sc.lo) let ind = (m.macd + m.signal + m.hist) | filter((v) => v != null) let reach = max([0.000001] + (ind | map((v) => abs(v)))) let isc = macd_chart_scale(0 - reach, reach, 6) let iy = (v) => (isc.hi - v) * 100 / (isc.hi - isc.lo) let x = (i) => (i + 0.5) * 100 / n let pct = (v) => macd_chart_pct(v) let money = (v) => `${v < 0 ? "-" : ""}${prefix}${macd_chart_num(abs(v), decimals)}${suffix}` let tick = (t) => `${t < 0 ? "-" : ""}${prefix}${macd_chart_num(abs(t))}` let fine = (v) => v == null ? "—" : macd_chart_num(v, decimals + 2) let path = (list_vals: list, at) => { let idx = range(n) | filter((i) => list_vals[i] != null) len(idx) == 0 ? "" : "M" + join(idx | map((i) => `${pct(x(i))},${pct(at(list_vals[i]))}`), " L") } let pline = path(vals, y) let when = (i) => i < len(times) ? macd_chart_when(times[i]) : `${i + 1}` let shrinking = (i) => i > 0 && m.hist[i - 1] != null && abs(m.hist[i]) < abs(m.hist[i - 1]) let last_macd = n > 0 ? m.macd[-1] : null let axis_width = max([5] + (sc.ticks | map((t) => len(tick(t)))) + (isc.ticks | map((t) => len(macd_chart_num(t)))) + [n > 0 ? len(money(vals[-1])) + 1 : 0, last_macd != null ? len(fine(last_macd)) + 1 : 0]) <figure class={ui_cls(["ui-macd", class])} aria-label={label} style={`--h: ${height}px; --ih: ${macd_height}px`}> {show_label && <figcaption.ui-macd-title>{label}</figcaption>} <ul.ui-macd-legend aria-hidden="true"> <li><span.ui-macd-key.ui-macd-cl></span>MACD ({fast}, {slow})</li> <li><span.ui-macd-key.ui-macd-cs></span>Signal ({signal})</li> <li><span.ui-macd-kh></span>Histogram</li> </ul> <div.ui-macd-frame aria-hidden="true"> <div.ui-macd-plot> {price && <div.ui-macd-pane> {for t in sc.ticks => <span.ui-macd-grid style={`top: ${pct(y(t))}%`}></span>} <svg.ui-macd-svg.ui-macd-cp viewBox="0 0 100 100" preserveAspectRatio="none"> {n > 0 && <path.ui-macd-fill d={`${pline} L${pct(x(n - 1))},100 L${pct(x(0))},100 Z`}/>} <path d={pline} vector-effect="non-scaling-stroke"/> </svg> </div>} <div.ui-macd-ipane> <span.ui-macd-name>MACD {fast} {slow} {signal}</span> {for t in isc.ticks => <span class={ui_cls(["ui-macd-grid", t == 0 && "ui-macd-zero"])} style={`top: ${pct(iy(t))}%`}></span>} <svg.ui-macd-svg viewBox="0 0 100 100" preserveAspectRatio="none"> <path.ui-macd-cl d={path(m.macd, iy)} vector-effect="non-scaling-stroke"/> <path.ui-macd-cs d={path(m.signal, iy)} vector-effect="non-scaling-stroke"/> </svg> </div> <div.ui-macd-cols> {for i in range(n) => <div class={ui_cls(["ui-macd-col", n > 1 && i >= n / 2 && "ui-macd-flip"])}> {price && <div.ui-macd-pane><span.ui-macd-dot.ui-macd-cp style={`top: ${pct(y(vals[i]))}%`}></span></div>} <div.ui-macd-ipane> {m.hist[i] != null && <span class={ui_cls(["ui-macd-hist", m.hist[i] >= 0 ? "ui-macd-up" : "ui-macd-down", shrinking(i) && "ui-macd-fade"])} style={`top: ${pct(iy(m.hist[i] > 0 ? m.hist[i] : 0))}%; height: ${pct(abs(iy(m.hist[i]) - iy(0)))}%`}></span>} {m.macd[i] != null && <span.ui-macd-dot.ui-macd-cl style={`top: ${pct(iy(m.macd[i]))}%`}></span>} </div> <span.ui-macd-tip> <strong>{when(i)}</strong> <p>Close<b>{money(vals[i])}</b></p> <p><span.ui-macd-key.ui-macd-cl></span>MACD<b>{fine(m.macd[i])}</b></p> <p><span.ui-macd-key.ui-macd-cs></span>Signal<b>{fine(m.signal[i])}</b></p> <p class={ui_cls(["ui-macd-hv", m.hist[i] != null && (m.hist[i] >= 0 ? "ui-macd-up" : "ui-macd-down")])}>Histogram<b>{fine(m.hist[i])}</b></p> </span> </div>} </div> </div> <div.ui-macd-y style={`width: ${axis_width}ch`}> {price && <div.ui-macd-yp> {for t in sc.ticks => !(n > 0 && abs(y(t) - y(vals[-1])) * height < 1400) && <span style={`top: ${pct(y(t))}%`}>{tick(t)}</span>} {n > 0 && <span.ui-macd-tag.ui-macd-cp style={`top: ${pct(y(vals[-1]))}%`}>{money(vals[-1])}</span>} </div>} <div.ui-macd-yi> {for t in isc.ticks => !(last_macd != null && abs(iy(t) - iy(last_macd)) * macd_height < 1400) && <span style={`top: ${pct(iy(t))}%`}>{t < 0 ? "-" : ""}{macd_chart_num(abs(t))}</span>} {last_macd != null && <span.ui-macd-tag.ui-macd-cl style={`top: ${pct(iy(last_macd))}%`}>{fine(last_macd)}</span>} </div> </div> <div.ui-macd-x> {len(times) == n && (for t in macd_chart_ticks(times, 7) => <span class={ui_cls([x(t.i) < 4 && "ui-macd-first", x(t.i) > 96 && "ui-macd-end"])} style={`left: ${pct(x(t.i))}%`}>{t.text}</span>)} </div> <span></span> </div> <table.ui-sr> <caption>{label}: close, MACD ({fast}, {slow}), signal ({signal}) and histogram</caption> <thead><tr><th scope="col">Time</th><th scope="col">Close</th><th scope="col">MACD</th><th scope="col">Signal</th><th scope="col">Histogram</th></tr></thead> <tbody> {for i in range(n) => <tr> <th scope="row">{when(i)}</th><td>{money(vals[i])}</td><td>{fine(m.macd[i])}</td><td>{fine(m.signal[i])}</td><td>{fine(m.hist[i])}</td> </tr>} </tbody> </table> </figure>}Related
BollingerChartPrices with Bollinger bands of a period and a number of deviations, closes outside them marked, as a line or candles.7 views · 5 downloadsCandlestickChartOHLC candles, green up and red down, with a volume pane, a date axis, moving averages and the details of each candle on hover.5 views · 7 downloadsDepthChartAn order book's bids and asks as stepped areas of the size waiting at each price or better, around the mid price, with the spread.5 views · 7 downloadsHeikinAshiChartHeikin-Ashi candles worked out from OHLC, which smooth the noise so trends show as runs of one colour, with the real close on hover.5 views · 6 downloadsLineBreakChartA three-line break chart from closing prices: lines go on while the close makes new ends, and turn only past the last three lines.5 views · 6 downloadsLiveCandlesCandles built from ticks as they come: the open candle grows, a new one starts each interval, with the last price and the time left.6 views · 6 downloads
Thread
Thread 0 posts
On MacdChart: questions, tips, corrections, and code that uses it.
No posts yet. The first one opens the thread.