mirror of
https://github.com/NicolasBohn/NexQuant.git
synced 2026-07-29 16:37:43 +00:00
Compare commits
757 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| d89fb2a82e | |||
| 976b86664f | |||
| 05b584b184 | |||
| c701a8105b | |||
| f075824a16 | |||
| 5c5508c8cc | |||
| a5c5c7172b | |||
| 58b5cc1458 | |||
| 80d81c8ea9 | |||
| 1b762ceddd | |||
| ed84b6b0a3 | |||
| 46367e15f5 | |||
| 0859b9f3a2 | |||
| e03fca3206 | |||
| 977136f1f3 | |||
| bf9efe127d | |||
| 243d5259f7 | |||
| dd10ddf9fd | |||
| a619ff999b | |||
| c215e735c2 | |||
| 0c219b81e0 | |||
| 9f793d58b3 | |||
| f0deace7a7 | |||
| 682f657637 | |||
| af5898211b | |||
| 1a1e88c47c | |||
| 9890bb4b00 | |||
| 5a3a2bf2be | |||
| 77e9f186d5 | |||
| 2187081905 | |||
| 698f89e07c | |||
| 304d3fad2e | |||
| ba76063069 | |||
| d18271275e | |||
| a4986c415c | |||
| 155675d4bf | |||
| 15e3ba9004 | |||
| 671771a626 | |||
| 63ba3296dd | |||
| 805f337fc4 | |||
| bdaa376569 | |||
| de6b7f7648 | |||
| 5bb5722921 | |||
| 1a61d51fa8 | |||
| 2b7e0c4bd0 | |||
| 311c2bf977 | |||
| 50702e254e | |||
| 543fb2c1ef | |||
| 51a5247285 | |||
| a1843a9c4e | |||
| b1029cbd5a | |||
| 0611a0846a | |||
| 4974277f1c | |||
| a7c6fca8b4 | |||
| 1091d5ea29 | |||
| 63ebdb5ada | |||
| d6ce70b551 | |||
| 628deade72 | |||
| 29c245c6e3 | |||
| 2e39700eeb | |||
| 370adbfa1e | |||
| dbaf70ce57 | |||
| 3c6f9ef76d | |||
| 0109b044a0 | |||
| 5a62b47e95 | |||
| 5b47c0ab5c | |||
| 3e60749f70 | |||
| cfa5f382aa | |||
| 9ea44be5f8 | |||
| 37e9912ac0 | |||
| bc9cee49ba | |||
| 763dff1596 | |||
| fe11ee92e6 | |||
| 2c11752a54 | |||
| 7aea9a27dc | |||
| 0c97fe4ae7 | |||
| 586349af36 | |||
| 5b3f5f66cf | |||
| 69e5c3a7de | |||
| b76abe839b | |||
| c8c8e26812 | |||
| 42ea6f106b | |||
| 7742a9e759 | |||
| 8acd24a016 | |||
| 54465d6e82 | |||
| 90f6c94d3e | |||
| 7f4e5096e8 | |||
| a294bc74e0 | |||
| e71d8f6c3c | |||
| 5c7cdf298c | |||
| 8a0a0fa3c4 | |||
| 69c630e983 | |||
| ad12fccb61 | |||
| 9986b5f9ce | |||
| eb1cefb202 | |||
| 4f5cce0607 | |||
| 495063c385 | |||
| 318acb4922 | |||
| 8340ab5d09 | |||
| 22a0c7fe56 | |||
| 02534cfd88 | |||
| 9a8426f373 | |||
| 6eef7517ad | |||
| 29a14e1e22 | |||
| 6f9843a7df | |||
| aa97d5a09d | |||
| 6b7988fba1 | |||
| 93303873d0 | |||
| d0e3fc1573 | |||
| cbedbc7d54 | |||
| 03040de35f | |||
| a73f2dbc12 | |||
| 45931b1012 | |||
| 6c179442bf | |||
| 8affbf89a9 | |||
| 8968ab8c9a | |||
| c89321f5a2 | |||
| d6990a12b8 | |||
| 86e05e6d35 | |||
| fda5c281a8 | |||
| 4f2a915da5 | |||
| ff99e4dc2c | |||
| c5beaeeaf8 | |||
| 82b037cb63 | |||
| 456ed100a0 | |||
| 0798c05cb7 | |||
| 7dbffc516d | |||
| 4509d92ea7 | |||
| 19bb2e740e | |||
| 2fea82bee7 | |||
| c68b597069 | |||
| bbb9d36f77 | |||
| e44bb2dcc1 | |||
| 08fc2dcef3 | |||
| c2759a2a0a | |||
| 05092c5c5b | |||
| d9cee55063 | |||
| fe3337d6ff | |||
| 90f6fde3d4 | |||
| 0e3dcc2d8d | |||
| aedd0a0f72 | |||
| 214da4826f | |||
| f25d729a02 | |||
| 773b7ac439 | |||
| 19dd259165 | |||
| ab52e1b65c | |||
| 959f2fa076 | |||
| f06e6986c8 | |||
| b5631b9f78 | |||
| b662f45021 | |||
| 92d007e179 | |||
| c40f22361c | |||
| e22fb84fb3 | |||
| 80c5eb209e | |||
| 67114540b1 | |||
| 8517eb4a18 | |||
| a16c79e45b | |||
| ce23e1c30b | |||
| 92e7932126 | |||
| 31752bb8f0 | |||
| 7372d1011e | |||
| a918f941dd | |||
| dee11fbd9c | |||
| 0dcc990bd4 | |||
| 3f41e868b3 | |||
| fac39e5588 | |||
| fce5342ad4 | |||
| 44ada185f4 | |||
| 6818ada2cf | |||
| 11e8acc88b | |||
| 9415113e01 | |||
| d3414ea07d | |||
| 8bd2714814 | |||
| 200764d38b | |||
| c1c1342a9e | |||
| 756dfba53f | |||
| 1f0032bc50 | |||
| 9eded6faa8 | |||
| 8783781daa | |||
| da8fbcf4ee | |||
| 22ed8b522b | |||
| 7fc5e73f76 | |||
| e30768969d | |||
| bc8e9dc23a | |||
| 1474478768 | |||
| 260b563710 | |||
| 3ef0b21350 | |||
| 473b9000b9 | |||
| 00b31fa752 | |||
| cc8ae7e1f0 | |||
| 752de9dc67 | |||
| a99276d59b | |||
| 450571e86e | |||
| 7fc9e18a71 | |||
| 031d264957 | |||
| 6da6fb5ee5 | |||
| 525b1a2136 | |||
| 61813cba67 | |||
| b33be5ed5b | |||
| 6b856e2217 | |||
| f5f3e050ab | |||
| 9a43e15bf4 | |||
| 251800396d | |||
| 5f3e382248 | |||
| fa0dbb69fe | |||
| f1e4e9900c | |||
| 203be39ad6 | |||
| 60b66aa6c9 | |||
| b91471181c | |||
| a48abf4a84 | |||
| 5b14779f69 | |||
| 8ea8817e7d | |||
| fd747fe741 | |||
| b666397786 | |||
| 31381743f7 | |||
| e564b418e1 | |||
| d1031ed24d | |||
| d66c045115 | |||
| 7b3473cf30 | |||
| 1d6e97cb99 | |||
| 3d7b2b4567 | |||
| b8a699a0df | |||
| 93b41c1414 | |||
| bb91201dd2 | |||
| e0ae91b497 | |||
| b20692cbd4 | |||
| 78e2665617 | |||
| 40f2b8f98b | |||
| b033215ca9 | |||
| 1f4432c39b | |||
| a9f0fd9786 | |||
| 05bf05ca49 | |||
| 9bba28093c | |||
| 3519b718ea | |||
| cde173688b | |||
| 68668d7a5b | |||
| 55b914fe22 | |||
| b2c1b68d51 | |||
| 14270354d1 | |||
| 7b981cbf09 | |||
| 27596473c7 | |||
| 14421c6cde | |||
| 918b0b0d43 | |||
| 4cd20a464d | |||
| 1c628c6c1a | |||
| a55af6fa00 | |||
| 824390e33c | |||
| 2171e99416 | |||
| b6ad5a6ed3 | |||
| b49505be8e | |||
| 2ed6ec53d9 | |||
| 30b52d7d57 | |||
| d753daf758 | |||
| 74cfc5b906 | |||
| 58910d2ce6 | |||
| bd258fe970 | |||
| 68bf5665f0 | |||
| a57e625b17 | |||
| d7da15c826 | |||
| ac7c2155e4 | |||
| bccf5aed8a | |||
| 5bb73ff6cb | |||
| b772fe2191 | |||
| 28f072da31 | |||
| 34e143cd66 | |||
| e73db7e0d7 | |||
| f120341c9c | |||
| 54cd73eb85 | |||
| 20bd55c3a5 | |||
| 403d7fcf80 | |||
| f5761b1f2d | |||
| d4ade36184 | |||
| 982b43e4fd | |||
| b64ab18caa | |||
| 433594297a | |||
| dff89d2950 | |||
| 0bd8366254 | |||
| 2222897b3f | |||
| fc5f295de7 | |||
| 05c7712770 | |||
| 1737aff7c9 | |||
| 464222094f | |||
| 42d15623ca | |||
| 6c20263e2e | |||
| 50e637f9cd | |||
| 1605cddb40 | |||
| 75e496d461 | |||
| 9fcd5d473e | |||
| 5f1c814355 | |||
| 21d88f38d0 | |||
| fd27842a98 | |||
| bddb5eb935 | |||
| ffc85936f1 | |||
| 241c05ccac | |||
| 50e020b75d | |||
| d1c005ff6d | |||
| 96ee62c7a2 | |||
| c321ebfbcb | |||
| 1a44a954df | |||
| 4d8e334ef8 | |||
| b7be0f35f8 | |||
| 97c1f7a021 | |||
| f362a1618d | |||
| 43703d45d2 | |||
| f06412e628 | |||
| dc2bf4b442 | |||
| 8f1f19d4b9 | |||
| 064733d82b | |||
| da7169675c | |||
| 6de33fa13b | |||
| c1085921b5 | |||
| 18de5eea43 | |||
| 13214ba5d0 | |||
| 56f3a668f2 | |||
| 75f29f0dd9 | |||
| 345a702501 | |||
| d2baa40fb1 | |||
| 216361c640 | |||
| 904f4b8523 | |||
| 59337a9050 | |||
| 0db49991cb | |||
| 34bf87c410 | |||
| f37ec32981 | |||
| f8a4d2a7b5 | |||
| cefef61d0e | |||
| 3090718ca3 | |||
| 7eb7f49f52 | |||
| c255b79da4 | |||
| 94d0eca0ca | |||
| bfdee6b692 | |||
| 732839e4bd | |||
| 98a0801a32 | |||
| e1f86d7ca0 | |||
| 5c7ceec37f | |||
| 723a3f4225 | |||
| b2d56e39e5 | |||
| 0e447a3a19 | |||
| e937f8710c | |||
| b1fce69153 | |||
| b092c24374 | |||
| 1678461f5a | |||
| 35e3156018 | |||
| 611fb28c58 | |||
| 10abb20117 | |||
| 6e96cff435 | |||
| fcf17d3292 | |||
| 4235440ff4 | |||
| 111dddda18 | |||
| 4b25dd1913 | |||
| 2453a6bff7 | |||
| f596e59bd8 | |||
| cb5127735f | |||
| 993f16a089 | |||
| 90ffb6cc8a | |||
| 17526da856 | |||
| eb597924b2 | |||
| e5b1912bfd | |||
| f19a91abfc | |||
| 7ff55f0013 | |||
| 17a901e8da | |||
| 1a19622add | |||
| 7cfeaff95b | |||
| a355b57623 | |||
| 14f7fc5e53 | |||
| 7f4c2d18c6 | |||
| d1fdfe10ea | |||
| 4546ebba98 | |||
| dd600c0b0c | |||
| 0a89784116 | |||
| cb66555a9c | |||
| 1a5aaf3fea | |||
| cff2d79c42 | |||
| ea85d5efc8 | |||
| c3f78f8bce | |||
| d54e14f1d9 | |||
| b7fcb13c33 | |||
| e1032b6a31 | |||
| ca46d11123 | |||
| f9bd19179f | |||
| ae8fc773cb | |||
| 8662211492 | |||
| 892283dc89 | |||
| 76b8f073e4 | |||
| fe7eb4cbe1 | |||
| 8c4c53339c | |||
| ef66c56c2b | |||
| e512d08439 | |||
| c6304add4a | |||
| 90d9cdd0e9 | |||
| bf719e0993 | |||
| 1726caa414 | |||
| 25af7e6cce | |||
| cbbbb4e9a5 | |||
| 450317d8fe | |||
| d62407cfbb | |||
| 09325aed89 | |||
| e0ce86b180 | |||
| 2c206e9ce5 | |||
| 80e4a2aa79 | |||
| 3da6af95bd | |||
| 62beb3a7ae | |||
| a7ec1485a7 | |||
| 992956db8e | |||
| 6fe0d75b38 | |||
| c379b9221a | |||
| effce1df15 | |||
| d57477aefa | |||
| 972d8602c2 | |||
| b3e627fb80 | |||
| 760aa3b2ac | |||
| d3c59b2f33 | |||
| 2161956315 | |||
| 46d8247697 | |||
| 8d88dbec33 | |||
| 254c8f9a49 | |||
| b2de6f3190 | |||
| 61189fbe73 | |||
| 4fff3370bd | |||
| 022a558dd1 | |||
| 5988683cd9 | |||
| a9421cb93f | |||
| ef373e1632 | |||
| a8e4e6b4ae | |||
| 216719670d | |||
| 25472fc1e3 | |||
| 8341430bc9 | |||
| f808c35c34 | |||
| f1a841ba14 | |||
| a1507aa7ab | |||
| f2a5967c12 | |||
| b3f1a10000 | |||
| dab1504b6c | |||
| a211facf79 | |||
| b8a931d0f5 | |||
| 858857a921 | |||
| 8ec00a5120 | |||
| 59cdf946a7 | |||
| 48c5dbfd4d | |||
| 455e73858e | |||
| 7fc53940fd | |||
| 1f9ae1af2e | |||
| a32cfcc116 | |||
| 3c80325aad | |||
| 5cdffe3510 | |||
| 7b865c3337 | |||
| 5a2744069c | |||
| 4f8a9aca40 | |||
| 346261c1ac | |||
| 3ea9d6744e | |||
| 1e710ebeb6 | |||
| f4c09c29a1 | |||
| 7642adc703 | |||
| 5787a546b5 | |||
| e1c310182f | |||
| 35c52bf9c4 | |||
| a885f9cfdc | |||
| 89e6a48b19 | |||
| f7c1c4fd74 | |||
| 437e8d2996 | |||
| 2d5fad409d | |||
| 0705e52d7d | |||
| b93f034b19 | |||
| 0e94e74d20 | |||
| 9c8fed3010 | |||
| f5a2ea3aa1 | |||
| ddc625f443 | |||
| 7cfd5be6ff | |||
| 4beb704b2b | |||
| 19ec34e613 | |||
| e046ce9e0e | |||
| 28dd0a0471 | |||
| a468234da1 | |||
| 725a788c34 | |||
| bbe06b9e50 | |||
| 9e14cefe65 | |||
| 43e24cc996 | |||
| 4b639452af | |||
| 7707f60bc9 | |||
| db2f5f7646 | |||
| e4c2b2537f | |||
| 2f1b393b3e | |||
| ddb2360cd8 | |||
| 0b6687dc3e | |||
| 34ef0c3a78 | |||
| 5ebeb20dc1 | |||
| b61d8847e1 | |||
| f9f46fce1b | |||
| d5f2c6a4d0 | |||
| e343a29c75 | |||
| 287e7e7e90 | |||
| 9ce243551b | |||
| cd59b55247 | |||
| aefba2046a | |||
| 3bf99ca0ee | |||
| b441fb8059 | |||
| d7c0785610 | |||
| 51b6038c2e | |||
| 1ee2f5d764 | |||
| 660371d686 | |||
| b0672baa9d | |||
| 67167041e7 | |||
| f732c39265 | |||
| d94ba1ace2 | |||
| 8dc837b731 | |||
| 05e9522f18 | |||
| 7e6e2b9c3a | |||
| 89c73fa19c | |||
| dbcf1b39de | |||
| 1e905dd426 | |||
| 087b7fa600 | |||
| 2523234d83 | |||
| 1f06e5c3cf | |||
| 003b067499 | |||
| 972bb2d99f | |||
| bfce8a6371 | |||
| b60c2cdc13 | |||
| a2f89951bb | |||
| 868dd724b3 | |||
| 9bfa0e597d | |||
| 2d1bfad557 | |||
| 696edd438c | |||
| d73f27be25 | |||
| fd8a5d1c83 | |||
| 884cef4c7d | |||
| f9a60d3b3c | |||
| 954270a5ca | |||
| f05907138a | |||
| ca6d3194d4 | |||
| a4adc96394 | |||
| 8d35befade | |||
| 597b8a37f9 | |||
| ca4e7e928b | |||
| 145e2f79e5 | |||
| fbe11fcf9b | |||
| 6aa6c74a34 | |||
| fffbd1925b | |||
| 48c227a2e0 | |||
| 25cd4eec76 | |||
| 72e7c3b83a | |||
| 204580bc52 | |||
| 5f3aff4dbe | |||
| 9d1f9ffc08 | |||
| a4d5a2d66a | |||
| ebb2a3cf75 | |||
| 88dd4390b6 | |||
| 03ade870e4 | |||
| 542d41aef4 | |||
| 68d47e1f1f | |||
| ce72d30139 | |||
| 92c46a66b6 | |||
| df1f5e9390 | |||
| 144d0f13b8 | |||
| d90ad532dc | |||
| 3b15bca356 | |||
| c6424e5250 | |||
| 34a63d4b7f | |||
| de8e310d6b | |||
| a8f1fc939c | |||
| 55256295c0 | |||
| a64e0c22b6 | |||
| 261fcfb19a | |||
| 3d13ba058d | |||
| 44d06c2f2c | |||
| 1a84b28b6e | |||
| 3c6415f85a | |||
| 089b45b3e1 | |||
| 5136ec2d57 | |||
| 50236d10d6 | |||
| 89d4f92051 | |||
| 28166fc4f5 | |||
| ce30936aca | |||
| e9eb22742a | |||
| aa05ed87bf | |||
| 44fd1563a2 | |||
| bc106cd076 | |||
| 3ee9add2d2 | |||
| f5b1a0d81a | |||
| 9c0bf60027 | |||
| 564cd26c0c | |||
| 7f10f44239 | |||
| 4b084f394f | |||
| 2f2d959efd | |||
| ec4daeb5a4 | |||
| eccc860446 | |||
| b5dc5af91e | |||
| a1399d65f1 | |||
| d82edc9c23 | |||
| 048e820d3d | |||
| 2d816035ef | |||
| 1328f45f97 | |||
| 2d5650ef8c | |||
| a75c19b17c | |||
| 05a3b67aa8 | |||
| 18ec2a259d | |||
| c12a914d39 | |||
| 97873dd1a9 | |||
| e089456cac | |||
| 59c1ace8a2 | |||
| a8b22ce3b9 | |||
| 7ff293f3f8 | |||
| d54dc4cffb | |||
| b08e8edf5d | |||
| 5a8e4f541d | |||
| 1280e681bb | |||
| 473a4e9c02 | |||
| c3298a8939 | |||
| cdc93bf630 | |||
| b39e2cc55e | |||
| 0ebc07809b | |||
| bbb4a1c41e | |||
| 4037dc821a | |||
| 0a39b1631e | |||
| 2f5db22afc | |||
| 4618d59ec3 | |||
| d2203530dc | |||
| aa1d4db6fa | |||
| cf8feecb46 | |||
| c1c3bad15d | |||
| 7437a45160 | |||
| ca39fcf320 | |||
| 6b212f1655 | |||
| 99d12e2861 | |||
| 0aa100d59a | |||
| 8b600827da | |||
| 5f948ee4bc | |||
| 23ccae68fe | |||
| ebed373e74 | |||
| 3537109143 | |||
| 363f616aae | |||
| 515fb50ce2 | |||
| 8a07dd6df6 | |||
| 3fb316bfbc | |||
| ccfa54cea1 | |||
| c0413b7a6e | |||
| b38cf35dcc | |||
| 7d02703981 | |||
| 73d098eb78 | |||
| 0a4bca5ffa | |||
| 2c1e1193be | |||
| 82a2a5d5b4 | |||
| f6dc1f4d3f | |||
| a2b96680dc | |||
| b9385f28a1 | |||
| bcd71def6c | |||
| f2f4636a33 | |||
| 7b31f735d9 | |||
| a93981a111 | |||
| 80622278bf | |||
| b1e2386400 | |||
| 0743588ef3 | |||
| c7cfd397ca | |||
| 45b7a169fe | |||
| 71d2f4adde | |||
| 8765f30352 | |||
| 0079a8b4e0 | |||
| 2d661a5d66 | |||
| 7bcb67f372 | |||
| fae883a26f | |||
| 49260d12c1 | |||
| 045bc3993b | |||
| 20738024c3 | |||
| 295ccf09b2 | |||
| 0b9d3046bf | |||
| ef4437d2dc | |||
| 5fca696be8 | |||
| fd2efcd47f | |||
| 26565d6dab | |||
| a2734fd34a | |||
| 0af2ca8211 | |||
| 25b5160185 | |||
| 0821fd4b8d | |||
| e11e175309 | |||
| b6c958b16c | |||
| 2b7837b774 | |||
| 2d4e9c41fc | |||
| 8500eba02a | |||
| b4b53ee6f7 | |||
| 2192ec1b1f | |||
| a11e2eb497 | |||
| f75b5d3ef5 | |||
| b219909135 | |||
| a485715156 | |||
| 4596388814 | |||
| a7e433cc21 | |||
| 0daa7e064b | |||
| a27b44fbbc | |||
| 15dbdb68d5 | |||
| 444a773259 | |||
| b3c57d9881 | |||
| 294579b941 | |||
| 8e737befc2 | |||
| 5b20c146bd | |||
| 26db33c75f | |||
| 73adf51fef | |||
| 6adb9faff9 | |||
| 670f8ffebd | |||
| ae2aa6e9b4 | |||
| 4b0ea172d2 | |||
| c75300e7cb | |||
| 35bb3b7e4d | |||
| 74bc047615 | |||
| 08eb29ca3b | |||
| 9029c4c801 | |||
| 032cf32ce6 | |||
| 9e2d6f3fdb | |||
| 1dbeebe6c4 | |||
| 79476a992e | |||
| d5a6a08210 | |||
| 9d7aa09f54 | |||
| 9b7d035b3f | |||
| d36a316509 | |||
| d70292959e | |||
| c9346a9377 | |||
| 87212b0310 | |||
| 848c10a8a5 | |||
| 0b250b93e9 | |||
| e6be18932d | |||
| 5f40d60f2a | |||
| b4d89b3094 | |||
| c4f5bd2f18 | |||
| 347a806f5b | |||
| c5dedc832b | |||
| 7bc2d83e75 | |||
| b1f62a475c | |||
| 601fb0186e | |||
| 95f825f4bc | |||
| a2de38462b | |||
| eb1a17e13d | |||
| a0d94a142f | |||
| 9cbb726389 | |||
| 6fb12fc753 | |||
| 033589bbe0 | |||
| 812e3921da | |||
| f84e90525e | |||
| 7a1abab73f | |||
| 903c1ed3f9 | |||
| b4ba69dacc | |||
| 22e1aa3330 | |||
| 63f7bf23da | |||
| a2f461cc81 | |||
| 5984ce22a6 | |||
| a96647b9ce | |||
| e7e365aef7 | |||
| 4b3739c5e8 | |||
| f2745c3cc0 | |||
| f2bd3355f6 | |||
| 4cb57b8f19 | |||
| b1826e0450 | |||
| 0de1201584 | |||
| 33f3dd921b | |||
| 94b624a632 | |||
| 47dc796b08 | |||
| b796b90cce | |||
| 43cb4a564b | |||
| 65bb980b22 | |||
| 51e921633b | |||
| 28e282d6c4 |
-39
@@ -1,39 +0,0 @@
|
||||
# Bandit security scanning configuration
|
||||
# This file configures which security checks to skip
|
||||
|
||||
skips:
|
||||
# B101: assert_used - assert statements are used for development
|
||||
- 'B101'
|
||||
# B104: hardcoded_bind_all_interfaces - we bind to 0.0.0.0 intentionally
|
||||
- 'B104'
|
||||
# B108: hardcoded_tmp_directory - /tmp is used intentionally for Docker volumes
|
||||
- 'B108'
|
||||
# B301: pickle - pickle is used for session serialization (internal data only)
|
||||
- 'B301'
|
||||
# B310: urllib_urlopen - used for internal URL fetching
|
||||
- 'B310'
|
||||
# B311: random - random is used for non-crypto purposes
|
||||
- 'B311'
|
||||
# B404: subprocess - subprocess is used for process management
|
||||
- 'B404'
|
||||
# B603: subprocess_without_shell_equals_true - intentional usage
|
||||
- 'B603'
|
||||
# B608: hardcoded_sql_expressions - false positive
|
||||
- 'B608'
|
||||
# B609: linux_commands_wildcard_injection - intentional usage
|
||||
- 'B609'
|
||||
# B102: exec_used - required for sandboxed strategy code evaluation
|
||||
- 'B102'
|
||||
# B602: subprocess_popen_with_shell_equals_true - intentional for Docker/Conda env setup
|
||||
- 'B602'
|
||||
# B701: jinja2_autoescape_false - internal template rendering, no user XSS exposure
|
||||
- 'B701'
|
||||
# B113: requests_without_timeout - internal API calls, timeout not critical
|
||||
- 'B113'
|
||||
# B614: pytorch_load - internal benchmark code loading .pt files from workspace only
|
||||
- 'B614'
|
||||
# B307: eval_used - internal config parsing with controlled input
|
||||
- 'B307'
|
||||
# B615: huggingface_unsafe_download - RL benchmark files use HuggingFace Hub for
|
||||
# research datasets; revision pinning is not required for benchmark reproducibility
|
||||
- 'B615'
|
||||
@@ -0,0 +1,6 @@
|
||||
[bumpversion]
|
||||
current_version = 0.0.0
|
||||
commit = True
|
||||
tag = True
|
||||
|
||||
[bumpversion:file:pyproject.toml]
|
||||
-33
@@ -1,33 +0,0 @@
|
||||
---
|
||||
engines:
|
||||
# Disable ESLint — no .eslintrc in web/ frontend directory
|
||||
eslint:
|
||||
enabled: false
|
||||
# Disable PMD — no Java code, no ruleset configured
|
||||
pmd:
|
||||
enabled: false
|
||||
# Disable Prospector — redundant with pylint
|
||||
prospector:
|
||||
enabled: false
|
||||
# Keep bandit for security scanning
|
||||
bandit:
|
||||
enabled: true
|
||||
# Keep pylint but limit scope via exclude_paths below
|
||||
pylint:
|
||||
enabled: true
|
||||
|
||||
# Global path exclusions — keeps pylint result count manageable
|
||||
# to avoid Codacy SARIF formatter IndexOutOfBoundsException (Sarif.scala:185)
|
||||
exclude_paths:
|
||||
- "web/**"
|
||||
- "git_ignore_folder/**"
|
||||
- "workspace/**"
|
||||
- "scripts/**"
|
||||
- "test/**"
|
||||
- "*.md"
|
||||
- "*.txt"
|
||||
- "*.yaml"
|
||||
- "*.yml"
|
||||
- "*.json"
|
||||
- "*.toml"
|
||||
- ".git/**"
|
||||
@@ -0,0 +1,21 @@
|
||||
module.exports = {
|
||||
extends: ["@commitlint/config-conventional"],
|
||||
rules: {
|
||||
// Configuration Format: [level, applicability, value]
|
||||
// level: Error level, usually expressed as a number:
|
||||
// 0 - disable rule
|
||||
// 1 - Warning (does not prevent commits)
|
||||
// 2 - Error (will block the commit)
|
||||
// applicability: the conditions under which the rule applies, commonly used values:
|
||||
// “always” - always apply the rule
|
||||
// “never” - never apply the rule
|
||||
// value: the specific value of the rule, e.g. a maximum length of 100.
|
||||
// Refs: https://commitlint.js.org/reference/rules-configuration.html
|
||||
"header-max-length": [2, "always", 100],
|
||||
"type-enum": [
|
||||
2,
|
||||
"always",
|
||||
["build", "chore", "ci", "docs", "feat", "fix", "perf", "refactor", "revert", "style", "test", "Release-As"]
|
||||
]
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,59 @@
|
||||
"""
|
||||
This file is a template for the .env file.
|
||||
|
||||
Please copy this file to .env and fill in the values.
|
||||
|
||||
For more information about configuration options, please refer to the documentation
|
||||
|
||||
"""
|
||||
|
||||
# ==========================================
|
||||
# Global configs:
|
||||
MAX_RETRY=10
|
||||
RETRY_WAIT_SECONDS=20
|
||||
# ==========================================
|
||||
|
||||
|
||||
# ==========================================
|
||||
# Backend Configuration
|
||||
# ==========================================
|
||||
# BACKEND=rdagent.oai.backend.LiteLLMAPIBackend
|
||||
# ==========================================
|
||||
|
||||
# ==========================================
|
||||
# Backend Configuration (choose one)
|
||||
# ==========================================
|
||||
|
||||
# 1. Set universal API key
|
||||
# CHAT_MODEL="gpt-4o"
|
||||
# EMBEDDING_MODEL="text-embedding-3-small"
|
||||
# OPENAI_API_BASE="https://your-endpoint.com/v1"
|
||||
# OPENAI_API_KEY="sk-your-api-key-here"
|
||||
|
||||
# 2. Set separate API KEY
|
||||
# Chat configuration
|
||||
OPENAI_API_KEY="sk-chat-key"
|
||||
OPENAI_API_BASE="https://xxx-litellm.com/v1"
|
||||
CHAT_MODEL='gpt-4o'
|
||||
|
||||
# Embedding configuration (using other service)
|
||||
# Use siliconflow as example, pay attention to the litellm_proxy prefix
|
||||
LITELLM_PROXY_API_KEY="sk-embedding-service-key"
|
||||
LITELLM_PROXY_API_BASE="https://api.siliconflow.cn/v1"
|
||||
EMBEDDING_MODEL="litellm_proxy/BAAI/bge-large-en-v1.5"
|
||||
# ==========================================
|
||||
|
||||
# ==========================================
|
||||
# Other Configuration
|
||||
# ==========================================
|
||||
# CHAT_AZURE_API_BASE=<for_Azure_user>
|
||||
# CHAT_AZURE_API_VERSION=<for_Azure_user>
|
||||
|
||||
# EMBEDDING_AZURE_API_BASE=<for_Azure_user>
|
||||
# EMBEDDING_AZURE_API_VERSION=<for_Azure_user>
|
||||
|
||||
# Cache Setting (Optional):
|
||||
# USE_CHAT_CACHE=True
|
||||
# USE_EMBEDDING_CACHE=True
|
||||
# Senario Configs:
|
||||
# ==========================================
|
||||
@@ -1,42 +0,0 @@
|
||||
# CODEOWNERS
|
||||
# Diese Datei definiert die Verantwortlichen für Code-Reviews
|
||||
# Siehe: https://docs.github.com/en/repositories/working-with-files/managing-files/about-code-owners
|
||||
|
||||
# Core Maintainer (Standard-Reviewer für alle Änderungen)
|
||||
* @nico
|
||||
|
||||
# RD-Agent Core-Module
|
||||
/rdagent/core/ @nico
|
||||
/rdagent/components/ @nico
|
||||
/rdagent/app/ @nico
|
||||
|
||||
# Trading-Spezifika
|
||||
/rdagent/scenarios/ @nico
|
||||
/prompts/ @nico
|
||||
|
||||
# Dokumentation
|
||||
/docs/ @nico
|
||||
/README.md @nico
|
||||
/examples/ @nico
|
||||
/CONTRIBUTING.md @nico
|
||||
/CODE_OF_CONDUCT.md @nico
|
||||
|
||||
# Konfiguration & Build
|
||||
/pyproject.toml @nico
|
||||
/requirements.txt @nico
|
||||
/setup.py @nico
|
||||
/Makefile @nico
|
||||
|
||||
# CI/CD & Security
|
||||
/.github/ @nico
|
||||
/.pre-commit-config.yaml @nico
|
||||
/.bandit.yml @nico
|
||||
/SECURITY.md @nico
|
||||
|
||||
# Dashboard & Visualization
|
||||
/dashboard/ @nico
|
||||
/web/ @nico
|
||||
|
||||
# Data Pipeline
|
||||
/data/ @nico
|
||||
/scripts/download*.py @nico
|
||||
@@ -0,0 +1,2 @@
|
||||
github:
|
||||
- MIIC-finance
|
||||
@@ -0,0 +1,51 @@
|
||||
---
|
||||
name: "\U0001F41B Bug Report"
|
||||
about: Submit a bug report to help us improve RD-Agent
|
||||
labels: bug
|
||||
|
||||
---
|
||||
|
||||
## 🐛 Bug Description
|
||||
|
||||
<!-- A clear and concise description of what the bug is. -->
|
||||
|
||||
## To Reproduce
|
||||
|
||||
Steps to reproduce the behavior:
|
||||
|
||||
1.
|
||||
2.
|
||||
3.
|
||||
|
||||
|
||||
## Expected Behavior
|
||||
|
||||
<!-- A clear and concise description of what you expected to happen. -->
|
||||
|
||||
## Screenshot
|
||||
|
||||
<!-- A screenshot of the error message or anything shouldn't appear-->
|
||||
|
||||
## Environment
|
||||
|
||||
**Note**: Users can run `rdagent collect_info` to get system information and paste it directly here.
|
||||
|
||||
- Name of current operating system:
|
||||
- Processor architecture:
|
||||
- System, version, and hardware information:
|
||||
- Version number of the system:
|
||||
- Python version:
|
||||
- Container ID:
|
||||
- Container Name:
|
||||
- Container Status:
|
||||
- Image ID used by the container:
|
||||
- Image tag used by the container:
|
||||
- Container port mapping:
|
||||
- Container Label:
|
||||
- Startup Commands:
|
||||
- RD-Agent version:
|
||||
- Package version:
|
||||
|
||||
## Additional Notes
|
||||
|
||||
<!-- Add any other information about the problem here. -->
|
||||
@@ -0,0 +1,9 @@
|
||||
---
|
||||
name: "\U0001F4D6 Documentation"
|
||||
about: Report an issue related to documentation
|
||||
|
||||
---
|
||||
|
||||
## 📖 Documentation
|
||||
|
||||
<!-- Please specify whether it's tutorial part or API reference part, and describe it.-->
|
||||
@@ -0,0 +1,25 @@
|
||||
---
|
||||
name: "\U0001F31FFeature Request"
|
||||
about: Request for a new RD-Agent feature
|
||||
labels: enhancement
|
||||
|
||||
---
|
||||
|
||||
## 🌟 Feature Description
|
||||
<!-- A clear and concise description of the feature proposal -->
|
||||
|
||||
## Motivation
|
||||
|
||||
1. Application scenario
|
||||
2. Related works (Papers, Github repos etc.):
|
||||
3. Any other relevant and important information:
|
||||
|
||||
<!-- Please describe why the feature is important. -->
|
||||
|
||||
## Alternatives
|
||||
|
||||
<!-- A short description of any alternative solutions or features you've considered. -->
|
||||
|
||||
## Additional Notes
|
||||
|
||||
<!-- Add any other context or screenshots about the feature request here. -->
|
||||
@@ -0,0 +1,10 @@
|
||||
---
|
||||
name: "❓Questions & Help"
|
||||
about: Have some questions? We can offer help.
|
||||
labels: question
|
||||
|
||||
---
|
||||
|
||||
## ❓ Questions and Help
|
||||
|
||||
We sincerely suggest you to carefully read the [documentation](http://rdagent.readthedocs.io/). After that, if you still feel puzzled, please describe the question clearly under this issue.
|
||||
@@ -1,58 +0,0 @@
|
||||
---
|
||||
name: 🐛 Bug Report
|
||||
about: Create a report to help us improve PREDIX
|
||||
title: '[Bug] '
|
||||
labels: 'bug, needs-triage'
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
## Beschreibung
|
||||
<!-- Eine klare und prägnante Beschreibung des Bugs -->
|
||||
|
||||
## Reproduktionsschritte
|
||||
<!-- Schritte zum Reproduzieren des Verhaltens -->
|
||||
|
||||
1. Schritt 1: `...`
|
||||
2. Schritt 2: `...`
|
||||
3. Schritt 3: `...`
|
||||
4. Fehler tritt auf
|
||||
|
||||
## Erwartetes Verhalten
|
||||
<!-- Eine klare Beschreibung dessen, was passieren sollte -->
|
||||
|
||||
## Tatsächliches Verhalten
|
||||
<!-- Was passiert tatsächlich? -->
|
||||
|
||||
## Environment
|
||||
|
||||
<!-- Bitte fülle die folgenden Informationen aus -->
|
||||
|
||||
- **OS:** [z.B. Linux, macOS, Windows]
|
||||
- **Python-Version:** [z.B. 3.10, 3.11]
|
||||
- **PREDIX-Version:** [z.B. v2.0.0, main-branch]
|
||||
- **Installation:** [z.B. pip, conda, from source]
|
||||
|
||||
## Logs & Screenshots
|
||||
|
||||
<!-- Füge relevante Logs oder Screenshots hinzu -->
|
||||
|
||||
<details>
|
||||
<summary>Log Output (klicken zum Aufklappen)</summary>
|
||||
|
||||
```
|
||||
Hier die Log-Ausgabe einfügen
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
## Zusätzliche Kontext
|
||||
|
||||
<!-- Weitere Informationen zum Problem -->
|
||||
|
||||
### Data Configuration
|
||||
- [ ] Ich habe sichergestellt, dass die Daten korrekt geladen sind
|
||||
- [ ] `qlib init` wurde erfolgreich ausgeführt
|
||||
|
||||
### Workaround
|
||||
<!-- Falls vorhanden: Gibt es einen Workaround? -->
|
||||
@@ -1,47 +0,0 @@
|
||||
---
|
||||
name: 💡 Feature Request
|
||||
about: Suggest an idea for PREDIX
|
||||
title: '[Feature] '
|
||||
labels: 'enhancement, needs-triage'
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
## Problem-Beschreibung
|
||||
<!-- Bezieht sich dein Feature auf ein Problem? Bitte beschreibe es -->
|
||||
<!-- Beispiel: "Ich bin immer frustriert, wenn ich..." -->
|
||||
|
||||
## Lösungsvorschlag
|
||||
<!-- Eine klare und prägnante Beschreibung dessen, was du gerne hättest -->
|
||||
|
||||
## Alternativen
|
||||
<!-- Hast du alternative Lösungen in Betracht gezogen? -->
|
||||
|
||||
## Zusätzliche Kontext
|
||||
<!-- Weitere Informationen, Screenshots oder Mockups -->
|
||||
|
||||
## Use Case
|
||||
<!-- Wie würde dieses Feature deinen Workflow verbessern? -->
|
||||
|
||||
### Checkliste
|
||||
<!-- Bitte bestätige die folgenden Punkte mit [x] -->
|
||||
|
||||
- [ ] Ich habe die [Dokumentation](https://github.com/nico/Predix/tree/main/docs) gelesen
|
||||
- [ ] Ich habe geprüft, ob dieses Feature bereits als [bestehendes Issue](https://github.com/nico/Predix/issues) existiert
|
||||
- [ ] Dieses Feature ist relevant für **Open-Source** (keine closed-source Komponenten)
|
||||
|
||||
## Impact
|
||||
|
||||
<!-- Wer würde von diesem Feature profitieren? -->
|
||||
|
||||
- [ ] Alle PREDIX-Nutzer
|
||||
- [ ] Spezifische Nutzer (z.B. FX-Trader, Qlib-Nutzer)
|
||||
- [ ] Entwickler/Contributors
|
||||
|
||||
## Priorität
|
||||
|
||||
<!-- Wie dringend ist dieses Feature? -->
|
||||
|
||||
- [ ] Niedrig (Nice-to-have)
|
||||
- [ ] Mittel (Würde den Workflow verbessern)
|
||||
- [ ] Hoch (Blockiert meine Arbeit)
|
||||
@@ -1,58 +0,0 @@
|
||||
---
|
||||
name: 📚 Documentation Improvement
|
||||
about: Suggest improvements to PREDIX documentation
|
||||
title: '[Docs] '
|
||||
labels: 'documentation'
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
## Aktueller Zustand
|
||||
<!-- Welche Seite/Welcher Teil der Dokumentation ist betroffen? -->
|
||||
|
||||
**URL/Datei:** `z.B. README.md, docs/quickstart.rst`
|
||||
|
||||
**Aktueller Inhalt:**
|
||||
<!-- Zitat oder Beschreibung des aktuellen Zustands -->
|
||||
|
||||
## Verbesserungsvorschlag
|
||||
<!-- Was sollte geändert/hinzugefügt werden? -->
|
||||
|
||||
## Beispiel/Begründung
|
||||
<!-- Warum ist diese Verbesserung notwendig? -->
|
||||
|
||||
### Art der Verbesserung
|
||||
|
||||
- [ ] Tippfehler/Grammatik
|
||||
- [ ] Fehlende Erklärung
|
||||
- [ ] Veraltetes Beispiel
|
||||
- [ ] Neues Beispiel hinzufügen
|
||||
- [ ] Struktur/Navigation verbessern
|
||||
- [ ] API-Dokumentation erweitern
|
||||
- [ ] Troubleshooting-Sektion
|
||||
|
||||
## Betroffene Nutzergruppe
|
||||
|
||||
<!-- Wer profitiert von dieser Verbesserung? -->
|
||||
|
||||
- [ ] Neueinsteiger
|
||||
- [ ] Fortgeschrittene Nutzer
|
||||
- [ ] Developers/Contributors
|
||||
- [ ] Alle
|
||||
|
||||
## Vorschlag (Optional)
|
||||
|
||||
<!-- Hast du bereits einen konkreten Formulierungsvorschlag? -->
|
||||
|
||||
<details>
|
||||
<summary>Vorgeschlagener Text (klicken zum Aufklappen)</summary>
|
||||
|
||||
```markdown
|
||||
Hier den verbesserten Text einfügen
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
## Zusätzliche Kontext
|
||||
|
||||
<!-- Weitere Informationen -->
|
||||
@@ -1,91 +1,34 @@
|
||||
# Pull Request
|
||||
<!--- Thank you for submitting a Pull Request! In order to make our work smoother. -->
|
||||
<!--- please make sure your Pull Request meets the following requirements: -->
|
||||
<!--- 1. Provide a general summary of your changes in the Title above; -->
|
||||
<!--- 2. Add appropriate prefixes to titles, such as `build:`, `chore:`, `ci:`, `docs:`, `feat:`, `fix:`, `perf:`, `refactor:`, `revert:`, `style:`, `test:`(Ref: https://www.conventionalcommits.org/). -->
|
||||
<!--- Category: -->
|
||||
<!--- Patch Updates: `fix:` -->
|
||||
<!--- Example: fix(auth): correct login validation issue -->
|
||||
<!--- minor update (introduces new functionality): `feat` -->
|
||||
<!--- Example: feature(parser): add ability to parse arrays -->
|
||||
<!--- major update(destructive update): Include BREAKING CHANGE in the commit message footer, or add `! ` in the commit footer to indicate that there is a destructive update. -->
|
||||
<!--- Example: feat(auth)! : remove support for old authentication method -->
|
||||
<!--- Other updates: `build:`, `chore:`, `ci:`, `docs:`, `perf:`, `refactor:`, `revert:`, `style:`, `test:`. -->
|
||||
|
||||
## Beschreibung
|
||||
## Description
|
||||
<!--- Describe your changes in detail -->
|
||||
|
||||
<!--
|
||||
Eine klare und prägnante Beschreibung der Änderungen.
|
||||
Beziehe dich auf das zugehörige Issue (falls vorhanden).
|
||||
-->
|
||||
## Motivation and Context
|
||||
<!--- Are there any related issues? If so, please put the link here. -->
|
||||
<!--- Why is this change required? What problem does it solve? -->
|
||||
|
||||
**Fixes:** #<!-- Issue-Nummer -->
|
||||
## How Has This Been Tested?
|
||||
<!--- Put an `x` in all the boxes that apply: --->
|
||||
- [ ] If you are adding a new feature, test on your own test scripts.
|
||||
|
||||
## Typ
|
||||
<!--- **ATTENTION**: If you are adding a new feature, please make sure your codes are **correctly tested**. If our test scripts do not cover your cases, please provide your own test scripts under the `tests` folder and test them. More information about test scripts can be found [here](https://docs.python.org/3/library/unittest.html#basic-example), or you could refer to those we provide under the `tests` folder. -->
|
||||
|
||||
<!-- Bitte zutreffendes ankreuzen [x] -->
|
||||
## Screenshots of Test Results (if appropriate):
|
||||
1. Your own tests:
|
||||
|
||||
- [ ] 🐛 Bug Fix
|
||||
- [ ] ✨ Neue Funktion
|
||||
- [ ] 📚 Dokumentation
|
||||
- [ ] 🧹 Code Cleanup/Refactoring
|
||||
- [ ] ⚡ Performance-Verbesserung
|
||||
- [ ] 🔧 Konfiguration/Build
|
||||
- [ ] 🧪 Tests
|
||||
|
||||
## Changes
|
||||
|
||||
<!-- Welche Dateien wurden geändert und warum? -->
|
||||
|
||||
- `Datei1.py`: Beschreibung der Änderung
|
||||
- `Datei2.py`: Beschreibung der Änderung
|
||||
|
||||
## Testing
|
||||
|
||||
<!-- Wie wurden die Änderungen getestet? -->
|
||||
|
||||
### Tests hinzugefügt/aktualisiert
|
||||
|
||||
- [ ] Ja, Unit Tests
|
||||
- [ ] Ja, Integration Tests
|
||||
- [ ] Nein, aber manuell getestet
|
||||
- [ ] Nicht zutreffend
|
||||
|
||||
### Testing Notes
|
||||
|
||||
<!-- Beschreibe deine Testing-Schritte -->
|
||||
|
||||
```bash
|
||||
# Beispiel: Tests ausführen
|
||||
pytest test/ -v --cov=rdagent
|
||||
|
||||
# Beispiel: CLI Command testen
|
||||
rdagent COMMAND --help
|
||||
```
|
||||
|
||||
## Checklist
|
||||
|
||||
<!-- Bitte alle zutreffenden Punkte ankreuzen [x] -->
|
||||
|
||||
- [ ] Meine Änderungen folgen dem [Coding Style](CONTRIBUTING.md)
|
||||
- [ ] Ich habe [CONTRIBUTING.md](CONTRIBUTING.md) gelesen und befolgt
|
||||
- [ ] Tests wurden hinzugefügt oder aktualisiert
|
||||
- [ ] Dokumentation wurde aktualisiert (`docs/` oder README.md)
|
||||
- [ ] CHANGELOG.md wurde aktualisiert (falls zutreffend)
|
||||
- [ ] Pre-commit Hooks bestanden (`pre-commit run --all-files`)
|
||||
- [ ] Keine closed-source Assets committen (siehe unten)
|
||||
|
||||
## ⚠️ Closed-Source Check
|
||||
|
||||
<!--
|
||||
KRITISCH: Bitte bestätige, dass KEINE der folgenden Dateien committen wurden:
|
||||
-->
|
||||
|
||||
- [ ] `git_ignore_folder/` – Trading-Skripte, OHLCV-Daten, Credentials
|
||||
- [ ] `results/` – Backtest-Ergebnisse, Strategien, Logs
|
||||
- [ ] `.env` – API-Keys, Credentials
|
||||
- [ ] `models/local/` – Eigene verbesserte Modelle
|
||||
- [ ] `prompts/local/` – Eigene verbesserte Prompts
|
||||
- [ ] `rdagent/scenarios/qlib/local/` – Closed-Source Komponenten
|
||||
- [ ] `*.db` – SQLite-Datenbanken
|
||||
- [ ] `*.log` – Log-Files
|
||||
|
||||
## Screenshots (falls relevant)
|
||||
|
||||
<!-- Vorher/Nachher-Vergleiche, UI-Änderungen etc. -->
|
||||
|
||||
| Vorher | Nachher |
|
||||
|--------|---------|
|
||||
| <!-- Screenshot --> | <!-- Screenshot --> |
|
||||
|
||||
## Zusätzliche Kontext
|
||||
|
||||
<!-- Weitere Informationen zu den Änderungen -->
|
||||
## Types of changes
|
||||
<!--- What types of changes does your code introduce? Put an `x` in all the boxes that apply: -->
|
||||
- [ ] Fix bugs
|
||||
- [ ] Add new feature
|
||||
- [ ] Update documentation
|
||||
|
||||
+16
-23
@@ -1,26 +1,19 @@
|
||||
version: 2
|
||||
updates:
|
||||
- package-ecosystem: "pip"
|
||||
directory: "/"
|
||||
- commit-message:
|
||||
prefix: build(actions)
|
||||
directory: /
|
||||
package-ecosystem: github-actions
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
day: "monday"
|
||||
time: "06:00"
|
||||
open-pull-requests-limit: 5
|
||||
labels:
|
||||
- "dependencies"
|
||||
ignore:
|
||||
# Ignore major version bumps — review manually
|
||||
- dependency-name: "*"
|
||||
update-types: ["version-update:semver-major"]
|
||||
|
||||
- package-ecosystem: "github-actions"
|
||||
directory: "/"
|
||||
interval: weekly
|
||||
- commit-message:
|
||||
prefix: build(requirements)
|
||||
directory: /
|
||||
groups:
|
||||
dev:
|
||||
dependency-type: development
|
||||
prod:
|
||||
dependency-type: production
|
||||
package-ecosystem: pip
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
day: "monday"
|
||||
time: "06:00"
|
||||
open-pull-requests-limit: 5
|
||||
labels:
|
||||
- "dependencies"
|
||||
- "github-actions"
|
||||
interval: weekly
|
||||
version: 2
|
||||
|
||||
+61
-40
@@ -1,49 +1,70 @@
|
||||
name: CI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [master, main]
|
||||
pull_request:
|
||||
branches: [master, main]
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
security-events: write
|
||||
|
||||
concurrency:
|
||||
cancel-in-progress: true
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
jobs:
|
||||
security:
|
||||
ci:
|
||||
if: ${{ !cancelled() && ! failure() }}
|
||||
needs: dependabot
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
|
||||
- name: Run Bandit (Security Scan)
|
||||
uses: PyCQA/bandit-action@v1
|
||||
- name: checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
targets: "rdagent/"
|
||||
severity: medium
|
||||
|
||||
test:
|
||||
fetch-depth: 0
|
||||
submodules: recursive
|
||||
- name: Set up Python ${{ matrix.python-version }}
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
cache: pip
|
||||
python-version: ${{ matrix.python-version }}
|
||||
- run: env | sort
|
||||
- run: make dev
|
||||
- name: lint test docs and build
|
||||
run: make lint docs-gen test-offline # test docs build
|
||||
strategy:
|
||||
matrix:
|
||||
python-version:
|
||||
- '3.10'
|
||||
- '3.11'
|
||||
dependabot:
|
||||
if: ${{ github.actor == 'dependabot[bot]' && startsWith(github.head_ref, 'dependabot/pip/') }}
|
||||
permissions:
|
||||
contents: write
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
|
||||
- uses: actions/setup-python@v6
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
python-version: "3.10"
|
||||
cache: "pip"
|
||||
|
||||
- name: Install dependencies
|
||||
fetch-depth: 0
|
||||
ref: ${{ github.head_ref }}
|
||||
- name: Set up Git
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
pip install -e ".[test]" || pip install -r requirements.txt
|
||||
pip install pytest pytest-cov
|
||||
|
||||
- name: Run unit tests (no Docker needed)
|
||||
run: |
|
||||
pytest test/backtesting/ -v --tb=short
|
||||
|
||||
- name: Upload coverage to Codecov
|
||||
uses: codecov/codecov-action@v7
|
||||
git config --global user.name github-actions
|
||||
git config --global user.email github-actions@github.com
|
||||
- name: Set up Python with multiple versions.
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
token: ${{ secrets.CODECOV_TOKEN }}
|
||||
fail_ci_if_error: false
|
||||
cache: pip
|
||||
python-version: |
|
||||
3.10
|
||||
3.11
|
||||
- name: Install pipenv using pipx
|
||||
run: pipx install pipenv
|
||||
- name: Generate constraints for all supported Python versions
|
||||
run: |
|
||||
CI= PYTHON_VERSION=3.10 make constraints
|
||||
CI= PYTHON_VERSION=3.11 make constraints
|
||||
- name: Push changes if applicable
|
||||
run: |
|
||||
if [[ -n `git status --porcelain` ]]; then
|
||||
git commit -a -m "build: Update constraints for dependabot."
|
||||
git push
|
||||
fi
|
||||
name: CI
|
||||
on:
|
||||
pull_request:
|
||||
types:
|
||||
- opened
|
||||
- synchronize
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
|
||||
@@ -1,61 +0,0 @@
|
||||
# This workflow uses actions that are not certified by GitHub.
|
||||
# They are provided by a third-party and are governed by
|
||||
# separate terms of service, privacy policy, and support
|
||||
# documentation.
|
||||
|
||||
# This workflow checks out code, performs a Codacy security scan
|
||||
# and integrates the results with the
|
||||
# GitHub Advanced Security code scanning feature. For more information on
|
||||
# the Codacy security scan action usage and parameters, see
|
||||
# https://github.com/codacy/codacy-analysis-cli-action.
|
||||
# For more information on Codacy Analysis CLI in general, see
|
||||
# https://github.com/codacy/codacy-analysis-cli.
|
||||
|
||||
name: Codacy Security Scan
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ "master" ]
|
||||
pull_request:
|
||||
# The branches below must be a subset of the branches above
|
||||
branches: [ "master" ]
|
||||
schedule:
|
||||
- cron: '45 11 * * 2'
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
codacy-security-scan:
|
||||
permissions:
|
||||
contents: read # for actions/checkout to fetch code
|
||||
security-events: write # for github/codeql-action/upload-sarif to upload SARIF results
|
||||
actions: read # only required for a private repository by github/codeql-action/upload-sarif to get the Action run status
|
||||
name: Codacy Security Scan
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
# Checkout the repository to the GitHub Actions runner
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v6
|
||||
|
||||
# Execute Codacy Analysis CLI and generate a SARIF output with the security issues identified during the analysis
|
||||
- name: Run Codacy Analysis CLI
|
||||
uses: codacy/codacy-analysis-cli-action@562ee3e92b8e92df8b67e0a5ff8aa8e261919c08
|
||||
env:
|
||||
JAVA_TOOL_OPTIONS: "-Dfile.encoding=UTF-8"
|
||||
with:
|
||||
project-token: ${{ secrets.CODACY_PROJECT_TOKEN }}
|
||||
verbose: true
|
||||
output: results.sarif
|
||||
format: sarif
|
||||
gh-code-scanning-compat: true
|
||||
max-allowed-issues: 2147483647
|
||||
# Limit to bandit only — avoids ESLint (no .eslintrc), PMD (no ruleset),
|
||||
# and pylint 14k-result SARIF crash (IndexOutOfBoundsException Sarif.scala:185)
|
||||
tool: bandit
|
||||
|
||||
# Upload the SARIF file generated in the previous step
|
||||
- name: Upload SARIF results file
|
||||
uses: github/codeql-action/upload-sarif@v4
|
||||
with:
|
||||
sarif_file: results.sarif
|
||||
@@ -1,78 +0,0 @@
|
||||
name: Conventional Commits
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
branches: [master, main]
|
||||
types: [opened, edited, synchronize, reopened]
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
pull-requests: read
|
||||
|
||||
jobs:
|
||||
check-title:
|
||||
name: Validate PR Title
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Check PR title follows Conventional Commits
|
||||
env:
|
||||
PR_TITLE: ${{ github.event.pull_request.title }}
|
||||
run: |
|
||||
echo "PR title: $PR_TITLE"
|
||||
|
||||
# Conventional Commits pattern: type(scope)!: description
|
||||
# Types: feat, fix, docs, style, refactor, perf, test, build, ci, chore, revert
|
||||
PATTERN='^(feat|fix|docs|style|refactor|perf|test|build|ci|chore|revert)(\([^)]+\))?(!)?: .{1,100}$'
|
||||
|
||||
if echo "$PR_TITLE" | grep -qE "$PATTERN"; then
|
||||
echo "✓ PR title follows Conventional Commits format"
|
||||
else
|
||||
echo "::error::PR title does not follow Conventional Commits format."
|
||||
echo ""
|
||||
echo "Expected format: type(scope): description"
|
||||
echo "Examples:"
|
||||
echo " feat: add volatility factor"
|
||||
echo " fix(optuna): fix inverted range in stage 2"
|
||||
echo " ci: add dependabot config"
|
||||
echo " chore(deps): pin aiohttp>=3.13.4"
|
||||
echo ""
|
||||
echo "Valid types: feat, fix, docs, style, refactor, perf, test, build, ci, chore, revert"
|
||||
echo ""
|
||||
echo "This is required for release-please to generate correct changelogs."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
check-commits:
|
||||
name: Validate Commit Messages
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Check commits in PR follow Conventional Commits
|
||||
env:
|
||||
BASE_SHA: ${{ github.event.pull_request.base.sha }}
|
||||
HEAD_SHA: ${{ github.event.pull_request.head.sha }}
|
||||
run: |
|
||||
PATTERN='^(feat|fix|docs|style|refactor|perf|test|build|ci|chore|revert)(\([^)]+\))?(!)?: .+'
|
||||
|
||||
FAILED=0
|
||||
while IFS= read -r msg; do
|
||||
# Skip merge commits
|
||||
if echo "$msg" | grep -qE "^Merge (pull request|branch|remote)"; then
|
||||
continue
|
||||
fi
|
||||
if ! echo "$msg" | grep -qE "$PATTERN"; then
|
||||
echo "::warning::Non-conventional commit: $msg"
|
||||
FAILED=1
|
||||
fi
|
||||
done < <(git log "$BASE_SHA..$HEAD_SHA" --format="%s")
|
||||
|
||||
if [ $FAILED -eq 1 ]; then
|
||||
echo ""
|
||||
echo "::warning::Some commits don't follow Conventional Commits."
|
||||
echo "This won't block the PR but may affect changelog generation."
|
||||
else
|
||||
echo "✓ All commits follow Conventional Commits format"
|
||||
fi
|
||||
@@ -1,86 +0,0 @@
|
||||
name: Documentation
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ main ]
|
||||
paths:
|
||||
- 'docs/**'
|
||||
- 'README.md'
|
||||
- '**/*.rst'
|
||||
- '.github/workflows/docs.yml'
|
||||
pull_request:
|
||||
branches: [ main ]
|
||||
paths:
|
||||
- 'docs/**'
|
||||
- 'README.md'
|
||||
- '**/*.rst'
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
docs:
|
||||
name: Build Documentation
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v6
|
||||
with:
|
||||
python-version: "3.10"
|
||||
|
||||
- name: Cache pip dependencies
|
||||
uses: actions/cache@v5
|
||||
with:
|
||||
path: ~/.cache/pip
|
||||
key: ${{ runner.os }}-pip-docs-${{ hashFiles('**/pyproject.toml') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-pip-docs-
|
||||
|
||||
- name: Install docs dependencies
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
pip install -e ".[docs]"
|
||||
|
||||
- name: Build Sphinx documentation
|
||||
run: |
|
||||
cd docs
|
||||
make clean
|
||||
make html SPHINXOPTS="-W --keep-going" || {
|
||||
echo "::error::Sphinx build failed with warnings"
|
||||
exit 1
|
||||
}
|
||||
|
||||
- name: Check for broken links
|
||||
run: |
|
||||
cd docs
|
||||
make linkcheck || {
|
||||
echo "::warning::Some links are broken (non-blocking)"
|
||||
exit 0
|
||||
}
|
||||
|
||||
- name: Upload docs artifact
|
||||
if: github.ref == 'refs/heads/main'
|
||||
uses: actions/upload-pages-artifact@v5
|
||||
with:
|
||||
path: docs/_build/html
|
||||
|
||||
deploy:
|
||||
name: Deploy to GitHub Pages
|
||||
needs: docs
|
||||
if: github.ref == 'refs/heads/main'
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
pages: write
|
||||
id-token: write
|
||||
environment:
|
||||
name: github-pages
|
||||
url: ${{ steps.deployment.outputs.page_url }}
|
||||
|
||||
steps:
|
||||
- name: Deploy to GitHub Pages
|
||||
id: deployment
|
||||
uses: actions/deploy-pages@v5
|
||||
@@ -1,84 +0,0 @@
|
||||
name: Code Quality
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ main, develop ]
|
||||
pull_request:
|
||||
branches: [ main ]
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
lint:
|
||||
name: Lint & Format
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v6
|
||||
with:
|
||||
python-version: "3.10"
|
||||
|
||||
- name: Cache pip dependencies
|
||||
uses: actions/cache@v5
|
||||
with:
|
||||
path: ~/.cache/pip
|
||||
key: ${{ runner.os }}-pip-lint-${{ hashFiles('**/pyproject.toml') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-pip-lint-
|
||||
|
||||
- name: Install lint dependencies
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
pip install ruff mypy
|
||||
|
||||
- name: Run Ruff (linter)
|
||||
run: |
|
||||
echo "=== Running Ruff Linter ==="
|
||||
ruff check . --statistics || {
|
||||
echo "::error::Ruff linter found issues. Run: ruff check . --fix"
|
||||
exit 1
|
||||
}
|
||||
|
||||
- name: Run Ruff (formatter)
|
||||
run: |
|
||||
echo "=== Running Ruff Formatter ==="
|
||||
ruff format --check . || {
|
||||
echo "::error::Ruff formatter found issues. Run: ruff format ."
|
||||
exit 1
|
||||
}
|
||||
|
||||
- name: Run MyPy (type checker)
|
||||
run: |
|
||||
echo "=== Running MyPy Type Checker ==="
|
||||
mypy rdagent/ \
|
||||
--ignore-missing-imports \
|
||||
--no-strict-optional \
|
||||
--follow-imports=skip \
|
||||
--warn-return-any || {
|
||||
echo "::warning::MyPy found type issues (non-blocking)"
|
||||
# Non-blocking: MyPy warnings don't fail the build
|
||||
exit 0
|
||||
}
|
||||
|
||||
- name: Check for trailing whitespace
|
||||
run: |
|
||||
echo "=== Checking for trailing whitespace ==="
|
||||
if grep -rIn '[[:space:]]$' --include='*.py' --include='*.md' --include='*.rst' . | grep -v '.git'; then
|
||||
echo "::error::Found trailing whitespace. Please remove it."
|
||||
exit 1
|
||||
fi
|
||||
echo "✓ No trailing whitespace found"
|
||||
|
||||
- name: Check for merge conflicts
|
||||
run: |
|
||||
echo "=== Checking for merge conflict markers ==="
|
||||
if grep -rn '<<<<<<< HEAD\|=======\|>>>>>>>' --include='*.py' --include='*.md' . | grep -v '.git'; then
|
||||
echo "::error::Found merge conflict markers. Please resolve them."
|
||||
exit 1
|
||||
fi
|
||||
echo "✓ No merge conflict markers found"
|
||||
@@ -0,0 +1,35 @@
|
||||
name: Lint pull request title
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
types:
|
||||
- opened
|
||||
- synchronize
|
||||
- reopened
|
||||
- edited
|
||||
|
||||
concurrency:
|
||||
cancel-in-progress: true
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
|
||||
jobs:
|
||||
lint-title:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
# This step is necessary because the lint title uses the .commitlintrc.js file in the project root directory.
|
||||
- name: Checkout Repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: '16'
|
||||
|
||||
- name: Install commitlint
|
||||
run: npm install --save-dev @commitlint/{config-conventional,cli}
|
||||
|
||||
- name: Validate PR Title with commitlint
|
||||
env:
|
||||
BODY: ${{ github.event.pull_request.title }}
|
||||
run: |
|
||||
echo "$BODY" | npx commitlint --config .commitlintrc.js
|
||||
@@ -0,0 +1,17 @@
|
||||
concurrency:
|
||||
cancel-in-progress: true
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
jobs:
|
||||
documentation-links:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: readthedocs/actions/preview@v1
|
||||
with:
|
||||
project-slug: RDAgent
|
||||
name: Read the Docs Pull Request Preview
|
||||
on:
|
||||
pull_request_target:
|
||||
types:
|
||||
- opened
|
||||
permissions:
|
||||
pull-requests: write
|
||||
@@ -1,19 +1,50 @@
|
||||
name: Release
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [master, main]
|
||||
|
||||
branches:
|
||||
- main
|
||||
permissions:
|
||||
contents: write
|
||||
pull-requests: write
|
||||
|
||||
contents: read
|
||||
jobs:
|
||||
release-please:
|
||||
release_and_publish:
|
||||
permissions:
|
||||
contents: write
|
||||
pull-requests: read
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: googleapis/release-please-action@v5
|
||||
- name: Release please
|
||||
id: release_please
|
||||
uses: googleapis/release-please-action@v4
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
config-file: release-please-config.json
|
||||
manifest-file: .release-please-manifest.json
|
||||
# The current PAT (personal access token) was created on 2024-08-05,
|
||||
# since the maximum validity of PAT is 1 year, you need to change the PAT before 2025-08-05.
|
||||
token: ${{ secrets.PAT }}
|
||||
release-type: simple
|
||||
- uses: actions/checkout@v4
|
||||
if: ${{ steps.release_please.outputs.release_created }}
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Set up Python
|
||||
if: ${{ steps.release_please.outputs.release_created }}
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
cache: pip
|
||||
python-version: '3.10'
|
||||
- name: Install dependencies
|
||||
if: ${{ steps.release_please.outputs.release_created }}
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
pip install setuptools wheel twine # better-exceptions(optional for debug)
|
||||
- run: env | sort
|
||||
if: ${{ steps.release_please.outputs.release_created }}
|
||||
- run: make dev
|
||||
if: ${{ steps.release_please.outputs.release_created }}
|
||||
- run: make build
|
||||
if: ${{ steps.release_please.outputs.release_created }}
|
||||
- name: upload
|
||||
if: ${{ steps.release_please.outputs.release_created }}
|
||||
env:
|
||||
TWINE_USERNAME: __token__
|
||||
TWINE_PASSWORD: ${{ secrets.PYPI_TOKEN }}
|
||||
run: |
|
||||
make upload
|
||||
|
||||
@@ -1,68 +0,0 @@
|
||||
name: Scheduled Tests
|
||||
|
||||
on:
|
||||
schedule:
|
||||
# Every Monday at 07:00 UTC
|
||||
- cron: "0 7 * * 1"
|
||||
workflow_dispatch: # Allow manual trigger
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
test:
|
||||
name: Weekly Test Run (Python ${{ matrix.python-version }})
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
python-version: ["3.10", "3.11"]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
|
||||
- uses: actions/setup-python@v6
|
||||
with:
|
||||
python-version: ${{ matrix.python-version }}
|
||||
cache: "pip"
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
pip install -e ".[test]" || pip install -r requirements.txt
|
||||
pip install pytest pytest-cov
|
||||
|
||||
- name: Run tests
|
||||
run: |
|
||||
pytest test/backtesting/ -v --tb=short --durations=10
|
||||
|
||||
- name: Upload results on failure
|
||||
if: failure()
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: test-results-py${{ matrix.python-version }}
|
||||
path: |
|
||||
.pytest_cache/
|
||||
retention-days: 7
|
||||
|
||||
dependency-audit:
|
||||
name: Dependency Audit
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
|
||||
- uses: actions/setup-python@v6
|
||||
with:
|
||||
python-version: "3.10"
|
||||
cache: "pip"
|
||||
|
||||
- name: Install safety
|
||||
run: pip install safety
|
||||
|
||||
- name: Check for known vulnerabilities
|
||||
run: |
|
||||
echo "=== Weekly dependency vulnerability scan ==="
|
||||
safety check -r requirements.txt --json || {
|
||||
echo "::warning::Vulnerabilities found — review and update dependencies"
|
||||
exit 0
|
||||
}
|
||||
@@ -1,155 +0,0 @@
|
||||
name: Security Scan
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ master, develop ]
|
||||
pull_request:
|
||||
branches: [ master ]
|
||||
schedule:
|
||||
# Weekly on Monday at 6:00 UTC
|
||||
- cron: '0 6 * * 1'
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
security:
|
||||
name: Security Analysis
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v6
|
||||
with:
|
||||
python-version: "3.10"
|
||||
|
||||
- name: Cache pip dependencies
|
||||
uses: actions/cache@v5
|
||||
with:
|
||||
path: ~/.cache/pip
|
||||
key: ${{ runner.os }}-pip-security-${{ hashFiles('**/requirements.txt') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-pip-security-
|
||||
|
||||
- name: Install security tools
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
pip install bandit safety
|
||||
|
||||
- name: Run Bandit (code security)
|
||||
run: |
|
||||
echo "=== Running Bandit Security Scan ==="
|
||||
bandit \
|
||||
-c .bandit.yml \
|
||||
-r rdagent/ \
|
||||
-f json \
|
||||
-o bandit-report.json \
|
||||
--exit-zero || true
|
||||
|
||||
# Show summary
|
||||
bandit -c .bandit.yml -r rdagent/ -ll || true
|
||||
|
||||
- name: Upload Bandit report
|
||||
uses: actions/upload-artifact@v7
|
||||
if: always()
|
||||
with:
|
||||
name: bandit-security-report
|
||||
path: bandit-report.json
|
||||
retention-days: 30
|
||||
|
||||
- name: Check dependencies for vulnerabilities
|
||||
run: |
|
||||
echo "=== Checking Dependencies for Vulnerabilities ==="
|
||||
safety check --json || {
|
||||
echo "::warning::Some dependencies have known vulnerabilities"
|
||||
echo "Please review and update dependencies."
|
||||
exit 0 # Non-blocking
|
||||
}
|
||||
|
||||
- name: Check for exposed secrets
|
||||
run: |
|
||||
echo "=== Scanning for Exposed Secrets ==="
|
||||
|
||||
# Check for common secret patterns
|
||||
PATTERNS=(
|
||||
"api_key\s*=\s*['\"][^'\"]+['\"]"
|
||||
"secret\s*=\s*['\"][^'\"]+['\"]"
|
||||
"password\s*=\s*['\"][^'\"]+['\"]"
|
||||
"token\s*=\s*['\"][^'\"]+['\"]"
|
||||
"PRIVATE.KEY"
|
||||
"BEGIN RSA PRIVATE KEY"
|
||||
)
|
||||
|
||||
FOUND_SECRETS=0
|
||||
for pattern in "${PATTERNS[@]}"; do
|
||||
if grep -rInE "$pattern" --include='*.py' --include='*.yml' --include='*.yaml' --include='*.json' . | \
|
||||
grep -v '.git' | \
|
||||
grep -v 'test/' | \
|
||||
grep -v 'example' | \
|
||||
grep -v '# ' | \
|
||||
grep -v 'os.environ' | \
|
||||
grep -v 'getenv' | \
|
||||
grep -v 'argparse'; then
|
||||
FOUND_SECRETS=1
|
||||
fi
|
||||
done
|
||||
|
||||
if [ $FOUND_SECRETS -eq 1 ]; then
|
||||
echo "::error::Potential secrets exposure detected!"
|
||||
echo "Please review the output above and remove any hardcoded credentials."
|
||||
echo "Use environment variables or .env files instead."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "✓ No exposed secrets found"
|
||||
|
||||
- name: Verify closed-source files not committed
|
||||
run: |
|
||||
echo "=== Verifying No Closed-Source Assets Committed ==="
|
||||
|
||||
FOUND_CLOSED=0
|
||||
|
||||
# Exact directory prefixes that must never appear (use grep -F for literal matching)
|
||||
EXACT_PREFIXES=(
|
||||
"git_ignore_folder/"
|
||||
"models/local/"
|
||||
"prompts/local/"
|
||||
"rdagent/scenarios/qlib/local/"
|
||||
)
|
||||
for prefix in "${EXACT_PREFIXES[@]}"; do
|
||||
if git ls-files | grep -qF "$prefix"; then
|
||||
echo "::error::Found closed-source asset: $prefix"
|
||||
FOUND_CLOSED=1
|
||||
fi
|
||||
done
|
||||
|
||||
# results/ — allow README.md and .gitkeep but nothing else
|
||||
if git ls-files | grep -F "results/" | grep -qvE "results/README\.md|results/\.gitkeep"; then
|
||||
echo "::error::Found closed-source asset: results/ (non-documentation file)"
|
||||
git ls-files | grep -F "results/" | grep -vE "results/README\.md|results/\.gitkeep"
|
||||
FOUND_CLOSED=1
|
||||
fi
|
||||
|
||||
# .env files — match only .env and .env.* exactly, not paths containing "env"
|
||||
if git ls-files | grep -qE "(^|/)\.env($|\.)"; then
|
||||
echo "::error::Found closed-source asset: .env file"
|
||||
FOUND_CLOSED=1
|
||||
fi
|
||||
|
||||
# Binary / data files that must never be committed
|
||||
if git ls-files | grep -qE "\.(db|h5|parquet|log)$"; then
|
||||
echo "::error::Found data/log file committed (*.db, *.h5, *.parquet, *.log)"
|
||||
git ls-files | grep -E "\.(db|h5|parquet|log)$"
|
||||
FOUND_CLOSED=1
|
||||
fi
|
||||
|
||||
if [ $FOUND_CLOSED -eq 1 ]; then
|
||||
echo "CRITICAL: Closed-source assets must not be committed to the repository!"
|
||||
echo "Please remove them and add to .gitignore if needed."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "✓ No closed-source assets found"
|
||||
+156
-120
@@ -1,144 +1,180 @@
|
||||
# ═══════════════════════════════════════════════════════════
|
||||
# PREDIX .gitignore
|
||||
# ═══════════════════════════════════════════════════════════
|
||||
# Custom
|
||||
*.swp
|
||||
.DS_Store
|
||||
Pipfile
|
||||
public
|
||||
release-notes.md
|
||||
typescript*
|
||||
|
||||
# ──────────────────────────────────────────────────────────
|
||||
# 🔒 CLOSED-SOURCE ASSETS (NIEMALS COMMITTEN!)
|
||||
# ──────────────────────────────────────────────────────────
|
||||
|
||||
# Trading scripts & raw OHLCV data
|
||||
git_ignore_folder/
|
||||
data_raw/
|
||||
|
||||
# Backtest results, strategies, logs
|
||||
results/
|
||||
*.log
|
||||
fin_quant*.log
|
||||
selector.log
|
||||
log/
|
||||
|
||||
# Credentials & environment
|
||||
.env
|
||||
.env.*
|
||||
!.env.example
|
||||
.env.backup
|
||||
.env.local
|
||||
.env.test
|
||||
*.test.env
|
||||
|
||||
# Private prompts (your improved versions)
|
||||
prompts/local/
|
||||
*.local.yaml
|
||||
*_private.yaml
|
||||
|
||||
# Private models (your improved versions)
|
||||
models/local/
|
||||
*.local.py
|
||||
*_private.py
|
||||
|
||||
# Closed source RD-Agent components
|
||||
rdagent/scenarios/qlib/local/
|
||||
|
||||
# Databases & generated data
|
||||
*.db
|
||||
*.h5
|
||||
intraday_pv*.h5
|
||||
prompt_cache.db
|
||||
|
||||
# Generated strategy files
|
||||
*.json
|
||||
!package.json
|
||||
!package-lock.json
|
||||
!pyproject.json
|
||||
|
||||
# Private test scripts
|
||||
test_credentials.py
|
||||
test/backtesting/test_smart_strategy_gen.py
|
||||
|
||||
# Private scripts (root)
|
||||
predix_quick_daytrading.py
|
||||
predix_smart_strategy_gen.py
|
||||
|
||||
# Internal docs
|
||||
TODO.md
|
||||
QWEN.md
|
||||
CLAUDE.md
|
||||
docs/COMPLETE_WORKFLOW.md
|
||||
docs/SMART_STRATEGY_GEN.md
|
||||
STARRED_REPOS_ANALYSIS.md
|
||||
|
||||
# OpenACP workspace (secrets)
|
||||
.openacp
|
||||
|
||||
# ──────────────────────────────────────────────────────────
|
||||
# 🐍 Python
|
||||
# ──────────────────────────────────────────────────────────
|
||||
|
||||
# Byte-compiled & cache
|
||||
# Byte-compiled / optimized / DLL files
|
||||
__pycache__/
|
||||
*.py[cod]
|
||||
*$py.class
|
||||
*.pyc
|
||||
.Python
|
||||
|
||||
# Distribution/packaging
|
||||
# C extensions
|
||||
*.so
|
||||
|
||||
# Distribution / packaging
|
||||
.Python
|
||||
build/
|
||||
develop-eggs/
|
||||
dist/
|
||||
*.egg-info/
|
||||
*.egg
|
||||
predix.egg-info/
|
||||
downloads/
|
||||
eggs/
|
||||
.eggs/
|
||||
lib/
|
||||
lib64/
|
||||
parts/
|
||||
sdist/
|
||||
var/
|
||||
wheels/
|
||||
pip-wheel-metadata/
|
||||
share/python-wheels/
|
||||
*.egg-info/
|
||||
.installed.cfg
|
||||
*.egg
|
||||
MANIFEST
|
||||
|
||||
# Virtual environments
|
||||
venv/
|
||||
ENV/
|
||||
env/
|
||||
.venv/
|
||||
# PyInstaller
|
||||
# Usually these files are written by a python script from a template
|
||||
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
||||
*.manifest
|
||||
*.spec
|
||||
|
||||
# ──────────────────────────────────────────────────────────
|
||||
# 🧪 Testing & Coverage
|
||||
# ──────────────────────────────────────────────────────────
|
||||
# Installer logs
|
||||
pip-log.txt
|
||||
pip-delete-this-directory.txt
|
||||
|
||||
.pytest_cache/
|
||||
.coverage
|
||||
.coverage.*
|
||||
# Unit test / coverage reports
|
||||
htmlcov/
|
||||
.tox/
|
||||
.nox/
|
||||
.coverage
|
||||
.coverage.*
|
||||
.cache
|
||||
nosetests.xml
|
||||
coverage.xml
|
||||
*.cover
|
||||
*.py,cover
|
||||
.hypothesis/
|
||||
.pytest_cache/
|
||||
|
||||
# ──────────────────────────────────────────────────────────
|
||||
# 💻 IDE & Editor
|
||||
# ──────────────────────────────────────────────────────────
|
||||
# Translations
|
||||
*.mo
|
||||
*.pot
|
||||
|
||||
.idea/
|
||||
# Django stuff:
|
||||
*.log
|
||||
/log*/
|
||||
local_settings.py
|
||||
db.sqlite3
|
||||
db.sqlite3-journal
|
||||
|
||||
# Flask stuff:
|
||||
instance/
|
||||
.webassets-cache
|
||||
|
||||
# Scrapy stuff:
|
||||
.scrapy
|
||||
|
||||
# Sphinx documentation
|
||||
docs/_build/
|
||||
|
||||
# PyBuilder
|
||||
target/
|
||||
|
||||
# Jupyter Notebook
|
||||
.ipynb_checkpoints
|
||||
|
||||
# IPython
|
||||
profile_default/
|
||||
ipython_config.py
|
||||
|
||||
# pyenv
|
||||
.python-version
|
||||
|
||||
# pipenv
|
||||
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
|
||||
# However, in case of collaboration, if having platform-specific dependencies or dependencies
|
||||
# having no cross-platform support, pipenv may install dependencies that don't work, or not
|
||||
# install all needed dependencies.
|
||||
#Pipfile.lock
|
||||
|
||||
# PEP 582; used by e.g. github.com/David-OConnor/pyflow
|
||||
__pypackages__/
|
||||
|
||||
# Celery stuff
|
||||
celerybeat-schedule
|
||||
celerybeat.pid
|
||||
|
||||
# SageMath parsed files
|
||||
*.sage.py
|
||||
|
||||
# Environments
|
||||
.env*
|
||||
*.env
|
||||
.venv
|
||||
^env/
|
||||
venv/
|
||||
ENV/
|
||||
env.bak/
|
||||
venv.bak/
|
||||
|
||||
# Spyder project settings
|
||||
.spyderproject
|
||||
.spyproject
|
||||
|
||||
# Rope project settings
|
||||
.ropeproject
|
||||
|
||||
# mkdocs documentation
|
||||
/site
|
||||
|
||||
# mypy
|
||||
.mypy_cache/
|
||||
.dmypy.json
|
||||
dmypy.json
|
||||
|
||||
# Pyre type checker
|
||||
.pyre/
|
||||
|
||||
# all pkl files
|
||||
*.pkl
|
||||
|
||||
# all h5 files
|
||||
*.h5
|
||||
|
||||
# all vs-code files
|
||||
.vscode/
|
||||
*.swp
|
||||
*.swo
|
||||
*~
|
||||
|
||||
# ──────────────────────────────────────────────────────────
|
||||
# 🗜️ Cache & Temp
|
||||
# ──────────────────────────────────────────────────────────
|
||||
# reports
|
||||
reports/
|
||||
|
||||
.cache/
|
||||
pickle_cache/
|
||||
*.so
|
||||
# git_ignore_folder
|
||||
git_ignore_folder/
|
||||
|
||||
# ──────────────────────────────────────────────────────────
|
||||
# 🏗️ Build & Reports
|
||||
# ──────────────────────────────────────────────────────────
|
||||
#cache
|
||||
*cache*/
|
||||
*cache.json
|
||||
|
||||
*.manifest
|
||||
*.spec
|
||||
..bfg-report/
|
||||
# DB files
|
||||
*.db
|
||||
|
||||
# ──────────────────────────────────────────────────────────
|
||||
# 🤖 AI Agent Workspaces (parallel runs)
|
||||
# ──────────────────────────────────────────────────────────
|
||||
# Docker
|
||||
factor_template/mlruns/
|
||||
env_tpl
|
||||
mlruns/
|
||||
|
||||
.qwen/
|
||||
RD-Agent_workspace_run*/
|
||||
AGENTS.md
|
||||
CLAUDE.md
|
||||
.claude/rdagent/components/coder/strategy_orchestrator.py
|
||||
# possible output from coder or runner
|
||||
*.pth
|
||||
*qlib_res.csv
|
||||
|
||||
# shell script
|
||||
*.out
|
||||
/*.sh
|
||||
.aider*
|
||||
rdagent/app/benchmark/factor/example.json
|
||||
|
||||
# UI Server resources
|
||||
videos/
|
||||
static/
|
||||
@@ -1,62 +0,0 @@
|
||||
# Pre-commit hooks configuration for NexQuant
|
||||
# See https://pre-commit.com for more information
|
||||
|
||||
repos:
|
||||
# ── Test Coverage Check: new modules must have tests ──────────────
|
||||
- repo: local
|
||||
hooks:
|
||||
- id: check-test-coverage
|
||||
name: Check new rdagent modules have tests
|
||||
entry: python scripts/check_test_coverage.py
|
||||
language: system
|
||||
pass_filenames: false
|
||||
always_run: true
|
||||
|
||||
# ── MyPy Ratchet: no new type errors allowed ────────────────────
|
||||
- repo: local
|
||||
hooks:
|
||||
- id: mypy-ratchet
|
||||
name: MyPy ratchet (no new type errors)
|
||||
entry: python scripts/check_mypy_ratchet.py
|
||||
language: system
|
||||
pass_filenames: false
|
||||
always_run: true
|
||||
|
||||
# ── Qlib Unit Tests (MANDATORY) ──────────────────────────────────
|
||||
- repo: local
|
||||
hooks:
|
||||
- id: qlib-unit-tests
|
||||
name: Qlib Unit Tests (~490 tests)
|
||||
entry: pytest
|
||||
language: system
|
||||
args:
|
||||
- test/qlib/
|
||||
- test/backtesting/
|
||||
- -v
|
||||
- --tb=short
|
||||
- --cov=rdagent
|
||||
- --cov-fail-under=33
|
||||
- --cov-report=term
|
||||
- --ignore=test/backtesting/test_ftmo_oos.py
|
||||
- --ignore=test/backtesting/test_kronos_adapter.py
|
||||
- --ignore=test/qlib/test_fin_quant_integration.py
|
||||
pass_filenames: false
|
||||
always_run: true
|
||||
|
||||
# ── Security Scanning (MANDATORY) ─────────────────────────────────
|
||||
- repo: local
|
||||
hooks:
|
||||
- id: bandit-security-scan
|
||||
name: Bandit Security Scan
|
||||
entry: bandit
|
||||
language: system
|
||||
args:
|
||||
- -r
|
||||
- rdagent/
|
||||
- -c
|
||||
- .bandit.yml
|
||||
- --severity-level=medium
|
||||
- --confidence-level=medium
|
||||
- --format=txt
|
||||
pass_filenames: false
|
||||
always_run: true
|
||||
@@ -1,39 +0,0 @@
|
||||
#!/bin/bash
|
||||
# Bandit Security Scanner Wrapper for Pre-Commit
|
||||
# This script runs Bandit with the correct configuration
|
||||
# Usage: .pre-commit-hooks/run_bandit.sh [files...]
|
||||
|
||||
set -e
|
||||
|
||||
BANDIT_CONFIG=".bandit.yml"
|
||||
SCAN_DIR="rdagent/"
|
||||
EXCLUDE_DIRS="test/,.git/,.qwen/,results/,git_ignore_folder/"
|
||||
EXCLUDE_FILES="rdagent/scenarios/qlib/proposal/bandit.py"
|
||||
|
||||
echo "🔒 Running Bandit Security Scanner..."
|
||||
echo " Config: ${BANDIT_CONFIG}"
|
||||
echo " Scan: ${SCAN_DIR}"
|
||||
echo ""
|
||||
|
||||
# Run bandit with high severity threshold
|
||||
# Exit code 1 if any HIGH severity issues found
|
||||
bandit \
|
||||
--configfile "${BANDIT_CONFIG}" \
|
||||
--severity-level high \
|
||||
--confidence-level medium \
|
||||
--format txt \
|
||||
--recursive "${SCAN_DIR}" \
|
||||
--exclude "${EXCLUDE_DIRS},${EXCLUDE_FILES}" \
|
||||
"$@"
|
||||
|
||||
exit_code=$?
|
||||
|
||||
if [ $exit_code -eq 0 ]; then
|
||||
echo "✅ No HIGH severity security issues found"
|
||||
else
|
||||
echo "⚠️ HIGH severity security issues detected!"
|
||||
echo " Review issues above and fix before committing."
|
||||
echo " To suppress false positives, add # nosec BXXX to the line."
|
||||
fi
|
||||
|
||||
exit $exit_code
|
||||
@@ -0,0 +1,38 @@
|
||||
# .readthedocs.yml
|
||||
# Read the Docs configuration file
|
||||
# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details
|
||||
|
||||
# Required
|
||||
version: 2
|
||||
|
||||
# Set the version of Python and other tools you might need
|
||||
build:
|
||||
os: ubuntu-22.04
|
||||
tools:
|
||||
python: "3.10"
|
||||
# During the build process, you need to fetch tags, and since the default command to read the docs only pulls shallow code, it will cause an error.
|
||||
# So we added the `git fetch --tags --unshallow || true` command to fetch the full tag record.
|
||||
# Adding this command overrides the default command, so we copied it over to make sure the build was successful.
|
||||
commands:
|
||||
- python -mvirtualenv $READTHEDOCS_VIRTUALENV_PATH
|
||||
- python -m pip install --upgrade --no-cache-dir pip setuptools
|
||||
- python -m pip install --upgrade --no-cache-dir sphinx
|
||||
- python -m pip install --exists-action=w --no-cache-dir -r requirements/docs.txt
|
||||
- python -m pip install --upgrade --upgrade-strategy only-if-needed --no-cache-dir .
|
||||
- git fetch --tags --unshallow || true
|
||||
- mkdir -p $READTHEDOCS_OUTPUT/html/
|
||||
- python -m sphinx -T -b html -d _build/doctrees -D language=en ./docs $READTHEDOCS_OUTPUT/html
|
||||
|
||||
# Build documentation in the docs/ directory with Sphinx
|
||||
sphinx:
|
||||
configuration: docs/conf.py
|
||||
|
||||
# Build all formats
|
||||
formats: all
|
||||
|
||||
# Optionally set the version of Python and requirements required to build your docs
|
||||
python:
|
||||
install:
|
||||
- requirements: requirements/docs.txt
|
||||
- method: pip
|
||||
path: .
|
||||
@@ -1 +0,0 @@
|
||||
{".": "1.5.0"}
|
||||
@@ -0,0 +1,2 @@
|
||||
[client]
|
||||
showSidebarNavigation = false
|
||||
+429
-572
File diff suppressed because it is too large
Load Diff
+6
-68
@@ -1,71 +1,9 @@
|
||||
# Contributor Covenant Code of Conduct
|
||||
# Microsoft Open Source Code of Conduct
|
||||
|
||||
## Our Pledge
|
||||
This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/).
|
||||
|
||||
We as members, contributors, and leaders pledge to make participation in our
|
||||
community a harassment-free experience for everyone, regardless of age, body
|
||||
size, visible or invisible disability, ethnicity, sex characteristics, gender
|
||||
identity and expression, level of experience, education, socio-economic status,
|
||||
nationality, personal appearance, race, religion, or sexual identity
|
||||
and orientation.
|
||||
Resources:
|
||||
|
||||
We pledge to act and interact in ways that contribute to an open, welcoming,
|
||||
diverse, inclusive, and healthy community.
|
||||
|
||||
## Our Standards
|
||||
|
||||
Examples of behavior that contributes to a positive environment for our
|
||||
community include:
|
||||
|
||||
* Demonstrating empathy and kindness toward other people
|
||||
* Being respectful of differing opinions, viewpoints, and experiences
|
||||
* Giving and gracefully accepting constructive feedback
|
||||
* Accepting responsibility and apologizing to those affected by our mistakes,
|
||||
and learning from the experience
|
||||
* Focusing on what is best not just for us as individuals, but for the
|
||||
overall community
|
||||
|
||||
Examples of unacceptable behavior include:
|
||||
|
||||
* The use of sexualized language or imagery, and sexual attention or
|
||||
advances of any kind
|
||||
* Trolling, insulting or derogatory comments, and personal or political attacks
|
||||
* Public or private harassment
|
||||
* Publishing others' private information, such as a physical or email
|
||||
address, without their explicit permission
|
||||
* Other conduct which could reasonably be considered inappropriate in a
|
||||
professional setting
|
||||
|
||||
## Enforcement Responsibilities
|
||||
|
||||
Community leaders are responsible for clarifying and enforcing our standards of
|
||||
acceptable behavior and will take appropriate and fair corrective action in
|
||||
response to any behavior that they deem inappropriate, threatening, offensive,
|
||||
or harmful.
|
||||
|
||||
## Scope
|
||||
|
||||
This Code of Conduct applies within all community spaces, and also applies when
|
||||
an individual is officially representing the community in public spaces.
|
||||
|
||||
## Enforcement
|
||||
|
||||
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
||||
reported to the community leaders responsible for enforcement at
|
||||
nico@nexquant.io.
|
||||
All complaints will be reviewed and investigated promptly and fairly.
|
||||
|
||||
## Attribution
|
||||
|
||||
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
|
||||
version 2.0, available at
|
||||
https://www.contributor-covenant.org/version/2/0/code_of_conduct.html.
|
||||
|
||||
Community Impact Guidelines were inspired by [Mozilla's code of conduct
|
||||
enforcement ladder](https://github.com/mozilla/diversity).
|
||||
|
||||
[homepage]: https://www.contributor-covenant.org
|
||||
|
||||
For answers to common questions about this code of conduct, see the FAQ at
|
||||
https://www.contributor-covenant.org/faq. Translations are available at
|
||||
https://www.contributor-covenant.org/translations.
|
||||
- [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/)
|
||||
- [Microsoft Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/)
|
||||
- Contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with questions or concerns
|
||||
|
||||
+34
-150
@@ -1,166 +1,50 @@
|
||||
# Contributing to NexQuant
|
||||
# Contributing to RD-Agent
|
||||
|
||||
We welcome contributions and suggestions to improve NexQuant. Whether it's solving an issue, addressing a bug, enhancing documentation, or even correcting a typo, every contribution is valuable and helps improve the project.
|
||||
We welcome contributions and suggestions to improve RD-Agent. Whether it's solving an issue, addressing a bug, enhancing documentation, or even correcting a typo, every contribution is valuable and helps improve the project.
|
||||
|
||||
## Getting Started
|
||||
|
||||
To get started, you can explore the issues list or search for `TODO:` comments in the codebase by running:
|
||||
To get started, you can explore the issues list or search for `TODO:` comments in the codebase by running the command:
|
||||
```sh
|
||||
grep -r "TODO:"
|
||||
```
|
||||
|
||||
## Development Workflow
|
||||
## How to Contribute
|
||||
|
||||
### 1. Fork and Clone
|
||||
1. **Fork the Repository**: Create a fork of the repository on GitHub.
|
||||
2. **Clone the Repository**: Clone your forked repository to your local machine.
|
||||
```sh
|
||||
git clone https://github.com/your-username/RD-Agent.git
|
||||
```
|
||||
3. **Create a Branch**: Create a new branch for your changes.
|
||||
```sh
|
||||
git checkout -b feature/your-feature-name
|
||||
```
|
||||
4. **Make Changes**: Make your changes to the codebase.
|
||||
5. **Commit Changes**: Commit your changes with a descriptive commit message.
|
||||
```sh
|
||||
git commit -m "Description of your changes"
|
||||
```
|
||||
6. **Push Changes**: Push your changes to your forked repository.
|
||||
```sh
|
||||
git push origin feature/your-feature-name
|
||||
```
|
||||
7. **Ensure CI Passes**: Make sure your code passes the automatic CI checks on GitHub.
|
||||
8. **Create a Pull Request**: Create a pull request from your forked repository to the main repository.
|
||||
|
||||
```bash
|
||||
# Fork the repository on GitHub, then clone your fork
|
||||
git clone https://github.com/YOUR-USERNAME/NexQuant.git
|
||||
cd NexQuant
|
||||
## Code of Conduct
|
||||
|
||||
# Add upstream remote
|
||||
git remote add upstream https://github.com/TPTBusiness/NexQuant.git
|
||||
```
|
||||
Please adhere to the [Code of Conduct](CODE_OF_CONDUCT.md) in all your interactions with the project.
|
||||
|
||||
### 2. Create a Branch
|
||||
## Reporting Issues
|
||||
|
||||
```bash
|
||||
# Use conventional commit prefixes in branch names
|
||||
git checkout -b feat/your-feature-name
|
||||
# or
|
||||
git checkout -b fix/bug-description
|
||||
git checkout -b docs/documentation-update
|
||||
git checkout -b refactor/code-cleanup
|
||||
```
|
||||
If you encounter any issues or have suggestions for improvements, please open an issue on GitHub.
|
||||
|
||||
**Branch naming convention:**
|
||||
- `feat/` - New features
|
||||
- `fix/` - Bug fixes
|
||||
- `docs/` - Documentation changes
|
||||
- `refactor/` - Code refactoring
|
||||
- `test/` - Test additions/fixes
|
||||
- `chore/` - Maintenance tasks
|
||||
## Guidelines
|
||||
|
||||
### 3. Make Your Changes
|
||||
- Ensure your code follows the project's coding standards.
|
||||
- Write clear and concise commit messages.
|
||||
- Update documentation as needed.
|
||||
- Test your changes thoroughly before submitting a pull request.
|
||||
|
||||
Follow the project conventions:
|
||||
|
||||
- **Code style**: Use type hints, docstrings (Google style), and 120 char line limit
|
||||
- **Language**: All comments and documentation MUST be in English
|
||||
- **Structure**: Follow the existing module structure
|
||||
|
||||
### 4. Write Tests
|
||||
|
||||
**MANDATORY:** All new features MUST have tests with >80% coverage.
|
||||
|
||||
```bash
|
||||
# Run tests
|
||||
pytest test/ -v
|
||||
|
||||
# Run with coverage
|
||||
pytest --cov=rdagent --cov-report=html
|
||||
|
||||
# Run integration tests
|
||||
pytest test/integration/ -v
|
||||
```
|
||||
|
||||
### 5. Run Pre-commit Hooks
|
||||
|
||||
Pre-commit hooks run automatically before EVERY commit:
|
||||
|
||||
```bash
|
||||
# Install pre-commit
|
||||
pre-commit install
|
||||
|
||||
# Run manually
|
||||
pre-commit run --all-files
|
||||
```
|
||||
|
||||
### 6. Commit Your Changes
|
||||
|
||||
Use [Conventional Commits](https://www.conventionalcommits.org/) format:
|
||||
|
||||
```bash
|
||||
git commit -m "type: description"
|
||||
|
||||
# Types:
|
||||
# feat: New feature
|
||||
# fix: Bug fix
|
||||
# docs: Documentation
|
||||
# style: Formatting
|
||||
# refactor: Code restructuring
|
||||
# test: Tests
|
||||
# chore: Maintenance
|
||||
```
|
||||
|
||||
**Examples:**
|
||||
```bash
|
||||
git commit -m "feat: Add Optuna hyperparameter optimization"
|
||||
git commit -m "fix: Resolve database connection timeout"
|
||||
git commit -m "docs: Update README with new CLI commands"
|
||||
git commit -m "test: Add integration tests for portfolio optimizer"
|
||||
```
|
||||
|
||||
### 7. Push and Create a Pull Request
|
||||
|
||||
```bash
|
||||
git push origin your-branch-name
|
||||
```
|
||||
|
||||
Then open a Pull Request on GitHub with:
|
||||
- Clear title (use conventional commit format)
|
||||
- Description of changes
|
||||
- Link to related issues
|
||||
- Screenshots (for UI changes)
|
||||
|
||||
## Code Review Process
|
||||
|
||||
All PRs are reviewed by maintainers. Expect:
|
||||
- Automated checks (tests, linting, security scan)
|
||||
- Code review by maintainers
|
||||
- Possible requested changes
|
||||
|
||||
## Important Rules
|
||||
|
||||
### 🚫 NEVER COMMIT
|
||||
|
||||
- `.env` files or API keys
|
||||
- Generated data (`results/`, `*.db`, `*.log`)
|
||||
- Closed-source assets (`models/local/`, `prompts/local/`)
|
||||
- JSON strategy files in root directory
|
||||
- Private credentials or tokens
|
||||
|
||||
### ✅ ALWAYS DO
|
||||
|
||||
- Write tests for new features
|
||||
- Update documentation for user-visible changes
|
||||
- Run `pre-commit run --all-files` before pushing
|
||||
- Keep commit messages in English
|
||||
- Follow conventional commit format
|
||||
|
||||
## Project Structure
|
||||
|
||||
```
|
||||
NexQuant/
|
||||
├── rdagent/ # Core framework (open source)
|
||||
│ ├── app/ # CLI and scenario apps
|
||||
│ ├── components/ # Reusable agent components
|
||||
│ └── scenarios/ # Domain-specific scenarios
|
||||
├── test/ # Test suite
|
||||
├── docs/ # Documentation
|
||||
├── scripts/ # Utility scripts
|
||||
├── prompts/ # LLM prompts
|
||||
├── models/ # ML models (standard only)
|
||||
├── constraints/ # Python version constraints
|
||||
└── requirements/ # Dependency files
|
||||
```
|
||||
|
||||
## Need Help?
|
||||
|
||||
- **Issues**: [GitHub Issues](https://github.com/TPTBusiness/NexQuant/issues)
|
||||
- **Discussions**: [GitHub Discussions](https://github.com/TPTBusiness/NexQuant/discussions)
|
||||
- **Documentation**: See `docs/` folder
|
||||
|
||||
## License
|
||||
|
||||
By contributing, you agree that your contributions will be licensed under the MIT License.
|
||||
Thank you for contributing to RD-Agent!
|
||||
|
||||
@@ -1,662 +1,21 @@
|
||||
GNU AFFERO GENERAL PUBLIC LICENSE
|
||||
Version 3, 19 November 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The GNU Affero General Public License is a free, copyleft license for
|
||||
software and other kinds of works, specifically designed to ensure
|
||||
cooperation with the community in the case of network server software.
|
||||
|
||||
The licenses for most software and other practical works are designed
|
||||
to take away your freedom to share and change the works. By contrast,
|
||||
our General Public Licenses are intended to guarantee your freedom to
|
||||
share and change all versions of a program--to make sure it remains free
|
||||
software for all its users.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
them if you wish), that you receive source code or can get it if you
|
||||
want it, that you can change the software or use pieces of it in new
|
||||
free programs, and that you know you can do these things.
|
||||
|
||||
Developers that use our General Public Licenses protect your rights
|
||||
with two steps: (1) assert copyright on the software, and (2) offer
|
||||
you this License which gives you legal permission to copy, distribute
|
||||
and/or modify the software.
|
||||
|
||||
A secondary benefit of defending all users' freedom is that
|
||||
improvements made in alternate versions of the program, if they
|
||||
receive widespread use, become available for other developers to
|
||||
incorporate. Many developers of free software are heartened and
|
||||
encouraged by the resulting cooperation. However, in the case of
|
||||
software used on network servers, this result may fail to come about.
|
||||
The GNU General Public License permits making a modified version and
|
||||
letting the public access it on a server without ever releasing its
|
||||
source code to the public.
|
||||
|
||||
The GNU Affero General Public License is designed specifically to
|
||||
ensure that, in such cases, the modified source code becomes available
|
||||
to the community. It requires the operator of a network server to
|
||||
provide the source code of the modified version running there to the
|
||||
users of that server. Therefore, public use of a modified version, on
|
||||
a publicly accessible server, gives the public access to the source
|
||||
code of the modified version.
|
||||
|
||||
An older license, called the Affero General Public License and
|
||||
published by Affero, was designed to accomplish similar goals. This is
|
||||
a different license, not a version of the Affero GPL, but Affero has
|
||||
released a new version of the Affero GPL which permits relicensing under
|
||||
this license.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
TERMS AND CONDITIONS
|
||||
|
||||
0. Definitions.
|
||||
|
||||
"This License" refers to version 3 of the GNU Affero General Public License.
|
||||
|
||||
"Copyright" also means copyright-like laws that apply to other kinds of
|
||||
works, such as semiconductor masks.
|
||||
|
||||
"The Program" refers to any copyrightable work licensed under this
|
||||
License. Each licensee is addressed as "you". "Licensees" and
|
||||
"recipients" may be individuals or organizations.
|
||||
|
||||
To "modify" a work means to copy from or adapt all or part of the work
|
||||
in a fashion requiring copyright permission, other than the making of an
|
||||
exact copy. The resulting work is called a "modified version" of the
|
||||
earlier work or a work "based on" the earlier work.
|
||||
|
||||
A "covered work" means either the unmodified Program or a work based
|
||||
on the Program.
|
||||
|
||||
To "propagate" a work means to do anything with it that, without
|
||||
permission, would make you directly or secondarily liable for
|
||||
infringement under applicable copyright law, except executing it on a
|
||||
computer or modifying a private copy. Propagation includes copying,
|
||||
distribution (with or without modification), making available to the
|
||||
public, and in some countries other activities as well.
|
||||
|
||||
To "convey" a work means any kind of propagation that enables other
|
||||
parties to make or receive copies. Mere interaction with a user through
|
||||
a computer network, with no transfer of a copy, is not conveying.
|
||||
|
||||
An interactive user interface displays "Appropriate Legal Notices"
|
||||
to the extent that it includes a convenient and prominently visible
|
||||
feature that (1) displays an appropriate copyright notice, and (2)
|
||||
tells the user that there is no warranty for the work (except to the
|
||||
extent that warranties are provided), that licensees may convey the
|
||||
work under this License, and how to view a copy of this License. If
|
||||
the interface presents a list of user commands or options, such as a
|
||||
menu, a prominent item in the list meets this criterion.
|
||||
|
||||
1. Source Code.
|
||||
|
||||
The "source code" for a work means the preferred form of the work
|
||||
for making modifications to it. "Object code" means any non-source
|
||||
form of a work.
|
||||
|
||||
A "Standard Interface" means an interface that either is an official
|
||||
standard defined by a recognized standards body, or, in the case of
|
||||
interfaces specified for a particular programming language, one that
|
||||
is widely used among developers working in that language.
|
||||
|
||||
The "System Libraries" of an executable work include anything, other
|
||||
than the work as a whole, that (a) is included in the normal form of
|
||||
packaging a Major Component, but which is not part of that Major
|
||||
Component, and (b) serves only to enable use of the work with that
|
||||
Major Component, or to implement a Standard Interface for which an
|
||||
implementation is available to the public in source code form. A
|
||||
"Major Component", in this context, means a major essential component
|
||||
(kernel, window system, and so on) of the specific operating system
|
||||
(if any) on which the executable work runs, or a compiler used to
|
||||
produce the work, or an object code interpreter used to run it.
|
||||
|
||||
The "Corresponding Source" for a work in object code form means all
|
||||
the source code needed to generate, install, and (for an executable
|
||||
work) run the object code and to modify the work, including scripts to
|
||||
control those activities. However, it does not include the work's
|
||||
System Libraries, or general-purpose tools or generally available free
|
||||
programs which are used unmodified in performing those activities but
|
||||
which are not part of the work. For example, Corresponding Source
|
||||
includes interface definition files associated with source files for
|
||||
the work, and the source code for shared libraries and dynamically
|
||||
linked subprograms that the work is specifically designed to require,
|
||||
such as by intimate data communication or control flow between those
|
||||
subprograms and other parts of the work.
|
||||
|
||||
The Corresponding Source need not include anything that users
|
||||
can regenerate automatically from other parts of the Corresponding
|
||||
Source.
|
||||
|
||||
The Corresponding Source for a work in source code form is that
|
||||
same work.
|
||||
|
||||
2. Basic Permissions.
|
||||
|
||||
All rights granted under this License are granted for the term of
|
||||
copyright on the Program, and are irrevocable provided the stated
|
||||
conditions are met. This License explicitly affirms your unlimited
|
||||
permission to run the unmodified Program. The output from running a
|
||||
covered work is covered by this License only if the output, given its
|
||||
content, constitutes a covered work. This License acknowledges your
|
||||
rights of fair use or other equivalent, as provided by copyright law.
|
||||
|
||||
You may make, run and propagate covered works that you do not
|
||||
convey, without conditions so long as your license otherwise remains
|
||||
in force. You may convey covered works to others for the sole purpose
|
||||
of having them make modifications exclusively for you, or provide you
|
||||
with facilities for running those works, provided that you comply with
|
||||
the terms of this License in conveying all material for which you do
|
||||
not control copyright. Those thus making or running the covered works
|
||||
for you must do so exclusively on your behalf, under your direction
|
||||
and control, on terms that prohibit them from making any copies of
|
||||
your copyrighted material outside their relationship with you.
|
||||
|
||||
Conveying under any other circumstances is permitted solely under
|
||||
the conditions stated below. Sublicensing is not allowed; section 10
|
||||
makes it unnecessary.
|
||||
|
||||
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
|
||||
|
||||
No covered work shall be deemed part of an effective technological
|
||||
measure under any applicable law fulfilling obligations under article
|
||||
11 of the WIPO copyright treaty adopted on 20 December 1996, or
|
||||
similar laws prohibiting or restricting circumvention of such
|
||||
measures.
|
||||
|
||||
When you convey a covered work, you waive any legal power to forbid
|
||||
circumvention of technological measures to the extent such circumvention
|
||||
is effected by exercising rights under this License with respect to
|
||||
the covered work, and you disclaim any intention to limit operation or
|
||||
modification of the work as a means of enforcing, against the work's
|
||||
users, your or third parties' legal rights to forbid circumvention of
|
||||
technological measures.
|
||||
|
||||
4. Conveying Verbatim Copies.
|
||||
|
||||
You may convey verbatim copies of the Program's source code as you
|
||||
receive it, in any medium, provided that you conspicuously and
|
||||
appropriately publish on each copy an appropriate copyright notice;
|
||||
keep intact all notices stating that this License and any
|
||||
non-permissive terms added in accord with section 7 apply to the code;
|
||||
keep intact all notices of the absence of any warranty; and give all
|
||||
recipients a copy of this License along with the Program.
|
||||
|
||||
You may charge any price or no price for each copy that you convey,
|
||||
and you may offer support or warranty protection for a fee.
|
||||
|
||||
5. Conveying Modified Source Versions.
|
||||
|
||||
You may convey a work based on the Program, or the modifications to
|
||||
produce it from the Program, in the form of source code under the
|
||||
terms of section 4, provided that you also meet all of these conditions:
|
||||
|
||||
a) The work must carry prominent notices stating that you modified
|
||||
it, and giving a relevant date.
|
||||
|
||||
b) The work must carry prominent notices stating that it is
|
||||
released under this License and any conditions added under section
|
||||
7. This requirement modifies the requirement in section 4 to
|
||||
"keep intact all notices".
|
||||
|
||||
c) You must license the entire work, as a whole, under this
|
||||
License to anyone who comes into possession of a copy. This
|
||||
License will therefore apply, along with any applicable section 7
|
||||
additional terms, to the whole of the work, and all its parts,
|
||||
regardless of how they are packaged. This License gives no
|
||||
permission to license the work in any other way, but it does not
|
||||
invalidate such permission if you have separately received it.
|
||||
|
||||
d) If the work has interactive user interfaces, each must display
|
||||
Appropriate Legal Notices; however, if the Program has interactive
|
||||
interfaces that do not display Appropriate Legal Notices, your
|
||||
work need not make them do so.
|
||||
|
||||
A compilation of a covered work with other separate and independent
|
||||
works, which are not by their nature extensions of the covered work,
|
||||
and which are not combined with it such as to form a larger program,
|
||||
in or on a volume of a storage or distribution medium, is called an
|
||||
"aggregate" if the compilation and its resulting copyright are not
|
||||
used to limit the access or legal rights of the compilation's users
|
||||
beyond what the individual works permit. Inclusion of a covered work
|
||||
in an aggregate does not cause this License to apply to the other
|
||||
parts of the aggregate.
|
||||
|
||||
6. Conveying Non-Source Forms.
|
||||
|
||||
You may convey a covered work in object code form under the terms
|
||||
of sections 4 and 5, provided that you also convey the
|
||||
machine-readable Corresponding Source under the terms of this License,
|
||||
in one of these ways:
|
||||
|
||||
a) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by the
|
||||
Corresponding Source fixed on a durable physical medium
|
||||
customarily used for software interchange.
|
||||
|
||||
b) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by a
|
||||
written offer, valid for at least three years and valid for as
|
||||
long as you offer spare parts or customer support for that product
|
||||
model, to give anyone who possesses the object code either (1) a
|
||||
copy of the Corresponding Source for all the software in the
|
||||
product that is covered by this License, on a durable physical
|
||||
medium customarily used for software interchange, for a price no
|
||||
more than your reasonable cost of physically performing this
|
||||
conveying of source, or (2) access to copy the
|
||||
Corresponding Source from a network server at no charge.
|
||||
|
||||
c) Convey individual copies of the object code with a copy of the
|
||||
written offer to provide the Corresponding Source. This
|
||||
alternative is allowed only occasionally and noncommercially, and
|
||||
only if you received the object code with such an offer, in accord
|
||||
with subsection 6b.
|
||||
|
||||
d) Convey the object code by offering access from a designated
|
||||
place (gratis or for a charge), and offer equivalent access to the
|
||||
Corresponding Source in the same way through the same place at no
|
||||
further charge. You need not require recipients to copy the
|
||||
Corresponding Source along with the object code. If the place to
|
||||
copy the object code is a network server, the Corresponding Source
|
||||
may be on a different server (operated by you or a third party)
|
||||
that supports equivalent copying facilities, provided you maintain
|
||||
clear directions next to the object code saying where to find the
|
||||
Corresponding Source. Regardless of what server hosts the
|
||||
Corresponding Source, you remain obligated to ensure that it is
|
||||
available for as long as needed to satisfy these requirements.
|
||||
|
||||
e) Convey the object code using peer-to-peer transmission, provided
|
||||
you inform other peers where the object code and Corresponding
|
||||
Source of the work are being offered to the general public at no
|
||||
charge under subsection 6d.
|
||||
|
||||
A separable portion of the object code, whose source code is excluded
|
||||
from the Corresponding Source as a System Library, need not be
|
||||
included in conveying the object code work.
|
||||
|
||||
A "User Product" is either (1) a "consumer product", which means any
|
||||
tangible personal property which is normally used for personal, family,
|
||||
or household purposes, or (2) anything designed or sold for incorporation
|
||||
into a dwelling. In determining whether a product is a consumer product,
|
||||
doubtful cases shall be resolved in favor of coverage. For a particular
|
||||
product received by a particular user, "normally used" refers to a
|
||||
typical or common use of that class of product, regardless of the status
|
||||
of the particular user or of the way in which the particular user
|
||||
actually uses, or expects or is expected to use, the product. A product
|
||||
is a consumer product regardless of whether the product has substantial
|
||||
commercial, industrial or non-consumer uses, unless such uses represent
|
||||
the only significant mode of use of the product.
|
||||
|
||||
"Installation Information" for a User Product means any methods,
|
||||
procedures, authorization keys, or other information required to install
|
||||
and execute modified versions of a covered work in that User Product from
|
||||
a modified version of its Corresponding Source. The information must
|
||||
suffice to ensure that the continued functioning of the modified object
|
||||
code is in no case prevented or interfered with solely because
|
||||
modification has been made.
|
||||
|
||||
If you convey an object code work under this section in, or with, or
|
||||
specifically for use in, a User Product, and the conveying occurs as
|
||||
part of a transaction in which the right of possession and use of the
|
||||
User Product is transferred to the recipient in perpetuity or for a
|
||||
fixed term (regardless of how the transaction is characterized), the
|
||||
Corresponding Source conveyed under this section must be accompanied
|
||||
by the Installation Information. But this requirement does not apply
|
||||
if neither you nor any third party retains the ability to install
|
||||
modified object code on the User Product (for example, the work has
|
||||
been installed in ROM).
|
||||
|
||||
The requirement to provide Installation Information does not include a
|
||||
requirement to continue to provide support service, warranty, or updates
|
||||
for a work that has been modified or installed by the recipient, or for
|
||||
the User Product in which it has been modified or installed. Access to a
|
||||
network may be denied when the modification itself materially and
|
||||
adversely affects the operation of the network or violates the rules and
|
||||
protocols for communication across the network.
|
||||
|
||||
Corresponding Source conveyed, and Installation Information provided,
|
||||
in accord with this section must be in a format that is publicly
|
||||
documented (and with an implementation available to the public in
|
||||
source code form), and must require no special password or key for
|
||||
unpacking, reading or copying.
|
||||
|
||||
7. Additional Terms.
|
||||
|
||||
"Additional permissions" are terms that supplement the terms of this
|
||||
License by making exceptions from one or more of its conditions.
|
||||
Additional permissions that are applicable to the entire Program shall
|
||||
be treated as though they were included in this License, to the extent
|
||||
that they are valid under applicable law. If additional permissions
|
||||
apply only to part of the Program, that part may be used separately
|
||||
under those permissions, but the entire Program remains governed by
|
||||
this License without regard to the additional permissions.
|
||||
|
||||
When you convey a copy of a covered work, you may at your option
|
||||
remove any additional permissions from that copy, or from any part of
|
||||
it. (Additional permissions may be written to require their own
|
||||
removal in certain cases when you modify the work.) You may place
|
||||
additional permissions on material, added by you to a covered work,
|
||||
for which you have or can give appropriate copyright permission.
|
||||
|
||||
Notwithstanding any other provision of this License, for material you
|
||||
add to a covered work, you may (if authorized by the copyright holders of
|
||||
that material) supplement the terms of this License with terms:
|
||||
|
||||
a) Disclaiming warranty or limiting liability differently from the
|
||||
terms of sections 15 and 16 of this License; or
|
||||
|
||||
b) Requiring preservation of specified reasonable legal notices or
|
||||
author attributions in that material or in the Appropriate Legal
|
||||
Notices displayed by works containing it; or
|
||||
|
||||
c) Prohibiting misrepresentation of the origin of that material, or
|
||||
requiring that modified versions of such material be marked in
|
||||
reasonable ways as different from the original version; or
|
||||
|
||||
d) Limiting the use for publicity purposes of names of licensors or
|
||||
authors of the material; or
|
||||
|
||||
e) Declining to grant rights under trademark law for use of some
|
||||
trade names, trademarks, or service marks; or
|
||||
|
||||
f) Requiring indemnification of licensors and authors of that
|
||||
material by anyone who conveys the material (or modified versions of
|
||||
it) with contractual assumptions of liability to the recipient, for
|
||||
any liability that these contractual assumptions directly impose on
|
||||
those licensors and authors.
|
||||
|
||||
All other non-permissive additional terms are considered "further
|
||||
restrictions" within the meaning of section 10. If the Program as you
|
||||
received it, or any part of it, contains a notice stating that it is
|
||||
governed by this License along with a term that is a further
|
||||
restriction, you may remove that term. If a license document contains
|
||||
a further restriction but permits relicensing or conveying under this
|
||||
License, you may add to a covered work material governed by the terms
|
||||
of that license document, provided that the further restriction does
|
||||
not survive such relicensing or conveying.
|
||||
|
||||
If you add terms to a covered work in accord with this section, you
|
||||
must place, in the relevant source files, a statement of the
|
||||
additional terms that apply to those files, or a notice indicating
|
||||
where to find the applicable terms.
|
||||
|
||||
Additional terms, permissive or non-permissive, may be stated in the
|
||||
form of a separately written license, or stated as exceptions;
|
||||
the above requirements apply either way.
|
||||
|
||||
8. Termination.
|
||||
|
||||
You may not propagate or modify a covered work except as expressly
|
||||
provided under this License. Any attempt otherwise to propagate or
|
||||
modify it is void, and will automatically terminate your rights under
|
||||
this License (including any patent licenses granted under the third
|
||||
paragraph of section 11).
|
||||
|
||||
However, if you cease all violation of this License, then your
|
||||
license from a particular copyright holder is reinstated (a)
|
||||
provisionally, unless and until the copyright holder explicitly and
|
||||
finally terminates your license, and (b) permanently, if the copyright
|
||||
holder fails to notify you of the violation by some reasonable means
|
||||
prior to 60 days after the cessation.
|
||||
|
||||
Moreover, your license from a particular copyright holder is
|
||||
reinstated permanently if the copyright holder notifies you of the
|
||||
violation by some reasonable means, this is the first time you have
|
||||
received notice of violation of this License (for any work) from that
|
||||
copyright holder, and you cure the violation prior to 30 days after
|
||||
your receipt of the notice.
|
||||
|
||||
Termination of your rights under this section does not terminate the
|
||||
licenses of parties who have received copies or rights from you under
|
||||
this License. If your rights have been terminated and not permanently
|
||||
reinstated, you do not qualify to receive new licenses for the same
|
||||
material under section 10.
|
||||
|
||||
9. Acceptance Not Required for Having Copies.
|
||||
|
||||
You are not required to accept this License in order to receive or
|
||||
run a copy of the Program. Ancillary propagation of a covered work
|
||||
occurring solely as a consequence of using peer-to-peer transmission
|
||||
to receive a copy likewise does not require acceptance. However,
|
||||
nothing other than this License grants you permission to propagate or
|
||||
modify any covered work. These actions infringe copyright if you do
|
||||
not accept this License. Therefore, by modifying or propagating a
|
||||
covered work, you indicate your acceptance of this License to do so.
|
||||
|
||||
10. Automatic Licensing of Downstream Recipients.
|
||||
|
||||
Each time you convey a covered work, the recipient automatically
|
||||
receives a license from the original licensors, to run, modify and
|
||||
propagate that work, subject to this License. You are not responsible
|
||||
for enforcing compliance by third parties with this License.
|
||||
|
||||
An "entity transaction" is a transaction transferring control of an
|
||||
organization, or substantially all assets of one, or subdividing an
|
||||
organization, or merging organizations. If propagation of a covered
|
||||
work results from an entity transaction, each party to that
|
||||
transaction who receives a copy of the work also receives whatever
|
||||
licenses to the work the party's predecessor in interest had or could
|
||||
give under the previous paragraph, plus a right to possession of the
|
||||
Corresponding Source of the work from the predecessor in interest, if
|
||||
the predecessor has it or can get it with reasonable efforts.
|
||||
|
||||
You may not impose any further restrictions on the exercise of the
|
||||
rights granted or affirmed under this License. For example, you may
|
||||
not impose a license fee, royalty, or other charge for exercise of
|
||||
rights granted under this License, and you may not initiate litigation
|
||||
(including a cross-claim or counterclaim in a lawsuit) alleging that
|
||||
any patent claim is infringed by making, using, selling, offering for
|
||||
sale, or importing the Program or any portion of it.
|
||||
|
||||
11. Patents.
|
||||
|
||||
A "contributor" is a copyright holder who authorizes use under this
|
||||
License of the Program or a work on which the Program is based. The
|
||||
work thus licensed is called the contributor's "contributor version".
|
||||
|
||||
A contributor's "essential patent claims" are all patent claims
|
||||
owned or controlled by the contributor, whether already acquired or
|
||||
hereafter acquired, that would be infringed by some manner, permitted
|
||||
by this License, of making, using, or selling its contributor version,
|
||||
but do not include claims that would be infringed only as a
|
||||
consequence of further modification of the contributor version. For
|
||||
purposes of this definition, "control" includes the right to grant
|
||||
patent sublicenses in a manner consistent with the requirements of
|
||||
this License.
|
||||
|
||||
Each contributor grants you a non-exclusive, worldwide, royalty-free
|
||||
patent license under the contributor's essential patent claims, to
|
||||
make, use, sell, offer for sale, import and otherwise run, modify and
|
||||
propagate the contents of its contributor version.
|
||||
|
||||
In the following three paragraphs, a "patent license" is any express
|
||||
agreement or commitment, however denominated, not to enforce a patent
|
||||
(such as an express permission to practice a patent or covenant not to
|
||||
sue for patent infringement). To "grant" such a patent license to a
|
||||
party means to make such an agreement or commitment not to enforce a
|
||||
patent against the party.
|
||||
|
||||
If you convey a covered work, knowingly relying on a patent license,
|
||||
and the Corresponding Source of the work is not available for anyone
|
||||
to copy, free of charge and under the terms of this License, through a
|
||||
publicly available network server or other readily accessible means,
|
||||
then you must either (1) cause the Corresponding Source to be so
|
||||
available, or (2) arrange to deprive yourself of the benefit of the
|
||||
patent license for this particular work, or (3) arrange, in a manner
|
||||
consistent with the requirements of this License, to extend the patent
|
||||
license to downstream recipients. "Knowingly relying" means you have
|
||||
actual knowledge that, but for the patent license, your conveying the
|
||||
covered work in a country, or your recipient's use of the covered work
|
||||
in a country, would infringe one or more identifiable patents in that
|
||||
country that you have reason to believe are valid.
|
||||
|
||||
If, pursuant to or in connection with a single transaction or
|
||||
arrangement, you convey, or propagate by procuring conveyance of, a
|
||||
covered work, and grant a patent license to some of the parties
|
||||
receiving the covered work authorizing them to use, propagate, modify
|
||||
or convey a specific copy of the covered work, then the patent license
|
||||
you grant is automatically extended to all recipients of the covered
|
||||
work and works based on it.
|
||||
|
||||
A patent license is "discriminatory" if it does not include within
|
||||
the scope of its coverage, prohibits the exercise of, or is
|
||||
conditioned on the non-exercise of one or more of the rights that are
|
||||
specifically granted under this License. You may not convey a covered
|
||||
work if you are a party to an arrangement with a third party that is
|
||||
in the business of distributing software, under which you make payment
|
||||
to the third party based on the extent of your activity of conveying
|
||||
the work, and under which the third party grants, to any of the
|
||||
parties who would receive the covered work from you, a discriminatory
|
||||
patent license (a) in connection with copies of the covered work
|
||||
conveyed by you (or copies made from those copies), or (b) primarily
|
||||
for and in connection with specific products or compilations that
|
||||
contain the covered work, unless you entered into that arrangement,
|
||||
or that patent license was granted, prior to 28 March 2007.
|
||||
|
||||
Nothing in this License shall be construed as excluding or limiting
|
||||
any implied license or other defenses to infringement that may
|
||||
otherwise be available to you under applicable patent law.
|
||||
|
||||
12. No Surrender of Others' Freedom.
|
||||
|
||||
If conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot convey a
|
||||
covered work so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you may
|
||||
not convey it at all. For example, if you agree to terms that obligate you
|
||||
to collect a royalty for further conveying from those to whom you convey
|
||||
the Program, the only way you could satisfy both those terms and this
|
||||
License would be to refrain entirely from conveying the Program.
|
||||
|
||||
13. Remote Network Interaction; Use with the GNU General Public License.
|
||||
|
||||
Notwithstanding any other provision of this License, if you modify the
|
||||
Program, your modified version must prominently offer all users
|
||||
interacting with it remotely through a computer network (if your version
|
||||
supports such interaction) an opportunity to receive the Corresponding
|
||||
Source of your version by providing access to the Corresponding Source
|
||||
from a network server at no charge, through some standard or customary
|
||||
means of facilitating copying of software. This Corresponding Source
|
||||
shall include the Corresponding Source for any work covered by version 3
|
||||
of the GNU General Public License that is incorporated pursuant to the
|
||||
following paragraph.
|
||||
|
||||
Notwithstanding any other provision of this License, you have
|
||||
permission to link or combine any covered work with a work licensed
|
||||
under version 3 of the GNU General Public License into a single
|
||||
combined work, and to convey the resulting work. The terms of this
|
||||
License will continue to apply to the part which is the covered work,
|
||||
but the work with which it is combined will remain governed by version
|
||||
3 of the GNU General Public License.
|
||||
|
||||
14. Revised Versions of this License.
|
||||
|
||||
The Free Software Foundation may publish revised and/or new versions of
|
||||
the GNU Affero General Public License from time to time. Such new versions
|
||||
will be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the
|
||||
Program specifies that a certain numbered version of the GNU Affero General
|
||||
Public License "or any later version" applies to it, you have the
|
||||
option of following the terms and conditions either of that numbered
|
||||
version or of any later version published by the Free Software
|
||||
Foundation. If the Program does not specify a version number of the
|
||||
GNU Affero General Public License, you may choose any version ever published
|
||||
by the Free Software Foundation.
|
||||
|
||||
If the Program specifies that a proxy can decide which future
|
||||
versions of the GNU Affero General Public License can be used, that proxy's
|
||||
public statement of acceptance of a version permanently authorizes you
|
||||
to choose that version for the Program.
|
||||
|
||||
Later license versions may give you additional or different
|
||||
permissions. However, no additional obligations are imposed on any
|
||||
author or copyright holder as a result of your choosing to follow a
|
||||
later version.
|
||||
|
||||
15. Disclaimer of Warranty.
|
||||
|
||||
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
|
||||
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
|
||||
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
|
||||
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
|
||||
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
|
||||
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
|
||||
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||
|
||||
16. Limitation of Liability.
|
||||
|
||||
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
|
||||
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
|
||||
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
|
||||
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
|
||||
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
|
||||
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
|
||||
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
|
||||
SUCH DAMAGES.
|
||||
|
||||
17. Interpretation of Sections 15 and 16.
|
||||
|
||||
If the disclaimer of warranty and limitation of liability provided
|
||||
above cannot be given local legal effect according to their terms,
|
||||
reviewing courts shall apply local law that most closely approximates
|
||||
an absolute waiver of all civil liability in connection with the
|
||||
Program, unless a warranty or assumption of liability accompanies a
|
||||
copy of the Program in return for a fee.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
state the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
|
||||
Copyright (C) {{ year }} {{ organization }}
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If your software can interact with users remotely through a computer
|
||||
network, you should also make sure that it provides a way for users to
|
||||
get its source. For example, if your program is a web application, its
|
||||
interface could display a "Source" link that leads users to an archive
|
||||
of the code. There are many ways you could offer source, and different
|
||||
solutions will be better for different programs; see section 13 for the
|
||||
specific requirements.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or school,
|
||||
if any, to sign a "copyright disclaimer" for the program, if necessary.
|
||||
For more information on this, and how to apply and follow the GNU AGPL, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
MIT License
|
||||
|
||||
Copyright (c) Microsoft Corporation.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE
|
||||
|
||||
@@ -0,0 +1,221 @@
|
||||
.PHONY: clean deepclean install init-qlib-env dev constraints black isort mypy ruff toml-sort lint pre-commit test-run test build upload docs-autobuild changelog docs-gen docs-mypy docs-coverage docs
|
||||
#You can modify it according to your terminal
|
||||
SHELL := /bin/bash
|
||||
|
||||
########################################################################################
|
||||
# Variables
|
||||
########################################################################################
|
||||
|
||||
# Determine whether to invoke pipenv based on CI environment variable and the availability of pipenv.
|
||||
PIPRUN := $(shell [ "$$CI" != "true" ] && command -v pipenv > /dev/null 2>&1 && echo "pipenv run")
|
||||
|
||||
# Get the Python version in `major.minor` format, using the environment variable or the virtual environment if exists.
|
||||
PYTHON_VERSION := $(shell echo $${PYTHON_VERSION:-$$(python -V 2>&1 | cut -d ' ' -f 2)} | cut -d '.' -f 1,2)
|
||||
|
||||
# Determine the constraints file based on the Python version.
|
||||
CONSTRAINTS_FILE := constraints/$(PYTHON_VERSION).txt
|
||||
|
||||
# Documentation target directory, will be adapted to specific folder for readthedocs.
|
||||
PUBLIC_DIR := $(shell [ "$$READTHEDOCS" = "True" ] && echo "$$READTHEDOCS_OUTPUT/html" || echo "public")
|
||||
|
||||
# URL and Path of changelog source code.
|
||||
CHANGELOG_URL := $(shell echo $${CI_PAGES_URL:-https://microsoft.github.io/rdagent}/_sources/changelog.md.txt)
|
||||
CHANGELOG_PATH := docs/changelog.md
|
||||
|
||||
########################################################################################
|
||||
# Development Environment Management
|
||||
########################################################################################
|
||||
|
||||
# Remove common intermediate files.
|
||||
clean:
|
||||
-rm -rf \
|
||||
$(PUBLIC_DIR) \
|
||||
.coverage \
|
||||
.mypy_cache \
|
||||
.pytest_cache \
|
||||
.ruff_cache \
|
||||
Pipfile* \
|
||||
coverage.xml \
|
||||
dist \
|
||||
release-notes.md
|
||||
find . -name '*.egg-info' -print0 | xargs -0 rm -rf
|
||||
find . -name '*.pyc' -print0 | xargs -0 rm -f
|
||||
find . -name '*.swp' -print0 | xargs -0 rm -f
|
||||
find . -name '.DS_Store' -print0 | xargs -0 rm -f
|
||||
find . -name '__pycache__' -print0 | xargs -0 rm -rf
|
||||
|
||||
# Remove pre-commit hook, virtual environment alongside itermediate files.
|
||||
deepclean: clean
|
||||
if command -v pre-commit > /dev/null 2>&1; then pre-commit uninstall --hook-type pre-push; fi
|
||||
if command -v pipenv >/dev/null 2>&1 && pipenv --venv >/dev/null 2>&1; then pipenv --rm; fi
|
||||
|
||||
# Install the package in editable mode.
|
||||
install:
|
||||
$(PIPRUN) pip install -e . -c $(CONSTRAINTS_FILE)
|
||||
|
||||
# Install the package in editable mode with specific optional dependencies.
|
||||
dev-%:
|
||||
$(PIPRUN) pip install -e .[$*] -c $(CONSTRAINTS_FILE)
|
||||
|
||||
# Prepare the development environment.
|
||||
# Build submodules.
|
||||
# Install the pacakge in editable mode with all optional dependencies and pre-commit hook.
|
||||
init-qlib-env:
|
||||
# note: You may need to install torch manually
|
||||
# todo: downgrade ruamel.yaml in pyqlib
|
||||
conda create -n qlibRDAgent python=3.8 -y
|
||||
@source $$(conda info --base)/etc/profile.d/conda.sh && conda activate qlibRDAgent && which pip && pip install pyqlib && pip install ruamel-yaml==0.17.21 && pip install torch==2.1.1 && pip install catboost==0.24.3 && conda deactivate
|
||||
|
||||
dev:
|
||||
$(PIPRUN) pip install -e .[docs,lint,package,test] -c $(CONSTRAINTS_FILE)
|
||||
$(PIPRUN) pip install -U kaggle
|
||||
if [ "$(CI)" != "true" ] && command -v pre-commit > /dev/null 2>&1; then pre-commit install --hook-type pre-push; fi
|
||||
|
||||
# Generate constraints for current Python version.
|
||||
constraints: deepclean
|
||||
$(PIPRUN) --python $(PYTHON_VERSION) pip install --upgrade -e .[docs,lint,package,test]
|
||||
$(PIPRUN) pip freeze --exclude-editable > $(CONSTRAINTS_FILE)
|
||||
|
||||
########################################################################################
|
||||
# Lint and pre-commit
|
||||
########################################################################################
|
||||
|
||||
# Check lint with black.
|
||||
black:
|
||||
$(PIPRUN) python -m black --check --diff . --extend-exclude test/scripts --extend-exclude git_ignore_folder -l 120
|
||||
|
||||
# Check lint with isort.
|
||||
isort:
|
||||
$(PIPRUN) python -m isort --check . -s git_ignore_folder -s test/scripts
|
||||
|
||||
# Check lint with mypy.
|
||||
# First deal with the core folder, and then gradually increase the scope of detection,
|
||||
# and eventually realize the detection of the complete project.
|
||||
mypy:
|
||||
$(PIPRUN) python -m mypy rdagent/core
|
||||
|
||||
# Check lint with ruff.
|
||||
# First deal with the core folder, and then gradually increase the scope of detection,
|
||||
# and eventually realize the detection of the complete project.
|
||||
ruff:
|
||||
$(PIPRUN) ruff check rdagent/core --ignore FBT001,FBT002,I001 # --exclude rdagent/scripts,git_ignore_folder
|
||||
|
||||
# Check lint with toml-sort.
|
||||
toml-sort:
|
||||
$(PIPRUN) toml-sort --check pyproject.toml
|
||||
|
||||
# Check lint with all linters.
|
||||
# Prioritize fixing isort, then black, otherwise you'll get weird and unfixable black errors.
|
||||
# lint: mypy ruff
|
||||
lint: mypy ruff isort black toml-sort
|
||||
|
||||
# Run pre-commit with autofix against all files.
|
||||
pre-commit:
|
||||
pre-commit run --all-files
|
||||
|
||||
########################################################################################
|
||||
# Auto Lint
|
||||
########################################################################################
|
||||
|
||||
# Auto lint with black.
|
||||
auto-black:
|
||||
$(PIPRUN) python -m black . --extend-exclude test/scripts --extend-exclude git_ignore_folder -l 120
|
||||
|
||||
# Auto lint with isort.
|
||||
auto-isort:
|
||||
$(PIPRUN) python -m isort . -s git_ignore_folder -s test/scripts
|
||||
|
||||
# Auto lint with toml-sort.
|
||||
auto-toml-sort:
|
||||
$(PIPRUN) toml-sort pyproject.toml
|
||||
|
||||
# Auto lint with all linters.
|
||||
auto-lint: auto-isort auto-black auto-toml-sort
|
||||
|
||||
########################################################################################
|
||||
# Test
|
||||
########################################################################################
|
||||
|
||||
# Clean and run test with coverage.
|
||||
test-run:
|
||||
$(PIPRUN) python -m coverage erase
|
||||
$(PIPRUN) python -m coverage run --concurrency=multiprocessing -m pytest --ignore test/scripts
|
||||
$(PIPRUN) python -m coverage combine
|
||||
|
||||
test-run-offline:
|
||||
# some test that does not require api calling
|
||||
$(PIPRUN) python -m coverage erase
|
||||
$(PIPRUN) python -m coverage run --concurrency=multiprocessing -m pytest -m "offline" --ignore test/scripts
|
||||
$(PIPRUN) python -m coverage combine
|
||||
|
||||
# Generate coverage report for terminal and xml.
|
||||
# TODO: we may have higher coverage rate if we have more test
|
||||
test: test-run
|
||||
$(PIPRUN) python -m coverage report --fail-under 20 # 80
|
||||
$(PIPRUN) python -m coverage xml --fail-under 20 # 80
|
||||
|
||||
test-offline: test-run-offline
|
||||
$(PIPRUN) python -m coverage report --fail-under 20 # 80
|
||||
$(PIPRUN) python -m coverage xml --fail-under 20 # 80
|
||||
|
||||
########################################################################################
|
||||
# Package
|
||||
########################################################################################
|
||||
|
||||
# Build the package.
|
||||
build:
|
||||
$(PIPRUN) python -m build
|
||||
|
||||
# Upload the package.
|
||||
upload:
|
||||
$(PIPRUN) python -m twine upload dist/*
|
||||
|
||||
########################################################################################
|
||||
# Documentation
|
||||
########################################################################################
|
||||
|
||||
# Generate documentation with auto build when changes happen.
|
||||
docs-autobuild:
|
||||
$(PIPRUN) python -m sphinx_autobuild docs $(PUBLIC_DIR) \
|
||||
--watch README.md \
|
||||
--watch rdagent
|
||||
|
||||
# Generate changelog from git commits.
|
||||
# The -c and -s arguments should match
|
||||
# If -c uses Basic (default, inherits from base class), -s optional argument: # If -c uses conventional (inherits from base class), -s optional parameter: add,fix,change,remove,merge,doc
|
||||
# If -c uses conventional (inherits from base class), -s is optional: build,chore,ci,deps,doc,docs,feat,fix,perf,ref,refactor,revert,style,test,tests
|
||||
# If -c uses angular (inherits from conventional), -s optional argument: build,chore,ci,deps,doc,docs,feat,fix,perf,ref,refactor,revert,style,test,tests
|
||||
# NOTE(xuan.hu): Need to be run before document generation to take effect.
|
||||
# $(PIPRUN) git-changelog -ETrio $(CHANGELOG_PATH) -c conventional -s build,chore,ci,docs,feat,fix,perf,refactor,revert,style,test
|
||||
changelog:
|
||||
@if wget -q --spider $(CHANGELOG_URL); then \
|
||||
echo "Existing Changelog found at '$(CHANGELOG_URL)', download for incremental generation."; \
|
||||
wget -q -O $(CHANGELOG_PATH) $(CHANGELOG_URL); \
|
||||
fi
|
||||
$(PIPRUN) LATEST_TAG=$$(git tag --sort=-creatordate | head -n 1); \
|
||||
git-changelog --bump $$LATEST_TAG -Tio docs/changelog.md -c conventional -s build,chore,ci,deps,doc,docs,feat,fix,perf,ref,refactor,revert,style,test,tests
|
||||
|
||||
# Generate release notes from changelog.
|
||||
release-notes:
|
||||
@$(PIPRUN) git-changelog --input $(CHANGELOG_PATH) --release-notes
|
||||
|
||||
# Build documentation only from rdagent.
|
||||
docs-gen:
|
||||
$(PIPRUN) python -m sphinx.cmd.build -W docs $(PUBLIC_DIR)
|
||||
|
||||
# Generate mypy reports.
|
||||
docs-mypy: docs-gen
|
||||
$(PIPRUN) python -m mypy rdagent test --exclude git_ignore_folder --exclude rdagent/scripts --html-report $(PUBLIC_DIR)/reports/mypy
|
||||
|
||||
# Generate html coverage reports with badge.
|
||||
docs-coverage: test-run docs-gen
|
||||
$(PIPRUN) python -m coverage html -d $(PUBLIC_DIR)/reports/coverage --fail-under 80
|
||||
$(PIPRUN) bash scripts/generate-coverage-badge.sh $(PUBLIC_DIR)/_static/badges
|
||||
|
||||
# Generate all documentation with reports.
|
||||
docs: changelog docs-gen docs-mypy docs-coverage
|
||||
|
||||
|
||||
########################################################################################
|
||||
# End
|
||||
########################################################################################
|
||||
@@ -1,228 +1,422 @@
|
||||
# NexQuant
|
||||
|
||||
<p align="center">
|
||||
<img src="https://img.shields.io/badge/Python-3.10%20|%203.11-blue?style=for-the-badge&logo=python" alt="Python">
|
||||
<img src="https://img.shields.io/badge/Platform-Linux-lightgrey?style=for-the-badge&logo=linux" alt="Platform">
|
||||
<img src="https://img.shields.io/badge/Numba-0.59+-00A3E0?style=for-the-badge&logo=numba" alt="Numba">
|
||||
<img src="https://img.shields.io/badge/Optuna-4.8+-009B77?style=for-the-badge&logo=optuna" alt="Optuna">
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
<img src="https://img.shields.io/badge/TA--Lib-0.6+-green?style=for-the-badge" alt="TA-Lib">
|
||||
<img src="https://img.shields.io/badge/LightGBM-4.6+-00A1E0?style=for-the-badge" alt="LightGBM">
|
||||
<img src="https://img.shields.io/badge/Pandas-2.0+-150458?style=for-the-badge&logo=pandas" alt="Pandas">
|
||||
<img src="https://img.shields.io/badge/cTrader-OpenAPI-FF6B6B?style=for-the-badge" alt="cTrader">
|
||||
</p>
|
||||
|
||||
<h4 align="center">
|
||||
<strong>High-Speed Strategy Discovery Framework</strong>
|
||||
</h4>
|
||||
<img src="docs/_static/logo.png" alt="RA-Agent logo" style="width:70%; ">
|
||||
|
||||
<a href="https://rdagent.azurewebsites.net" target="_blank">🖥️ Live Demo</a> |
|
||||
<a href="https://rdagent.azurewebsites.net/factor_loop" target="_blank">🎥 Demo Video</a> <a href="https://www.youtube.com/watch?v=JJ4JYO3HscM&list=PLALmKB0_N3_i52fhUmPQiL4jsO354uopR" target="_blank">▶️YouTube</a> |
|
||||
<a href="https://rdagent.readthedocs.io/en/latest/index.html" target="_blank">📖 Documentation</a> |
|
||||
<a href="https://aka.ms/RD-Agent-Tech-Report" target="_blank">📄 Tech Report</a> |
|
||||
<a href="#-paperwork-list"> 📃 Papers </a>
|
||||
</h3>
|
||||
|
||||
<p align="center">
|
||||
<a href="#quick-start">Quick Start</a> •
|
||||
<a href="#strategy-discovery">Strategy Discovery</a> •
|
||||
<a href="#live-trading">Live Trading</a> •
|
||||
<a href="#features">Features</a>
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
<a href="https://github.com/TPTBusiness/NexQuant/actions/workflows/ci.yml">
|
||||
<img src="https://img.shields.io/github/actions/workflow/status/TPTBusiness/NexQuant/ci.yml?branch=master&label=CI&logo=github&style=flat-square" alt="CI Status">
|
||||
</a>
|
||||
<a href="https://github.com/TPTBusiness/NexQuant/actions/workflows/codacy.yml">
|
||||
<img src="https://img.shields.io/github/actions/workflow/status/TPTBusiness/NexQuant/codacy.yml?branch=master&label=Security&logo=shield&style=flat-square" alt="Security Scan">
|
||||
</a>
|
||||
<a href="https://github.com/TPTBusiness/NexQuant/blob/master/LICENSE">
|
||||
<img src="https://img.shields.io/github/license/TPTBusiness/NexQuant?style=flat-square" alt="License">
|
||||
</a>
|
||||
<a href="https://github.com/astral-sh/ruff">
|
||||
<img src="https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json&style=flat-square" alt="Ruff">
|
||||
</a>
|
||||
<a href="https://github.com/TPTBusiness/NexQuant/commits/master">
|
||||
<img src="https://img.shields.io/github/last-commit/TPTBusiness/NexQuant?style=flat-square" alt="Last Commit">
|
||||
</a>
|
||||
</p>
|
||||
[](https://github.com/microsoft/RD-Agent/actions/workflows/ci.yml)
|
||||
[](https://github.com/microsoft/RD-Agent/actions/workflows/github-code-scanning/codeql)
|
||||
[](https://github.com/microsoft/RD-Agent/actions/workflows/dependabot/dependabot-updates)
|
||||
[](https://github.com/microsoft/RD-Agent/actions/workflows/pr.yml)
|
||||
[](https://github.com/microsoft/RD-Agent/actions/workflows/release.yml)
|
||||
[](https://pypi.org/project/rdagent/#files)
|
||||
[](https://pypi.org/project/rdagent/)
|
||||
[](https://pypi.org/project/rdagent/)
|
||||
[](https://github.com/microsoft/RD-Agent/releases)
|
||||
[](https://github.com/microsoft/RD-Agent/blob/main/LICENSE)
|
||||
[](https://github.com/pre-commit/pre-commit)
|
||||
[](http://mypy-lang.org/)
|
||||
[](https://github.com/astral-sh/ruff)
|
||||
[](https://discord.gg/ybQ97B6Jjy)
|
||||
[](https://rdagent.readthedocs.io/en/latest/?badge=latest)
|
||||
[](https://github.com/microsoft/RD-Agent/actions/workflows/readthedocs-preview.yml) <!-- this badge is too long, please place it in the last one to make it pretty -->
|
||||
[](https://arxiv.org/abs/2505.14738)
|
||||
|
||||
---
|
||||
|
||||
## Overview
|
||||
|
||||
**NexQuant** discovers profitable trading strategies through high-speed search — no LLM required. Core engine: Numba JIT-compiled backtest at **735 million bars/second** (245× faster than pandas). Four discovery methods run in a continuous loop:
|
||||
# 🏆 The Best Machine Learning Engineering Agent!
|
||||
|
||||
| Method | Frequency | Description |
|
||||
|--------|-----------|-------------|
|
||||
| **Explore** | 30% of iterations | Random strategies from 17 TA-Lib indicators across timeframes |
|
||||
| **Exploit** | 70% of iterations | Mutate the best-known strategy (change params, indicator, or timeframe) |
|
||||
| **Optuna** | Every 500 iterations | 20-trial hyperparameter optimization on the current best |
|
||||
| **LightGBM** | Every 2000 iterations | ML classifier trained on SOTA indicator signals to predict direction |
|
||||
[MLE-bench](https://github.com/openai/mle-bench) is a comprehensive benchmark evaluating the performance of AI agents on machine learning engineering tasks. Utilizing datasets from 75 Kaggle competitions, MLE-bench provides robust assessments of AI systems' capabilities in real-world ML engineering scenarios.
|
||||
|
||||
**Current best strategy**: MACD(3,10,3) 4-TF with 2/4 vote majority — **+32.0%/month** (Numba), **+24.3%/month** (verified independent backtest), 0/75 negative months.
|
||||
R&D-Agent currently leads as the top-performing machine learning engineering agent on MLE-bench:
|
||||
|
||||
> **This repository contains the research framework.** Trading strategies, broker integrations, and live trading infrastructure are available as separate closed-source modules (`git_ignore_folder/`).
|
||||
| Agent | Low == Lite (%) | Medium (%) | High (%) | All (%) |
|
||||
|---------|--------|-----------|---------|----------|
|
||||
| R&D-Agent o1-preview | 48.18 ± 2.49 | 8.95 ± 2.36 | 18.67 ± 2.98 | 22.4 ± 1.1 |
|
||||
| R&D-Agent o3(R)+GPT-4.1(D) | 51.52 ± 6.21 | 7.89 ± 3.33 | 16.67 ± 3.65 | 22.45 ± 2.45 |
|
||||
| AIDE o1-preview | 34.3 ± 2.4 | 8.8 ± 1.1 | 10.0 ± 1.9 | 16.9 ± 1.1 |
|
||||
|
||||
---
|
||||
**Notes:**
|
||||
- **O3(R)+GPT-4.1(D)**: This version is designed to both reduce average time per loop and leverage a cost-effective combination of backend LLMs by seamlessly integrating Research Agent (o3) with Development Agent (GPT-4.1).
|
||||
- **AIDE o1-preview**: Represents the previously best public result on MLE-bench as reported in the original MLE-bench paper.
|
||||
- Average and standard deviation results for R&D-Agent o1-preview is based on a independent of 5 seeds and for R&D-Agent o3(R)+GPT-4.1(D) is based on 6 seeds.
|
||||
- According to MLE-Bench, the 75 competitions are categorized into three levels of complexity: **Low==Lite** if we estimate that an experienced ML engineer can produce a sensible solution in under 2 hours, excluding the time taken to train any models; **Medium** if it takes between 2 and 10 hours; and **High** if it takes more than 10 hours.
|
||||
|
||||
## Quick Start
|
||||
You can inspect the detailed runs of the above results online.
|
||||
- [R&D-Agent o1-preview detailed runs](https://aka.ms/RD-Agent_MLE-Bench_O1-preview)
|
||||
- [R&D-Agent o3(R)+GPT-4.1(D) detailed runs](https://aka.ms/RD-Agent_MLE-Bench_O3_GPT41)
|
||||
|
||||
```bash
|
||||
# Prerequisites
|
||||
conda create -n nexquant python=3.10 -y && conda activate nexquant
|
||||
pip install -e .
|
||||
# Ensure OHLCV data exists: git_ignore_folder/intraday_pv_all.h5
|
||||
For running R&D-Agent on MLE-bench, refer to **[MLE-bench Guide: Running ML Engineering via MLE-bench](https://rdagent.readthedocs.io/en/latest/scens/data_science.html)**
|
||||
|
||||
# Strategy Discovery Loop (10,000 iterations, ~1 hour)
|
||||
python scripts/nexquant_rd_loop.py --iterations 10000
|
||||
# 🥇 The First Data-Centric Quant Multi-Agent Framework!
|
||||
|
||||
# Price-Action Indicator Loop (grid search all TA-Lib indicators)
|
||||
python scripts/nexquant_priceaction_loop.py
|
||||
R&D-Agent for Quantitative Finance, in short **RD-Agent(Q)**, is the first data-centric, multi-agent framework designed to automate the full-stack research and development of quantitative strategies via coordinated factor-model co-optimization.
|
||||
|
||||
# Top strategies report
|
||||
python nexquant.py best -n 20 -m monthly_return --min-trades 30
|
||||

|
||||
|
||||
Extensive experiments in real stock markets show that, at a cost under $10, RD-Agent(Q) achieves approximately 2× higher ARR than benchmark factor libraries while using over 70% fewer factors. It also surpasses state-of-the-art deep time-series models under smaller resource budgets. Its alternating factor–model optimization further delivers excellent trade-off between predictive accuracy and strategy robustness.
|
||||
|
||||
You can learn more details about **RD-Agent(Q)** through the [paper](https://arxiv.org/abs/2505.15155) and reproduce it through the [documentation](https://rdagent.readthedocs.io/en/latest/scens/quant_agent_fin.html).
|
||||
|
||||
# 📰 News
|
||||
| 🗞️ News | 📝 Description |
|
||||
| -- | ------ |
|
||||
| [Technical Report Release](#overall-technical-report) | Overall framework description and results on MLE-bench |
|
||||
| [R&D-Agent-Quant Release](#deep-application-in-diverse-scenarios) | Apply R&D-Agent to quant trading |
|
||||
| MLE-Bench Results Released | R&D-Agent currently leads as the [top-performing machine learning engineering agent](#-the-best-machine-learning-engineering-agent) on MLE-bench |
|
||||
| Support LiteLLM Backend | We now fully support **[LiteLLM](https://github.com/BerriAI/litellm)** as a backend for integration with multiple LLM providers. |
|
||||
| General Data Science Agent | [Data Science Agent](https://rdagent.readthedocs.io/en/latest/scens/data_science.html) |
|
||||
| Kaggle Scenario release | We release **[Kaggle Agent](https://rdagent.readthedocs.io/en/latest/scens/data_science.html)**, try the new features! |
|
||||
| Official WeChat group release | We created a WeChat group, welcome to join! (🗪[QR Code](https://github.com/microsoft/RD-Agent/issues/880)) |
|
||||
| Official Discord release | We launch our first chatting channel in Discord (🗪[](https://discord.gg/ybQ97B6Jjy)) |
|
||||
| First release | **R&D-Agent** is released on GitHub |
|
||||
|
||||
|
||||
|
||||
# Data Science Agent Preview
|
||||
Check out our demo video showcasing the current progress of our Data Science Agent under development:
|
||||
|
||||
https://github.com/user-attachments/assets/3eccbecb-34a4-4c81-bce4-d3f8862f7305
|
||||
|
||||
# 🌟 Introduction
|
||||
<div align="center">
|
||||
<img src="docs/_static/scen.png" alt="Our focused scenario" style="width:80%; ">
|
||||
</div>
|
||||
|
||||
R&D-Agent aims to automate the most critical and valuable aspects of the industrial R&D process, and we begin with focusing on the data-driven scenarios to streamline the development of models and data.
|
||||
Methodologically, we have identified a framework with two key components: 'R' for proposing new ideas and 'D' for implementing them.
|
||||
We believe that the automatic evolution of R&D will lead to solutions of significant industrial value.
|
||||
|
||||
|
||||
<!-- Tag Cloud -->
|
||||
R&D is a very general scenario. The advent of R&D-Agent can be your
|
||||
- 💰 **Automatic Quant Factory** ([🎥Demo Video](https://rdagent.azurewebsites.net/factor_loop)|[▶️YouTube](https://www.youtube.com/watch?v=X4DK2QZKaKY&t=6s))
|
||||
- 🤖 **Data Mining Agent:** Iteratively proposing data & models ([🎥Demo Video 1](https://rdagent.azurewebsites.net/model_loop)|[▶️YouTube](https://www.youtube.com/watch?v=dm0dWL49Bc0&t=104s)) ([🎥Demo Video 2](https://rdagent.azurewebsites.net/dmm)|[▶️YouTube](https://www.youtube.com/watch?v=VIaSTZuoZg4)) and implementing them by gaining knowledge from data.
|
||||
- 🦾 **Research Copilot:** Auto read research papers ([🎥Demo Video](https://rdagent.azurewebsites.net/report_model)|[▶️YouTube](https://www.youtube.com/watch?v=BiA2SfdKQ7o)) / financial reports ([🎥Demo Video](https://rdagent.azurewebsites.net/report_factor)|[▶️YouTube](https://www.youtube.com/watch?v=ECLTXVcSx-c)) and implement model structures or building datasets.
|
||||
- 🤖 **Kaggle Agent:** Auto Model Tuning and Feature Engineering([🎥Demo Video Coming Soon...]()) and implementing them to achieve more in competitions.
|
||||
- ...
|
||||
|
||||
You can click the links above to view the demo. We're continuously adding more methods and scenarios to the project to enhance your R&D processes and boost productivity.
|
||||
|
||||
Additionally, you can take a closer look at the examples in our **[🖥️ Live Demo](https://rdagent.azurewebsites.net/)**.
|
||||
|
||||
<div align="center">
|
||||
<a href="https://rdagent.azurewebsites.net/" target="_blank">
|
||||
<img src="docs/_static/demo.png" alt="Watch the demo" width="80%">
|
||||
</a>
|
||||
</div>
|
||||
|
||||
|
||||
# ⚡ Quick start
|
||||
|
||||
You can try above demos by running the following command:
|
||||
|
||||
### 🐳 Docker installation.
|
||||
Users must ensure Docker is installed before attempting most scenarios. Please refer to the [official 🐳Docker page](https://docs.docker.com/engine/install/) for installation instructions.
|
||||
Ensure the current user can run Docker commands **without using sudo**. You can verify this by executing `docker run hello-world`.
|
||||
|
||||
### 🐍 Create a Conda Environment
|
||||
- Create a new conda environment with Python (3.10 and 3.11 are well-tested in our CI):
|
||||
```sh
|
||||
conda create -n rdagent python=3.10
|
||||
```
|
||||
- Activate the environment:
|
||||
```sh
|
||||
conda activate rdagent
|
||||
```
|
||||
|
||||
### 🛠️ Install the R&D-Agent
|
||||
- You can directly install the R&D-Agent package from PyPI:
|
||||
```sh
|
||||
pip install rdagent
|
||||
```
|
||||
|
||||
### 💊 Health check
|
||||
- rdagent provides a health check that currently checks two things.
|
||||
- whether the docker installation was successful.
|
||||
- whether the default port used by the [rdagent ui](https://github.com/microsoft/RD-Agent?tab=readme-ov-file#%EF%B8%8F-monitor-the-application-results) is occupied.
|
||||
```sh
|
||||
rdagent health_check
|
||||
```
|
||||
|
||||
|
||||
### ⚙️ Configuration
|
||||
- The demos requires following ability:
|
||||
- ChatCompletion
|
||||
- json_mode
|
||||
- embedding query
|
||||
|
||||
You can set your Chat Model and Embedding Model in the following ways:
|
||||
|
||||
- **Using LiteLLM (Default)**: We now support LiteLLM as a backend for integration with multiple LLM providers. You can configure in two ways:
|
||||
|
||||
**Option 1: Unified API base for both models**
|
||||
```bash
|
||||
cat << EOF > .env
|
||||
# Set to any model supported by LiteLLM.
|
||||
CHAT_MODEL=gpt-4o
|
||||
EMBEDDING_MODEL=text-embedding-3-small
|
||||
# Configure unified API base
|
||||
OPENAI_API_BASE=<your_unified_api_base>
|
||||
OPENAI_API_KEY=<replace_with_your_openai_api_key>
|
||||
```
|
||||
|
||||
**Option 2: Separate API bases for Chat and Embedding models**
|
||||
```bash
|
||||
cat << EOF > .env
|
||||
# Set to any model supported by LiteLLM.
|
||||
# Configure separate API bases for chat and embedding
|
||||
|
||||
# CHAT MODEL:
|
||||
CHAT_MODEL=gpt-4o
|
||||
OPENAI_API_BASE=<your_chat_api_base>
|
||||
OPENAI_API_KEY=<replace_with_your_openai_api_key>
|
||||
|
||||
# EMBEDDING MODEL:
|
||||
# TAKE siliconflow as an example, you can use other providers.
|
||||
# Note: embedding requires litellm_proxy prefix
|
||||
EMBEDDING_MODEL=litellm_proxy/BAAI/bge-large-en-v1.5
|
||||
LITELLM_PROXY_API_KEY=<replace_with_your_siliconflow_api_key>
|
||||
LITELLM_PROXY_API_BASE=https://api.siliconflow.cn/v1
|
||||
```
|
||||
|
||||
Notice: If you are using reasoning models that include thought processes in their responses (such as \<think> tags), you need to set the following environment variable:
|
||||
```bash
|
||||
REASONING_THINK_RM=True
|
||||
```
|
||||
|
||||
- You can also use a deprecated backend if you only use `OpenAI API` or `Azure OpenAI` directly. For this deprecated setting and more configuration information, please refer to the [documentation](https://rdagent.readthedocs.io/en/latest/installation_and_configuration.html).
|
||||
|
||||
### 🚀 Run the Application
|
||||
|
||||
The **[🖥️ Live Demo](https://rdagent.azurewebsites.net/)** is implemented by the following commands(each item represents one demo, you can select the one you prefer):
|
||||
|
||||
- Run the **Automated Quantitative Trading & Iterative Factors Model Joint Evolution**: [Qlib](http://github.com/microsoft/qlib) self-loop factor & model proposal and implementation application
|
||||
```sh
|
||||
rdagent fin_quant
|
||||
```
|
||||
|
||||
- Run the **Automated Quantitative Trading & Iterative Factors Evolution**: [Qlib](http://github.com/microsoft/qlib) self-loop factor proposal and implementation application
|
||||
```sh
|
||||
rdagent fin_factor
|
||||
```
|
||||
|
||||
- Run the **Automated Quantitative Trading & Iterative Model Evolution**: [Qlib](http://github.com/microsoft/qlib) self-loop model proposal and implementation application
|
||||
```sh
|
||||
rdagent fin_model
|
||||
```
|
||||
|
||||
- Run the **Automated Quantitative Trading & Factors Extraction from Financial Reports**: Run the [Qlib](http://github.com/microsoft/qlib) factor extraction and implementation application based on financial reports
|
||||
```sh
|
||||
# 1. Generally, you can run this scenario using the following command:
|
||||
rdagent fin_factor_report --report_folder=<Your financial reports folder path>
|
||||
|
||||
# 2. Specifically, you need to prepare some financial reports first. You can follow this concrete example:
|
||||
wget https://github.com/SunsetWolf/rdagent_resource/releases/download/reports/all_reports.zip
|
||||
unzip all_reports.zip -d git_ignore_folder/reports
|
||||
rdagent fin_factor_report --report_folder=git_ignore_folder/reports
|
||||
```
|
||||
|
||||
- Run the **Automated Model Research & Development Copilot**: model extraction and implementation application
|
||||
```sh
|
||||
# 1. Generally, you can run your own papers/reports with the following command:
|
||||
rdagent general_model <Your paper URL>
|
||||
|
||||
# 2. Specifically, you can do it like this. For more details and additional paper examples, use `rdagent general_model -h`:
|
||||
rdagent general_model "https://arxiv.org/pdf/2210.09789"
|
||||
```
|
||||
|
||||
- Run the **Automated Kaggle Model Tuning & Feature Engineering**: self-loop model proposal and feature engineering implementation application <br />
|
||||
> Using **sf-crime** *(San Francisco Crime Classification)* as an example. <br />
|
||||
> 1. Register and login on the [Kaggle](https://www.kaggle.com/) website. <br />
|
||||
> 2. Configuring the Kaggle API. <br />
|
||||
> (1) Click on the avatar (usually in the top right corner of the page) -> `Settings` -> `Create New Token`, A file called `kaggle.json` will be downloaded. <br />
|
||||
> (2) Move `kaggle.json` to `~/.config/kaggle/` <br />
|
||||
> (3) Modify the permissions of the kaggle.json file. Reference command: `chmod 600 ~/.config/kaggle/kaggle.json` <br />
|
||||
> 3. Join the competition: Click `Join the competition` -> `I Understand and Accept` at the bottom of the [competition details page](https://www.kaggle.com/competitions/sf-crime/data).
|
||||
```bash
|
||||
# Generally, you can run the Kaggle competition program with the following command:
|
||||
rdagent data_science --competition <your competition name>
|
||||
|
||||
# Specifically, you need to create a folder for storing competition files (e.g., competition description file, competition datasets, etc.), and configure the path to the folder in your environment. In addition, you need to use chromedriver when you download the competition descriptors, which you can follow for this specific example:
|
||||
|
||||
# 1. Install chromedriver.
|
||||
|
||||
# 2. Add the competition description file path to the `.env` file.
|
||||
mkdir -p ./git_ignore_folder/kaggle_data
|
||||
dotenv set DS_LOCAL_DATA_PATH "$(pwd)/git_ignore_folder/kaggle_data"
|
||||
dotenv set DS_IF_USING_MLE_DATA True
|
||||
|
||||
# 3. run the application
|
||||
rdagent data_science --competition sf-crime
|
||||
```
|
||||
|
||||
### 🖥️ Monitor the Application Results
|
||||
- You can run the following command for our demo program to see the run logs.
|
||||
|
||||
```sh
|
||||
rdagent ui --port 19899 --log_dir <your log folder like "log/">
|
||||
```
|
||||
|
||||
**Note:** Although port 19899 is not commonly used, but before you run this demo, you need to check if port 19899 is occupied. If it is, please change it to another port that is not occupied.
|
||||
|
||||
You can check if a port is occupied by running the following command.
|
||||
|
||||
```sh
|
||||
rdagent health_check
|
||||
```
|
||||
|
||||
# 🏭 Scenarios
|
||||
|
||||
We have applied R&D-Agent to multiple valuable data-driven industrial scenarios.
|
||||
|
||||
|
||||
## 🎯 Goal: Agent for Data-driven R&D
|
||||
|
||||
In this project, we are aiming to build an Agent to automate Data-Driven R\&D that can
|
||||
+ 📄 Read real-world material (reports, papers, etc.) and **extract** key formulas, descriptions of interested **features** and **models**, which are the key components of data-driven R&D .
|
||||
+ 🛠️ **Implement** the extracted formulas (e.g., features, factors, and models) in runnable codes.
|
||||
+ Due to the limited ability of LLM in implementing at once, build an evolving process for the agent to improve performance by learning from feedback and knowledge.
|
||||
+ 💡 Propose **new ideas** based on current knowledge and observations.
|
||||
|
||||
<!--  -->
|
||||
|
||||
## 📈 Scenarios/Demos
|
||||
|
||||
In the two key areas of data-driven scenarios, model implementation and data building, our system aims to serve two main roles: 🦾Copilot and 🤖Agent.
|
||||
- The 🦾Copilot follows human instructions to automate repetitive tasks.
|
||||
- The 🤖Agent, being more autonomous, actively proposes ideas for better results in the future.
|
||||
|
||||
The supported scenarios are listed below:
|
||||
|
||||
| Scenario/Target | Model Implementation | Data Building |
|
||||
| -- | -- | -- |
|
||||
| **💹 Finance** | 🤖 [Iteratively Proposing Ideas & Evolving](https://rdagent.azurewebsites.net/model_loop)[▶️YouTube](https://www.youtube.com/watch?v=dm0dWL49Bc0&t=104s) | 🤖 [Iteratively Proposing Ideas & Evolving](https://rdagent.azurewebsites.net/factor_loop) [▶️YouTube](https://www.youtube.com/watch?v=X4DK2QZKaKY&t=6s) <br/> 🦾 [Auto reports reading & implementation](https://rdagent.azurewebsites.net/report_factor)[▶️YouTube](https://www.youtube.com/watch?v=ECLTXVcSx-c) |
|
||||
| **🩺 Medical** | 🤖 [Iteratively Proposing Ideas & Evolving](https://rdagent.azurewebsites.net/dmm)[▶️YouTube](https://www.youtube.com/watch?v=VIaSTZuoZg4) | - |
|
||||
| **🏭 General** | 🦾 [Auto paper reading & implementation](https://rdagent.azurewebsites.net/report_model)[▶️YouTube](https://www.youtube.com/watch?v=BiA2SfdKQ7o) <br/> 🤖 Auto Kaggle Model Tuning | 🤖Auto Kaggle feature Engineering |
|
||||
|
||||
- **[RoadMap](https://rdagent.readthedocs.io/en/latest/scens/data_science.html#roadmap)**: Currently, we are working hard to add new features to the Kaggle scenario.
|
||||
|
||||
Different scenarios vary in entrance and configuration. Please check the detailed setup tutorial in the scenarios documents.
|
||||
|
||||
Here is a gallery of [successful explorations](https://github.com/SunsetWolf/rdagent_resource/releases/download/demo_traces/demo_traces.zip) (5 traces showed in **[🖥️ Live Demo](https://rdagent.azurewebsites.net/)**). You can download and view the execution trace using [this command](https://github.com/microsoft/RD-Agent?tab=readme-ov-file#%EF%B8%8F-monitor-the-application-results) from the documentation.
|
||||
|
||||
Please refer to **[📖readthedocs_scen](https://rdagent.readthedocs.io/en/latest/scens/catalog.html)** for more details of the scenarios.
|
||||
|
||||
# ⚙️ Framework
|
||||
|
||||
<div align="center">
|
||||
<img src="docs/_static/Framework-RDAgent.png" alt="Framework-RDAgent" width="85%">
|
||||
</div>
|
||||
|
||||
|
||||
Automating the R&D process in data science is a highly valuable yet underexplored area in industry. We propose a framework to push the boundaries of this important research field.
|
||||
|
||||
The research questions within this framework can be divided into three main categories:
|
||||
| Research Area | Paper/Work List |
|
||||
|--------------------|-----------------|
|
||||
| **Benchmark the R&D abilities** | [Benchmark](#benchmark) |
|
||||
| **Idea proposal:** Explore new ideas or refine existing ones | [Research](#research) |
|
||||
| **Ability to realize ideas:** Implement and execute ideas | [Development](#development) |
|
||||
|
||||
We believe that the key to delivering high-quality solutions lies in the ability to evolve R&D capabilities. Agents should learn like human experts, continuously improving their R&D skills.
|
||||
|
||||
More documents can be found in the **[📖 readthedocs](https://rdagent.readthedocs.io/)**.
|
||||
|
||||
# 📃 Paper/Work list
|
||||
|
||||
## Overall Technical Report
|
||||
- [R&D-Agent: Automating Data-Driven AI Solution Building Through LLM-Powered Automated Research, Development, and Evolution](https://arxiv.org/abs/2505.14738)
|
||||
```BibTeX
|
||||
@misc{yang2024rdagent,
|
||||
title={R\&D-Agent: Automating Data-Driven AI Solution Building Through LLM-Powered Automated Research, Development, and Evolution},
|
||||
author={Xu Yang and Xiao Yang and Shikai Fang and Bowen Xian and Yuante Li and Jian Wang and Minrui Xu and Haoran Pan and Xinpeng Hong and Weiqing Liu and Yelong Shen and Weizhu Chen and Jiang Bian},
|
||||
year={2025},
|
||||
eprint={2505.14738},
|
||||
archivePrefix={arXiv},
|
||||
primaryClass={cs.AI},
|
||||
url={https://arxiv.org/abs/2505.14738}
|
||||
}
|
||||
```
|
||||

|
||||
|
||||
---
|
||||
|
||||
## Strategy Discovery
|
||||
|
||||
### R&D Loop (`scripts/nexquant_rd_loop.py`)
|
||||
|
||||
## 📊 Benchmark
|
||||
- [Towards Data-Centric Automatic R&D](https://arxiv.org/abs/2404.11276)
|
||||
```BibTeX
|
||||
@misc{chen2024datacentric,
|
||||
title={Towards Data-Centric Automatic R&D},
|
||||
author={Haotian Chen and Xinjie Shen and Zeqi Ye and Wenjun Feng and Haoxue Wang and Xiao Yang and Xu Yang and Weiqing Liu and Jiang Bian},
|
||||
year={2024},
|
||||
eprint={2404.11276},
|
||||
archivePrefix={arXiv},
|
||||
primaryClass={cs.AI}
|
||||
}
|
||||
```
|
||||
┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐
|
||||
│ Explore │ ──→ │ Exploit │ ──→ │ Optuna │ ──→ │ LightGBM │
|
||||
│ (Random) │ │ (Mutate) │ │ (Tuning) │ │ (ML) │
|
||||
└──────────┘ └──────────┘ └──────────┘ └──────────┘
|
||||
30% 70% /500 iter /2000 iter
|
||||

|
||||
|
||||
## 🔍 Research
|
||||
|
||||
In a data mining expert's daily research and development process, they propose a hypothesis (e.g., a model structure like RNN can capture patterns in time-series data), design experiments (e.g., finance data contains time-series and we can verify the hypothesis in this scenario), implement the experiment as code (e.g., Pytorch model structure), and then execute the code to get feedback (e.g., metrics, loss curve, etc.). The experts learn from the feedback and improve in the next iteration.
|
||||
|
||||
Based on the principles above, we have established a basic method framework that continuously proposes hypotheses, verifies them, and gets feedback from the real-world practice. This is the first scientific research automation framework that supports linking with real-world verification.
|
||||
|
||||
For more detail, please refer to our **[🖥️ Live Demo page](https://rdagent.azurewebsites.net)**.
|
||||
|
||||
## 🛠️ Development
|
||||
|
||||
- [Collaborative Evolving Strategy for Automatic Data-Centric Development](https://arxiv.org/abs/2407.18690)
|
||||
```BibTeX
|
||||
@misc{yang2024collaborative,
|
||||
title={Collaborative Evolving Strategy for Automatic Data-Centric Development},
|
||||
author={Xu Yang and Haotian Chen and Wenjun Feng and Haoxue Wang and Zeqi Ye and Xinjie Shen and Xiao Yang and Shizhao Sun and Weiqing Liu and Jiang Bian},
|
||||
year={2024},
|
||||
eprint={2407.18690},
|
||||
archivePrefix={arXiv},
|
||||
primaryClass={cs.AI}
|
||||
}
|
||||
```
|
||||

|
||||
|
||||
**17 TA-Lib indicators**: MACD, RSI, Donchian, SAR, ADX, BBANDS, CCI, WCLPRICE, MFI, OBV, STOCH, ROC, AROON, AROONOSC, MOM, ULTOSC, WILLR
|
||||
## Deep Application in Diverse Scenarios
|
||||
|
||||
**4 timeframes**: 15min, 30min, 1h, 4h
|
||||
|
||||
**3 strategy types**: Single-TF, Multi-TF (vote majority), Portfolio (indicator ensemble)
|
||||
|
||||
**Discovery example** (50,000 iterations):
|
||||
```
|
||||
random → SAR(+65) → MACD(+73) → MACD-mutated(+102.75, +32%/month)
|
||||
↓
|
||||
Optuna tuned params
|
||||
↓
|
||||
LightGBM ensemble
|
||||
- [R&D-Agent-Quant: A Multi-Agent Framework for Data-Centric Factors and Model Joint Optimization](https://arxiv.org/abs/2505.15155)
|
||||
```BibTeX
|
||||
@misc{li2025rdagentquant,
|
||||
title={R\&D-Agent-Quant: A Multi-Agent Framework for Data-Centric Factors and Model Joint Optimization},
|
||||
author={Yuante Li and Xu Yang and Xiao Yang and Minrui Xu and Xisen Wang and Weiqing Liu and Jiang Bian},
|
||||
year={2025},
|
||||
eprint={2505.15155},
|
||||
archivePrefix={arXiv},
|
||||
primaryClass={cs.AI}
|
||||
}
|
||||
```
|
||||

|
||||
|
||||
### Grid Search (`scripts/nexquant_priceaction_loop.py`)
|
||||
|
||||
Deterministic parameter grid over all 17 indicators. Finds MACD(3,10,3) as optimal.
|
||||
# 🤝 Contributing
|
||||
|
||||
### Portfolio Optimizer (`scripts/nexquant_portfolio_optimizer.py`)
|
||||
We welcome contributions and suggestions to improve R&D-Agent. Please refer to the [Contributing Guide](CONTRIBUTING.md) for more details on how to contribute.
|
||||
|
||||
Greedy correlation-aware selection from discovered strategies.
|
||||
Before submitting a pull request, ensure that your code passes the automatic CI checks.
|
||||
|
||||
---
|
||||
## 📝 Guidelines
|
||||
This project welcomes contributions and suggestions.
|
||||
Contributing to this project is straightforward and rewarding. Whether it's solving an issue, addressing a bug, enhancing documentation, or even correcting a typo, every contribution is valuable and helps improve R&D-Agent.
|
||||
|
||||
## Live Trading
|
||||
To get started, you can explore the issues list, or search for `TODO:` comments in the codebase by running the command `grep -r "TODO:"`.
|
||||
|
||||
Closed-source module at `git_ignore_folder/nexquant_live_trader.py`. Architecture:
|
||||
<img src="https://img.shields.io/github/contributors-anon/microsoft/RD-Agent"/>
|
||||
|
||||
```
|
||||
MACD(3,10,3) Signal → cTrader OpenAPI → Live Account
|
||||
4-TF 2/4 Votes (WebSocket+Protobuf) ↓
|
||||
Paper Mode
|
||||
```
|
||||
<a href="https://github.com/microsoft/RD-Agent/graphs/contributors">
|
||||
<img src="https://contrib.rocks/image?repo=microsoft/RD-Agent&max=100&columns=15" />
|
||||
</a>
|
||||
|
||||
Integration: cTrader WebSocket `live.ctraderapi.com:5035`, OAuth2 authentication, Protobuf message encoding, FIX protocol.
|
||||
Before we released R&D-Agent as an open-source project on GitHub, it was an internal project within our group. Unfortunately, the internal commit history was not preserved when we removed some confidential code. As a result, some contributions from our group members, including Haotian Chen, Wenjun Feng, Haoxue Wang, Zeqi Ye, Xinjie Shen, and Jinhui Li, were not included in the public commits.
|
||||
|
||||
---
|
||||
|
||||
## Features
|
||||
|
||||
### ⚡ Numba Backtest
|
||||
- 735M bars/second (0.003s for 2.26M bars)
|
||||
- JIT-compiled profit/drawdown/sharpe computation
|
||||
- Signal construction via pandas resample + TA-Lib (~0.4s) is the bottleneck
|
||||
|
||||
### 🔍 Four Discovery Methods
|
||||
- **Explore**: Random indicator + timeframe + parameters
|
||||
- **Exploit**: Mutation of top-5 SOTA strategies (parameter tweak, indicator swap, timeframe change)
|
||||
- **Optuna**: 20-trial TPE hyperparameter optimization on best strategy
|
||||
- **LightGBM**: ML classifier on SOTA indicator signals (80/20 train/test split)
|
||||
|
||||
### 📊 TA-Lib Integration
|
||||
- 17 indicators with full parameter ranges
|
||||
- Auto-guard against bad parameters (negative/zero values that crash TA-Lib)
|
||||
- Multi-timeframe voting with configurable threshold
|
||||
|
||||
### 🔒 Security & Quality
|
||||
- 0 Dependabot alerts, 0 CodeScan alerts
|
||||
- No proprietary terms in git history
|
||||
- Closed-source detection CI
|
||||
|
||||
---
|
||||
|
||||
## Project Structure
|
||||
|
||||
```
|
||||
nexquant/
|
||||
├── scripts/ # Strategy discovery & trading
|
||||
│ ├── nexquant_rd_loop.py # High-speed R&D loop (Numba + Optuna + ML)
|
||||
│ ├── nexquant_priceaction_loop.py # TA-Lib grid search loop
|
||||
│ ├── nexquant_portfolio_optimizer.py # Correlation-aware portfolio selection
|
||||
│ ├── nexquant_gridsearch.py # Deterministic parameter grid search
|
||||
│ ├── nexquant_daily_strategies.py # Daily Kronos + factor combinations
|
||||
│ ├── nexquant_gen_strategies_real_bt.py # LLM-based strategy generation
|
||||
│ ├── nexquant_autopilot.py # 24/7 continuous generator
|
||||
│ └── nexquant_parallel.py # Multi-instance parallel runs
|
||||
├── rdagent/ # Core framework (LLM-based, see note below)
|
||||
│ ├── app/ # CLI and scenario apps
|
||||
│ ├── components/ # Backtest engine, protections, coders
|
||||
│ ├── core/ # Core abstractions
|
||||
│ ├── scenarios/ # Domain-specific scenarios
|
||||
│ └── utils/ # Utilities
|
||||
├── git_ignore_folder/ # Closed-source (never committed)
|
||||
│ ├── nexquant_live_trader.py # cTrader live trading
|
||||
│ ├── nexquant_fix_trader.py # FIX protocol trader
|
||||
│ ├── intraday_pv_all.h5 # OHLCV data
|
||||
│ ├── gbpusdt_1min.h5 # GBP/USD data
|
||||
│ └── btc_1min.h5 # BTC data
|
||||
├── test/ # 1,125+ collected tests
|
||||
├── data_config.yaml # Walk-forward split configuration
|
||||
├── requirements.txt # Dependencies
|
||||
└── AGENTS.md # Agent configuration & workflow guide
|
||||
```
|
||||
|
||||
> **Note on `rdagent/`**: The LLM-based R&D framework (`rdagent fin_quant`) is part of the codebase but the Qlib/CoSTEER pipeline currently produces zero factors. The primary strategy discovery path is the Numba-based loop in `scripts/`.
|
||||
|
||||
---
|
||||
|
||||
## Installation
|
||||
|
||||
### Prerequisites
|
||||
- **Conda** (Miniconda or Anaconda)
|
||||
- **TA-Lib** system library (`apt install ta-lib` or `brew install ta-lib`)
|
||||
- **Linux** (Ubuntu 22.04+)
|
||||
|
||||
### Install
|
||||
|
||||
```bash
|
||||
git clone https://github.com/TPTBusiness/NexQuant && cd NexQuant
|
||||
conda create -n nexquant python=3.10 -y && conda activate nexquant
|
||||
pip install -e .
|
||||
```
|
||||
|
||||
### Data
|
||||
Place OHLCV HDF5 data at `git_ignore_folder/intraday_pv_all.h5`:
|
||||
```python
|
||||
# Format: MultiIndex (datetime, instrument), columns: $open $close $high $low $volume
|
||||
df.to_hdf('git_ignore_folder/intraday_pv_all.h5', key='data')
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## License
|
||||
|
||||
**GNU Affero General Public License v3.0 (AGPL-3.0)**. See [`LICENSE`](LICENSE).
|
||||
|
||||
---
|
||||
|
||||
## Disclaimer
|
||||
|
||||
NexQuant is provided for **research and educational purposes only**. Past performance does not guarantee future results. Users assume all liability.
|
||||
# ⚖️ Legal disclaimer
|
||||
<p style="line-height: 1; font-style: italic;">The RD-agent is provided “as is”, without warranty of any kind, express or implied, including but not limited to the warranties of merchantability, fitness for a particular purpose and noninfringement. The RD-agent is aimed to facilitate research and development process in the financial industry and not ready-to-use for any financial investment or advice. Users shall independently assess and test the risks of the RD-agent in a specific use scenario, ensure the responsible use of AI technology, including but not limited to developing and integrating risk mitigation measures, and comply with all applicable laws and regulations in all applicable jurisdictions. The RD-agent does not provide financial opinions or reflect the opinions of Microsoft, nor is it designed to replace the role of qualified financial professionals in formulating, assessing, and approving finance products. The inputs and outputs of the RD-agent belong to the users and users shall assume all liability under any theory of liability, whether in contract, torts, regulatory, negligence, products liability, or otherwise, associated with use of the RD-agent and any inputs and outputs thereof.</p>
|
||||
|
||||
+33
-13
@@ -1,21 +1,41 @@
|
||||
# Security Policy
|
||||
<!-- BEGIN MICROSOFT SECURITY.MD V0.0.9 BLOCK -->
|
||||
|
||||
## Reporting a Vulnerability
|
||||
## Security
|
||||
|
||||
We take the security of NexQuant seriously. If you believe you have found a security vulnerability, please report it responsibly.
|
||||
Microsoft takes the security of our software products and services seriously, which includes all source code repositories managed through our GitHub organizations, which include [Microsoft](https://github.com/Microsoft), [Azure](https://github.com/Azure), [DotNet](https://github.com/dotnet), [AspNet](https://github.com/aspnet) and [Xamarin](https://github.com/xamarin).
|
||||
|
||||
If you believe you have found a security vulnerability in any Microsoft-owned repository that meets [Microsoft's definition of a security vulnerability](https://aka.ms/security.md/definition), please report it to us as described below.
|
||||
|
||||
## Reporting Security Issues
|
||||
|
||||
**Please do not report security vulnerabilities through public GitHub issues.**
|
||||
|
||||
### How to Report
|
||||
Instead, please report them to the Microsoft Security Response Center (MSRC) at [https://msrc.microsoft.com/create-report](https://aka.ms/security.md/msrc/create-report).
|
||||
|
||||
1. **Open a private security advisory** on GitHub: https://github.com/TPTBusiness/NexQuant/security/advisories
|
||||
2. Provide a detailed description of the vulnerability
|
||||
3. Include steps to reproduce if possible
|
||||
4. We will respond within 48 hours
|
||||
If you prefer to submit without logging in, send email to [secure@microsoft.com](mailto:secure@microsoft.com). If possible, encrypt your message with our PGP key; please download it from the [Microsoft Security Response Center PGP Key page](https://aka.ms/security.md/msrc/pgp).
|
||||
|
||||
### What to Expect
|
||||
You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message. Additional information can be found at [microsoft.com/msrc](https://www.microsoft.com/msrc).
|
||||
|
||||
- We will acknowledge your report within 48 hours
|
||||
- We will investigate and provide updates regularly
|
||||
- Once resolved, we will credit you in the release notes (if desired)
|
||||
- Please allow reasonable time for us to address the issue before public disclosure
|
||||
Please include the requested information listed below (as much as you can provide) to help us better understand the nature and scope of the possible issue:
|
||||
|
||||
* Type of issue (e.g. buffer overflow, SQL injection, cross-site scripting, etc.)
|
||||
* Full paths of source file(s) related to the manifestation of the issue
|
||||
* The location of the affected source code (tag/branch/commit or direct URL)
|
||||
* Any special configuration required to reproduce the issue
|
||||
* Step-by-step instructions to reproduce the issue
|
||||
* Proof-of-concept or exploit code (if possible)
|
||||
* Impact of the issue, including how an attacker might exploit the issue
|
||||
|
||||
This information will help us triage your report more quickly.
|
||||
|
||||
If you are reporting for a bug bounty, more complete reports can contribute to a higher bounty award. Please visit our [Microsoft Bug Bounty Program](https://aka.ms/security.md/msrc/bounty) page for more details about our active programs.
|
||||
|
||||
## Preferred Languages
|
||||
|
||||
We prefer all communications to be in English.
|
||||
|
||||
## Policy
|
||||
|
||||
Microsoft follows the principle of [Coordinated Vulnerability Disclosure](https://aka.ms/security.md/cvd).
|
||||
|
||||
<!-- END MICROSOFT SECURITY.MD BLOCK -->
|
||||
|
||||
+25
-25
@@ -1,25 +1,25 @@
|
||||
# Support
|
||||
|
||||
## How to file issues and get help
|
||||
|
||||
This project uses GitHub Issues to track bugs and feature requests. Please search the existing
|
||||
issues before filing new issues to avoid duplicates. For new issues, file your bug or
|
||||
feature request as a new Issue.
|
||||
|
||||
- **Issues**: [https://github.com/NexQuantAI/nexquant/issues](https://github.com/NexQuantAI/nexquant/issues)
|
||||
|
||||
For help and questions about using this project, please reach out via:
|
||||
|
||||
- **Email**: nico@nexquant.io
|
||||
- **GitHub Discussions**: [https://github.com/NexQuantAI/nexquant/discussions](https://github.com/NexQuantAI/nexquant/discussions)
|
||||
|
||||
## Community Support
|
||||
|
||||
We encourage users to help each other through GitHub Discussions or by contributing
|
||||
answers to issues. If you find a solution to a problem, please consider sharing it
|
||||
publicly to help others.
|
||||
|
||||
## Support Policy
|
||||
|
||||
Support is provided on a best-effort basis by the maintainers and community.
|
||||
For critical issues or commercial support needs, please contact the maintainers directly.
|
||||
# TODO: The maintainer of this repo has not yet edited this file
|
||||
|
||||
**REPO OWNER**: Do you want Customer Service & Support (CSS) support for this product/project?
|
||||
|
||||
- **No CSS support:** Fill out this template with information about how to file issues and get help.
|
||||
- **Yes CSS support:** Fill out an intake form at [aka.ms/onboardsupport](https://aka.ms/onboardsupport). CSS will work with/help you to determine next steps.
|
||||
- **Not sure?** Fill out an intake as though the answer were "Yes". CSS will help you decide.
|
||||
|
||||
*Then remove this first heading from this SUPPORT.MD file before publishing your repo.*
|
||||
|
||||
# Support
|
||||
|
||||
## How to file issues and get help
|
||||
|
||||
This project uses GitHub Issues to track bugs and feature requests. Please search the existing
|
||||
issues before filing new issues to avoid duplicates. For new issues, file your bug or
|
||||
feature request as a new Issue.
|
||||
|
||||
For help and questions about using this project, please **REPO MAINTAINER: INSERT INSTRUCTIONS HERE
|
||||
FOR HOW TO ENGAGE REPO OWNERS OR COMMUNITY FOR HELP. COULD BE A STACK OVERFLOW TAG OR OTHER
|
||||
CHANNEL. WHERE WILL YOU HELP PEOPLE?**.
|
||||
|
||||
## Microsoft Support Policy
|
||||
|
||||
Support for this **PROJECT or PRODUCT** is limited to the resources listed above.
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
We encourage to set the TODOs in code. But some TODOs are more global.
|
||||
So we place it here.
|
||||
|
||||
|
||||
- [ ] Aligning the naming of files in components & scenarios.
|
||||
- We would like to have the same logic for naming convention in components(reusable components for all scenarios) and scenarios (componets for specific scenario).
|
||||
- But now we have following mismatch
|
||||
- `coder` in `components` & `developer` in `components`
|
||||
- [ ] The name of the folders mismatch with the content in them.
|
||||
- Why are scenarios in experiments?
|
||||
@@ -1,175 +0,0 @@
|
||||
# NexQuant v1.0.0 Release Notes
|
||||
|
||||
**Release Date:** 2026-04-02
|
||||
|
||||
**Tag:** v1.0.0
|
||||
|
||||
---
|
||||
|
||||
## 🎉 Overview
|
||||
|
||||
Initial release of NexQuant - an autonomous AI-powered quantitative trading agent for EUR/USD forex markets.
|
||||
|
||||
---
|
||||
|
||||
## ✨ Added
|
||||
|
||||
### Autonomous Factor Generation
|
||||
- **110+ EURUSD factors** generated autonomously using LLMs
|
||||
- Multi-agent debate system (Bull/Bear/Neutral analysts)
|
||||
- Stanley Druckenmiller-style macro analysis agent
|
||||
- Market regime detection using Hurst Exponent
|
||||
- Session-aware analysis (Asian/London/NY sessions)
|
||||
|
||||
### Backtesting Engine
|
||||
- IC (Information Coefficient) calculation
|
||||
- Sharpe Ratio, Sortino Ratio, Calmar Ratio
|
||||
- Max Drawdown with start/end dates
|
||||
- Win Rate, Total Trades tracking
|
||||
- Transaction cost modeling (1.5 bps spread)
|
||||
- Forward return calculation
|
||||
|
||||
### Results Database
|
||||
- SQLite database for tracking all backtest results
|
||||
- Tables: factors, backtest_runs, backtest_metrics, daily_returns, loop_results
|
||||
- Queries for top factors by Sharpe/IC
|
||||
- Aggregate statistics
|
||||
- Foreign key integrity
|
||||
|
||||
### Risk Management
|
||||
- Correlation matrix between factors
|
||||
- Portfolio optimization (Mean-Variance, Risk Parity)
|
||||
- Position sizing with volatility adjustment
|
||||
- Risk limits (position size, leverage, drawdown)
|
||||
- Advanced risk manager with custom thresholds
|
||||
|
||||
### Dashboards & UI
|
||||
- **Web Dashboard** (Flask + HTML) with live progress
|
||||
- **CLI Dashboard** (Rich library) for terminal
|
||||
- Real-time macro data (EURUSD, DXY, Volatility)
|
||||
- Session info with recommendations
|
||||
- Memory statistics (Win-Rate, PnL, Sharpe)
|
||||
|
||||
### Testing Infrastructure
|
||||
- **97 unit tests** with **98.77% code coverage**
|
||||
- Edge case testing for all metrics
|
||||
- Integration tests for full workflows
|
||||
- pytest configuration
|
||||
- Test fixtures for mock data
|
||||
|
||||
### Documentation
|
||||
- Comprehensive QWEN.md (development guide)
|
||||
- ATTRIBUTION.md (usage guidelines)
|
||||
- README.md (installation, quick start)
|
||||
- All code comments in English
|
||||
- Git commit guidelines (English-only)
|
||||
|
||||
### Developer Experience
|
||||
- English-only commit messages policy
|
||||
- Clean git history (all German messages translated)
|
||||
- .gitignore for sensitive files (.env, logs, results, etc.)
|
||||
- Makefile for common tasks
|
||||
- Pre-commit hooks support
|
||||
|
||||
---
|
||||
|
||||
## 🔧 Changed
|
||||
|
||||
- Rebranded from RD-Agent to NexQuant for EUR/USD quantitative trading
|
||||
- Updated project metadata for NexQuantAI organization
|
||||
- All code comments translated to English
|
||||
- Removed 'Inspired by' comments, added comprehensive Acknowledgments
|
||||
- Enhanced .gitignore for better file management
|
||||
- Removed test configuration files from root directory
|
||||
- Cleaned up log files and test artifacts from git history
|
||||
|
||||
---
|
||||
|
||||
## 🛡️ Fixed
|
||||
|
||||
- Removed all Chinese stock references, replaced with EUR/USD 1min FX data
|
||||
- Migrated to 1min EURUSD data (2020-2026)
|
||||
- Injected MultiIndex warning into factor interface prompt
|
||||
- Fixed Embedding Context Length errors with intelligent chunking
|
||||
- Fixed LLM connection errors with multi-provider fallback
|
||||
- Fixed division by zero in volatility calculations
|
||||
- Fixed NaN handling in correlation matrices
|
||||
|
||||
---
|
||||
|
||||
## 📦 Dependencies
|
||||
|
||||
### Core
|
||||
- Python 3.10/3.11
|
||||
- PyTorch for deep learning
|
||||
- Qlib for backtesting
|
||||
- Flask for web dashboard
|
||||
- Rich/Typer for CLI
|
||||
- pytest for testing (98.77% coverage)
|
||||
|
||||
### Additional
|
||||
- pandas, numpy for data processing
|
||||
- SQLite for database
|
||||
- yfinance for live market data
|
||||
- langchain, langgraph for agent workflows
|
||||
|
||||
---
|
||||
|
||||
## 📊 Statistics
|
||||
|
||||
| Metric | Value |
|
||||
|--------|-------|
|
||||
| Lines of Code | ~15,000+ |
|
||||
| Files | 100+ |
|
||||
| Commits | 20+ |
|
||||
| Contributors | 1 |
|
||||
| Test Coverage | 98.77% |
|
||||
| Tests Passed | 97/97 |
|
||||
| Factors Generated | 110+ |
|
||||
|
||||
---
|
||||
|
||||
## 🙏 Acknowledgments
|
||||
|
||||
This release builds upon and is inspired by:
|
||||
|
||||
- **Microsoft RD-Agent** (MIT License) - Foundation for autonomous R&D framework
|
||||
- **TradingAgents** (Apache 2.0 License) - Multi-agent debate patterns
|
||||
- **ai-hedge-fund** - Macro analysis and risk management concepts
|
||||
|
||||
**All code in NexQuant v1.0.0 is originally written and independently implemented.**
|
||||
|
||||
---
|
||||
|
||||
## 📝 License
|
||||
|
||||
**MIT License** - See [LICENSE](../LICENSE) file for details.
|
||||
|
||||
### Attribution Requirements
|
||||
|
||||
If you use this code or concepts in your project, you **must**:
|
||||
1. Include the MIT License text
|
||||
2. Keep the copyright notice: "Copyright (c) 2025 NexQuant Team"
|
||||
3. Provide attribution to the original project
|
||||
|
||||
See [ATTRIBUTION.md](../ATTRIBUTION.md) for detailed guidelines.
|
||||
|
||||
---
|
||||
|
||||
## 🔗 Links
|
||||
|
||||
- **GitHub Release:** https://github.com/TPTBusiness/NexQuant/releases/tag/v1.0.0
|
||||
- **Main Changelog:** ../CHANGELOG.md
|
||||
- **Attribution Guidelines:** ../ATTRIBUTION.md
|
||||
- **Installation Guide:** ../README.md#installation
|
||||
- **Quick Start:** ../README.md#quick-start
|
||||
|
||||
---
|
||||
|
||||
<div align="center">
|
||||
|
||||
**Made with ❤️ by NexQuant Team**
|
||||
|
||||
For detailed usage guidelines, see [README.md](../README.md)
|
||||
|
||||
</div>
|
||||
@@ -1,102 +0,0 @@
|
||||
# NexQuant v2.0.0 Release Notes
|
||||
|
||||
**Release Date:** 2026-04-10
|
||||
|
||||
**Tag:** v2.0.0
|
||||
|
||||
---
|
||||
|
||||
## 🎉 Overview
|
||||
|
||||
Major update adding AI-powered strategy generation, realistic backtesting, and comprehensive CLI tooling. NexQuant now autonomously generates, evaluates, and optimizes trading strategies using local LLMs.
|
||||
|
||||
---
|
||||
|
||||
## ✨ Added
|
||||
|
||||
### LLM-Powered Strategy Generation
|
||||
- **StrategyOrchestrator**: Generate trading strategies by combining factors with LLM
|
||||
- **Local llama.cpp Support**: Run strategy generation locally (Qwen3.5-35B)
|
||||
- **OpenRouter Support**: Optional cloud model fallback
|
||||
- **Improved Prompts (v3)**: IC-sign-aware factor combination instructions
|
||||
- **Diverse Factor Selection**: Automatic selection by type (momentum, divergence, volatility, session)
|
||||
|
||||
### Realistic Backtesting
|
||||
- **OHLCV-Based Returns**: Real price returns instead of factor proxies
|
||||
- **Spread Costs**: 1.5 bps per trade deducted from returns
|
||||
- **Forward-Fill Support**: Daily factors → 1-min frequency
|
||||
- **Proper Annualization**: sqrt(252*1440) for 1-min data
|
||||
|
||||
### CLI Commands
|
||||
- `rdagent nexquant` - Show beautiful welcome screen (perfect for screenshots!)
|
||||
- `rdagent start_llama` - Start llama.cpp server
|
||||
- `rdagent start_loop` - Start strategy generator loop with auto-restart
|
||||
- `rdagent generate_strategies` - Generate strategies from factors
|
||||
- `rdagent optimize_portfolio` - Portfolio optimization
|
||||
- `rdagent eval_all` - Evaluate factors with full data
|
||||
- `rdagent batch_backtest` - Batch backtest existing factors
|
||||
- `rdagent report` - Generate PDF performance reports
|
||||
- `rdagent rebacktest` - Re-backtest existing strategies
|
||||
|
||||
### Code Quality
|
||||
- **282+ Integration Tests**: All features tested
|
||||
- **Security Hardening**: All Dependabot/CodeQL alerts resolved
|
||||
- **Pre-commit Hooks**: Automated tests + security scanning
|
||||
|
||||
---
|
||||
|
||||
## 🔧 Changed
|
||||
|
||||
- Utility scripts organized in `scripts/` directory
|
||||
- Generated data moved to `results/`
|
||||
- Config files moved to `constraints/`
|
||||
- Root directory cleaned
|
||||
|
||||
---
|
||||
|
||||
## 🐛 Fixed
|
||||
|
||||
- JSON strategy files no longer committed to root
|
||||
- LICENSE badge link corrected (main → master)
|
||||
- Security vulnerabilities resolved (bandit, path traversal)
|
||||
|
||||
---
|
||||
|
||||
## 📦 Installation
|
||||
|
||||
```bash
|
||||
git clone https://github.com/TPTBusiness/NexQuant
|
||||
cd NexQuant
|
||||
pip install -e .
|
||||
```
|
||||
|
||||
## 🚀 Quick Start
|
||||
|
||||
```bash
|
||||
# Show welcome screen
|
||||
rdagent nexquant
|
||||
|
||||
# Start LLM server
|
||||
rdagent start_llama
|
||||
|
||||
# Run trading loop
|
||||
rdagent fin_quant --auto-strategies
|
||||
|
||||
# Generate strategies manually
|
||||
rdagent generate_strategies --count 5 --optuna
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔒 Security
|
||||
|
||||
- All known vulnerabilities resolved
|
||||
- Bandit security scanning integrated
|
||||
- Pre-commit hooks for automated checks
|
||||
- Path traversal prevention hardened
|
||||
|
||||
---
|
||||
|
||||
## 📄 License
|
||||
|
||||
MIT License - see [LICENSE](../LICENSE) for details.
|
||||
@@ -1,24 +0,0 @@
|
||||
# Bandit Security Scanner Configuration
|
||||
# Documentation: https://bandit.readthedocs.io/
|
||||
|
||||
title: Bandit Security Scan for NexQuant
|
||||
|
||||
# Tests to skip (known false positives or acceptable risks)
|
||||
skips:
|
||||
- B101 # assert_used (asserts are OK in non-production code)
|
||||
- B602 # subprocess_popen_with_shell_equals_true (known issue, will fix separately)
|
||||
- B701 # jinja2_autoescape_false (false positive - code templates, not HTML)
|
||||
- B301 # pickle (known usage for internal data, will audit separately)
|
||||
- B108 # hardcoded_tmp_directory (internal tool)
|
||||
- B615 # huggingface_unsafe_download (will audit separately)
|
||||
- B307 # eval usage (will audit separately)
|
||||
- B614 # pytorch_load (internal benchmark code)
|
||||
- B104 # hardcoded_bind_all_interfaces (internal tool, localhost only)
|
||||
- B310 # urllib_urlopen (internal API calls)
|
||||
|
||||
# Minimum severity to report (LOW, MEDIUM, HIGH)
|
||||
# Pre-commit only warns on MEDIUM, blocks on HIGH
|
||||
severity_level: HIGH
|
||||
|
||||
# Minimum confidence level (LOW, MEDIUM, HIGH)
|
||||
confidence_level: MEDIUM
|
||||
@@ -1,5 +1,8 @@
|
||||
azure-identity==1.25.3
|
||||
dill==0.4.1
|
||||
pillow==12.2.0
|
||||
psutil==6.1.1
|
||||
scipy==1.15.3
|
||||
azure-identity==1.17.1
|
||||
dill==0.3.9
|
||||
pillow==10.4.0
|
||||
psutil==6.1.0
|
||||
rich==13.9.2
|
||||
scipy==1.14.1
|
||||
tqdm==4.66.5
|
||||
litellm==1.72.4
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
azure-identity==1.25.3
|
||||
dill==0.4.1
|
||||
pillow==12.2.0
|
||||
psutil==6.1.1
|
||||
scipy==1.15.3
|
||||
azure-identity==1.17.1
|
||||
dill==0.3.9
|
||||
pillow==10.4.0
|
||||
psutil==6.1.0
|
||||
rich==13.9.2
|
||||
scipy==1.14.1
|
||||
tqdm==4.66.5
|
||||
litellm==1.72.4
|
||||
|
||||
@@ -1,44 +0,0 @@
|
||||
# ============================================================
|
||||
# NexQuant Data Configuration
|
||||
# Change instrument, frequency, and time periods here
|
||||
# All other components read from this file
|
||||
# ============================================================
|
||||
|
||||
instrument: EURUSD
|
||||
frequency: 1min # 1min, 5min, 15min, 1h, 1d
|
||||
data_path: ~/.qlib/qlib_data/eurusd_1min_data
|
||||
|
||||
# Available columns (no $factor column!)
|
||||
columns:
|
||||
- $open
|
||||
- $close
|
||||
- $high
|
||||
- $low
|
||||
- $volume
|
||||
|
||||
# Walk-Forward Split
|
||||
train_start: "2022-03-14"
|
||||
train_end: "2024-06-30"
|
||||
valid_start: "2024-07-01"
|
||||
valid_end: "2024-12-31"
|
||||
test_start: "2025-01-01"
|
||||
test_end: "2026-03-20"
|
||||
|
||||
# Market Context for LLM Prompts
|
||||
market_context:
|
||||
spread_bps: 1.5
|
||||
sessions:
|
||||
asian: "00:00-08:00 UTC"
|
||||
london: "08:00-16:00 UTC"
|
||||
ny: "13:00-21:00 UTC"
|
||||
overlap: "13:00-16:00 UTC"
|
||||
target_arr: 9.62 # % ARR to beat
|
||||
max_drawdown: 20 # % maximum drawdown
|
||||
|
||||
# Lookback Reference (in Bars)
|
||||
lookback:
|
||||
1h: 4
|
||||
2h: 8
|
||||
4h: 16
|
||||
8h: 32
|
||||
1d: 96
|
||||
@@ -1,43 +0,0 @@
|
||||
# PREDIX Data Configuration
|
||||
#
|
||||
# This file configures the data sources and paths for EUR/USD trading.
|
||||
# Adjust paths and settings to match your environment.
|
||||
|
||||
# Data source configuration
|
||||
data_source:
|
||||
type: "qlib" # Options: qlib, csv, api
|
||||
provider: "eurusd_1min"
|
||||
|
||||
# Data paths
|
||||
paths:
|
||||
qlib_data_dir: "~/.qlib/qlib_data/eurusd_1min_data"
|
||||
raw_data_dir: "data_raw"
|
||||
cache_dir: ".cache"
|
||||
|
||||
# Instrument configuration
|
||||
instrument:
|
||||
symbol: "EURUSD"
|
||||
timeframe: "1min"
|
||||
sessions:
|
||||
asian:
|
||||
start: "00:00"
|
||||
end: "08:00"
|
||||
london:
|
||||
start: "08:00"
|
||||
end: "16:00"
|
||||
ny:
|
||||
start: "13:00"
|
||||
end: "21:00"
|
||||
overlap:
|
||||
start: "13:00"
|
||||
end: "16:00"
|
||||
|
||||
# Trading costs
|
||||
costs:
|
||||
spread_bps: 1.5 # Average spread in basis points
|
||||
commission_bps: 0.0 # Commission (if any)
|
||||
|
||||
# Data range
|
||||
date_range:
|
||||
start: "2020-01-01"
|
||||
end: "2026-03-20"
|
||||
@@ -1,101 +0,0 @@
|
||||
# Attribution Guidelines
|
||||
|
||||
## Using NexQuant in Your Project
|
||||
|
||||
If you use code, concepts, or ideas from this project, you **must**:
|
||||
|
||||
### 1. Keep the MIT License
|
||||
|
||||
Include the full MIT License text in your project's LICENSE file or documentation.
|
||||
|
||||
### 2. Include Copyright Notice
|
||||
|
||||
```
|
||||
Copyright (c) 2025 NexQuant Team
|
||||
Original Project: https://github.com/TPTBusiness/NexQuant
|
||||
```
|
||||
|
||||
### 3. Provide Attribution
|
||||
|
||||
Add a notice in your documentation or README:
|
||||
|
||||
```markdown
|
||||
## Acknowledgments
|
||||
|
||||
This project uses code/concepts from [NexQuant](https://github.com/TPTBusiness/NexQuant),
|
||||
licensed under the [MIT License](https://opensource.org/licenses/MIT).
|
||||
```
|
||||
|
||||
### 4. State Changes
|
||||
|
||||
If you modified the code:
|
||||
|
||||
```markdown
|
||||
## Modifications
|
||||
|
||||
Based on NexQuant (original by NexQuant Team).
|
||||
Modified by [Your Name/Organization] on [Date].
|
||||
Changes: [Brief description of changes]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## What You CAN Do
|
||||
|
||||
✅ Use in commercial projects
|
||||
✅ Modify the code
|
||||
✅ Distribute copies
|
||||
✅ Use in proprietary software
|
||||
✅ Sell products that include this code
|
||||
|
||||
## What You CANNOT Do
|
||||
|
||||
❌ Remove copyright notice
|
||||
❌ Remove license text
|
||||
❌ Claim you wrote the original code
|
||||
❌ Hold the authors liable
|
||||
|
||||
---
|
||||
|
||||
## Example Attribution
|
||||
|
||||
**Good Example:**
|
||||
```markdown
|
||||
# My Trading Project
|
||||
|
||||
This project uses factor generation concepts from [NexQuant](https://github.com/TPTBusiness/NexQuant).
|
||||
|
||||
## License
|
||||
MIT License - see LICENSE file for details.
|
||||
|
||||
## Credits
|
||||
- Original NexQuant code by NexQuant Team (MIT License)
|
||||
- Modified by John Doe, 2025
|
||||
```
|
||||
|
||||
**Bad Example (Copyright Violation):**
|
||||
```markdown
|
||||
# My Trading Project
|
||||
|
||||
All code written by John Doe.
|
||||
All rights reserved. No copying allowed.
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Legal Basis
|
||||
|
||||
This requirement comes from the MIT License itself:
|
||||
|
||||
> "The above copyright notice and this permission notice shall be included
|
||||
> in all copies or substantial portions of the Software."
|
||||
|
||||
Failure to comply means your license to use this code is automatically terminated.
|
||||
|
||||
---
|
||||
|
||||
## Questions?
|
||||
|
||||
If you're unsure about attribution requirements, please open an issue or contact us.
|
||||
|
||||
We want our code to be used and appreciated, but proper attribution is essential.
|
||||
@@ -1,34 +0,0 @@
|
||||
# Changelog
|
||||
|
||||
All notable changes to NexQuant will be documented in this file.
|
||||
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## Releases
|
||||
|
||||
### Version 1.0.0 (2026-04-02)
|
||||
|
||||
**Initial Release - EURUSD Trading Agent**
|
||||
|
||||
📄 **Detailed release notes:** [changelog/v1.0.0.md](changelog/v1.0.0.md)
|
||||
|
||||
**Highlights:**
|
||||
- ✨ 110+ EURUSD factors generated autonomously
|
||||
- 🧠 Multi-agent debate system (Bull/Bear/Neutral)
|
||||
- 📊 Backtesting engine with IC, Sharpe, Drawdown
|
||||
- 🗄️ SQLite database for tracking results
|
||||
- ⚖️ Risk management with correlation analysis
|
||||
- 📱 Web + CLI dashboards
|
||||
- ✅ 97 tests with 98.77% coverage
|
||||
- 📚 Comprehensive documentation
|
||||
|
||||
---
|
||||
|
||||
## Historical Changes (from RD-Agent upstream)
|
||||
|
||||
For earlier changes inherited from the RD-Agent project, see the [upstream changelog](https://github.com/microsoft/RD-Agent/blob/main/CHANGELOG.md).
|
||||
|
||||
---
|
||||
|
||||
## [Unreleased]
|
||||
@@ -1,95 +0,0 @@
|
||||
# 🎯 PREDIX: Vollständige Integration in fin_quant Loop
|
||||
|
||||
## ✅ Implementierte Features
|
||||
|
||||
### 1. Realistisches Backtesting
|
||||
- **Echte OHLCV-Daten** aus `intraday_pv.h5` (2.26M Bars, 2020-2026)
|
||||
- **Forward-Fill** täglicher Faktoren auf 1-Min-Frequenz
|
||||
- **Spread-Kosten**: 1.5 bps pro Trade
|
||||
- **Korrekte Annualisierung**: sqrt(252*1440) für 1-Min-Daten
|
||||
|
||||
### 2. Verbesserter LLM-Prompt
|
||||
- **IC-geführte Faktorwahl**: |IC| > 0.10 PRIORITIZE, |IC| > 0.05 USE
|
||||
- **IC-gewichtete Kombinationen**: Höhere IC = höheres Gewicht
|
||||
- **Bessere Beispiele** mit IC-Gewichten im Prompt
|
||||
- **Verfügbarkeit von 'close' Series** für zusätzliche Berechnungen
|
||||
|
||||
### 3. Optuna-Optimierung
|
||||
- **20 Trials pro Strategie** (konfigurierbar)
|
||||
- **TPESampler** mit MedianPruner
|
||||
- **Optimiert**: entry_threshold, rolling_window, SL, TP, Trailing Stop
|
||||
- **Auto-Update** wenn Optuna Sharpe verbessert
|
||||
|
||||
### 4. Automatische Strategiegenerierung
|
||||
- **Trigger**: Alle 500 Faktoren (konfigurierbar)
|
||||
- **3 Strategien pro Zyklus** mit zufälligen Faktor-Kombinationen
|
||||
- **Graceful Degradation**: Bricht Hauptloop nicht bei Fehlern
|
||||
|
||||
## 🚀 Benutzung
|
||||
|
||||
### Automatisch (im fin_quant Loop)
|
||||
```bash
|
||||
# Standard: Alle 500 Faktoren
|
||||
rdagent fin_quant --auto-strategies
|
||||
|
||||
# Custom threshold
|
||||
rdagent fin_quant --auto-strategies --auto-strategies-threshold 1000
|
||||
|
||||
# Mit OpenRouter
|
||||
rdagent fin_quant -m openrouter --auto-strategies
|
||||
```
|
||||
|
||||
### Manuell
|
||||
```bash
|
||||
# 5 Strategien mit Optuna
|
||||
rdagent generate_strategies --count 5 --optuna --optuna-trials 20
|
||||
|
||||
# Ohne Optuna (schneller)
|
||||
rdagent generate_strategies --count 5 --no-optuna
|
||||
```
|
||||
|
||||
## 📊 Testergebnisse
|
||||
|
||||
### MomentumDivergenceZScore (vorher vs. nachher)
|
||||
|
||||
| Metrik | Vorher | Nachher |
|
||||
|--------|--------|---------|
|
||||
| **Datenpunkte** | 259 (4.3h) | 823,450 (2.27 Jahre) |
|
||||
| **Sharpe** | 3.59 | 6.04 |
|
||||
| **Max DD** | -0.22% | -1.57% |
|
||||
| **Win Rate** | 49.46% | 49.19% |
|
||||
| **Ann Return** | 543% (falsch) | 21.88% ✅ |
|
||||
|
||||
## 🔧 Architecture
|
||||
|
||||
```
|
||||
fin_quant Loop
|
||||
│
|
||||
├─ Factor Generation (LLM → Docker → Evaluation)
|
||||
│ └─ Every 500 factors → Trigger Strategy Generation
|
||||
│
|
||||
└─ StrategyOrchestrator (auto-strategies)
|
||||
│
|
||||
├─ Load Top 50 Factors (by IC)
|
||||
├─ For each strategy (3x):
|
||||
│ ├─ Select random 2-5 factors
|
||||
│ ├─ LLM generates code (improved prompt)
|
||||
│ ├─ Evaluate with real OHLCV
|
||||
│ ├─ Optuna optimize (20 trials)
|
||||
│ └─ Save if accepted
|
||||
│
|
||||
└─ Log results
|
||||
```
|
||||
|
||||
## 📝 Nächste Schritte
|
||||
|
||||
1. **Live Trading**: Bestehende Strategien für Paper Trading nutzen
|
||||
2. **Mehr Faktoren**: Weiterhin Faktoren generieren für bessere Strategien
|
||||
3. **Dashboard**: Live-Statistiken im Web/CLI Dashboard anzeigen
|
||||
|
||||
## ⚠️ Wichtige Hinweise
|
||||
|
||||
- **Forward-Fill** kann zu Daten-Leakage führen (tägliche Werte werden auf Minuten aufgefüllt)
|
||||
- **Optuna** benötigt 20-30 Sekunden pro Strategie
|
||||
- **Auto-Strategies** nur wenn ≥10 Faktoren verfügbar
|
||||
- **LLM** muss verfügbar sein (local oder openrouter)
|
||||
@@ -1,890 +0,0 @@
|
||||
# StrategyBuilder — Architektur-Design
|
||||
|
||||
## Überblick
|
||||
|
||||
Der **StrategyBuilder** kombiniert existierende Faktoren systematisch zu handelbaren Strategien.
|
||||
Im Gegensatz zum ML-Trainer (der ein einzelnes Modell auf Top-Faktoren trainiert) testet der
|
||||
StrategyBuilder **explizite Kombinationsregeln** mit Walk-Forward-Validierung.
|
||||
|
||||
---
|
||||
|
||||
## 1. Klassen-Design
|
||||
|
||||
### 1.1 StrategyCombinator
|
||||
|
||||
**Zweck:** Generiert systematische Faktorkombinationen nach verschiedenen Strategien.
|
||||
|
||||
```python
|
||||
# rdagent/scenarios/qlib/developer/strategy_builder.py
|
||||
|
||||
class CombinationStrategy(Enum):
|
||||
"""Supported combination methods."""
|
||||
PAIR = "pair" # Top-N pairs by IC product
|
||||
TRIPLET = "triplet" # Top triplets
|
||||
CATEGORY = "category" # All factors of same type
|
||||
TEMPORAL = "temporal" # Session/time-specific combos
|
||||
CUSTOM = "custom" # User-defined combinations
|
||||
|
||||
|
||||
@dataclass
|
||||
class StrategySpec:
|
||||
"""Defines a single strategy configuration."""
|
||||
name: str
|
||||
factors: List[str] # Factor names to combine
|
||||
combination_type: str # "weighted_sum", "regime_switch", etc.
|
||||
weighting: str # "equal", "ic_weighted", "risk_parity"
|
||||
metadata: Dict[str, Any] # Additional context (category, session, etc.)
|
||||
|
||||
|
||||
class StrategyCombinator:
|
||||
"""Generate factor combinations systematically."""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
factors_db: ResultsDatabase,
|
||||
min_ic: float = 0.02,
|
||||
max_factors_per_strategy: int = 5,
|
||||
) -> None: ...
|
||||
|
||||
def load_valid_factors(self, min_ic: float = 0.02) -> pd.DataFrame:
|
||||
"""Load all factors with IC >= threshold from DB."""
|
||||
...
|
||||
|
||||
def generate_pairs(
|
||||
self,
|
||||
top_n: int = 50,
|
||||
max_correlation: float = 0.7,
|
||||
) -> List[StrategySpec]:
|
||||
"""
|
||||
Generate pairwise combinations.
|
||||
|
||||
Rules:
|
||||
- Take top_n factors by |IC|
|
||||
- Filter pairs with correlation < max_correlation
|
||||
- Score by |IC1 * IC2| (both must have predictive power)
|
||||
- Prefer complementary pairs (one positive IC, one negative)
|
||||
"""
|
||||
...
|
||||
|
||||
def generate_triplets(
|
||||
self,
|
||||
top_n: int = 30,
|
||||
max_pairwise_corr: float = 0.5,
|
||||
) -> List[StrategySpec]:
|
||||
"""
|
||||
Generate triplet combinations.
|
||||
|
||||
Rules:
|
||||
- Top 30 factors by |IC|
|
||||
- All pairwise correlations < max_pairwise_corr
|
||||
- Score by geometric mean of |IC|
|
||||
"""
|
||||
...
|
||||
|
||||
def generate_category_combos(
|
||||
self,
|
||||
category: str,
|
||||
min_factors: int = 2,
|
||||
max_factors: int = 5,
|
||||
) -> List[StrategySpec]:
|
||||
"""
|
||||
Combine all factors within a category.
|
||||
|
||||
Categories (inferred from factor names):
|
||||
- "Momentum": mom_*, trend_*
|
||||
- "Mean Reversion": mean_rev_*, reversal_*
|
||||
- "Volatility": vol_*, std_*
|
||||
- "Session": session_*, intraday_*
|
||||
- "Volume": volume_*, turnover_*
|
||||
"""
|
||||
...
|
||||
|
||||
def generate_temporal_combos(
|
||||
self,
|
||||
session_filters: Dict[str, Callable],
|
||||
) -> List[StrategySpec]:
|
||||
"""
|
||||
Generate session-specific combinations.
|
||||
|
||||
Example strategies:
|
||||
- "London Open": Use momentum factors 07:00-09:00 UTC
|
||||
- "NY Close": Use mean reversion 14:00-16:00 UTC
|
||||
- "Asian Session": Use volatility factors 00:00-06:00 UTC
|
||||
"""
|
||||
...
|
||||
|
||||
def generate_custom_combo(
|
||||
self,
|
||||
factor_names: List[str],
|
||||
weighting: str = "equal",
|
||||
) -> StrategySpec:
|
||||
"""User-defined combination for testing specific hypotheses."""
|
||||
...
|
||||
|
||||
def generate_all(
|
||||
self,
|
||||
strategies: List[CombinationStrategy] = None,
|
||||
) -> List[StrategySpec]:
|
||||
"""
|
||||
Run all enabled combination strategies.
|
||||
|
||||
Default: PAIR + TRIPLET + CATEGORY
|
||||
Returns list of all StrategySpec objects.
|
||||
"""
|
||||
...
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 1.2 StrategyEvaluator
|
||||
|
||||
**Zweck:** Walk-Forward-Backtesting für Strategien mit Transaktionskosten.
|
||||
|
||||
```python
|
||||
@dataclass
|
||||
class WalkForwardConfig:
|
||||
"""Walk-forward validation configuration."""
|
||||
train_window: int = 30 # Days for training
|
||||
test_window: int = 5 # Days for out-of-sample testing
|
||||
step_size: int = 5 # Days to slide forward
|
||||
min_train_periods: int = 3 # Minimum windows before first test
|
||||
|
||||
|
||||
@dataclass
|
||||
class TransactionCostModel:
|
||||
"""Realistic transaction cost modeling."""
|
||||
cost_per_trade_bps: float = 1.5 # 1.5 bps per trade
|
||||
slippage_bps: float = 0.5 # Additional slippage
|
||||
min_trade_size: float = 0.01 # Minimum position size
|
||||
|
||||
|
||||
class StrategyMetrics:
|
||||
"""Complete metrics for a validated strategy."""
|
||||
|
||||
def __init__(self, strategy_name: str) -> None: ...
|
||||
|
||||
def update(
|
||||
self,
|
||||
window_idx: int,
|
||||
in_sample_ic: float,
|
||||
out_of_sample_ic: float,
|
||||
oos_sharpe: float,
|
||||
oos_return: float,
|
||||
oos_drawdown: float,
|
||||
n_trades: int,
|
||||
transaction_costs: float,
|
||||
) -> None: ...
|
||||
|
||||
def finalize(self) -> Dict[str, Any]:
|
||||
"""
|
||||
Calculate aggregate metrics:
|
||||
|
||||
- Mean OOS IC
|
||||
- IC decay (IS IC vs OOS IC)
|
||||
- Mean OOS Sharpe
|
||||
- Worst OOS Drawdown
|
||||
- Calmar Ratio (Ann Return / Max DD)
|
||||
- Total transaction costs
|
||||
- Win rate across windows
|
||||
- Consistency score (% windows with positive IC)
|
||||
"""
|
||||
...
|
||||
|
||||
|
||||
class StrategyEvaluator:
|
||||
"""Walk-forward backtesting for strategy combinations."""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
data_source: str, # Path to intraday_pv.h5
|
||||
wf_config: WalkForwardConfig = None,
|
||||
cost_model: TransactionCostModel = None,
|
||||
) -> None: ...
|
||||
|
||||
def load_factor_values(
|
||||
self,
|
||||
factor_names: List[str],
|
||||
) -> Dict[str, pd.Series]:
|
||||
"""Load time series values for each factor."""
|
||||
...
|
||||
|
||||
def compute_combined_signal(
|
||||
self,
|
||||
factor_values: Dict[str, pd.Series],
|
||||
weights: Dict[str, float],
|
||||
combination_type: str = "weighted_sum",
|
||||
) -> pd.Series:
|
||||
"""
|
||||
Combine factors into single signal.
|
||||
|
||||
Types:
|
||||
- "weighted_sum": sum(w_i * factor_i)
|
||||
- "regime_switch": use different factors per regime
|
||||
- "timing": use volatility to scale momentum
|
||||
"""
|
||||
...
|
||||
|
||||
def walk_forward_backtest(
|
||||
self,
|
||||
strategy_spec: StrategySpec,
|
||||
) -> StrategyMetrics:
|
||||
"""
|
||||
Run walk-forward validation for a single strategy.
|
||||
|
||||
Process:
|
||||
1. Split time series into rolling windows
|
||||
2. For each window:
|
||||
a. Optimize weights on train period
|
||||
b. Test on out-of-sample period
|
||||
c. Apply transaction costs
|
||||
d. Record metrics
|
||||
3. Aggregate across all windows
|
||||
|
||||
Returns StrategyMetrics with full validation results.
|
||||
"""
|
||||
...
|
||||
|
||||
def backtest_single_window(
|
||||
self,
|
||||
train_data: pd.DataFrame,
|
||||
test_data: pd.DataFrame,
|
||||
strategy_spec: StrategySpec,
|
||||
) -> Dict[str, float]:
|
||||
"""
|
||||
Backtest strategy on single train/test split.
|
||||
|
||||
Steps:
|
||||
1. Compute factor values on train period
|
||||
2. Optimize weights (IC-weighted or risk parity)
|
||||
3. Apply to test period
|
||||
4. Calculate returns with transaction costs
|
||||
5. Return metrics
|
||||
"""
|
||||
...
|
||||
|
||||
def apply_transaction_costs(
|
||||
self,
|
||||
raw_returns: pd.Series,
|
||||
signals: pd.Series,
|
||||
cost_model: TransactionCostModel,
|
||||
) -> pd.Series:
|
||||
"""
|
||||
Deduct transaction costs from returns.
|
||||
|
||||
Cost = (signal changes) * (cost_per_trade + slippage)
|
||||
Only charged when position actually changes.
|
||||
"""
|
||||
...
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 1.3 StrategySelector
|
||||
|
||||
**Zweck:** Selektiere beste Strategien nach Out-of-Sample-Performance.
|
||||
|
||||
```python
|
||||
@dataclass
|
||||
class StrategyRanking:
|
||||
"""Ranking criteria for strategies."""
|
||||
primary_metric: str = "oos_sharpe" # oos_sharpe, calmar, oos_ic
|
||||
min_oos_ic: float = 0.02 # Minimum OOS IC
|
||||
max_drawdown: float = -0.15 # Maximum allowed drawdown
|
||||
min_consistency: float = 0.6 # % of windows with positive IC
|
||||
min_windows: int = 3 # Minimum validation windows
|
||||
|
||||
|
||||
class StrategySelector:
|
||||
"""Select and rank best strategies based on walk-forward results."""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
ranking: StrategyRanking = None,
|
||||
) -> None: ...
|
||||
|
||||
def rank_strategies(
|
||||
self,
|
||||
strategy_results: List[Dict[str, Any]],
|
||||
) -> pd.DataFrame:
|
||||
"""
|
||||
Rank strategies by primary metric.
|
||||
|
||||
Filters:
|
||||
- OOS IC >= min_oos_ic
|
||||
- Max DD <= max_drawdown threshold
|
||||
- Consistency >= min_consistency
|
||||
- At least min_windows validated
|
||||
|
||||
Returns sorted DataFrame with:
|
||||
- strategy_name
|
||||
- oos_sharpe (primary)
|
||||
- oos_ic_mean
|
||||
- ic_decay (IS vs OOS gap)
|
||||
- calmar_ratio
|
||||
- max_drawdown
|
||||
- consistency_score
|
||||
- n_windows
|
||||
- total_transaction_costs
|
||||
"""
|
||||
...
|
||||
|
||||
def select_top_k(
|
||||
self,
|
||||
ranked: pd.DataFrame,
|
||||
k: int = 10,
|
||||
) -> List[Dict[str, Any]]:
|
||||
"""Return top K strategies passing all filters."""
|
||||
...
|
||||
|
||||
def identify_overfitting(
|
||||
self,
|
||||
strategy_results: List[Dict[str, Any]],
|
||||
ic_decay_threshold: float = 0.5,
|
||||
) -> List[str]:
|
||||
"""
|
||||
Flag strategies where OOS IC < 50% of IS IC.
|
||||
Indicates overfitting to training period.
|
||||
"""
|
||||
...
|
||||
|
||||
def recommend_ensemble(
|
||||
self,
|
||||
ranked: pd.DataFrame,
|
||||
max_correlation: float = 0.3,
|
||||
max_strategies: int = 3,
|
||||
) -> List[str]:
|
||||
"""
|
||||
Recommend ensemble of uncorrelated strategies.
|
||||
|
||||
Select up to max_strategies with:
|
||||
- Highest combined Sharpe
|
||||
- Pairwise correlation < max_correlation
|
||||
"""
|
||||
...
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 1.4 StrategySaver
|
||||
|
||||
**Zweck:** Persistiert Strategien in `results/strategies/`.
|
||||
|
||||
```python
|
||||
class StrategySaver:
|
||||
"""Save validated strategies to results/strategies/."""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
strategies_dir: Optional[str] = None,
|
||||
) -> None:
|
||||
project_root = Path(__file__).parent.parent.parent.parent
|
||||
self.strategies_dir = Path(strategies_dir) if strategies_dir \
|
||||
else project_root / "results" / "strategies"
|
||||
self.strategies_dir.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
def save_strategy(
|
||||
self,
|
||||
strategy_spec: StrategySpec,
|
||||
metrics: Dict[str, Any],
|
||||
ranking: Dict[str, Any] = None,
|
||||
) -> Path:
|
||||
"""
|
||||
Save complete strategy to JSON.
|
||||
|
||||
JSON structure:
|
||||
{
|
||||
"name": "momentum_mean_rev_pair",
|
||||
"created_at": "2026-04-05T12:00:00",
|
||||
"combination_type": "pair",
|
||||
"factors": ["Momentum_v3", "MeanReversion_v2"],
|
||||
"weights": {"Momentum_v3": 0.63, "MeanReversion_v2": 0.37},
|
||||
"weighting_method": "ic_weighted",
|
||||
|
||||
"walk_forward": {
|
||||
"train_window_days": 30,
|
||||
"test_window_days": 5,
|
||||
"n_windows": 8,
|
||||
"total_test_days": 40
|
||||
},
|
||||
|
||||
"metrics": {
|
||||
"oos_ic_mean": 0.045,
|
||||
"oos_ic_std": 0.012,
|
||||
"is_ic_mean": 0.062,
|
||||
"ic_decay": 0.27,
|
||||
"oos_sharpe": 2.15,
|
||||
"oos_annualized_return": 0.128,
|
||||
"oos_max_drawdown": -0.089,
|
||||
"calmar_ratio": 1.44,
|
||||
"consistency_score": 0.875,
|
||||
"win_rate": 0.58,
|
||||
"total_transaction_costs_bps": 12.4,
|
||||
"net_sharpe": 1.98
|
||||
},
|
||||
|
||||
"per_window_metrics": [
|
||||
{"window": 0, "oos_ic": 0.051, "oos_sharpe": 2.3, ...},
|
||||
{"window": 1, "oos_ic": 0.038, "oos_sharpe": 1.9, ...},
|
||||
...
|
||||
],
|
||||
|
||||
"ranking": {
|
||||
"rank_by_sharpe": 3,
|
||||
"rank_by_ic": 5,
|
||||
"rank_by_calmar": 2,
|
||||
"passes_filters": true
|
||||
}
|
||||
}
|
||||
"""
|
||||
...
|
||||
|
||||
def load_all_strategies(
|
||||
self,
|
||||
min_oos_sharpe: float = None,
|
||||
) -> List[Dict[str, Any]]:
|
||||
"""Load all saved strategies, optionally filtered."""
|
||||
...
|
||||
|
||||
def load_best_strategy(self) -> Optional[Dict[str, Any]]:
|
||||
"""Load the single best strategy by OOS Sharpe."""
|
||||
...
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 2. Kombinations-Logik
|
||||
|
||||
### 2.1 Faktor-Auswahl für Kombinationen
|
||||
|
||||
```python
|
||||
def select_factors_for_combination(
|
||||
factors_df: pd.DataFrame,
|
||||
min_ic: float = 0.02,
|
||||
max_correlation: float = 0.7,
|
||||
) -> Tuple[List[str], pd.DataFrame]:
|
||||
"""
|
||||
Select factors suitable for combination.
|
||||
|
||||
Algorithm:
|
||||
1. Filter: |IC| >= min_ic
|
||||
2. Compute correlation matrix
|
||||
3. Cluster factors by correlation (hierarchical clustering)
|
||||
4. From each cluster, pick factor with highest |IC|
|
||||
5. Return selected factors + correlation matrix
|
||||
|
||||
Rationale:
|
||||
- Avoid combining highly correlated factors (redundant)
|
||||
- Ensure each selected factor has standalone predictive power
|
||||
- Maximize diversity in combinations
|
||||
"""
|
||||
...
|
||||
```
|
||||
|
||||
### 2.2 Pair-Strategie
|
||||
|
||||
```
|
||||
Regel: Kombiniere Faktor A + B wenn:
|
||||
1. |IC_A| >= 0.02 UND |IC_B| >= 0.02
|
||||
2. Korrelation(A, B) < 0.7
|
||||
3. Score = |IC_A * IC_B| * (1 - corr(A, B))
|
||||
|
||||
Priorisiere:
|
||||
- Momentum + Mean Reversion (komplementär)
|
||||
- Volatility + Momentum (Timing)
|
||||
- Session + Hauptfaktor (Filter)
|
||||
```
|
||||
|
||||
### 2.3 Triplet-Strategie
|
||||
|
||||
```
|
||||
Regel: Kombiniere Faktor A + B + C wenn:
|
||||
1. Alle |IC| >= 0.02
|
||||
2. Alle pairwise Korrelationen < 0.5
|
||||
3. Score = (|IC_A| * |IC_B| * |IC_C|)^(1/3) * diversity_factor
|
||||
|
||||
Priorisiere:
|
||||
- Momentum + Mean Reversion + Volatility
|
||||
- Hauptfaktor + Session + Volatility
|
||||
- Drei unkorrelierte Alpha-Faktoren
|
||||
```
|
||||
|
||||
### 2.4 Gewichtungsmethoden
|
||||
|
||||
```python
|
||||
def compute_weights(
|
||||
factor_ics: Dict[str, float],
|
||||
factor_correlations: pd.DataFrame,
|
||||
method: str = "ic_weighted",
|
||||
) -> Dict[str, float]:
|
||||
"""
|
||||
Compute factor weights.
|
||||
|
||||
Methods:
|
||||
|
||||
1. "equal": w_i = 1/N
|
||||
|
||||
2. "ic_weighted": w_i = |IC_i| / sum(|IC|)
|
||||
- Simple, effective when ICs are reliable
|
||||
|
||||
3. "risk_parity":
|
||||
- w_i proportional to 1/vol_i
|
||||
- Equalize risk contribution from each factor
|
||||
- Requires factor return covariance matrix
|
||||
|
||||
4. "sharpe_weighted": w_i = Sharpe_i / sum(Sharpe)
|
||||
- Weight by risk-adjusted performance
|
||||
|
||||
Returns normalized weights summing to 1.0
|
||||
"""
|
||||
...
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3. Walk-Forward-Validierung
|
||||
|
||||
### 3.1 Schema
|
||||
|
||||
```
|
||||
Zeitachse (Beispiel: 90 Tage Daten):
|
||||
|
||||
[---- Train 30d ----][Test 5d][---- Train 30d ----][Test 5d]...
|
||||
Window 0 Window 1
|
||||
|
||||
Gesamt: ~8 Walks bei 90 Tagen
|
||||
```
|
||||
|
||||
### 3.2 Ablauf pro Window
|
||||
|
||||
```python
|
||||
for window_idx in range(n_windows):
|
||||
# 1. Define train/test periods
|
||||
train_start = window_idx * step_size
|
||||
train_end = train_start + train_window
|
||||
test_start = train_end
|
||||
test_end = test_start + test_window
|
||||
|
||||
# 2. Optimize weights on train period
|
||||
weights = optimize_weights(
|
||||
factor_values[train_start:train_end],
|
||||
forward_returns[train_start:train_end],
|
||||
method=strategy_spec.weighting,
|
||||
)
|
||||
|
||||
# 3. Generate signal on test period
|
||||
signal = compute_combined_signal(
|
||||
factor_values[test_start:test_end],
|
||||
weights,
|
||||
)
|
||||
|
||||
# 4. Calculate returns with costs
|
||||
raw_returns = signal.shift(1) * forward_returns[test_start:test_end]
|
||||
net_returns = apply_transaction_costs(raw_returns, signal, cost_model)
|
||||
|
||||
# 5. Record metrics
|
||||
metrics.update(
|
||||
window_idx=window_idx,
|
||||
in_sample_ic=compute_ic(train_period),
|
||||
out_of_sample_ic=compute_ic(test_period),
|
||||
oos_sharpe=calculate_sharpe(net_returns),
|
||||
oos_drawdown=calculate_max_drawdown(net_returns),
|
||||
n_trades=count_signal_changes(signal),
|
||||
transaction_costs=raw_returns.sum() - net_returns.sum(),
|
||||
)
|
||||
```
|
||||
|
||||
### 3.3 Aggregierte Metriken
|
||||
|
||||
```python
|
||||
final_metrics = {
|
||||
# Primary
|
||||
"oos_ic_mean": mean(window_oos_ics),
|
||||
"oos_ic_std": std(window_oos_ics),
|
||||
"oos_sharpe": mean(window_sharpes),
|
||||
|
||||
# Overfitting detection
|
||||
"is_ic_mean": mean(window_is_ics),
|
||||
"ic_decay": 1 - (oos_ic_mean / is_ic_mean), # < 0.5 good
|
||||
|
||||
# Risk
|
||||
"oos_max_drawdown": min(window_drawdowns),
|
||||
"calmar_ratio": annualized_return / abs(max_drawdown),
|
||||
|
||||
# Consistency
|
||||
"consistency_score": sum(ic > 0 for ic in window_oos_ics) / n_windows,
|
||||
|
||||
# Costs
|
||||
"total_transaction_costs_bps": sum(window_costs),
|
||||
"net_sharpe": sharpe_after_costs,
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. Integrationspunkte mit factor_runner.py
|
||||
|
||||
### 4.1 Wo passt der StrategyBuilder hin?
|
||||
|
||||
```
|
||||
Bestehender Flow (factor_runner.py):
|
||||
┌─────────────────────────────────────────┐
|
||||
│ 1. Hypothesis Gen → Factor Hypothesis │
|
||||
│ 2. Factor Coder → Generate factor code │
|
||||
│ 3. Factor Runner → Docker backtest │
|
||||
│ 4. Protection Check → Risk validation │
|
||||
│ 5. Save to DB → ResultsDatabase │
|
||||
│ 6. Feedback → Guide next hypothesis │
|
||||
└─────────────────────────────────────────┘
|
||||
|
||||
NEUER Flow (StrategyBuilder):
|
||||
┌─────────────────────────────────────────┐
|
||||
│ 7. StrategyCombinator → Combos │ ← AFTER factor generation
|
||||
│ 8. StrategyEvaluator → Walk-forward │ ← SEPARATE phase
|
||||
│ 9. StrategySelector → Rank strategies │
|
||||
│ 10. StrategySaver → results/strategies/ │
|
||||
└─────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### 4.2 Konkrete Integration
|
||||
|
||||
```python
|
||||
# Option A: Eigenständiger CLI-Befehl (empfohlen)
|
||||
# rdagent/build_strategies --top-n 100 --walk-forward
|
||||
|
||||
# Option B: Integration in QuantRDLoop
|
||||
class QuantRDLoop:
|
||||
def running(self, prev_out):
|
||||
# ... existing factor runner code ...
|
||||
exp = self.factor_runner.develop(prev_out["coding"])
|
||||
|
||||
# NEW: Periodically run strategy builder
|
||||
if self.should_build_strategies():
|
||||
self._run_strategy_builder()
|
||||
|
||||
return exp
|
||||
|
||||
def should_build_strategies(self) -> bool:
|
||||
"""Check if enough factors exist to build strategies."""
|
||||
n_factors = self.trace.get_valid_factor_count()
|
||||
return n_factors >= 100 and self.loop_idx % 50 == 0
|
||||
|
||||
def _run_strategy_builder(self) -> None:
|
||||
"""Trigger strategy building process."""
|
||||
from rdagent.scenarios.qlib.developer.strategy_builder import (
|
||||
StrategyBuilder,
|
||||
)
|
||||
|
||||
builder = StrategyBuilder(
|
||||
db=self.results_db,
|
||||
data_source=self.data_path,
|
||||
)
|
||||
builder.run(top_n=100)
|
||||
```
|
||||
|
||||
### 4.3 Datenabhängigkeiten
|
||||
|
||||
```python
|
||||
# Benötigt von factor_runner.py:
|
||||
# ✅ ResultsDatabase → already exists, factor_runner schreibt dort
|
||||
# ✅ Factor JSON files → already in results/factors/
|
||||
# ✅ Factor values → Müssen aus workspace/result.h5 geladen werden
|
||||
|
||||
# Neue Abhängigkeit:
|
||||
# ⚠️ Factor time series values → Müssen für Walk-Forward verfügbar sein
|
||||
# Lösung: Factor values beim Speichern in DB auch als Parquet schreiben
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5. Integration in QuantRDLoop Workflow
|
||||
|
||||
### 5.1 Erweiterte Loop-Phasen
|
||||
|
||||
```
|
||||
Phase 1: Factor Generation (EXISTIEREND)
|
||||
└─ Generate → Code → Backtest → Save to DB
|
||||
└─ Continue until N factors reached (z.B. 500)
|
||||
|
||||
Phase 2: Strategy Building (NEU)
|
||||
└─ Load top factors from DB
|
||||
└─ Generate combinations (pairs, triplets, categories)
|
||||
└─ Walk-forward validation
|
||||
└─ Save strategies to results/strategies/
|
||||
|
||||
Phase 3: Strategy Selection (NEU)
|
||||
└─ Rank by OOS Sharpe
|
||||
└─ Filter by max drawdown, consistency
|
||||
└─ Select top 3 strategies for live trading
|
||||
|
||||
Phase 4: ML Training (EXISTIEREND, optional)
|
||||
└─ Train ML model on top strategies' factors
|
||||
|
||||
Phase 5: Live Trading (ZUKUNFT)
|
||||
└─ Paper trade selected strategies
|
||||
└─ Monitor and adapt
|
||||
```
|
||||
|
||||
### 5.2 Haupt-CLI-Befehl
|
||||
|
||||
```python
|
||||
# rdagent/scenarios/qlib/developer/strategy_builder.py
|
||||
|
||||
class StrategyBuilder:
|
||||
"""Main orchestrator for strategy building process."""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
db: ResultsDatabase,
|
||||
data_source: str,
|
||||
output_dir: Optional[str] = None,
|
||||
) -> None:
|
||||
self.db = db
|
||||
self.data_source = data_source
|
||||
self.combinator = StrategyCombinator(db)
|
||||
self.evaluator = StrategyEvaluator(data_source)
|
||||
self.selector = StrategySelector()
|
||||
self.saver = StrategySaver(output_dir)
|
||||
|
||||
def run(
|
||||
self,
|
||||
top_n: int = 100,
|
||||
min_ic: float = 0.02,
|
||||
strategies: List[CombinationStrategy] = None,
|
||||
save: bool = True,
|
||||
) -> pd.DataFrame:
|
||||
"""
|
||||
Complete strategy building pipeline.
|
||||
|
||||
Steps:
|
||||
1. Load top N factors from DB
|
||||
2. Generate combinations
|
||||
3. Walk-forward validate each
|
||||
4. Rank and filter
|
||||
5. Save top strategies
|
||||
6. Return ranked results
|
||||
"""
|
||||
logger.info(f"=== Strategy Builder: Top {top_n} factors ===")
|
||||
|
||||
# Step 1: Load factors
|
||||
factors = self.combinator.load_valid_factors(min_ic=min_ic)
|
||||
logger.info(f"Loaded {len(factors)} valid factors")
|
||||
|
||||
# Step 2: Generate combinations
|
||||
combos = self.combinator.generate_all(strategies)
|
||||
logger.info(f"Generated {len(combos)} strategy combinations")
|
||||
|
||||
# Step 3: Walk-forward validate
|
||||
results = []
|
||||
for spec in combos:
|
||||
logger.info(f"Evaluating: {spec.name}")
|
||||
metrics = self.evaluator.walk_forward_backtest(spec)
|
||||
results.append(metrics.finalize())
|
||||
|
||||
# Step 4: Rank
|
||||
ranked = self.selector.rank_strategies(results)
|
||||
|
||||
# Step 5: Save
|
||||
if save:
|
||||
for _, row in ranked.iterrows():
|
||||
spec = next(s for s in combos if s.name == row["strategy_name"])
|
||||
self.saver.save_strategy(spec, row)
|
||||
|
||||
logger.info(f"=== Top 5 Strategies ===")
|
||||
logger.info(ranked.head(5).to_string())
|
||||
|
||||
return ranked
|
||||
|
||||
|
||||
def build_strategies(
|
||||
top_n: int = 100,
|
||||
min_ic: float = 0.02,
|
||||
data_source: str = None,
|
||||
) -> None:
|
||||
"""CLI entry point: rdagent build_strategies"""
|
||||
from rdagent.components.backtesting.results_db import ResultsDatabase
|
||||
|
||||
db = ResultsDatabase()
|
||||
|
||||
if data_source is None:
|
||||
data_source = str(Path(__file__).parent.parent.parent.parent.parent
|
||||
/ "git_ignore_folder"
|
||||
/ "factor_implementation_source_data"
|
||||
/ "intraday_pv.h5")
|
||||
|
||||
builder = StrategyBuilder(db=db, data_source=data_source)
|
||||
ranked = builder.run(top_n=top_n, min_ic=min_ic)
|
||||
|
||||
logger.info(f"\nStrategy building complete. Results in results/strategies/")
|
||||
```
|
||||
|
||||
### 5.3 Config-Erweiterung
|
||||
|
||||
```python
|
||||
# rdagent/app/qlib_rd_loop/conf.py
|
||||
|
||||
@dataclass
|
||||
class StrategyBuilderSetting:
|
||||
"""Configuration for strategy building."""
|
||||
top_n_factors: int = 100
|
||||
min_ic_threshold: float = 0.02
|
||||
max_correlation: float = 0.7
|
||||
train_window_days: int = 30
|
||||
test_window_days: int = 5
|
||||
step_size_days: int = 5
|
||||
transaction_cost_bps: float = 1.5
|
||||
min_oos_sharpe: float = 1.0
|
||||
max_drawdown_threshold: float = -0.15
|
||||
combination_strategies: List[str] = None # ["pair", "triplet", "category"]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 6. Datei-Struktur
|
||||
|
||||
```
|
||||
rdagent/scenarios/qlib/developer/
|
||||
└── strategy_builder.py # Hauptmodul (alle Klassen)
|
||||
|
||||
# ODER aufgeteilt:
|
||||
rdagent/scenarios/qlib/developer/
|
||||
└── strategy_builder/
|
||||
├── __init__.py
|
||||
├── combinator.py # StrategyCombinator
|
||||
├── evaluator.py # StrategyEvaluator
|
||||
├── selector.py # StrategySelector
|
||||
├── saver.py # StrategySaver
|
||||
└── builder.py # StrategyBuilder (Orchestrator)
|
||||
|
||||
results/
|
||||
└── strategies/
|
||||
├── momentum_mean_rev_pair.json
|
||||
├── momentum_vol_timing.json
|
||||
├── session_alpha_combo.json
|
||||
└── strategy_ranking.json # Summary aller Strategien
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 7. Nächste Schritte
|
||||
|
||||
1. **Implementierung Phase 1:** StrategyCombinator + einfache Pair-Tests
|
||||
2. **Implementierung Phase 2:** StrategyEvaluator mit Walk-Forward
|
||||
3. **Implementierung Phase 3:** StrategySelector + Saver
|
||||
4. **Integration:** CLI-Befehl `rdagent build_strategies`
|
||||
5. **Validierung:** Top-Strategien gegen Hold-out Periode testen
|
||||
6. **Dashboard:** Web-UI zur Strategie-Anzeige (erweitert)
|
||||
|
||||
---
|
||||
|
||||
## 8. Offene Fragen
|
||||
|
||||
- **Factor Values:** Woher kommen die Zeitreihen-Werte für jeden Faktor?
|
||||
- Aktuell: Nur in workspace/result.h5 gespeichert (nicht persistent)
|
||||
- Lösung: Beim Speichern in DB auch als Parquet in results/factors/values/ ablegen
|
||||
|
||||
- **Performance:** 100 Faktoren → ~5000 Pairs → 8 Walks each = 40.000 Backtests
|
||||
- Lösung: Parallelisierung (multiprocessing), Top-1000 Paare vorher filtern
|
||||
|
||||
- **Regime Detection:** Wie erkennen wir Markt-Regimes?
|
||||
- Vorschlag: Volatility-based (high/low vol), Trend-based (uptrend/downtrend)
|
||||
- Später: ML-basiert (HMM, Clustering)
|
||||
Vendored
+332
@@ -0,0 +1,332 @@
|
||||
{
|
||||
"alpha053_15": {
|
||||
"description": "Reversal class factor, negative delta of a ratio involving close, low, and high prices over 15 days.",
|
||||
"formulation": "-1 times Deltaleft(frac{(text{close} - text{low}) - (text{high} - text{close})}{text{close} - text{low}}, 15right)",
|
||||
"variables": {
|
||||
"Delta(x, d)": "Change in 'x' over 'd' days.",
|
||||
"text{close}": "Closing price of the stock.",
|
||||
"text{low}": "Lowest price of the stock for the day.",
|
||||
"text{high}": "Highest price of the stock for the day."
|
||||
},
|
||||
"Category": "Volume&Price",
|
||||
"Difficulty": "Easy",
|
||||
"gt_code": "import pandas as pd\ndata_pv = pd.read_hdf('daily_pv.h5')\nnew_df= data_pv.reset_index()\n# Calculate Alpha053\nnew_df['ratio'] = (new_df['$close'] - new_df['$low'] - (new_df['$high'] - new_df['$close'])) / (new_df['$close'] - new_df['$low'])\n# the change of ratio in new_df over the 15 days\nnew_df['result']=-new_df['ratio'].diff(15)\n# transfer the result to series\nresult=pd.DataFrame(new_df['result']).set_index(data_pv.index)\nresult=result['result']\nresult.to_hdf('result.h5', key='data')"
|
||||
},
|
||||
"liquidity_imbalance": {
|
||||
"description": "liquidity_imbalance=std(minute trading liquidity_imbalance)/mean(minute trading liquidity_imbalance).",
|
||||
"formulation": "liquidity_imbalance = frac{text{std}(text{minute trading liquidity_imbalance})}{text{mean}(text{minute liquidity_imbalance})}",
|
||||
"variables": {
|
||||
"std(minute liquidity_imbalance)": "Standard deviation of trading liquidity_imbalance for each minute of the trading day.",
|
||||
"mean(minute liquidity_imbalance)": "Mean of trading liquidity_imbalance for each minute of the trading day.",
|
||||
"liquidity_imbalance": "(bid_size-ask_size)/(bid_size+ask_size), we use something like bidV for the size"
|
||||
},
|
||||
"Category": "High-Frequency",
|
||||
"Difficulty": "Medium",
|
||||
"gt_code": "import pandas as pd\ndata_hf = pd.read_hdf('high_freq.h5')\nsample_df= data_hf.reset_index()\n# Convert 'datetime' column to datetime and extract date for grouping\nsample_df['date'] = sample_df['datetime'].dt.date\nsample_df['liquidity_imbalance']=(sample_df['bidV']-sample_df['askV'])/(sample_df['bidV']+sample_df['askV'])\n# Group by instrument and date\ngrouped = sample_df.groupby(['date','instrument'])['liquidity_imbalance']\n# Calculate mean and standard deviation of the volume for each group\nstats = grouped.agg(['mean', 'std'])\n# Calculate Z value for each instrument per day\nstats['liquidity_imbalance'] = stats['std'] / stats['mean']\n# Display the calculated Z values\nresult=stats['liquidity_imbalance']\nresult.index.names = ['datetime','instrument']\n# result = result.swaplevel().sort_index()\nresult.to_hdf('result.h5', key='data')"
|
||||
},
|
||||
"liquidity_imbalance_2": {
|
||||
"description": "liquidity_imbalance=std(minute trading liquidity_imbalance)/mean(minute trading liquidity_imbalance).",
|
||||
"formulation": "liquidity_imbalance = frac{text{std}(text{minute trading liquidity_imbalance})}{text{mean}(text{minute liquidity_imbalance})}",
|
||||
"variables": {
|
||||
"std(minute liquidity_imbalance)": "Standard deviation of trading liquidity_imbalance for each minute of the trading day.",
|
||||
"mean(minute liquidity_imbalance)": "Mean of trading liquidity_imbalance for each minute of the trading day.",
|
||||
"liquidity_imbalance": "(bid_size-ask_size)/2*(bid_size+ask_size), we use something like bidV for the size"
|
||||
},
|
||||
"Category": "High-Frequency",
|
||||
"Difficulty": "Medium",
|
||||
"gt_code": "import pandas as pd\ndata_hf = pd.read_hdf('high_freq.h5')\nsample_df= data_hf.reset_index()\n# Convert 'datetime' column to datetime and extract date for grouping\nsample_df['date'] = sample_df['datetime'].dt.date\nsample_df['liquidity_imbalance']=(sample_df['bidV']-sample_df['askV'])/((sample_df['bidV']+sample_df['askV'])*2)\n# Group by instrument and date\ngrouped = sample_df.groupby(['date','instrument'])['liquidity_imbalance']\n# Calculate mean and standard deviation of the volume for each group\nstats = grouped.agg(['mean', 'std'])\n# Calculate Z value for each instrument per day\nstats['liquidity_imbalance'] = stats['std'] / stats['mean']\n# Display the calculated Z values\nresult=stats['liquidity_imbalance']\nresult.index.names = ['datetime','instrument']\n# result = result.swaplevel().sort_index()\nresult.to_hdf('result.h5', key='data')"
|
||||
},
|
||||
"liquidity_imbalance_3": {
|
||||
"description": "liquidity_imbalance=std(minute trading liquidity_imbalance)/mean(minute trading liquidity_imbalance).",
|
||||
"formulation": "liquidity_imbalance = frac{text{std}(text{minute trading liquidity_imbalance})}{text{mean}(text{minute liquidity_imbalance})}",
|
||||
"variables": {
|
||||
"std(minute liquidity_imbalance)": "Standard deviation of trading liquidity_imbalance for each minute of the trading day.",
|
||||
"mean(minute liquidity_imbalance)": "Mean of trading liquidity_imbalance for each minute of the trading day.",
|
||||
"liquidity_imbalance": "(bid_size-ask_size)/3*(bid_size+ask_size), we use something like bidV for the size"
|
||||
},
|
||||
"Category": "High-Frequency",
|
||||
"Difficulty": "Medium",
|
||||
"gt_code": "import pandas as pd\ndata_hf = pd.read_hdf('high_freq.h5')\nsample_df= data_hf.reset_index()\n# Convert 'datetime' column to datetime and extract date for grouping\nsample_df['date'] = sample_df['datetime'].dt.date\nsample_df['liquidity_imbalance']=(sample_df['bidV']-sample_df['askV'])/((sample_df['bidV']+sample_df['askV'])*3)\n# Group by instrument and date\ngrouped = sample_df.groupby(['date','instrument'])['liquidity_imbalance']\n# Calculate mean and standard deviation of the volume for each group\nstats = grouped.agg(['mean', 'std'])\n# Calculate Z value for each instrument per day\nstats['liquidity_imbalance'] = stats['std'] / stats['mean']\n# Display the calculated Z values\nresult=stats['liquidity_imbalance']\nresult.index.names = ['datetime','instrument']\n# result = result.swaplevel().sort_index()\nresult.to_hdf('result.h5', key='data')"
|
||||
},
|
||||
"micro_price": {
|
||||
"description": "micro_price=std(minute trading micro_price)/mean(minute trading micro_price).",
|
||||
"formulation": "micro_price = frac{text{std}(text{minute trading micro_price})}{text{mean}(text{minute micro_price})}",
|
||||
"variables": {
|
||||
"std(minute micro_price)": "Standard deviation of trading micro_price for each minute of the trading day.",
|
||||
"mean(minute micro_price)": "Mean of trading micro_price for each minute of the trading day.",
|
||||
"micro_price": "((df['bid_price'] * df['ask_size']) + (df['ask_price'] * df['bid_size'])) / (df['bid_size'] + df['ask_size'])"
|
||||
},
|
||||
"Category": "High-Frequency",
|
||||
"Difficulty": "Hard",
|
||||
"gt_code": "import pandas as pd\ndata_hf = pd.read_hdf('high_freq.h5')\nsample_df= data_hf.reset_index()\n# Convert 'datetime' column to datetime and extract date for grouping\nsample_df['date'] = sample_df['datetime'].dt.date\nsample_df['micro_price']=(sample_df['bid']*sample_df['askV']+sample_df['ask']*sample_df['bidV'])/(sample_df['bidV']+sample_df['askV'])\n# Group by instrument and date\ngrouped = sample_df.groupby(['date','instrument'])['micro_price']\n# Calculate mean and standard deviation of the volume for each group\nstats = grouped.agg(['mean', 'std'])\n# Calculate Z value for each instrument per day\nstats['micro_price'] = stats['std'] / stats['mean']\n# Display the calculated Z values\nresult=stats['micro_price']\nresult.index.names = ['datetime','instrument']\n# result = result.swaplevel().sort_index()\nresult.to_hdf('result.h5', key='data')"
|
||||
},
|
||||
"micro_price_2": {
|
||||
"description": "micro_price_2=std(minute trading micro_price)/mean(minute trading micro_price).",
|
||||
"formulation": "micro_price_2 = frac{text{std}(text{minute trading micro_price})}{text{mean}(text{minute micro_price})}",
|
||||
"variables": {
|
||||
"std(minute micro_price)": "Standard deviation of trading micro_price for each minute of the trading day.",
|
||||
"mean(minute micro_price)": "Mean of trading micro_price for each minute of the trading day.",
|
||||
"micro_price": "((df['bid_price'] * df['ask_size']) + (df['ask_price'] * df['bid_size'])) / 2*(df['bid_size'] + df['ask_size']), we use something like bidV for the size"
|
||||
},
|
||||
"Category": "High-Frequency",
|
||||
"Difficulty": "Hard",
|
||||
"gt_code": "import pandas as pd\ndata_hf = pd.read_hdf('high_freq.h5')\nsample_df= data_hf.reset_index()\n# Convert 'datetime' column to datetime and extract date for grouping\nsample_df['date'] = sample_df['datetime'].dt.date\nsample_df['micro_price']=(sample_df['bid']*sample_df['askV']+sample_df['ask']*sample_df['bidV'])/((sample_df['bidV']+sample_df['askV'])*2)\n# Group by instrument and date\ngrouped = sample_df.groupby(['date','instrument'])['micro_price']\n# Calculate mean and standard deviation of the volume for each group\nstats = grouped.agg(['mean', 'std'])\n# Calculate Z value for each instrument per day\nstats['micro_price'] = stats['std'] / stats['mean']\n# Display the calculated Z values\nresult=stats['micro_price']\nresult.index.names = ['datetime','instrument']\n# result = result.swaplevel().sort_index()\nresult.to_hdf('result.h5', key='data')"
|
||||
},
|
||||
"micro_price_3": {
|
||||
"description": "micro_price_3=std(minute trading micro_price)/mean(minute trading micro_price).",
|
||||
"formulation": "micro_price_3 = frac{text{std}(text{minute trading micro_price})}{text{mean}(text{minute micro_price})}",
|
||||
"variables": {
|
||||
"std(minute micro_price)": "Standard deviation of trading micro_price for each minute of the trading day.",
|
||||
"mean(minute micro_price)": "Mean of trading micro_price for each minute of the trading day.",
|
||||
"micro_price": "((df['bid_price'] * df['ask_size']) + (df['ask_price'] * df['bid_size'])) / 3*(df['bid_size'] + df['ask_size']), we use something like bidV for the size"
|
||||
},
|
||||
"Category": "High-Frequency",
|
||||
"Difficulty": "Hard",
|
||||
"gt_code": "import pandas as pd\ndata_hf = pd.read_hdf('high_freq.h5')\nsample_df= data_hf.reset_index()\n# Convert 'datetime' column to datetime and extract date for grouping\nsample_df['date'] = sample_df['datetime'].dt.date\nsample_df['micro_price']=(sample_df['bid']*sample_df['askV']+sample_df['ask']*sample_df['bidV'])/((sample_df['bidV']+sample_df['askV'])*3)\n# Group by instrument and date\ngrouped = sample_df.groupby(['date','instrument'])['micro_price']\n# Calculate mean and standard deviation of the volume for each group\nstats = grouped.agg(['mean', 'std'])\n# Calculate Z value for each instrument per day\nstats['micro_price'] = stats['std'] / stats['mean']\n# Display the calculated Z values\nresult=stats['micro_price']\nresult.index.names = ['datetime','instrument']\n# result = result.swaplevel().sort_index()\nresult.to_hdf('result.h5', key='data')"
|
||||
},
|
||||
"mid_price": {
|
||||
"description": "mid_price=std(minute trading mid_price)/mean(minute trading mid_price).",
|
||||
"formulation": "mid_price = frac{text{std}(text{minute trading mid price})}{text{mean}(text{minute mid price})}",
|
||||
"variables": {
|
||||
"std(minute mid_price)": "Standard deviation of trading mid_price for each minute of the trading day.",
|
||||
"mean(minute mid_price)": "Mean of trading mid_price for each minute of the trading day.",
|
||||
"mid_price": "The average of the bid and ask prices."
|
||||
},
|
||||
"Category": "High-Frequency",
|
||||
"Difficulty": "Easy",
|
||||
"gt_code": "import pandas as pd\ndata_hf = pd.read_hdf('high_freq.h5')\nsample_df= data_hf.reset_index()\n# Convert 'datetime' column to datetime and extract date for grouping\nsample_df['date'] = sample_df['datetime'].dt.date\nsample_df['mid_price']=(sample_df['bid']+sample_df['ask'])/2\n# Group by instrument and date\ngrouped = sample_df.groupby(['date','instrument'])['mid_price']\n# Calculate mean and standard deviation of the volume for each group\nstats = grouped.agg(['mean', 'std'])\nstats['mid_price'] = stats['std'] / stats['mean']\nresult=stats['mid_price']\nresult.index.names = ['datetime','instrument']\n# result = result.swaplevel().sort_index()\nresult.to_hdf('result.h5', key='data')"
|
||||
},
|
||||
"mid_price_2": {
|
||||
"description": "mid_price=std(minute trading mid_price)/mean(minute trading mid_price).",
|
||||
"formulation": "mid_price = frac{text{std}(text{minute trading mid price})}{text{mean}(text{minute mid price})}",
|
||||
"variables": {
|
||||
"std(minute mid_price)": "Standard deviation of trading mid_price for each minute of the trading day.",
|
||||
"mean(minute mid_price)": "Mean of trading mid_price for each minute of the trading day.",
|
||||
"mid_price_2": "the average of the bid and ask prices plus the the average of the bid and ask size (bidV and askV)."
|
||||
},
|
||||
"Category": "High-Frequency",
|
||||
"Difficulty": "Easy",
|
||||
"gt_code": "import pandas as pd\ndata_hf = pd.read_hdf('high_freq.h5')\nsample_df= data_hf.reset_index()\n# Convert 'datetime' column to datetime and extract date for grouping\nsample_df['date'] = sample_df['datetime'].dt.date\nsample_df['mid_price']=(sample_df['bid']+sample_df['ask'])/2+(sample_df['bidV']+sample_df['askV'])/2\n# Group by instrument and date\ngrouped = sample_df.groupby(['date','instrument'])['mid_price']\n# Calculate mean and standard deviation of the volume for each group\nstats = grouped.agg(['mean', 'std'])\nstats['mid_price'] = stats['std'] / stats['mean']\nresult=stats['mid_price']\nresult.index.names = ['datetime','instrument']\n# result = result.swaplevel().sort_index()\nresult.to_hdf('result.h5', key='data')"
|
||||
},
|
||||
"mid_price_3": {
|
||||
"description": "mid_price=std(minute trading mid_price)/mean(minute trading mid_price).",
|
||||
"formulation": "mid_price = frac{text{std}(text{minute trading mid price})}{text{mean}(text{minute mid price})}",
|
||||
"variables": {
|
||||
"std(minute mid_price)": "Standard deviation of trading mid_price for each minute of the trading day.",
|
||||
"mean(minute mid_price)": "Mean of trading mid_price for each minute of the trading day.",
|
||||
"mid_price_3": "The coefficient of variation (CV) of the mid-price for each minute of the trading day, calculated as the standard deviation of the mid-price divided by the mean mid-price."
|
||||
},
|
||||
"Category": "High-Frequency",
|
||||
"Difficulty": "Easy",
|
||||
"gt_code": "import pandas as pd\ndata_hf = pd.read_hdf('high_freq.h5')\nsample_df= data_hf.reset_index()\n# Convert 'datetime' column to datetime and extract date for grouping\nsample_df['date'] = sample_df['datetime'].dt.date\nsample_df['mid_price']=(sample_df['bid']+sample_df['ask'])/3\n# Group by instrument and date\ngrouped = sample_df.groupby(['date','instrument'])['mid_price']\n# Calculate mean and standard deviation of the volume for each group\nstats = grouped.agg(['mean', 'std'])\nstats['mid_price'] = stats['std'] / stats['mean']\nresult=stats['mid_price']\nresult.index.names = ['datetime','instrument']\n# result = result.swaplevel().sort_index()\nresult.to_hdf('result.h5', key='data')"
|
||||
},
|
||||
"PB_ROE": {
|
||||
"description": "Constructed using the ranking difference between PB and ROE, with regression versions of PB and ROE replacing original PB and ROE to obtain reconstructed factor values.",
|
||||
"formulation": "text{rank}(PB_t) - rank(ROE_t)",
|
||||
"variables": {
|
||||
"text{rank}(PB_t)": "Ranking of regression version PB on cross-section at time t.",
|
||||
"text{rank}(ROE_t)": "Ranking of regression version single-quarter ROE on cross-section at time t."
|
||||
},
|
||||
"Category": "Fundamentals",
|
||||
"Difficulty": "Easy",
|
||||
"gt_code": "import pandas as pd\ndata_f = pd.read_hdf('daily_f.h5')\ndata = data_f.reset_index()\n# Calculate the rank of PB and ROE\ndata['PB_rank'] = data.groupby('datetime')['B/P'].rank()\ndata['ROE_rank'] = data.groupby('datetime')['ROE'].rank()\n# Calculate the difference between the ranks\ndata['PB_ROE'] = data['PB_rank'] - data['ROE_rank']\n# set the datetime and instrument as index and drop the original index\nresult=pd.DataFrame(data['PB_ROE']).set_index(data_f.index)\n# transfer the result to series\nresult=result['PB_ROE']\nresult.to_hdf('result.h5', key='data')"
|
||||
},
|
||||
"PB_ROE_2": {
|
||||
"description": "Constructed using the ranking difference between PB/2 and ROE, with regression versions of PB and ROE replacing original PB and ROE to obtain reconstructed factor values.",
|
||||
"formulation": "text{rank}(PB_t)/2 - rank(ROE_t)",
|
||||
"variables": {
|
||||
"text{rank}(PB_t)": "Ranking of regression version PB on cross-section at time t.",
|
||||
"text{rank}(ROE_t)": "Ranking of regression version single-quarter ROE on cross-section at time t."
|
||||
},
|
||||
"Category": "Fundamentals",
|
||||
"Difficulty": "Easy",
|
||||
"gt_code": "import pandas as pd\ndata_f = pd.read_hdf('daily_f.h5')\ndata = data_f.reset_index()\n# Calculate the rank of PB and ROE\ndata['PB_rank'] = data.groupby('datetime')['B/P'].rank()\ndata['ROE_rank'] = data.groupby('datetime')['ROE'].rank()\n# Calculate the difference between the ranks\ndata['PB_ROE'] = data['PB_rank']/2 - data['ROE_rank']\n# set the datetime and instrument as index and drop the original index\nresult=pd.DataFrame(data['PB_ROE']).set_index(data_f.index)\n# transfer the result to series\nresult=result['PB_ROE']\nresult.to_hdf('result.h5', key='data')"
|
||||
},
|
||||
"PB_ROE_3": {
|
||||
"description": "Constructed using the ranking difference between PB/3 and ROE, with regression versions of PB and ROE replacing original PB and ROE to obtain reconstructed factor values.",
|
||||
"formulation": "text{rank}(PB_t)/3 - rank(ROE_t)",
|
||||
"variables": {
|
||||
"text{rank}(PB_t)": "Ranking of regression version PB on cross-section at time t.",
|
||||
"text{rank}(ROE_t)": "Ranking of regression version single-quarter ROE on cross-section at time t."
|
||||
},
|
||||
"Category": "Fundamentals",
|
||||
"Difficulty": "Easy",
|
||||
"gt_code": "import pandas as pd\ndata_f = pd.read_hdf('daily_f.h5')\ndata = data_f.reset_index()\n# Calculate the rank of PB and ROE\ndata['PB_rank'] = data.groupby('datetime')['B/P'].rank()\ndata['ROE_rank'] = data.groupby('datetime')['ROE'].rank()\n# Calculate the difference between the ranks\ndata['PB_ROE'] = data['PB_rank']/3 - data['ROE_rank']\n# set the datetime and instrument as index and drop the original index\nresult=pd.DataFrame(data['PB_ROE']).set_index(data_f.index)\n# transfer the result to series\nresult=result['PB_ROE']\nresult.to_hdf('result.h5', key='data')"
|
||||
},
|
||||
"PB_ROE_movement": {
|
||||
"description": "PB_ROE_movement=five day PB_ROE movement indicator(-1 and 1 or 0).",
|
||||
"formulation": "PB_ROE_movement = 5_day_movement(PB_ROE), PB_ROE = text{rank}(PB_t) - rank(ROE_t)",
|
||||
"variables": {
|
||||
"PB_ROE": "the ranking difference between PB and ROE.",
|
||||
"5_day_PB_ROE_movement": "1 if PB_ROE is higher than the PB_ROE 5 days ago, -1 if PB_ROE is lower than the PB_ROE 5 days ago, 0 if PB_ROE is the same as the PB_ROE 5 days ago.",
|
||||
"text{rank}(PB_t)": "Ranking of regression version PB on cross-section at time t.",
|
||||
"text{rank}(ROE_t)": "Ranking of regression version single-quarter ROE on cross-section at time t."
|
||||
},
|
||||
"Category": "Fundamentals",
|
||||
"Difficulty": "Hard",
|
||||
"gt_code": "import pandas as pd\ndata_f = pd.read_hdf('daily_f.h5')\nsample_df = data_f.reset_index()\n# Calculate the rank of PB and ROE\nsample_df['PB_rank'] = sample_df.groupby('datetime')['B/P'].rank()\nsample_df['ROE_rank'] = sample_df.groupby('datetime')['ROE'].rank()\nsample_df['PB_ROE'] = sample_df['PB_rank'] - sample_df['ROE_rank']\n# Group by instrument and date\nsample_df['PB_ROE_movement'] = sample_df['PB_ROE'].diff(periods=5).apply(lambda x: 1 if x > 0 else (-1 if x < 0 else 0))\n#calculate the mid_price_movement ratio for each day\n# set the datetime and instrument as index and drop the original index\nresult=pd.DataFrame(sample_df['PB_ROE_movement']).set_index(data_f.index)\n# transfer the result to series\nresult=result['PB_ROE_movement']\nresult.to_hdf('result.h5', key='data')"
|
||||
},
|
||||
"PB_ROE_movement_10": {
|
||||
"description": "PB_ROE_movement=10 days PB_ROE movement indicator(-1 and 1 or 0).",
|
||||
"formulation": "PB_ROE_movement = 10_day_movement(PB_ROE), PB_ROE = text{rank}(PB_t) - rank(ROE_t)",
|
||||
"variables": {
|
||||
"PB_ROE": "the ranking difference between PB and ROE.",
|
||||
"10_day_PB_ROE_movement": "1 if PB_ROE is higher than the PB_ROE 10 days ago, -1 if PB_ROE is lower than the PB_ROE 10 days ago, 0 if PB_ROE is the same as the PB_ROE 10 days ago.",
|
||||
"text{rank}(PB_t)": "Ranking of regression version PB on cross-section at time t.",
|
||||
"text{rank}(ROE_t)": "Ranking of regression version single-quarter ROE on cross-section at time t."
|
||||
},
|
||||
"Category": "Fundamentals",
|
||||
"Difficulty": "Hard",
|
||||
"gt_code": "import pandas as pd\ndata_f = pd.read_hdf('daily_f.h5')\nsample_df = data_f.reset_index()\n# Calculate the rank of PB and ROE\nsample_df['PB_rank'] = sample_df.groupby('datetime')['B/P'].rank()\nsample_df['ROE_rank'] = sample_df.groupby('datetime')['ROE'].rank()\nsample_df['PB_ROE'] = sample_df['PB_rank'] - sample_df['ROE_rank']\n# Group by instrument and date\nsample_df['PB_ROE_movement'] = sample_df['PB_ROE'].diff(periods=10).apply(lambda x: 1 if x > 0 else (-1 if x < 0 else 0))\n#calculate the mid_price_movement ratio for each day\n# set the datetime and instrument as index and drop the original index\nresult=pd.DataFrame(sample_df['PB_ROE_movement']).set_index(data_f.index)\n# transfer the result to series\nresult=result['PB_ROE_movement']\nresult.to_hdf('result.h5', key='data')"
|
||||
},
|
||||
"PB_ROE_movement_20": {
|
||||
"description": "PB_ROE_movement=20 days PB_ROE movement indicator(-1 and 1 or 0).",
|
||||
"formulation": "PB_ROE_movement = 20_day_movement(PB_ROE), PB_ROE = text{rank}(PB_t) - rank(ROE_t)",
|
||||
"variables": {
|
||||
"PB_ROE": "the ranking difference between PB and ROE.",
|
||||
"20_day_PB_ROE_movement": "1 if PB_ROE is higher than the PB_ROE 20 days ago, -1 if PB_ROE is lower than the PB_ROE 20 days ago, 0 if PB_ROE is the same as the PB_ROE 20 days ago.",
|
||||
"text{rank}(PB_t)": "Ranking of regression version PB on cross-section at time t.",
|
||||
"text{rank}(ROE_t)": "Ranking of regression version single-quarter ROE on cross-section at time t."
|
||||
},
|
||||
"Category": "Fundamentals",
|
||||
"Difficulty": "Hard",
|
||||
"gt_code": "import pandas as pd\ndata_f = pd.read_hdf('daily_f.h5')\nsample_df = data_f.reset_index()\n# Calculate the rank of PB and ROE\nsample_df['PB_rank'] = sample_df.groupby('datetime')['B/P'].rank()\nsample_df['ROE_rank'] = sample_df.groupby('datetime')['ROE'].rank()\nsample_df['PB_ROE'] = sample_df['PB_rank'] - sample_df['ROE_rank']\n# Group by instrument and date\nsample_df['PB_ROE_movement'] = sample_df['PB_ROE'].diff(periods=20).apply(lambda x: 1 if x > 0 else (-1 if x < 0 else 0))\n#calculate the mid_price_movement ratio for each day\n# set the datetime and instrument as index and drop the original index\nresult=pd.DataFrame(sample_df['PB_ROE_movement']).set_index(data_f.index)\n# transfer the result to series\nresult=result['PB_ROE_movement']\nresult.to_hdf('result.h5', key='data')"
|
||||
},
|
||||
"ROE_movement": {
|
||||
"description": "ROE_movement=five day ROE movement indicator(-1 and 1 or 0).",
|
||||
"formulation": "ROE_movement = 5_day_movement(ROE)",
|
||||
"variables": {
|
||||
"ROE": "ROE in fundamental statistics.",
|
||||
"5_day_ROE_movement": "1 if ROE is higher than the ROE 5 days ago, -1 if ROE is lower than the ROE 5 days ago, 0 if ROE is the same as the ROE 5 days ago."
|
||||
},
|
||||
"Category": "Fundamentals",
|
||||
"Difficulty": "Medium",
|
||||
"gt_code": "import pandas as pd\ndata_f = pd.read_hdf('daily_f.h5')\nsample_df = data_f.reset_index()\n# Group by instrument and date\nsample_df['ROE_movement'] = sample_df['ROE'].diff(periods=5).apply(lambda x: 1 if x > 0 else (-1 if x < 0 else 0))\n#calculate the mid_price_movement ratio for each day\n# set the datetime and instrument as index and drop the original index\nresult=pd.DataFrame(sample_df['ROE_movement']).set_index(data_f.index)\n# transfer the result to series\nresult=result['ROE_movement']\nresult.to_hdf('result.h5', key='data')"
|
||||
},
|
||||
"ROE_movement_10": {
|
||||
"description": "ROE_movement_10=ten day ROE movement indicator(-1 and 1 or 0).",
|
||||
"formulation": "ROE_movement = 10_day_movement(ROE)",
|
||||
"variables": {
|
||||
"ROE": "ROE in fundamental statistics.",
|
||||
"10_day_ROE_movement": "1 if ROE is higher than the ROE 10 days ago, -1 if ROE is lower than the ROE 10 days ago, 0 if ROE is the same as the ROE 10 days ago."
|
||||
},
|
||||
"Category": "Fundamentals",
|
||||
"Difficulty": "Medium",
|
||||
"gt_code": "import pandas as pd\ndata_f = pd.read_hdf('daily_f.h5')\nsample_df = data_f.reset_index()\n# Group by instrument and date\nsample_df['ROE_movement'] = sample_df['ROE'].diff(periods=10).apply(lambda x: 1 if x > 0 else (-1 if x < 0 else 0))\n#calculate the mid_price_movement ratio for each day\n# set the datetime and instrument as index and drop the original index\nresult=pd.DataFrame(sample_df['ROE_movement']).set_index(data_f.index)\n# transfer the result to series\nresult=result['ROE_movement']\nresult.to_hdf('result.h5', key='data')"
|
||||
},
|
||||
"ROE_movement_20": {
|
||||
"description": "ROE_movement_20=20 day ROE movement indicator(-1 and 1 or 0).",
|
||||
"formulation": "ROE_movement_20 = 20_day_movement(ROE)",
|
||||
"variables": {
|
||||
"ROE": "ROE in fundamental statistics.",
|
||||
"20_day_ROE_movement": "1 if ROE is higher than the ROE 20 days ago, -1 if ROE is lower than the ROE 20 days ago, 0 if ROE is the same as the ROE 20 days ago."
|
||||
},
|
||||
"Category": "Fundamentals",
|
||||
"Difficulty": "Medium",
|
||||
"gt_code": "import pandas as pd\ndata_f = pd.read_hdf('daily_f.h5')\nsample_df = data_f.reset_index()\n# Group by instrument and date\nsample_df['ROE_movement'] = sample_df['ROE'].diff(periods=20).apply(lambda x: 1 if x > 0 else (-1 if x < 0 else 0))\n#calculate the mid_price_movement ratio for each day\n# set the datetime and instrument as index and drop the original index\nresult=pd.DataFrame(sample_df['ROE_movement']).set_index(data_f.index)\n# transfer the result to series\nresult=result['ROE_movement']\nresult.to_hdf('result.h5', key='data')"
|
||||
},
|
||||
"alpha_pv_diff": {
|
||||
"description": "alpha_pv_diff is defined as the ratio of the difference between close prices 10 days change and open prices 10 days change to the sum of the highest minus lowest prices plus a small constant.",
|
||||
"formulation": "frac{(text{close_diff10} - text{open_diff10})}{(text{high} - text{low} + 0.001)}",
|
||||
"variables": {
|
||||
"close": "Closing price of the stock",
|
||||
"open": "Opening price of the stock",
|
||||
"high": "Highest price of the stock during the day",
|
||||
"low": "Lowest price of the stock during the day"
|
||||
},
|
||||
"Category": "Volume&Price",
|
||||
"Difficulty": "Medium",
|
||||
"gt_code": "import pandas as pd\ndata_pv = pd.read_hdf('daily_pv.h5')\nnew_df= data_pv.reset_index()\n# Calculate Alpha101\nnew_df['result'] = (new_df['$close'].diff(10) - new_df['$open'].diff(10)) / (new_df['$high'] - new_df['$low'] + 0.001)\n# keep the index of the original dataframe\nresult=pd.DataFrame(new_df['result']).set_index(data_pv.index)\n# transfer the result to series\nresult=result['result']\nresult.to_hdf('result.h5', key='data')"
|
||||
},
|
||||
"alpha_pv_diff_15": {
|
||||
"description": "alpha_pv_diff is defined as the ratio of the difference between close prices 15 days change and open prices 15 days change to the sum of the highest minus lowest prices plus a small constant.",
|
||||
"formulation": "frac{(text{close_diff15} - text{open_diff15})}{(text{high} - text{low} + 0.001)}",
|
||||
"variables": {
|
||||
"close": "Closing price of the stock",
|
||||
"open": "Opening price of the stock",
|
||||
"high": "Highest price of the stock during the day",
|
||||
"low": "Lowest price of the stock during the day"
|
||||
},
|
||||
"Category": "Volume&Price",
|
||||
"Difficulty": "Medium",
|
||||
"gt_code": "import pandas as pd\ndata_pv = pd.read_hdf('daily_pv.h5')\nnew_df= data_pv.reset_index()\n# Calculate Alpha101\nnew_df['result'] = (new_df['$close'].diff(15) - new_df['$open'].diff(15)) / (new_df['$high'] - new_df['$low'] + 0.001)\n# keep the index of the original dataframe\nresult=pd.DataFrame(new_df['result']).set_index(data_pv.index)\n# transfer the result to series\nresult=result['result']\nresult.to_hdf('result.h5', key='data')"
|
||||
},
|
||||
"alpha_pv_diff_20": {
|
||||
"description": "alpha_pv_diff is defined as the ratio of the difference between close prices 20 days change and open prices 20 days change to the sum of the highest minus lowest prices plus a small constant.",
|
||||
"formulation": "frac{(text{close_diff20} - text{open_diff20})}{(text{high} - text{low} + 0.001)}",
|
||||
"variables": {
|
||||
"close": "Closing price of the stock",
|
||||
"open": "Opening price of the stock",
|
||||
"high": "Highest price of the stock during the day",
|
||||
"low": "Lowest price of the stock during the day"
|
||||
},
|
||||
"Category": "Volume&Price",
|
||||
"Difficulty": "Medium",
|
||||
"gt_code": "import pandas as pd\ndata_pv = pd.read_hdf('daily_pv.h5')\nnew_df= data_pv.reset_index()\n# Calculate Alpha101\nnew_df['result'] = (new_df['$close'].diff(20) - new_df['$open'].diff(20)) / (new_df['$high'] - new_df['$low'] + 0.001)\n# keep the index of the original dataframe\nresult=pd.DataFrame(new_df['result']).set_index(data_pv.index)\n# transfer the result to series\nresult=result['result']\nresult.to_hdf('result.h5', key='data')"
|
||||
},
|
||||
"alpha_pv_diff_pct": {
|
||||
"description": "alpha_pv is defined as the ratio of the difference between close prices 10 days change and open prices 10 days change to the sum of the highest prices 10 days change ratio minus lowest prices 10 days change ratio plus a small constant.",
|
||||
"formulation": "frac{(text{close_diff10} - text{open_diff10})}{(text{high_pct10} - text{low_pct10} + 0.001)}",
|
||||
"variables": {
|
||||
"close": "Closing price of the stock",
|
||||
"open": "Opening price of the stock",
|
||||
"high": "Highest price of the stock during the day",
|
||||
"low": "Lowest price of the stock during the day"
|
||||
},
|
||||
"Category": "Volume&Price",
|
||||
"Difficulty": "Hard",
|
||||
"gt_code": "import pandas as pd\ndata_pv = pd.read_hdf('daily_pv.h5')\nnew_df= data_pv.reset_index()\n# Calculate Alpha101\nnew_df['result'] = (new_df['$close'].diff(10) - new_df['$open'].diff(10)) / (new_df['$high'].pct_change(10) - new_df['$low'].pct_change(10) + 0.001)\n# keep the index of the original dataframe\nresult=pd.DataFrame(new_df['result']).set_index(data_pv.index)\n# transfer the result to series\nresult=result['result']\nresult.to_hdf('result.h5', key='data')"
|
||||
},
|
||||
"alpha_pv_diff_pct_15": {
|
||||
"description": "alpha_pv is defined as the ratio of the difference between close prices 15 days change and open prices 15 days change to the sum of the highest prices 10 days change ratio minus lowest prices 10 days change ratio plus a small constant.",
|
||||
"formulation": "frac{(text{close_diff15} - text{open_diff15})}{(text{high_pct10} - text{low_pct10} + 0.001)}",
|
||||
"variables": {
|
||||
"close": "Closing price of the stock",
|
||||
"open": "Opening price of the stock",
|
||||
"high": "Highest price of the stock during the day",
|
||||
"low": "Lowest price of the stock during the day"
|
||||
},
|
||||
"Category": "Volume&Price",
|
||||
"Difficulty": "Hard",
|
||||
"gt_code": "import pandas as pd\ndata_pv = pd.read_hdf('daily_pv.h5')\nnew_df= data_pv.reset_index()\n# Calculate Alpha101\nnew_df['result'] = (new_df['$close'].diff(15) - new_df['$open'].diff(15)) / (new_df['$high'].pct_change(10) - new_df['$low'].pct_change(10) + 0.001)\n# keep the index of the original dataframe\nresult=pd.DataFrame(new_df['result']).set_index(data_pv.index)\n# transfer the result to series\nresult=result['result']\nresult.to_hdf('result.h5', key='data')"
|
||||
},
|
||||
"alpha_pv_diff_pct_20": {
|
||||
"description": "alpha_pv is defined as the ratio of the difference between close prices 20 days change and open prices 20 days change to the sum of the highest prices 10 days change ratio minus lowest prices 10 days change ratio plus a small constant.",
|
||||
"formulation": "frac{(text{close_diff20} - text{open_diff20})}{(text{high_pct10} - text{low_pct10} + 0.001)}",
|
||||
"variables": {
|
||||
"close": "Closing price of the stock",
|
||||
"open": "Opening price of the stock",
|
||||
"high": "Highest price of the stock during the day",
|
||||
"low": "Lowest price of the stock during the day"
|
||||
},
|
||||
"Category": "Volume&Price",
|
||||
"Difficulty": "Hard",
|
||||
"gt_code": "import pandas as pd\ndata_pv = pd.read_hdf('daily_pv.h5')\nnew_df= data_pv.reset_index()\n# Calculate Alpha101\nnew_df['result'] = (new_df['$close'].diff(20) - new_df['$open'].diff(20)) / (new_df['$high'].pct_change(10) - new_df['$low'].pct_change(10) + 0.001)\n# keep the index of the original dataframe\nresult=pd.DataFrame(new_df['result']).set_index(data_pv.index)\n# transfer the result to series\nresult=result['result']\nresult.to_hdf('result.h5', key='data')"
|
||||
},
|
||||
"alpha053": {
|
||||
"description": "Reversal class factor, negative delta of a ratio involving close, low, and high prices over 9 days.",
|
||||
"formulation": "-1 times Deltaleft(frac{(text{close} - text{low}) - (text{high} - text{close})}{text{close} - text{low}}, 9right)",
|
||||
"variables": {
|
||||
"Delta(x, d)": "Change in 'x' over 'd' days.",
|
||||
"text{close}": "Closing price of the stock.",
|
||||
"text{low}": "Lowest price of the stock for the day.",
|
||||
"text{high}": "Highest price of the stock for the day."
|
||||
},
|
||||
"Category": "Volume&Price",
|
||||
"Difficulty": "Easy",
|
||||
"gt_code": "import pandas as pd\ndata_pv = pd.read_hdf('daily_pv.h5')\nnew_df= data_pv.reset_index()\n# Calculate Alpha053\nnew_df['ratio'] = (new_df['$close'] - new_df['$low'] - (new_df['$high'] - new_df['$close'])) / (new_df['$close'] - new_df['$low'])\n# the change of ratio in new_df over the 9 days\nnew_df['result']=-new_df['ratio'].diff(9)\n# transfer the result to series\nresult=pd.DataFrame(new_df['result']).set_index(data_pv.index)\nresult=result['result']\nresult.to_hdf('result.h5', key='data')"
|
||||
},
|
||||
"alpha053_5": {
|
||||
"description": "Reversal class factor, negative delta of a ratio involving close, low, and high prices over 5 days.",
|
||||
"formulation": "-1 times Deltaleft(frac{(text{close} - text{low}) - (text{high} - text{close})}{text{close} - text{low}}, 5right)",
|
||||
"variables": {
|
||||
"Delta(x, d)": "Change in 'x' over 'd' days.",
|
||||
"text{close}": "Closing price of the stock.",
|
||||
"text{low}": "Lowest price of the stock for the day.",
|
||||
"text{high}": "Highest price of the stock for the day."
|
||||
},
|
||||
"Category": "Volume&Price",
|
||||
"Difficulty": "Easy",
|
||||
"gt_code": "import pandas as pd\ndata_pv = pd.read_hdf('daily_pv.h5')\nnew_df= data_pv.reset_index()\n# Calculate Alpha053\nnew_df['ratio'] = (new_df['$close'] - new_df['$low'] - (new_df['$high'] - new_df['$close'])) / (new_df['$close'] - new_df['$low'])\n# the change of ratio in new_df over the 5 days\nnew_df['result']=-new_df['ratio'].diff(5)\n# transfer the result to series\nresult=pd.DataFrame(new_df['result']).set_index(data_pv.index)\nresult=result['result']\nresult.to_hdf('result.h5', key='data')"
|
||||
}
|
||||
}
|
||||
@@ -1,158 +0,0 @@
|
||||
<svg width="100%" viewBox="0 0 680 920" xmlns="http://www.w3.org/2000/svg" role="img">
|
||||
<title>NexQuant data flow architecture</title>
|
||||
<desc>Full pipeline from Qlib data source through R&D loop, factor and model tracks, strategy generation, portfolio optimization, to live trading.</desc>
|
||||
|
||||
<defs>
|
||||
<marker id="arrow" viewBox="0 0 10 10" refX="8" refY="5" markerWidth="6" markerHeight="6" orient="auto-start-reverse">
|
||||
<path d="M2 1L8 5L2 9" fill="none" stroke="context-stroke" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</marker>
|
||||
<style>
|
||||
text { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; }
|
||||
.th { font-size: 14px; font-weight: 600; fill: #1a1a1a; }
|
||||
.ts { font-size: 12px; font-weight: 400; fill: #555; }
|
||||
.arr { stroke: #888; stroke-width: 1.2; fill: none; }
|
||||
.box-blue { fill: #E6F1FB; stroke: #185FA5; }
|
||||
.box-purple { fill: #EEEDFE; stroke: #534AB7; }
|
||||
.th-purple { fill: #3C3489; }
|
||||
.ts-purple { fill: #534AB7; }
|
||||
.box-teal { fill: #E1F5EE; stroke: #0F6E56; }
|
||||
.th-teal { fill: #085041; }
|
||||
.ts-teal { fill: #0F6E56; }
|
||||
.box-coral { fill: #FAECE7; stroke: #993C1D; }
|
||||
.th-coral { fill: #712B13; }
|
||||
.ts-coral { fill: #993C1D; }
|
||||
.box-amber { fill: #FAEEDA; stroke: #854F0B; }
|
||||
.th-amber { fill: #633806; }
|
||||
.ts-amber { fill: #854F0B; }
|
||||
.box-green { fill: #EAF3DE; stroke: #3B6D11; }
|
||||
.th-green { fill: #27500A; }
|
||||
.ts-green { fill: #3B6D11; }
|
||||
.box-gray { fill: #F1EFE8; stroke: #5F5E5A; }
|
||||
.th-gray { fill: #2C2C2A; }
|
||||
.ts-gray { fill: #5F5E5A; }
|
||||
.th-blue { fill: #0C447C; }
|
||||
.ts-blue { fill: #185FA5; }
|
||||
.container { fill: none; stroke: #B4B2A9; stroke-width: 0.5; }
|
||||
.label-muted { font-size: 12px; fill: #888780; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; }
|
||||
</style>
|
||||
</defs>
|
||||
|
||||
<!-- DATA SOURCE -->
|
||||
<rect x="200" y="20" width="280" height="56" rx="8" stroke-width="0.5" class="box-blue"/>
|
||||
<text class="th th-blue" x="340" y="43" text-anchor="middle" dominant-baseline="central">Qlib data (1-min EUR/USD)</text>
|
||||
<text class="ts ts-blue" x="340" y="63" text-anchor="middle" dominant-baseline="central">2020–2026 · 96 bars/day</text>
|
||||
|
||||
<line x1="340" y1="76" x2="340" y2="104" class="arr" marker-end="url(#arrow)"/>
|
||||
|
||||
<!-- R&D LOOP container -->
|
||||
<rect x="40" y="104" width="600" height="190" rx="10" class="container"/>
|
||||
<text class="label-muted" x="56" y="121" dominant-baseline="central">R&D loop (rdagent fin_quant)</text>
|
||||
|
||||
<rect x="56" y="132" width="100" height="56" rx="6" stroke-width="0.5" class="box-purple"/>
|
||||
<text class="th th-purple" x="106" y="154" text-anchor="middle" dominant-baseline="central">Propose</text>
|
||||
<text class="ts ts-purple" x="106" y="172" text-anchor="middle" dominant-baseline="central">LLM</text>
|
||||
<line x1="156" y1="160" x2="170" y2="160" class="arr" marker-end="url(#arrow)"/>
|
||||
|
||||
<rect x="170" y="132" width="100" height="56" rx="6" stroke-width="0.5" class="box-purple"/>
|
||||
<text class="th th-purple" x="220" y="154" text-anchor="middle" dominant-baseline="central">Coding</text>
|
||||
<text class="ts ts-purple" x="220" y="172" text-anchor="middle" dominant-baseline="central">CoSTEER</text>
|
||||
<line x1="270" y1="160" x2="284" y2="160" class="arr" marker-end="url(#arrow)"/>
|
||||
|
||||
<rect x="284" y="132" width="100" height="56" rx="6" stroke-width="0.5" class="box-purple"/>
|
||||
<text class="th th-purple" x="334" y="154" text-anchor="middle" dominant-baseline="central">Running</text>
|
||||
<text class="ts ts-purple" x="334" y="172" text-anchor="middle" dominant-baseline="central">Docker</text>
|
||||
<line x1="384" y1="160" x2="398" y2="160" class="arr" marker-end="url(#arrow)"/>
|
||||
|
||||
<rect x="398" y="132" width="100" height="56" rx="6" stroke-width="0.5" class="box-purple"/>
|
||||
<text class="th th-purple" x="448" y="154" text-anchor="middle" dominant-baseline="central">Feedback</text>
|
||||
<text class="ts ts-purple" x="448" y="172" text-anchor="middle" dominant-baseline="central">LLM</text>
|
||||
<line x1="498" y1="160" x2="512" y2="160" class="arr" marker-end="url(#arrow)"/>
|
||||
|
||||
<rect x="512" y="132" width="100" height="56" rx="6" stroke-width="0.5" class="box-purple"/>
|
||||
<text class="th th-purple" x="562" y="154" text-anchor="middle" dominant-baseline="central">Record</text>
|
||||
<text class="ts ts-purple" x="562" y="172" text-anchor="middle" dominant-baseline="central">Pickle</text>
|
||||
|
||||
<text class="label-muted" x="340" y="216" text-anchor="middle" dominant-baseline="central">Bandit selection → factor track or model track</text>
|
||||
|
||||
<!-- Split to two tracks -->
|
||||
<path d="M210 294 L210 308 L470 308 L470 294" fill="none" stroke="#B4B2A9" stroke-width="0.5"/>
|
||||
<line x1="210" y1="308" x2="210" y2="322" class="arr" marker-end="url(#arrow)"/>
|
||||
<line x1="470" y1="308" x2="470" y2="322" class="arr" marker-end="url(#arrow)"/>
|
||||
<text class="label-muted" x="340" y="478" text-anchor="middle">every N factors · auto or CLI</text>
|
||||
|
||||
<!-- FACTOR TRACK -->
|
||||
<rect x="40" y="322" width="260" height="130" rx="8" stroke-width="0.5" class="box-teal"/>
|
||||
<text class="th th-teal" x="170" y="344" text-anchor="middle" dominant-baseline="central">Factor track</text>
|
||||
<text class="ts ts-teal" x="170" y="364" text-anchor="middle" dominant-baseline="central">Hypothesis → FactorCoSTEER</text>
|
||||
<text class="ts ts-teal" x="170" y="382" text-anchor="middle" dominant-baseline="central">FactorRunner → FactorFeedback</text>
|
||||
<text class="ts ts-teal" x="170" y="402" text-anchor="middle" dominant-baseline="central">Output: result.h5</text>
|
||||
<text class="ts ts-teal" x="170" y="420" text-anchor="middle" dominant-baseline="central">MultiIndex DataFrame</text>
|
||||
<text class="ts ts-teal" x="170" y="438" text-anchor="middle" dominant-baseline="central">IC / Sharpe metrics</text>
|
||||
|
||||
<!-- MODEL TRACK -->
|
||||
<rect x="380" y="322" width="260" height="130" rx="8" stroke-width="0.5" class="box-coral"/>
|
||||
<text class="th th-coral" x="510" y="344" text-anchor="middle" dominant-baseline="central">Model track</text>
|
||||
<text class="ts ts-coral" x="510" y="364" text-anchor="middle" dominant-baseline="central">Hypothesis → ModelCoSTEER</text>
|
||||
<text class="ts ts-coral" x="510" y="382" text-anchor="middle" dominant-baseline="central">ModelRunner → ModelFeedback</text>
|
||||
<text class="ts ts-coral" x="510" y="402" text-anchor="middle" dominant-baseline="central">Output: PyTorch preds</text>
|
||||
<text class="ts ts-coral" x="510" y="420" text-anchor="middle" dominant-baseline="central">+ mlflow logs</text>
|
||||
<text class="ts ts-coral" x="510" y="438" text-anchor="middle" dominant-baseline="central">LSTM / Transformer / CNN</text>
|
||||
|
||||
<!-- Merge to strategy -->
|
||||
<path d="M170 452 L170 486 L340 486 L340 502" fill="none" stroke="#B4B2A9" stroke-width="0.5" marker-end="url(#arrow)"/>
|
||||
<path d="M510 452 L510 486 L340 486" fill="none" stroke="#B4B2A9" stroke-width="0.5"/>
|
||||
|
||||
<!-- STRATEGY GENERATION -->
|
||||
<rect x="100" y="502" width="480" height="120" rx="8" stroke-width="0.5" class="box-amber"/>
|
||||
<text class="th th-amber" x="340" y="524" text-anchor="middle" dominant-baseline="central">Strategy generation pipeline</text>
|
||||
|
||||
<rect x="116" y="536" width="120" height="44" rx="6" stroke-width="0.5" class="box-gray"/>
|
||||
<text class="ts th-gray" x="176" y="554" text-anchor="middle" dominant-baseline="central">Load top factors</text>
|
||||
<text class="ts ts-gray" x="176" y="570" text-anchor="middle" dominant-baseline="central">by |IC|</text>
|
||||
<line x1="236" y1="558" x2="252" y2="558" class="arr" marker-end="url(#arrow)"/>
|
||||
|
||||
<rect x="252" y="536" width="120" height="44" rx="6" stroke-width="0.5" class="box-gray"/>
|
||||
<text class="ts th-gray" x="312" y="554" text-anchor="middle" dominant-baseline="central">LLM strategy</text>
|
||||
<text class="ts ts-gray" x="312" y="570" text-anchor="middle" dominant-baseline="central">code gen</text>
|
||||
<line x1="372" y1="558" x2="388" y2="558" class="arr" marker-end="url(#arrow)"/>
|
||||
|
||||
<rect x="388" y="536" width="120" height="44" rx="6" stroke-width="0.5" class="box-gray"/>
|
||||
<text class="ts th-gray" x="448" y="554" text-anchor="middle" dominant-baseline="central">OHLCV backtest</text>
|
||||
<text class="ts ts-gray" x="448" y="570" text-anchor="middle" dominant-baseline="central">signals eval</text>
|
||||
|
||||
<text class="label-muted" x="340" y="600" text-anchor="middle" dominant-baseline="central">Optuna: 10 → 15 → 5 trials · Sharpe ≥ 1.5 · DD ≥ −0.30 · WR ≥ 0.40</text>
|
||||
|
||||
<line x1="340" y1="622" x2="340" y2="648" class="arr" marker-end="url(#arrow)"/>
|
||||
|
||||
<!-- PORTFOLIO -->
|
||||
<rect x="160" y="648" width="360" height="56" rx="8" stroke-width="0.5" class="box-green"/>
|
||||
<text class="th th-green" x="340" y="670" text-anchor="middle" dominant-baseline="central">Portfolio optimization</text>
|
||||
<text class="ts ts-green" x="340" y="688" text-anchor="middle" dominant-baseline="central">Mean-variance · Risk parity · Black-Litterman</text>
|
||||
|
||||
<line x1="340" y1="704" x2="340" y2="730" class="arr" marker-end="url(#arrow)"/>
|
||||
|
||||
<!-- LIVE TRADING -->
|
||||
<rect x="160" y="730" width="360" height="56" rx="8" stroke-width="0.5" class="box-gray"/>
|
||||
<text class="th th-gray" x="340" y="752" text-anchor="middle" dominant-baseline="central">Live trading (closed-source)</text>
|
||||
<text class="ts ts-gray" x="340" y="770" text-anchor="middle" dominant-baseline="central">ftmo_live_trader.py · FTMO signals</text>
|
||||
|
||||
<!-- EXTERNAL SERVICES -->
|
||||
<text class="label-muted" x="340" y="812" text-anchor="middle">External services</text>
|
||||
|
||||
<rect x="40" y="824" width="130" height="44" rx="6" stroke-width="0.5" class="box-gray"/>
|
||||
<text class="ts th-gray" x="105" y="842" text-anchor="middle" dominant-baseline="central">llama.cpp</text>
|
||||
<text class="ts ts-gray" x="105" y="858" text-anchor="middle" dominant-baseline="central">LLM inference</text>
|
||||
|
||||
<rect x="185" y="824" width="130" height="44" rx="6" stroke-width="0.5" class="box-gray"/>
|
||||
<text class="ts th-gray" x="250" y="842" text-anchor="middle" dominant-baseline="central">Docker</text>
|
||||
<text class="ts ts-gray" x="250" y="858" text-anchor="middle" dominant-baseline="central">sandbox</text>
|
||||
|
||||
<rect x="330" y="824" width="130" height="44" rx="6" stroke-width="0.5" class="box-gray"/>
|
||||
<text class="ts th-gray" x="395" y="842" text-anchor="middle" dominant-baseline="central">Optuna</text>
|
||||
<text class="ts ts-gray" x="395" y="858" text-anchor="middle" dominant-baseline="central">Bayesian opt</text>
|
||||
|
||||
<rect x="475" y="824" width="130" height="44" rx="6" stroke-width="0.5" class="box-gray"/>
|
||||
<text class="ts th-gray" x="540" y="842" text-anchor="middle" dominant-baseline="central">Qlib</text>
|
||||
<text class="ts ts-gray" x="540" y="858" text-anchor="middle" dominant-baseline="central">backtest engine</text>
|
||||
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 10 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 131 KiB |
+4
-4
@@ -10,9 +10,9 @@ import subprocess
|
||||
|
||||
latest_tag = subprocess.check_output(["git", "describe", "--tags", "--abbrev=0"], text=True).strip()
|
||||
|
||||
project = "NexQuant"
|
||||
copyright = "2025, NexQuant Team"
|
||||
author = "NexQuant Team"
|
||||
project = "RDAgent"
|
||||
copyright = "2024, Microsoft"
|
||||
author = "Microsoft"
|
||||
|
||||
# -- General configuration ---------------------------------------------------
|
||||
# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration
|
||||
@@ -66,7 +66,7 @@ html_static_path = ["_static"]
|
||||
html_favicon = "_static/favicon.ico"
|
||||
|
||||
html_theme_options = {
|
||||
"source_repository": "https://github.com/NexQuantAI/nexquant",
|
||||
"source_repository": "https://github.com/microsoft/RD-Agent",
|
||||
"source_branch": "main",
|
||||
"source_directory": "docs/",
|
||||
}
|
||||
|
||||
+4
-4
@@ -1,13 +1,13 @@
|
||||
.. NexQuant documentation master file, created by
|
||||
.. RDAgent documentation master file, created by
|
||||
sphinx-quickstart on Mon Jul 15 04:27:50 2024.
|
||||
You can adapt this file completely to your liking, but it should at least
|
||||
contain the root `toctree` directive.
|
||||
|
||||
Welcome to NexQuant's documentation!
|
||||
Welcome to RDAgent's documentation!
|
||||
===================================
|
||||
|
||||
.. image:: _static/logo.png
|
||||
:alt: NexQuant Logo
|
||||
:alt: RD-Agent Logo
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 3
|
||||
@@ -23,7 +23,7 @@ Welcome to NexQuant's documentation!
|
||||
api_reference
|
||||
policy
|
||||
|
||||
GitHub <https://github.com/NexQuantAI/nexquant>
|
||||
GitHub <https://github.com/microsoft/RD-Agent>
|
||||
|
||||
|
||||
Indices and tables
|
||||
|
||||
@@ -16,9 +16,6 @@ Ensure the current user can run Docker commands **without using sudo**. You can
|
||||
LiteLLM Backend Configuration (Default)
|
||||
=======================================
|
||||
|
||||
.. note::
|
||||
🔥 **Attention**: We now provide experimental support for **DeepSeek** models! You can use DeepSeek's official API for cost-effective and high-performance inference. See the configuration example below for DeepSeek setup.
|
||||
|
||||
Option 1: Unified API base for both models
|
||||
------------------------------------------
|
||||
|
||||
@@ -51,23 +48,6 @@ Option 2: Separate API bases for Chat and Embedding models
|
||||
LITELLM_PROXY_API_KEY=<replace_with_your_siliconflow_api_key>
|
||||
LITELLM_PROXY_API_BASE=https://api.siliconflow.cn/v1
|
||||
|
||||
Configuration Example: DeepSeek Setup
|
||||
-------------------------------------
|
||||
|
||||
Many users encounter configuration errors when setting up DeepSeek. Here's a complete working example:
|
||||
|
||||
.. code-block:: Properties
|
||||
|
||||
# CHAT MODEL: Using DeepSeek Official API
|
||||
CHAT_MODEL=deepseek/deepseek-chat
|
||||
DEEPSEEK_API_KEY=<replace_with_your_deepseek_api_key>
|
||||
|
||||
# EMBEDDING MODEL: Using SiliconFlow for embedding since DeepSeek has no embedding model.
|
||||
# Note: embedding requires litellm_proxy prefix
|
||||
EMBEDDING_MODEL=litellm_proxy/BAAI/bge-m3
|
||||
LITELLM_PROXY_API_KEY=<replace_with_your_siliconflow_api_key>
|
||||
LITELLM_PROXY_API_BASE=https://api.siliconflow.cn/v1
|
||||
|
||||
Necessary parameters include:
|
||||
|
||||
- `CHAT_MODEL`: The model name of the chat model.
|
||||
@@ -107,184 +87,6 @@ Besides, when you are using reasoning models, the response might include the tho
|
||||
|
||||
For more details on LiteLLM requirements, refer to the `official LiteLLM documentation <https://docs.litellm.ai/docs>`_.
|
||||
|
||||
Configuration Example 2: Azure OpenAI Setup
|
||||
-------------------------------------------
|
||||
Here’s a sample configuration specifically for Azure OpenAI, based on the `official LiteLLM documentation <https://docs.litellm.ai/docs>`_:
|
||||
|
||||
If you're using Azure OpenAI, below is a working example using the Python SDK, following the `LiteLLM Azure OpenAI documentation <https://docs.litellm.ai/docs/providers/azure/>`_:
|
||||
|
||||
.. code-block:: Properties
|
||||
|
||||
from litellm import completion
|
||||
import os
|
||||
|
||||
# Set Azure OpenAI environment variables
|
||||
os.environ["AZURE_API_KEY"] = "<your_azure_api_key>"
|
||||
os.environ["AZURE_API_BASE"] = "<your_azure_api_base>"
|
||||
os.environ["AZURE_API_VERSION"] = "<version>"
|
||||
|
||||
# Make a request to your Azure deployment
|
||||
response = completion(
|
||||
"azure/<your_deployment_name>",
|
||||
messages = [{ "content": "Hello, how are you?", "role": "user" }]
|
||||
)
|
||||
|
||||
To align with the Python SDK example above, you can configure the `CHAT_MODEL` based on the `response` model setting and use the corresponding `os.environ` variables by writing them into your local `.env` file as follows:
|
||||
|
||||
.. code-block:: Properties
|
||||
|
||||
cat << EOF > .env
|
||||
# CHAT MODEL: Azure OpenAI via LiteLLM
|
||||
CHAT_MODEL=azure/<your_deployment_name>
|
||||
AZURE_API_BASE=https://<your_azure_base>.openai.azure.com/
|
||||
AZURE_API_KEY=<your_azure_api_key>
|
||||
AZURE_API_VERSION=<version>
|
||||
|
||||
# EMBEDDING MODEL: Using SiliconFlow via litellm_proxy
|
||||
EMBEDDING_MODEL=litellm_proxy/BAAI/bge-large-en-v1.5
|
||||
LITELLM_PROXY_API_KEY=<your_siliconflow_api_key>
|
||||
LITELLM_PROXY_API_BASE=https://api.siliconflow.cn/v1
|
||||
EOF
|
||||
|
||||
This configuration allows you to call Azure OpenAI through LiteLLM while using an external provider (e.g., SiliconFlow) for embeddings.
|
||||
|
||||
If your `Azure OpenAI API Key`` supports `embedding model`, you can refer to the following configuration example.
|
||||
|
||||
.. code-block:: Properties
|
||||
|
||||
cat << EOF > .env
|
||||
EMBEDDING_MODEL=azure/<Model deployment supporting embedding>
|
||||
CHAT_MODEL=azure/<your deployment name>
|
||||
AZURE_API_KEY=<replace_with_your_openai_api_key>
|
||||
AZURE_API_BASE=<your_unified_api_base>
|
||||
AZURE_API_VERSION=<azure api version>
|
||||
|
||||
Execution Environment Configuration
|
||||
===================================
|
||||
|
||||
Coder Environment Configuration (Docker vs. Conda)
|
||||
|
||||
RD-Agent's coders can execute code in different environments. You can control this behavior by setting environment variables in your ``.env`` file. This is useful for switching between a local Conda environment and an isolated Docker container.
|
||||
|
||||
To configure the environment, add the corresponding line to your ``.env`` file based on the scenario you are running.
|
||||
|
||||
**For the Model (Quant) Scenario:**
|
||||
|
||||
The execution environment is determined by the ``MODEL_COSTEER_ENV_TYPE`` variable, which is read from ``rdagent/components/coder/model_coder/conf.py``.
|
||||
|
||||
* **To use Docker** (recommended for isolated execution):
|
||||
|
||||
.. code-block:: properties
|
||||
|
||||
MODEL_COSTEER_ENV_TYPE=docker
|
||||
|
||||
* **To use Conda** (for running in a local Conda environment):
|
||||
|
||||
.. code-block:: properties
|
||||
|
||||
MODEL_COSTEER_ENV_TYPE=conda
|
||||
|
||||
**For the Data Science Scenario:**
|
||||
|
||||
The execution environment is determined by the ``DS_CODER_COSTEER_ENV_TYPE`` variable, which is read from ``rdagent/components/coder/data_science/conf.py``.
|
||||
|
||||
* **To use Docker** (recommended for isolated execution):
|
||||
|
||||
.. code-block:: properties
|
||||
|
||||
DS_CODER_COSTEER_ENV_TYPE=docker
|
||||
|
||||
* **To use Conda** (for running in a local Conda environment):
|
||||
|
||||
.. code-block:: properties
|
||||
|
||||
DS_CODER_COSTEER_ENV_TYPE=conda
|
||||
|
||||
|
||||
Custom Time Segment Configuration (Train / Valid / Test)
|
||||
=========================================================
|
||||
|
||||
RD-Agent now supports user-defined time segments for training, validation,
|
||||
and testing (backtesting). Users can customize these segments via environment
|
||||
variables in the ``.env`` file, depending on the scenario being executed.
|
||||
|
||||
This feature allows greater flexibility when running experiments on different
|
||||
time ranges without modifying code or YAML configurations.
|
||||
|
||||
Fin-Factor Scenario
|
||||
-------------------
|
||||
|
||||
When running the **fin_factor** scenario, you can configure the time segments
|
||||
using the following environment variables. These variables are read by the
|
||||
Factor-related PropSettings and directly affect the execution process.
|
||||
|
||||
Add the following entries to your ``.env`` file as needed:
|
||||
|
||||
.. code-block:: properties
|
||||
|
||||
QLIB_FACTOR_TRAIN_START=<train start date, default is 2008-01-01>
|
||||
QLIB_FACTOR_TRAIN_END=<train end date, default is 2014-12-31>
|
||||
QLIB_FACTOR_VALID_START=<valid start date, default is 2015-01-01>
|
||||
QLIB_FACTOR_VALID_END=<valid end date, default is 2016-12-31>
|
||||
QLIB_FACTOR_TEST_START=<test / backtest start date, default is 2017-01-01>
|
||||
QLIB_FACTOR_TEST_END=<test / backtest end date, default is 2020-12-31>
|
||||
|
||||
Fin-Model Scenario
|
||||
------------------
|
||||
|
||||
When running the **fin_model** scenario, the model training, validation, and
|
||||
testing time segments can be configured independently via the following
|
||||
environment variables:
|
||||
|
||||
.. code-block:: properties
|
||||
|
||||
QLIB_MODEL_TRAIN_START=<train start date, default is 2008-01-01>
|
||||
QLIB_MODEL_TRAIN_END=<train end date, default is 2014-12-31>
|
||||
QLIB_MODEL_VALID_START=<valid start date, default is 2015-01-01>
|
||||
QLIB_MODEL_VALID_END=<valid end date, default is 2016-12-31>
|
||||
QLIB_MODEL_TEST_START=<test / backtest start date, default is 2017-01-01>
|
||||
QLIB_MODEL_TEST_END=<test / backtest end date, default is 2020-12-31>
|
||||
|
||||
These settings are used during model training and evaluation and directly
|
||||
impact the execution workflow.
|
||||
|
||||
Fin-Quant Scenario
|
||||
------------------
|
||||
|
||||
When running the **fin_quant** scenario, RD-Agent supports configuring time
|
||||
segments for factor, model, and quant stages simultaneously.
|
||||
|
||||
**Note:** The ``QLIB_QUANT_*`` variables are only used for front-end UI display
|
||||
purposes and do **not** affect the actual execution process.
|
||||
|
||||
You may configure the following variables in your ``.env`` file:
|
||||
|
||||
.. code-block:: properties
|
||||
|
||||
QLIB_FACTOR_TRAIN_START=<train start date, default is 2008-01-01>
|
||||
QLIB_FACTOR_TRAIN_END=<train end date, default is 2014-12-31>
|
||||
QLIB_FACTOR_VALID_START=<valid start date, default is 2015-01-01>
|
||||
QLIB_FACTOR_VALID_END=<valid end date, default is 2016-12-31>
|
||||
QLIB_FACTOR_TEST_START=<test / backtest start date, default is 2017-01-01>
|
||||
QLIB_FACTOR_TEST_END=<test / backtest end date, default is 2020-12-31>
|
||||
|
||||
QLIB_MODEL_TRAIN_START=<train start date, default is 2008-01-01>
|
||||
QLIB_MODEL_TRAIN_END=<train end date, default is 2014-12-31>
|
||||
QLIB_MODEL_VALID_START=<valid start date, default is 2015-01-01>
|
||||
QLIB_MODEL_VALID_END=<valid end date, default is 2016-12-31>
|
||||
QLIB_MODEL_TEST_START=<test / backtest start date, default is 2017-01-01>
|
||||
QLIB_MODEL_TEST_END=<test / backtest end date, default is 2020-12-31>
|
||||
|
||||
QLIB_QUANT_TRAIN_START=<train start date, default is 2008-01-01>
|
||||
QLIB_QUANT_TRAIN_END=<train end date, default is 2014-12-31>
|
||||
QLIB_QUANT_VALID_START=<valid start date, default is 2015-01-01>
|
||||
QLIB_QUANT_VALID_END=<valid end date, default is 2016-12-31>
|
||||
QLIB_QUANT_TEST_START=<test / backtest start date, default is 2017-01-01>
|
||||
QLIB_QUANT_TEST_END=<test / backtest end date, default is 2020-12-31>
|
||||
|
||||
This setup allows the front-end to display consistent segment information
|
||||
across different stages while keeping execution logic unchanged.
|
||||
|
||||
|
||||
Configuration(deprecated)
|
||||
=========================
|
||||
@@ -293,10 +95,6 @@ To run the application, please create a `.env` file in the root directory of the
|
||||
|
||||
If you are using this deprecated version, you should set `BACKEND` to `rdagent.oai.backend.DeprecBackend`.
|
||||
|
||||
.. code-block:: Properties
|
||||
|
||||
BACKEND=rdagent.oai.backend.DeprecBackend
|
||||
|
||||
Here are some other configuration options that you can use:
|
||||
|
||||
OpenAI API
|
||||
|
||||
@@ -1,238 +0,0 @@
|
||||
# NexQuant Parallel Run System
|
||||
|
||||
## Overview
|
||||
|
||||
The Parallel Run System enables concurrent execution of 5+ factor generation experiments with automatic API key distribution and complete isolation between runs.
|
||||
|
||||
## Architecture
|
||||
|
||||
### Components
|
||||
|
||||
| File | Purpose |
|
||||
|------|---------|
|
||||
| `nexquant.py` | Extended with `--run-id` parameter for isolated single runs |
|
||||
| `nexquant_parallel.py` | Parallel runner manager with Rich live dashboard |
|
||||
| `factor_runner.py` | Modified to use `PARALLEL_RUN_ID` for path isolation |
|
||||
| `CoSTEER/__init__.py` | Modified to use `PARALLEL_RUN_ID` for intermediate results |
|
||||
|
||||
### Directory Structure (Per Run)
|
||||
|
||||
```
|
||||
results/
|
||||
├── db/ # Shared database
|
||||
├── runs/
|
||||
│ ├── run1/ # Run #1 isolated results
|
||||
│ │ ├── factors/ # Factor JSON files
|
||||
│ │ ├── logs/ # Run-specific logs
|
||||
│ │ ├── db/ # Run-specific database
|
||||
│ │ └── costeer/ # CoSTEER intermediate results
|
||||
│ ├── run2/ # Run #2 isolated results
|
||||
│ │ └── ...
|
||||
│ └── runN/ # Run #N isolated results
|
||||
│ └── ...
|
||||
└── logs/ # Default (non-parallel) logs
|
||||
```
|
||||
|
||||
### Log Files
|
||||
|
||||
```
|
||||
fin_quant.log # Single run (run_id=0)
|
||||
fin_quant_run1.log # Parallel run #1
|
||||
fin_quant_run2.log # Parallel run #2
|
||||
...
|
||||
```
|
||||
|
||||
### Workspaces
|
||||
|
||||
```
|
||||
RD-Agent_workspace/ # Single run (run_id=0)
|
||||
RD-Agent_workspace_run1/ # Parallel run #1
|
||||
RD-Agent_workspace_run2/ # Parallel run #2
|
||||
...
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
### CLI - Single Parallel Run
|
||||
|
||||
```bash
|
||||
# Run with isolated results
|
||||
nexquant quant --run-id 1 -m openrouter
|
||||
```
|
||||
|
||||
### CLI - Parallel Runner (Direct)
|
||||
|
||||
```bash
|
||||
# Run 5 experiments with 2 API keys
|
||||
python nexquant_parallel.py --runs 5 --api-keys 2
|
||||
|
||||
# Run 3 experiments with local model
|
||||
python nexquant_parallel.py --runs 3 --model local
|
||||
|
||||
# Custom configuration
|
||||
python nexquant_parallel.py -n 10 -k 2 -m openrouter
|
||||
```
|
||||
|
||||
### Programmatic Usage
|
||||
|
||||
```python
|
||||
from nexquant_parallel import main
|
||||
|
||||
result = main(runs=5, api_keys=2, model="openrouter")
|
||||
print(f"Success: {result['success']}/{result['total']}")
|
||||
```
|
||||
|
||||
## API Key Distribution
|
||||
|
||||
The system distributes API keys using round-robin assignment:
|
||||
|
||||
| Run ID | API Key | Model |
|
||||
|--------|---------|-------|
|
||||
| 1 | Key 1 | openrouter |
|
||||
| 2 | Key 2 | openrouter |
|
||||
| 3 | Key 1 | openrouter |
|
||||
| 4 | Key 2 | openrouter |
|
||||
| 5 | Key 1 | openrouter |
|
||||
|
||||
**With 2 API keys:**
|
||||
- Runs 1, 3, 5 → Key 1
|
||||
- Runs 2, 4 → Key 2
|
||||
|
||||
**LiteLLM Load Balancing:**
|
||||
When 2 API keys are available, the system configures LiteLLM for parallel request handling:
|
||||
```
|
||||
OPENAI_API_KEY=key1,key2
|
||||
LITELLM_PARALLEL_CALLS=2
|
||||
```
|
||||
|
||||
## Isolation Guarantees
|
||||
|
||||
Each parallel run is completely isolated:
|
||||
|
||||
### Environment Variables
|
||||
- `PARALLEL_RUN_ID=N` - Identifies the run
|
||||
- `RD_AGENT_WORKSPACE` - Points to run-specific workspace
|
||||
- `OPENAI_API_KEY` - Assigned API key for this run
|
||||
|
||||
### No Shared State
|
||||
- ✅ Separate log files
|
||||
- ✅ Separate result directories
|
||||
- ✅ Separate workspace directories
|
||||
- ✅ Separate database files (optional)
|
||||
- ✅ No race conditions (no shared mutable state)
|
||||
|
||||
### Graceful Degradation
|
||||
- If a run fails, others continue unaffected
|
||||
- Each run is independently restartable
|
||||
- Results are persisted immediately after completion
|
||||
|
||||
## Live Dashboard
|
||||
|
||||
The parallel runner shows a Rich-based live dashboard:
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────┐
|
||||
│ 🔀 NexQuant Parallel Run Dashboard │
|
||||
├──────┬──────────┬──────────┬─────────┬──────────┬───────┤
|
||||
│ Run │ Status │ Elapsed │ API Key │ Model │ Exit │
|
||||
├──────┼──────────┼──────────┼─────────┼──────────┼───────┤
|
||||
│ #1 │ ✅ success│ 02:15:30│ 1 │openrouter│ 0 │
|
||||
│ #2 │ 🔄 running│ 01:45:12│ 2 │openrouter│ -- │
|
||||
│ #3 │ 🔄 running│ 01:42:08│ 1 │openrouter│ -- │
|
||||
│ #4 │ ⏳ pending│ --:--:--│ 2 │openrouter│ -- │
|
||||
│ #5 │ ❌ failed │ 00:05:23│ 1 │openrouter│ 1 │
|
||||
├──────┴──────────┴──────────┴─────────┴──────────┴───────┤
|
||||
│ Summary: 5 total | 1 done | 2 running | 1 pending | 1 failed │
|
||||
└─────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
## Signal Handling
|
||||
|
||||
- **First Ctrl+C:** Gracefully stops all running subprocesses
|
||||
- **Second Ctrl+C:** Force kills all remaining processes
|
||||
- Dashboard updates in real-time during shutdown
|
||||
|
||||
## Configuration
|
||||
|
||||
### Environment Variables (`.env`)
|
||||
|
||||
```bash
|
||||
# Required for openrouter mode
|
||||
OPENROUTER_API_KEY=sk-or-your-first-key
|
||||
OPENROUTER_API_KEY_2=sk-or-your-second-key # Optional
|
||||
|
||||
# Required for local mode
|
||||
OPENAI_API_KEY=local
|
||||
OPENAI_API_BASE=http://localhost:8081/v1
|
||||
CHAT_MODEL=qwen3.5-35b
|
||||
|
||||
# Optional: Custom model
|
||||
OPENROUTER_MODEL=openrouter/qwen/qwen3.6-plus:free
|
||||
```
|
||||
|
||||
## Performance
|
||||
|
||||
**Expected Speedup:**
|
||||
- 5 runs with 2 API keys ≈ 2.5× faster than sequential
|
||||
- 5 runs with local model ≈ 5× faster than sequential (no API rate limits)
|
||||
|
||||
**Overhead:**
|
||||
- ~1 second per run for subprocess startup
|
||||
- Dashboard refresh: 2 Hz (negligible CPU)
|
||||
|
||||
## Error Handling
|
||||
|
||||
| Scenario | Behavior |
|
||||
|----------|----------|
|
||||
| Run fails | Logged, others continue |
|
||||
| API key exhausted | Retry with next key |
|
||||
| Ctrl+C pressed | Graceful shutdown of all runs |
|
||||
| Disk full | Error logged, run marked failed |
|
||||
| LLM timeout | Run fails, others unaffected |
|
||||
|
||||
## Integration with Existing Code
|
||||
|
||||
### factor_runner.py Changes
|
||||
|
||||
```python
|
||||
# Before (shared paths)
|
||||
log_dir = project_root / "results" / "logs"
|
||||
factors_dir = project_root / "results" / "factors"
|
||||
|
||||
# After (parallel-aware)
|
||||
parallel_run_id = os.getenv("PARALLEL_RUN_ID", "0")
|
||||
if parallel_run_id != "0":
|
||||
log_dir = project_root / "results" / "runs" / f"run{parallel_run_id}" / "logs"
|
||||
factors_dir = project_root / "results" / "runs" / f"run{parallel_run_id}" / "factors"
|
||||
```
|
||||
|
||||
### CoSTEER/__init__.py Changes
|
||||
|
||||
```python
|
||||
# Intermediate results isolation
|
||||
parallel_run_id = os.getenv("PARALLEL_RUN_ID", "0")
|
||||
if parallel_run_id != "0":
|
||||
results_dir = project_root / "results" / "runs" / f"run{parallel_run_id}" / "costeer"
|
||||
```
|
||||
|
||||
## Testing
|
||||
|
||||
```bash
|
||||
# Run all integration tests
|
||||
pytest test/integration/test_all_features.py -v
|
||||
|
||||
# Test parallel runner imports
|
||||
python -c "from nexquant_parallel import ParallelRunner, main; print('✅ OK')"
|
||||
|
||||
# Test CLI options
|
||||
nexquant quant --help # Should show --run-id option
|
||||
```
|
||||
|
||||
## Future Enhancements
|
||||
|
||||
- [ ] Auto-detect optimal number of parallel runs based on API rate limits
|
||||
- [ ] Result aggregation and comparison across runs
|
||||
- [ ] Dynamic API key rebalancing (assign more runs to faster key)
|
||||
- [ ] Support for >2 API keys
|
||||
- [ ] Run prioritization (run high-priority experiments first)
|
||||
- [ ] Slack/email notifications on completion
|
||||
@@ -43,4 +43,3 @@ The supported scenarios are listed below:
|
||||
model_agent_fin
|
||||
model_copilot_general
|
||||
data_science
|
||||
finetune
|
||||
|
||||
@@ -125,7 +125,7 @@ You can try our demo by running the following command:
|
||||
|
||||
.. code-block:: sh
|
||||
|
||||
rdagent fin_factor_report --report-folder=git_ignore_folder/reports
|
||||
rdagent fin_factor_report --report_folder=git_ignore_folder/reports
|
||||
|
||||
- Alternatively, you can store the paths of the reports in `report_result_json_file_path`. The format should be:
|
||||
|
||||
|
||||
+97
-479
@@ -8,61 +8,12 @@ Data Science Agent
|
||||
------------------------------------------------------------------------------------------
|
||||
The Data Science Agent is an agent that can automatically perform feature engineering and model tuning. It can be used to solve various data science problems, such as image classification, time series forecasting, and text classification.
|
||||
|
||||
🌟 Introduction
|
||||
~~~~~~~~~~~~~~~~~~
|
||||
|
||||
In this scenario, our automated system proposes hypothesis, choose action, implements code, conducts validation, and utilizes feedback in a continuous, iterative process.
|
||||
|
||||
The goal is to automatically optimize performance metrics within the validation set or Kaggle Leaderboard, ultimately discovering the most efficient features and models through autonomous research and development.
|
||||
|
||||
Here's an enhanced outline of the steps:
|
||||
|
||||
**Step 1 : Hypothesis Generation 🔍**
|
||||
|
||||
- Generate and propose initial hypotheses based on previous experiment analysis and domain expertise, with thorough reasoning and financial justification.
|
||||
|
||||
**Step 2 : Experiment Creation ✨**
|
||||
|
||||
- Transform the hypothesis into a task.
|
||||
- Choose a specific action within feature engineering or model tuning.
|
||||
- Develop, define, and implement a new feature or model, including its name, description, and formulation.
|
||||
|
||||
**Step 3 : Model/Feature Implementation 👨💻**
|
||||
|
||||
- Implement the model code based on the detailed description.
|
||||
- Evolve the model iteratively as a developer would, ensuring accuracy and efficiency.
|
||||
|
||||
**Step 4 : Validation on Test Set or Kaggle 📉**
|
||||
|
||||
- Validate the newly developed model using the test set or Kaggle dataset.
|
||||
- Assess the model's effectiveness and performance based on the validation results.
|
||||
|
||||
**Step 5: Feedback Analysis 🔍**
|
||||
|
||||
- Analyze validation results to assess performance.
|
||||
- Use insights to refine hypotheses and enhance the model.
|
||||
|
||||
**Step 6: Hypothesis Refinement ♻️**
|
||||
|
||||
- Adjust hypotheses based on validation feedback.
|
||||
- Iterate the process to continuously improve the model.
|
||||
|
||||
📖 Data Science Background
|
||||
🧭 Example Guide
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
In the evolving landscape of artificial intelligence, **Data Science** represents a powerful paradigm where machines engage in autonomous exploration, hypothesis testing, and model development across diverse domains — from healthcare and finance to logistics and research.
|
||||
- 🔧 **Set up RD-Agent Environment**
|
||||
|
||||
The **Data Science** Agent stands as a central engine in this transformation, enabling users to automate the entire machine learning workflow: from hypothesis generation to code implementation, validation, and refinement — all guided by performance feedback.
|
||||
|
||||
By leveraging the **Data Science** Agent, researchers and developers can accelerate experimentation cycles. Whether fine-tuning custom models or competing in high-stakes benchmarks like Kaggle, the Data Science Agent unlocks new frontiers in intelligent, self-directed discovery.
|
||||
|
||||
🧭 Example Guide - Customized dataset
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
🔧 **Set up RD-Agent Environment**
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
- Before you start, please make sure you have installed RD-Agent and configured the environment for RD-Agent correctly. If you want to know how to install and configure the RD-Agent, please refer to the `documentation <../installation_and_configuration.html>`_.
|
||||
- Before you start, please make sure you have installed RD-Agent and configured the environment for RD-Agent correctly. If you want to know how to install and configure the RD-Agent, please refer to the `documentation <../installation_and_configuration.html>`_.
|
||||
|
||||
- 🔩 **Setting the Environment variables at .env file**
|
||||
|
||||
@@ -73,494 +24,161 @@ By leveraging the **Data Science** Agent, researchers and developers can acceler
|
||||
dotenv set DS_LOCAL_DATA_PATH <your local directory>/ds_data
|
||||
dotenv set DS_SCEN rdagent.scenarios.data_science.scen.DataScienceScen
|
||||
|
||||
📥 **Prepare Customized datasets**
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
- 📥 **Prepare Competition Data**
|
||||
|
||||
- A data science competition dataset usually consists of two parts: ``competition dataset`` and ``evaluation dataset``. (We provide `a sample <https://github.com/microsoft/RD-Agent/tree/main/rdagent/scenarios/data_science/example>`_ of a customized dataset named: `arf-12-hours-prediction-task as a reference`.)
|
||||
|
||||
- The ``competition dataset`` contains **training data**, **test data**, **description files**, **formatted submission files**, **data sampling codes**.
|
||||
|
||||
- The ``evaluation dataset`` contains **standard answer file**, **data checking codes**, and **Code for calculation of scores**.
|
||||
- Data Science competition data typically consists of three components: a competition description file (in Markdown format), the competition dataset, and evaluation scripts. For reference, an example of a custom user-defined dataset is provided in ``rdagent/scenarios/data_science/example``.
|
||||
|
||||
- We use the ``arf-12-hours-prediction-task`` data as a sample to introduce the preparation workflow for the competition dataset.
|
||||
|
||||
- Create a ``ds_data/source_data/arf-12-hours-prediction-task`` folder, which will be used to store your raw dataset.
|
||||
|
||||
- The raw files for the competition ``arf-12-hours-prediction-task`` have two files: ``ARF_12h.csv`` and ``X.npz``.
|
||||
|
||||
- Create a ``ds_data/source_data/arf-12-hours-prediction-task/prepare.py`` file that splits your raw data into **training data**, **test data**, **formatted submission file**, and **standard answer file**. (You will need to write a script based on your raw data.)
|
||||
|
||||
- The following shows the preprocessing code for the raw data of ``arf-12-hours-prediction-task``.
|
||||
|
||||
.. literalinclude:: ../../rdagent/scenarios/data_science/example/source_data/arf-12-hours-prediction-task/prepare.py
|
||||
:language: python
|
||||
:caption: ds_data/source_data/arf-12-hours-prediction-task/prepare.py
|
||||
:linenos:
|
||||
|
||||
- At the end of program execution, the ``ds_data`` folder structure will look like this:
|
||||
- **Correct directory structure (Here is an example of competition data with id custom_data)**
|
||||
|
||||
.. code-block:: text
|
||||
|
||||
ds_data
|
||||
├── arf-12-hours-prediction-task
|
||||
│ ├── train
|
||||
│ │ ├── ARF_12h.csv
|
||||
│ │ └── X.npz
|
||||
│ ├── test
|
||||
│ │ ├── ARF_12h.csv
|
||||
│ │ └── X.npz
|
||||
│ └── sample_submission.csv
|
||||
├── eval
|
||||
│ └── arf-12-hours-prediction-task
|
||||
│ └── submission_test.csv
|
||||
└── source_data
|
||||
└── arf-12-hours-prediction-task
|
||||
├── ARF_12h.csv
|
||||
├── prepare.py
|
||||
└── X.npz
|
||||
└── eval
|
||||
| └── custom_data
|
||||
| └── grade.py
|
||||
| └── valid.py
|
||||
| └── test.csv
|
||||
└── custom_data
|
||||
└── train.csv
|
||||
└── test.csv
|
||||
└── sample_submission.csv
|
||||
└── description.md
|
||||
└── sample.py
|
||||
|
||||
- ``ds_data/custom_data/train.csv:`` Necessary training data in csv or parquet format, or training images.
|
||||
|
||||
- Create a ``ds_data/arf-12-hours-prediction-task/description.md`` file to describe your competition, Objective, dataset, and other information.
|
||||
- ``ds_data/custom_data/description.md:`` (Optional) Competition description file.
|
||||
|
||||
- The following shows the description file for ``arf-12-hours-prediction-task``
|
||||
- ``ds_data/custom_data/sample_submission.csv:`` (Optional) Competition sample submission file.
|
||||
|
||||
.. literalinclude:: ../../rdagent/scenarios/data_science/example/arf-12-hours-prediction-task/description.md
|
||||
:language: markdown
|
||||
:caption: ds_data/arf-12-hours-prediction-task/description.md
|
||||
:linenos:
|
||||
- ``ds_data/custom_data/sample.py:`` (Optional) Sample code for generating debug data from the competition dataset. If not provided, R&D-Agent will use its default sampling logic. For details, see the ``create_debug_data`` function in ``rdagent/scenarios/data_science/debug/data.py``.
|
||||
|
||||
- Create a ``ds_data/arf-12-hours-prediction-task/sample.py`` file to construct the debugging sample data.
|
||||
- ``ds_data/eval/custom_data/grade.py:`` (Optional) Competition grade script, in order to calculate the score for the submission.
|
||||
|
||||
- The following shows the script for constructing the debugging sample data based on the ``arf-12-hours-prediction-task`` dataset implementation.
|
||||
- ``ds_data/eval/custom_data/valid.py:`` (Optional) Competition validation script, in order to check if the submission format is correct.
|
||||
|
||||
.. literalinclude:: ../../rdagent/scenarios/data_science/example/arf-12-hours-prediction-task/sample.py
|
||||
:language: markdown
|
||||
:caption: ds_data/arf-12-hours-prediction-task/sample.py
|
||||
:linenos:
|
||||
- ``ds_data/eval/custom_data/submission_test.csv:`` (Optional) Competition test label file.
|
||||
|
||||
- Create a ``ds_data/eval/arf-12-hours-prediction-task/valid.py`` file, which is used to check the validity of the submission files to ensure that their formatting is consistent with the reference file.
|
||||
|
||||
- The following shows a script that checks the validity of a submission based on the ``arf-12-hours-prediction-task`` data.
|
||||
|
||||
.. literalinclude:: ../../rdagent/scenarios/data_science/example/eval/arf-12-hours-prediction-task/valid.py
|
||||
:language: markdown
|
||||
:caption: ds_data/eval/arf-12-hours-prediction-task/valid.py
|
||||
:linenos:
|
||||
|
||||
- Create a ``ds_data/eval/arf-12-hours-prediction-task/grade.py`` file, which is used to calculate the score based on the submission file and the **standard answer file**, and output the result in JSON format.
|
||||
|
||||
- The following shows a grading script based on the ``arf-12-hours-prediction-task`` data implementation.
|
||||
|
||||
.. literalinclude:: ../../rdagent/scenarios/data_science/example/eval/arf-12-hours-prediction-task/grade.py
|
||||
:language: markdown
|
||||
:caption: ds_data/eval/arf-12-hours-prediction-task/grade.py
|
||||
:linenos:
|
||||
|
||||
- At this point, you have created a complete dataset. The correct structure of the dataset should look like this.
|
||||
|
||||
.. code-block:: text
|
||||
|
||||
ds_data
|
||||
├── arf-12-hours-prediction-task
|
||||
│ ├── train
|
||||
│ │ ├── ARF_12h.csv
|
||||
│ │ └── X.npz
|
||||
│ ├── test
|
||||
│ │ ├── ARF_12h.csv
|
||||
│ │ └── X.npz
|
||||
│ ├── description.md
|
||||
│ ├── sample_submission.csv
|
||||
│ └── sample.py
|
||||
├── eval
|
||||
│ └── arf-12-hours-prediction-task
|
||||
│ ├── grade.py
|
||||
│ ├── submission_test.csv
|
||||
│ └── valid.py
|
||||
└── source_data
|
||||
└── arf-12-hours-prediction-task
|
||||
├── ARF_12h.csv
|
||||
├── prepare.py
|
||||
└── X.npz
|
||||
|
||||
- The above shows the complete dataset creation workflow, some of the files are not required, in practice you can customize the dataset according to your own needs.
|
||||
|
||||
- If we don't need the test set scores, then we can choose not to generate **formatted submission files** and **standard answer file** in the prepare code, and we don't need to write **data checking codes** and **Code for calculation of scores**.
|
||||
|
||||
- **Data sampling code** can also be created according to the actual need, if you do not provide **data sampling code**, RD-Agent will be handed over to the LLM sampling at runtime.
|
||||
|
||||
- In the default sampling method (``create_debug_data``), the default sampling ratio (parameter: ``min_frac``) is 1%, if 1% of the data is less than 5, then 5 data will be sampled (parameter: ``min_num``), you can adjust the sampling ratio by adjusting these two parameters.
|
||||
|
||||
- If you have customized data sampling code, you need to set ``DS_SAMPLE_DATA_BY_LLM`` to ``False`` (default is True) in the ``.env`` file before running, so that the program will use the customized sampling code when running, and you can just execute this line of code in the command line:
|
||||
|
||||
.. code-block:: sh
|
||||
|
||||
dotenv set DS_SAMPLE_DATA_BY_LLM False
|
||||
|
||||
- In addition, we provide a data sampling method in `rdagent.scenarios.data_science.debug.data.create_debug_data <https://github.com/microsoft/RD-Agent/blob/main/rdagent/scenarios/data_science/debug/data.py#L605>`_, in this method, the default sampling ratio (parameter: ``min_frac``) is 1%, if 1% of the data is less than 5, then 5 data will be sampled (parameter: ``min_num``), you can use this method by the following two ways.
|
||||
|
||||
- You can set ``DS_SAMPLE_DATA_BY_LLM`` to ``False`` in the ``.env`` file so that when the program runs, it will use the sampling code provided by RD-Agent.
|
||||
|
||||
.. code-block:: sh
|
||||
|
||||
dotenv set DS_SAMPLE_DATA_BY_LLM False
|
||||
|
||||
- If you think that the parameters in the receipt sampling method provided by RD-Agent are not suitable, you can customize the parameters in the following command and run it, and set ``DS_SAMPLE_DATA_BY_LLM`` to ``False`` in the ``.env`` so that the program will use the sampling data you provided when running.
|
||||
|
||||
.. code-block:: sh
|
||||
|
||||
python rdagent/app/data_science/debug.py --dataset_path <dataset path> --competition <competiton_name> --min_frac <sampling ratio> --min_num <minimum number of sampling>
|
||||
dotenv set DS_SAMPLE_DATA_BY_LLM False
|
||||
|
||||
- If you don't need the scores from the test set and leave the data sampling to the LLM, or if you use the sampling method provided by the RD-Agent, you only need to prepare a minimal dataset. The structure of the simplest dataset should be as shown below.
|
||||
|
||||
.. code-block:: text
|
||||
|
||||
ds_data
|
||||
├── arf-12-hours-prediction-task
|
||||
│ ├── train
|
||||
│ │ ├── ARF_12h.csv
|
||||
│ │ └── X.npz
|
||||
│ ├── test
|
||||
│ │ ├── ARF_12h.csv
|
||||
│ │ └── X.npz
|
||||
│ └── description.md
|
||||
└── source_data
|
||||
└── arf-12-hours-prediction-task
|
||||
├── ARF_12h.csv
|
||||
├── prepare.py
|
||||
└── X.npz
|
||||
|
||||
- We have prepared a dataset based on the above description for your reference. You can download it with the following command.
|
||||
|
||||
.. code-block:: sh
|
||||
|
||||
wget https://github.com/SunsetWolf/rdagent_resource/releases/download/ds_data/arf-12-hours-prediction-task.zip
|
||||
|
||||
⚙️ **Set up Environment for Customized datasets**
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
- 🔧 **Set up Environment for Custom User-defined Dataset**
|
||||
|
||||
.. code-block:: sh
|
||||
|
||||
dotenv set DS_SCEN rdagent.scenarios.data_science.scen.DataScienceScen
|
||||
dotenv set DS_LOCAL_DATA_PATH <your local directory>/ds_data
|
||||
dotenv set DS_LOCAL_DATA_PATH rdagent/scenarios/data_science/example
|
||||
dotenv set DS_IF_USING_MLE_DATA False
|
||||
dotenv set DS_CODER_ON_WHOLE_PIPELINE True
|
||||
dotenv set DS_CODER_COSTEER_ENV_TYPE docker
|
||||
|
||||
- 📘 More Environment Variables (Optional)
|
||||
- 🚀 **Run the Application**
|
||||
|
||||
- If you want to see all the available environment variables, you can refer to the configuration file for Data Science scenarios:
|
||||
|
||||
.. literalinclude:: ../../rdagent/app/data_science/conf.py
|
||||
:language: python
|
||||
:linenos:
|
||||
|
||||
- These variables allow you to have finer-grained control in Data Science scenarios.
|
||||
|
||||
🚀 **Run the Application**
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
- 🌏 You can directly run the application by using the following command:
|
||||
- You can directly run the application by using the following command:
|
||||
|
||||
.. code-block:: sh
|
||||
|
||||
rdagent data_science --competition <Competition ID>
|
||||
|
||||
- The following shows the command to run based on the ``arf-12-hours-prediction-task`` data
|
||||
|
||||
.. code-block:: sh
|
||||
|
||||
rdagent data_science --competition arf-12-hours-prediction-task
|
||||
|
||||
- More CLI Parameters for `rdagent data_science` command:
|
||||
|
||||
.. automodule:: rdagent.app.data_science.loop
|
||||
:members:
|
||||
:no-index:
|
||||
|
||||
- 📈 Visualize the R&D Process
|
||||
|
||||
- We provide a web UI to visualize the log. You just need to run:
|
||||
|
||||
.. code-block:: sh
|
||||
|
||||
rdagent ui --port <custom port> --log-dir <your log folder like "log/"> --data_science True
|
||||
|
||||
- Then you can input the log path and visualize the R&D process.
|
||||
|
||||
- 🧪 Scoring the test results
|
||||
|
||||
- Finally, shutdown the program, and get the test set scores with this command.
|
||||
- Then, you can run the test set score corresponding to each round of the loop.
|
||||
|
||||
.. code-block:: sh
|
||||
|
||||
dotenv run -- python rdagent/log/mle_summary.py grade <url_to_log>
|
||||
dotenv run -- python rdagent/log/mle_summary.py grade <url_to_log>
|
||||
|
||||
Here, <url_to_log> refers to the parent directory of the log folder generated during the run.
|
||||
|
||||
🕹️ Kaggle Agent
|
||||
~~~~~~~~~~~~~~~~
|
||||
- 📥 **Visualize the R&D Process**
|
||||
|
||||
📖 Background
|
||||
^^^^^^^^^^^^^^
|
||||
- We provide a web UI to visualize the log. You just need to run:
|
||||
|
||||
In the landscape of data science competitions, Kaggle serves as the ultimate arena where data enthusiasts harness the power of algorithms to tackle real-world challenges.
|
||||
The Kaggle Agent stands as a pivotal tool, empowering participants to seamlessly integrate cutting-edge models and datasets, transforming raw data into actionable insights.
|
||||
.. code-block:: sh
|
||||
|
||||
By utilizing the **Kaggle Agent**, data scientists can craft innovative solutions that not only uncover hidden patterns but also drive significant advancements in predictive accuracy and model robustness.
|
||||
streamlit run rdagent/log/ui/dsapp.py
|
||||
|
||||
🧭 Example Guide - Kaggle Dataset
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
- Then you can input the log path and visualize the R&D process.
|
||||
|
||||
🛠️ Preparing For The Competition
|
||||
""""""""""""""""""""""""""""""""""
|
||||
🔍 MLE-bench Guide: Running ML Engineering via MLE-bench
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
- 📝 **MLE-bench Overview**
|
||||
|
||||
- MLE-bench is a comprehensive benchmark designed to evaluate the ML engineering capabilities of AI systems using real-world scenarios. The dataset comprises 75 Kaggle competitions. Since Kaggle does not provide held-out test sets for these competitions, the benchmark includes preparation scripts that split the publicly available training data into new training and test sets, and grading scripts are provided for each competition to accurately evaluate submission scores.
|
||||
|
||||
- 🔧 **Set up Environment for MLE-bench**
|
||||
|
||||
- Running R&D-Agent on MLE-bench is designed for full automation. There is no need for manual downloads and data preparation. Simply set the environment variable ``DS_IF_USING_MLE_DATA`` to True.
|
||||
|
||||
- At runtime, R&D-Agent will automatically build the Docker image specified at ``rdagent/scenarios/kaggle/docker/mle_bench_docker/Dockerfile``. This image is responsible for downloading the required datasets and grading files for MLE-bench.
|
||||
|
||||
- Note: The first run may take longer than subsequent runs as the Docker image and data are being downloaded and set up for the first time.
|
||||
|
||||
.. code-block:: sh
|
||||
|
||||
dotenv set DS_LOCAL_DATA_PATH <your local directory>/ds_data
|
||||
dotenv set DS_IF_USING_MLE_DATA True
|
||||
|
||||
- 🔨 **Configuring the Kaggle API**
|
||||
|
||||
- Register and login on the `Kaggle <https://www.kaggle.com/>`_ website.
|
||||
- Click on the avatar (usually in the top right corner of the page) -> ``Settings`` -> ``Create New Token``, A file called ``kaggle.json`` will be downloaded.
|
||||
- Move ``kaggle.json`` to ``~/.config/kaggle/``
|
||||
- Modify the permissions of the ``kaggle.json`` file.
|
||||
- Downloading Kaggle competition data requires the Kaggle API. You can set up the Kaggle API by following these steps:
|
||||
|
||||
- Register and login on the `Kaggle <https://www.kaggle.com/>`_ website.
|
||||
|
||||
.. code-block:: sh
|
||||
- Click on the avatar (usually in the top right corner of the page) -> ``Settings`` -> ``Create New Token``, A file called ``kaggle.json`` will be downloaded.
|
||||
|
||||
chmod 600 ~/.config/kaggle/kaggle.json
|
||||
- Move ``kaggle.json`` to ``~/.config/kaggle/``
|
||||
|
||||
- Modify the permissions of the ``kaggle.json`` file.
|
||||
|
||||
.. code-block:: sh
|
||||
|
||||
chmod 600 ~/.config/kaggle/kaggle.json
|
||||
|
||||
- For more information about Kaggle API Settings, refer to the `Kaggle API <https://github.com/Kaggle/kaggle-api>`_.
|
||||
|
||||
- 🔩 **Setting the Environment variables at .env file**
|
||||
|
||||
- Determine the path where the data will be stored and add it to the ``.env`` file.
|
||||
- 🔩 **Setting the Environment Variables for MLE-bench**
|
||||
|
||||
.. code-block:: sh
|
||||
|
||||
mkdir -p <your local directory>/ds_data
|
||||
dotenv set KG_LOCAL_DATA_PATH <your local directory>/ds_data
|
||||
|
||||
- 📘 More Environment Variables (Optional)
|
||||
|
||||
- If you want to see all the available environment variables, you can refer to the configuration file for Data Science scenarios:
|
||||
|
||||
.. literalinclude:: ../../rdagent/app/data_science/conf.py
|
||||
:language: python
|
||||
:linenos:
|
||||
|
||||
- These variables allow you to have finer-grained control in Data Science scenarios.
|
||||
|
||||
- 🗳️ **Join the competition**
|
||||
|
||||
- If your Kaggle API account has not joined a competition, you will need to join the competition before running the program.
|
||||
|
||||
- At the bottom of the competition details page, you can find the ``Join the competition`` button, click on it and select ``I Understand and Accept`` to join the competition.
|
||||
|
||||
- In the **Competition List Available** below, you can jump to the competition details page.
|
||||
|
||||
📥 Preparing Competition DataDataset && Set up RD-Agent Environment
|
||||
""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
|
||||
|
||||
- As a subset of data science, kaggle's dataset still follows the data science format. Based on this, the kaggle dataset can be divided into two categories depending on whether or not it is supported by the **MLE-Bench**.
|
||||
|
||||
- What is **MLE-Bench**?
|
||||
|
||||
- **MLE-Bench** is a comprehensive benchmark designed to evaluate the **machine learning engineering** capabilities of AI systems using real-world scenarios. The dataset includes multiple Kaggle competitions. Since Kaggle does not provide reserved test sets for these competitions, the benchmark includes preparation scripts for splitting publicly available training data into new training and test sets, and scoring scripts for each competition to accurately evaluate submission scores.
|
||||
|
||||
- I'm running a competition Is **MLE-Bench** supported?
|
||||
|
||||
- You can see all the competitions supported by **MLE-Bench** `here <https://github.com/openai/mle-bench/tree/main/mlebench/competitions>`_.
|
||||
|
||||
- Prepare datasets for **MLE-Bench** supported competitions.
|
||||
|
||||
- If you agree with the **MLE-Bench** standard, then you don't need to prepare the dataset, you just need to configure your ``.env`` file to automate the download of the dataset.
|
||||
|
||||
- Configure environment variables, add ``DS_IF_USING_MLE_DATA`` to environment variables, and set it to ``True``.
|
||||
|
||||
.. code-block:: sh
|
||||
|
||||
dotenv set DS_IF_USING_MLE_DATA True
|
||||
|
||||
- Configure environment variables, add ``DS_SAMPLE_DATA_BY_LLM`` to environment variables, and set it to ``True``.
|
||||
|
||||
.. code-block:: sh
|
||||
|
||||
dotenv set DS_SAMPLE_DATA_BY_LLM True
|
||||
|
||||
- Configure environment variables, add ``DS_SCEN`` to environment variables, and set it to ``rdagent.scenarios.data_science.scen.KaggleScen``.
|
||||
|
||||
.. code-block:: sh
|
||||
|
||||
dotenv set DS_SCEN rdagent.scenarios.data_science.scen.KaggleScen
|
||||
|
||||
- At this point, you are ready to start running your competition, which will automatically download the data, and the LLM will automatically extract the minimum dataset.
|
||||
|
||||
- After running the program the structure of the ds_data folder should look like this (Using the ``tabular-playground-series-dec-2021`` contest as an example).
|
||||
|
||||
.. code-block:: text
|
||||
|
||||
ds_data
|
||||
├── tabular-playground-series-dec-2021
|
||||
│ ├── description.md
|
||||
│ ├── sample_submission.csv
|
||||
│ ├── test.csv
|
||||
│ └── train.csv
|
||||
└── zip_files
|
||||
└── tabular-playground-series-dec-2021
|
||||
└── tabular-playground-series-dec-2021.zip
|
||||
|
||||
- The ``ds_data/zip_files`` folder contains a zip file of the raw competition data downloaded from kaggle website.
|
||||
|
||||
- At runtime, RD-Agent will automatically build the Docker image specified at `rdagent/scenarios/kaggle/docker/mle_bench_docker/Dockerfile <https://github.com/microsoft/RD-Agent/blob/main/rdagent/scenarios/kaggle/docker/mle_bench_docker/Dockerfile>`_. This image is responsible for downloading the required datasets and grading files for MLE-Bench.
|
||||
|
||||
Note: The first run may take longer than subsequent runs as the Docker image and data are being downloaded and set up for the first time.
|
||||
|
||||
- Prepare datasets for competitions that are not supported by **MLE-Bench**.
|
||||
|
||||
- As a subset of data science, we can follow the format and steps of data science dataset to prepare kaggle dataset. Below we will describe the workflow for preparing a kaggle dataset using the competition ``playground-series-s4e9`` as an example.
|
||||
|
||||
- Create a ``ds_data/source_data/playground-series-s4e9`` folder, which will be used to store your raw dataset.
|
||||
|
||||
- The raw files for the competition ``playground-series-s4e9`` have two files: ``train.csv``, ``test.csv``, ``sample_submission.csv``, and there are two ways to get the raw data:
|
||||
|
||||
- You can find the raw data required for the competition on the `official kaggle website <https://www.kaggle.com/competitions/playground-series-s4e9/data>`_.
|
||||
|
||||
- Or you can use the command line to download the raw data for the competition, the download command is as follows.
|
||||
|
||||
.. code-block:: sh
|
||||
|
||||
kaggle competitions download -c playground-series-s4e9
|
||||
|
||||
- Create a ``ds_data/source_data/playground-series-s4e9/prepare.py`` file that splits your raw data into **training data**, **test data**, **formatted submission file**, and **standard answer file**. (You will need to write a script based on your raw data.)
|
||||
|
||||
- The following shows the preprocessing code for the raw data of ``playground-series-s4e9``.
|
||||
|
||||
.. literalinclude:: ../../rdagent/scenarios/data_science/example/source_data/playground-series-s4e9/prepare.py
|
||||
:language: python
|
||||
:caption: ds_data/source_data/playground-series-s4e9/prepare.py
|
||||
:linenos:
|
||||
|
||||
- At the end of program execution, the ``ds_data`` folder structure will look like this:
|
||||
|
||||
.. code-block:: text
|
||||
|
||||
ds_data
|
||||
├── playground-series-s4e9
|
||||
│ ├── train.csv
|
||||
│ ├── test.csv
|
||||
│ └── sample_submission.csv
|
||||
├── eval
|
||||
│ └── playground-series-s4e9
|
||||
│ └── submission_test.csv
|
||||
└── source_data
|
||||
└── playground-series-s4e9
|
||||
├── prepare.py
|
||||
├── sample_submission.csv
|
||||
├── test.csv
|
||||
└── train.csv
|
||||
|
||||
- Create a ``ds_data/playground-series-s4e9/description.md`` file to describe your competition, dataset description, and other information. We can find the `competition description information <https://www.kaggle.com/competitions/playground-series-s4e9/overview>`_ and the `dataset description information <https://www.kaggle.com/competitions/playground-series-s4e9/data>`_ from the Kaggle website.
|
||||
|
||||
- The following shows the description file for ``playground-series-s4e9``
|
||||
|
||||
.. literalinclude:: ../../rdagent/scenarios/data_science/example/playground-series-s4e9/description.md
|
||||
:language: markdown
|
||||
:caption: ds_data/playground-series-s4e9/description.md
|
||||
:linenos:
|
||||
|
||||
- Create a ``ds_data/eval/playground-series-s4e9/valid.py`` file, which is used to check the validity of the submission files to ensure that their formatting is consistent with the reference file.
|
||||
|
||||
- The following shows a script that checks the validity of a submission based on the ``playground-series-s4e9`` data.
|
||||
|
||||
.. literalinclude:: ../../rdagent/scenarios/data_science/example/eval/playground-series-s4e9/valid.py
|
||||
:language: markdown
|
||||
:caption: ds_data/eval/playground-series-s4e9/valid.py
|
||||
:linenos:
|
||||
|
||||
- Create a ``ds_data/eval/playground-series-s4e9/grade.py`` file, which is used to calculate the score based on the submission file and the **standard answer file**, and output the result in JSON format.
|
||||
|
||||
- The following shows a grading script based on the ``playground-series-s4e9`` data implementation.
|
||||
|
||||
.. literalinclude:: ../../rdagent/scenarios/data_science/example/eval/playground-series-s4e9/grade.py
|
||||
:language: markdown
|
||||
:caption: ds_data/eval/playground-series-s4e9/grade.py
|
||||
:linenos:
|
||||
|
||||
- In this example we don't create a ``ds_data/eval/playground-series-s4e9/sample.py``, we use the sample method provided by RD-Agent by default.
|
||||
|
||||
- At this point, you have created a complete dataset. The correct structure of the dataset should look like this.
|
||||
|
||||
.. code-block:: text
|
||||
|
||||
ds_data
|
||||
├── playground-series-s4e9
|
||||
│ ├── train.csv
|
||||
│ ├── test.csv
|
||||
│ ├── description.md
|
||||
│ └── sample_submission.csv
|
||||
├── eval
|
||||
│ └── playground-series-s4e9
|
||||
│ ├── grade.py
|
||||
│ ├── submission_test.csv
|
||||
│ └── valid.py
|
||||
└── source_data
|
||||
└── playground-series-s4e9
|
||||
├── prepare.py
|
||||
├── sample_submission.csv
|
||||
├── test.csv
|
||||
└── train.csv
|
||||
|
||||
- We have prepared a dataset based on the above description for your reference. You can download it with the following command.
|
||||
- In addition to auto-downloading the benchmark data, you must also configure the runtime environment for executing the competition code.
|
||||
- Use the environment variable ``DS_CODER_COSTEER_ENV_TYPE`` to select the execution mode:
|
||||
|
||||
• When set to docker (the default), RD-Agent utilizes the official Kaggle Docker image (``gcr.io/kaggle-gpu-images/python:latest``) to ensure that all required packages are available.
|
||||
• If you prefer to use a custom Docker setup, you can modify the configuration using ``DS_DOCKER_IMAGE`` or ``DS_DOCKERFILE_FOLDER_PATH``.
|
||||
• Alternatively, if your competition work only demands basic libraries, you may set ``DS_CODER_COSTEER_ENV_TYPE`` to conda. In this mode, you must create a local conda environment named “kaggle” and pre-install the necessary packages. RD-Agent will execute the competition code within this “kaggle” conda environment.
|
||||
|
||||
.. code-block:: sh
|
||||
|
||||
wget https://github.com/SunsetWolf/rdagent_resource/releases/download/ds_data/playground-series-s4e9.zip
|
||||
# Configure the runtime environment: choice between 'docker' (default) or 'conda'
|
||||
dotenv set DS_CODER_COSTEER_ENV_TYPE docker
|
||||
|
||||
- Next, we need to configure the environment for the ``playground-series-s4e9`` contest. You can do this by executing the following command at the command line.
|
||||
|
||||
.. code-block:: sh
|
||||
|
||||
dotenv set DS_IF_USING_MLE_DATA False
|
||||
dotenv set DS_SAMPLE_DATA_BY_LLM False
|
||||
dotenv set DS_SCEN rdagent.scenarios.data_science.scen.KaggleScen
|
||||
|
||||
🚀 **Run the Application**
|
||||
""""""""""""""""""""""""""""""""""""
|
||||
|
||||
- 🌏 You can directly run the application by using the following command:
|
||||
- 🚀 **Run the Application**
|
||||
|
||||
- You can directly run the application by using the following command:
|
||||
|
||||
.. code-block:: sh
|
||||
|
||||
rdagent data_science --competition <Competition ID>
|
||||
|
||||
- The following shows the command to run based on the ``playground-series-s4e9`` data
|
||||
- 📥 **Visualize the R&D Process**
|
||||
|
||||
.. code-block:: sh
|
||||
|
||||
rdagent data_science --competition playground-series-s4e9
|
||||
|
||||
- More CLI Parameters for `rdagent data_science` command:
|
||||
|
||||
.. automodule:: rdagent.app.data_science.loop
|
||||
:members:
|
||||
:no-index:
|
||||
|
||||
- 📈 Visualize the R&D Process
|
||||
|
||||
- We provide a web UI to visualize the log. You just need to run:
|
||||
|
||||
.. code-block:: sh
|
||||
|
||||
rdagent ui --port <custom port> --log-dir <your log folder like "log/"> --data_science True
|
||||
|
||||
- Then you can input the log path and visualize the R&D process.
|
||||
|
||||
- 🧪 Scoring the test results
|
||||
|
||||
- Finally, shutdown the program, and get the test set scores with this command.
|
||||
- We provide a web UI to visualize the log. You just need to run:
|
||||
|
||||
.. code-block:: sh
|
||||
|
||||
dotenv run -- python rdagent/log/mle_summary.py grade <url_to_log>
|
||||
streamlit run rdagent/log/ui/dsapp.py
|
||||
|
||||
- If you have configured the full output in ``ds_data/eval/playground-series-s4e9/grade.py``, or if you are running a competition that receives **MLE-Bench** support, you can also summarize the scores by running the following command.
|
||||
- Then you can input the log path and visualize the R&D process.
|
||||
|
||||
- **Additional Guidance**
|
||||
|
||||
- **Combine different LLM Models at R&D Stage**
|
||||
|
||||
- You can combine different LLM models at the R&D stage.
|
||||
|
||||
- By default, when you set environment variable ``CHAT_MODEL``, it covers both R&D stages. When customizing the model for the development stage, you can set:
|
||||
|
||||
.. code-block:: sh
|
||||
|
||||
rdagent grade_summary --log-folder=<url_to_log>
|
||||
# This example sets the model to "o3-mini". For some models, the reasoning effort shoule be set to "None".
|
||||
dotenv set LITELLM_CHAT_MODEL_MAP '{"coding":{"model":"o3-mini","reasoning_effort":"high"},"running":{"model":"o3-mini","reasoning_effort":"high"}}'
|
||||
|
||||
|
||||
|
||||
|
||||
Here, <url_to_log> refers to the parent directory of the log folder generated during the run.
|
||||
|
||||
@@ -1,163 +0,0 @@
|
||||
.. _finetune_agent:
|
||||
|
||||
=============================
|
||||
Fine-tuning an Existing Model
|
||||
=============================
|
||||
|
||||
## **🎯 Scenario: Continue Training on a Pre-trained Model**
|
||||
|
||||
In this workflow the **Data Science Agent** starts from a *previously trained* model (and its training script), performs additional fine-tuning on new data, and then re-uses the updated weights for subsequent inference runs.
|
||||
|
||||
🚧 Directory Structure
|
||||
|
||||
Your competition folder (here called ``custom_data``) must contain **one extra sub-directory** named ``prev_model`` where you keep the old weights and the code that produced them:
|
||||
|
||||
.. code-block:: text
|
||||
|
||||
ds_data
|
||||
└── custom_data
|
||||
├── train.csv
|
||||
├── test.csv
|
||||
├── sample_submission.csv # optional
|
||||
├── description.md # optional
|
||||
├── sample.py # optional
|
||||
└── prev_model # ← NEW
|
||||
├── models/ # previous checkpoints (e.g. *.bin, *.pt, *.ckpt)
|
||||
└── main.py # training/inference scripts you used before
|
||||
|
||||
If your competition provides custom grading/validation scripts, keep them under ``ds_data/eval/custom_data`` exactly as before.
|
||||
|
||||
🔧 Environment Setup
|
||||
~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Add or update the following variables in **.env** (examples shown):
|
||||
|
||||
.. code-block:: sh
|
||||
|
||||
# required for all Data-Science runs
|
||||
dotenv set DS_LOCAL_DATA_PATH <your local path>/ds_data
|
||||
|
||||
# optional: choose docker / conda, etc.
|
||||
dotenv set DS_CODER_COSTEER_ENV_TYPE docker
|
||||
|
||||
🚀 How It Works at Runtime
|
||||
|
||||
1. **First run**
|
||||
|
||||
* `rdagent` detects `prev_model/models`.
|
||||
* It loads the latest checkpoint and prepare the fine-tuning based on code found under `prev_model/*.py` (or your own pipeline if you override it).
|
||||
* Fine-tuned weights are written to `./workspace_input/models`.
|
||||
|
||||
2. **Subsequent runs**
|
||||
|
||||
* When you execute `python ./workspace_input/main.py`, the script first looks for a checkpoint in `./workspace_input/models`.
|
||||
* If found, it **skips fine-tuning** and goes straight to prediction / submission generation.
|
||||
|
||||
⏰ Managing Timeouts
|
||||
|
||||
|
||||
By default:
|
||||
|
||||
* **Debug loop**: 1 hour (``DS_DEBUG_TIMEOUT=3600`` seconds)
|
||||
* **Full run** : 3 hours (``DS_FULL_TIMEOUT=10800`` seconds)
|
||||
|
||||
Override either value in **.env**:
|
||||
|
||||
.. code-block:: sh
|
||||
|
||||
# give the debug loop 45 min and the full loop 6 h
|
||||
dotenv set DS_DEBUG_TIMEOUT 2700
|
||||
dotenv set DS_FULL_TIMEOUT 21600
|
||||
|
||||
- 🚀 **Run the Application**
|
||||
|
||||
- You can directly run the application by using the following command:
|
||||
|
||||
.. code-block:: sh
|
||||
|
||||
dotenv run -- python rdagent/app/finetune/data_science/loop.py --competition <Competition ID>
|
||||
|
||||
- Then, you can run the test set score corresponding to each round of the loop.
|
||||
|
||||
.. code-block:: sh
|
||||
|
||||
dotenv run -- python rdagent/log/mle_summary.py grade <url_to_log>
|
||||
|
||||
Here, <url_to_log> refers to the parent directory of the log folder generated during the run.
|
||||
|
||||
- 📥 **Visualize the R&D Process**
|
||||
|
||||
- We provide a web UI to visualize the log. You just need to run:
|
||||
|
||||
.. code-block:: sh
|
||||
|
||||
streamlit run rdagent/log/ui/dsapp.py
|
||||
|
||||
- Then you can input the log path and visualize the R&D process.
|
||||
|
||||
🔍 MLE-bench Guide: Running ML Engineering via MLE-bench
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
- 📝 **MLE-bench Overview**
|
||||
|
||||
- MLE-bench is a comprehensive benchmark designed to evaluate the ML engineering capabilities of AI systems using real-world scenarios. The dataset comprises 75 Kaggle competitions. Since Kaggle does not provide held-out test sets for these competitions, the benchmark includes preparation scripts that split the publicly available training data into new training and test sets, and grading scripts are provided for each competition to accurately evaluate submission scores.
|
||||
|
||||
- 🔧 **Set up Environment for MLE-bench**
|
||||
|
||||
- Running R&D-Agent on MLE-bench is designed for full automation. There is no need for manual downloads and data preparation. Simply set the environment variable ``DS_IF_USING_MLE_DATA`` to True.
|
||||
|
||||
- At runtime, R&D-Agent will automatically build the Docker image specified at ``rdagent/scenarios/kaggle/docker/mle_bench_docker/Dockerfile``. This image is responsible for downloading the required datasets and grading files for MLE-bench.
|
||||
|
||||
- Note: The first run may take longer than subsequent runs as the Docker image and data are being downloaded and set up for the first time.
|
||||
|
||||
.. code-block:: sh
|
||||
|
||||
dotenv set DS_LOCAL_DATA_PATH <your local directory>/ds_data
|
||||
dotenv set DS_IF_USING_MLE_DATA True
|
||||
|
||||
- 🔨 **Configuring the Kaggle API**
|
||||
|
||||
- Downloading Kaggle competition data requires the Kaggle API. You can set up the Kaggle API by following these steps:
|
||||
|
||||
- Register and login on the `Kaggle <https://www.kaggle.com/>`_ website.
|
||||
|
||||
- Click on the avatar (usually in the top right corner of the page) -> ``Settings`` -> ``Create New Token``, A file called ``kaggle.json`` will be downloaded.
|
||||
|
||||
- Move ``kaggle.json`` to ``~/.config/kaggle/``
|
||||
|
||||
- Modify the permissions of the ``kaggle.json`` file.
|
||||
|
||||
.. code-block:: sh
|
||||
|
||||
chmod 600 ~/.config/kaggle/kaggle.json
|
||||
|
||||
- For more information about Kaggle API Settings, refer to the `Kaggle API <https://github.com/Kaggle/kaggle-api>`_.
|
||||
|
||||
|
||||
- 🔩 **Setting the Environment Variables for MLE-bench**
|
||||
|
||||
- In addition to auto-downloading the benchmark data, you must also configure the runtime environment for executing the competition code.
|
||||
- Use the environment variable ``DS_CODER_COSTEER_ENV_TYPE`` to select the execution mode:
|
||||
|
||||
• When set to docker (the default), RD-Agent utilizes the official Kaggle Docker image (``gcr.io/kaggle-gpu-images/python:latest``) to ensure that all required packages are available.
|
||||
• If you prefer to use a custom Docker setup, you can modify the configuration using ``DS_DOCKER_IMAGE`` or ``DS_DOCKERFILE_FOLDER_PATH``.
|
||||
• Alternatively, if your competition work only demands basic libraries, you may set ``DS_CODER_COSTEER_ENV_TYPE`` to conda. In this mode, you must create a local conda environment named “kaggle” and pre-install the necessary packages. RD-Agent will execute the competition code within this “kaggle” conda environment.
|
||||
|
||||
.. code-block:: sh
|
||||
|
||||
# Configure the runtime environment: choice between 'docker' (default) or 'conda'
|
||||
dotenv set DS_CODER_COSTEER_ENV_TYPE docker
|
||||
|
||||
- **Additional Guidance**
|
||||
|
||||
- **Combine different LLM Models at R&D Stage**
|
||||
|
||||
- You can combine different LLM models at the R&D stage.
|
||||
|
||||
- By default, when you set environment variable ``CHAT_MODEL``, it covers both R&D stages. When customizing the model for the development stage, you can set:
|
||||
|
||||
.. code-block:: sh
|
||||
|
||||
# This example sets the model to "o3-mini". For some models, the reasoning effort shoule be set to "None".
|
||||
dotenv set LITELLM_CHAT_MODEL_MAP '{"coding":{"model":"o3-mini","reasoning_effort":"high"},"running":{"model":"o3-mini","reasoning_effort":"high"}}'
|
||||
|
||||
@@ -96,4 +96,4 @@ You can try our demo by running the following command:
|
||||
|
||||
.. code-block:: sh
|
||||
|
||||
rdagent general_model --report-file-path=<path_to_pdf_file>
|
||||
rdagent general_model --report_file_path=<path_to_pdf_file>
|
||||
|
||||
@@ -1,264 +0,0 @@
|
||||
# Security Runbook für NexQuant
|
||||
|
||||
## Bandit Security Scanner
|
||||
|
||||
### Konfiguration
|
||||
|
||||
Bandit ist als Pre-Commit Hook konfiguriert und scannt automatisch alle Python-Dateien vor jedem Commit.
|
||||
|
||||
**Konfigurationsdateien:**
|
||||
- `.bandit.yml` - Bandit-Einstellungen
|
||||
- `.pre-commit-config.yaml` - Pre-commit Hooks
|
||||
- `requirements/lint.txt` - Bandit Dependency
|
||||
|
||||
### Scan-Befehle
|
||||
|
||||
```bash
|
||||
# Alle Dateien scannen
|
||||
bandit -r rdagent/ -c .bandit.yml
|
||||
|
||||
# Nur HIGH Severity Issues
|
||||
bandit -r rdagent/ -c .bandit.yml --severity-level high
|
||||
|
||||
# Spezifische Datei scannen
|
||||
bandit rdagent/components/backtesting/results_db.py -c .bandit.yml
|
||||
|
||||
# Mit JSON Output (für CI/CD)
|
||||
bandit -r rdagent/ -c .bandit.yml -f json -o results/security/bandit-report.json
|
||||
```
|
||||
|
||||
### Gefundene HIGH Severity Issues
|
||||
|
||||
#### 1. subprocess mit shell=True (12 Issues)
|
||||
|
||||
**Dateien:**
|
||||
- `rdagent/utils/env.py` (mehrere Stellen)
|
||||
- `rdagent/components/coder/factor_coder/factor.py`
|
||||
|
||||
**Bewertung:** ✅ **Akzeptiert** - Internal Tool
|
||||
- Alle Commands verwenden hardcodierte Strings, keine User-Inputs
|
||||
- Risk: Command Injection bei manipulierten Inputs
|
||||
- Mitigation: Code-Review für alle subprocess-Aufrufe, keine externen Inputs
|
||||
|
||||
**Empfohlene Fixes (Future PR):**
|
||||
```python
|
||||
# Statt:
|
||||
subprocess.run(f"conda env list | grep -q '^{env_name} '", shell=True)
|
||||
|
||||
# Besser:
|
||||
subprocess.run(["conda", "env", "list"], capture_output=True, text=True, check=True)
|
||||
# Dann in Python auf env_name prüfen
|
||||
```
|
||||
|
||||
**Priority:** MEDIUM - Refactor in nächster Wartungsphase
|
||||
|
||||
---
|
||||
|
||||
#### 2. Jinja2 autoescape=False (6 Issues)
|
||||
|
||||
**Dateien:**
|
||||
- `rdagent/components/coder/data_science/ensemble/__init__.py`
|
||||
- `rdagent/components/coder/data_science/ensemble/eval.py`
|
||||
- `rdagent/scenarios/kaggle/developer/coder.py` (2x)
|
||||
- `rdagent/scenarios/qlib/experiment/utils.py`
|
||||
- `rdagent/utils/agent/tpl.py`
|
||||
|
||||
**Bewertung:** ✅ **Akzeptiert** - Template Generation für Code
|
||||
- Templates generieren Python-Code, nicht HTML
|
||||
- XSS-Risiko besteht nicht bei Code-Templates
|
||||
- `StrictUndefined` verhindert undefined variable leaks
|
||||
|
||||
**Mitigation:** ✅ Already secure durch `StrictUndefined`
|
||||
|
||||
---
|
||||
|
||||
#### 3. MD5 Hash (2 Issues)
|
||||
|
||||
**Dateien:**
|
||||
- `rdagent/log/ui/ds_trace.py` (2x)
|
||||
|
||||
**Bewertung:** ✅ **Akzeptiert** - Non-Crypto Use Case
|
||||
- MD5 wird für UI-Caching verwendet, nicht für Security
|
||||
- `usedforsecurity=False` kann hinzugefügt werden
|
||||
|
||||
**Empfohlener Fix (Quick Win):**
|
||||
```python
|
||||
# Zeile 226 & 333 in rdagent/log/ui/ds_trace.py
|
||||
unique_key = hashlib.md5("...".encode(), usedforsecurity=False).hexdigest()
|
||||
```
|
||||
|
||||
**Priority:** LOW - 5 Minuten Fix
|
||||
|
||||
---
|
||||
|
||||
#### 4. tarfile.extractall ohne Validation (2 Issues)
|
||||
|
||||
**Dateien:**
|
||||
- `rdagent/scenarios/data_science/proposal/exp_gen/select/submit.py`
|
||||
- `rdagent/scenarios/kaggle/kaggle_crawler.py`
|
||||
|
||||
**Bewertung:** ⚠️ **Sollte gefixt werden** - Path Traversal Risk
|
||||
- Extrahiert externe Archive (Kaggle Datasets)
|
||||
- Risk: Path Traversal Attacks via `../../../etc/passwd`
|
||||
|
||||
**Empfohlener Fix:**
|
||||
```python
|
||||
import tarfile
|
||||
import os
|
||||
|
||||
def safe_extractall(tar: tarfile.TarFile, path: str) -> None:
|
||||
"""Extract tarfile safely, preventing path traversal."""
|
||||
def is_within_directory(directory: str, target: str) -> bool:
|
||||
abs_directory = os.path.abspath(directory)
|
||||
abs_target = os.path.abspath(target)
|
||||
prefix = os.path.commonprefix([abs_directory, abs_target])
|
||||
return prefix == abs_directory
|
||||
|
||||
for member in tar.getmembers():
|
||||
member_path = os.path.join(path, member.name)
|
||||
if not is_within_directory(path, member_path):
|
||||
raise ValueError(f"Attempted Path Traversal: {member.name}")
|
||||
tar.extractall(path=path)
|
||||
|
||||
# Usage:
|
||||
with tarfile.open(tar_path, mode="r:*") as tar:
|
||||
safe_extractall(tar, to_dir)
|
||||
```
|
||||
|
||||
**Priority:** HIGH - Nächster Sprint
|
||||
|
||||
---
|
||||
|
||||
#### 5. Flask debug=True (1 Issue)
|
||||
|
||||
**Datei:**
|
||||
- `rdagent/log/server/debug_app.py:170`
|
||||
|
||||
**Bewertung:** ⚠️ **Sollte gefixt werden** - Debugger Exposure
|
||||
- `debug=True` ermöglicht arbitrary code execution
|
||||
- Sollte nur in Development-Umgebung sein
|
||||
|
||||
**Empfohlener Fix:**
|
||||
```python
|
||||
import os
|
||||
|
||||
# Zeile 170
|
||||
debug_mode = os.getenv("FLASK_ENV") == "development"
|
||||
app.run(debug=debug_mode, host="0.0.0.0", port=port)
|
||||
```
|
||||
|
||||
**Priority:** HIGH - Quick Fix
|
||||
|
||||
---
|
||||
|
||||
### Skipped Rules Begründung
|
||||
|
||||
| Rule | Begründung | Status |
|
||||
|------|-----------|--------|
|
||||
| B101 (assert) | Development/Debug Assertions | ✅ Akzeptiert |
|
||||
| B311 (random) | Non-Crypto Random Usage | ✅ Akzeptiert |
|
||||
| B404, B603, B607 (subprocess) | Legitimate System Operations | ⚠️ Monitor |
|
||||
| B113 (request timeout) | Wird in future PR gefixt | 📋 Planned |
|
||||
| B608 (SQL injection) | Internal Tool, keine User-Inputs | ⚠️ Monitor |
|
||||
| B301 (pickle) | Controlled Data Sources | ⚠️ Monitor |
|
||||
| B701 (jinja2) | Code Templates, nicht HTML | ✅ Secure |
|
||||
| B201 (flask debug) | Development Only | 📋 Fix Planned |
|
||||
| B324 (hashlib) | Non-Crypto (Caching) | 📋 Quick Fix |
|
||||
| B202 (tarfile) | External Archives | 🔴 Fix Required |
|
||||
|
||||
---
|
||||
|
||||
### Pre-Commit Verhalten
|
||||
|
||||
**Blockiert Commit bei:**
|
||||
- HIGH Severity Issues (standardmäßig aktiv)
|
||||
|
||||
**Erlaubt Commit bei:**
|
||||
- MEDIUM Severity Issues (Informational)
|
||||
- LOW Severity Issues (Informational)
|
||||
|
||||
**Manuelles Überspringen (NOT recommended):**
|
||||
```bash
|
||||
# Nur im Notfall!
|
||||
git commit --no-verify -m "feat: urgent fix"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### CI/CD Integration
|
||||
|
||||
Für GitHub Actions:
|
||||
|
||||
```yaml
|
||||
# .github/workflows/security.yml
|
||||
name: Security Scan
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [master, main]
|
||||
pull_request:
|
||||
branches: [master, main]
|
||||
|
||||
jobs:
|
||||
bandit:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: '3.10'
|
||||
|
||||
- name: Install dependencies
|
||||
run: pip install bandit
|
||||
|
||||
- name: Run Bandit
|
||||
run: |
|
||||
bandit -r rdagent/ \
|
||||
-c .bandit.yml \
|
||||
-f json \
|
||||
-o bandit-report.json \
|
||||
--exit-zero
|
||||
|
||||
- name: Upload Security Report
|
||||
uses: github/codeql-action/upload-sarif@v3
|
||||
if: always()
|
||||
with:
|
||||
sarif_file: bandit-report.json
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Regelmäßige Wartung
|
||||
|
||||
**Monatlich:**
|
||||
```bash
|
||||
# Bandit-Report generieren
|
||||
bandit -r rdagent/ -c .bandit.yml -f html -o results/security/bandit-report-$(date +%Y-%m).html
|
||||
|
||||
# Trend-Analyse
|
||||
bandit -r rdagent/ -c .bandit.yml -lll | grep "Total issues"
|
||||
```
|
||||
|
||||
**Quartalsweise:**
|
||||
- Alle `# nosec` Comments reviewen
|
||||
- Skipped Rules reevaluieren
|
||||
- Neue Security-Best-Practices einarbeiten
|
||||
|
||||
---
|
||||
|
||||
### Kontakt & Eskalation
|
||||
|
||||
- **Security Issues melden:** @TPTBusiness
|
||||
- **False Positives:** Zu `.bandit.yml` hinzufügen mit Begründung
|
||||
- **Patches:** PR mit Label `security` erstellen
|
||||
|
||||
---
|
||||
|
||||
### Referenzen
|
||||
|
||||
- [Bandit Documentation](https://bandit.readthedocs.io/)
|
||||
- [OWASP Top 10](https://owasp.org/www-project-top-ten/)
|
||||
- [CWE Database](https://cwe.mitre.org/)
|
||||
- [Pre-Commit Hooks](https://pre-commit.com/)
|
||||
+1
-1
@@ -18,7 +18,7 @@ In `RD-Agent/` folder, run:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
rdagent ui --port <port> --log-dir <log_dir like "log/"> [--debug]
|
||||
rdagent ui --port <port> --log_dir <log_dir like "log/"> [--debug]
|
||||
|
||||
This will start a web app on `http://localhost:<port>`.
|
||||
|
||||
|
||||
@@ -1,188 +0,0 @@
|
||||
#!/usr/bin/env python
|
||||
"""
|
||||
Beispiel 01: Factor Discovery - Automatische Faktor-Generierung
|
||||
|
||||
Was macht dieses Beispiel?
|
||||
Dieses Skript demonstriert die automatische Generierung neuer Trading-Faktoren
|
||||
mittels LLM (Large Language Model). Es führt den CoSTEER-Loop aus, der:
|
||||
1. Faktor-Hypothesen generiert
|
||||
2. Implementiert und backtestet
|
||||
3. Feedback für Verbesserungen gibt
|
||||
|
||||
Voraussetzungen:
|
||||
- PREDIX installiert (`pip install -e ".[all]"`)
|
||||
- EURUSD 1-Minute Daten in Qlib geladen
|
||||
- LLM-Server läuft (für --llm local) ODER API-Key gesetzt
|
||||
|
||||
Erwartete Laufzeit:
|
||||
~10-15 Minuten pro Loop (local LLM)
|
||||
~30-60 Minuten pro Loop (API LLM)
|
||||
|
||||
Output:
|
||||
- Generierte Faktoren in RD-Agent_workspace/
|
||||
- Performance-Metriken (ARR, Sharpe, IC, MaxDD)
|
||||
- Faktor-Implementierungen als Python-Code
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import logging
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
# Logging konfigurieren
|
||||
logging.basicConfig(
|
||||
level=logging.INFO,
|
||||
format='%(asctime)s | %(levelname)-8s | %(message)s',
|
||||
datefmt='%Y-%m-%d %H:%M:%S'
|
||||
)
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def run_factor_discovery(loop_n: int, llm_model: str, skip_checkout: bool = False) -> None:
|
||||
"""
|
||||
Führt die Faktor-Generierung aus.
|
||||
|
||||
Args:
|
||||
loop_n: Anzahl der Evolutions-Loops (default: 3)
|
||||
llm_model: LLM-Modell ('local', 'openai', 'anthropic')
|
||||
skip_checkout: Git checkout überspringen (für Testing)
|
||||
"""
|
||||
logger.info("=" * 60)
|
||||
logger.info("PREDIX Factor Discovery - Beispiel 01")
|
||||
logger.info("=" * 60)
|
||||
logger.info(f"Loops: {loop_n}")
|
||||
logger.info(f"LLM Model: {llm_model}")
|
||||
logger.info(f"Skip Checkout: {skip_checkout}")
|
||||
logger.info("=" * 60)
|
||||
|
||||
# Versuche rdagent zu importieren
|
||||
try:
|
||||
from rdagent.app import fin_quant
|
||||
from rdagent.scenarios.qlib.factor_experiment import factor_experiment
|
||||
except ImportError as e:
|
||||
logger.error(f"Konnte rdagent nicht importieren: {e}")
|
||||
logger.error("Bitte installiere PREDIX: pip install -e \".[all]\"")
|
||||
sys.exit(1)
|
||||
|
||||
# Parameter konfigurieren
|
||||
logger.info("Konfiguriere Experiment...")
|
||||
|
||||
# In der Realität würde hier das rdagent CLI aufgerufen werden:
|
||||
# rdagent fin_quant --loop-n {loop_n} --model {llm_model}
|
||||
|
||||
# Für dieses Beispiel simulieren wir den Ablauf:
|
||||
logger.info("Starte Faktor-Generierung...")
|
||||
logger.info("Dieser Schritt würde in der Produktion den LLM-gesteuerten")
|
||||
logger.info("CoSTEER-Loop ausführen, der neue Faktoren generiert.")
|
||||
|
||||
# Beispiel-Output (simuliert)
|
||||
logger.info("-" * 60)
|
||||
logger.info("SIMULIERTER OUTPUT (echter Lauf würde LLM verwenden):")
|
||||
logger.info("-" * 60)
|
||||
|
||||
example_factors = [
|
||||
{
|
||||
"name": "london_momentum_open_16",
|
||||
"hypothesis": "Long EURUSD wenn erste 16 Bars der London-Session positiven Return zeigen",
|
||||
"arr": "12.4%",
|
||||
"sharpe": 2.1,
|
||||
"ic": 0.087,
|
||||
"max_dd": "8.3%",
|
||||
"trades_per_day": "8-12"
|
||||
},
|
||||
{
|
||||
"name": "hl_range_mean_reversion",
|
||||
"hypothesis": "Short EURUSD wenn High-Low-Range über 2x Durchschnitt expandiert",
|
||||
"arr": "9.8%",
|
||||
"sharpe": 1.7,
|
||||
"ic": -0.065,
|
||||
"max_dd": "11.2%",
|
||||
"trades_per_day": "6-10"
|
||||
},
|
||||
{
|
||||
"name": "session_volatility_ratio",
|
||||
"hypothesis": "Long EURUSD wenn aktuelle Vol unter Durchschnitt (calm before trend)",
|
||||
"arr": "11.2%",
|
||||
"sharpe": 1.9,
|
||||
"ic": 0.072,
|
||||
"max_dd": "9.1%",
|
||||
"trades_per_day": "10-14"
|
||||
}
|
||||
]
|
||||
|
||||
for i, factor in enumerate(example_factors, 1):
|
||||
logger.info(f"\nFaktor {i}: {factor['name']}")
|
||||
logger.info(f" Hypothese: {factor['hypothesis']}")
|
||||
logger.info(f" ARR: {factor['arr']}")
|
||||
logger.info(f" Sharpe: {factor['sharpe']}")
|
||||
logger.info(f" IC: {factor['ic']}")
|
||||
logger.info(f" Max DD: {factor['max_dd']}")
|
||||
logger.info(f" Trades/Tag: {factor['trades_per_day']}")
|
||||
|
||||
logger.info("-" * 60)
|
||||
logger.info(f"Fertig! {len(example_factors)} Faktoren generiert.")
|
||||
logger.info(f"Ergebnisse gespeichert in: RD-Agent_workspace/")
|
||||
logger.info("-" * 60)
|
||||
|
||||
# Nächste Schritte
|
||||
logger.info("\nNächste Schritte:")
|
||||
logger.info(" 1. Faktoren begutachten: ls RD-Agent_workspace/")
|
||||
logger.info(" 2. Faktoren optimieren: python examples/02_factor_evolution.py")
|
||||
logger.info(" 3. Strategie bauen: python examples/03_strategy_generation.py")
|
||||
|
||||
|
||||
def main():
|
||||
"""Hauptfunktion mit Argument-Parsing."""
|
||||
parser = argparse.ArgumentParser(
|
||||
description="Beispiel 01: Automatische Faktor-Generierung mit LLM",
|
||||
formatter_class=argparse.RawDescriptionHelpFormatter,
|
||||
epilog="""
|
||||
Beispiele:
|
||||
# 3 Loops mit lokalem LLM
|
||||
python 01_factor_discovery.py --loop-n 3 --llm local
|
||||
|
||||
# 10 Loops mit OpenAI API
|
||||
python 01_factor_discovery.py --loop-n 10 --llm openai
|
||||
|
||||
# Testing ohne Git-Checkout
|
||||
python 01_factor_discovery.py --loop-n 1 --skip-checkout
|
||||
"""
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
"--loop-n",
|
||||
type=int,
|
||||
default=3,
|
||||
help="Anzahl der Evolutions-Loops (default: 3)"
|
||||
)
|
||||
parser.add_argument(
|
||||
"--llm",
|
||||
type=str,
|
||||
choices=["local", "openai", "anthropic"],
|
||||
default="local",
|
||||
help="LLM-Modell für Generierung (default: local)"
|
||||
)
|
||||
parser.add_argument(
|
||||
"--skip-checkout",
|
||||
action="store_true",
|
||||
help="Git checkout überspringen (für Testing)"
|
||||
)
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
try:
|
||||
run_factor_discovery(
|
||||
loop_n=args.loop_n,
|
||||
llm_model=args.llm,
|
||||
skip_checkout=args.skip_checkout
|
||||
)
|
||||
except KeyboardInterrupt:
|
||||
logger.warning("\nAbgebrochen durch Benutzer.")
|
||||
sys.exit(130)
|
||||
except Exception as e:
|
||||
logger.error(f"Fehler bei der Faktor-Generierung: {e}")
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -1,254 +0,0 @@
|
||||
#!/usr/bin/env python
|
||||
"""
|
||||
Beispiel 02: Factor Evolution - Bestehende Faktoren optimieren
|
||||
|
||||
Was macht dieses Beispiel?
|
||||
Dieses Skript zeigt, wie man bestehende Trading-Faktoren durch Hinzufügen
|
||||
von Session-Filtern, Regime-Filtern und anderen Techniken verbessert.
|
||||
|
||||
Verbesserungstechniken:
|
||||
1. Session-Filter (London/NY nur) - 73% Erfolgsrate
|
||||
2. Regime-Filter (ADX-basiert) - 65% Erfolgsrate
|
||||
3. Lookback-Optimierung - 58% Erfolgsrate
|
||||
4. Kombination mit komplementären Faktoren - 69% Erfolgsrate
|
||||
|
||||
Voraussetzungen:
|
||||
- Mindestens ein generierter Faktor vorhanden (aus Beispiel 01)
|
||||
- EURUSD 1-Minute Daten in Qlib geladen
|
||||
|
||||
Erwartete Laufzeit:
|
||||
~15-20 Minuten pro Faktor
|
||||
|
||||
Output:
|
||||
- Optimierte Faktoren mit Before/After-Vergleich
|
||||
- Metrik-Verbesserungen (ARR +X%, Sharpe +X.X)
|
||||
- Implementierter Code für optimierte Faktoren
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import logging
|
||||
import sys
|
||||
|
||||
logging.basicConfig(
|
||||
level=logging.INFO,
|
||||
format='%(asctime)s | %(levelname)-8s | %(message)s',
|
||||
datefmt='%Y-%m-%d %H:%M:%S'
|
||||
)
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
# Beispiel-Faktor (wie aus Beispiel 01 generiert)
|
||||
EXAMPLE_FACTOR = {
|
||||
"name": "momentum_16",
|
||||
"code": """
|
||||
def calculate_momentum_16():
|
||||
df = pd.read_hdf("intraday_pv.h5", key="data")
|
||||
close = df['$close'].unstack(level='instrument')
|
||||
momentum = close.pct_change(16)
|
||||
result = momentum.stack(level='instrument')
|
||||
factor_df = pd.DataFrame({'momentum_16': result}, index=df.index)
|
||||
factor_df.to_hdf("result.h5", key="data", mode="w")
|
||||
""",
|
||||
"metrics": {
|
||||
"arr": "8.2%",
|
||||
"sharpe": 1.3,
|
||||
"ic": 0.054,
|
||||
"max_dd": "12.4%",
|
||||
"trades_per_day": 14,
|
||||
"win_rate": "52%"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
def improve_with_session_filter(factor: dict) -> dict:
|
||||
"""
|
||||
Verbesserung: Session-Filter hinzufügen.
|
||||
|
||||
Erfolgsrate: 73% (aus 11 getesteten Faktoren)
|
||||
Durchschnittliche Verbesserung:
|
||||
ARR: +2.8%
|
||||
Sharpe: +0.31
|
||||
Max-DD: -3.2%
|
||||
"""
|
||||
improved = factor.copy()
|
||||
improved["improvement_type"] = "session_filter"
|
||||
improved["improvement_desc"] = "London-Session-Filter hinzugefügt (08:00-16:00 UTC)"
|
||||
improved["improved_code"] = """
|
||||
def calculate_momentum_16_london():
|
||||
df = pd.read_hdf("intraday_pv.h5", key="data")
|
||||
close = df['$close'].unstack(level='instrument')
|
||||
|
||||
# 16-bar momentum
|
||||
momentum = close.pct_change(16)
|
||||
|
||||
# Session-Filter: Nur London-Session (08:00-16:00 UTC)
|
||||
hour = close.index.hour
|
||||
london_mask = (hour >= 8) & (hour < 16)
|
||||
momentum = momentum.where(london_mask, np.nan)
|
||||
|
||||
# Stack back to MultiIndex
|
||||
result = momentum.stack(level='instrument')
|
||||
factor_df = pd.DataFrame({'momentum_16_london': result}, index=df.index)
|
||||
factor_df.to_hdf("result.h5", key="data", mode="w")
|
||||
"""
|
||||
improved["improved_metrics"] = {
|
||||
"arr": "11.0%",
|
||||
"sharpe": 1.6,
|
||||
"ic": 0.071,
|
||||
"max_dd": "9.2%",
|
||||
"trades_per_day": 8,
|
||||
"win_rate": "56%"
|
||||
}
|
||||
return improved
|
||||
|
||||
|
||||
def improve_with_regime_filter(factor: dict) -> dict:
|
||||
"""
|
||||
Verbesserung: Regime-Filter (ADX-basiert) hinzufügen.
|
||||
|
||||
Erfolgsrate: 65% (aus 8 getesteten Faktoren)
|
||||
Durchschnittliche Verbesserung:
|
||||
Sharpe: +0.34
|
||||
"""
|
||||
improved = factor.copy()
|
||||
improved["improvement_type"] = "regime_filter"
|
||||
improved["improvement_desc"] = "ADX-Regime-Filter: Nur trending wenn ADX > 1.2"
|
||||
improved["improved_code"] = """
|
||||
def calculate_momentum_16_adx():
|
||||
df = pd.read_hdf("intraday_pv.h5", key="data")
|
||||
close = df['$close'].unstack(level='instrument')
|
||||
high = df['$high'].unstack(level='instrument')
|
||||
low = df['$low'].unstack(level='instrument')
|
||||
|
||||
# 16-bar momentum
|
||||
momentum = close.pct_change(16)
|
||||
|
||||
# ADX-Proxy: Short-term vs Long-term Volatility Ratio
|
||||
hl_range = (high - low) / close
|
||||
atr_short = hl_range.rolling(14).mean()
|
||||
atr_long = hl_range.rolling(42).mean()
|
||||
adx_proxy = atr_short / (atr_long + 1e-8)
|
||||
|
||||
# Regime-Filter: Nur wenn trending (ADX > 1.2)
|
||||
is_trending = adx_proxy > 1.2
|
||||
momentum = momentum.where(is_trending, np.nan)
|
||||
|
||||
result = momentum.stack(level='instrument')
|
||||
factor_df = pd.DataFrame({'momentum_16_adx': result}, index=df.index)
|
||||
factor_df.to_hdf("result.h5", key="data", mode="w")
|
||||
"""
|
||||
improved["improved_metrics"] = {
|
||||
"arr": "10.5%",
|
||||
"sharpe": 1.7,
|
||||
"ic": 0.068,
|
||||
"max_dd": "8.8%",
|
||||
"trades_per_day": 9,
|
||||
"win_rate": "58%"
|
||||
}
|
||||
return improved
|
||||
|
||||
|
||||
def run_factor_evolution(factor_name: str, improvement_type: str) -> None:
|
||||
"""
|
||||
Führt die Faktor-Optimierung aus.
|
||||
|
||||
Args:
|
||||
factor_name: Name des zu optimierenden Faktors
|
||||
improvement_type: Art der Verbesserung ('session_filter', 'regime_filter', 'both')
|
||||
"""
|
||||
logger.info("=" * 60)
|
||||
logger.info("PREDIX Factor Evolution - Beispiel 02")
|
||||
logger.info("=" * 60)
|
||||
logger.info(f"Faktor: {factor_name}")
|
||||
logger.info(f"Verbesserung: {improvement_type}")
|
||||
logger.info("=" * 60)
|
||||
|
||||
# Zeige Original-Faktor
|
||||
logger.info("\nORIGINAL FAKTOR:")
|
||||
logger.info(f" Name: {EXAMPLE_FACTOR['name']}")
|
||||
logger.info(f" ARR: {EXAMPLE_FACTOR['metrics']['arr']}")
|
||||
logger.info(f" Sharpe: {EXAMPLE_FACTOR['metrics']['sharpe']}")
|
||||
logger.info(f" IC: {EXAMPLE_FACTOR['metrics']['ic']}")
|
||||
logger.info(f" Max DD: {EXAMPLE_FACTOR['metrics']['max_dd']}")
|
||||
|
||||
# Wende Verbesserungen an
|
||||
logger.info("\n" + "-" * 60)
|
||||
logger.info("VERBESSERUNGEN")
|
||||
logger.info("-" * 60)
|
||||
|
||||
if improvement_type in ["session_filter", "both"]:
|
||||
improved_session = improve_with_session_filter(EXAMPLE_FACTOR)
|
||||
logger.info(f"\n✓ Session-Filter angewendet:")
|
||||
logger.info(f" Typ: {improved_session['improvement_desc']}")
|
||||
logger.info(f" ARR: {EXAMPLE_FACTOR['metrics']['arr']} → {improved_session['improved_metrics']['arr']}")
|
||||
logger.info(f" Sharpe: {EXAMPLE_FACTOR['metrics']['sharpe']} → {improved_session['improved_metrics']['sharpe']}")
|
||||
logger.info(f" Max DD: {EXAMPLE_FACTOR['metrics']['max_dd']} → {improved_session['improved_metrics']['max_dd']}")
|
||||
|
||||
if improvement_type in ["regime_filter", "both"]:
|
||||
improved_regime = improve_with_regime_filter(EXAMPLE_FACTOR)
|
||||
logger.info(f"\n✓ Regime-Filter angewendet:")
|
||||
logger.info(f" Typ: {improved_regime['improvement_desc']}")
|
||||
logger.info(f" ARR: {EXAMPLE_FACTOR['metrics']['arr']} → {improved_regime['improved_metrics']['arr']}")
|
||||
logger.info(f" Sharpe: {EXAMPLE_FACTOR['metrics']['sharpe']} → {improved_regime['improved_metrics']['sharpe']}")
|
||||
logger.info(f" Max DD: {EXAMPLE_FACTOR['metrics']['max_dd']} → {improved_regime['improved_metrics']['max_dd']}")
|
||||
|
||||
# Zusammenfassung
|
||||
logger.info("\n" + "=" * 60)
|
||||
logger.info("ZUSAMMENFASSUNG")
|
||||
logger.info("=" * 60)
|
||||
logger.info(f"Beste Verbesserung: {improvement_type}")
|
||||
logger.info(f"Ergebnisse gespeichert in: RD-Agent_workspace/")
|
||||
logger.info("\nNächste Schritte:")
|
||||
logger.info(" 1. Optimierten Faktor begutachten: cat RD-Agent_workspace/evolved_factor.py")
|
||||
logger.info(" 2. Strategie bauen: python examples/03_strategy_generation.py")
|
||||
|
||||
|
||||
def main():
|
||||
"""Hauptfunktion mit Argument-Parsing."""
|
||||
parser = argparse.ArgumentParser(
|
||||
description="Beispiel 02: Faktor-Optimierung mit Filtern",
|
||||
formatter_class=argparse.RawDescriptionHelpFormatter,
|
||||
epilog="""
|
||||
Beispiele:
|
||||
# Session-Filter anwenden
|
||||
python 02_factor_evolution.py --factor momentum_16 --improve session_filter
|
||||
|
||||
# Regime-Filter anwenden
|
||||
python 02_factor_evolution.py --factor momentum_16 --improve regime_filter
|
||||
|
||||
# Beide Filter kombinieren
|
||||
python 02_factor_evolution.py --factor momentum_16 --improve both
|
||||
"""
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
"--factor",
|
||||
type=str,
|
||||
default="momentum_16",
|
||||
help="Name des zu optimierenden Faktors (default: momentum_16)"
|
||||
)
|
||||
parser.add_argument(
|
||||
"--improve",
|
||||
type=str,
|
||||
choices=["session_filter", "regime_filter", "both"],
|
||||
default="both",
|
||||
help="Art der Verbesserung (default: both)"
|
||||
)
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
try:
|
||||
run_factor_evolution(
|
||||
factor_name=args.factor,
|
||||
improvement_type=args.improve
|
||||
)
|
||||
except KeyboardInterrupt:
|
||||
logger.warning("\nAbgebrochen durch Benutzer.")
|
||||
sys.exit(130)
|
||||
except Exception as e:
|
||||
logger.error(f"Fehler bei der Faktor-Evolution: {e}")
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -1,190 +0,0 @@
|
||||
#!/usr/bin/env python
|
||||
"""
|
||||
Beispiel 03: Strategy Generation - Faktoren zu Strategien kombinieren
|
||||
|
||||
Was macht dieses Beispiel?
|
||||
Dieses Skript zeigt, wie man mehrere Trading-Faktoren zu einer robusten
|
||||
Strategie kombiniert. Dabei wird die IC-weighted Combination verwendet,
|
||||
die Faktoren nach ihrer prädiktiven Kraft (Information Coefficient) gewichtet.
|
||||
|
||||
WICHTIG: Faktoren mit negativem IC müssen invertiert werden!
|
||||
|
||||
Voraussetzungen:
|
||||
- Mindestens 2-3 generierte Faktoren (aus Beispiel 01)
|
||||
- Faktoren sollten unkorreliert sein (Korrelation < 0.6)
|
||||
|
||||
Erwartete Laufzeit:
|
||||
~3-5 Minuten
|
||||
|
||||
Output:
|
||||
- IC-weighted Faktor-Kombination
|
||||
- Signal-Verteilung (Long/Short/Neutral)
|
||||
- Composite Signal Code
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import logging
|
||||
import sys
|
||||
|
||||
logging.basicConfig(
|
||||
level=logging.INFO,
|
||||
format='%(asctime)s | %(levelname)-8s | %(message)s',
|
||||
datefmt='%Y-%m-%d %H:%M:%S'
|
||||
)
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def run_strategy_generation(factors: list, use_ai: bool = False) -> None:
|
||||
"""
|
||||
Kombiniert Faktoren zu einer Strategie.
|
||||
|
||||
Args:
|
||||
factors: Liste der Faktor-Namen
|
||||
use_ai: KI-gestützte Strategiegenerierung (StrategyCoSTEER)
|
||||
"""
|
||||
logger.info("=" * 60)
|
||||
logger.info("PREDIX Strategy Generation - Beispiel 03")
|
||||
logger.info("=" * 60)
|
||||
logger.info(f"Faktoren: {', '.join(factors)}")
|
||||
logger.info(f"KI-gestützt: {use_ai}")
|
||||
logger.info("=" * 60)
|
||||
|
||||
# Beispiel-Faktoren mit IC-Werten
|
||||
example_factors_data = {
|
||||
"momentum_16": {
|
||||
"ic": 0.074,
|
||||
"sharpe": 1.6,
|
||||
"arr": "10.2%",
|
||||
"type": "trend_following"
|
||||
},
|
||||
"hl_range_reversal": {
|
||||
"ic": -0.065,
|
||||
"sharpe": 1.4,
|
||||
"arr": "8.5%",
|
||||
"type": "mean_reversion"
|
||||
},
|
||||
"session_alpha": {
|
||||
"ic": 0.082,
|
||||
"sharpe": 1.8,
|
||||
"arr": "11.8%",
|
||||
"type": "session_timing"
|
||||
}
|
||||
}
|
||||
|
||||
# IC-Weights berechnen (negative IC invertieren!)
|
||||
logger.info("\nFAKTOR-ANALYSE:")
|
||||
logger.info("-" * 60)
|
||||
|
||||
total_abs_ic = 0
|
||||
for factor_name in factors:
|
||||
if factor_name in example_factors_data:
|
||||
data = example_factors_data[factor_name]
|
||||
logger.info(f" {factor_name}:")
|
||||
logger.info(f" IC: {data['ic']}")
|
||||
logger.info(f" Typ: {data['type']}")
|
||||
logger.info(f" Sharpe: {data['sharpe']}")
|
||||
total_abs_ic += abs(data['ic'])
|
||||
|
||||
# Normalize weights
|
||||
logger.info("\nIC-WEIGHTED COMBINATION:")
|
||||
logger.info("-" * 60)
|
||||
|
||||
weights = {}
|
||||
for factor_name in factors:
|
||||
if factor_name in example_factors_data:
|
||||
ic = example_factors_data[factor_name]['ic']
|
||||
# Negative IC invertieren
|
||||
weight = ic / total_abs_ic
|
||||
weights[factor_name] = weight
|
||||
logger.info(f" {factor_name}: {weight:.3f} (IC: {ic})")
|
||||
|
||||
# Strategie-Code generieren
|
||||
strategy_code = f"""
|
||||
import pandas as pd
|
||||
import numpy as np
|
||||
|
||||
# UNSTACK für cross-sectionale Operationen
|
||||
factor_matrix = factors.unstack(level='instrument')
|
||||
|
||||
# Rolling Z-Score Normalisierung (Window=20)
|
||||
z = (factor_matrix - factor_matrix.rolling(20).mean()) / (factor_matrix.rolling(20).std() + 1e-8)
|
||||
|
||||
# IC-weighted Combination (negative IC invertiert!)
|
||||
composite = ({weights.get('momentum_16', 0):.3f} * z['momentum_16']
|
||||
{weights.get('hl_range_reversal', 0):+.3f} * z['hl_range_reversal']
|
||||
{weights.get('session_alpha', 0):+.3f} * z['session_alpha'])
|
||||
|
||||
# STACK back zu MultiIndex
|
||||
composite = composite.stack(level='instrument')
|
||||
|
||||
# Signal-Generierung mit Thresholds
|
||||
signal = pd.Series(0, index=factors.index)
|
||||
signal[composite > 0.5] = 1 # LONG
|
||||
signal[composite < -0.5] = -1 # SHORT
|
||||
signal.name = 'signal'
|
||||
"""
|
||||
|
||||
logger.info("\nSTRATEGIE-CODE:")
|
||||
logger.info("-" * 60)
|
||||
logger.info(strategy_code)
|
||||
|
||||
# Erwartete Performance
|
||||
logger.info("\nERWARTETE PERFORMANCE:")
|
||||
logger.info("-" * 60)
|
||||
logger.info(" ARR: 12-15%")
|
||||
logger.info(" Sharpe: 2.0-2.4")
|
||||
logger.info(" Max DD: 7-9%")
|
||||
logger.info(" Trades/Tag: 10-14")
|
||||
logger.info(" Win Rate: 55-58%")
|
||||
|
||||
logger.info("\n" + "=" * 60)
|
||||
logger.info("FERTIG!")
|
||||
logger.info("=" * 60)
|
||||
logger.info("Strategie gespeichert in: RD-Agent_workspace/strategy.py")
|
||||
logger.info("\nNächste Schritte:")
|
||||
logger.info(" 1. Backtest durchführen: python examples/04_backtest_simple.py")
|
||||
logger.info(" 2. Strategie optimieren: rdagent build_strategies_ai")
|
||||
|
||||
|
||||
def main():
|
||||
"""Hauptfunktion mit Argument-Parsing."""
|
||||
parser = argparse.ArgumentParser(
|
||||
description="Beispiel 03: Faktoren zu Strategie kombinieren",
|
||||
formatter_class=argparse.RawDescriptionHelpFormatter,
|
||||
epilog="""
|
||||
Beispiele:
|
||||
# 3 Faktoren kombinieren
|
||||
python 03_strategy_generation.py --factors momentum_16,hl_range_reversal,session_alpha
|
||||
|
||||
# Mit KI-gestützter Generierung
|
||||
python 03_strategy_generation.py --factors momentum_16,session_alpha --ai
|
||||
"""
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
"--factors",
|
||||
type=str,
|
||||
default="momentum_16,hl_range_reversal,session_alpha",
|
||||
help="Kommagetrennte Liste der Faktoren (default: momentum_16,hl_range_reversal,session_alpha)"
|
||||
)
|
||||
parser.add_argument(
|
||||
"--ai",
|
||||
action="store_true",
|
||||
help="KI-gestützte Strategiegenerierung (StrategyCoSTEER)"
|
||||
)
|
||||
|
||||
args = parser.parse_args()
|
||||
factors = [f.strip() for f in args.factors.split(',')]
|
||||
|
||||
try:
|
||||
run_strategy_generation(factors=factors, use_ai=args.ai)
|
||||
except KeyboardInterrupt:
|
||||
logger.warning("\nAbgebrochen durch Benutzer.")
|
||||
sys.exit(130)
|
||||
except Exception as e:
|
||||
logger.error(f"Fehler bei der Strategie-Generierung: {e}")
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -1,280 +0,0 @@
|
||||
#!/usr/bin/env python
|
||||
"""
|
||||
Beispiel 04: Backtest - Trading-Strategie auf historischen Daten testen
|
||||
|
||||
Was macht dieses Beispiel?
|
||||
Dieses Skript führt einen Backtest einer Trading-Strategie auf historischen
|
||||
EUR/USD 1-Minute Daten durch. Es berechnet Key-Metriiken wie ARR, Sharpe,
|
||||
Max Drawdown, Win Rate und zeigt die Equity-Kurve.
|
||||
|
||||
Voraussetzungen:
|
||||
- EURUSD 1-Minute Daten in Qlib geladen
|
||||
- Strategie-File vorhanden (aus Beispiel 03 oder eigenem Code)
|
||||
|
||||
Erwartete Laufzeit:
|
||||
~2-5 Minuten (abhä ngig vom Datenzeitraum)
|
||||
|
||||
Output:
|
||||
- Key-Metriiken: ARR, Sharpe, MaxDD, WinRate, Profit Factor
|
||||
- Trade-Statistik (Anzahl Trades, avg Hold Time)
|
||||
- Equity Curve (optional als Plotly Chart)
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import logging
|
||||
import sys
|
||||
from datetime import datetime
|
||||
|
||||
logging.basicConfig(
|
||||
level=logging.INFO,
|
||||
format='%(asctime)s | %(levelname)-8s | %(message)s',
|
||||
datefmt='%Y-%m-%d %H:%M:%S'
|
||||
)
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def run_backtest(strategy: str, start_date: str, end_date: str, plot: bool = False) -> None:
|
||||
"""
|
||||
Führt den Backtest aus.
|
||||
|
||||
Args:
|
||||
strategy: Strategie-Name ('momentum', 'reversal', 'combined', oder eigener Pfad)
|
||||
start_date: Startdatum (YYYY-MM-DD)
|
||||
end_date: Enddatum (YYYY-MM-DD)
|
||||
plot: Equity Curve als Plotly Chart anzeigen
|
||||
"""
|
||||
logger.info("=" * 60)
|
||||
logger.info("PREDIX Backtest - Beispiel 04")
|
||||
logger.info("=" * 60)
|
||||
logger.info(f"Strategie: {strategy}")
|
||||
logger.info(f"Zeitraum: {start_date} bis {end_date}")
|
||||
logger.info(f"Plot anzeigen: {plot}")
|
||||
logger.info("=" * 60)
|
||||
|
||||
# Simulierter Backtest (in Produktion: Echte Backtest-Engine)
|
||||
logger.info("\nLade Daten...")
|
||||
logger.info(f" Instrument: EURUSD")
|
||||
logger.info(f" Zeitrahmen: 1 Minute")
|
||||
logger.info(f" Von: {start_date}")
|
||||
logger.info(f" Bis: {end_date}")
|
||||
|
||||
logger.info("\nStarte Backtest...")
|
||||
|
||||
# Beispiel-Ergebnisse (simuliert)
|
||||
results = {
|
||||
"momentum": {
|
||||
"arr": "12.4%",
|
||||
"sharpe": 2.1,
|
||||
"max_dd": "8.3%",
|
||||
"win_rate": "56.2%",
|
||||
"profit_factor": 1.8,
|
||||
"total_trades": 4521,
|
||||
"trades_per_day": 12,
|
||||
"avg_hold_time": "24 min",
|
||||
"avg_win": "0.00042",
|
||||
"avg_loss": "-0.00031",
|
||||
"best_trade": "0.00187",
|
||||
"worst_trade": "-0.00142",
|
||||
"consecutive_wins": 12,
|
||||
"consecutive_losses": 5,
|
||||
"calmar_ratio": 1.49,
|
||||
"sortino_ratio": 2.8
|
||||
},
|
||||
"reversal": {
|
||||
"arr": "9.8%",
|
||||
"sharpe": 1.7,
|
||||
"max_dd": "11.2%",
|
||||
"win_rate": "61.3%",
|
||||
"profit_factor": 1.6,
|
||||
"total_trades": 3210,
|
||||
"trades_per_day": 8,
|
||||
"avg_hold_time": "18 min",
|
||||
"avg_win": "0.00035",
|
||||
"avg_loss": "-0.00028",
|
||||
"best_trade": "0.00124",
|
||||
"worst_trade": "-0.00098",
|
||||
"consecutive_wins": 15,
|
||||
"consecutive_losses": 4,
|
||||
"calmar_ratio": 0.87,
|
||||
"sortino_ratio": 2.2
|
||||
},
|
||||
"combined": {
|
||||
"arr": "14.2%",
|
||||
"sharpe": 2.3,
|
||||
"max_dd": "7.8%",
|
||||
"win_rate": "58.1%",
|
||||
"profit_factor": 1.9,
|
||||
"total_trades": 5180,
|
||||
"trades_per_day": 14,
|
||||
"avg_hold_time": "22 min",
|
||||
"avg_win": "0.00048",
|
||||
"avg_loss": "-0.00029",
|
||||
"best_trade": "0.00201",
|
||||
"worst_trade": "-0.00118",
|
||||
"consecutive_wins": 14,
|
||||
"consecutive_losses": 4,
|
||||
"calmar_ratio": 1.82,
|
||||
"sortino_ratio": 3.1
|
||||
}
|
||||
}
|
||||
|
||||
if strategy not in results:
|
||||
logger.warning(f"Strategie '{strategy}' nicht gefunden. Verwende 'combined' als Default.")
|
||||
strategy = "combined"
|
||||
|
||||
r = results[strategy]
|
||||
|
||||
# Ergebnisse anzeigen
|
||||
logger.info("\n" + "=" * 60)
|
||||
logger.info("BACKTEST ERGEBNISSE")
|
||||
logger.info("=" * 60)
|
||||
|
||||
logger.info("\n📊 KEY-METRIKEN:")
|
||||
logger.info(f" ARR (Annualized Return): {r['arr']}")
|
||||
logger.info(f" Sharpe Ratio: {r['sharpe']}")
|
||||
logger.info(f" Sortino Ratio: {r['sortino_ratio']}")
|
||||
logger.info(f" Calmar Ratio: {r['calmar_ratio']}")
|
||||
logger.info(f" Max Drawdown: {r['max_dd']}")
|
||||
logger.info(f" Profit Factor: {r['profit_factor']}")
|
||||
|
||||
logger.info("\n📈 TRADE-STATISTIK:")
|
||||
logger.info(f" Total Trades: {r['total_trades']}")
|
||||
logger.info(f" Trades/Tag: {r['trades_per_day']}")
|
||||
logger.info(f" Win Rate: {r['win_rate']}")
|
||||
logger.info(f" Avg Hold Time: {r['avg_hold_time']}")
|
||||
logger.info(f" Avg Win: {r['avg_win']}")
|
||||
logger.info(f" Avg Loss: {r['avg_loss']}")
|
||||
|
||||
logger.info("\n🏆 EXTREME:")
|
||||
logger.info(f" Best Trade: {r['best_trade']}")
|
||||
logger.info(f" Worst Trade: {r['worst_trade']}")
|
||||
logger.info(f" Consecutive Wins: {r['consecutive_wins']}")
|
||||
logger.info(f" Consecutive Losses: {r['consecutive_losses']}")
|
||||
|
||||
# Bewertung
|
||||
logger.info("\n" + "-" * 60)
|
||||
logger.info("BEWERTUNG:")
|
||||
logger.info("-" * 60)
|
||||
|
||||
sharpe = r['sharpe']
|
||||
if sharpe >= 2.0:
|
||||
logger.info(" ✅ Sharpe > 2.0: Ausgezeichnete risikobereinigte Rendite")
|
||||
elif sharpe >= 1.5:
|
||||
logger.info(" ✓ Sharpe > 1.5: Gute risikobereinigte Rendite")
|
||||
elif sharpe >= 1.0:
|
||||
logger.info(" ⚠ Sharpe > 1.0: Akzeptabel, aber verbesserungsfä hig")
|
||||
else:
|
||||
logger.info(" ❌ Sharpe < 1.0: Zu riskant für die Rendite")
|
||||
|
||||
max_dd = float(r['max_dd'].replace('%', ''))
|
||||
if max_dd < 10:
|
||||
logger.info(" ✅ Max DD < 10%: Gutes Risikomanagement")
|
||||
elif max_dd < 15:
|
||||
logger.info(" ✓ Max DD < 15%: Akzeptabel")
|
||||
else:
|
||||
logger.info(" ⚠ Max DD > 15%: Hohes Drawdown-Risiko")
|
||||
|
||||
# Plot (optional)
|
||||
if plot:
|
||||
logger.info("\n📊 Equity Curve wird generiert...")
|
||||
try:
|
||||
import plotly.graph_objects as go
|
||||
import numpy as np
|
||||
|
||||
# Simulierte Equity Curve
|
||||
np.random.seed(42)
|
||||
days = 252 * 5 # 5 Jahre
|
||||
daily_returns = np.random.normal(0.0005, 0.008, days)
|
||||
equity = np.cumprod(1 + daily_returns)
|
||||
|
||||
fig = go.Figure()
|
||||
fig.add_trace(go.Scatter(
|
||||
x=list(range(days)),
|
||||
y=equity,
|
||||
mode='lines',
|
||||
name='Equity',
|
||||
line=dict(color='#2E86AB', width=2)
|
||||
))
|
||||
fig.update_layout(
|
||||
title='PREDIX Backtest - Equity Curve',
|
||||
xaxis_title='Trading Days',
|
||||
yaxis_title='Portfolio Value',
|
||||
template='plotly_dark',
|
||||
height=500
|
||||
)
|
||||
fig.write_html('equity_curve.html')
|
||||
logger.info(" ✅ Equity Curve gespeichert: equity_curve.html")
|
||||
except ImportError:
|
||||
logger.warning(" ⚠ Plotly nicht installiert: pip install plotly")
|
||||
|
||||
logger.info("\n" + "=" * 60)
|
||||
logger.info("FERTIG!")
|
||||
logger.info("=" * 60)
|
||||
logger.info("\nNächste Schritte:")
|
||||
logger.info(" 1. Strategie optimieren: python examples/05_model_training.py")
|
||||
logger.info(" 2. RL Agent trainieren: python examples/06_rl_trading_agent.py")
|
||||
logger.info(" 3. Live Trading: rdagent quant --live")
|
||||
|
||||
|
||||
def main():
|
||||
"""Hauptfunktion mit Argument-Parsing."""
|
||||
parser = argparse.ArgumentParser(
|
||||
description="Beispiel 04: Backtest einer Trading-Strategie",
|
||||
formatter_class=argparse.RawDescriptionHelpFormatter,
|
||||
epilog="""
|
||||
Beispiele:
|
||||
# Momentum-Strategie testen
|
||||
python 04_backtest_simple.py --strategy momentum
|
||||
|
||||
# Kombinierte Strategie mit Plot
|
||||
python 04_backtest_simple.py --strategy combined --plot
|
||||
|
||||
# Eigener Zeitraum
|
||||
python 04_backtest_simple.py --strategy momentum --start 2022-01-01 --end 2025-12-31
|
||||
"""
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
"--strategy",
|
||||
type=str,
|
||||
choices=["momentum", "reversal", "combined"],
|
||||
default="combined",
|
||||
help="Strategie-Name (default: combined)"
|
||||
)
|
||||
parser.add_argument(
|
||||
"--start",
|
||||
type=str,
|
||||
default="2020-01-01",
|
||||
help="Startdatum YYYY-MM-DD (default: 2020-01-01)"
|
||||
)
|
||||
parser.add_argument(
|
||||
"--end",
|
||||
type=str,
|
||||
default="2025-12-31",
|
||||
help="Enddatum YYYY-MM-DD (default: 2025-12-31)"
|
||||
)
|
||||
parser.add_argument(
|
||||
"--plot",
|
||||
action="store_true",
|
||||
help="Equity Curve als Plotly Chart anzeigen"
|
||||
)
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
try:
|
||||
run_backtest(
|
||||
strategy=args.strategy,
|
||||
start_date=args.start,
|
||||
end_date=args.end,
|
||||
plot=args.plot
|
||||
)
|
||||
except KeyboardInterrupt:
|
||||
logger.warning("\nAbgebrochen durch Benutzer.")
|
||||
sys.exit(130)
|
||||
except Exception as e:
|
||||
logger.error(f"Fehler beim Backtest: {e}")
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -1,316 +0,0 @@
|
||||
#!/usr/bin/env python
|
||||
"""
|
||||
Beispiel 05: Model Training - ML-Modell (LSTM/XGBoost) trainieren
|
||||
|
||||
Was macht dieses Beispiel?
|
||||
Dieses Skript trainiert ein ML-Modell auf Faktor-Daten für EUR/USD
|
||||
Vorhersagen. Es unterstützt LSTM (Deep Learning) und XGBoost (Gradient Boosting).
|
||||
|
||||
Der Workflow umfasst:
|
||||
1. Daten laden & Features engineering (MultiIndex-safe)
|
||||
2. Temporale Train/Val/Test Split (KEIN Shuffle!)
|
||||
3. Modell-Training mit Early Stopping
|
||||
4. Evaluation auf Test-Set
|
||||
5. Modell speichern
|
||||
|
||||
Voraussetzungen:
|
||||
- Generierte Faktoren vorhanden (aus Beispiel 01)
|
||||
- Für LSTM: PyTorch installiert (`pip install torch`)
|
||||
- Für XGBoost: XGBoost installiert (`pip install xgboost`)
|
||||
|
||||
Erwartete Laufzeit:
|
||||
XGBoost: ~5-10 Minuten
|
||||
LSTM: ~20-40 Minuten (CPU), ~5-10 Minuten (GPU)
|
||||
|
||||
Output:
|
||||
- Trainiertes Modell in models/
|
||||
- Train/Val/Test Ergebnisse
|
||||
- Feature Importance (bei XGBoost)
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import logging
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
logging.basicConfig(
|
||||
level=logging.INFO,
|
||||
format='%(asctime)s | %(levelname)-8s | %(message)s',
|
||||
datefmt='%Y-%m-%d %H:%M:%S'
|
||||
)
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def train_xgboost(features: list, target: str) -> dict:
|
||||
"""
|
||||
Trainiert XGBoost-Modell.
|
||||
|
||||
Args:
|
||||
features: Liste der Feature-Namen
|
||||
target: Target-Variable ('fwd_sign_4', 'fwd_ret_4')
|
||||
|
||||
Returns:
|
||||
Dictionary mit Trainings-Ergebnissen
|
||||
"""
|
||||
logger.info("Starte XGBoost Training...")
|
||||
|
||||
# Beispiel-Code (in Produktion: Echte Implementierung)
|
||||
training_code = """
|
||||
import pandas as pd
|
||||
import numpy as np
|
||||
from xgboost import XGBClassifier
|
||||
from sklearn.metrics import accuracy_score, classification_report
|
||||
|
||||
# 1. Daten laden (MultiIndex-safe)
|
||||
df = pd.read_hdf("intraday_pv.h5", key="data")
|
||||
close = df['$close'].unstack(level='instrument')
|
||||
|
||||
# 2. Features erstellen
|
||||
features = pd.DataFrame(index=close.index)
|
||||
features['ret_8'] = close.pct_change(8)
|
||||
features['ret_16'] = close.pct_change(16)
|
||||
features['ret_96'] = close.pct_change(96)
|
||||
features['hl_range'] = (df['$high'].unstack() - df['$low'].unstack()) / close
|
||||
features = features.fillna(0)
|
||||
|
||||
# 3. Target: Forward 4-bar direction
|
||||
fwd_ret_4 = close.shift(-4) / close - 1
|
||||
target = (fwd_ret_4 > 0).astype(int)
|
||||
|
||||
# 4. Temporale Split (KEIN Shuffle!)
|
||||
train_end = '2024-01-01'
|
||||
val_end = '2024-06-01'
|
||||
|
||||
train_mask = features.index < train_end
|
||||
val_mask = (features.index >= train_end) & (features.index < val_end)
|
||||
test_mask = features.index >= val_end
|
||||
|
||||
# 5. Modell trainieren
|
||||
model = XGBClassifier(
|
||||
max_depth=4,
|
||||
learning_rate=0.05,
|
||||
n_estimators=200,
|
||||
subsample=0.8,
|
||||
colsample_bytree=0.8,
|
||||
min_child_weight=5,
|
||||
eval_metric='logloss',
|
||||
early_stopping_rounds=10
|
||||
)
|
||||
|
||||
model.fit(
|
||||
features[train_mask], target[train_mask],
|
||||
eval_set=[(features[val_mask], target[val_mask])],
|
||||
verbose=False
|
||||
)
|
||||
|
||||
# 6. Evaluation
|
||||
y_pred = model.predict(features[test_mask])
|
||||
accuracy = accuracy_score(target[test_mask], y_pred)
|
||||
print(f"Test Accuracy: {accuracy:.4f}")
|
||||
|
||||
# 7. Feature Importance
|
||||
importance = model.feature_importances_
|
||||
for feat, imp in zip(features.columns, importance):
|
||||
print(f" {feat}: {imp:.4f}")
|
||||
|
||||
# 8. Speichern
|
||||
import joblib
|
||||
joblib.dump(model, 'models/xgboost_model.pkl')
|
||||
"""
|
||||
|
||||
# Simulierte Ergebnisse (aus 8 echten Läufen)
|
||||
results = {
|
||||
"model_type": "XGBoost",
|
||||
"accuracy": "56.1%",
|
||||
"sharpe": 1.5,
|
||||
"arr": "9.8%",
|
||||
"ic": 0.067,
|
||||
"max_dd": "9.7%",
|
||||
"feature_importance": {
|
||||
"ret_16": 0.28,
|
||||
"ret_96": 0.22,
|
||||
"hl_range": 0.18,
|
||||
"ret_8": 0.17,
|
||||
"rsi_14": 0.15
|
||||
},
|
||||
"training_time": "4 min 32 sec",
|
||||
"model_path": "models/xgboost_model.pkl"
|
||||
}
|
||||
|
||||
logger.info(f"\n{'='*60}")
|
||||
logger.info("XGBOOST TRAINING ERGEBNISSE")
|
||||
logger.info(f"{'='*60}")
|
||||
|
||||
logger.info(f"\n📊 MODEL:")
|
||||
logger.info(f" Typ: {results['model_type']}")
|
||||
logger.info(f" Target: {target}")
|
||||
logger.info(f" Features: {', '.join(features)}")
|
||||
|
||||
logger.info(f"\n🎯 TEST ERGEBNISSE:")
|
||||
logger.info(f" Accuracy: {results['accuracy']}")
|
||||
logger.info(f" Sharpe: {results['sharpe']}")
|
||||
logger.info(f" ARR: {results['arr']}")
|
||||
logger.info(f" IC: {results['ic']}")
|
||||
logger.info(f" Max DD: {results['max_dd']}")
|
||||
|
||||
logger.info(f"\n🔧 FEATURE IMPORTANCE:")
|
||||
for feat, imp in results['feature_importance'].items():
|
||||
bar = "█" * int(imp * 40)
|
||||
logger.info(f" {feat:12s}: {imp:.4f} {bar}")
|
||||
|
||||
logger.info(f"\n⏱️ TRAINING:")
|
||||
logger.info(f" Dauer: {results['training_time']}")
|
||||
logger.info(f" Modell: {results['model_path']}")
|
||||
|
||||
return results
|
||||
|
||||
|
||||
def train_lstm(features: list, target: str) -> dict:
|
||||
"""
|
||||
Trainiert LSTM-Modell.
|
||||
|
||||
Args:
|
||||
features: Liste der Feature-Namen
|
||||
target: Target-Variable
|
||||
|
||||
Returns:
|
||||
Dictionary mit Trainings-Ergebnissen
|
||||
"""
|
||||
logger.info("Starte LSTM Training...")
|
||||
|
||||
# Simulierte Ergebnisse (aus 12 echten Läufen)
|
||||
results = {
|
||||
"model_type": "LSTM",
|
||||
"seq_len": 96,
|
||||
"hidden_size": 128,
|
||||
"num_layers": 2,
|
||||
"accuracy": "58.2%",
|
||||
"sharpe": 1.8,
|
||||
"arr": "12.1%",
|
||||
"ic": 0.074,
|
||||
"max_dd": "8.3%",
|
||||
"epochs_trained": 23,
|
||||
"early_stop_patience": 5,
|
||||
"training_time": "18 min 45 sec",
|
||||
"model_path": "models/lstm_model.pth"
|
||||
}
|
||||
|
||||
logger.info(f"\n{'='*60}")
|
||||
logger.info("LSTM TRAINING ERGEBNISSE")
|
||||
logger.info(f"{'='*60}")
|
||||
|
||||
logger.info(f"\n📊 MODEL ARCHITEKTUR:")
|
||||
logger.info(f" Typ: {results['model_type']}")
|
||||
logger.info(f" Sequence Length: {results['seq_len']} bars")
|
||||
logger.info(f" Hidden Size: {results['hidden_size']}")
|
||||
logger.info(f" Layers: {results['num_layers']}")
|
||||
logger.info(f" Target: {target}")
|
||||
logger.info(f" Features: {', '.join(features)}")
|
||||
|
||||
logger.info(f"\n🎯 TEST ERGEBNISSE:")
|
||||
logger.info(f" Accuracy: {results['accuracy']}")
|
||||
logger.info(f" Sharpe: {results['sharpe']}")
|
||||
logger.info(f" ARR: {results['arr']}")
|
||||
logger.info(f" IC: {results['ic']}")
|
||||
logger.info(f" Max DD: {results['max_dd']}")
|
||||
|
||||
logger.info(f"\n⏱️ TRAINING:")
|
||||
logger.info(f" Epochs: {results['epochs_trained']} (Early Stop nach {results['early_stop_patience']} Patience)")
|
||||
logger.info(f" Dauer: {results['training_time']}")
|
||||
logger.info(f" Modell: {results['model_path']}")
|
||||
|
||||
return results
|
||||
|
||||
|
||||
def run_model_training(model_type: str, features: list, target: str) -> None:
|
||||
"""
|
||||
Führt das Modell-Training aus.
|
||||
|
||||
Args:
|
||||
model_type: 'xgboost' oder 'lstm'
|
||||
features: Liste der Feature-Namen
|
||||
target: Target-Variable
|
||||
"""
|
||||
logger.info("=" * 60)
|
||||
logger.info("PREDIX Model Training - Beispiel 05")
|
||||
logger.info("=" * 60)
|
||||
logger.info(f"Modell: {model_type}")
|
||||
logger.info(f"Features: {', '.join(features)}")
|
||||
logger.info(f"Target: {target}")
|
||||
logger.info("=" * 60)
|
||||
|
||||
if model_type == "xgboost":
|
||||
train_xgboost(features, target)
|
||||
elif model_type == "lstm":
|
||||
train_lstm(features, target)
|
||||
else:
|
||||
logger.error(f"Unbekannter Modell-Typ: {model_type}")
|
||||
sys.exit(1)
|
||||
|
||||
logger.info("\n" + "=" * 60)
|
||||
logger.info("FERTIG!")
|
||||
logger.info("=" * 60)
|
||||
logger.info("\nNächste Schritte:")
|
||||
logger.info(" 1. Modell evaluieren: rdagent evaluate --model models/{model_type}_model.*")
|
||||
logger.info(" 2. RL Agent trainieren: python examples/06_rl_trading_agent.py")
|
||||
logger.info(" 3. Live Trading: rdagent quant --live --model models/{model_type}_model.*")
|
||||
|
||||
|
||||
def main():
|
||||
"""Hauptfunktion mit Argument-Parsing."""
|
||||
parser = argparse.ArgumentParser(
|
||||
description="Beispiel 05: ML-Modell-Training (LSTM/XGBoost)",
|
||||
formatter_class=argparse.RawDescriptionHelpFormatter,
|
||||
epilog="""
|
||||
Beispiele:
|
||||
# XGBoost trainieren
|
||||
python 05_model_training.py --model xgboost --features ret_16,ret_96,hl_range
|
||||
|
||||
# LSTM trainieren
|
||||
python 05_model_training.py --model lstm --features ret_8,ret_16,ret_96,hl_range,rsi_14
|
||||
|
||||
# Custom Target
|
||||
python 05_model_training.py --model xgboost --target fwd_ret_4
|
||||
"""
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
"--model",
|
||||
type=str,
|
||||
choices=["xgboost", "lstm"],
|
||||
default="xgboost",
|
||||
help="Modell-Typ (default: xgboost)"
|
||||
)
|
||||
parser.add_argument(
|
||||
"--features",
|
||||
type=str,
|
||||
default="ret_16,ret_96,hl_range,ret_8,rsi_14",
|
||||
help="Kommagetrennte Feature-Liste (default: ret_16,ret_96,hl_range,ret_8,rsi_14)"
|
||||
)
|
||||
parser.add_argument(
|
||||
"--target",
|
||||
type=str,
|
||||
choices=["fwd_sign_4", "fwd_ret_4", "fwd_sign_16"],
|
||||
default="fwd_sign_4",
|
||||
help="Target-Variable (default: fwd_sign_4)"
|
||||
)
|
||||
|
||||
args = parser.parse_args()
|
||||
features = [f.strip() for f in args.features.split(',')]
|
||||
|
||||
try:
|
||||
run_model_training(
|
||||
model_type=args.model,
|
||||
features=features,
|
||||
target=args.target
|
||||
)
|
||||
except KeyboardInterrupt:
|
||||
logger.warning("\nAbgebrochen durch Benutzer.")
|
||||
sys.exit(130)
|
||||
except Exception as e:
|
||||
logger.error(f"Fehler beim Training: {e}")
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -1,248 +0,0 @@
|
||||
#!/usr/bin/env python
|
||||
"""
|
||||
Beispiel 06: RL Trading Agent - Reinforcement Learning für Trading
|
||||
|
||||
Was macht dieses Beispiel?
|
||||
Dieses Skript trainiert einen Reinforcement Learning (RL) Agent, der
|
||||
eigenständig Trading-Entscheidungen trifft. Der Agent lernt durch
|
||||
Trial-and-Error, wann er Long/Short gehen oder neutral bleiben soll.
|
||||
|
||||
Unterstützte Algorithmen:
|
||||
- PPO (Proximal Policy Optimization): Stabil, guter Default
|
||||
- DQN (Deep Q-Network): Sample-effizient, aber komplexer
|
||||
- A2C (Advantage Actor-Critic): Schneller, aber weniger stabil
|
||||
|
||||
Voraussetzungen:
|
||||
- RL-Abhängigkeiten installiert (`pip install -e ".[rl]"`)
|
||||
- Faktor-Daten vorhanden (aus Beispiel 01)
|
||||
- Empfohlen: GPU für schnellere Laufzeit
|
||||
|
||||
Erwartete Laufzeit:
|
||||
~30-60 Minuten (CPU, 1000 Episodes)
|
||||
~10-20 Minuten (GPU, 1000 Episodes)
|
||||
|
||||
Output:
|
||||
- Trainierter RL-Agent in models/rl_agent/
|
||||
- Learning Curve (Reward pro Episode)
|
||||
- Trading-Statistiken des Agents
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import logging
|
||||
import sys
|
||||
|
||||
logging.basicConfig(
|
||||
level=logging.INFO,
|
||||
format='%(asctime)s | %(levelname)-8s | %(message)s',
|
||||
datefmt='%Y-%m-%d %H:%M:%S'
|
||||
)
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def train_rl_agent(algo: str, episodes: int, learning_rate: float) -> dict:
|
||||
"""
|
||||
Trainiert einen RL Trading Agent.
|
||||
|
||||
Args:
|
||||
algo: Algorithmus ('ppo', 'dqn', 'a2c')
|
||||
episodes: Anzahl der Trainings-Episoden
|
||||
learning_rate: Lernrate für den Optimierer
|
||||
|
||||
Returns:
|
||||
Dictionary mit Trainings-Ergebnissen
|
||||
"""
|
||||
logger.info("=" * 60)
|
||||
logger.info("PREDIX RL Trading Agent - Beispiel 06")
|
||||
logger.info("=" * 60)
|
||||
logger.info(f"Algorithmus: {algo.upper()}")
|
||||
logger.info(f"Episoden: {episodes}")
|
||||
logger.info(f"Lernrate: {learning_rate}")
|
||||
logger.info("=" * 60)
|
||||
|
||||
# Beispiel-Code (in Produktion: Echte RL-Implementierung mit Gym/Stable-Baselines3)
|
||||
logger.info("\nInitialisiere Trading Environment...")
|
||||
logger.info(" Observation Space: [ret_16, ret_96, hl_range, rsi_14, adx_14]")
|
||||
logger.info(" Action Space: [LONG=0, SHORT=1, NEUTRAL=2]")
|
||||
logger.info(" Reward: PnL - Spread-Kosten - Drawdown-Penalty")
|
||||
|
||||
logger.info(f"\nStarte {algo.upper()} Training mit {episodes} Episoden...")
|
||||
|
||||
# Simuliere Learning Curve
|
||||
logger.info("\nTRAININGS-FORTSCHRITT (simuliert):")
|
||||
logger.info("-" * 60)
|
||||
|
||||
# Beispiel-Lernkurve (exponentiell ansteigend mit Rauschen)
|
||||
import math
|
||||
milestones = [0, 100, 250, 500, 750, 1000]
|
||||
expected_rewards = [-0.05, -0.02, 0.01, 0.03, 0.045, 0.052]
|
||||
|
||||
for episode, reward in zip(milestones, expected_rewards):
|
||||
if episode <= episodes:
|
||||
noise = 0.005 * (1 - episode / episodes) # Weniger Rauschen über Zeit
|
||||
logger.info(f" Episode {episode:5d} | Avg Reward: {reward:+.4f} ± {noise:.4f}")
|
||||
|
||||
# Ergebnisse (simuliert, basierend auf echten Läufen)
|
||||
results = {
|
||||
"ppo": {
|
||||
"algo": "PPO",
|
||||
"final_avg_reward": 0.052,
|
||||
"best_episode_reward": 0.127,
|
||||
"convergence_episode": 650,
|
||||
"total_trades": 8420,
|
||||
"trades_per_day": 15,
|
||||
"win_rate": "54.8%",
|
||||
"sharpe": 1.7,
|
||||
"arr": "11.2%",
|
||||
"max_dd": "9.8%",
|
||||
"profit_factor": 1.65,
|
||||
"training_time": "42 min 15 sec",
|
||||
"model_path": "models/rl_agent/ppo_model.zip",
|
||||
"learning_curve": "models/rl_agent/learning_curve.png"
|
||||
},
|
||||
"dqn": {
|
||||
"algo": "DQN",
|
||||
"final_avg_reward": 0.048,
|
||||
"best_episode_reward": 0.115,
|
||||
"convergence_episode": 720,
|
||||
"total_trades": 7650,
|
||||
"trades_per_day": 13,
|
||||
"win_rate": "52.3%",
|
||||
"sharpe": 1.5,
|
||||
"arr": "9.8%",
|
||||
"max_dd": "11.2%",
|
||||
"profit_factor": 1.52,
|
||||
"training_time": "38 min 42 sec",
|
||||
"model_path": "models/rl_agent/dqn_model.zip",
|
||||
"learning_curve": "models/rl_agent/learning_curve.png"
|
||||
},
|
||||
"a2c": {
|
||||
"algo": "A2C",
|
||||
"final_avg_reward": 0.044,
|
||||
"best_episode_reward": 0.108,
|
||||
"convergence_episode": 580,
|
||||
"total_trades": 9100,
|
||||
"trades_per_day": 17,
|
||||
"win_rate": "51.1%",
|
||||
"sharpe": 1.4,
|
||||
"arr": "9.2%",
|
||||
"max_dd": "12.1%",
|
||||
"profit_factor": 1.48,
|
||||
"training_time": "35 min 28 sec",
|
||||
"model_path": "models/rl_agent/a2c_model.zip",
|
||||
"learning_curve": "models/rl_agent/learning_curve.png"
|
||||
}
|
||||
}
|
||||
|
||||
r = results.get(algo, results["ppo"])
|
||||
|
||||
# Ergebnisse anzeigen
|
||||
logger.info("\n" + "=" * 60)
|
||||
logger.info("RL AGENT TRAINING ERGEBNISSE")
|
||||
logger.info("=" * 60)
|
||||
|
||||
logger.info(f"\n🤖 ALGORITHMUS:")
|
||||
logger.info(f" Typ: {r['algo']}")
|
||||
logger.info(f" Lernrate: {learning_rate}")
|
||||
logger.info(f" Konvergenz: Episode {r['convergence_episode']}")
|
||||
|
||||
logger.info(f"\n📈 LEARNING:")
|
||||
logger.info(f" Final Avg Reward: {r['final_avg_reward']:+.4f}")
|
||||
logger.info(f" Best Episode Reward: {r['best_episode_reward']:+.4f}")
|
||||
logger.info(f" Learning Curve: {r['learning_curve']}")
|
||||
|
||||
logger.info(f"\n💰 TRADING PERFORMANCE:")
|
||||
logger.info(f" ARR: {r['arr']}")
|
||||
logger.info(f" Sharpe: {r['sharpe']}")
|
||||
logger.info(f" Max DD: {r['max_dd']}")
|
||||
logger.info(f" Win Rate: {r['win_rate']}")
|
||||
logger.info(f" Profit Factor: {r['profit_factor']}")
|
||||
logger.info(f" Total Trades: {r['total_trades']}")
|
||||
logger.info(f" Trades/Tag: {r['trades_per_day']}")
|
||||
|
||||
logger.info(f"\n💾 MODEL:")
|
||||
logger.info(f" Pfad: {r['model_path']}")
|
||||
logger.info(f" Trainingsdauer: {r['training_time']}")
|
||||
|
||||
# Bewertung
|
||||
logger.info("\n" + "-" * 60)
|
||||
logger.info("BEWERTUNG:")
|
||||
logger.info("-" * 60)
|
||||
|
||||
if r['sharpe'] >= 1.5:
|
||||
logger.info(" ✅ Sharpe >= 1.5: RL-Agent lernt profitable Strategie")
|
||||
else:
|
||||
logger.info(" ⚠ Sharpe < 1.5: Agent braucht mehr Training oder bessere Features")
|
||||
|
||||
if r['final_avg_reward'] > 0.03:
|
||||
logger.info(" ✅ Reward positiv und steigend: Agent konvergiert")
|
||||
else:
|
||||
logger.info(" ⚠ Reward niedrig: Lernrate oder Reward-Function anpassen")
|
||||
|
||||
# Nächste Schritte
|
||||
logger.info("\n" + "=" * 60)
|
||||
logger.info("FERTIG!")
|
||||
logger.info("=" * 60)
|
||||
logger.info("\nNächste Schritte:")
|
||||
logger.info(" 1. Agent evaluieren: rdagent evaluate --rl models/rl_agent/{algo}_model.zip")
|
||||
logger.info(" 2. Live Trading: rdagent quant --live --rl models/rl_agent/{algo}_model.zip")
|
||||
logger.info(" 3. Hyperparameter optimieren: rdagent rl_trading --tune")
|
||||
|
||||
return r
|
||||
|
||||
|
||||
def main():
|
||||
"""Hauptfunktion mit Argument-Parsing."""
|
||||
parser = argparse.ArgumentParser(
|
||||
description="Beispiel 06: RL Trading Agent trainieren",
|
||||
formatter_class=argparse.RawDescriptionHelpFormatter,
|
||||
epilog="""
|
||||
Beispiele:
|
||||
# PPO Agent trainieren (empfohlen)
|
||||
python 06_rl_trading_agent.py --algo ppo --episodes 1000
|
||||
|
||||
# DQN mit custom Lernrate
|
||||
python 06_rl_trading_agent.py --algo dqn --episodes 2000 --lr 0.0005
|
||||
|
||||
# A2C schnelles Training (Testing)
|
||||
python 06_rl_trading_agent.py --algo a2c --episodes 100
|
||||
"""
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
"--algo",
|
||||
type=str,
|
||||
choices=["ppo", "dqn", "a2c"],
|
||||
default="ppo",
|
||||
help="RL-Algorithmus (default: ppo)"
|
||||
)
|
||||
parser.add_argument(
|
||||
"--episodes",
|
||||
type=int,
|
||||
default=1000,
|
||||
help="Anzahl Trainings-Episoden (default: 1000)"
|
||||
)
|
||||
parser.add_argument(
|
||||
"--lr",
|
||||
type=float,
|
||||
default=0.0003,
|
||||
help="Lernrate (default: 0.0003)"
|
||||
)
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
try:
|
||||
train_rl_agent(
|
||||
algo=args.algo,
|
||||
episodes=args.episodes,
|
||||
learning_rate=args.lr
|
||||
)
|
||||
except KeyboardInterrupt:
|
||||
logger.warning("\nAbgebrochen durch Benutzer.")
|
||||
sys.exit(130)
|
||||
except Exception as e:
|
||||
logger.error(f"Fehler beim RL-Training: {e}")
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -1,137 +0,0 @@
|
||||
# PREDIX Examples
|
||||
|
||||
Willkommen zu den PREDIX Trading Platform Beispielen! Dieser Ordner enthält vollständi ge, lauffä hige Beispiele, die dir den Einstieg in algorithmisches Trading mit EUR/USD erleichtern.
|
||||
|
||||
## 📚 Beispiele im Überblick
|
||||
|
||||
| Nr. | Beispiel | Beschreibung | Dauer | Schwierigkeit |
|
||||
|-----|----------|--------------|-------|---------------|
|
||||
| 01 | [`factor_discovery.py`](01_factor_discovery.py) | Automatische Generierung neuer Trading-Faktoren | ~10 Min | ⭐ Anfänger |
|
||||
| 02 | [`factor_evolution.py`](02_factor_evolution.py) | Optimierung bestehender Faktoren | ~15 Min | ⭐⭐ Mittel |
|
||||
| 03 | [`strategy_generation.py`](03_strategy_generation.py) | Kombination von Faktoren zu Strategien | ~5 Min | ⭐ Anfänger |
|
||||
| 04 | [`backtest_simple.py`](04_backtest_simple.py) | Backtest einer Trading-Strategie | ~3 Min | ⭐ Anfänger |
|
||||
| 05 | [`model_training.py`](05_model_training.py) | ML-Modell-Training (LSTM/XGBoost) | ~30 Min | ⭐⭐⭐ Fortgeschritten |
|
||||
| 06 | [`rl_trading_agent.py`](06_rl_trading_agent.py) | Reinforcement Learning Agent | ~60 Min | ⭐⭐⭐ Fortgeschritten |
|
||||
|
||||
## 🚀 Schnellstart
|
||||
|
||||
### Voraussetzungen
|
||||
|
||||
```bash
|
||||
# Installation
|
||||
pip install -e ".[all]"
|
||||
|
||||
# Daten herunterladen (falls noch nicht geschehen)
|
||||
rdagent download-data
|
||||
```
|
||||
|
||||
### Beispiel ausführen
|
||||
|
||||
```bash
|
||||
# Faktor-Generierung (3 Loops)
|
||||
python examples/01_factor_discovery.py --loop-n 3
|
||||
|
||||
# Backtest durchführen
|
||||
python examples/04_backtest_simple.py --strategy momentum
|
||||
```
|
||||
|
||||
## 📖 Detaillierte Anleitungen
|
||||
|
||||
### Beispiel 01: Factor Discovery
|
||||
|
||||
**Ziel:** Automatisch neue Trading-Faktoren mit LLM generieren lassen
|
||||
|
||||
```bash
|
||||
python examples/01_factor_discovery.py --loop-n 5 --llm local
|
||||
```
|
||||
|
||||
**Output:**
|
||||
- Generierte Faktoren in `RD-Agent_workspace/`
|
||||
- Performance-Metriken (ARR, Sharpe, IC)
|
||||
- Faktor-Implementierungen als Python-Code
|
||||
|
||||
**Nächste Schritte:**
|
||||
→ Siehe `02_factor_evolution.py` um Faktoren zu optimieren
|
||||
|
||||
### Beispiel 02: Factor Evolution
|
||||
|
||||
**Ziel:** Bestehende Faktoren mit Session/Regime Filters verbessern
|
||||
|
||||
```bash
|
||||
python examples/02_factor_evolution.py --factor momentum_16 --improve session_filter
|
||||
```
|
||||
|
||||
**Output:**
|
||||
- Verbesserte Faktoren mit Before/After-Vergleich
|
||||
- Metrik-Verbesserungen (ARR +X%, Sharpe +X.X)
|
||||
|
||||
### Beispiel 03: Strategy Generation
|
||||
|
||||
**Ziel:** Mehrere Faktoren zu einer robusten Strategie kombinieren
|
||||
|
||||
```bash
|
||||
python examples/03_strategy_generation.py --factors momentum_16,reversal,session_alpha
|
||||
```
|
||||
|
||||
**Output:**
|
||||
- IC-weighted Faktor-Kombination
|
||||
- Signal-Verteilung (Long/Short/Neutral)
|
||||
|
||||
### Beispiel 04: Backtest
|
||||
|
||||
**Ziel:** Backtest einer Trading-Strategie auf historischen Daten
|
||||
|
||||
```bash
|
||||
python examples/04_backtest_simple.py --strategy momentum --start 2020-01-01 --end 2025-12-31
|
||||
```
|
||||
|
||||
**Output:**
|
||||
- Key-Metriken: ARR, Sharpe, MaxDD, WinRate
|
||||
- Equity Curve (optional als Plot)
|
||||
|
||||
### Beispiel 05: Model Training
|
||||
|
||||
**Ziel:** ML-Modell (LSTM/XGBoost) auf Faktor-Daten trainieren
|
||||
|
||||
```bash
|
||||
python examples/05_model_training.py --model lstm --features momentum_16,reversal
|
||||
```
|
||||
|
||||
**Output:**
|
||||
- Trainiertes Modell in `models/`
|
||||
- Train/Val/Test Split Ergebnisse
|
||||
- Feature Importance (bei XGBoost)
|
||||
|
||||
### Beispiel 06: RL Trading Agent
|
||||
|
||||
**Ziel:** Reinforcement Learning Agent für Trading trainieren
|
||||
|
||||
```bash
|
||||
python examples/06_rl_trading_agent.py --algo ppo --episodes 1000
|
||||
```
|
||||
|
||||
**Output:**
|
||||
- Trainierter RL-Agent in `models/rl_agent/`
|
||||
- Learning Curve
|
||||
- Trading-Statistiken
|
||||
|
||||
## 📓 Jupyter Notebook
|
||||
|
||||
Für eine interaktive Einführung siehe:
|
||||
|
||||
```bash
|
||||
jupyter notebook examples/notebooks/quickstart.ipynb
|
||||
```
|
||||
|
||||
## 🐛 Probleme?
|
||||
|
||||
- **Dokumentation:** `docs/` oder [README.md](../README.md)
|
||||
- **CLI Hilfe:** `rdagent COMMAND --help`
|
||||
- **Issues:** [GitHub Issues](https://github.com/nico/NexQuant/issues)
|
||||
- **Community:** [Discussions](https://github.com/nico/NexQuant/discussions)
|
||||
|
||||
## ⚠️ Wichtige Hinweise
|
||||
|
||||
- **Keine Closed-Source Assets:** Commite niemals `git_ignore_folder/`, `results/`, `.env`, `models/local/`, `prompts/local/`
|
||||
- **Daten-Pfade:** Passe ggf. Datenpfade in den Beispielen an deine Installation an
|
||||
- **Laufzeit:** ML/RL-Beispiele benötigen ggf. GPU für akzeptable Laufzeiten
|
||||
@@ -1,411 +0,0 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# PREDIX Quickstart Tutorial\n",
|
||||
"\n",
|
||||
"Willkommen zu PREDIX – deiner Plattform für algorithmisches EUR/USD Trading!\n",
|
||||
"\n",
|
||||
"In diesem Notebook lernst du:\n",
|
||||
"1. **Daten laden** – EUR/USD 1-Minute Daten vorbereiten\n",
|
||||
"2. **Faktoren generieren** – Einfache Trading-Faktoren berechnen\n",
|
||||
"3. **Strategie kombinieren** – Mehrere Faktoren zu einer Strategie verbinden\n",
|
||||
"4. **Backtest durchführen** – Historische Performance testen\n",
|
||||
"5. **Ergebnisse visualisieren** – Equity Curve und Metriken\n",
|
||||
"\n",
|
||||
"## Voraussetzungen\n",
|
||||
"\n",
|
||||
"```bash\n",
|
||||
"pip install -e \".[all]\"\n",
|
||||
"```"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## 1. Setup & Daten laden\n",
|
||||
"\n",
|
||||
"Zuerst importieren wir die benötigten Bibliotheken und laden die EUR/USD Daten."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import pandas as pd\n",
|
||||
"import numpy as np\n",
|
||||
"import matplotlib.pyplot as plt\n",
|
||||
"import warnings\n",
|
||||
"warnings.filterwarnings('ignore')\n",
|
||||
"\n",
|
||||
"# Plotly für interaktive Charts (optional)\n",
|
||||
"try:\n",
|
||||
" import plotly.graph_objects as go\n",
|
||||
" from plotly.subplots import make_subplots\n",
|
||||
" HAS_PLOTLY = True\n",
|
||||
"except ImportError:\n",
|
||||
" HAS_PLOTLY = False\n",
|
||||
"\n",
|
||||
"print(\"✓ Imports erfolgreich!\")\n",
|
||||
"print(f\" Pandas: {pd.__version__}\")\n",
|
||||
"print(f\" NumPy: {np.__version__}\")\n",
|
||||
"print(f\" Plotly: {'ja' if HAS_PLOTLY else 'nein (pip install plotly)'}\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### Daten-Simulation\n",
|
||||
"\n",
|
||||
"Für dieses Tutorial simulieren wir EUR/USD Daten (in Produktion: Echte Daten aus Qlib)."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Simuliere EUR/USD 1-Minute Daten (1 Jahr)\n",
|
||||
"np.random.seed(42)\n",
|
||||
"n_bars = 525600 # 525600 Minuten pro Jahr\n",
|
||||
"\n",
|
||||
"# Datetime-Index (24/7 Trading)\n",
|
||||
"dates = pd.date_range('2024-01-01', periods=n_bars, freq='min')\n",
|
||||
"\n",
|
||||
"# Simulierte Preise (Geometric Brownian Motion)\n",
|
||||
"dt = 1/525600\n",
|
||||
"mu = 0.00002 # Drift\n",
|
||||
"sigma = 0.0003 # Volatilität\n",
|
||||
"returns = np.random.normal(mu, sigma, n_bars)\n",
|
||||
"prices = 1.0850 * np.exp(np.cumsum(returns)) # Start bei 1.0850\n",
|
||||
"\n",
|
||||
# OHLCV erstellen\n",
|
||||
"df = pd.DataFrame({\n",
|
||||
" 'open': prices + np.random.normal(0, 0.0001, n_bars),\n",
|
||||
" 'high': prices + np.abs(np.random.normal(0, 0.0002, n_bars)),\n",
|
||||
" 'low': prices - np.abs(np.random.normal(0, 0.0002, n_bars)),\n",
|
||||
" 'close': prices,\n",
|
||||
" 'volume': np.random.exponential(100, n_bars).astype(int)\n",
|
||||
"}, index=dates)\n",
|
||||
"\n",
|
||||
"print(f\"✓ Daten generiert: {len(df)} Bars\")\n",
|
||||
"print(f\" Zeitraum: {df.index[0]} bis {df.index[-1]}\")\n",
|
||||
"print(f\"\\nErste 5 Zeilen:\")\n",
|
||||
"df.head()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## 2. Trading-Faktoren berechnen\n",
|
||||
"\n",
|
||||
"Jetzt berechnen wir verschiedene Trading-Faktoren:"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def calculate_momentum(close: pd.Series, window: int) -> pd.Series:\n",
|
||||
" \"\"\"Momentum-Faktor: Prozentuale Veränderung über window Bars.\"\"\"\n",
|
||||
" return close.pct_change(window)\n",
|
||||
"\n",
|
||||
"def calculate_rsi(close: pd.Series, period: int = 14) -> pd.Series:\n",
|
||||
" \"\"\"RSI (Relative Strength Index).\"\"\"\n",
|
||||
" delta = close.diff()\n",
|
||||
" gain = delta.where(delta > 0, 0).rolling(period).mean()\n",
|
||||
" loss = (-delta.where(delta < 0, 0)).rolling(period).mean()\n",
|
||||
" rs = gain / (loss + 1e-8)\n",
|
||||
" return 100 - (100 / (1 + rs))\n",
|
||||
"\n",
|
||||
"def calculate_hl_range(high: pd.Series, low: pd.Series, close: pd.Series) -> pd.Series:\n",
|
||||
" \"\"\"High-Low Range als Volatilitäts-Proxy.\"\"\"\n",
|
||||
" return (high - low) / close\n",
|
||||
"\n",
|
||||
"def calculate_session_flag(index: pd.DatetimeIndex, session: str) -> pd.Series:\n",
|
||||
" \"\"\"Session-Filter (London, NY, Asian).\"\"\"\n",
|
||||
" hour = index.hour\n",
|
||||
" if session == 'london':\n",
|
||||
" return ((hour >= 8) & (hour < 16)).astype(float)\n",
|
||||
" elif session == 'ny':\n",
|
||||
" return ((hour >= 13) & (hour < 21)).astype(float)\n",
|
||||
" elif session == 'overlap':\n",
|
||||
" return ((hour >= 13) & (hour < 16)).astype(float)\n",
|
||||
" return pd.Series(1, index=index)\n",
|
||||
"\n",
|
||||
"# Faktoren berechnen\n",
|
||||
"factors = pd.DataFrame(index=df.index)\n",
|
||||
"factors['momentum_16'] = calculate_momentum(df['close'], 16)\n",
|
||||
"factors['momentum_96'] = calculate_momentum(df['close'], 96)\n",
|
||||
"factors['rsi_14'] = calculate_rsi(df['close'], 14)\n",
|
||||
"factors['hl_range'] = calculate_hl_range(df['high'], df['low'], df['close'])\n",
|
||||
"factors['is_london'] = calculate_session_flag(df.index, 'london')\n",
|
||||
"factors['is_ny'] = calculate_session_flag(df.index, 'ny')\n",
|
||||
"\n",
|
||||
"# NaN entfernen\n",
|
||||
"factors = factors.dropna()\n",
|
||||
"\n",
|
||||
"print(f\"✓ {len(factors.columns)} Faktoren berechnet:\")\n",
|
||||
"for col in factors.columns:\n",
|
||||
" print(f\" - {col:15s} | Mean: {factors[col].mean():+.4f} | Std: {factors[col].std():.4f}\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## 3. Strategie kombinieren\n",
|
||||
"\n",
|
||||
"Wir kombinieren die Faktoren zu einer IC-weighted Strategie:"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Simulierte IC-Werte (Information Coefficient)\n",
|
||||
"ic_values = {\n",
|
||||
" 'momentum_16': 0.074, # Positiv: Trend-following\n",
|
||||
" 'momentum_96': 0.051, # Positiv: Langfristiger Trend\n",
|
||||
" 'rsi_14': -0.045, # Negativ: Mean-reversion\n",
|
||||
" 'hl_range': -0.032 # Negativ: Volatilitäts-Fade\n",
|
||||
"}\n",
|
||||
"\n",
|
||||
"# Z-Score Normalisierung\n",
|
||||
"z_scores = (factors[list(ic_values.keys())] - factors[list(ic_values.keys())].rolling(20).mean()) / (\n",
|
||||
" factors[list(ic_values.keys())].rolling(20).std() + 1e-8\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"# IC-Weights (normalisieren)\n",
|
||||
"total_abs_ic = sum(abs(ic) for ic in ic_values.values())\n",
|
||||
"weights = {k: v / total_abs_ic for k, v in ic_values.items()}\n",
|
||||
"\n",
|
||||
"# Composite Signal\n",
|
||||
"composite = pd.Series(0.0, index=z_scores.index)\n",
|
||||
"for factor_name, weight in weights.items():\n",
|
||||
" composite += weight * z_scores[factor_name]\n",
|
||||
"\n",
|
||||
"# Signale generieren (Thresholds)\n",
|
||||
"signal = pd.Series(0, index=composite.index)\n",
|
||||
"signal[composite > 0.5] = 1 # LONG\n",
|
||||
"signal[composite < -0.5] = -1 # SHORT\n",
|
||||
"\n",
|
||||
"print(f\"✓ Strategie generiert\")\n",
|
||||
"print(f\"\\nSignal-Verteilung:\")\n",
|
||||
"print(f\" LONG: {(signal == 1).sum():6d} ({(signal == 1).mean()*100:.1f}%)\")\n",
|
||||
"print(f\" SHORT: {(signal == -1).sum():6d} ({(signal == -1).mean()*100:.1f}%)\")\n",
|
||||
"print(f\" NEUTRAL: {(signal == 0).sum():6d} ({(signal == 0).mean()*100:.1f}%)\")\n",
|
||||
"\n",
|
||||
"# IC-Weights anzeigen\n",
|
||||
"print(f\"\\nIC-Weights:\")\n",
|
||||
"for factor_name, weight in weights.items():\n",
|
||||
" print(f\" {factor_name:15s}: {weight:+.4f} (IC: {ic_values[factor_name]:+.4f})\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## 4. Backtest\n",
|
||||
"\n",
|
||||
"Simulieren wir einen einfachen Backtest mit Spread-Kosten:"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Backtest-Parameter\n",
|
||||
"spread_cost = 0.00015 # 1.5 bps\n",
|
||||
"initial_capital = 100000\n",
|
||||
"position_size = 0.1 # 10% des Kapitals pro Trade\n",
|
||||
"\n",
|
||||
"# Nur London/NY Session handeln\n",
|
||||
"active_mask = (factors['is_london'] == 1) | (factors['is_ny'] == 1)\n",
|
||||
"\n",
|
||||
"# Returns berechnen\n",
|
||||
"close = df.loc[signal.index, 'close']\n",
|
||||
"returns = close.pct_change()\n",
|
||||
"\n",
|
||||
"# Strategie-Returns\n",
|
||||
"strategy_returns = signal.shift(1) * returns # Signal vom Vortag\n",
|
||||
"strategy_returns = strategy_returns[active_mask]\n",
|
||||
"\n",
|
||||
"# Spread-Kosten abziehen\n",
|
||||
"trade_costs = (signal.shift(1) != signal).astype(float) * spread_cost\n",
|
||||
"strategy_returns = strategy_returns - trade_costs\n",
|
||||
"\n",
|
||||
"# Kumulierte Returns\n",
|
||||
"equity = initial_capital * (1 + strategy_returns).cumprod()\n",
|
||||
"benchmark_equity = initial_capital * (1 + returns[active_mask]).cumprod()\n",
|
||||
"\n",
|
||||
"# Metriken berechnen\n",
|
||||
"total_return = (equity.iloc[-1] / initial_capital - 1) * 100\n",
|
||||
"years = len(strategy_returns) / 525600\n",
|
||||
"arr = ((equity.iloc[-1] / initial_capital) ** (1/max(years, 0.001)) - 1) * 100\n",
|
||||
"sharpe = strategy_returns.mean() / (strategy_returns.std() + 1e-8) * np.sqrt(525600)\n",
|
||||
"\n",
|
||||
"# Max Drawdown\n",
|
||||
"rolling_max = equity.cummax()\n",
|
||||
"drawdown = (equity - rolling_max) / rolling_max\n",
|
||||
"max_dd = drawdown.min() * 100\n",
|
||||
"\n",
|
||||
"print(f\"=\" * 50)\n",
|
||||
"print(f\"BACKTEST ERGEBNISSE\")\n",
|
||||
"print(f\"=\" * 50)\n",
|
||||
"print(f\" Initial Capital: ${initial_capital:,.0f}\")\n",
|
||||
"print(f\" Final Capital: ${equity.iloc[-1]:,.0f}\")\n",
|
||||
"print(f\" Total Return: {total_return:+.2f}%\")\n",
|
||||
"print(f\" ARR: {arr:+.2f}%\")\n",
|
||||
"print(f\" Sharpe Ratio: {sharpe:.2f}\")\n",
|
||||
"print(f\" Max Drawdown: {max_dd:.2f}%\")\n",
|
||||
"print(f\" Trades: {(signal.shift(1) != signal).sum()}\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## 5. Visualisierung\n",
|
||||
"\n",
|
||||
"Jetzt visualisieren wir die Equity Curve und die Drawdowns."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"if HAS_PLOTLY:\n",
|
||||
" # Subplots: Equity + Drawdown\n",
|
||||
" fig = make_subplots(\n",
|
||||
" rows=2, cols=1,\n",
|
||||
" shared_xaxes=True,\n",
|
||||
" vertical_spacing=0.05,\n",
|
||||
" row_heights=[0.7, 0.3],\n",
|
||||
" subplot_titles=('Equity Curve', 'Drawdown')\n",
|
||||
" )\n",
|
||||
" \n",
|
||||
" # Equity Curve\n",
|
||||
" fig.add_trace(\n",
|
||||
" go.Scatter(x=equity.index, y=equity.values, name='Strategy', line=dict(color='#2E86AB', width=2)),\n",
|
||||
" row=1, col=1\n",
|
||||
" )\n",
|
||||
" fig.add_trace(\n",
|
||||
" go.Scatter(x=benchmark_equity.index, y=benchmark_equity.values, name='Benchmark', line=dict(color='#A23B72', width=1, dash='dot')),\n",
|
||||
" row=1, col=1\n",
|
||||
" )\n",
|
||||
" \n",
|
||||
" # Drawdown\n",
|
||||
" fig.add_trace(\n",
|
||||
" go.Scatter(x=drawdown.index, y=drawdown.values*100, name='Drawdown',\n",
|
||||
" fill='tozeroy', line=dict(color='#F18F01', width=1)),\n",
|
||||
" row=2, col=1\n",
|
||||
" )\n",
|
||||
" \n",
|
||||
" fig.update_layout(\n",
|
||||
" title='PREDIX Backtest - EUR/USD 1-Minute',\n",
|
||||
" template='plotly_dark',\n",
|
||||
" height=700,\n",
|
||||
" showlegend=True\n",
|
||||
" )\n",
|
||||
" \n",
|
||||
" fig.show()\n",
|
||||
"else:\n",
|
||||
" # Matplotlib Fallback\n",
|
||||
" fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(14, 8), sharex=True, gridspec_kw={'height_ratios': [3, 1]})\n",
|
||||
" \n",
|
||||
" ax1.plot(equity.index, equity.values, label='Strategy', color='#2E86AB', linewidth=2)\n",
|
||||
" ax1.plot(benchmark_equity.index, benchmark_equity.values, label='Benchmark', color='#A23B72', linewidth=1, linestyle='--')\n",
|
||||
" ax1.set_title('Equity Curve')\n",
|
||||
" ax1.legend()\n",
|
||||
" ax1.grid(True, alpha=0.3)\n",
|
||||
" \n",
|
||||
" ax2.fill_between(drawdown.index, drawdown.values*100, 0, color='#F18F01', alpha=0.5)\n",
|
||||
" ax2.set_title('Drawdown')\n",
|
||||
" ax2.grid(True, alpha=0.3)\n",
|
||||
" \n",
|
||||
" plt.tight_layout()\n",
|
||||
" plt.savefig('equity_curve.png', dpi=150)\n",
|
||||
" plt.show()\n",
|
||||
" print(\"✓ Chart gespeichert: equity_curve.png\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## 6. Nächste Schritte\n",
|
||||
"\n",
|
||||
"🎉 Glückwunsch! Du hast deinen ersten PREDIX-Backtest durchgeführt.\n",
|
||||
"\n",
|
||||
"### Weiterführende Beispiele:\n",
|
||||
"\n",
|
||||
"| Beispiel | Beschreibung |\n",
|
||||
"|----------|-------------|\n",
|
||||
"| `01_factor_discovery.py` | Automatische Faktor-Generierung mit LLM |\n",
|
||||
"| `02_factor_evolution.py` | Faktor-Optimierung mit Session/Regime Filters |\n",
|
||||
"| `05_model_training.py` | ML-Modelle (LSTM/XGBoost) trainieren |\n",
|
||||
"| `06_rl_trading_agent.py` | Reinforcement Learning Agent |\n",
|
||||
"\n",
|
||||
"### CLI Commands:\n",
|
||||
"\n",
|
||||
"```bash\n",
|
||||
"# Alle Commands anzeigen\n",
|
||||
"rdagent --help\n",
|
||||
"\n",
|
||||
"# Faktor-Generierung starten\n",
|
||||
"rdagent quant --loop-n 10\n",
|
||||
"\n",
|
||||
"# Faktoren evaluieren\n",
|
||||
"rdagent evaluate\n",
|
||||
"\n",
|
||||
"# Top-Faktoren anzeigen\n",
|
||||
"rdagent top --n 10\n",
|
||||
"```\n",
|
||||
"\n",
|
||||
"### Ressourcen:\n",
|
||||
"\n",
|
||||
"- 📚 [Dokumentation](../docs/)\n",
|
||||
"- 💬 [GitHub Discussions](https://github.com/nico/NexQuant/discussions)\n",
|
||||
"- 🐛 [Issues melden](https://github.com/nico/NexQuant/issues)"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3 (ipykernel)",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.10.0"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 4
|
||||
}
|
||||
@@ -1,239 +0,0 @@
|
||||
# NexQuant Models
|
||||
|
||||
This directory contains all ML model definitions for NexQuant trading factors.
|
||||
|
||||
---
|
||||
|
||||
## 📁 Directory Structure
|
||||
|
||||
```
|
||||
models/
|
||||
├── standard/ # Default models (committed to Git)
|
||||
│ ├── xgboost_factor.py # XGBoost for tabular data
|
||||
│ ├── lightgbm_factor.py # LightGBM (faster than XGBoost)
|
||||
│ └── randomforest_factor.py # Baseline model
|
||||
│
|
||||
├── local/ # YOUR IMPROVED MODELS (not in Git!)
|
||||
│ ├── transformer_factor.py # Your Transformer
|
||||
│ ├── tcn_factor.py # Your TCN
|
||||
│ ├── patchtst_factor.py # Your PatchTST
|
||||
│ ├── cnn_lstm_hybrid.py # Your Hybrid model
|
||||
│ └── optimized_xgboost.py # Your optimized XGBoost
|
||||
│
|
||||
└── README.md # This file
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🎯 How It Works
|
||||
|
||||
**Model Loading Priority:**
|
||||
|
||||
1. **`models/local/*.py`** ← Your improved models (loaded first!)
|
||||
2. **`models/standard/*.py`** ← Default models (fallback)
|
||||
|
||||
**Example:**
|
||||
```python
|
||||
from rdagent.components.model_loader import load_model
|
||||
|
||||
# Load XGBoost model
|
||||
# If models/local/xgboost_factor*.py exists → loads that
|
||||
# Otherwise → loads from models/standard/
|
||||
model_factory = load_model("xgboost_factor")
|
||||
|
||||
# Create model instance
|
||||
model = model_factory(max_depth=8, learning_rate=0.1)
|
||||
|
||||
# Train
|
||||
model.fit(X_train, y_train)
|
||||
|
||||
# Predict
|
||||
predictions = model.predict(X_test)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📝 Available Standard Models
|
||||
|
||||
| Model | File | Use Case |
|
||||
|-------|------|----------|
|
||||
| **XGBoost** | `xgboost_factor.py` | Tabular factors, fast training |
|
||||
| **LightGBM** | `lightgbm_factor.py` | Large datasets, faster than XGBoost |
|
||||
| **RandomForest** | `randomforest_factor.py` | Baseline, robust |
|
||||
|
||||
---
|
||||
|
||||
## 🚀 Creating Your Improved Models
|
||||
|
||||
### Step 1: Create Local Model File
|
||||
|
||||
```bash
|
||||
# Create local directory (if not exists)
|
||||
mkdir -p models/local
|
||||
|
||||
# Copy standard model as template
|
||||
cp models/standard/xgboost_factor.py models/local/optimized_xgboost.py
|
||||
```
|
||||
|
||||
### Step 2: Improve Your Model
|
||||
|
||||
```python
|
||||
# models/local/optimized_xgboost.py
|
||||
|
||||
class XGBoostFactorModel:
|
||||
"""Your optimized version with better hyperparameters."""
|
||||
|
||||
def __init__(self, **params):
|
||||
self.params = {
|
||||
'objective': 'reg:squarederror',
|
||||
'max_depth': 8, # Deeper trees
|
||||
'learning_rate': 0.03, # Slower learning
|
||||
'n_estimators': 1000, # More estimators
|
||||
'subsample': 0.9, # Less dropout
|
||||
'colsample_bytree': 0.9,
|
||||
'random_state': 42,
|
||||
# Your custom params
|
||||
'gamma': 0.1, # Regularization
|
||||
'min_child_weight': 3,
|
||||
**params
|
||||
}
|
||||
# ... rest of implementation
|
||||
```
|
||||
|
||||
### Step 3: Use in Trading
|
||||
|
||||
Your improved models are automatically used when running:
|
||||
|
||||
```python
|
||||
from rdagent.components.model_loader import load_model
|
||||
|
||||
# Auto-loads your optimized version!
|
||||
model_factory = load_model("xgboost_factor")
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔐 Security
|
||||
|
||||
**What to keep in `models/local/`:**
|
||||
|
||||
✅ Your proprietary model architectures
|
||||
✅ Optimized hyperparameters
|
||||
✅ Custom feature engineering
|
||||
✅ Ensemble methods
|
||||
✅ Trade secrets & alpha-generating logic
|
||||
|
||||
**What NOT to commit to Git:**
|
||||
|
||||
❌ Anything in `models/local/` (already in .gitignore)
|
||||
❌ Files with `.local.py` suffix
|
||||
❌ Files with `_private.py` suffix
|
||||
|
||||
---
|
||||
|
||||
## 📊 Best Practices
|
||||
|
||||
### 1. Version Your Models
|
||||
|
||||
```python
|
||||
# Good naming:
|
||||
models/local/
|
||||
├── xgboost_v2.py # Version 2
|
||||
├── xgboost_v3_optimized.py # Version 3 optimized
|
||||
└── lightgbm_lstm_hybrid_v1.py # Hybrid v1
|
||||
```
|
||||
|
||||
### 2. Document Changes
|
||||
|
||||
```python
|
||||
# models/local/optimized_xgboost_v2.py
|
||||
"""
|
||||
XGBoost Factor Model v2.0
|
||||
|
||||
Changes from v1:
|
||||
- Increased max_depth from 6 to 8
|
||||
- Added gamma regularization
|
||||
- Increased n_estimators from 500 to 1000
|
||||
- Target: +2% ARR, +0.2 Sharpe
|
||||
|
||||
Author: Your Name
|
||||
Date: 2026-04-02
|
||||
"""
|
||||
```
|
||||
|
||||
### 3. Test Performance
|
||||
|
||||
```python
|
||||
# Compare model versions
|
||||
from rdagent.components.model_loader import load_model
|
||||
|
||||
# Load standard
|
||||
std_model = load_model("xgboost_factor", local_only=False)
|
||||
|
||||
# Load local (if exists)
|
||||
local_model = load_model("xgboost_factor", local_only=True)
|
||||
|
||||
# Backtest both and compare
|
||||
# ...
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔧 Advanced Usage
|
||||
|
||||
### Load All Models
|
||||
|
||||
```python
|
||||
from rdagent.components.model_loader import list_available_models
|
||||
|
||||
all_models = list_available_models()
|
||||
print(f"Standard: {all_models['standard']}")
|
||||
print(f"Local: {all_models['local']}")
|
||||
```
|
||||
|
||||
### Force Local Model
|
||||
|
||||
```python
|
||||
# Raise error if local model not found
|
||||
model = load_model("transformer_factor", local_only=True)
|
||||
```
|
||||
|
||||
### Custom Model Path
|
||||
|
||||
```python
|
||||
from rdagent.components.model_loader import load_module_from_path
|
||||
from pathlib import Path
|
||||
|
||||
# Load from custom location
|
||||
module = load_module_from_path(
|
||||
Path("/path/to/my/custom_model.py"),
|
||||
"custom_model"
|
||||
)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📈 Model Selection Guide
|
||||
|
||||
| Scenario | Recommended Model | Why |
|
||||
|----------|------------------|-----|
|
||||
| **Tabular Factors** | XGBoost / LightGBM | Fast, interpretable |
|
||||
| **Large Dataset** | LightGBM | Lower memory, faster |
|
||||
| **Baseline** | RandomForest | Robust, no tuning needed |
|
||||
| **Time-Series Patterns** | LSTM / GRU (local) | Sequential dependencies |
|
||||
| **Multi-Scale** | TCN (local) | Different time horizons |
|
||||
| **Long-Range** | Transformer (local) | Attention mechanism |
|
||||
| **Best Performance** | Ensemble (local) | Combine multiple models |
|
||||
|
||||
---
|
||||
|
||||
## 🎯 Next Steps
|
||||
|
||||
1. **Review standard models:** `cat models/standard/*.py`
|
||||
2. **Create your improved version:** `mkdir -p models/local`
|
||||
3. **Test:** `python rdagent/components/model_loader.py`
|
||||
4. **Run trading:** `rdagent fin_quant`
|
||||
|
||||
---
|
||||
|
||||
**Your improved models in `models/local/` are your competitive edge! 🚀**
|
||||
@@ -1,98 +0,0 @@
|
||||
"""
|
||||
LightGBM Factor Model - Standard Version
|
||||
|
||||
Usage:
|
||||
from rdagent.components.model_loader import load_model
|
||||
model = load_model("lightgbm_factor")
|
||||
"""
|
||||
|
||||
import lightgbm as lgb
|
||||
import numpy as np
|
||||
import pandas as pd
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
class LightGBMFactorModel:
|
||||
"""
|
||||
LightGBM-based factor model for EUR/USD trading.
|
||||
|
||||
Features:
|
||||
- Faster than XGBoost
|
||||
- Lower memory usage
|
||||
- Good for large datasets
|
||||
"""
|
||||
|
||||
def __init__(self, **params):
|
||||
self.params = {
|
||||
'objective': 'regression',
|
||||
'metric': 'mse',
|
||||
'num_leaves': 31,
|
||||
'learning_rate': 0.05,
|
||||
'feature_fraction': 0.8,
|
||||
'bagging_fraction': 0.8,
|
||||
'bagging_freq': 5,
|
||||
'verbose': -1,
|
||||
'random_state': 42,
|
||||
**params
|
||||
}
|
||||
self.model = None
|
||||
self.feature_names = None
|
||||
|
||||
def fit(self, X, y, feature_names=None, **fit_params):
|
||||
"""Train the model."""
|
||||
self.feature_names = feature_names
|
||||
|
||||
# Create LightGBM datasets
|
||||
train_data = lgb.Dataset(X, label=y, feature_name=feature_names if feature_names else 'auto')
|
||||
|
||||
self.model = lgb.train(
|
||||
self.params,
|
||||
train_data,
|
||||
num_boost_round=500,
|
||||
**fit_params
|
||||
)
|
||||
|
||||
return self
|
||||
|
||||
def predict(self, X):
|
||||
"""Generate predictions."""
|
||||
if self.model is None:
|
||||
raise ValueError("Model not trained. Call fit() first.")
|
||||
|
||||
return self.model.predict(X)
|
||||
|
||||
def get_feature_importance(self, top_n=10, importance_type='gain'):
|
||||
"""Get top N most important features."""
|
||||
if self.model is None:
|
||||
raise ValueError("Model not trained.")
|
||||
|
||||
importance = self.model.feature_importance(importance_type=importance_type)
|
||||
if self.feature_names is not None:
|
||||
indices = np.argsort(importance)[::-1][:top_n]
|
||||
return [(self.feature_names[i], importance[i]) for i in indices]
|
||||
return importance
|
||||
|
||||
def save(self, path: str):
|
||||
"""Save model to file."""
|
||||
Path(path).parent.mkdir(parents=True, exist_ok=True)
|
||||
self.model.save_model(path)
|
||||
print(f"✓ Model saved to {path}")
|
||||
|
||||
def load(self, path: str):
|
||||
"""Load model from file."""
|
||||
self.model = lgb.Booster(model_file=path)
|
||||
print(f"✓ Model loaded from {path}")
|
||||
return self
|
||||
|
||||
|
||||
# Convenience function
|
||||
def create_lightgbm_factor_model(**params):
|
||||
"""Create LightGBM factor model."""
|
||||
return LightGBMFactorModel(**params)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
# Test
|
||||
print("=== LightGBM Factor Model Test ===")
|
||||
model = create_lightgbm_factor_model()
|
||||
print(f"✓ Model created with params: {model.params}")
|
||||
@@ -1,90 +0,0 @@
|
||||
"""
|
||||
XGBoost Factor Model - Standard Version
|
||||
|
||||
Usage:
|
||||
from rdagent.components.model_loader import load_model
|
||||
model = load_model("xgboost_factor")
|
||||
"""
|
||||
|
||||
import xgboost as xgb
|
||||
import numpy as np
|
||||
import pandas as pd
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
class XGBoostFactorModel:
|
||||
"""
|
||||
XGBoost-based factor model for EUR/USD trading.
|
||||
|
||||
Features:
|
||||
- Handles tabular data efficiently
|
||||
- Built-in feature importance
|
||||
- Fast training and inference
|
||||
"""
|
||||
|
||||
def __init__(self, **params):
|
||||
self.params = {
|
||||
'objective': 'reg:squarederror',
|
||||
'max_depth': 6,
|
||||
'learning_rate': 0.05,
|
||||
'n_estimators': 500,
|
||||
'subsample': 0.8,
|
||||
'colsample_bytree': 0.8,
|
||||
'random_state': 42,
|
||||
**params
|
||||
}
|
||||
self.model = None
|
||||
self.feature_names = None
|
||||
|
||||
def fit(self, X, y, feature_names=None, **fit_params):
|
||||
"""Train the model."""
|
||||
self.feature_names = feature_names
|
||||
|
||||
self.model = xgb.XGBRegressor(**self.params)
|
||||
self.model.fit(X, y, **fit_params)
|
||||
|
||||
return self
|
||||
|
||||
def predict(self, X):
|
||||
"""Generate predictions."""
|
||||
if self.model is None:
|
||||
raise ValueError("Model not trained. Call fit() first.")
|
||||
|
||||
return self.model.predict(X)
|
||||
|
||||
def get_feature_importance(self, top_n=10):
|
||||
"""Get top N most important features."""
|
||||
if self.model is None:
|
||||
raise ValueError("Model not trained.")
|
||||
|
||||
importance = self.model.feature_importances_
|
||||
if self.feature_names is not None:
|
||||
indices = np.argsort(importance)[::-1][:top_n]
|
||||
return [(self.feature_names[i], importance[i]) for i in indices]
|
||||
return importance
|
||||
|
||||
def save(self, path: str):
|
||||
"""Save model to file."""
|
||||
Path(path).parent.mkdir(parents=True, exist_ok=True)
|
||||
self.model.save_model(path)
|
||||
print(f"✓ Model saved to {path}")
|
||||
|
||||
def load(self, path: str):
|
||||
"""Load model from file."""
|
||||
self.model = xgb.XGBRegressor()
|
||||
self.model.load_model(path)
|
||||
print(f"✓ Model loaded from {path}")
|
||||
return self
|
||||
|
||||
|
||||
# Convenience function
|
||||
def create_xgboost_factor_model(**params):
|
||||
"""Create XGBoost factor model."""
|
||||
return XGBoostFactorModel(**params)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
# Test
|
||||
print("=== XGBoost Factor Model Test ===")
|
||||
model = create_xgboost_factor_model()
|
||||
print(f"✓ Model created with params: {model.params}")
|
||||
-1950
File diff suppressed because it is too large
Load Diff
@@ -1,553 +0,0 @@
|
||||
import io
|
||||
import json
|
||||
from abc import abstractmethod
|
||||
from typing import Dict, Tuple
|
||||
|
||||
import pandas as pd
|
||||
|
||||
from rdagent.components.coder.factor_coder.config import FACTOR_COSTEER_SETTINGS
|
||||
from rdagent.components.coder.factor_coder.factor import FactorTask
|
||||
from rdagent.core.experiment import Task, Workspace
|
||||
from rdagent.oai.llm_conf import LLM_SETTINGS
|
||||
from rdagent.oai.llm_utils import APIBackend
|
||||
from rdagent.utils.agent.tpl import T
|
||||
|
||||
|
||||
class FactorEvaluator:
|
||||
"""Although the init method is same to Evaluator, but we want to emphasize they are different"""
|
||||
|
||||
def __init__(self, scen=None) -> None:
|
||||
self.scen = scen
|
||||
|
||||
@abstractmethod
|
||||
def evaluate(
|
||||
self,
|
||||
target_task: Task,
|
||||
implementation: Workspace,
|
||||
gt_implementation: Workspace,
|
||||
**kwargs,
|
||||
) -> Tuple[str, object]:
|
||||
"""You can get the dataframe by
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
_, gen_df = implementation.execute()
|
||||
_, gt_df = gt_implementation.execute()
|
||||
|
||||
Returns
|
||||
-------
|
||||
Tuple[str, object]
|
||||
- str: the text-based description of the evaluation result
|
||||
- object: a comparable metric (bool, integer, float ...) None for evaluator with only text-based result
|
||||
|
||||
"""
|
||||
raise NotImplementedError("Please implement the `evaluator` method")
|
||||
|
||||
def _get_df(self, gt_implementation: Workspace, implementation: Workspace):
|
||||
if gt_implementation is not None:
|
||||
_, gt_df = gt_implementation.execute()
|
||||
if isinstance(gt_df, pd.Series):
|
||||
gt_df = gt_df.to_frame("gt_factor")
|
||||
if isinstance(gt_df, pd.DataFrame):
|
||||
gt_df = gt_df.sort_index()
|
||||
else:
|
||||
gt_df = None
|
||||
|
||||
_, gen_df = implementation.execute()
|
||||
if isinstance(gen_df, pd.Series):
|
||||
gen_df = gen_df.to_frame("source_factor")
|
||||
if isinstance(gen_df, pd.DataFrame):
|
||||
gen_df = gen_df.sort_index()
|
||||
return gt_df, gen_df
|
||||
|
||||
def __str__(self) -> str:
|
||||
return self.__class__.__name__
|
||||
|
||||
|
||||
class FactorCodeEvaluator(FactorEvaluator):
|
||||
def evaluate(
|
||||
self,
|
||||
target_task: FactorTask,
|
||||
implementation: Workspace,
|
||||
execution_feedback: str,
|
||||
value_feedback: str = "",
|
||||
gt_implementation: Workspace = None,
|
||||
**kwargs,
|
||||
):
|
||||
factor_information = target_task.get_task_information()
|
||||
code = implementation.all_codes
|
||||
|
||||
system_prompt = T(".prompts:evaluator_code_feedback_v1_system").r(
|
||||
scenario=(
|
||||
self.scen.get_scenario_all_desc(
|
||||
target_task,
|
||||
filtered_tag="feature",
|
||||
simple_background=FACTOR_COSTEER_SETTINGS.simple_background,
|
||||
)
|
||||
if self.scen is not None
|
||||
else "No scenario description."
|
||||
)
|
||||
)
|
||||
|
||||
execution_feedback_to_render = execution_feedback
|
||||
for _ in range(10): # 10 times to split the content is enough
|
||||
user_prompt = T(".prompts:evaluator_code_feedback_v1_user").r(
|
||||
factor_information=factor_information,
|
||||
code=code,
|
||||
execution_feedback=execution_feedback_to_render,
|
||||
value_feedback=value_feedback,
|
||||
gt_code=gt_implementation.code if gt_implementation else None,
|
||||
)
|
||||
if (
|
||||
APIBackend().build_messages_and_calculate_token(
|
||||
user_prompt=user_prompt,
|
||||
system_prompt=system_prompt,
|
||||
)
|
||||
> APIBackend().chat_token_limit
|
||||
):
|
||||
execution_feedback_to_render = execution_feedback_to_render[len(execution_feedback_to_render) // 2 :]
|
||||
else:
|
||||
break
|
||||
critic_response = APIBackend().build_messages_and_create_chat_completion(
|
||||
user_prompt=user_prompt,
|
||||
system_prompt=system_prompt,
|
||||
json_mode=False,
|
||||
)
|
||||
|
||||
return critic_response, None
|
||||
|
||||
|
||||
class FactorInfEvaluator(FactorEvaluator):
|
||||
def evaluate(
|
||||
self,
|
||||
implementation: Workspace,
|
||||
gt_implementation: Workspace,
|
||||
) -> Tuple[str, object]:
|
||||
_, gen_df = self._get_df(gt_implementation, implementation)
|
||||
if gen_df is None:
|
||||
return (
|
||||
"The source dataframe is None. Please check the implementation.",
|
||||
False,
|
||||
)
|
||||
INF_count = gen_df.isin([float("inf"), -float("inf")]).sum().sum()
|
||||
if INF_count == 0:
|
||||
return "The source dataframe does not have any infinite values.", True
|
||||
else:
|
||||
return (
|
||||
f"The source dataframe has {INF_count} infinite values. Please check the implementation.",
|
||||
False,
|
||||
)
|
||||
|
||||
|
||||
class FactorSingleColumnEvaluator(FactorEvaluator):
|
||||
def evaluate(
|
||||
self,
|
||||
implementation: Workspace,
|
||||
gt_implementation: Workspace,
|
||||
) -> Tuple[str, object]:
|
||||
_, gen_df = self._get_df(gt_implementation, implementation)
|
||||
if gen_df is None:
|
||||
return (
|
||||
"The source dataframe is None. Please check the implementation.",
|
||||
False,
|
||||
)
|
||||
if len(gen_df.columns) == 1:
|
||||
return "The source dataframe has only one column which is correct.", True
|
||||
else:
|
||||
return (
|
||||
"The source dataframe has more than one column. Please check the implementation. We only evaluate the first column.",
|
||||
False,
|
||||
)
|
||||
|
||||
|
||||
class FactorOutputFormatEvaluator(FactorEvaluator):
|
||||
def evaluate(
|
||||
self,
|
||||
implementation: Workspace,
|
||||
gt_implementation: Workspace,
|
||||
) -> Tuple[str, object]:
|
||||
gt_df, gen_df = self._get_df(gt_implementation, implementation)
|
||||
if gen_df is None:
|
||||
return (
|
||||
"The source dataframe is None. Skip the evaluation of the output format.",
|
||||
False,
|
||||
)
|
||||
buffer = io.StringIO()
|
||||
gen_df.info(buf=buffer)
|
||||
gen_df_info_str = f"The user is currently working on a feature related task.\nThe output dataframe info is:\n{buffer.getvalue()}"
|
||||
system_prompt = T(".prompts:evaluator_output_format_system").r(
|
||||
scenario=(
|
||||
self.scen.get_scenario_all_desc(implementation.target_task, filtered_tag="feature")
|
||||
if self.scen is not None
|
||||
else "No scenario description."
|
||||
)
|
||||
)
|
||||
|
||||
# TODO: with retry_context(retry_n=3, except_list=[KeyError]):
|
||||
max_attempts = 3
|
||||
attempts = 0
|
||||
final_evaluation_dict = None
|
||||
|
||||
while attempts < max_attempts:
|
||||
try:
|
||||
api = APIBackend() if attempts == 0 else APIBackend(use_chat_cache=False)
|
||||
resp = api.build_messages_and_create_chat_completion(
|
||||
user_prompt=gen_df_info_str,
|
||||
system_prompt=system_prompt,
|
||||
json_mode=True,
|
||||
json_target_type=Dict[str, str | bool | int],
|
||||
)
|
||||
resp_dict = json.loads(resp)
|
||||
resp_dict["output_format_decision"] = str(resp_dict["output_format_decision"]).lower() in ["true", "1"]
|
||||
|
||||
return (
|
||||
str(resp_dict["output_format_feedback"]),
|
||||
resp_dict["output_format_decision"],
|
||||
)
|
||||
except (KeyError, json.JSONDecodeError) as e:
|
||||
attempts += 1
|
||||
if attempts >= max_attempts:
|
||||
raise KeyError(
|
||||
"Wrong JSON Response or missing 'output_format_decision' or 'output_format_feedback' key after multiple attempts."
|
||||
) from e
|
||||
|
||||
return "Failed to evaluate output format after multiple attempts.", False
|
||||
|
||||
|
||||
class FactorDatetimeDailyEvaluator(FactorEvaluator):
|
||||
def evaluate(
|
||||
self,
|
||||
implementation: Workspace,
|
||||
gt_implementation: Workspace,
|
||||
) -> Tuple[str | object]:
|
||||
_, gen_df = self._get_df(gt_implementation, implementation)
|
||||
if gen_df is None:
|
||||
return "The source dataframe is None. Skip the evaluation of the datetime format.", False
|
||||
|
||||
if "datetime" not in gen_df.index.names:
|
||||
return "The source dataframe does not have a datetime index. Please check the implementation.", False
|
||||
|
||||
try:
|
||||
pd.to_datetime(gen_df.index.get_level_values("datetime"))
|
||||
except Exception:
|
||||
return (
|
||||
f"The source dataframe has a datetime index but it is not in the correct format (maybe a regular string or other objects). Please check the implementation.\n The head of the output dataframe is: \n{gen_df.head()}",
|
||||
False,
|
||||
)
|
||||
|
||||
time_diff = pd.to_datetime(gen_df.index.get_level_values("datetime")).to_series().diff().dropna()
|
||||
min_diff = time_diff.min()
|
||||
if min_diff <= pd.Timedelta(minutes=1):
|
||||
return (
|
||||
"The generated dataframe is not daily. The implementation is definitely wrong. Please check the implementation.",
|
||||
False,
|
||||
)
|
||||
if min_diff <= pd.Timedelta(minutes=30):
|
||||
return "The generated dataframe is intraday (1min bars). This is correct for EURUSD.", True
|
||||
return "The generated dataframe is daily.", True
|
||||
|
||||
|
||||
class FactorRowCountEvaluator(FactorEvaluator):
|
||||
def evaluate(
|
||||
self,
|
||||
implementation: Workspace,
|
||||
gt_implementation: Workspace,
|
||||
) -> Tuple[str, object]:
|
||||
gt_df, gen_df = self._get_df(gt_implementation, implementation)
|
||||
if gen_df is None:
|
||||
return (
|
||||
"The source dataframe is None. Please check the implementation.",
|
||||
False,
|
||||
)
|
||||
ratio = min(len(gen_df), len(gt_df)) / max(len(gen_df), len(gt_df))
|
||||
return (
|
||||
(
|
||||
f"The ratio of rows count in the source dataframe to the ground truth dataframe is {ratio:.2f}. "
|
||||
+ "Please verify the implementation. "
|
||||
if ratio <= 0.99
|
||||
else ""
|
||||
),
|
||||
ratio,
|
||||
)
|
||||
|
||||
|
||||
class FactorIndexEvaluator(FactorEvaluator):
|
||||
def evaluate(
|
||||
self,
|
||||
implementation: Workspace,
|
||||
gt_implementation: Workspace,
|
||||
) -> Tuple[str, object]:
|
||||
gt_df, gen_df = self._get_df(gt_implementation, implementation)
|
||||
if gen_df is None:
|
||||
return (
|
||||
"The source dataframe is None. Please check the implementation.",
|
||||
False,
|
||||
)
|
||||
gen_index_set, gt_index_set = set(gen_df.index), set(gt_df.index)
|
||||
similarity = len(gen_index_set.intersection(gt_index_set)) / len(gen_index_set.union(gt_index_set))
|
||||
return (
|
||||
(
|
||||
f"The source dataframe and the ground truth dataframe have different index with a similarity of {similarity:.2%}. The similarity is calculated by the number of shared indices divided by the union indices. "
|
||||
+ "Please check the implementation."
|
||||
if similarity <= 0.99
|
||||
else ""
|
||||
),
|
||||
similarity,
|
||||
)
|
||||
|
||||
|
||||
class FactorMissingValuesEvaluator(FactorEvaluator):
|
||||
def evaluate(
|
||||
self,
|
||||
implementation: Workspace,
|
||||
gt_implementation: Workspace,
|
||||
) -> Tuple[str, object]:
|
||||
gt_df, gen_df = self._get_df(gt_implementation, implementation)
|
||||
if gen_df is None:
|
||||
return (
|
||||
"The source dataframe is None. Please check the implementation.",
|
||||
False,
|
||||
)
|
||||
if gen_df.isna().sum().sum() == gt_df.isna().sum().sum():
|
||||
return "Both dataframes have the same missing values.", True
|
||||
else:
|
||||
return (
|
||||
f"The dataframes do not have the same missing values. The source dataframe has {gen_df.isna().sum().sum()} missing values, while the ground truth dataframe has {gt_df.isna().sum().sum()} missing values. Please check the implementation.",
|
||||
False,
|
||||
)
|
||||
|
||||
|
||||
class FactorEqualValueRatioEvaluator(FactorEvaluator):
|
||||
def evaluate(
|
||||
self,
|
||||
implementation: Workspace,
|
||||
gt_implementation: Workspace,
|
||||
) -> Tuple[str, object]:
|
||||
gt_df, gen_df = self._get_df(gt_implementation, implementation)
|
||||
if gen_df is None:
|
||||
return (
|
||||
"The source dataframe is None. Please check the implementation.",
|
||||
-1,
|
||||
)
|
||||
try:
|
||||
close_values = gen_df.sub(gt_df).abs().lt(1e-6)
|
||||
result_int = close_values.astype(int)
|
||||
pos_num = result_int.sum().sum()
|
||||
acc_rate = pos_num / close_values.size
|
||||
except:
|
||||
close_values = gen_df
|
||||
if close_values.all().iloc[0]:
|
||||
return (
|
||||
"All values in the dataframes are equal within the tolerance of 1e-6.",
|
||||
acc_rate,
|
||||
)
|
||||
else:
|
||||
return (
|
||||
"Some values differ by more than the tolerance of 1e-6. Check for rounding errors or differences in the calculation methods.",
|
||||
acc_rate,
|
||||
)
|
||||
|
||||
|
||||
class FactorCorrelationEvaluator(FactorEvaluator):
|
||||
def __init__(self, hard_check: bool, *args, **kwargs) -> None:
|
||||
super().__init__(*args, **kwargs)
|
||||
self.hard_check = hard_check
|
||||
|
||||
def evaluate(
|
||||
self,
|
||||
implementation: Workspace,
|
||||
gt_implementation: Workspace,
|
||||
) -> Tuple[str, object]:
|
||||
gt_df, gen_df = self._get_df(gt_implementation, implementation)
|
||||
if gen_df is None:
|
||||
return (
|
||||
"The source dataframe is None. Please check the implementation.",
|
||||
False,
|
||||
)
|
||||
concat_df = pd.concat([gen_df, gt_df], axis=1)
|
||||
concat_df.columns = ["source", "gt"]
|
||||
ic = concat_df.groupby("datetime").apply(lambda df: df["source"].corr(df["gt"])).dropna().mean()
|
||||
ric = (
|
||||
concat_df.groupby("datetime")
|
||||
.apply(lambda df: df["source"].corr(df["gt"], method="spearman"))
|
||||
.dropna()
|
||||
.mean()
|
||||
)
|
||||
|
||||
if self.hard_check:
|
||||
if ic > 0.99 and ric > 0.99:
|
||||
return (
|
||||
f"The dataframes are highly correlated. The ic is {ic:.6f} and the rankic is {ric:.6f}.",
|
||||
True,
|
||||
)
|
||||
else:
|
||||
return (
|
||||
f"The dataframes are not sufficiently high correlated. The ic is {ic:.6f} and the rankic is {ric:.6f}. Investigate the factors that might be causing the discrepancies and ensure that the logic of the factor calculation is consistent.",
|
||||
False,
|
||||
)
|
||||
else:
|
||||
return f"The ic is ({ic:.6f}) and the rankic is ({ric:.6f}).", ic
|
||||
|
||||
|
||||
class FactorValueEvaluator(FactorEvaluator):
|
||||
def evaluate(
|
||||
self,
|
||||
implementation: Workspace,
|
||||
gt_implementation: Workspace,
|
||||
version: int = 1, # 1 for qlib factors and 2 for kaggle factors
|
||||
**kwargs,
|
||||
) -> Tuple:
|
||||
conclusions = []
|
||||
|
||||
# Initialize result variables
|
||||
row_result = 0
|
||||
index_result = 0
|
||||
output_format_result = None
|
||||
equal_value_ratio_result = 0
|
||||
high_correlation_result = False
|
||||
row_result = None
|
||||
|
||||
# Check if both dataframe has only one columns Mute this since factor task might generate more than one columns now
|
||||
if version == 1:
|
||||
feedback_str, _ = FactorSingleColumnEvaluator(self.scen).evaluate(implementation, gt_implementation)
|
||||
conclusions.append(feedback_str)
|
||||
elif version == 2:
|
||||
input_shape = self.scen.input_shape
|
||||
_, gen_df = self._get_df(gt_implementation, implementation)
|
||||
if gen_df.shape[-1] > input_shape[-1]:
|
||||
conclusions.append(
|
||||
"Output dataframe has more columns than input feature which is not acceptable in feature processing tasks. Please check the implementation to avoid generating too many columns. Consider this implementation as a failure."
|
||||
)
|
||||
|
||||
feedback_str, inf_evaluate_res = FactorInfEvaluator(self.scen).evaluate(implementation, gt_implementation)
|
||||
conclusions.append(feedback_str)
|
||||
|
||||
# Check if the index of the dataframe is ("datetime", "instrument")
|
||||
feedback_str, _ = FactorOutputFormatEvaluator(self.scen).evaluate(implementation, gt_implementation)
|
||||
conclusions.append(feedback_str)
|
||||
if version == 1:
|
||||
feedback_str, daily_check_result = FactorDatetimeDailyEvaluator(self.scen).evaluate(
|
||||
implementation, gt_implementation
|
||||
)
|
||||
conclusions.append(feedback_str)
|
||||
else:
|
||||
daily_check_result = None
|
||||
|
||||
# Check dataframe format
|
||||
if gt_implementation is not None:
|
||||
feedback_str, row_result = FactorRowCountEvaluator(self.scen).evaluate(implementation, gt_implementation)
|
||||
conclusions.append(feedback_str)
|
||||
|
||||
feedback_str, index_result = FactorIndexEvaluator(self.scen).evaluate(implementation, gt_implementation)
|
||||
conclusions.append(feedback_str)
|
||||
|
||||
feedback_str, output_format_result = FactorMissingValuesEvaluator(self.scen).evaluate(
|
||||
implementation, gt_implementation
|
||||
)
|
||||
conclusions.append(feedback_str)
|
||||
|
||||
feedback_str, equal_value_ratio_result = FactorEqualValueRatioEvaluator(self.scen).evaluate(
|
||||
implementation, gt_implementation
|
||||
)
|
||||
conclusions.append(feedback_str)
|
||||
|
||||
if index_result > 0.99:
|
||||
feedback_str, high_correlation_result = FactorCorrelationEvaluator(
|
||||
hard_check=True, scen=self.scen
|
||||
).evaluate(implementation, gt_implementation)
|
||||
else:
|
||||
high_correlation_result = False
|
||||
feedback_str = "The source dataframe and the ground truth dataframe have different index. Give up comparing the values and correlation because it's useless"
|
||||
conclusions.append(feedback_str)
|
||||
|
||||
# Combine all conclusions into a single string
|
||||
conclusion_str = "\n".join(conclusions)
|
||||
|
||||
if gt_implementation is not None and (equal_value_ratio_result > 0.99) or high_correlation_result:
|
||||
decision_from_value_check = True
|
||||
elif (
|
||||
row_result is not None
|
||||
and row_result <= 0.99
|
||||
or output_format_result is False
|
||||
or daily_check_result is False
|
||||
or inf_evaluate_res is False
|
||||
):
|
||||
decision_from_value_check = False
|
||||
else:
|
||||
decision_from_value_check = None
|
||||
return conclusion_str, decision_from_value_check
|
||||
|
||||
|
||||
class FactorFinalDecisionEvaluator(FactorEvaluator):
|
||||
def evaluate(
|
||||
self,
|
||||
target_task: FactorTask,
|
||||
execution_feedback: str,
|
||||
value_feedback: str,
|
||||
code_feedback: str,
|
||||
**kwargs,
|
||||
) -> Tuple:
|
||||
system_prompt = T(".prompts:evaluator_final_decision_v1_system").r(
|
||||
scenario=(
|
||||
self.scen.get_scenario_all_desc(target_task, filtered_tag="feature")
|
||||
if self.scen is not None
|
||||
else "No scenario description."
|
||||
)
|
||||
)
|
||||
execution_feedback_to_render = execution_feedback
|
||||
|
||||
for _ in range(10): # 10 times to split the content is enough
|
||||
user_prompt = T(".prompts:evaluator_final_decision_v1_user").r(
|
||||
factor_information=target_task.get_task_information(),
|
||||
execution_feedback=execution_feedback_to_render,
|
||||
code_feedback=code_feedback,
|
||||
value_feedback=(
|
||||
value_feedback
|
||||
if value_feedback is not None
|
||||
else "No Ground Truth Value provided, so no evaluation on value is performed."
|
||||
),
|
||||
)
|
||||
if (
|
||||
APIBackend().build_messages_and_calculate_token(
|
||||
user_prompt=user_prompt,
|
||||
system_prompt=system_prompt,
|
||||
)
|
||||
> APIBackend().chat_token_limit
|
||||
):
|
||||
execution_feedback_to_render = execution_feedback_to_render[len(execution_feedback_to_render) // 2 :]
|
||||
else:
|
||||
break
|
||||
|
||||
# TODO: with retry_context(retry_n=3, except_list=[KeyError]):
|
||||
final_evaluation_dict = None
|
||||
attempts = 0
|
||||
max_attempts = 3
|
||||
|
||||
while attempts < max_attempts:
|
||||
try:
|
||||
api = APIBackend() if attempts == 0 else APIBackend(use_chat_cache=False)
|
||||
final_evaluation_dict = json.loads(
|
||||
api.build_messages_and_create_chat_completion(
|
||||
user_prompt=user_prompt,
|
||||
system_prompt=system_prompt,
|
||||
json_mode=True,
|
||||
seed=attempts, # in case of useless retrying when cache enabled.
|
||||
json_target_type=Dict[str, str | bool | int],
|
||||
),
|
||||
)
|
||||
final_decision = final_evaluation_dict["final_decision"]
|
||||
final_feedback = final_evaluation_dict["final_feedback"]
|
||||
|
||||
final_decision = str(final_decision).lower() in ["true", "1"]
|
||||
return final_decision, final_feedback
|
||||
|
||||
except json.JSONDecodeError as e:
|
||||
raise ValueError("Failed to decode JSON response from API.") from e
|
||||
except KeyError as e:
|
||||
attempts += 1
|
||||
if attempts >= max_attempts:
|
||||
raise KeyError(
|
||||
"Response from API is missing 'final_decision' or 'final_feedback' key after multiple attempts."
|
||||
) from e
|
||||
|
||||
return None, None
|
||||
@@ -1,42 +0,0 @@
|
||||
# How to read files.
|
||||
For example, if you want to read `filename.h5`
|
||||
```Python
|
||||
import pandas as pd
|
||||
df = pd.read_hdf("filename.h5", key="data")
|
||||
```
|
||||
NOTE: **key is always "data" for all hdf5 files **.
|
||||
|
||||
# Here is a short description about the data
|
||||
| Filename | Description |
|
||||
| -------------- | -----------------------------------------------------------------|
|
||||
| "intraday_pv.h5" | EURUSD 1-minute OHLCV intraday data (2020-2026). |
|
||||
|
||||
# For different data, We have some basic knowledge for them
|
||||
|
||||
## EURUSD 1min intraday data
|
||||
$open: open price of EURUSD at the start of the 1min bar.
|
||||
$close: close price of EURUSD at the end of the 1min bar.
|
||||
$high: highest price of EURUSD during the 1min bar.
|
||||
$low: lowest price of EURUSD during the 1min bar.
|
||||
$volume: traded volume during the 1min bar (tick volume for FX).
|
||||
|
||||
**IMPORTANT: There is NO $factor column. Use only $open, $close, $high, $low, $volume.**
|
||||
|
||||
## Market sessions (UTC)
|
||||
- Asian session: 00:00 - 08:00 (mean reversion tendencies)
|
||||
- London session: 08:00 - 16:00 (trending, momentum works)
|
||||
- NY session: 13:00 - 21:00 (high volatility)
|
||||
- London-NY overlap: 13:00 - 16:00 (highest volume)
|
||||
|
||||
## Lookback reference for 1min data
|
||||
- 4 bars = 4 minutes
|
||||
- 8 bars = 8 minutes
|
||||
- 16 bars = 16 minutes
|
||||
- 32 bars = 32 minutes
|
||||
- 96 bars = 1.6 hours
|
||||
- 1440 bars = 1 day (24 hours)
|
||||
|
||||
## Data range
|
||||
- Start: 2020-01-01 17:00:00 UTC
|
||||
- End: 2026-03-20 15:58:00 UTC
|
||||
- Total bars: ~2.26 million
|
||||
@@ -1,132 +0,0 @@
|
||||
import json
|
||||
from typing import List, Tuple
|
||||
|
||||
from rdagent.components.coder.factor_coder.factor import FactorExperiment, FactorTask
|
||||
from rdagent.components.proposal import FactorHypothesis2Experiment, FactorHypothesisGen
|
||||
from rdagent.core.proposal import Hypothesis, Scenario, Trace
|
||||
from rdagent.scenarios.qlib.experiment.factor_experiment import QlibFactorExperiment
|
||||
from rdagent.scenarios.qlib.experiment.model_experiment import QlibModelExperiment
|
||||
from rdagent.scenarios.qlib.experiment.quant_experiment import QlibQuantScenario
|
||||
from rdagent.utils.agent.tpl import T
|
||||
|
||||
QlibFactorHypothesis = Hypothesis
|
||||
|
||||
|
||||
class QlibFactorHypothesisGen(FactorHypothesisGen):
|
||||
def __init__(self, scen: Scenario) -> Tuple[dict, bool]:
|
||||
super().__init__(scen)
|
||||
|
||||
def prepare_context(self, trace: Trace) -> Tuple[dict, bool]:
|
||||
hypothesis_and_feedback = (
|
||||
T("scenarios.qlib.prompts:hypothesis_and_feedback").r(
|
||||
trace=trace,
|
||||
)
|
||||
if len(trace.hist) > 0
|
||||
else "No previous hypothesis and feedback available since it's the first round."
|
||||
)
|
||||
last_hypothesis_and_feedback = (
|
||||
T("scenarios.qlib.prompts:last_hypothesis_and_feedback").r(
|
||||
experiment=trace.hist[-1][0], feedback=trace.hist[-1][1]
|
||||
)
|
||||
if len(trace.hist) > 0
|
||||
else "No previous hypothesis and feedback available since it's the first round."
|
||||
)
|
||||
|
||||
context_dict = {
|
||||
"hypothesis_and_feedback": hypothesis_and_feedback,
|
||||
"last_hypothesis_and_feedback": last_hypothesis_and_feedback,
|
||||
"RAG": (
|
||||
"Try EURUSD-specific FX factors: momentum (4-32 bars), mean reversion, ATR volatility, volume spikes, session-based signals. Use only $open $close $high $low $volume columns. No $factor column exists."
|
||||
if len(trace.hist) < 15
|
||||
else "Now, you need to try factors that can achieve high IC (e.g., machine learning-based factors)."
|
||||
),
|
||||
"hypothesis_output_format": T("scenarios.qlib.prompts:factor_hypothesis_output_format").r(),
|
||||
"hypothesis_specification": T("scenarios.qlib.prompts:factor_hypothesis_specification").r(),
|
||||
}
|
||||
return context_dict, True
|
||||
|
||||
def convert_response(self, response: str) -> Hypothesis:
|
||||
response_dict = json.loads(response)
|
||||
hypothesis = QlibFactorHypothesis(
|
||||
hypothesis=response_dict.get("hypothesis"),
|
||||
reason=response_dict.get("reason"),
|
||||
concise_reason=response_dict.get("concise_reason"),
|
||||
concise_observation=response_dict.get("concise_observation"),
|
||||
concise_justification=response_dict.get("concise_justification"),
|
||||
concise_knowledge=response_dict.get("concise_knowledge"),
|
||||
)
|
||||
return hypothesis
|
||||
|
||||
|
||||
class QlibFactorHypothesis2Experiment(FactorHypothesis2Experiment):
|
||||
def prepare_context(self, hypothesis: Hypothesis, trace: Trace) -> Tuple[dict | bool]:
|
||||
if isinstance(trace.scen, QlibQuantScenario):
|
||||
scenario = trace.scen.get_scenario_all_desc(action="factor")
|
||||
else:
|
||||
scenario = trace.scen.get_scenario_all_desc()
|
||||
|
||||
experiment_output_format = T("scenarios.qlib.prompts:factor_experiment_output_format").r()
|
||||
|
||||
if len(trace.hist) == 0:
|
||||
hypothesis_and_feedback = "No previous hypothesis and feedback available since it's the first round."
|
||||
else:
|
||||
specific_trace = Trace(trace.scen)
|
||||
for i in range(len(trace.hist) - 1, -1, -1):
|
||||
if not hasattr(trace.hist[i][0].hypothesis, "action") or trace.hist[i][0].hypothesis.action == "factor":
|
||||
specific_trace.hist.insert(0, trace.hist[i])
|
||||
if len(specific_trace.hist) > 0:
|
||||
specific_trace.hist.reverse()
|
||||
hypothesis_and_feedback = T("scenarios.qlib.prompts:hypothesis_and_feedback").r(
|
||||
trace=specific_trace,
|
||||
)
|
||||
else:
|
||||
hypothesis_and_feedback = "No previous hypothesis and feedback available."
|
||||
|
||||
return {
|
||||
"target_hypothesis": str(hypothesis),
|
||||
"scenario": scenario,
|
||||
"hypothesis_and_feedback": hypothesis_and_feedback,
|
||||
"experiment_output_format": experiment_output_format,
|
||||
"target_list": [],
|
||||
"RAG": None,
|
||||
}, True
|
||||
|
||||
def convert_response(self, response: str, hypothesis: Hypothesis, trace: Trace) -> FactorExperiment:
|
||||
response_dict = json.loads(response)
|
||||
tasks = []
|
||||
|
||||
for factor_name in response_dict:
|
||||
description = response_dict[factor_name]["description"]
|
||||
formulation = response_dict[factor_name]["formulation"]
|
||||
variables = response_dict[factor_name]["variables"]
|
||||
tasks.append(
|
||||
FactorTask(
|
||||
factor_name=factor_name,
|
||||
factor_description=description,
|
||||
factor_formulation=formulation,
|
||||
variables=variables,
|
||||
)
|
||||
)
|
||||
|
||||
exp = QlibFactorExperiment(tasks, hypothesis=hypothesis)
|
||||
exp.based_experiments = [QlibFactorExperiment(sub_tasks=[])] + [
|
||||
t[0] for t in trace.hist if t[1] and isinstance(t[0], FactorExperiment)
|
||||
]
|
||||
|
||||
unique_tasks = []
|
||||
for task in tasks:
|
||||
duplicate = False
|
||||
for based_exp in exp.based_experiments:
|
||||
if isinstance(based_exp, QlibModelExperiment):
|
||||
continue
|
||||
for sub_task in based_exp.sub_tasks:
|
||||
if task.factor_name == sub_task.factor_name:
|
||||
duplicate = True
|
||||
break
|
||||
if duplicate:
|
||||
break
|
||||
if not duplicate:
|
||||
unique_tasks.append(task)
|
||||
|
||||
exp.tasks = unique_tasks
|
||||
return exp
|
||||
@@ -1,21 +0,0 @@
|
||||
import subprocess
|
||||
import sys
|
||||
import os
|
||||
|
||||
# Qlib läuft in rdagent4qlib environment
|
||||
result = subprocess.run(
|
||||
["/home/nico/miniconda3/envs/rdagent4qlib/bin/python3", "-c", """
|
||||
import qlib
|
||||
from qlib.data import D
|
||||
qlib.init(provider_uri="~/.qlib/qlib_data/eurusd_1min_data")
|
||||
fields = ["$open", "$close", "$high", "$low", "$volume"]
|
||||
data = (D.features(["EURUSD"], fields, start_time="2022-03-14", end_time="2026-03-20", freq="1min")
|
||||
.swaplevel().sort_index())
|
||||
data.to_hdf("./intraday_pv_all.h5", key="data")
|
||||
data_debug = (D.features(["EURUSD"], fields, start_time="2024-01-01", end_time="2026-03-20", freq="1min")
|
||||
.swaplevel().sort_index())
|
||||
data_debug.to_hdf("./intraday_pv_debug.h5", key="data")
|
||||
print(f"Done: {data.shape[0]} rows")
|
||||
"""],
|
||||
capture_output=False
|
||||
)
|
||||
@@ -1,257 +0,0 @@
|
||||
qlib_quant_background: |-
|
||||
Quantitative investment is a data-driven approach to asset management that relies on mathematical models, statistical techniques, and computational methods to analyze financial markets and make investment decisions. Two essential components of this approach are factors and models.
|
||||
|
||||
You are one of the most authoritative quantitative researchers at a top Wall Street hedge fund. I need your expertise to develop new factors and models that can enhance our investment returns. Based on the given context, I will ask for your assistance in designing and implementing either factors or a model.
|
||||
|
||||
{% if runtime_environment is not none %}
|
||||
====== Runtime Environment ======
|
||||
You have following environment to run the code:
|
||||
{{ runtime_environment }}
|
||||
{% endif %}
|
||||
|
||||
qlib_factor_background: |-
|
||||
The factor is a characteristic or variable used in quant investment that can help explain the returns and risks of a portfolio or a single asset. Factors are used by investors to identify and exploit sources of excess returns, and they are central to many quantitative investment strategies.
|
||||
Each number in the factor represents a physics value to an instrument on a day.
|
||||
User will train a model to predict the next several days return based on the factor values of the previous days.
|
||||
The factor is defined in the following parts:
|
||||
1. Name: The name of the factor.
|
||||
2. Description: The description of the factor.
|
||||
3. Formulation: The formulation of the factor.
|
||||
4. Variables: The variables or functions used in the formulation of the factor.
|
||||
The factor might not provide all the parts of the information above since some might not be applicable.
|
||||
Please specifically give all the hyperparameter in the factors like the window size, look back period, and so on. One factor should statically defines one output with a static source data. For example, last 10 days momentum and last 20 days momentum should be two different factors.
|
||||
|
||||
{% if runtime_environment is not none %}
|
||||
====== Runtime Environment ======
|
||||
You have following environment to run the code:
|
||||
{{ runtime_environment }}
|
||||
{% endif %}
|
||||
|
||||
qlib_factor_interface: |-
|
||||
Your python code should follow the interface to better interact with the user's system.
|
||||
CRITICAL DATA FORMAT: The HDF5 file has a MultiIndex with levels ['datetime', 'instrument']. The instrument is an INDEX LEVEL, NOT a column. Never use df['instrument']. Always use df.index.get_level_values('instrument') or df.groupby(level='instrument'). For rolling calculations use df['$close'].unstack(level='instrument'), apply rolling, then .stack() to restore MultiIndex.
|
||||
Your python code should contain the following part: the import part, the function part, and the main part. You should write a main function name: "calculate_{function_name}" and call this function in "if __name__ == __main__" part. Don't write any try-except block in your python code. The user will catch the exception message and provide the feedback to you.
|
||||
User will write your python code into a python file and execute the file directly with "python {your_file_name}.py". You should calculate the factor values and save the result into a HDF5(H5) file named "result.h5" in the same directory as your python file. The result file is a HDF5(H5) file containing a pandas dataframe. The index of the dataframe is the "datetime" and "instrument", and the single column name is the factor name,and the value is the factor value. The result file should be saved in the same directory as your python file.
|
||||
|
||||
qlib_factor_strategy: |-
|
||||
Ensure that for every step of data processing, the data format (including indexes) is clearly explained through comments.
|
||||
Each transformation or calculation should be accompanied by a detailed description of how the data is structured, especially focusing on key aspects like whether the data has multi-level indexing, how to access specific columns or index levels, and any operations that affect the data shape (e.g., `reset_index()`, `groupby()`, `merge()`).
|
||||
This step-by-step explanation will ensure clarity and accuracy in data handling. For example:
|
||||
1. **Start with multi-level index**:
|
||||
```python
|
||||
# The initial DataFrame has a multi-level index with 'datetime' and 'instrument'.
|
||||
# To access the 'datetime' index, use df.index.get_level_values('datetime').
|
||||
datetime_values = df.index.get_level_values('datetime')
|
||||
```
|
||||
|
||||
2. **Reset the index if necessary**:
|
||||
```python
|
||||
# Resetting the index to move 'datetime' and 'instrument' from the index to columns.
|
||||
# This operation flattens the multi-index structure.
|
||||
df = df.reset_index()
|
||||
```
|
||||
|
||||
3. **Perform groupby operations**:
|
||||
```python
|
||||
# Grouping by 'datetime' and 'instrument' to aggregate the data.
|
||||
# After groupby, the result will maintain 'datetime' and 'instrument' as a multi-level index.
|
||||
df_grouped = df.groupby(['datetime', 'instrument']).sum()
|
||||
```
|
||||
|
||||
4. **Ensure consistent datetime formats**:
|
||||
```python
|
||||
# Before merging, ensure that the 'datetime' column in both DataFrames is of the same format.
|
||||
# Convert to datetime format if necessary.
|
||||
df['datetime'] = pd.to_datetime(df['datetime'])
|
||||
other_df['datetime'] = pd.to_datetime(other_df['datetime'])
|
||||
```
|
||||
|
||||
5. **Merge operations**:
|
||||
```python
|
||||
# When merging DataFrames, ensure you are merging on both 'datetime' and 'instrument'.
|
||||
# If these are part of the index, reset the index before merging.
|
||||
merged_df = pd.merge(df, other_df, on=['datetime', 'instrument'], how='inner')
|
||||
```
|
||||
|
||||
qlib_factor_output_format: |-
|
||||
Your output should be a pandas dataframe similar to the following example information:
|
||||
<class 'pandas.core.frame.DataFrame'>
|
||||
MultiIndex: 2261923 entries, (Timestamp('2020-01-01 17:00:00'), 'EURUSD') to (Timestamp('2026-03-20 15:58:00'), 'EURUSD')
|
||||
Data columns (total 1 columns):
|
||||
# Column Non-Null Count Dtype
|
||||
--- ------ -------------- -----
|
||||
0 your factor name 2261923 non-null float64
|
||||
dtypes: float64(1)
|
||||
memory usage: <ignore>
|
||||
Notice: The non-null count is OK to be different to the total number of entries since some instruments may not have the factor value on some days.
|
||||
One possible format of `result.h5` may be like following:
|
||||
datetime instrument
|
||||
2020-01-01 EURUSD 1.094240
|
||||
2020-01-02 EURUSD 1.094280
|
||||
2020-01-03 EURUSD 1.095920
|
||||
...
|
||||
2026-03-20 EURUSD 1.083150
|
||||
|
||||
qlib_factor_simulator: |-
|
||||
The factors will be sent into Qlib to train a model to predict the next several days return based on the factor values of the previous days.
|
||||
Qlib is an AI-oriented quantitative investment platform that aims to realize the potential, empower research, and create value using AI technologies in quantitative investment, from exploring ideas to implementing productions. Qlib supports diverse machine learning modeling paradigms. including supervised learning, market dynamics modeling, and RL.
|
||||
User will use Qlib to automatically do the following things:
|
||||
1. generate a new factor table based on the factor values.
|
||||
2. train a model like LightGBM, CatBoost, LSTM or simple PyTorch model to predict the next several days return based on the factor values.
|
||||
3. build a portfolio based on the predicted return based on a strategy.
|
||||
4. evaluate the portfolio's performance including the return, sharpe ratio, max drawdown, and so on.
|
||||
|
||||
qlib_factor_rich_style_description : |-
|
||||
### R&D Agent-Qlib: Automated Quantitative Trading & Iterative Factors Evolution Demo
|
||||
|
||||
#### [Overview](#_summary)
|
||||
|
||||
The demo showcases the iterative process of hypothesis generation, knowledge construction, and decision-making. It highlights how financial factors evolve through continuous feedback and refinement.
|
||||
|
||||
#### [Automated R&D](#_rdloops)
|
||||
|
||||
- **[R (Research)](#_research)**
|
||||
- Iterative development of ideas and hypotheses.
|
||||
- Continuous learning and knowledge construction.
|
||||
|
||||
- **[D (Development)](#_development)**
|
||||
- Progressive implementation and code generation of factors.
|
||||
- Automated testing and validation of financial factors.
|
||||
|
||||
#### [Objective](#_summary)
|
||||
|
||||
To demonstrate the dynamic evolution of financial factors through the Qlib platform, emphasizing how each iteration enhances the accuracy and reliability of the resulting financial factors.
|
||||
|
||||
qlib_factor_from_report_rich_style_description : |-
|
||||
### R&D Agent-Qlib: Automated Quantitative Trading & Factor Extraction from Financial Reports Demo
|
||||
|
||||
#### [Overview](#_summary)
|
||||
|
||||
This demo showcases the process of extracting factors from financial research reports, implementing these factors, and analyzing their performance through Qlib backtest, continually expanding and refining the factor library.
|
||||
|
||||
#### [Automated R&D](#_rdloops)
|
||||
|
||||
- **[R (Research)](#_research)**
|
||||
- Iterative development of ideas and hypotheses from financial reports.
|
||||
- Continuous learning and knowledge construction.
|
||||
|
||||
- **[D (Development)](#_development)**
|
||||
- Progressive factor extraction and code generation.
|
||||
- Automated implementation and testing of financial factors.
|
||||
|
||||
#### [Objective](#_summary)
|
||||
|
||||
<table border="1" style="width:100%; border-collapse: collapse;">
|
||||
<tr>
|
||||
<td>💡 <strong>Innovation </strong></td>
|
||||
<td>Tool to quickly extract and test factors from research reports.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>⚡ <strong>Efficiency </strong></td>
|
||||
<td>Rapid identification of valuable factors from numerous reports.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>🗃️ <strong>Outputs </strong></td>
|
||||
<td>Expand and refine the factor library to support further research.</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
qlib_factor_experiment_setting: |-
|
||||
| Dataset 📊 | Model 🤖 | Factors 🌟 | Data Split 🧮 |
|
||||
|---------|----------|---------------|-------------------------------------------------|
|
||||
| EURUSD | LGBModel | Alpha158 Plus | Train: 2022-01-01 to 2024-06-30 <br> Valid: 2024-07-01 to 2024-12-31 <br> Test : 2025-01-01 to 2026-03-20 |
|
||||
|
||||
|
||||
qlib_model_background: |-
|
||||
The model is a machine learning or deep learning structure used in quantitative investment to predict the returns and risks of a portfolio or a single asset. Models are employed by investors to generate forecasts based on historical data and identified factors, which are central to many quantitative investment strategies.
|
||||
Each model takes the factors as input and predicts the future returns. Usually, the bigger the model is, the better the performance would be.
|
||||
The model is defined in the following parts:
|
||||
1. Name: The name of the model.
|
||||
2. Description: The description of the model.
|
||||
3. Architecture: The detailed architecture of the model, such as neural network layers or tree structures.
|
||||
4. Hyperparameters: The hyperparameters used in the model.
|
||||
5. Training_hyperparameters: The hyperparameters used during the training process.
|
||||
6. ModelType: The type of the model, "Tabular" for tabular model and "TimeSeries" for time series model.
|
||||
The model should provide clear and detailed documentation of its architecture and hyperparameters. One model should statically define one output with a fixed architecture and hyperparameters.
|
||||
|
||||
{% if runtime_environment is not none %}
|
||||
====== Runtime Environment ======
|
||||
You have following environment to run the code:
|
||||
{{ runtime_environment }}
|
||||
{% endif %}
|
||||
|
||||
qlib_model_interface: |-
|
||||
Your python code should follow the interface to better interact with the user's system.
|
||||
You code should contain several parts:
|
||||
1. The import part: import the necessary libraries.
|
||||
2. A class which is a sub-class of pytorch.nn.Module. This class should should have a init function and a forward function which inputs a tensor and outputs a tensor.
|
||||
3. Set a variable called "model_cls" to the class you defined.
|
||||
|
||||
The user will save your code into a python file called "model.py". Then the user imports model_cls in file "model.py" after setting the cwd into the directory:
|
||||
```python
|
||||
from model import model_cls
|
||||
```
|
||||
So your python code should follow the pattern:
|
||||
```python
|
||||
class XXXModel(torch.nn.Module):
|
||||
...
|
||||
model_cls = XXXModel
|
||||
```
|
||||
|
||||
The model can be configured as either "Tabular" for tabular models or "TimeSeries" for time series models. For a tabular model, the input shape is (batch_size, num_features), while for a time series model, the input shape is (batch_size, num_timesteps, num_features). In both cases, the output shape of the model should be (batch_size, 1).
|
||||
`num_features` will be directly set for the model based on the input data shape.
|
||||
User will initialize the tabular model with the following code:
|
||||
```python
|
||||
model = model_cls(num_features=num_features)
|
||||
```
|
||||
User will initialize the time series model with the following code:
|
||||
```python
|
||||
model = model_cls(num_features=num_features, num_timesteps=num_timesteps)
|
||||
```
|
||||
No other parameters will be passed to the model so give other parameters a default value or just make them static.
|
||||
|
||||
Don't write any try-except block in your python code. The user will catch the exception message and provide the feedback to you. Also, don't write main function in your python code. The user will call the forward method in the model_cls to get the output tensor.
|
||||
|
||||
Please notice that your model should only use current features as input. The user will provide the input tensor to the model's forward function.
|
||||
|
||||
|
||||
qlib_model_output_format: |-
|
||||
Your output should be a tensor with shape (batch_size, 1).
|
||||
The output tensor should be saved in a file named "output.pth" in the same directory as your python file.
|
||||
The user will evaluate the shape of the output tensor so the tensor read from "output.pth" should be 8 numbers.
|
||||
|
||||
qlib_model_simulator: |-
|
||||
The models will be sent into Qlib to train and evaluate their performance in predicting future returns. Hypothesis is improved upon checking the feedback on the results.
|
||||
Qlib is an AI-oriented quantitative investment platform that aims to realize the potential, empower research, and create value using AI technologies in quantitative investment, from exploring ideas to implementing productions. Qlib supports diverse machine learning modeling paradigms, including supervised learning, market dynamics modeling, and reinforcement learning (RL).
|
||||
User will use Qlib to automatically perform the following tasks:
|
||||
1. Generate a baseline factor table.
|
||||
2. Train the model defined in your class Net to predict the next several days' returns based on the factor values.
|
||||
3. Build a portfolio based on the predicted returns using a specific strategy.
|
||||
4. Evaluate the portfolio's performance, including metrics such as return, IC, max drawdown, and others.
|
||||
5. Iterate on growing the hypothesis to enable model improvements based on performance evaluations and feedback.
|
||||
|
||||
qlib_model_rich_style_description: |-
|
||||
### Qlib Model Evolving Automatic R&D Demo
|
||||
|
||||
#### [Overview](#_summary)
|
||||
|
||||
The demo showcases the iterative process of hypothesis generation, knowledge construction, and decision-making in model construction in quantitative finance. It highlights how models evolve through continuous feedback and refinement.
|
||||
|
||||
#### [Automated R&D](#_rdloops)
|
||||
|
||||
- **[R (Research)](#_research)**
|
||||
- Iteration of ideas and hypotheses.
|
||||
- Continuous learning and knowledge construction.
|
||||
|
||||
- **[D (Development)](#_development)**
|
||||
- Evolving code generation and model refinement.
|
||||
- Automated implementation and testing of models.
|
||||
|
||||
#### [Objective](#_summary)
|
||||
|
||||
To demonstrate the dynamic evolution of models through the Qlib platform, emphasizing how each iteration enhances the accuracy and reliability of the resulting models.
|
||||
|
||||
qlib_model_experiment_setting: |-
|
||||
| Dataset 📊 | Model 🤖 | Factors 🌟 | Data Split 🧮 |
|
||||
|---------|----------|---------------|-------------------------------------------------|
|
||||
| EURUSD | RDAgent-dev | 20 factors (Alpha158) | Train: 2022-01-01 to 2024-06-30 <br> Valid: 2024-07-01 to 2024-12-31 <br> Test : 2025-01-01 to 2026-03-20 |
|
||||
@@ -1,23 +0,0 @@
|
||||
hypothesis_generation:
|
||||
system: |-
|
||||
You are an expert in FX and quantitative trading, specialized in EURUSD intraday strategies.
|
||||
Your task is to generate a well-reasoned hypothesis for new alpha factors based on EURUSD 1min OHLCV data.
|
||||
|
||||
Key market knowledge:
|
||||
- EURUSD trades 24h with three main sessions: Asian (00:00-08:00 UTC), London (08:00-16:00 UTC), NY (13:00-21:00 UTC)
|
||||
- London-NY overlap (13:00-16:00 UTC) has highest volume and momentum
|
||||
- Asian session shows mean reversion tendencies
|
||||
- Spread costs approximately 1.5 bps per trade — avoid overtrading
|
||||
- No overnight gap risk like stocks, but weekend gaps exist
|
||||
- Volume spikes signal news events (NFP, ECB, Fed)
|
||||
|
||||
Please ensure your response is in JSON format as shown below:
|
||||
{
|
||||
"hypothesis": "A clear and concise hypothesis based on the provided information.",
|
||||
"reason": "A detailed explanation supporting the generated hypothesis.",
|
||||
}
|
||||
user: |-
|
||||
The following are the financial factors and their descriptions:
|
||||
{{ factor_descriptions }}
|
||||
The report content is as follows:
|
||||
{{ report_content }}
|
||||
@@ -1,312 +0,0 @@
|
||||
hypothesis_and_feedback: |-
|
||||
=========================================================
|
||||
{% for experiment, feedback in trace.hist %}
|
||||
# Trial {{ loop.index }}:
|
||||
## Hypothesis
|
||||
{{ experiment.hypothesis }}
|
||||
## Specific task:
|
||||
{% for task in experiment.sub_tasks %}
|
||||
{% if task is not none and task.get_task_brief_information is defined %}
|
||||
{{ task.get_task_brief_information() }}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
## Backtest Analysis and Feedback:
|
||||
{% if experiment.result is not none %}
|
||||
Backtest Result: {{ experiment.result.loc[["IC", "1day.excess_return_without_cost.annualized_return", "1day.excess_return_without_cost.max_drawdown"]] }}
|
||||
{% endif %}
|
||||
Observation: {{ feedback.observations }}
|
||||
Hypothesis Evaluation: {{ feedback.hypothesis_evaluation }}
|
||||
Decision (Whether the hypothesis was successful): {{ feedback.decision }}
|
||||
=========================================================
|
||||
{% endfor %}
|
||||
|
||||
last_hypothesis_and_feedback: |-
|
||||
## Hypothesis
|
||||
{{ experiment.hypothesis }}
|
||||
## Specific task:
|
||||
{% for task in experiment.sub_tasks %}
|
||||
{% if task is not none and task.get_task_brief_information is defined %}
|
||||
{{ task.get_task_brief_information() }}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
## Backtest Analysis and Feedback:
|
||||
{% if experiment.result is not none %}
|
||||
Backtest Result: {{ experiment.result.loc[["IC", "1day.excess_return_without_cost.annualized_return", "1day.excess_return_without_cost.max_drawdown"]] }}
|
||||
{% endif %}
|
||||
Training Log:
|
||||
Here, you need to focus on analyzing whether there are any issues with the training. If any problems are identified, you must correct them in the next iteration and clearly describe how the changes will be made in the hypothesis.
|
||||
{{ experiment.stdout }}
|
||||
Observation: {{ feedback.observations }}
|
||||
Evaluation: {{ feedback.hypothesis_evaluation }}
|
||||
Decision (Whether this experiment is SOTA): {{ feedback.decision }}
|
||||
New Hypothesis (Given in feedback stage, just for reference, and can be accepted or rejected in the next round): {{ feedback.new_hypothesis }}
|
||||
Reasoning (Justification for the new hypothesis): {{ feedback.reason }}
|
||||
|
||||
sota_hypothesis_and_feedback: |-
|
||||
## Hypothesis
|
||||
{{ experiment.hypothesis }}
|
||||
## Specific task:
|
||||
{% for task in experiment.sub_tasks %}
|
||||
{% if task is not none and task.get_task_brief_information is defined %}
|
||||
{{ task.get_task_brief_information() }}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
## Backtest Analysis and Feedback:
|
||||
{% if experiment.result is not none %}
|
||||
Backtest Result: {{ experiment.result.loc[["IC", "1day.excess_return_without_cost.annualized_return", "1day.excess_return_without_cost.max_drawdown"]] }}
|
||||
{% endif %}
|
||||
Training Log: {{ experiment.stdout }}
|
||||
Observation: {{ feedback.observations }}
|
||||
Evaluation: {{ feedback.hypothesis_evaluation }}
|
||||
Decision (Whether this experiment is SOTA): {{ feedback.decision }}
|
||||
|
||||
hypothesis_output_format: |-
|
||||
The output should follow JSON format. The schema is as follows:
|
||||
{
|
||||
"hypothesis": "An exact, testable, and innovative statement derived from previous experimental trace analysis. Avoid overly general ideas and ensure precision. The hypothesis should clearly specify the exact approach and expected improvement in performance in two or three sentences.",
|
||||
"reason": "Provide a clear, logical explanation for why this hypothesis was proposed, grounded in evidence (e.g., trace history, domain principles). Reason should be short with no more than two sentences.",
|
||||
}
|
||||
|
||||
factor_hypothesis_output_format: |-
|
||||
The output should follow JSON format. The schema is as follows:
|
||||
{
|
||||
"hypothesis": "The new hypothesis generated based on the information provided. Limit in two or three sentences.",
|
||||
"reason": "The reason why you generate this hypothesis. It should be comprehensive and logical. It should cover the other keys below and extend them. Limit in two or three sentences.",
|
||||
}
|
||||
|
||||
hypothesis_output_format_with_action: |-
|
||||
The output should follow JSON format. The schema is as follows:
|
||||
{
|
||||
"action": "If `hypothesis_specification` provides the action you need to take, please follow "hypothesis_specification" to choose the action. Otherwise, based on previous experimental results, suggest the action you believe is most appropriate at the moment. It should be one of [`factor`, `model`].",
|
||||
"hypothesis": "The new hypothesis generated based on the information provided,should be a string.",
|
||||
"reason": "The reason why you generate this hypothesis. It should be comprehensive and logical. It should cover the other keys below and extend them. Limit in two or three sentences.",
|
||||
}
|
||||
|
||||
model_hypothesis_specification: |-
|
||||
1. First, observe and analyze the overall experimental progression in `hypothesis_and_feedback`. Analyze where the previous model designs were inadequate — whether it was due to parameter settings, architectural flaws, or a lack of novelty (proposing entirely new concepts is highly encouraged as long as they demonstrate effectiveness).
|
||||
2. Second, `last_hypothesis_and_feedback` and `sota_hypothesis_and_feedback` are key references you should pay close attention to. You can choose to optimize based on either of them or generate new ideas to form hypotheses and experiments.
|
||||
3. If there is no prior experiment or result available at the beginning, you can start by implementing a simple and small architecture.
|
||||
4. If a series of attempts fail to achieve SOTA, consider exploring entirely new directions; at this point, it is acceptable to return to simple architectures.
|
||||
5. Focus exclusively on the architecture of PyTorch models. Each hypothesis should specifically address architectural decisions, such as layer configurations, activation functions, regularization methods, and overall model structure. DO NOT do any feature-specific processing. Instead, you can propose innovative transformations on the input time-series data to enhance model training effectiveness.
|
||||
6. Avoid including aspects unrelated to architecture, such as input features or optimization strategies.
|
||||
7. Sometimes, when training performance is poor, adjusting hyperparameters can also be an effective strategy for improvement.
|
||||
8. Use standard libraries for baseline models, but also explore custom architecture designs to investigate novel structures. After sufficient trials with traditional models, aim for innovation comparable to top-tier AI conferences (NeurIPS, ICLR, ICML, SIGKDD, etc.) in time series modeling.
|
||||
|
||||
factor_hypothesis_specification: |-
|
||||
You are developing alpha factors for EURUSD intraday trading using 1-MINUTE OHLCV bars.
|
||||
|
||||
**Market Context:**
|
||||
- EURUSD trades 24h with three sessions: Asian (00:00-08:00 UTC), London (08:00-16:00 UTC), NY (13:00-21:00 UTC)
|
||||
- London-NY overlap (13:00-16:00 UTC) has highest volume and trending behavior
|
||||
- Asian session shows mean reversion tendencies
|
||||
- Spread cost ~1.5 bps per trade — avoid high-turnover factors
|
||||
- No $factor column exists — use only $open, $close, $high, $low, $volume
|
||||
- Each "instrument" is EURUSD, each "day" has 96 bars (24h * 60min = 1440 minutes / 15min bars was wrong, correct is 1440 1min bars)
|
||||
- Bar interpretation: 4 bars = 4 minutes, 16 bars = 16 minutes, 96 bars = 1.6 hours
|
||||
|
||||
**Factor Generation Rules:**
|
||||
1. **3-5 Factors per Generation** — cover different signal types per round
|
||||
2. **FX-Specific Signals First:**
|
||||
- Momentum: price change over last N bars (N=4,8,16,32 = 1h,2h,4h,8h)
|
||||
- Mean Reversion: deviation from rolling mean, Bollinger Band position
|
||||
- Volatility: ATR, realized vol, high-low range normalized
|
||||
- Volume: volume spike ratio, volume trend
|
||||
- Session: time-of-day encoded signals (London open, NY open)
|
||||
3. **Gradual Complexity:**
|
||||
- Rounds 1-5: single indicators (RSI, momentum, ATR)
|
||||
- Rounds 6-15: combined signals (momentum + volume filter)
|
||||
- Rounds 15+: ML-based factors (LSTM embeddings, XGBoost residuals)
|
||||
4. **Avoid:**
|
||||
- Factors requiring $factor column
|
||||
- Daily-frequency assumptions (no overnight gaps in logic)
|
||||
- Factors with >100 bar lookback without justification
|
||||
5. No matter how many factors you plan to generate, only reply with one set of hypothesis and reason.
|
||||
|
||||
factor_experiment_output_format: |-
|
||||
The output should follow JSON format. The schema is as follows:
|
||||
{
|
||||
"factor name 1": {
|
||||
"description": "description of factor 1, start with its type, e.g. [Momentum Factor]",
|
||||
"formulation": "latex formulation of factor 1",
|
||||
"variables": {
|
||||
"variable or function name 1": "description of variable or function 1",
|
||||
"variable or function name 2": "description of variable or function 2"
|
||||
}
|
||||
},
|
||||
"factor name 2": {
|
||||
"description": "description of factor 2, start with its type, e.g. [Machine Learning based Factor]",
|
||||
"formulation": "latex formulation of factor 2",
|
||||
"variables": {
|
||||
"variable or function name 1": "description of variable or function 1",
|
||||
"variable or function name 2": "description of variable or function 2"
|
||||
}
|
||||
}
|
||||
# Don't add ellipsis (...) or any filler text that might cause JSON parsing errors here!
|
||||
}
|
||||
|
||||
model_experiment_output_format: |-
|
||||
So far please only design one model to test the hypothesis!
|
||||
The output should follow JSON format. The schema is as follows (value in training_hyperparameters is a basic setting for reference, you CAN CHANGE depends on the previous training log):
|
||||
{
|
||||
"model_name (The name of the model)": {
|
||||
"description": "A detailed description of the model",
|
||||
"formulation": "A LaTeX formula representing the model's formulation",
|
||||
"architecture": "A detailed description of the model's architecture, e.g., neural network layers or tree structures",
|
||||
"variables": {
|
||||
"\\hat{y}_u": "The predicted output for node u",
|
||||
"variable_name_2": "Description of variable 2",
|
||||
"variable_name_3": "Description of variable 3"
|
||||
},
|
||||
"hyperparameters": {
|
||||
"hyperparameter_name_1": "value of hyperparameter 1",
|
||||
"hyperparameter_name_2": "value of hyperparameter 2",
|
||||
"hyperparameter_name_3": "value of hyperparameter 3"
|
||||
},
|
||||
"training_hyperparameters" { # All values are for reference; you can set them yourself
|
||||
"n_epochs": "100",
|
||||
"lr": "1e-3",
|
||||
"early_stop": 10,
|
||||
"batch_size": 256,
|
||||
"weight_decay": 1e-4,
|
||||
}
|
||||
"model_type": "Tabular or TimeSeries" # Should be one of "Tabular" or "TimeSeries"
|
||||
},
|
||||
}
|
||||
|
||||
factor_feedback_generation:
|
||||
system: |-
|
||||
You are a professional FX quantitative analyst specializing in EURUSD intraday strategies.
|
||||
The task is described in the following scenario:
|
||||
|
||||
{{ scenario }}
|
||||
|
||||
You will receive a hypothesis, multiple tasks with their factors, their results, and the SOTA result.
|
||||
Your feedback should specify whether the current result supports or refutes the hypothesis, compare it with previous SOTA results, and suggest FX-specific improvements.
|
||||
|
||||
**FX-specific evaluation criteria:**
|
||||
- IC > 0.02 is meaningful for 1min EURUSD data
|
||||
- Annualized return target: >9.62% (current SOTA to beat)
|
||||
- Spread cost ~1.5 bps per trade — penalize high-turnover factors
|
||||
- Factors using $factor column are INVALID — only $open $close $high $low $volume allowed
|
||||
- Session-aware factors (London/NY) tend to outperform session-agnostic ones
|
||||
- Mean reversion works in Asian session, momentum in London-NY overlap
|
||||
|
||||
Please understand the following operation logic:
|
||||
1. Logic Explanation:
|
||||
a) All factors that have surpassed SOTA in previous attempts will be included in the SOTA factor library.
|
||||
b) New experiments will generate new factors, combined with the SOTA library factors.
|
||||
c) These combined factors will be backtested and compared against current SOTA.
|
||||
2. Development Directions:
|
||||
a) New Direction: Propose a new FX-specific factor (session filter, volatility regime, volume spike).
|
||||
b) Optimization: Refine lookback windows (4/8/16/32 bars), add ADX filter, adjust for spread costs.
|
||||
3. Final Goal: Beat 9.62% ARR on EURUSD 1min with controlled drawdown (<20%).
|
||||
|
||||
When judging results:
|
||||
1. Any small improvement in annualized return → set Replace Best Result as yes.
|
||||
2. If IC < 0 consistently → factor has no predictive power, change direction entirely.
|
||||
3. High turnover with low return → add volume or volatility filter to reduce trade frequency.
|
||||
|
||||
Respond in JSON format:
|
||||
{
|
||||
"Observations": "Your overall observations here",
|
||||
"Feedback for Hypothesis": "Observations related to the hypothesis",
|
||||
"New Hypothesis": "Your new FX-specific hypothesis here",
|
||||
"Reasoning": "Reasoning for the new hypothesis",
|
||||
"Replace Best Result": "yes or no"
|
||||
}
|
||||
user: |-
|
||||
Target hypothesis:
|
||||
{{ hypothesis_text }}
|
||||
Tasks and Factors:
|
||||
{% for task in task_details %}
|
||||
- {{ task.factor_name }}: {{ task.factor_description }}
|
||||
- Factor Formulation: {{ task.factor_formulation }}
|
||||
- Variables: {{ task.variables }}
|
||||
- Factor Implementation: {{ task.factor_implementation }}
|
||||
{% if task.factor_implementation == "False" %}
|
||||
**Note: This factor was not implemented in the current experiment. Only the hypothesis for implemented factors can be verified.**
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
Combined Results:
|
||||
{{ combined_result }}
|
||||
|
||||
Analyze the combined result in the context of its ability to:
|
||||
1. Support or refute the hypothesis.
|
||||
2. Show improvement or deterioration compared to the SOTA experiment.
|
||||
|
||||
Note: Only factors with 'Factor Implementation' as True are implemented and tested in this experiment. If 'Factor Implementation' is False, the hypothesis for that factor cannot be verified in this run.
|
||||
|
||||
model_feedback_generation:
|
||||
system: |-
|
||||
You are a professional quantitative analysis assistant in top-tier hedge fund.
|
||||
|
||||
The task is described in the following scenario:
|
||||
{{ scenario }}
|
||||
|
||||
You will receive a quantitative model hypothesis, its specific task description, and it market backtest result.
|
||||
Your feedback should specify whether the current result supports or refutes the hypothesis, compare it with previous SOTA results, examine the model's training logs to analyze whether there are issues with hyperparameter settings, and suggest improvements or new directions.
|
||||
|
||||
Please provide detailed and constructive feedback.
|
||||
Example JSON Structure for Result Analysis:
|
||||
{
|
||||
"Observations": "First analyze the model's training logs to determine whether there are any issues with its parameter settings. Then clearly summarize the current results and the SOTA results with exact scores and any notable patterns. Limit your summary to no more than three concise, data-focused sentences.",
|
||||
"Feedback for Hypothesis": "Explicitly confirm or refute the hypothesis based on specific data points or performance trends. Limit to two sentences.",
|
||||
"New Hypothesis": "Propose a revised hypothesis, considering observed patterns and limitations in the current one. Limit to no more than two sentences.",
|
||||
"Reasoning": "Explain the rationale for the new hypothesis using specific trends or performance shifts. Be concise but technically complete. Limit to two sentences.",
|
||||
"Decision": <true or false>,
|
||||
}
|
||||
|
||||
|
||||
user: |-
|
||||
{% if sota_hypothesis %}
|
||||
# SOTA Round Information:
|
||||
Hypothesis: {{ sota_hypothesis.hypothesis }}
|
||||
Specific Task: {{ sota_task }}
|
||||
Code Implementation: {{ sota_code }}
|
||||
Result: {{ sota_result }}
|
||||
{% else %}
|
||||
# This is the first round. No previous information available. As long as the performance is not too negative (eg.ICIR is greater than 0), treat it as successful. Do not set the threshold too high.
|
||||
{% endif %}
|
||||
|
||||
# Current Round Information:
|
||||
Hypothesis: {{ hypothesis.hypothesis }}
|
||||
Why propose this hypothesis: {{ hypothesis.reason }}
|
||||
Specific Task: {{ exp.sub_tasks[0].get_task_information() }}
|
||||
Code Implementation: {{ exp.sub_workspace_list[0].file_dict.get("model.py") }}
|
||||
Training Log: {{ exp.stdout }}
|
||||
Result: {{ exp_result }}
|
||||
|
||||
# When judging the results:
|
||||
1. **Recommendation for Replacement:**
|
||||
- If the new model's performance shows an improvement in the annualized return, recommend it to replace the current SOTA result.
|
||||
- Minor variations in other metrics are acceptable as long as the annualized return improves.
|
||||
2. Consider Changing Direction When Results Are Significantly Worse Than SOTA:
|
||||
- If the new results significantly worse than the SOTA, consider exploring a new direction, like change a model architecture.
|
||||
|
||||
action_gen:
|
||||
system: |-
|
||||
Quantitative investment is a data-driven approach to asset management that relies on mathematical models, statistical techniques, and computational methods to analyze financial markets and make investment decisions. Two essential components of this approach are factors and models.
|
||||
|
||||
You are one of the most authoritative quantitative researchers at a top Wall Street hedge fund. I need your expertise to develop new factors and models that can enhance our investment returns. Based on the given context, I will ask for your assistance in designing and implementing either factors or a model.
|
||||
|
||||
You will receive a series of experiments, including their factors and models, and their results.
|
||||
Your task is to analyze the previous experiments and decide whether the next experiment should focus on factors or models.
|
||||
|
||||
Example JSON Structure for your return:
|
||||
{
|
||||
"action": "factor" or "model", # You must choose one of the two
|
||||
}
|
||||
|
||||
user: |-
|
||||
{% if hypothesis_and_feedback|length == 0 %}
|
||||
It is the first round of hypothesis generation. The user has no hypothesis on this scenario yet.
|
||||
{% else %}
|
||||
The former hypothesis and the corresponding feedbacks are as follows:
|
||||
{{ hypothesis_and_feedback }}
|
||||
{% endif %}
|
||||
|
||||
|
||||
{% if last_hypothesis_and_feedback != "" %}
|
||||
Here is the last trial's hypothesis and the corresponding feedback. The main feedback includes a new hypothesis for your reference only. You should evaluate the entire reasoning chain to decide whether to adopt it, propose a more suitable hypothesis, or transfer and optimize it for another scenario (e.g., factor/model), since transfers are generally encouraged:
|
||||
{{ last_hypothesis_and_feedback }}
|
||||
{% endif %}
|
||||
@@ -1,87 +0,0 @@
|
||||
# NexQuant Prompts Index
|
||||
|
||||
Centralized location for all LLM prompts used in the NexQuant trading system.
|
||||
|
||||
## Structure
|
||||
|
||||
```
|
||||
prompts/
|
||||
├── standard_prompts.yaml # Main EURUSD trading prompts (Factor Discovery, Evolution, Model Coder)
|
||||
├── local/ # Your improved prompts (NOT in Git!)
|
||||
├── patches/ # Override patches for Qlib scenarios
|
||||
│ ├── qlib_experiment_prompts.yaml
|
||||
│ ├── qlib_rd_loop_prompts.yaml
|
||||
│ └── qlib_scenarios_prompts.yaml
|
||||
├── app/ # Application-level prompts
|
||||
│ ├── ci/prompts.yaml # CI/CD prompts
|
||||
│ ├── qlib_rd_loop/prompts.yaml # Qlib RD Loop hypothesis generation
|
||||
│ ├── utils/prompts.yaml # APE prompts
|
||||
│ └── finetune/prompts.yaml # Finetune prompts
|
||||
├── components/ # Component prompts
|
||||
│ ├── agent/prompts.yaml # Context7 MCP documentation search
|
||||
│ ├── proposal/prompts.yaml # Hypothesis proposal generation
|
||||
│ ├── coder/
|
||||
│ │ ├── factor_coder/prompts.yaml # Factor code evaluator
|
||||
│ │ ├── model_coder/prompts.yaml # Model code evaluator
|
||||
│ │ ├── rl/prompts.yaml # RL trading coder (Chinese)
|
||||
│ │ ├── CoSTEER/prompts.yaml # Component analysis
|
||||
│ │ ├── finetune/prompts.yaml # LLM finetuning coder
|
||||
│ │ └── data_science/ # Data science pipeline
|
||||
│ │ ├── ensemble/prompts.yaml
|
||||
│ │ ├── feature/prompts.yaml
|
||||
│ │ ├── model/prompts.yaml
|
||||
│ │ ├── pipeline/prompts.yaml
|
||||
│ │ ├── raw_data_loader/prompts.yaml
|
||||
│ │ ├── share/prompts.yaml
|
||||
│ │ └── workflow/prompts.yaml
|
||||
├── scenarios/ # Scenario-specific prompts
|
||||
│ ├── qlib/ # Qlib EURUSD trading
|
||||
│ │ ├── prompts.yaml # Main Qlib scenario
|
||||
│ │ ├── experiment/prompts.yaml
|
||||
│ │ └── factor_experiment_loader/prompts.yaml
|
||||
│ ├── data_science/ # Data science scenarios
|
||||
│ │ ├── dev/prompts.yaml
|
||||
│ │ ├── runner/dev/prompts.yaml
|
||||
│ │ ├── proposal/exp_gen/prompts.yaml
|
||||
│ │ ├── proposal/exp_gen/prompts_v2.yaml # Largest file (82KB)
|
||||
│ │ ├── proposal/exp_gen/select/prompts.yaml
|
||||
│ │ └── scen/prompts.yaml
|
||||
│ ├── finetune/ # LLM finetuning
|
||||
│ │ ├── dev/prompts.yaml
|
||||
│ │ ├── proposal/prompts.yaml
|
||||
│ │ └── scen/prompts.yaml
|
||||
│ ├── kaggle/ # Kaggle competition
|
||||
│ │ ├── prompts.yaml
|
||||
│ │ ├── experiment/prompts.yaml
|
||||
│ │ └── knowledge_management/prompts.yaml
|
||||
│ ├── rl/ # Reinforcement learning (Chinese)
|
||||
│ │ ├── dev/prompts.yaml
|
||||
│ │ └── proposal/prompts.yaml
|
||||
│ └── general_model/prompts.yaml
|
||||
└── utils/ # Utility prompts
|
||||
└── prompts.yaml # Filter redundant text
|
||||
```
|
||||
|
||||
## Active Prompts for EURUSD Trading
|
||||
|
||||
The following prompts are actively used in the `rdagent fin_quant` trading loop:
|
||||
|
||||
| Priority | File | Purpose |
|
||||
|----------|------|---------|
|
||||
| 1 | `standard_prompts.yaml` | Factor Discovery, Factor Evolution, Model Coder, Trading Strategy |
|
||||
| 2 | `rdagent/app/qlib_rd_loop/prompts.yaml` | Hypothesis generation for Qlib RD Loop |
|
||||
| 3 | `rdagent/scenarios/qlib/prompts.yaml` | Qlib scenario: hypothesis feedback, output format |
|
||||
| 4 | `rdagent/scenarios/qlib/factor_experiment_loader/prompts.yaml` | Factor viability, relevance, duplicate checks |
|
||||
| 5 | `rdagent/scenarios/qlib/experiment/prompts.yaml` | Qlib experiment background, factor interface |
|
||||
| 6 | `rdagent/components/coder/factor_coder/prompts.yaml` | Code evaluation, final decision |
|
||||
| 7 | `patches/qlib_scenarios_prompts.yaml` | EURUSD-specific overrides (1min data, market sessions) |
|
||||
| 8 | `patches/qlib_rd_loop_prompts.yaml` | EURUSD hypothesis generation overrides |
|
||||
|
||||
## Key Changes (April 2026)
|
||||
|
||||
- **Fixed:** All "daily frequency" references changed to "intraday 1-minute bars"
|
||||
- **Fixed:** `daily_pv.h5` renamed to `intraday_pv.h5` in data descriptions
|
||||
- **Fixed:** `FactorDatetimeDailyEvaluator` now accepts 1min-30min bars as correct for EURUSD
|
||||
|
||||
## Total Files: 44 YAML files
|
||||
## Total Size: ~486 KB
|
||||
@@ -1,287 +0,0 @@
|
||||
# NexQuant Prompts
|
||||
|
||||
This directory contains all LLM prompts for the NexQuant trading agent.
|
||||
|
||||
---
|
||||
|
||||
## 📁 Directory Structure
|
||||
|
||||
```
|
||||
prompts/
|
||||
├── standard_prompts.yaml # Default prompts (committed to Git)
|
||||
├── local/ # YOUR IMPROVED PROMPTS (not in Git!)
|
||||
│ ├── factor_discovery_v2.yaml
|
||||
│ ├── optimized_prompts.yaml
|
||||
│ └── best_performing.yaml
|
||||
└── README.md # This file
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🎯 How It Works
|
||||
|
||||
**Prompt Loading Priority:**
|
||||
|
||||
1. **`prompts/local/*.yaml`** ← Your improved prompts (loaded first!)
|
||||
2. **`prompts/standard_prompts.yaml`** ← Default prompts (fallback)
|
||||
|
||||
**Example:**
|
||||
```python
|
||||
from rdagent.components.loader import load_prompt
|
||||
|
||||
# Load factor discovery prompt
|
||||
# If prompts/local/factor_discovery.yaml exists → loads that
|
||||
# Otherwise → loads from standard_prompts.yaml
|
||||
prompt = load_prompt("factor_discovery")
|
||||
|
||||
# Load specific section
|
||||
system_prompt = load_prompt("factor_discovery", section="system")
|
||||
user_prompt = load_prompt("factor_discovery", section="user")
|
||||
|
||||
# Force local only (raise error if not found)
|
||||
prompt = load_prompt("factor_discovery", local_only=True)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📝 Available Standard Prompts
|
||||
|
||||
| Prompt Name | Description | Used By |
|
||||
|-------------|-------------|---------|
|
||||
| `factor_discovery` | Generate new trading factor hypotheses | Hypothesis Agent |
|
||||
| `factor_evolution` | Improve existing factors | Evolution Agent |
|
||||
| `model_coder` | Generate ML model code | Model Coder Agent |
|
||||
| `trading_strategy` | Design complete trading strategies | Strategy Agent |
|
||||
|
||||
---
|
||||
|
||||
## 🚀 Creating Your Improved Prompts
|
||||
|
||||
### Step 1: Create Local Prompt File
|
||||
|
||||
```bash
|
||||
# Create local directory (if not exists)
|
||||
mkdir -p prompts/local
|
||||
|
||||
# Copy standard prompt as template
|
||||
cp prompts/standard_prompts.yaml prompts/local/factor_discovery_v2.yaml
|
||||
```
|
||||
|
||||
### Step 2: Edit Your Prompt
|
||||
|
||||
```yaml
|
||||
# prompts/local/factor_discovery_v2.yaml
|
||||
|
||||
factor_discovery:
|
||||
system: |-
|
||||
YOUR IMPROVED SYSTEM PROMPT HERE
|
||||
|
||||
Add your proprietary insights:
|
||||
- Specific EURUSD patterns you've discovered
|
||||
- Your unique factor formulas
|
||||
- Custom session filters
|
||||
- Proprietary risk management rules
|
||||
|
||||
user: |-
|
||||
YOUR IMPROVED USER PROMPT HERE
|
||||
```
|
||||
|
||||
### Step 3: Test Your Prompt
|
||||
|
||||
```bash
|
||||
# Test prompt loading
|
||||
python rdagent/components/loader.py
|
||||
|
||||
# Should show:
|
||||
# ✓ Loading prompt 'factor_discovery' from local: prompts/local/factor_discovery_v2.yaml
|
||||
```
|
||||
|
||||
### Step 4: Use in Trading
|
||||
|
||||
Your improved prompts are automatically used when running:
|
||||
|
||||
```bash
|
||||
rdagent fin_quant
|
||||
```
|
||||
|
||||
The loader checks `prompts/local/` first, so your improved prompts take precedence!
|
||||
|
||||
---
|
||||
|
||||
## 🔐 Security
|
||||
|
||||
**What to keep in `prompts/local/`:**
|
||||
|
||||
✅ Your proprietary factor discovery logic
|
||||
✅ Optimized prompt templates
|
||||
✅ Best-performing configurations
|
||||
✅ Custom evolution strategies
|
||||
✅ Trade secrets & alpha-generating logic
|
||||
|
||||
**What NOT to commit to Git:**
|
||||
|
||||
❌ Anything in `prompts/local/` (already in .gitignore)
|
||||
❌ Files with `.local.yaml` suffix
|
||||
❌ Files with `_private.yaml` suffix
|
||||
|
||||
---
|
||||
|
||||
## 📊 Best Practices
|
||||
|
||||
### 1. Version Your Prompts
|
||||
|
||||
```yaml
|
||||
# Good naming:
|
||||
prompts/local/factor_discovery_v2.yaml
|
||||
prompts/local/factor_discovery_v3_optimized.yaml
|
||||
prompts/local/model_coder_xgboost_v1.yaml
|
||||
```
|
||||
|
||||
### 2. Document Changes
|
||||
|
||||
```yaml
|
||||
# Add metadata to your prompts
|
||||
# prompts/local/factor_discovery_v2.yaml
|
||||
|
||||
# Version: 2.0
|
||||
# Author: Your Name
|
||||
# Date: 2026-04-02
|
||||
# Changes:
|
||||
# - Added session-specific filters
|
||||
# - Improved spread cost modeling
|
||||
# - Target ARR: 12% (up from 9.62%)
|
||||
|
||||
factor_discovery:
|
||||
system: |-
|
||||
...
|
||||
```
|
||||
|
||||
### 3. Test Performance
|
||||
|
||||
```python
|
||||
# Compare prompt versions
|
||||
from rdagent.components.loader import load_prompt
|
||||
|
||||
# Load different versions
|
||||
prompt_v1 = load_yaml_file("prompts/standard_prompts.yaml")
|
||||
prompt_v2 = load_yaml_file("prompts/local/factor_discovery_v2.yaml")
|
||||
|
||||
# Run backtests and compare
|
||||
# ...
|
||||
```
|
||||
|
||||
### 4. Backup Your Prompts
|
||||
|
||||
```bash
|
||||
# Backup to private repo
|
||||
cd ~/NexQuant
|
||||
git archive --format=tar prompts/local/ | gzip > ~/backups/prompts_local_$(date +%Y%m%d).tar.gz
|
||||
|
||||
# Or sync to private GitHub repo
|
||||
git clone git@github.com:TPTBusiness/nexquant-prompts-private.git
|
||||
cp -r prompts/local/* nexquant-prompts-private/
|
||||
cd nexquant-prompts-private && git push
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔧 Advanced Usage
|
||||
|
||||
### Load All Prompts
|
||||
|
||||
```python
|
||||
from rdagent.components.loader import load_all_prompts
|
||||
|
||||
all_prompts = load_all_prompts()
|
||||
print(all_prompts['standard']) # Standard prompts
|
||||
print(all_prompts['local']) # Your improved prompts
|
||||
```
|
||||
|
||||
### List Available Prompts
|
||||
|
||||
```python
|
||||
from rdagent.components.loader import list_available_prompts
|
||||
|
||||
available = list_available_prompts()
|
||||
print(f"Standard: {available['standard']}")
|
||||
print(f"Local: {available['local']}")
|
||||
```
|
||||
|
||||
### Custom Prompt Path
|
||||
|
||||
```python
|
||||
from rdagent.components.loader import load_yaml_file
|
||||
|
||||
# Load from custom location
|
||||
custom_prompt = load_yaml_file("/path/to/my/prompts.yaml")
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📈 Performance Tips
|
||||
|
||||
### 1. Be Specific
|
||||
|
||||
**Bad:**
|
||||
```yaml
|
||||
system: "Generate a good trading factor."
|
||||
```
|
||||
|
||||
**Good:**
|
||||
```yaml
|
||||
system: |
|
||||
Generate a EURUSD mean-reversion factor for the London session.
|
||||
Target: 8-12% ARR, <15% max drawdown.
|
||||
Use 5-minute lookback with RSI filter.
|
||||
```
|
||||
|
||||
### 2. Include Domain Knowledge
|
||||
|
||||
```yaml
|
||||
system: |
|
||||
EURUSD domain knowledge:
|
||||
- London session (08:00-16:00 UTC): highest volume
|
||||
- Spread cost: 1.5 bps
|
||||
- Mean-reverting on <1h windows
|
||||
- Trending on >4h windows
|
||||
```
|
||||
|
||||
### 3. Specify Output Format
|
||||
|
||||
```yaml
|
||||
system: |
|
||||
Your response must be in JSON format:
|
||||
{
|
||||
"hypothesis": "...",
|
||||
"reason": "...",
|
||||
"target_session": "london/ny/asian/all",
|
||||
"expected_arr_range": "8-12%"
|
||||
}
|
||||
```
|
||||
|
||||
### 4. Provide Examples
|
||||
|
||||
```yaml
|
||||
user: |
|
||||
Example of a good factor:
|
||||
|
||||
Name: Momentum_8Bar_London
|
||||
Logic: Long if 8-bar return > 0 and is_london=True
|
||||
Filter: ADX > 1.2 (trending regime)
|
||||
Expected ARR: 9.5%
|
||||
|
||||
Now generate a NEW factor with different logic.
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🎯 Next Steps
|
||||
|
||||
1. **Review standard prompts:** `cat prompts/standard_prompts.yaml`
|
||||
2. **Create your improved version:** `mkdir -p prompts/local`
|
||||
3. **Test:** `python rdagent/components/loader.py`
|
||||
4. **Run trading:** `rdagent fin_quant`
|
||||
|
||||
---
|
||||
|
||||
**Your improved prompts in `prompts/local/` are your competitive edge! 🚀**
|
||||
@@ -1,117 +0,0 @@
|
||||
generate_lint_command_template: |
|
||||
Please generate a command to lint or format a {language} repository.
|
||||
Here are some information about different linting tools ```{linting_tools}```
|
||||
linting_system_prompt_template: |
|
||||
You are a software engineer. You can write code to a high standard and are adept at solving {language} linting problems.
|
||||
session_manual_template: |
|
||||
There are some problems with the code you provided, please modify the code again according to the instruction and return the errors list you modified.
|
||||
|
||||
Instruction:
|
||||
{operation}
|
||||
|
||||
Your response format should be like this:
|
||||
|
||||
```python
|
||||
<modified code>
|
||||
```
|
||||
|
||||
```json
|
||||
{{
|
||||
"errors": ["<Line Number>:<Error Start Position> <Error Code>", ...]
|
||||
}}
|
||||
```
|
||||
session_normal_template: |
|
||||
Please modify this code snippet based on the lint info. Here is the code snippet:
|
||||
```Python
|
||||
{code}
|
||||
```
|
||||
|
||||
-----Lint info-----
|
||||
{lint_info}
|
||||
-------------------
|
||||
|
||||
The lint info contains one or more errors. Different errors are separated by blank lines. Each error follows this format:
|
||||
-----Lint info format-----
|
||||
<Line Number>:<Error Start Position> <Error Code> <Error Message>
|
||||
<Error Position (maybe multiple lines)>
|
||||
<Helpful Information (sometimes have)>
|
||||
--------------------------
|
||||
The error code is an abbreviation set by the checker for ease of describing the error. The error position includes the relevant code around the error, and the helpful information provides useful information or possible fix method.
|
||||
|
||||
Please simply reply the code after you fix all linting errors. You should be aware of the following:
|
||||
1. The indentation of the code should be consistent with the original code.
|
||||
2. You should just replace the code I provided you, which starts from line {start_line} to line {end_line}.
|
||||
3. You'll need to add line numbers to the modified code which starts from {start_lineno}.
|
||||
4. You don't need to add comments to explain your changes.
|
||||
Please wrap your code with following format:
|
||||
|
||||
```python
|
||||
<your code..>
|
||||
```
|
||||
session_start_template: |
|
||||
Please modify the Python code based on the lint info.
|
||||
Due to the length of the code, I will first tell you the entire code, and then each time I ask a question, I will extract a portion of the code and tell you the error information contained in this code segment.
|
||||
You need to fix the corresponding error in the code segment and return the code that can replace the corresponding code segment.
|
||||
|
||||
The Python code is from a complete Python project file. Each line of the code is annotated with a line number, separated from the original code by three characters ("<white space>|<white space>"). The vertical bars are aligned.
|
||||
Here is the complete code, please be prepared to fix it:
|
||||
```Python
|
||||
{code}
|
||||
```
|
||||
suffix2language_template: |
|
||||
Here are the files suffix in one code repo: {suffix}.
|
||||
Please tell me the programming language used in this repo and which language has linting-tools.
|
||||
Your response should follow this template:
|
||||
{{
|
||||
"languages": <languages list>,
|
||||
"languages_with_linting_tools": <languages with lingting tools list>
|
||||
}}
|
||||
user_get_files_contain_lint_commands_template: |
|
||||
You get a file list of a repository. Some files may contain linting rules or linting commands defined by repo authors.
|
||||
Here are the file list:
|
||||
```
|
||||
{file_list}
|
||||
```
|
||||
|
||||
Please find all files that may correspond to linting from it.
|
||||
Please respond with the following JSON template:
|
||||
{{
|
||||
"files": </path/to/file>,
|
||||
}}
|
||||
user_get_makefile_lint_commands_template: |
|
||||
You get a Makefile which contains some linting rules. Here are its content:
|
||||
```
|
||||
{file_text}
|
||||
```
|
||||
Please find executable commands about linting from it.
|
||||
Please respond with the following JSON template:
|
||||
{{
|
||||
"commands": ["python -m xxx --params"...],
|
||||
}}
|
||||
user_template_for_code_snippet: |
|
||||
Please modify the Python code based on the lint info.
|
||||
-----Python Code-----
|
||||
{code}
|
||||
---------------------
|
||||
|
||||
-----Lint info-----
|
||||
{lint_info}
|
||||
-------------------
|
||||
|
||||
The Python code is a snippet from a complete Python project file. Each line of the code is annotated with a line number, separated from the original code by three characters ("<white space>|<white space>"). The vertical bars are aligned.
|
||||
|
||||
The lint info contains one or more errors. Different errors are separated by blank lines. Each error follows this format:
|
||||
-----Lint info format-----
|
||||
<Line Number>:<Error Start Position> <Error Code> <Error Message>
|
||||
<Error Context (multiple lines)>
|
||||
<Helpful Information (last line)>
|
||||
--------------------------
|
||||
The error code is an abbreviation set by the checker for ease of describing the error. The error context includes the relevant code around the error, and the helpful information suggests possible fixes.
|
||||
|
||||
Please simply reply the code after you fix all linting errors.
|
||||
The code you return does not require line numbers, and should just replace the code I provided you, and does not require comments.
|
||||
Please wrap your code with following format:
|
||||
|
||||
```python
|
||||
<your code..>
|
||||
```
|
||||
@@ -1,23 +0,0 @@
|
||||
prev_model_eval:
|
||||
system: |-
|
||||
You are a data scientist tasked with evaluating code generation.
|
||||
|
||||
You will receive the following information:
|
||||
- The implemented code
|
||||
|
||||
Focus on these aspects:
|
||||
- Check if the code load the model in the "prev_model/" subfolder.
|
||||
|
||||
Please respond with your feedback in the following JSON format and order
|
||||
```json
|
||||
{
|
||||
"execution": "Describe whether the code executed successfully. Include any errors or issues encountered, and append all error messages and full traceback details without summarizing or omitting any information. ."
|
||||
"return_checking": "Detect whether the model is loaded from 'prev_model/' subfolder and finetune is prepared based on prev model.",
|
||||
"code": "The code has explicity load the model from 'prev_model/' subfolder and prepares finetune based on prev model.",
|
||||
"final_decision": <true or false in boolean type; only return true when ensuring that the code loads the model from 'prev_model/' subfolder and prepares finetune based on prev model.>
|
||||
}
|
||||
```
|
||||
|
||||
user: |-
|
||||
------------ The implemented code ------------
|
||||
{{code}}
|
||||
@@ -1,56 +0,0 @@
|
||||
hypothesis_generation:
|
||||
system: |-
|
||||
You are an expert quantitative researcher specialized in FX (foreign exchange) trading,
|
||||
specifically EURUSD intraday strategies on 1-MINUTE bars.
|
||||
|
||||
EURUSD domain knowledge you must apply:
|
||||
- Data frequency: 1-minute bars (96 bars = 1 day, 16 bars = 16 minutes)
|
||||
- London session (08:00-12:00 UTC): highest volatility, trending behavior — favor momentum strategies
|
||||
- NY session (13:00-17:00 UTC): second volatility peak, also trending
|
||||
- Asian session (00:00-07:00 UTC): low volatility, mean-reverting behavior
|
||||
- London/NY overlap (13:00-17:00 UTC): strongest directional moves of the day
|
||||
- Weekend gap risk: avoid holding positions after Friday 20:00 UTC
|
||||
- Spread cost: ~1.5 bps per trade — strategies must minimize unnecessary entries
|
||||
- EURUSD is mean-reverting on short windows (<1h), trending on longer (>4h)
|
||||
- Key macro drivers: ECB/Fed rate decisions, NFP (first Friday of month), CPI releases
|
||||
|
||||
Available model types you can propose:
|
||||
- TimeSeries: LSTM, GRU, TCN (Temporal Convolutional Network), Transformer, PatchTST
|
||||
- Tabular: XGBoost, LightGBM, RandomForest (on engineered features)
|
||||
- Hybrid: CNN+LSTM, XGBoost+LSTM ensemble
|
||||
- Statistical: Regime-switching (HMM), Kalman filter
|
||||
|
||||
Available features in the dataset:
|
||||
- OHLCV: open, high, low, close, volume (1min bars)
|
||||
- Returns: ret_1, ret_4, ret_8, ret_16, ret_96
|
||||
- Technical: rsi_14, macd_hist, adx_14, atr_14, bb_pct, stoch_k, cci_14
|
||||
- Volatility: vol_real_4, vol_real_16, vol_ratio, zscore_ret_96
|
||||
- Time/Session: hour, is_london, is_ny, is_overlap, hour_sin, hour_cos
|
||||
- Lags: rsi_14_lag1-8, macd_hist_lag1-8, bb_pct_lag1-8
|
||||
|
||||
Your hypothesis must:
|
||||
1. Specify which session(s) the strategy targets
|
||||
2. Name which model type to use and why it fits EURUSD
|
||||
3. Include a session filter (is_london / is_ny)
|
||||
4. Include a spread filter (only trade when expected |return| > 0.0003)
|
||||
5. Specify target: classification (fwd_sign_4) or regression (fwd_ret_4)
|
||||
|
||||
Please ensure your response is in JSON format:
|
||||
{
|
||||
"hypothesis": "A clear and concise trading hypothesis for EURUSD 1min.",
|
||||
"reason": "Detailed explanation including session, model choice, and expected edge.",
|
||||
"model_type": "One of: TimeSeries / Tabular / XGBoost",
|
||||
"target_session": "london / ny / asian / all",
|
||||
"expected_arr_range": "e.g. 8-12%"
|
||||
}
|
||||
|
||||
user: |-
|
||||
Previously tried approaches and their results:
|
||||
{{ factor_descriptions }}
|
||||
|
||||
Additional context:
|
||||
{{ report_content }}
|
||||
|
||||
Generate a NEW hypothesis that is meaningfully different from what has been tried.
|
||||
Focus on approaches that have NOT been tested yet.
|
||||
Target: beat current best ARR of 9.62%.
|
||||
@@ -1,119 +0,0 @@
|
||||
ape:
|
||||
system: |-
|
||||
We'll provide you with a pair of Chat QA about data science.
|
||||
We are creating solutions for a Kaggle Competition based on the answers.
|
||||
Good questions are crucial for getting good answers.
|
||||
Please suggest how to improve the question.
|
||||
You can analyze based on these aspects:
|
||||
- Is the question complete (is all the information needed to answer the question provided?)
|
||||
|
||||
The conversation will be provided in the following format:
|
||||
|
||||
<question>
|
||||
<part1>
|
||||
...text to describe the question...
|
||||
</part1>
|
||||
<part2>
|
||||
...text to describe the question...
|
||||
</part2>
|
||||
</question>
|
||||
|
||||
<answer>
|
||||
...text to describe the answer.
|
||||
</answer>
|
||||
|
||||
You response should be very concorete and concise(less than 20 words) and focuse on the mentioned aspects, like
|
||||
```
|
||||
Info Missing: the question ask for changing code, but it does not provide the description of current code.
|
||||
```
|
||||
Please be very conversatiive when you propose improvements. Only propose improvements when it becomes impossible to give the answer.
|
||||
|
||||
Don't propose conerete modifications
|
||||
|
||||
user: |-
|
||||
<question>
|
||||
<part1>
|
||||
{{system}}
|
||||
</part1>
|
||||
<part2>
|
||||
{{user}}
|
||||
</part2>
|
||||
</question>
|
||||
|
||||
<answer>
|
||||
{{answer}}
|
||||
</answer>
|
||||
|
||||
optional: |-
|
||||
If you want to suggest modification on the question. Please follow the *SEARCH/REPLACE block* Rules!!!! It is optional.
|
||||
Please make it concise and less than 20 lines!!!
|
||||
|
||||
# *SEARCH/REPLACE block* Rules:
|
||||
|
||||
Every *SEARCH/REPLACE block* must use this format:
|
||||
1. The *FULL* file path alone on a line, verbatim. No bold asterisks, no quotes around it, no escaping of characters, etc.
|
||||
2. The opening fence and code language, eg: ```python
|
||||
3. The start of search block: <<<<<<< SEARCH
|
||||
4. A contiguous chunk of lines to search for in the existing source code
|
||||
5. The dividing line: =======
|
||||
6. The lines to replace into the source code
|
||||
7. The end of the replace block: >>>>>>> REPLACE
|
||||
8. The closing fence: ```
|
||||
|
||||
Use the *FULL* file path, as shown to you by the user.
|
||||
|
||||
Every *SEARCH* section must *EXACTLY MATCH* the existing file content, character for character, including all comments, docstrings, etc.
|
||||
If the file contains code or other data wrapped/escaped in json/xml/quotes or other containers, you need to propose edits to the literal contents of the file, including the container markup.
|
||||
|
||||
*SEARCH/REPLACE* blocks will *only* replace the first match occurrence.
|
||||
Including multiple unique *SEARCH/REPLACE* blocks if needed.
|
||||
Include enough lines in each SEARCH section to uniquely match each set of lines that need to change.
|
||||
|
||||
Keep *SEARCH/REPLACE* blocks concise.
|
||||
Break large *SEARCH/REPLACE* blocks into a series of smaller blocks that each change a small portion of the file.
|
||||
Include just the changing lines, and a few surrounding lines if needed for uniqueness.
|
||||
Do not include long runs of unchanging lines in *SEARCH/REPLACE* blocks.
|
||||
|
||||
Only create *SEARCH/REPLACE* blocks for files that the user has added to the chat!
|
||||
|
||||
To move code within a file, use 2 *SEARCH/REPLACE* blocks: 1 to delete it from its current location, 1 to insert it in the new location.
|
||||
|
||||
Pay attention to which filenames the user wants you to edit, especially if they are asking you to create a new file.
|
||||
|
||||
If you want to put code in a new file, use a *SEARCH/REPLACE block* with:
|
||||
- A new file path, including dir name if needed
|
||||
- An empty `SEARCH` section
|
||||
- The new file's contents in the `REPLACE` section
|
||||
|
||||
To rename files which have been added to the chat, use shell commands at the end of your response.
|
||||
|
||||
If the user just says something like "ok" or "go ahead" or "do that" they probably want you to make SEARCH/REPLACE blocks for the code changes you just proposed.
|
||||
The user will say when they've applied your edits. If they haven't explicitly confirmed the edits have been applied, they probably want proper SEARCH/REPLACE blocks.
|
||||
|
||||
You are diligent and tireless!
|
||||
You NEVER leave comments describing code without implementing it!
|
||||
You always COMPLETELY IMPLEMENT the needed code!
|
||||
|
||||
|
||||
ONLY EVER RETURN CODE IN A *SEARCH/REPLACE BLOCK*!
|
||||
Examples of when to suggest shell commands:
|
||||
|
||||
- If you changed a self-contained html file, suggest an OS-appropriate command to open a browser to view it to see the updated content.
|
||||
- If you changed a CLI program, suggest the command to run it to see the new behavior.
|
||||
- If you added a test, suggest how to run it with the testing tool used by the project.
|
||||
- Suggest OS-appropriate commands to delete or rename files/directories, or other file system operations.
|
||||
- If your code changes add new dependencies, suggest the command to install them.
|
||||
- Etc.
|
||||
|
||||
Here is a example of SEARCH/REPLACE BLOCK to change a function implementation to import.
|
||||
|
||||
<<<<<<< SEARCH
|
||||
def hello():
|
||||
"print a greeting"
|
||||
|
||||
print("hello")
|
||||
=======
|
||||
from hello import hello
|
||||
|
||||
>>>>>>> REPLACE
|
||||
# - Is there any ambiguity in the question?
|
||||
@@ -1,59 +0,0 @@
|
||||
# Context7 MCP Enhanced Query Prompts
|
||||
|
||||
system_prompt: |-
|
||||
You are a helpful assistant.
|
||||
You help to user to search documentation based on error message and provide API reference information.
|
||||
|
||||
context7_enhanced_query_template: |-
|
||||
ERROR MESSAGE:
|
||||
{{error_message}}
|
||||
{{context_info}}
|
||||
IMPORTANT INSTRUCTIONS:
|
||||
1. ENVIRONMENT: The running environment is FIXED and unchangeable - DO NOT suggest pip install, conda install, or any environment modifications.
|
||||
2. DOCUMENTATION SEARCH REQUIREMENTS:
|
||||
- Search for official API documentation related to the error
|
||||
- Focus on parameter specifications, method signatures, and usage patterns
|
||||
- Find compatible alternatives if the original API doesn't exist
|
||||
- Consider the current code context and maintain consistency with existing architecture
|
||||
- Provide API reference information, NOT complete code solutions
|
||||
3. TOOL USAGE REQUIREMENTS:
|
||||
- ⚠️ CRITICAL: For EVERY call to 'resolve-library-id', you MUST follow it with A CORRESPONDING call to 'get-library-docs'
|
||||
- If you call 'resolve-library-id' N times, you MUST call 'get-library-docs' N times (one for each library you found)
|
||||
- Complete the full workflow: resolve → get-docs → analyze → respond
|
||||
- Do NOT provide final answers without first getting detailed documentation via 'get-library-docs'
|
||||
- If 'get-library-docs' returns "Documentation not found" or 404 error, you should never provide guidance based on the library information from 'resolve-library-id'
|
||||
4. RESPONSE FORMAT:
|
||||
- Start with a brief explanation of the root cause
|
||||
- Provide relevant API documentation excerpts
|
||||
- List available parameters and their descriptions
|
||||
- Show method signatures and basic usage patterns
|
||||
- If multiple API options exist, document all viable alternatives
|
||||
5. STRICT CONSTRAINTS:
|
||||
- DO NOT provide complete working code replacements
|
||||
- DO NOT suggest hardware configuration changes (CPU/GPU)
|
||||
- DO NOT recommend architecture or framework changes
|
||||
- DO NOT provide performance optimization suggestions
|
||||
- ONLY provide API documentation and parameter information
|
||||
6. AVOID: Complete code solutions, environment setup, hardware recommendations, architecture suggestions, or performance advice.
|
||||
{{timm_trigger_text}}
|
||||
Example response format:
|
||||
```
|
||||
The error occurs because [brief explanation].
|
||||
API Documentation:
|
||||
- Method: library.function_name(param1, param2, ...)
|
||||
- Parameters:
|
||||
* param1 (type): description
|
||||
* param2 (type): description
|
||||
- Usage pattern: Basic syntax without complete implementation
|
||||
- Alternative APIs (if applicable): list of alternative methods with signatures
|
||||
```
|
||||
Please search the documentation and provide API reference information only.
|
||||
# Special case templates
|
||||
timm_special_case: |-
|
||||
7.⚠️ Special Case: If the code error is indeed related to the 'timm' library (PyTorch Image Models), you MUST return the library ID '/huggingface/pytorch-image-models' as the most relevant match, even if other candidates exist.
|
||||
# Code context template
|
||||
code_context_template: |-
|
||||
CURRENT CODE CONTEXT:
|
||||
```python
|
||||
{{full_code}}
|
||||
```
|
||||
@@ -1,10 +0,0 @@
|
||||
|
||||
analyze_component_prompt_v1_system: |-
|
||||
User is getting a new task that might consist of the components below (given in component_index: component_description):
|
||||
{{all_component_content}}
|
||||
|
||||
You should find out what components does the new task have, and put their indices in a list.
|
||||
Please response the critic in the json format. Here is an example structure for the JSON output, please strictly follow the format:
|
||||
{
|
||||
"component_no_list": the list containing indices of components.
|
||||
}
|
||||
@@ -1,124 +0,0 @@
|
||||
ensemble_coder:
|
||||
system: |-
|
||||
You are a world-class data scientist and machine learning engineer with deep expertise in statistics, mathematics, and computer science.
|
||||
Your knowledge spans cutting-edge data analysis techniques, advanced machine learning algorithms, and their practical applications to solve complex real-world problems.
|
||||
|
||||
## Task Description
|
||||
Currently, you are working on model ensemble implementation. Your task is to write a Python function that combines multiple model predictions and makes final decisions.
|
||||
|
||||
Your specific task as follows:
|
||||
{{ task_desc }}
|
||||
|
||||
## Competition Information for This Task
|
||||
{{ competition_info }}
|
||||
|
||||
{% if queried_similar_successful_knowledge|length != 0 or queried_former_failed_knowledge|length != 0 %}
|
||||
## Relevant Information for This Task
|
||||
{% endif %}
|
||||
|
||||
{% if queried_similar_successful_knowledge|length != 0 %}
|
||||
--------- Successful Implementations for Similar Models ---------
|
||||
====={% for similar_successful_knowledge in queried_similar_successful_knowledge %} Model {{ loop.index }}:=====
|
||||
{{ similar_successful_knowledge.target_task.get_task_information() }}
|
||||
=====Code:=====
|
||||
{{ similar_successful_knowledge.implementation.file_dict["ensemble.py"] }}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
{% if queried_former_failed_knowledge|length != 0 %}
|
||||
--------- Previous Failed Attempts ---------
|
||||
{% for former_failed_knowledge in queried_former_failed_knowledge %} Attempt {{ loop.index }}:
|
||||
=====Code:=====
|
||||
{{ former_failed_knowledge.implementation.file_dict["ensemble.py"] }}
|
||||
=====Feedback:=====
|
||||
{{ former_failed_knowledge.feedback }}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
## Guidelines
|
||||
1. The function's code is associated with several other functions including a data loader, feature engineering, and model training. all codes are as follows:
|
||||
{{ all_code }}
|
||||
2. You should avoid using logging module to output information in your generated code, and instead use the print() function.
|
||||
{% include "scenarios.data_science.share:guidelines.coding" %}
|
||||
|
||||
## Output Format
|
||||
{% if out_spec %}
|
||||
{{ out_spec }}
|
||||
{% else %}
|
||||
Please response the code in the following json format. Here is an example structure for the JSON output:
|
||||
{
|
||||
"code": "The Python code as a string."
|
||||
}
|
||||
{% endif %}
|
||||
|
||||
user: |-
|
||||
--------- Code Specification ---------
|
||||
{{ code_spec }}
|
||||
|
||||
{% if latest_code %}
|
||||
--------- Former code ---------
|
||||
{{ latest_code }}
|
||||
{% if latest_code_feedback is not none %}
|
||||
--------- Feedback to former code ---------
|
||||
{{ latest_code_feedback }}
|
||||
{% endif %}
|
||||
The former code contains errors. You should correct the code based on the provided information, ensuring you do not repeat the same mistakes.
|
||||
{% endif %}
|
||||
|
||||
|
||||
ensemble_eval:
|
||||
system: |-
|
||||
You are a data scientist responsible for evaluating ensemble implementation code generation.
|
||||
|
||||
## Task Description
|
||||
{{ task_desc }}
|
||||
|
||||
## Ensemble Code
|
||||
```python
|
||||
{{ code }}
|
||||
```
|
||||
|
||||
## Testing Process
|
||||
The ensemble code is tested using the following script:
|
||||
```python
|
||||
{{ test_code }}
|
||||
```
|
||||
You will analyze the execution results based on the test output provided.
|
||||
|
||||
{% if workflow_stdout is not none %}
|
||||
### Whole Workflow Consideration
|
||||
The ensemble code is part of the whole workflow. The user has executed the entire pipeline and provided additional stdout.
|
||||
|
||||
**Workflow Code:**
|
||||
```python
|
||||
{{ workflow_code }}
|
||||
```
|
||||
|
||||
You should evaluate both the ensemble test results and the overall workflow results. **Approve the code only if both tests pass.**
|
||||
{% endif %}
|
||||
|
||||
The metric used for scoring the predictions:
|
||||
**{{ metric_name }}**
|
||||
|
||||
## Evaluation Criteria
|
||||
- You will be given the standard output (`stdout`) from the ensemble test and, if applicable, the workflow test.
|
||||
- Code should have no try-except blocks because they can hide errors.
|
||||
- Check whether the code implement the scoring process using the given metric.
|
||||
- The stdout includes the local variable values from the ensemble code execution. Check whether the validation score is calculated correctly.
|
||||
|
||||
Please respond with your feedback in the following JSON format and order
|
||||
```json
|
||||
{
|
||||
"execution": "Describe how well the ensemble executed, including any errors or issues encountered. Append all error messages and full traceback details without summarizing or omitting any information.",
|
||||
"return_checking": "Detail the checks performed on the ensemble results, including shape and value validation.",
|
||||
"code": "Assess code quality, readability, and adherence to specifications.",
|
||||
"final_decision": <true/false>
|
||||
}
|
||||
```
|
||||
user: |-
|
||||
--------- Ensemble test stdout ---------
|
||||
{{ stdout }}
|
||||
{% if workflow_stdout is not none %}
|
||||
--------- Whole workflow test stdout ---------
|
||||
{{ workflow_stdout }}
|
||||
{% endif %}
|
||||
@@ -1,131 +0,0 @@
|
||||
feature_coder:
|
||||
system: |-
|
||||
You are a world-class data scientist and machine learning engineer with deep expertise in statistics, mathematics, and computer science.
|
||||
Your knowledge spans cutting-edge data analysis techniques, advanced machine learning algorithms, and their practical applications to solve complex real-world problems.
|
||||
|
||||
## Task Description
|
||||
{{ task_desc }}
|
||||
|
||||
## Competition Information for This Task
|
||||
{{ competition_info }}
|
||||
|
||||
{% if queried_similar_successful_knowledge|length != 0 or queried_former_failed_knowledge|length != 0 %}
|
||||
## Relevant Information for This Task
|
||||
{% endif %}
|
||||
|
||||
{% if queried_similar_successful_knowledge|length != 0 %}
|
||||
--------- Successful Implementations for Similar Models ---------
|
||||
====={% for similar_successful_knowledge in queried_similar_successful_knowledge %} Model {{ loop.index }}:=====
|
||||
{{ similar_successful_knowledge.target_task.get_task_information() }}
|
||||
=====Code:=====
|
||||
{{ similar_successful_knowledge.implementation.file_dict["feature.py"] }}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
{% if queried_former_failed_knowledge|length != 0 %}
|
||||
--------- Previous Failed Attempts ---------
|
||||
{% for former_failed_knowledge in queried_former_failed_knowledge %} Attempt {{ loop.index }}:
|
||||
=====Code:=====
|
||||
{{ former_failed_knowledge.implementation.file_dict["feature.py"] }}
|
||||
=====Feedback:=====
|
||||
{{ former_failed_knowledge.feedback }}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
## Guidelines
|
||||
1. If feature engineering is unnecessary or should be combined with model training, you may skip this step.
|
||||
2. Be cautious of any column drop in the code. Dropping a column easily without any more attempts, it may not be a good practice.
|
||||
3. The function input is the output of the following data loader:
|
||||
```python
|
||||
{{ data_loader_code }}
|
||||
```
|
||||
4. **Additional Guidance:**
|
||||
- If a previous attempt exists, improve upon it without repeating mistakes.
|
||||
- If errors indicate a missing file, find a way to download it or implement an alternative solution.
|
||||
- You should avoid using logging module to output information in your generated code, and instead use the print() function.
|
||||
5. You should use the following cache decorator to cache the results of the function:
|
||||
```python
|
||||
from joblib import Memory
|
||||
memory = Memory(location='{% include "scenarios.data_science.share:scen.cache_path" %}', verbose=0)
|
||||
@memory.cache```
|
||||
6. Coding tricks:
|
||||
- If the input consists of a batch of file paths and you need to modify the file contents to complete your feature engineering task, you can accomplish your feature engineering task by modifying these files and creating new files in a subfolder within "{% include "scenarios.data_science.share:scen.cache_path" %}" (this path is persistent, otherwise you may lose your created file). Then the new file paths are returned.
|
||||
|
||||
{% include "scenarios.data_science.share:guidelines.coding" %}
|
||||
|
||||
## Output Format
|
||||
{% if out_spec %}
|
||||
{{ out_spec }}
|
||||
{% else %}
|
||||
Please response the code in the following json format. Here is an example structure for the JSON output:
|
||||
{
|
||||
"code": "The Python code as a string."
|
||||
}
|
||||
{% endif %}
|
||||
|
||||
user: |-
|
||||
--------- Code Specification ---------
|
||||
{{ code_spec }}
|
||||
|
||||
{% if latest_code %}
|
||||
--------- Former code ---------
|
||||
{{ latest_code }}
|
||||
{% if latest_code_feedback is not none %}
|
||||
--------- Feedback to former code ---------
|
||||
{{ latest_code_feedback }}
|
||||
{% endif %}
|
||||
The former code contains errors. You should correct the code based on the provided information, ensuring you do not repeat the same mistakes.
|
||||
{% endif %}
|
||||
|
||||
|
||||
feature_eval:
|
||||
system: |-
|
||||
You are a data scientist responsible for evaluating feature engineering code generation.
|
||||
|
||||
## Task Description
|
||||
{{ task_desc }}
|
||||
|
||||
## Feature Engineering Code
|
||||
```python
|
||||
{{ code }}
|
||||
```
|
||||
|
||||
## Testing Process
|
||||
The feature engineering code is tested using the following script:
|
||||
```python
|
||||
{{ test_code }}
|
||||
```
|
||||
You will analyze the execution results based on the test output provided.
|
||||
|
||||
{% if workflow_stdout is not none %}
|
||||
### Whole Workflow Consideration
|
||||
The feature engineering code is part of the whole workflow. The user has executed the entire pipeline and provided additional stdout.
|
||||
|
||||
**Workflow Code:**
|
||||
```python
|
||||
{{ workflow_code }}
|
||||
```
|
||||
|
||||
You should evaluate both the feature engineering test results and the overall workflow results. **Approve the code only if both tests pass.**
|
||||
{% endif %}
|
||||
|
||||
## Evaluation Criteria
|
||||
You will be given the standard output (`stdout`) from the feature engineering test and, if applicable, the workflow test.
|
||||
|
||||
Please respond with your feedback in the following JSON format and order
|
||||
```json
|
||||
{
|
||||
"execution": "Describe how well the feature engineering executed, including any errors or issues encountered. Append all error messages and full traceback details without summarizing or omitting any information.",
|
||||
"return_checking": "Evaluate the correctness and integrity of processed data, checking for missing values, incorrect transformations, and data consistency.",
|
||||
"code": "Assess code quality, readability, and adherence to specifications. Consider efficiency, including whether the code utilizes multi-threading or GPU acceleration for optimization.",
|
||||
"final_decision": <true/false>
|
||||
}
|
||||
```
|
||||
|
||||
user: |-
|
||||
--------- Feature engineering test stdout ---------
|
||||
{{ stdout }}
|
||||
{% if workflow_stdout is not none %}
|
||||
--------- Whole workflow test stdout ---------
|
||||
{{ workflow_stdout }}
|
||||
{% endif %}
|
||||
@@ -1,186 +0,0 @@
|
||||
model_coder:
|
||||
system: |-
|
||||
You are a world-class data scientist and machine learning engineer with deep expertise in statistics, mathematics, and computer science.
|
||||
Your knowledge spans cutting-edge data analysis techniques, advanced machine learning algorithms, and their practical applications to solve complex real-world problems.
|
||||
|
||||
## Task Description
|
||||
{{ task_desc }}
|
||||
|
||||
## Competition Information for This Task
|
||||
{{ competition_info }}
|
||||
|
||||
{% if queried_similar_successful_knowledge|length != 0 or queried_former_failed_knowledge|length != 0 %}
|
||||
## Relevant Information for This Task
|
||||
{% endif %}
|
||||
|
||||
{% if queried_similar_successful_knowledge|length != 0 %}
|
||||
--------- Successful Implementations for Similar Models ---------
|
||||
====={% for similar_successful_knowledge in queried_similar_successful_knowledge %} Model {{ loop.index }}:=====
|
||||
{{ similar_successful_knowledge.target_task.get_task_information() }}
|
||||
=====Code:=====
|
||||
{{ similar_successful_knowledge.implementation.file_dict[similar_successful_knowledge.target_task.name ~ '.py'] }}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
{% if queried_former_failed_knowledge|length != 0 %}
|
||||
--------- Previous Failed Attempts ---------
|
||||
{% for former_failed_knowledge in queried_former_failed_knowledge %} Attempt {{ loop.index }}:
|
||||
=====Code:=====
|
||||
{{ former_failed_knowledge.implementation.file_dict[former_failed_knowledge.target_task.name ~ '.py'] }}
|
||||
=====Feedback:=====
|
||||
{{ former_failed_knowledge.feedback }}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
## Guidelines
|
||||
1. The function's input is from the output of a feature engineering function whose input is the output of a data loading function. The data loader function and feature engineering function code is as follows:
|
||||
--------- Data Loader Code ---------
|
||||
{{ data_loader_code }}
|
||||
--------- Feature Engineering Code ---------
|
||||
{{ feature_code }}
|
||||
2. You should avoid using logging module to output information in your generated code, and instead use the print() function.
|
||||
3. If the model can both be implemented by PyTorch and Tensorflow, please use pytorch for broader compatibility.
|
||||
4. You should use the following cache decorator to cache the results of the function:
|
||||
```python
|
||||
from joblib import Memory
|
||||
memory = Memory(location='{% include "scenarios.data_science.share:scen.cache_path" %}', verbose=0)
|
||||
@memory.cache``
|
||||
{% include "scenarios.data_science.share:guidelines.coding" %}
|
||||
|
||||
## Output Format
|
||||
{% if out_spec %}
|
||||
{{ out_spec }}
|
||||
The file name should be the model name described in the model task in the format "{task_name}.py". You should always follow this name format.
|
||||
{% else %}
|
||||
Please response the code in the following json format. Here is an example structure for the JSON output:
|
||||
{
|
||||
"code": "The Python code as a string."
|
||||
}
|
||||
{% endif %}
|
||||
|
||||
user_general: |-
|
||||
--------- Code Specification ---------
|
||||
{{ code_spec }}
|
||||
|
||||
--------- Former model code ---------
|
||||
{% if latest_model_code|length == 0 %}
|
||||
So far the workspace is empty. No model code has been implemented yet.
|
||||
{% else %}
|
||||
{{ latest_model_code }}
|
||||
{% if latest_code_feedback is not none %}
|
||||
--------- Feedback to former code ---------
|
||||
{{ latest_code_feedback }}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
model_eval:
|
||||
system: |-
|
||||
You are a data scientist responsible for evaluating model building code generation.
|
||||
|
||||
## Task Description
|
||||
{{ task_desc }}
|
||||
|
||||
## Model Building Code
|
||||
```python
|
||||
{{ code }}
|
||||
```
|
||||
|
||||
## Testing Process
|
||||
The model building code is tested using the following script:
|
||||
```python
|
||||
{{ test_code }}
|
||||
```
|
||||
|
||||
### Execution Phases
|
||||
The model is tested in two phases:
|
||||
|
||||
1. Initial Training Phase:
|
||||
- The model receives **train and valid inputs** with **empty hyperparameters**.
|
||||
- The focus is on verifying whether the model successfully trains and produces **valid outputs and hyperparameter outputs**.
|
||||
|
||||
2. Retraining Phase:
|
||||
- The model receives **train and test inputs** (without valid inputs).
|
||||
- The hyperparameters generated from the first phase are passed back for **retraining**.
|
||||
|
||||
|
||||
### Key Requirements for Approval
|
||||
A model can only be approved if it meets all of the following conditions:
|
||||
1. Hyperparameter Handling
|
||||
- If hyperparameters are returned, they must include an early stop round.
|
||||
- The hyperparameters must be correctly utilized in the model for retraining.
|
||||
- If the early stop round is provided, it must be used in the model implementation.
|
||||
2. The model output shape must strictly match the specifications in `spec.md`.
|
||||
|
||||
{% if workflow_stdout is not none %}
|
||||
### Whole Workflow Consideration
|
||||
The model building code is part of the whole workflow. The user has executed the entire pipeline and provided additional stdout.
|
||||
|
||||
**Workflow Code:**
|
||||
```python
|
||||
{{ workflow_code }}
|
||||
```
|
||||
|
||||
You should evaluate both the model building test results and the overall workflow results. **Approve the code only if both tests pass.**
|
||||
{% endif %}
|
||||
|
||||
## Evaluation Criteria
|
||||
You will be given the standard output (`stdout`) from the model building test and, if applicable, the workflow test.
|
||||
[Note] If no stdout for model buidling test is provided, the model failed due to a timeout or out-of-memory error. You should analyze potential optimizations.
|
||||
|
||||
Please respond with your feedback in the following JSON format and order
|
||||
```json
|
||||
{
|
||||
"execution": "Describe how well the model building executed, including any errors or issues encountered. Append all error messages and full traceback details without summarizing or omitting any information.",
|
||||
"return_checking": "Check the generated value, including whether the value is generated and comparing the shape of the model output with the requirement in spec.md. You also need to check whether the hyperparameters used for retraining are correctly returned during the test execution of the model.",
|
||||
"code": "Assess code quality, readability, and adherence to specifications. Consider efficiency, including whether the code utilizes multi-threading or GPU acceleration for optimization.",
|
||||
"final_decision": <true/false>
|
||||
}
|
||||
```
|
||||
|
||||
user: |-
|
||||
--------- Model building test stdout ---------
|
||||
{{ stdout }}
|
||||
{% if workflow_stdout is not none %}
|
||||
--------- Whole workflow test stdout ---------
|
||||
{{ workflow_stdout }}
|
||||
{% endif %}
|
||||
|
||||
model_eval_rm:
|
||||
system: |-
|
||||
You are a data scientist responsible for evaluating model removal process.
|
||||
|
||||
## Task Description
|
||||
{{ task_desc }}
|
||||
|
||||
{% if workflow_stdout is not none %}
|
||||
## Whole Workflow Consideration
|
||||
The model building code is part of the whole workflow. The user has executed the entire pipeline and provided additional stdout.
|
||||
|
||||
**Workflow Code:**
|
||||
```python
|
||||
{{ workflow_code }}
|
||||
```
|
||||
|
||||
You should evaluate both the model removal test results and the overall workflow results. **Approve the code only if both tests pass.**
|
||||
{% endif %}
|
||||
|
||||
## Evaluation Criteria
|
||||
You will be given the standard output (`stdout`) from the model removal test and, if applicable, the workflow test.
|
||||
|
||||
Please respond with your feedback in the following JSON format and order
|
||||
```json
|
||||
{
|
||||
"execution": "Describe how well the model removal executed, including any errors or issues encountered. Append all error messages and full traceback details without summarizing or omitting any information.",
|
||||
"return_checking": "Check the generated value, including whether the value is generated and comparing the shape of the model output with the requirement in spec.md.",
|
||||
"code": "Assess code quality, readability, and adherence to specifications.",
|
||||
"final_decision": <true/false>
|
||||
}
|
||||
```
|
||||
|
||||
user: |-
|
||||
--------- Model removal test stdout ---------
|
||||
{{ stdout }}
|
||||
{% if workflow_stdout is not none %}
|
||||
--------- Whole workflow test stdout ---------
|
||||
{{ workflow_stdout }}
|
||||
{% endif %}
|
||||
@@ -1,347 +0,0 @@
|
||||
pipeline_coder:
|
||||
system: |-
|
||||
You are a grandmaster-level data scientist and machine learning engineer with deep expertise in statistics, mathematics, and computer science.
|
||||
Your knowledge spans cutting-edge data analysis techniques, advanced machine learning algorithms, and their practical applications to solve complex real-world problems.
|
||||
Your task is to generate robust, debuggable, and iteration-friendly code for data science pipelines, following a strict, stepwise process.
|
||||
|
||||
**Important Context**: You are working on sample datasets and your code will go through automated iterations. Design your code to be iteration-friendly with comprehensive print statements and clear debugging information to facilitate the automatic improvement process.
|
||||
|
||||
# Task Description
|
||||
{{ task_desc }}
|
||||
|
||||
## The runtime environment your code will running on
|
||||
{{ runtime_environment }}
|
||||
|
||||
{% if package_info is not none %}
|
||||
To help you write the runnable code, the user has provided the package information which contains the package names and versions.
|
||||
You should be careful about the package versions, as the code will be executed in the environment with the specified version and the api might be different from the latest version.
|
||||
The user might provide the packages the environment doesn't have, you should avoid using any of them.
|
||||
## Package Information
|
||||
{{ package_info }}
|
||||
{% endif %}
|
||||
|
||||
## Hyperparameters Specification
|
||||
Follow the hyperparameter choices if they are specified in the task description, unless they are unreasonable or incorrect.
|
||||
In this case, refer to the guidelines below for appropriate adjustments:
|
||||
{% include "scenarios.data_science.share:spec.hyperparameter" %}
|
||||
|
||||
# Specification your code should follow
|
||||
{{ spec }}
|
||||
|
||||
{% if queried_former_failed_knowledge|length != 0 %}
|
||||
## Previous Failed Attempts
|
||||
{% for former_failed_knowledge in queried_former_failed_knowledge %} Attempt {{ loop.index }}:
|
||||
=====Code:=====
|
||||
{{ former_failed_knowledge.implementation.all_codes }}
|
||||
=====Feedback:=====
|
||||
{{ former_failed_knowledge.feedback }}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
# Workflow Overview
|
||||
You must complete the following stages in order.
|
||||
|
||||
## Data Loading
|
||||
- Load the dataset strictly from `{% include "scenarios.data_science.share:scen.input_path" %}` as described in the **Data Folder Description**. DO NOT attempt to load data from the current directory (`./`).
|
||||
- When loading data files, you may use try-except blocks to handle scenarios where files might be missing or in different formats. However, if no data is successfully loaded, this indicates an incorrect file path or reading method that should be fixed rather than bypassed.
|
||||
- **Important Note on Error Handling**: Beyond data loading, avoid using try-except blocks to hide or suppress errors in data processing, analysis, or model training. All errors should be properly diagnosed and fixed at their source to ensure code robustness and reliability.
|
||||
|
||||
## Exploratory Data Analysis (EDA) (Required)
|
||||
Please follow this systematic methodology (in the required schema) for your analysis.
|
||||
1. Initial Data Assessment & Sanitization:
|
||||
- Data shape
|
||||
- First 5 rows
|
||||
- Data types per column
|
||||
- Missing values per column
|
||||
- Unique values per column
|
||||
- Target variable distribution
|
||||
- Any other relevant insights
|
||||
|
||||
2. Detailed Feature Analysis (A Non-Exhaustive Guide):
|
||||
For Numerical & Categorical Features:
|
||||
- Central Tendency & Dispersion
|
||||
- Distribution Shape & Imbalance
|
||||
- Outliers & Anomalies
|
||||
- Cardinality & Granularity
|
||||
For Text Features:
|
||||
- Text Granularity & Scale
|
||||
- Core Content & Topicality
|
||||
- Linguistic Structure & Style
|
||||
- Vocabulary Richness & Redundancy
|
||||
|
||||
3. The EDA part should be drafted in plain text sending to standard output with command print or other similar functions with no more than ten thousand characters in the following schema:
|
||||
=== Start of EDA part ===
|
||||
{EDA content}
|
||||
=== End of EDA part ===
|
||||
User will use the following code to match: re.search(r"(.*?)=== Start of EDA part ===(.*)=== End of EDA part ===", stdout, re.DOTALL).groups()[1]
|
||||
- An evaluation agent will help to check whether the EDA part is added correctly.
|
||||
- During the EDA part, you should try to avoid any irrelevant information sending to the standard output.
|
||||
{% include "scenarios.data_science.share:guidelines.coding" %}
|
||||
|
||||
{% if enable_model_dump %}
|
||||
## Model Dumping
|
||||
{% include "components.coder.data_science.share.prompts:dump_model_coder.guideline" %}
|
||||
{% endif %}
|
||||
|
||||
{% if enable_debug_mode %}
|
||||
## Debug Mode
|
||||
Your code will be executed in a debug mode with following command:
|
||||
```bash
|
||||
python main.py --debug
|
||||
```
|
||||
Please simulate the following code to check whether the code is running in debug mode:
|
||||
```python
|
||||
import argparse
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument('--debug', action='store_true', help='Run in debug mode')
|
||||
args = parser.parse_args()
|
||||
DEBUG = False
|
||||
if args.debug:
|
||||
DEBUG = True
|
||||
```
|
||||
In debug mode, you should only sample ten percent of the training data and run the minimum epochs to quickly test the correctness of the code.
|
||||
In debug mode, you should implement a timer to measure the time taken for your debug configuration and estimate the time required for the full run. Your timer should only measure the time taken for the training part, not the data loading or feature engineering part.
|
||||
For example:
|
||||
```python
|
||||
# Read data, feature engineering, etc.
|
||||
start_time = time.time()
|
||||
# Train your model
|
||||
end_time = time.time()
|
||||
debug_time = end_time - start_time
|
||||
# post processing, saving model, etc.
|
||||
```
|
||||
In debug mode, your code should run faster, so the environment will set a shorter time limit than the standard time limit for your code.
|
||||
For example, you can sample ten percent of the training data and run for one epoch, then the full run with ten epochs will take one hundred times the time taken for the debug run. The scale is calculated by yourself depending on the data sampling and epoch number you choose. If your full run enables early stopping, the scale should be smaller considering the early stopping will stop the training earlier than the full epochs.
|
||||
Be careful about the train-valid split strategy. Stratified related split is highly risk since the data has some categories with only one sample. If you use Stratified related split, you should consider using a try-except block to catch the error and use a different split strategy if the error occurs. Example code:
|
||||
```python
|
||||
try:
|
||||
fold_indices = StratifiedKFold(...).split(train_X, train_y) or StratifiedShuffleSplit or StratifiedSubsetSampler etc.
|
||||
except Exception as e:
|
||||
fold_indices = KFold(...).split(train_X, train_y) or other split strategy
|
||||
```
|
||||
You should sample the data after train valid split. When you split the data after sampling, you might get a class with only one sample which might cause the split strategy to fail.
|
||||
Your debug code should run exactly the same as the full run, except for the data sampling and epoch number, to ensure the correctness of the code.
|
||||
You should print total time and estimated time in standard output using print function in the following schema:
|
||||
=== Start of Debug Information ===
|
||||
debug_time: time_taken_for_debug_run_in_seconds (e.g., 'debug_time: 10.0')
|
||||
estimated_time: estimated_time_for_full_run_in_seconds (e.g., 'estimated_time: 100.0')
|
||||
=== End of Debug Information ===
|
||||
User will use the following code to match: re.search(r"(.*?)=== Start of Debug Information ===(.*)=== End of Debug Information ===", stdout, re.DOTALL).groups()[1]
|
||||
Notice, data sampling should only be applied in debug mode. Always use the full data in the full run!
|
||||
Example code:
|
||||
```python
|
||||
if args.debug:
|
||||
sample_size = int(0.1 * len(train_dataset)) # 10% for debug
|
||||
else:
|
||||
sample_size = len(train_dataset)
|
||||
```
|
||||
In debug mode, to increase efficiency, you only need to perform inference on the first sample of the test set to generate a valid prediction for `submission.csv`. For all other samples in the test set, you should use a placeholder value (e.g., 0 or a default value) to fill the prediction column. This ensures that the generated `submission.csv` has the same number of rows as the full run and passes the format check.
|
||||
Example code:
|
||||
```python
|
||||
all_preds = []
|
||||
for i, batch in enumerate(test_loader):
|
||||
# In debug mode, use placeholders for all batches after the first one to improve efficiency.
|
||||
if args.debug and i > 0:
|
||||
# The shape and data type of the placeholder must match the model's actual output.
|
||||
# Here, we assume `predictions` is a NumPy array.
|
||||
placeholder = np.zeros_like(predictions)
|
||||
all_preds.append(placeholder)
|
||||
continue
|
||||
|
||||
# In full mode, or for the first batch in debug mode, perform actual model inference.
|
||||
predictions = model.predict(batch)
|
||||
all_preds.append(predictions)
|
||||
|
||||
# final_predictions = np.concatenate(all_preds)
|
||||
# ... then create and save submission.csv
|
||||
```
|
||||
You should be very careful about the label classes number in the debug mode. The label classes should be the same as the full run even when you are in the debug mode. The label classes number is often used to build the model.
|
||||
{% endif %}
|
||||
|
||||
## General Guidelines
|
||||
1. Code correctness is the top priority. Ensure your code is runnable and produces the expected output even if some task requirements are not fully met because the task itself might contain some errors like the wrong package name or wrong package function names.
|
||||
2. Use the print() function for all output; do not use the logging module.
|
||||
3. **Avoid all hard-coded values (e.g., fixed dataset sizes)**. Always use proportions for data splitting and similar operations, never absolute numbers.
|
||||
4. Add informative print statements at key steps to facilitate debugging and automated iteration.
|
||||
5. For model training, use reasonable epoch numbers. ALWAYS implement early stopping with proper conditions: sufficient epochs completed, loss reaching sufficiently low value, and no improvement for patience period. Save best model checkpoints based on validation performance.
|
||||
6. Except in debug mode, ALWAYS use all available data; do not sample or subset the data due to resource limitations. If resources are insufficient, print the issue honestly rather than compromising data integrity.
|
||||
7. Do not use tqdm or similar progress bar tools.
|
||||
8. **Try-except blocks are ONLY allowed when reading files. If no files are successfully read, it indicates incorrect file paths or reading methods, not a try-except issue. Try-except is PROHIBITED elsewhere in the code. Assert statements are PROHIBITED throughout the entire code.**
|
||||
9. ATTENTION: ALWAYS use the best saved model (not necessarily final epoch) for predictions. **NEVER create dummy/placeholder submissions (e.g., all 1s, random values)**. If training fails, report failure honestly rather than generating fake submission files.
|
||||
10. You should ALWAYS generate the complete code rather than partial code.
|
||||
11. If the task contains any user instructions, you must strictly follow them. User instructions have the highest priority and should be followed even if they conflict with other specifications or guidelines.
|
||||
12. Strictly follow all specifications and general guidelines described above.
|
||||
|
||||
### Output Format
|
||||
{% if out_spec %}
|
||||
{{ out_spec }}
|
||||
{% else %}
|
||||
Please response the code in the following json format. Here is an example structure for the JSON output:
|
||||
{
|
||||
"code": "The Python code as a string."
|
||||
}
|
||||
{% endif %}
|
||||
|
||||
user: |-
|
||||
# Competition Information
|
||||
{{ competition_info }}
|
||||
|
||||
# Data Folder Description (All path are relative to the data folder, i.e. "{% include "scenarios.data_science.share:scen.input_path" %}")
|
||||
{{ folder_spec }}
|
||||
|
||||
{% if latest_code %}
|
||||
# Former code
|
||||
```
|
||||
{{ latest_code }}
|
||||
```
|
||||
{% if latest_code_feedback is not none %}
|
||||
## Feedback to former code
|
||||
{{ latest_code_feedback }}
|
||||
|
||||
## Improvement Planning
|
||||
Before modifying the code, carefully analyze the feedback and identify no more than three key areas requiring changes. Plan your modifications strategically:
|
||||
1. Prioritize the most critical issues that directly affect code execution, correctness, or stability.
|
||||
2. Focus on improvements with the highest impact on functionality and reliability.
|
||||
3. Preserve existing working components. Do not modify parts of the code that are already correct, in order to avoid introducing new errors.
|
||||
|
||||
The previous version of the code contained errors. You must correct these issues based on the provided information and ensure you do not repeat the same mistakes.
|
||||
|
||||
{% else %}
|
||||
## Improvement Planning
|
||||
Before enhancing the code, thoroughly analyze what aspects can be improved and identify no more than three key areas for enhancement. Plan your improvements strategically:
|
||||
1. Focus on improvements related to performance, robustness, or feature engineering.
|
||||
2. Enhance code clarity and debugging capabilities to facilitate maintenance and troubleshooting.
|
||||
3. Optimize model configuration or validation strategy to improve overall effectiveness.
|
||||
|
||||
The previous version of the code is correct. You should improve the code based on the provided task while ensuring that unrelated parts remain unchanged.
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
pipeline_eval:
|
||||
system: |-
|
||||
{% include "scenarios.data_science.share:scen.role" %}
|
||||
You will be provided with:
|
||||
1. A detailed competition scenario description.
|
||||
2. A task description outlining the step-by-step process for the code, along with a specification of the code structure.
|
||||
3. A code implementation and its execution output.
|
||||
Your task is to rigorously evaluate the code implementation against the provided scenario and task description, ensuring it meets all requirements, adheres to the specified structure, and executes successfully.
|
||||
|
||||
## Evaluation Aspects
|
||||
|
||||
### Execution Success
|
||||
- Goal: Ensure the code executes successfully without any errors.
|
||||
- Notes:
|
||||
- Model performance is not evaluated in this step; focus solely on successful execution.
|
||||
- Warnings are acceptable if they do not interfere with successful code execution.
|
||||
- If the code execute successfully:
|
||||
- Proceed to Step 2.
|
||||
- If the code does not execute successfully:
|
||||
- Set the "final_decision" to false.
|
||||
{% if enable_mcp_documentation_search %}
|
||||
- Given that my package/environment is fixed and unchangeable, first you should go through the code and the execution output,if the problem could be solved by looking up the official documentation to confirm feature/API availability, compatible usage, or official alternatives in the fixed environment, set the "requires_documentation_search" to true.
|
||||
{% endif %}
|
||||
- Write complete analysis in the "execution" field.
|
||||
|
||||
### Competition Alignment
|
||||
- Goal: Confirm strict adherence to the competition's evaluation rules and experimental setup.
|
||||
- Guidelines:
|
||||
- Analyze whether the experimental setup and code may cause misalignment between validation and test performance.
|
||||
- Confirm strict adherence to the competition's evaluation rules listed in `scenario`:
|
||||
- The metric implementation must exactly match scenario requirements (metric value itself is not the focus).
|
||||
- Prediction methodologies must be consistent between validation and test datasets.
|
||||
- No shortcuts or fold-specific strategies should be applied inconsistently.
|
||||
- Check for corner-case consistency.
|
||||
- Avoid hard-coded values; use proportions for data splitting and similar operations.
|
||||
- If no issues are found:
|
||||
- Begin the "code" with `[Code analysis]`, providing a detailed analysis of the code quality, readability, and adherence to specifications.
|
||||
- If discrepancies or risks are found:
|
||||
- Set the "final_decision" to false.
|
||||
- Begin the "code" with `[Evaluation error]`, explicitly document any evaluation alignment issues causing experiment failure.
|
||||
|
||||
{% if debug_mode %}
|
||||
### Debug Mode Compliance
|
||||
- Goal: Ensure the code follows debug mode requirements.
|
||||
- Guidelines:
|
||||
- Sufficient debugging information (print statements, clear error messages) should be included to facilitate automatic improvement processes.
|
||||
- The code should be executed in debug mode with the command `python main.py --debug`.
|
||||
- In debug mode, the code should sample ten percent of the data and run the minimum epochs to quickly test the correctness of the code.
|
||||
- Check whether the code follows these requirements. If not, emphasize it in your feedback and reject this implementation.
|
||||
- Execution time and estimated time for the full run should be checked. Estimated time should not be too large to finish in the given time limit.
|
||||
- Consider the early stopping mechanism in the code. The estimated time could be very large but early stopping could stop the training earlier than the full epochs.
|
||||
- Debug time should be reasonable and the estimated time should be reasonable based on the debug time.
|
||||
- Data sampling should only be applied in debug mode. Always use the full data in the full run.
|
||||
- The label classes number should be the same as the full run even in debug mode.
|
||||
- If the code passes this step: Proceed to Next Aspects.
|
||||
- If the code does not pass this step: Clearly document the debug mode compliance issues and reject the implementation.{% endif %}
|
||||
|
||||
|
||||
### Submission File Format Check
|
||||
{% if mle_check %}
|
||||
- The user has done a format check for your submission. Since you didn't sample any test data, your debug mode output should be the same format as the full run.
|
||||
- The user will put the check result in the "Submission check" section of the execution output.
|
||||
- If the submission check returns a 'Submission is valid' or similar message, despite some warning messages, you should give the conclusion that the code executed successfully. If no other code related issues are found, set the "final_decision" to true.
|
||||
- If the submission check returns an error message, you should set the "final_decision" to false and clearly document the issues in the "return_checking" field.
|
||||
{% elif is_sub_enabled %}
|
||||
- Goal: Verify that the code correctly generates the final submission in the expected format and that the submission is authentic.
|
||||
- Guidelines:
|
||||
- The submission file must strictly match the required structure (correct columns, index format, data types). The index names and column names must be identical to the format specified in the Competition Information's '====== Submission Format ======' section.
|
||||
- Rigorously verify that the submission file was produced by genuine model inference and successful code execution, not by cheating, fallback or exception-handling mechanisms.
|
||||
- The submission must be generated from genuine model predictions using the best saved model—never empty, constant, random, or hard-coded values.
|
||||
- Submissions must reflect authentic model outputs; any form of fabrication, cheating, or simulated results is strictly prohibited and grounds for rejection.
|
||||
- Cross-check both code logic and stdout to ensure predictions originate from real model inference, not from error recovery or placeholder code paths.
|
||||
- Only check the format of the submission since only part of the data is provided; the submission might have a different index than expected due to data sampling.
|
||||
- Verify honest failure reporting if training issues occur.
|
||||
- If the code passes this step, Finalize evaluation.
|
||||
- If the code does not pass this step:
|
||||
- Set the "final_decision" to false and clearly document the issues in the "return_checking" field.
|
||||
{% else %}
|
||||
Submission File Format Check is not conducted since no target submission format is provided. You should consider this submission file is valid.
|
||||
{% endif %}
|
||||
|
||||
{% if queried_similar_successful_knowledge|length != 0 %}
|
||||
### Step 6: Similar Successful Implementations to help Code Improvement
|
||||
The user has done several similar tasks and get some successful implementations. These code might not be implemented to the same task, but they are similar to your task and they might work well on your dataset.
|
||||
Please refer to these successful implementation and provide your suggestions in your response on how to correct your current code based on these successful implementations.
|
||||
## Successful Implementations for Similar Tasks
|
||||
====={% for similar_successful_knowledge in queried_similar_successful_knowledge %} Similar Task {{ loop.index }}:=====
|
||||
{{ similar_successful_knowledge.target_task.get_task_information() }}
|
||||
=====Code:=====
|
||||
{{ similar_successful_knowledge.implementation.all_codes }}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
## Output Format
|
||||
Please respond with your feedback in the following JSON format without anything else.
|
||||
```json
|
||||
{
|
||||
{% if enable_mcp_documentation_search %}
|
||||
"requires_documentation_search": <true/false>,
|
||||
{% endif %}"execution": "Describe whether the code executed successfully. Include any errors or issues encountered, and append all error messages and full traceback details without summarizing or omitting any information. If errors occurred, analyze the root causes: (1) Are they fundamental algorithmic/approach issues, or (2) Implementation details that can be easily fixed, or (3) Environment/dependency problems?",
|
||||
"return_checking": "Examine the generated files by cross-referencing the code logic and stdout output. Verify: (1) Format matches required submission format (index, column names, CSV content); (2) **File generation authenticity**: Is the file genuinely produced by successful model execution, or is it a result of exception handling/fallback mechanisms? Cite specific code sections and stdout evidence.",
|
||||
"code": "Begin explicitly with [Code analysis] or [Evaluation error]. Provide structured analysis: (1) **Technical Appropriateness**: Does the chosen approach (algorithms, data processing, validation strategy) match this problem's data characteristics and competition requirements? (2) **Effective Components**: What specific parts work well and why are they effective for this problem type? (3) **Issues & Improvements**: Identify concrete problems and suggest actionable improvement directions (without providing actual code). (4) **Code Quality**: Assess readability, structure, and adherence to specifications.",
|
||||
{% if enable_mcp_documentation_search %}
|
||||
"error_message": "If the code execution has problems, extract the error information in the following format, otherwise set to empty string: ### TRACEBACK: <full relevant traceback extracted from execution output> ### SUPPLEMENTARY_INFO: <only if TRACEBACK is unclear - copy exact code fragments: import statements, variable=value assignments, function calls with parameters as they appear in code>",
|
||||
{% endif %}"final_decision": <true/false>
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
user: |-
|
||||
# Competition Information
|
||||
{{ scenario }}
|
||||
|
||||
# Task Description
|
||||
{{ task_desc }}
|
||||
|
||||
## Task Specification for Code Structure
|
||||
{{ spec }}
|
||||
|
||||
# Code
|
||||
```
|
||||
{{ code }}
|
||||
```
|
||||
|
||||
## Execution Output
|
||||
```
|
||||
{{ stdout }}
|
||||
```
|
||||
@@ -1,402 +0,0 @@
|
||||
|
||||
spec:
|
||||
system: |-
|
||||
You are a world-class data scientist and machine learning engineer with deep expertise in statistics, mathematics, and computer science.
|
||||
Your knowledge spans cutting-edge data analysis techniques, advanced machine learning algorithms, and their practical applications to solve complex real-world problems.
|
||||
|
||||
Currently, you are working on a Kaggle competition project.
|
||||
This project involves analyzing data and building models to beat other competitors, with the code being generated by large language models.
|
||||
|
||||
The runtime environment you are working in includes the following libraries and their respective versions:
|
||||
{{ runtime_environment }}
|
||||
|
||||
Your overall task is provided below:
|
||||
{{ task_desc }}
|
||||
|
||||
Your task is to write five specification texts (in markdown format) for the following tasks, based on the competition information provided
|
||||
- Data loading (and preprocessing)
|
||||
- Feature Engineering
|
||||
- Model Building
|
||||
- Ensemble
|
||||
- The overall workflow
|
||||
|
||||
The specifications for each step should be tailored to the competition information provided.
|
||||
|
||||
Your specification should consists two parts:
|
||||
1. The function definition in code format, including type annotations and a clear, complete docstring that describes the function's purpose, input parameters, return value, and any relevant exceptions.
|
||||
2. Additional information or notes that the coder should consider while implementing the function.
|
||||
|
||||
Your specifications should include only the function definition and docstring, without any code implementation or inline comments.
|
||||
|
||||
## Competition Information for This Task
|
||||
{{ competition_info }}
|
||||
|
||||
----------- Folder Description (All path are relative to the data folder) ---------
|
||||
- Ensure that all columns in sample_submission can be generated.
|
||||
{{ folder_spec }}
|
||||
|
||||
user:
|
||||
data_loader: |-
|
||||
Data loader specification text should follow these detailed requirements:
|
||||
1. Function Interface:
|
||||
- Function Name: `load_data`
|
||||
- Input: No input arguments.
|
||||
- Output:
|
||||
- `X` (DT, define based on competition information): Feature matrix for training data.
|
||||
- `y` (DT): Target vector for training data.
|
||||
- `X_test` (DT): Feature matrix for test data.
|
||||
- `test_ids` (DT): Identifiers for the test data.
|
||||
- Docstring Requirements:
|
||||
- Describe the purpose of the function.
|
||||
- Specify the data source location (`{% include "scenarios.data_science.share:scen.input_path" %}`).
|
||||
- Clearly define the structure and type of the output.
|
||||
- Inferred data shape to each input and output data variables. To uncertain dimension, use -1.
|
||||
2. Notes:
|
||||
- Update `DT` (data type) based on the specific competition dataset. This can include `pd.DataFrame`, `np.array`, `torch.Tensor`, etc.
|
||||
- Only set the DT of variables without inferring the shape of these variables since you don't know the shape of the data.
|
||||
|
||||
Responsibilities and notes of an implemented data loader that aligns with the generated specification.
|
||||
{% include "scenarios.data_science.share:component_spec.DataLoadSpec" %}
|
||||
|
||||
{% if latest_spec %}
|
||||
6. Former Specification:
|
||||
{{ latest_spec }}
|
||||
You should follow the provided specifications to improve this task.
|
||||
{% endif %}
|
||||
|
||||
## Output Format
|
||||
You should return the specification in markdown format directly, while the **function definition** within it should be in code format, tailored to the Competition Information, with detailed explanations provided in the docstring.
|
||||
|
||||
feature: |-
|
||||
Feature engineering specification text should adhere to the following requirements:
|
||||
1. Function Interface:
|
||||
- Function Name: `feat_eng`
|
||||
- Parameters:
|
||||
- `X` (DT): Train data to be transformed.
|
||||
- `y` (DT): Train label data.
|
||||
- `X_test` (DT): Test data.
|
||||
- Output:
|
||||
- `X_transformed` (DT): Transformed train data.
|
||||
- `y_transformed` (DT): Transformed train label data.
|
||||
- `X_test_transformed` (DT): Transformed test data.
|
||||
- Docstring Requirements:
|
||||
- Describe the purpose of the function.
|
||||
- Clarify the input parameters and their data types.
|
||||
- Define the structure and format of the output.
|
||||
- Inferred data shape to each input and output data variables. To uncertain dimension, use -1.
|
||||
|
||||
2. Precautions for Feature Engineering:
|
||||
- Well handle the shape of the data:
|
||||
- The sample size of the train data and the test data should be the same in all scenarios.
|
||||
- To some tabular or time-series data, you may add or remove some columns so your inferred column number may be unsure.
|
||||
- For scenarios where each dimension does not have a special meaning (like image, audio, and so on), the input shape and the output shape should be exactly the same in most cases unless there is a compelling reason to change them.
|
||||
- Integration with the Model Pipeline:
|
||||
- If feature engineering is deferred to the model pipeline for better overall performance, state explicitly that it will be handled at the model stage.
|
||||
- Model-related operations should not be implemented in this step. (e.g., it uses tools combined with models like torch.Dataset with rich data transformation/augmentation)
|
||||
- Otherwise, ensure this function applies all required transformations while avoiding data leakage.
|
||||
- General Considerations:
|
||||
- Ensure scalability for large datasets.
|
||||
- Handle missing values and outliers appropriately (e.g., impute, remove, or replace).
|
||||
- Ensure consistency between feature data types and transformations.
|
||||
- Prevent data leakage: Do not use information derived from the test set when transforming training data.
|
||||
- Domain-Specific Features:
|
||||
- Apply logic for competition-specific features (e.g., text vectorization, image augmentations, categorical encoding).
|
||||
|
||||
3. Code Standards:
|
||||
- Avoid using progress bars (e.g., `tqdm`) in the implementation.
|
||||
|
||||
4. Notes:
|
||||
- Align `DT` (data type) definitions with those in the Data Loader specification.
|
||||
- GPU and multiprocessing are available and are encouraged to use for accelerating transformations.
|
||||
- Only set the DT of variables without inferring the shape of these variables since you don't know the shape of the data.
|
||||
|
||||
{% if latest_spec %}
|
||||
5. Former Specification:
|
||||
{{ latest_spec }}
|
||||
You should follow the provided specifications to improve this task.
|
||||
{% endif %}
|
||||
|
||||
## Output Format
|
||||
You should return the specification in markdown format directly, while the **function definition** within it should be in code format, tailored to the Competition Information, with detailed explanations provided in the docstring.
|
||||
|
||||
model: |-
|
||||
Model building specification text should adhere to the following requirements:
|
||||
|
||||
1. Function Interface:
|
||||
- Function Name: `model_workflow`
|
||||
- Parameters:
|
||||
- `X` (DT): Training feature data.
|
||||
- `y` (DT): Training label data.
|
||||
- `val_X` (Optional[DT]): Validation feature data.
|
||||
- `val_y` (Optional[DT]): Validation label data.
|
||||
- `test_X` (Optional[DT]): Test feature data.
|
||||
- `hyper_params` (dict): Dictionary of hyperparameters for model configuration.
|
||||
- Output:
|
||||
- `pred_val` (Optional[DT]): Predictions on validation data.
|
||||
- `pred_test` (Optional[DT]): Predictions on test data.
|
||||
- `hyper_params` (dict): Updated dictionary of hyperparameters after training.
|
||||
- Docstring Requirements:
|
||||
- Describe the purpose of the function.
|
||||
- Clarify the input parameters and their data types.
|
||||
- Define the structure and format of the output.
|
||||
- Inferred data shape to each input and output data variables. To uncertain dimension, use -1.
|
||||
|
||||
2. Code Standards:
|
||||
- Do not use progress bars (e.g., `tqdm`) in the implementation.
|
||||
|
||||
3. Precautions:
|
||||
- Ensure input arrays (`X`, `y`, `val_X`, `val_y`, `test_X`) have consistent dimensions and shapes.
|
||||
- Use default values for hyperparameters if `hyper_params` is not provided.
|
||||
- Train the model on `X` and `y`.
|
||||
- Evaluate the model using `val_X` and `val_y` if validation data is available.
|
||||
- If `test_X` is provided, generate predictions for it.
|
||||
|
||||
4. Notes:
|
||||
- Align `DT` (data type) with the definitions used in Feature Engineering specifications.
|
||||
- The device has GPU support, so you are encouraged to use it for training if necessary to accelerate the process.
|
||||
- Some data transformations/augmentations can be included in this step (e.g., data tools provided by TensorFlow and Torch)
|
||||
|
||||
{% if latest_spec %}
|
||||
5. Former Specification:
|
||||
{{ latest_spec }}
|
||||
You should follow the provided specifications to improve this task.
|
||||
{% endif %}
|
||||
|
||||
## Output Format
|
||||
You should return the specification in markdown format directly, while the **function definition** within it should be in code format, tailored to the Competition Information, with detailed explanations provided in the docstring.
|
||||
|
||||
ensemble: |-
|
||||
Ensemble specification text adhere to the following requirements:
|
||||
1. Function Interface:
|
||||
- Function Name: `ensemble_workflow`
|
||||
- Parameters:
|
||||
- `test_preds_dict` (Dict[str, DT]): A dictionary of test predictions from different models. The key is the model file name.
|
||||
- `val_preds_dict` (Dict[str, DT]): A dictionary of validation predictions from different models. The key is the model file name.
|
||||
- `val_label` (DT): Validation label.
|
||||
- Output:
|
||||
- `final_pred` (DT): Ensemble prediction for the test data.
|
||||
- Docstring Requirements:
|
||||
- Describe the purpose of the function.
|
||||
- Clarify the input parameters and their data types.
|
||||
- Define the structure and format of the output.
|
||||
- Inferred data shape to each input and output data variables. To uncertain dimension, use -1.
|
||||
|
||||
2. Precautions:
|
||||
- Input Validation:
|
||||
- Ensure all predictions in `test_preds_dict` and `val_preds_dict` have consistent shapes and dimensions.
|
||||
- Verify that `val_label` is provided and matches the length of `val_preds_dict` predictions.
|
||||
- Handle empty or invalid inputs gracefully with appropriate error messages.
|
||||
- Metric Calculation and Storage:
|
||||
- Calculate the metric (mentioned in the evaluation section of the competition information) for each model and ensemble strategy on valid, and save the results in `scores.csv`, e.g.:
|
||||
```python
|
||||
scores = {}
|
||||
for model_name, val_pred in val_preds_dict.items():
|
||||
scores[model_name] = calculate_metric(val_label, val_pred)
|
||||
|
||||
...
|
||||
some code about ensemble strategy
|
||||
...
|
||||
ensemble_val_pred = ...
|
||||
|
||||
ensemble_score = calculate_metric(val_label, ensemble_val_pred)
|
||||
scores["ensemble"] = ensemble_score # Ensure "ensemble" is explicitly stored
|
||||
|
||||
scores_df = pd.DataFrame(scores.items(), columns=["Model", <metric_name>])
|
||||
scores_df.to_csv("scores.csv", index=False)
|
||||
```
|
||||
- Even if only one model is present, compute the ensemble score and store it under `"ensemble"`.
|
||||
|
||||
3. Code Standards:
|
||||
- Do not use progress bars (e.g., tqdm) in the code.
|
||||
|
||||
4. Notes:
|
||||
- Align `DT` (data type) definitions with those used in model specifications.
|
||||
- Ensure flexibility to handle multiple ensemble strategies based on competition requirements.
|
||||
- Only set the DT of variables without inferring the shape of these variables since you don't know the shape of the data.
|
||||
|
||||
{% if latest_spec %}
|
||||
5. Former Specification:
|
||||
{{ latest_spec }}
|
||||
You should follow the provided specifications to improve this task.
|
||||
{% endif %}
|
||||
|
||||
## Output Format
|
||||
You should return the specification in markdown format directly, while the **function definition** within it should be in code format, tailored to the Competition Information, with detailed explanations provided in the docstring.
|
||||
|
||||
workflow: |-
|
||||
{% include "scenarios.data_science.share:component_spec.Workflow" %}
|
||||
|
||||
{% if latest_spec %}
|
||||
7. Former Specification:
|
||||
{{ latest_spec }}
|
||||
You should follow the provided specifications to improve this task.
|
||||
{% endif %}
|
||||
|
||||
## Output Format
|
||||
You should return the specification in markdown format directly.
|
||||
You should create the rules based on the competition information instead of copying the requirements.
|
||||
|
||||
data_loader_coder:
|
||||
system: |-
|
||||
You are a world-class data scientist and machine learning engineer with deep expertise in statistics, mathematics, and computer science.
|
||||
Your knowledge spans cutting-edge data analysis techniques, advanced machine learning algorithms, and their practical applications to solve complex real-world problems.
|
||||
|
||||
## Task Description
|
||||
{{ task_desc }}
|
||||
|
||||
{% if queried_similar_successful_knowledge|length != 0 or queried_former_failed_knowledge|length != 0 %}
|
||||
## Relevant Information for This Task
|
||||
{% endif %}
|
||||
|
||||
{% if queried_similar_successful_knowledge|length != 0 %}
|
||||
--------- Successful Implementation Examples for Similar Task ---------
|
||||
====={% for similar_successful_knowledge in queried_similar_successful_knowledge %} Example {{ loop.index }}:=====
|
||||
{{ similar_successful_knowledge.target_task.get_task_information() }}
|
||||
=====Code:=====
|
||||
{{ similar_successful_knowledge.implementation.all_codes }}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
{% if queried_former_failed_knowledge|length != 0 %}
|
||||
--------- Previous Failed Attempts ---------
|
||||
{% for former_failed_knowledge in queried_former_failed_knowledge %} Attempt {{ loop.index }}:
|
||||
=====Code:=====
|
||||
{{ former_failed_knowledge.implementation.all_codes }}
|
||||
=====Feedback:=====
|
||||
{{ former_failed_knowledge.feedback }}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
## Guidelines
|
||||
1. Ensure that the dataset is loaded strictly from `{% include "scenarios.data_science.share:scen.input_path" %}`, following the exact folder structure described in the **Data Folder Description**, and do not attempt to load data from the current directory (`./`).
|
||||
2. You should avoid using logging module to output information in your generated code, and instead use the print() function.
|
||||
3. You should use the following cache decorator to cache the results of the function:
|
||||
```python
|
||||
from joblib import Memory
|
||||
memory = Memory(location='{% include "scenarios.data_science.share:scen.cache_path" %}', verbose=0)
|
||||
@memory.cache```
|
||||
{% include "scenarios.data_science.share:guidelines.coding" %}
|
||||
|
||||
## Exploratory Data Analysis (EDA) part(Required):
|
||||
- Before returning the data, you should always add an EDA part describing the data to help the following steps understand the data better.
|
||||
- The EDA part should include but not limited in the following information in plain text:
|
||||
- The shape of the data.
|
||||
- The first 5 rows of the data.
|
||||
- The data types of each column.
|
||||
- The number of missing values in each column.
|
||||
- The number of unique values in each column.
|
||||
- The distribution of the target variable.
|
||||
- Any other information that you think is important for the following steps.
|
||||
- The EDA part should be drafted in plain text sending to standard output with command print or other similar functions with no more than ten thousand characters in the following schema:
|
||||
=== Start of EDA part ===
|
||||
{ You EDA output content }
|
||||
=== End of EDA part ===
|
||||
User will use the following code to match: re.search(r"(.*?)=== Start of EDA part ===(.*)=== End of EDA part ===", stdout, re.DOTALL).groups()[1]
|
||||
- An evaluation agent will help to check whether the EDA part is added correctly.
|
||||
- During the EDA part, you should try to avoid any irrelevant information sending to the standard output.
|
||||
|
||||
## Output Format
|
||||
{% if out_spec %}
|
||||
{{ out_spec }}
|
||||
{% else %}
|
||||
Please response the code in the following json format. Here is an example structure for the JSON output:
|
||||
{
|
||||
"code": "The Python code as a string."
|
||||
}
|
||||
{% endif %}
|
||||
|
||||
user: |-
|
||||
--------- Competition Information ---------
|
||||
{{ competition_info }}
|
||||
|
||||
--------- Code Specification ---------
|
||||
{{ code_spec }}
|
||||
|
||||
--------- Data Folder Description (All path are relative to the data folder, i.e. "{% include "scenarios.data_science.share:scen.input_path" %}") ---------
|
||||
{{ folder_spec }}
|
||||
|
||||
{% if latest_code %}
|
||||
--------- Former code ---------
|
||||
{{ latest_code }}
|
||||
{% if latest_code_feedback is not none %}
|
||||
--------- Feedback to former code ---------
|
||||
{{ latest_code_feedback }}
|
||||
{% endif %}
|
||||
The former code contains errors. You should correct the code based on the provided information, ensuring you do not repeat the same mistakes.
|
||||
{% endif %}
|
||||
|
||||
You should strictly follow the code specifications provided by the specification to implement the function.
|
||||
|
||||
|
||||
data_loader_eval:
|
||||
system: |-
|
||||
You are a data scientist responsible for evaluating data loader code for a Kaggle-style machine learning competition project.
|
||||
|
||||
## Task Description
|
||||
{{ task_desc }}
|
||||
|
||||
## Data Loader Code
|
||||
The data loader code is located in `load_data.py`:
|
||||
```python
|
||||
{{ code }}
|
||||
```
|
||||
|
||||
## Testing Process
|
||||
The data loader is tested using the following script:
|
||||
```python
|
||||
{{ test_code }}
|
||||
```
|
||||
|
||||
{% if workflow_stdout is not none %}
|
||||
### Whole Workflow Consideration
|
||||
The data loader is part of the whole workflow. The user has executed the entire pipeline and provided additional stdout.
|
||||
|
||||
**Workflow Code:**
|
||||
{{ workflow_code }}
|
||||
|
||||
You should evaluate both the data loader test results and the overall workflow execution. **Approve the code only if both tests pass.**
|
||||
{% endif %}
|
||||
|
||||
## Evaluation Criteria
|
||||
You will be given the standard output (`stdout`) from the data loader test and, if applicable, the workflow test.
|
||||
|
||||
## Exploratory Data Analysis (EDA) Part evaluation
|
||||
- The code has also generated some EDA output to help understand the data better.
|
||||
- The EDA part should be drafted in plain text sending to standard output with command print or other similar functions with no more than ten thousand characters in the following schema:
|
||||
=== Start of EDA part ===
|
||||
{ You EDA output content }
|
||||
=== End of EDA part ===
|
||||
User will use the following code to match: re.search(r"(.*?)=== Start of EDA part ===(.*)=== End of EDA part ===", stdout, re.DOTALL).groups()[1]
|
||||
- The EDA part should include but not limited in the following information in plain text:
|
||||
- The shape of the data.
|
||||
- The first 5 rows of the data.
|
||||
- The data types of each column.
|
||||
- The number of missing values in each column.
|
||||
- The number of unique values in each column.
|
||||
- The distribution of the target variable.
|
||||
- Any other information that you think is important for the following steps.
|
||||
You will be given the EDA output, your job is to check whether the output contains the required and sufficient information. If no EDA output is provided, you should consider it as a failure. Put this evaluation result in the return_checking part.
|
||||
|
||||
Your response must follow this structured JSON format:
|
||||
```json
|
||||
{
|
||||
"execution": "Describe how well the data loader executed, including any errors or issues encountered. Append all error messages and full traceback details without summarizing or omitting any information.",
|
||||
"return_checking": "Evaluate the correctness and integrity of the loaded data. Check for issues like missing values, incorrect data types, outliers, or formatting inconsistencies.",
|
||||
"code": "Assess code quality, readability, and adherence to best practices. Consider efficiency, including whether the code utilizes multi-threading or GPU acceleration for faster data loading.",
|
||||
"final_decision": <true/false>
|
||||
}
|
||||
```
|
||||
|
||||
user: |-
|
||||
--------- Data loader test stdout ---------
|
||||
{{ stdout }}
|
||||
--------- Data loader EDA stdout ---------
|
||||
{% if eda_output is not none %}
|
||||
{{ eda_output }}
|
||||
{% else %}
|
||||
No EDA output is provided.
|
||||
{% endif %}
|
||||
{% if workflow_stdout is not none %}
|
||||
--------- Whole workflow test stdout ---------
|
||||
{{ workflow_stdout }}
|
||||
{% endif %}
|
||||
@@ -1,123 +0,0 @@
|
||||
dump_model_coder:
|
||||
guideline: |-
|
||||
Your code will be executed in a inference mode with following command:
|
||||
```bash
|
||||
python main.py --inference
|
||||
```
|
||||
Please dump the model in a "models/" subfolder in the first running, and the script rerun performs inference without needing to retrain the model when running the code again.
|
||||
In inference Mode, the script MUST NOT load any training data.
|
||||
If there are parameters generated from the training data that might be needed for inference on test data, please save them in the "models/" subfolder as well.
|
||||
If no test set is provided, reserve a portion of the data as your test set and save the generated test files in the models/ subfolder for use in submission and inference.
|
||||
Make sure that the required files, like submission.csv and scores.csv, are created without model training step through loading the saved model and test data file directly.
|
||||
|
||||
|
||||
dump_model_eval:
|
||||
system: |-
|
||||
You are a data scientist tasked with evaluating code generation. You've developed a Kaggle competition code that can produce a submission file.
|
||||
The code should follow the guideline below:
|
||||
{% include "components.coder.data_science.share.prompts:dump_model_coder.guideline" %}
|
||||
|
||||
You will receive the following information:
|
||||
- The implemented code
|
||||
- The stdout from running the code
|
||||
- The file list in "models/" subfolder
|
||||
- The scores.csv file generated during both training and inference (if it exists)
|
||||
|
||||
Focus on these aspects:
|
||||
- Check if the code saves the model in the "models/" subfolder.
|
||||
- Check if the code saves the test data in the "models/" subfolder when there is no test data specified.
|
||||
- Ensure that when the code is rerun in inference mode, it skips the training process and loads the model from the "models/" subfolder for direct inference.
|
||||
- Verify that there is no training activity in the output.
|
||||
- Verify that the script does not load the original training data.
|
||||
- Ensure that even if you skip the model training by loading saved models, the files like scores.csv and submission.csv are still correctly created.
|
||||
- The model's performance should remain consistent and not vary unreasonably between training and inference.
|
||||
|
||||
Please respond with your feedback in the following JSON format and order
|
||||
```json
|
||||
{
|
||||
"execution": "Describe whether the code executed successfully. Include any errors or issues encountered, and append all error messages and full traceback details without summarizing or omitting any information. Carefully check the stdout to ensure that when the code is rerun, it skips the training process and loads the model from the 'models/' subfolder for direct inference. Append the information that makes you think that the model is still being retrained when rerunning the code."
|
||||
"return_checking": "Verify the generated files include necessary files. Make sure scores.csv file does not change unreasonably between training and inference",
|
||||
"code": "The code has explicity dump the model into 'models/' subfolder; When the modes files are already in 'models/' subfolder, the code will explicity skip the training process.",
|
||||
"final_decision": <true or false in boolean type; only return true when ensuring that the code saves the model in a 'models/' subfolder, and the script rerun performs inference without needing to retrain the model.>
|
||||
}
|
||||
```
|
||||
|
||||
user: |-
|
||||
------------ The implemented code ------------
|
||||
{{code}}
|
||||
|
||||
------------ The stdout from running the code ------------
|
||||
{{stdout}}
|
||||
|
||||
------------ File opened by the code ------------
|
||||
{{opened_trace_lines}}
|
||||
|
||||
------------ The file list in "models/" subfolder ------------
|
||||
{% for f in model_folder_files %}
|
||||
- {{ f }}
|
||||
{% endfor %}
|
||||
|
||||
------------ The scores.csv file generated ------------
|
||||
# Training:
|
||||
{{scores_content_before}}
|
||||
|
||||
# Inference:
|
||||
{{scores_content_after}}
|
||||
|
||||
|
||||
docdev:
|
||||
system: |-
|
||||
{% include "scenarios.data_science.share:scen.role" %} Your task is to create documentation for a data science solution.
|
||||
|
||||
You will be given:
|
||||
- a list of files in the folder.
|
||||
- content from some important files.
|
||||
|
||||
Please explain the trained models in the "models/" folder. The training and inference processes are detailed in the `main.py` file. The models' evaluation results are in `scores.csv`. Please respond with a markdown file that includes the following information:
|
||||
- Explain the purpose of each model. If some models are part of a group (like those from cross-validation), describe them together.
|
||||
- Provide key details for each model group:
|
||||
- Important training parameters
|
||||
- Model details
|
||||
- Performance of each model
|
||||
|
||||
Be brief. Mention the file path when you introduce files.
|
||||
Don't introduce anything other than models.
|
||||
|
||||
{% include "utils.agent.tpl:MarkdownOut" %}
|
||||
|
||||
user: |-
|
||||
--------------- The file list in the workspace ---------------
|
||||
{% for f in file_li %}
|
||||
- {{ f }}
|
||||
{% endfor %}
|
||||
|
||||
--------------- File content of each file ---------------
|
||||
{% for fname, content in key_files.items() %}
|
||||
File Path: {{fname}}
|
||||
```
|
||||
{{content}}
|
||||
```
|
||||
{% endfor %}
|
||||
|
||||
notebookconverter:
|
||||
system: |-
|
||||
{% include "scenarios.data_science.share:scen.role" %} Your task is to provide a summary for a data science solution.
|
||||
|
||||
You will be given:
|
||||
- The original implementation plan for the script.
|
||||
- A Python script that contains code and output.
|
||||
|
||||
Your task is to generate markdown content that includes a title and a short paragraph summarizing the technique in model training, the type of model produced and any other noteworthy details in the solution.
|
||||
|
||||
The return content should be like the format below(Please note that "````" is used to avoid confliction of "```" in markdown file)
|
||||
````markdown
|
||||
# <The title of the notebook>
|
||||
<the content of markdown file>
|
||||
````
|
||||
|
||||
user: |-
|
||||
--------------- The implementation plan ---------------
|
||||
{{plan}}
|
||||
|
||||
--------------- The Python script content ---------------
|
||||
{{code}}
|
||||
@@ -1,137 +0,0 @@
|
||||
workflow_coder:
|
||||
system: |-
|
||||
You are a world-class data scientist and machine learning engineer with deep expertise in statistics, mathematics, and computer science.
|
||||
Your knowledge spans cutting-edge data analysis techniques, advanced machine learning algorithms, and their practical applications to solve complex real-world problems.
|
||||
|
||||
## Task Description
|
||||
{{ task_desc }}
|
||||
|
||||
Here is the competition information for this task:
|
||||
{{ competition_info }}
|
||||
|
||||
{% if queried_similar_successful_knowledge|length != 0 or queried_former_failed_knowledge|length != 0 %}
|
||||
## Relevant Information for This Task
|
||||
{% endif %}
|
||||
|
||||
{% if queried_similar_successful_knowledge|length != 0 %}
|
||||
--------- Successful Implementations for Similar Models ---------
|
||||
====={% for similar_successful_knowledge in queried_similar_successful_knowledge %} Model {{ loop.index }}:=====
|
||||
{{ similar_successful_knowledge.target_task.get_task_information() }}
|
||||
=====Code:=====
|
||||
{{ similar_successful_knowledge.implementation.file_dict["main.py"] }}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
{% if queried_former_failed_knowledge|length != 0 %}
|
||||
--------- Previous Failed Attempts ---------
|
||||
{% for former_failed_knowledge in queried_former_failed_knowledge %} Attempt {{ loop.index }}:
|
||||
=====Code:=====
|
||||
{{ former_failed_knowledge.implementation.file_dict["main.py"] }}
|
||||
=====Feedback:=====
|
||||
{{ former_failed_knowledge.feedback }}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
## Guidelines
|
||||
1. Understand the User's Code Structure
|
||||
- The user has written different Python functions that can load and preprocess data, execute feature engineering, train models, and ensemble them.
|
||||
- Each functionality is in a separate Python file.
|
||||
2. Your task is only to integrate the existing processes of load_data, feature, model, and ensemble into a complete workflow. Do not edit or modify the existing Python files. The final step should output the predictions in the required format.
|
||||
3. The user may provide specific code organization rules and instructions. Ensure that the integration follows the given framework and structure.
|
||||
4. After predicting the output, print the shape and other information of the output to stdout to help the evaluator assess the code.
|
||||
5. You should avoid using logging module to output information in your generated code, and instead use the print() function.
|
||||
{% include "scenarios.data_science.share:guidelines.coding" %}
|
||||
|
||||
## Output Format
|
||||
{% if out_spec %}
|
||||
{{ out_spec }}
|
||||
{% else %}
|
||||
Please response the code in the following json format. Here is an example structure for the JSON output:
|
||||
{
|
||||
"code": "The Python code as a string."
|
||||
}
|
||||
{% endif %}
|
||||
|
||||
user: |-
|
||||
--------- Code Specification ---------
|
||||
{{ code_spec }}
|
||||
|
||||
--------- load data code ---------
|
||||
file: load_data.py
|
||||
{{ load_data_code }}
|
||||
|
||||
--------- feature engineering code ---------
|
||||
file: feature.py
|
||||
{{ feature_code }}
|
||||
|
||||
--------- model training code ---------
|
||||
Attention: The input and output of the model function is flexible. Training dataset is necessary, but validation and test dateset might be optional. The hyperparameters can either be passed as arguments or be set as default values in the function. You need to use the function correctly.
|
||||
All model files share the same function name. Please import the model files with their name like: from {file_name} import {function_name}
|
||||
{{ model_codes }}
|
||||
|
||||
--------- ensemble code ---------
|
||||
Note, we will check the index of the score.csv, so please use the model name as the index to feed into ensemble function.
|
||||
file: ensemble.py
|
||||
{{ ensemble_code }}
|
||||
|
||||
{% if latest_code %}
|
||||
--------- Former code ---------
|
||||
{{ latest_code }}
|
||||
{% if latest_code_feedback is not none %}
|
||||
--------- Feedback to former code ---------
|
||||
{{ latest_code_feedback }}
|
||||
{% endif %}
|
||||
The former code contains errors. You should correct the code based on the provided information, ensuring you do not repeat the same mistakes.
|
||||
{% endif %}
|
||||
|
||||
workflow_eval:
|
||||
system: |-
|
||||
You are a data scientist responsible for evaluating workflow code generation.
|
||||
|
||||
## Task Description
|
||||
The user is trying to build a workflow in the following scenario:
|
||||
{{ scenario }}
|
||||
|
||||
The main code generation task is as follows:
|
||||
{{ task_desc }}
|
||||
|
||||
The user provides workflow information and its components.
|
||||
The details on how to structure the workflow are given in the specification file:
|
||||
```markdown
|
||||
{{ spec }}
|
||||
```
|
||||
|
||||
This workflow integrates multiple stages, including:
|
||||
- Data loading
|
||||
- Feature engineering
|
||||
- Model training
|
||||
- Ensembling
|
||||
|
||||
## Evaluation Scope
|
||||
Your focus is to check whether the workflow code:
|
||||
1. Executes successfully, correctly organizing components and generating a final submission.
|
||||
2. Generates predictions in the correct format, ensuring they align with the **sample submission** structure!
|
||||
|
||||
[Note]
|
||||
1. The individual components (data loading, feature engineering, model tuning, etc.) have already been evaluated by the user. You should only evaluate and improve the workflow code, unless there are critical issues in the components.
|
||||
2. Model performance is NOT a concern in this evaluation—only correct execution and formatting matter.
|
||||
3. As long as the execution does not exceed the time limit, ensure that the code uses cross-validation to split the training data and train the model. If cross-validation is not used, mention it in the execution section and set `final_decision` to `false`.
|
||||
|
||||
## Evaluation Criteria
|
||||
You will be given the workflow execution output (`stdout`) to determine correctness.
|
||||
|
||||
Please respond with your feedback in the following JSON format and order
|
||||
```json
|
||||
{
|
||||
"execution": "Describe whether the main workflow executed successfully, correctly integrating all components and generating the final submission. Include any errors or issues encountered, and append all error messages and full traceback details without summarizing or omitting any information.",
|
||||
"return_checking": "Verify the generated files, particularly the submission file. Ensure that its format matches the sample submission, checking the index, column names, and CSV content.",
|
||||
"code": "Provide feedback on code quality, readability, and adherence to the given specifications.",
|
||||
"final_decision": <true/false>
|
||||
}
|
||||
```
|
||||
|
||||
user: |-
|
||||
--------- Workflow test stdout ---------
|
||||
{{ stdout }}
|
||||
--------- Workflow code generated by user ---------
|
||||
{{ code }}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user