Compare commits
1395 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 4c9e608a1a | |||
| 90665731c1 | |||
| 7a9ea40d72 | |||
| c66e221012 | |||
| f38d2466df | |||
| 1cc92c645a | |||
| ab764df411 | |||
| 87c5f89b6c | |||
| 780c794ef0 | |||
| 8b4070dbcf | |||
| 4e089fd17e | |||
| f454006ec3 | |||
| f5002929ee | |||
| 4e1d75a3e1 | |||
| d4462ba5d8 | |||
| 6dc71269a2 | |||
| 730ccba535 | |||
| 1175721579 | |||
| e5157d5471 | |||
| 7fcb23e0c7 | |||
| f075d90d99 | |||
| bf94748058 | |||
| 2890d13d92 | |||
| 9232778732 | |||
| 70a25f9837 | |||
| 4434df1999 | |||
| b9e9f6f040 | |||
| f92caf0f1f | |||
| 55b90917e4 | |||
| d0546e998a | |||
| e9f414b29c | |||
| 7638261e8f | |||
| a049d6eab1 | |||
| 61f46b959e | |||
| ccb1e4af02 | |||
| 06424cae28 | |||
| 9aeb2eaabd | |||
| c6061daec4 | |||
| 5be0352705 | |||
| 06995f26fd | |||
| 7b45844670 | |||
| 0a0c2adf7d | |||
| 7aab3b34d6 | |||
| c4aa221c9b | |||
| da12071d8f | |||
| 581a9bb1c9 | |||
| f5258510cc | |||
| 99401f9d69 | |||
| 729bea2d8e | |||
| 8b72e4f23e | |||
| 17202c6d29 | |||
| 567d4331fd | |||
| 92c9f443e8 | |||
| dd2d7bb863 | |||
| 9c0d612729 | |||
| 07d5636d1e | |||
| 977cabb580 | |||
| 15a7e1d9d1 | |||
| 953ffcf204 | |||
| b24e6e72c7 | |||
| 82b05f6b5a | |||
| a662802011 | |||
| 5483ade786 | |||
| ae02a7007b | |||
| 3c6e058b00 | |||
| ad3ddcaadb | |||
| be56052417 | |||
| 9a888d9896 | |||
| 24a7e585e4 | |||
| 2120f1ed5b | |||
| 3a2bb22cb3 | |||
| a7c4ec6eaf | |||
| f7b934b306 | |||
| d34e7a1e8e | |||
| 4804ec986a | |||
| 16117e5b6c | |||
| 985805e0d5 | |||
| 78acaf8f4c | |||
| a1dad065b2 | |||
| 3b03d4346c | |||
| c6551819cd | |||
| e58635a881 | |||
| 8e3331d0db | |||
| 8391a0612d | |||
| 68c00d1c4d | |||
| f48f24ce2e | |||
| 9d5a88416a | |||
| a314786056 | |||
| aee9b2c749 | |||
| 3fffee3b05 | |||
| 72abae7b94 | |||
| a300df7ff3 | |||
| 8e500d4601 | |||
| f6e1442fdf | |||
| d8d8260d76 | |||
| 72dd0d062b | |||
| 03c67d6a3b | |||
| 314cd10e27 | |||
| 6e6a929fac | |||
| d069f5477e | |||
| a4a5fbe4a8 | |||
| 01e288297a | |||
| 7564b1e6df | |||
| cf010c3f17 | |||
| 5ff95db9e1 | |||
| ada72d2264 | |||
| 9f436dcd1e | |||
| 95a710d4a8 | |||
| bf5d300a54 | |||
| f7a1325339 | |||
| e13152715c | |||
| 19a35ed111 | |||
| e62ba8ed1e | |||
| f62ded94bb | |||
| 74f459d7ed | |||
| 815a351435 | |||
| 9857f30703 | |||
| a7de2cf682 | |||
| 5e2f4924d6 | |||
| b74a334f25 | |||
| 58c9a61cf0 | |||
| d5620cf8b5 | |||
| 2e50c100f9 | |||
| 776d9ac5e0 | |||
| 301e348789 | |||
| 6467d85059 | |||
| 4b4d090d39 | |||
| 2ddafa28f2 | |||
| d6bb47816c | |||
| f40d90cf08 | |||
| ab7c1ec24f | |||
| be5969a1e1 | |||
| 992d173adc | |||
| 5396519b20 | |||
| d8122f5d33 | |||
| 92f8b2dd02 | |||
| 29e35cf824 | |||
| 26ff88c71a | |||
| 7b3951f1e5 | |||
| 5dbfc92c5a | |||
| a14281722a | |||
| a80f3ae919 | |||
| 5f558137d3 | |||
| ecd66f8a64 | |||
| 8d965d4833 | |||
| 25a3de653c | |||
| ac519a273b | |||
| 68429f9c37 | |||
| 5cb41badc1 | |||
| 54bebeabb7 | |||
| 3a17c2b55c | |||
| 7b7b8b8f8b | |||
| 55201b6224 | |||
| 49b9296cd9 | |||
| 09fabd911e | |||
| 43be752847 | |||
| 6cfd31c705 | |||
| 3bce9278bd | |||
| 068caf159d | |||
| eb8875b64b | |||
| 97578c0831 | |||
| 7219f71bc1 | |||
| eea9133b3f | |||
| a8f543ce62 | |||
| b35172a3b8 | |||
| 7b8f0583a4 | |||
| 7ae89711dd | |||
| a2c3729254 | |||
| 14c9f783d5 | |||
| 6c9c709c65 | |||
| 1c2ffc6aaa | |||
| a6d2bc5238 | |||
| 737d2804d2 | |||
| 3e14c2664e | |||
| 78bd8554aa | |||
| f1d5679fba | |||
| a9e82b7fc2 | |||
| 21f77f9c5d | |||
| c4c0198d20 | |||
| d72d13ed58 | |||
| 5ea0705547 | |||
| 575b50deda | |||
| a0d1a04605 | |||
| aa4704e37d | |||
| 4143a2559a | |||
| 693a8fa979 | |||
| 6ec639d347 | |||
| 52d5d35afb | |||
| 8a21cc6d18 | |||
| b6bedf20ce | |||
| 9f02279d5a | |||
| 6f9906e935 | |||
| e934c3934d | |||
| d6f78e4cc8 | |||
| f9cc05b202 | |||
| 76eb92b821 | |||
| e749051dbc | |||
| 6de7c70e7e | |||
| 74f52b14cd | |||
| e33363bf6c | |||
| 7d77e63b81 | |||
| cfa855dec8 | |||
| 34a72a0555 | |||
| a9db7d0286 | |||
| 19140e9cfa | |||
| b0c3f2ff7f | |||
| 8686b56b9e | |||
| 6ab731acdb | |||
| 8ca63cf0ee | |||
| 5774c08b4a | |||
| b731cdef56 | |||
| b51c93fbc1 | |||
| e948839fb5 | |||
| 587ec513db | |||
| efed5700be | |||
| 5ddaea7efc | |||
| 66577b741f | |||
| 09017980b6 | |||
| 3a7721ebe8 | |||
| 35cc3efd5a | |||
| 95ad756909 | |||
| 816ca2ea15 | |||
| 246891a8f6 | |||
| 25fd63c6d0 | |||
| cadbbd0e2e | |||
| 65b83c46fb | |||
| 31204a37a5 | |||
| 67774c71e5 | |||
| 44b65daf1c | |||
| 48ff0c5744 | |||
| 3934aa118f | |||
| d40efb883c | |||
| 84ec09565a | |||
| 387431e4df | |||
| 662747c06c | |||
| 89272e9ddb | |||
| 23d4d25e39 | |||
| 488a608c90 | |||
| a94d18a10b | |||
| 94aba0f9ac | |||
| 35c3ca91eb | |||
| 53328bc595 | |||
| bb7a4c4739 | |||
| 7d38963c61 | |||
| a7e7c17134 | |||
| 0544af1f68 | |||
| ba87f3e7d7 | |||
| b60a3802e7 | |||
| 4beb6a8049 | |||
| bd10afc796 | |||
| 2868efa779 | |||
| fe466e2e86 | |||
| 6c5771b40c | |||
| 5c81d31bd1 | |||
| b1b3b42489 | |||
| 5b03fc1a89 | |||
| dd73c724c4 | |||
| 5cbcd68446 | |||
| 3bc1afd149 | |||
| 877761ecd3 | |||
| 9ef464e002 | |||
| 3deb089d64 | |||
| f4f2249447 | |||
| 1c5a4f4f39 | |||
| 1909fc3139 | |||
| 2de831f1b2 | |||
| 1739200ee4 | |||
| 31a44178a4 | |||
| eb9f233a78 | |||
| 3986dc2617 | |||
| 1f7f2ee3dd | |||
| 6e0da1aa3a | |||
| af3b0ed39f | |||
| 1302b67772 | |||
| 6d44248607 | |||
| 5f1d9cbab1 | |||
| aad21195df | |||
| 739a67fdcb | |||
| 48bd5cb2c0 | |||
| 9c079ccdfd | |||
| 2542102280 | |||
| 5407c2efec | |||
| 81a5d49687 | |||
| 321b44b779 | |||
| 61a1ed897f | |||
| 5bb4cffa21 | |||
| 5c314b6f1c | |||
| cee8855dca | |||
| 1196237f82 | |||
| 9d5295fdb4 | |||
| 71e1c91148 | |||
| e9718e064f | |||
| 3e8bb29c9f | |||
| 2fd703fcc5 | |||
| 2a84b00dad | |||
| 711ebfea28 | |||
| 8cd2ee95f9 | |||
| 539937c0eb | |||
| fefd698e96 | |||
| 3512d788dc | |||
| 54c4dd1ce6 | |||
| daaff66ff0 | |||
| 8610f9883d | |||
| e503d4a9c0 | |||
| eaf3fc8833 | |||
| 94c5ddc13d | |||
| a3fedbaba7 | |||
| 1cf1d9e3d7 | |||
| 6b250f9dfe | |||
| 3d24ef66d8 | |||
| ef0fc13235 | |||
| 394ff1bbf6 | |||
| 5cdd087465 | |||
| 93051f4f97 | |||
| 1c2eed1421 | |||
| 532f5ab080 | |||
| e3ffe56549 | |||
| 564634be45 | |||
| ab3ae3dc62 | |||
| d037f67f74 | |||
| b1b6341a6e | |||
| 8c92f9407d | |||
| e0aa660b56 | |||
| 25d4cabe3b | |||
| 7539b6ffda | |||
| 8e623ee64c | |||
| 59ab51c06c | |||
| 2eb2617b6f | |||
| b284572ea7 | |||
| 1e5d9ecfa3 | |||
| e8bda298e3 | |||
| 489cd008d6 | |||
| 22ddd9a7d4 | |||
| 128ea45fee | |||
| 3ff1e31a81 | |||
| 2495f68751 | |||
| 70ee652be5 | |||
| bb1d34c33d | |||
| 8f6d64f5e1 | |||
| b40848373d | |||
| 2824bcff41 | |||
| e8b967d634 | |||
| 12d617cf8d | |||
| 48ab5ed990 | |||
| 3363b1062e | |||
| d35dde6757 | |||
| 6016d4886e | |||
| f77eaa4083 | |||
| 460d88ced7 | |||
| 6bb559f1b0 | |||
| 7c91eb0091 | |||
| ae672e1110 | |||
| 1c4bf67e29 | |||
| c4e671fdc3 | |||
| c5c5198fb3 | |||
| 634ec3c85f | |||
| d15aa4b337 | |||
| e160739a28 | |||
| 030e07030c | |||
| a50a15ebc6 | |||
| 514452c4ec | |||
| f091db3b0e | |||
| caf1d6e7f2 | |||
| 81f6637803 | |||
| f764f1fc10 | |||
| 9a8ef17c73 | |||
| 8fe582a7a7 | |||
| 5cf3a2256a | |||
| caf4ffbc0b | |||
| d156f36f99 | |||
| 4390324d22 | |||
| 8d7ef1929e | |||
| 08fb8e42f7 | |||
| eaf6abecc8 | |||
| b4796cbf73 | |||
| e042b2e07b | |||
| 9f021cbee6 | |||
| bf615e415b | |||
| c72f5b79fe | |||
| 51c1674663 | |||
| e445452d35 | |||
| 9fff38d0a3 | |||
| bdd69dbfbc | |||
| ec4767acd5 | |||
| 78c8054954 | |||
| f21c5ea88a | |||
| 82903cc567 | |||
| 0233c38711 | |||
| 24f5096ec6 | |||
| 030bc8641b | |||
| c9403eb946 | |||
| 87b0a6d3f3 | |||
| c0d404edb5 | |||
| a7a16d1e1e | |||
| 1f21d5e2c2 | |||
| a531f8644d | |||
| 765a0b52cb | |||
| 4919d6944e | |||
| ac20596f10 | |||
| 5e79a93235 | |||
| 2e8decbb6d | |||
| 196e599dc8 | |||
| 485cad2dc6 | |||
| 61cbe0c4b1 | |||
| 5510e138db | |||
| c9e9f9bd82 | |||
| 768ba1baaf | |||
| ad25a60149 | |||
| 3fdcd6e8f1 | |||
| be0c0761e3 | |||
| 00dd3f05ac | |||
| c6f30989c9 | |||
| 4ab6fba9e7 | |||
| 3ef082e2d9 | |||
| cccf44cd68 | |||
| 506d665a43 | |||
| 8514e35ad0 | |||
| af0a3f9a8d | |||
| 2df1a93dfc | |||
| 75e39d3154 | |||
| 5d755e3ca0 | |||
| fbeb2e4789 | |||
| 6b288d46af | |||
| 394cdfcc15 | |||
| 28df02da82 | |||
| d4ee725747 | |||
| 6617d3bb46 | |||
| 2453e344f4 | |||
| 7f0e886cfd | |||
| e34ea393d9 | |||
| a00a5e52c4 | |||
| 6abc0a3fb9 | |||
| 7e4b9d7481 | |||
| e3f241acb7 | |||
| eee233f894 | |||
| 615095c780 | |||
| b22bce3dd8 | |||
| 9f1d9add18 | |||
| 36f2bef6b8 | |||
| 07906d2576 | |||
| 5c977c212b | |||
| 09b084e85a | |||
| aefc72554a | |||
| 33c2cc806a | |||
| 74aa17d534 | |||
| 4de1501c68 | |||
| dc12b3e750 | |||
| dacd09db8b | |||
| c63d0e167c | |||
| 6ccd98d795 | |||
| 52b0e64950 | |||
| 5e5137edc1 | |||
| 5d4edb5ec0 | |||
| 6dccab9bfe | |||
| 653c160d76 | |||
| 3f65ed452e | |||
| 09cdc7ceca | |||
| e98e6d8aee | |||
| f10223bf13 | |||
| 38b3062653 | |||
| 6063e4accb | |||
| 06e249f569 | |||
| d064bd4f34 | |||
| 765d2c332c | |||
| 8857c77645 | |||
| 1ff4e40824 | |||
| 09d59c79a7 | |||
| dd6ac4b196 | |||
| 67fe3682b5 | |||
| a07e6183bb | |||
| ac99537c25 | |||
| 734a6f0442 | |||
| da52ef8729 | |||
| c934535dc8 | |||
| 3e3f092f0c | |||
| 834aafb8f2 | |||
| df19c77bcf | |||
| 6edcda1e42 | |||
| fe8c367bce | |||
| a37edf8c62 | |||
| 09ef2c9dea | |||
| 42b1d8ecf8 | |||
| 32437a95f3 | |||
| 2e29d3523b | |||
| 530300a951 | |||
| 612a09634c | |||
| fd6a2456d0 | |||
| 1ad0e7e365 | |||
| 055ee5c88f | |||
| ae676d8e03 | |||
| 0dc665e45b | |||
| bc6ea16db8 | |||
| a1d0528adb | |||
| ecfa1fd5b5 | |||
| eaf76047e3 | |||
| 761d3f216e | |||
| e7d9ac2247 | |||
| 842e651928 | |||
| 091d1c2d55 | |||
| 47bf2d1f26 | |||
| 758392c206 | |||
| 647011bf0c | |||
| 580413b5f8 | |||
| c8c9e5167e | |||
| 2e8707059d | |||
| e0d9d01493 | |||
| 45bf1ace7d | |||
| 39a5328f5a | |||
| 9f82738c96 | |||
| f69f6ec8be | |||
| 8b3fb11f14 | |||
| b0f4c57fa8 | |||
| d759deae8f | |||
| b695b5a83c | |||
| b8883b790e | |||
| 423197cb23 | |||
| 38107664b5 | |||
| 42d3f557bc | |||
| 1a3c913176 | |||
| 83de41ad0e | |||
| 8cc4664823 | |||
| aaecbc2206 | |||
| e36df7eff5 | |||
| 95f58b2b8c | |||
| 8df0ce3fb5 | |||
| 4177809f71 | |||
| 96aa214fc5 | |||
| a3c1c8c1b4 | |||
| 2bf3494cbc | |||
| e3dd3478bb | |||
| 457af15b35 | |||
| 1eef1675cc | |||
| 89ef31b381 | |||
| c00472c42d | |||
| c0143b04c8 | |||
| d1c901ae94 | |||
| dd0aeaf380 | |||
| 3e8e250a65 | |||
| a34b580444 | |||
| e7ea9d09c9 | |||
| e4e11be331 | |||
| 9774c51a97 | |||
| 87ff8dc7bc | |||
| 2434ae5476 | |||
| e474294d55 | |||
| b081716df7 | |||
| e1af43b133 | |||
| 1ea6a99c48 | |||
| 79fc80957f | |||
| 937eedd8ca | |||
| 93ae45dcbb | |||
| 1adbd525bc | |||
| ced7465c1f | |||
| d635cb8516 | |||
| 2b578633ab | |||
| 824f555d48 | |||
| 999fd15bee | |||
| be07879a1e | |||
| ab543c2680 | |||
| 79aa0bce5a | |||
| 05a76c0297 | |||
| 15eeac3c48 | |||
| d8a84a7d6b | |||
| 863a5b7b81 | |||
| 4ad049aec3 | |||
| 03c16d034d | |||
| c1f8dce109 | |||
| 887f513438 | |||
| 12fbae7204 | |||
| a05cb8f1c5 | |||
| cffee80b0e | |||
| 0c0f2e43e8 | |||
| 35456a1f32 | |||
| b6a6bca41b | |||
| 102cc87618 | |||
| 1ec45dcf19 | |||
| f2fb1b7919 | |||
| 78c5b18937 | |||
| 86de1dee29 | |||
| 7afd3cb730 | |||
| b887e2ad21 | |||
| ea2350f1ed | |||
| 786c858452 | |||
| a6b643a33f | |||
| 0e5235e6dc | |||
| c93c97c2de | |||
| 271ba462b1 | |||
| 690918f8d3 | |||
| de5dd66512 | |||
| c8593b2307 | |||
| fc21757e40 | |||
| b6d0cde29f | |||
| f0dfc23a5f | |||
| c9dda3480d | |||
| 45804e1bef | |||
| 6dd5dc5d2c | |||
| a5db75d361 | |||
| 4c4bc2be9b | |||
| e9cc9bb38a | |||
| 3b6395ddb8 | |||
| fdcbb3c0d0 | |||
| b07ffbf721 | |||
| a7b7e10c09 | |||
| f18472479a | |||
| 18c37b9b8f | |||
| d28abc18ea | |||
| 80b50141ee | |||
| b15d49f9ae | |||
| 668635892c | |||
| 670a29d420 | |||
| fd0d089f43 | |||
| b5fb6888f0 | |||
| edc23dcd2f | |||
| 1dc299f6f4 | |||
| 99d2423534 | |||
| b8b8da2eb2 | |||
| 4237d9fd11 | |||
| b98a91ba4c | |||
| e74db3e024 | |||
| ead3282229 | |||
| dfd9e7e777 | |||
| 71362c9140 | |||
| 68114691c6 | |||
| 37a3bdd507 | |||
| 50389cbbf4 | |||
| a7e5d3e427 | |||
| 48d1106546 | |||
| 6452521002 | |||
| 52374b39f2 | |||
| 300a866aac | |||
| 9873a862e0 | |||
| 1c8bbc14b8 | |||
| afa1311ff8 | |||
| 3ecc9c30cb | |||
| a85bb040f2 | |||
| 841e480ff5 | |||
| a0e9b77f75 | |||
| 47d59f8ff4 | |||
| 676c48411b | |||
| 954950c8cb | |||
| 2520b7cd51 | |||
| f9d7f05d38 | |||
| 46d4ff3d36 | |||
| 9347d823fc | |||
| 5e8bd359c8 | |||
| bae8a55f81 | |||
| 56c672b6d2 | |||
| de3956f2f9 | |||
| ddd7009fa8 | |||
| 31891b25af | |||
| 187b19b1d6 | |||
| e55d8512e7 | |||
| 697912f244 | |||
| 2f3ad09cf5 | |||
| 523dd305ba | |||
| 2d87d74829 | |||
| 820791e889 | |||
| a130122cc6 | |||
| 3a58297a8d | |||
| 65d22f9f1c | |||
| ec5df87318 | |||
| cf1533c478 | |||
| fc34f8cad2 | |||
| 3fbb38730c | |||
| 6a327440e0 | |||
| f1c8d8325b | |||
| d2557a70d7 | |||
| bf76347751 | |||
| a99a49e2af | |||
| b7fc924e82 | |||
| ef55bf6800 | |||
| 25ffc76655 | |||
| 15b1cff9c2 | |||
| c1ba2936ec | |||
| f08c0c9870 | |||
| 3b5b8bd007 | |||
| 74067d454b | |||
| 16359d617d | |||
| ae9f83ed30 | |||
| 49626ca31c | |||
| 884f543fb7 | |||
| 29df7499c5 | |||
| 5e64416dfa | |||
| 1118032c1f | |||
| 277828b1d4 | |||
| 47dcf7bc93 | |||
| 75081ab046 | |||
| 571497e58b | |||
| d710c85cda | |||
| 978f9c804b | |||
| 31522c681e | |||
| a5ac8a95a7 | |||
| 35dab9b566 | |||
| 2b05a49671 | |||
| b79b5b6c32 | |||
| 78124cd025 | |||
| 7c4c789711 | |||
| 30b32a0d2e | |||
| d33768ecee | |||
| ccf20b2fe1 | |||
| 23bbbddcdb | |||
| c6ed64746c | |||
| 8f4dfbf55d | |||
| 5296a3be23 | |||
| c92c64bac2 | |||
| aaca904455 | |||
| 19b57ad87e | |||
| 583738040c | |||
| 6e38b72601 | |||
| 8bf8ccfe50 | |||
| e721a741ca | |||
| 19e9effae4 | |||
| 84100ca7ae | |||
| a6f94f7d24 | |||
| 0a32be3fc3 | |||
| 065203c3db | |||
| 758ae42092 | |||
| 6fdc0f1b22 | |||
| 7c9fe22b9f | |||
| 53aecfa856 | |||
| bf511f12d4 | |||
| 0eed655e7c | |||
| d2d283a4b2 | |||
| 85492c1084 | |||
| f07134bf66 | |||
| 7678a59b1f | |||
| daced63d00 | |||
| 002d8c4022 | |||
| 8c85448ed7 | |||
| 2236b08fc2 | |||
| 24f904efc4 | |||
| 3eaa862caf | |||
| 469587e656 | |||
| b24064d706 | |||
| c4a29a0178 | |||
| aedbe0d1d2 | |||
| c5e3f7d0ba | |||
| bc019d6b6d | |||
| f889061b95 | |||
| 1f52ff3f94 | |||
| d0c3b30289 | |||
| e77feafee0 | |||
| 1889a315a3 | |||
| cc998afb44 | |||
| 97f30cf13d | |||
| ccbc48b590 | |||
| dde6001ad0 | |||
| aae3ab23ac | |||
| 604e08382e | |||
| 2ecadabd92 | |||
| 17c7826756 | |||
| fe92df7842 | |||
| e6dd932436 | |||
| 8acc05bb2d | |||
| c39f6f892b | |||
| f13b51cf91 | |||
| e90c60c940 | |||
| 60029c2a8b | |||
| 14429d449c | |||
| cba9d6078c | |||
| 2dfad98ed6 | |||
| 9de9cac23a | |||
| d1fd7c3f6e | |||
| 8fd5b93127 | |||
| dafa5d4bac | |||
| d29cd5b9d9 | |||
| 60094c6581 | |||
| dd32e228ce | |||
| 81639c61a8 | |||
| ae1fcbcffb | |||
| 263d035181 | |||
| 8ecd7011cb | |||
| f7d42ba60d | |||
| 701cf47c4b | |||
| 315009a7f0 | |||
| 6e98a369de | |||
| fa69b7017b | |||
| e98f3cfedf | |||
| 5f4184536a | |||
| ac904c60c8 | |||
| 16defdbfdf | |||
| d010a050d3 | |||
| 7b541ff958 | |||
| 78a47920ef | |||
| e5a2011a85 | |||
| 640cab2ca8 | |||
| deb8bde078 | |||
| 79f0271720 | |||
| 5b8b80cf59 | |||
| a7ee45a0ba | |||
| 37cc949d94 | |||
| 5f59e1435e | |||
| e1f26aeb4e | |||
| b49dafc412 | |||
| 7c84059b3a | |||
| 10a0bf386b | |||
| 2936cb425d | |||
| e5a9c65e66 | |||
| 81fdff1039 | |||
| 5101b1767b | |||
| e90aa6abda | |||
| 1dd56df5d8 | |||
| 9bd8b7acf5 | |||
| 2a5a422079 | |||
| e92afb74c6 | |||
| 4421e54cde | |||
| b5938985f2 | |||
| 0601f15bd0 | |||
| 66020d250c | |||
| 909286c0f7 | |||
| 5efad94d3d | |||
| 1e24653e79 | |||
| c9bc2b880a | |||
| 545cd3a994 | |||
| 51a09585db | |||
| b98816635d | |||
| f6ed609134 | |||
| aec2dc5bb0 | |||
| cc807d1cf9 | |||
| 15c836c566 | |||
| 5f907a4b1a | |||
| a464a2fdbc | |||
| fa3d95fd89 | |||
| ba8778b181 | |||
| 6421f767c6 | |||
| f18c7f0cad | |||
| e63017a2b9 | |||
| 049cc10169 | |||
| 595db54ac7 | |||
| bfa9c818e6 | |||
| 30afedd4f8 | |||
| 6049ac1561 | |||
| 25c24ddc9c | |||
| 03df35b49b | |||
| 3b441cd08f | |||
| 0f67d32b75 | |||
| 820a83c96f | |||
| fae30c6ff9 | |||
| 3e4ffb9c1d | |||
| f6d10dad6a | |||
| 79b530d98e | |||
| 3b8e521b81 | |||
| 7e228ba7ab | |||
| 6050d09ed8 | |||
| b7f158a79e | |||
| bc13d1636c | |||
| 021fdcab43 | |||
| d206b601b3 | |||
| 949c7318f4 | |||
| 3666362479 | |||
| f27540d221 | |||
| 31dc0fe327 | |||
| 1125c60f07 | |||
| 9f5fd574b4 | |||
| 74eb0d9f88 | |||
| 52c78966ef | |||
| 1641f56956 | |||
| d27981f8cf | |||
| 6031ccabac | |||
| c64b6b0d69 | |||
| 4203693428 | |||
| c76c26cc34 | |||
| 1c87748b99 | |||
| 4ae80423e0 | |||
| 4e6ae88557 | |||
| 102c33d68b | |||
| 12a72fa161 | |||
| 3a5b555f1e | |||
| 8f2ee28395 | |||
| e57d0e3bc4 | |||
| f5205da459 | |||
| bd773b9baf | |||
| 7b4a6a48ee | |||
| 24a3a29360 | |||
| 6a279043fa | |||
| 60764500db | |||
| ba5a64aa34 | |||
| f40576091a | |||
| de3eedb39e | |||
| fded8bf43e | |||
| 5a45b4a3e1 | |||
| 0b3ea4d0ed | |||
| 822dce09b7 | |||
| 2ebc5374f4 | |||
| 3465f35d75 | |||
| 2165c3e542 | |||
| 5e059660d4 | |||
| 5ca69687dc | |||
| d042085b24 | |||
| effd989796 | |||
| ca85deafb8 | |||
| d46cc552be | |||
| 1dc2bcb47e | |||
| d6bf20b7b4 | |||
| 2d842ea129 | |||
| 76d5423eee | |||
| 489b7e6d18 | |||
| 18dfb0fe39 | |||
| 63efed736c | |||
| 4c568e40c2 | |||
| b54d231b79 | |||
| 58f361f8b3 | |||
| f78d383448 | |||
| 1be9a79e96 | |||
| d9e98bb687 | |||
| 7fd7061304 | |||
| db50d2b85d | |||
| d2a1e52d79 | |||
| 70e78e6521 | |||
| 913148bf1d | |||
| 0ecb3e45f6 | |||
| 74f870c435 | |||
| 8f62462e15 | |||
| 38183fe952 | |||
| 215b111cff | |||
| 4ea9d70743 | |||
| 0893350285 | |||
| 27bd34c3be | |||
| ebf6ca1a5f | |||
| a91ed0b4d9 | |||
| 097b27208d | |||
| 136623b3f5 | |||
| 02648e29c4 | |||
| beb6d41360 | |||
| a1207eca56 | |||
| 1a247a1035 | |||
| 4e0203d4af | |||
| 332518c1a0 | |||
| 15353f44f0 | |||
| 093cdae39c | |||
| 5dd5b95d6a | |||
| 20e0b542e3 | |||
| 1d24f9047c | |||
| f2c37e2575 | |||
| 95fbe04225 | |||
| 43c5b8d0ed | |||
| 301d85ef4f | |||
| 48f3d612e9 | |||
| c53c70d597 | |||
| aa89ce80ab | |||
| 971dfef0ee | |||
| 5d8a3cdb31 | |||
| 5246eecaf6 | |||
| 18b6f374d6 | |||
| 95c6997209 | |||
| ca79b84e4a | |||
| 3670df8771 | |||
| ff06d58ace | |||
| 1b4592a2f3 | |||
| 5138e97b70 | |||
| 340cad3707 | |||
| ca32cb9e61 | |||
| c911b7fa70 | |||
| 9323b6b946 | |||
| 92ef1ef761 | |||
| e38504b9db | |||
| e437847916 | |||
| a3a30f9046 | |||
| df507e2335 | |||
| 2f1f60a8fc | |||
| 1c1a165ba4 | |||
| 00fe02c854 | |||
| 6ff26b075e | |||
| 03a46ec784 | |||
| ec31764aed | |||
| 1ba411cccf | |||
| 7957231ce4 | |||
| 6b88c49e0a | |||
| 4fe99e0333 | |||
| 9a38dfcc26 | |||
| 3ecbfeb1d5 | |||
| 02229c959f | |||
| 2a2f205fbe | |||
| c415dab846 | |||
| 5b47960567 | |||
| 3f9749b03b | |||
| 528b11af07 | |||
| 0a31ff3747 | |||
| e1ee566634 | |||
| 1cff4d13de | |||
| 22b1bc7210 | |||
| c741c168e8 | |||
| c997f02085 | |||
| ead6d89e35 | |||
| 985c15bdd9 | |||
| 7fb7c43e45 | |||
| 0e68de0c6d | |||
| ba5f771e65 | |||
| e0f147e076 | |||
| b874ceaf2f | |||
| 11f339f802 | |||
| 9d46fd21dc | |||
| 286f385f99 | |||
| 69cca13d15 | |||
| 37d03a5b44 | |||
| 0e1d3e279c | |||
| ae671c736e | |||
| 28064d013c | |||
| 5b9c03e7e2 | |||
| f2569e36e8 | |||
| bf2092977c | |||
| 613e31a9a5 | |||
| 326a4f17d2 | |||
| a8d617d747 | |||
| ba9f795df5 | |||
| dbccc69f05 | |||
| db80318946 | |||
| 5698793dcc | |||
| bf96be2b71 | |||
| 2af454333b | |||
| cb869a2e4d | |||
| afc5205bea | |||
| 842f3a2a36 | |||
| 582871b0d5 | |||
| c6c2934741 | |||
| d3b5be6cb6 | |||
| 473a15c4ef | |||
| 2c4452453a | |||
| da6affcd6a | |||
| 3ebbe2b56c | |||
| 8f13a5db29 | |||
| 3155dfc14c | |||
| cc30e71ab2 | |||
| f5cb486f5e | |||
| 42c8795141 | |||
| f878d051df | |||
| aefa7e401c | |||
| dc06510d4a | |||
| 7740b61f02 | |||
| 950f5a722e | |||
| 9b56245b1d | |||
| b05fb57fb7 | |||
| 1a4db77131 | |||
| 71920cefb1 | |||
| b5cbbd7c30 | |||
| f75a0817a6 | |||
| d12132ae7a | |||
| a81bec0da2 | |||
| cc41cb831f | |||
| 2b70ec896d | |||
| 470dbb6060 | |||
| afc61ca788 | |||
| ba62e5e007 | |||
| 9af401b091 | |||
| 1fdbace02d | |||
| cfeda4493b | |||
| 0de48d90f8 | |||
| c4eb26be9d | |||
| 04a8539f10 | |||
| d600461a84 | |||
| ce46cd7343 | |||
| d1cca4ac51 | |||
| 28399aaab2 | |||
| eb5d5e0d3f | |||
| 560085ab92 | |||
| 17c315bf4a | |||
| e8145e0057 | |||
| ae9073885f | |||
| 61886942c5 | |||
| 12d31c4acb | |||
| 14cfdb13c5 | |||
| e58ab7852a | |||
| 77dcc5354c | |||
| 3ac4a872b1 | |||
| b8b94d58c4 | |||
| dfae7ca2ec | |||
| 17cd0452ec | |||
| 33b5482065 | |||
| 9fe361f6fc | |||
| da7f35db8d | |||
| 4f216eb861 | |||
| 53383f3184 | |||
| b51c937e87 | |||
| f3d7f67671 | |||
| 87001d0806 | |||
| ffce0dfb2e | |||
| c1d08019d9 | |||
| bfa95ad976 | |||
| 4a4b39f898 | |||
| 215499a3f8 | |||
| 8c11974644 | |||
| 7dcbd8108e | |||
| 43fea43363 | |||
| e00b74c0e0 | |||
| 5ef439dd0f | |||
| 538c7b3c97 | |||
| 81456b2340 | |||
| dfec3f16ab | |||
| e67499e6cc | |||
| a1b5e7899f | |||
| a88a149999 | |||
| 168593d7af | |||
| c646abc05d | |||
| f2a1561d31 | |||
| d7a3aeaa1b | |||
| 4b9a63de19 | |||
| 07985c2cae | |||
| 0c13414f14 | |||
| 1021c7a7af | |||
| 5306fb3709 | |||
| 1afddf9db4 | |||
| 929538dd5f | |||
| f432e65a14 | |||
| dfc1193c52 | |||
| 25077a1008 | |||
| b3b3bf6c1d | |||
| 29ae71333a | |||
| a7ebbd89c0 | |||
| ee25635c79 | |||
| b8e19ae78a | |||
| 937bd892fd | |||
| adce6e4f68 | |||
| 0b1ba0458d | |||
| 7668b95900 | |||
| 47465f198c | |||
| f3d03dd26a | |||
| ecdd84efd8 | |||
| 0ad6a6a951 | |||
| dc97f709d7 | |||
| 34ccf141d1 | |||
| f0b16c277c | |||
| 68061444d8 | |||
| 93356286d8 | |||
| 84e816fc5b | |||
| 12a482a6ba | |||
| a26a40d00f | |||
| 64c6b4718d | |||
| d1ebdf5df2 | |||
| 496c4947bd | |||
| 82f98746bd | |||
| 65418c7c00 | |||
| bbf6bade7c | |||
| b6cde05f0d | |||
| 0a3a1d7eca | |||
| 947cbdd858 | |||
| 7a84d1ecba | |||
| 8c999cd60c | |||
| ad5d2a36bc | |||
| 1666746692 | |||
| 3a74fc85b4 | |||
| 92a1c304a8 | |||
| d8c24663fc | |||
| 195c15c8dc | |||
| 44c06f6d20 | |||
| c268f20d18 | |||
| 83c92f3ac1 | |||
| b4a3eccfa3 | |||
| 837d006e11 | |||
| c1f1639807 | |||
| 8f71e45666 | |||
| 17fa2c9933 | |||
| 22fdf157ef | |||
| 6c8b39d32a | |||
| 5a2b3d9d87 | |||
| 8641796d04 | |||
| c5c5cfb4d5 | |||
| c74033d7f1 | |||
| d8c6873ee9 | |||
| b0cc2a2a1d | |||
| 226f9b7857 | |||
| 1abf72855e | |||
| b044410e42 | |||
| b64052850f | |||
| 8868b10042 | |||
| b18190891d | |||
| 5b001eec3e | |||
| 882ca44816 | |||
| 60157606fe | |||
| cbb0294cd2 | |||
| 1b4802ab73 | |||
| 6b7f210ef3 | |||
| 571b154345 | |||
| 9a2b5a1219 | |||
| fe9de41d58 | |||
| daff50e79e | |||
| 09b687d66f | |||
| 665ff9f14e | |||
| bd1a12ceaa | |||
| d33e931a0d | |||
| fbe38c362c | |||
| 718efc828a | |||
| 6d3ed84807 | |||
| 28e5efc902 | |||
| 510c47bd78 | |||
| 2e0065216f | |||
| ce024c74e1 | |||
| 90e2935abf | |||
| 12cd654bce | |||
| c3ea793abb | |||
| c901f6d1dd | |||
| 193cfb634c | |||
| a2b7620b64 | |||
| 9d91a4a298 | |||
| 3b6dbaccf8 | |||
| 3fe9e6b82b | |||
| b6614045aa | |||
| cbf27f0bdb | |||
| bc78e2e1b9 | |||
| deafe39f76 | |||
| 1f63eca1a8 | |||
| 3fb6bc888b | |||
| 2c0db908b5 | |||
| ca9403f981 | |||
| a8d96087c1 | |||
| 1649505121 | |||
| 41a063e2ac | |||
| ba019ad143 | |||
| 6f3071f6ce | |||
| 5cdb2dd601 | |||
| 4db41f0225 | |||
| cc8581164d | |||
| 7d50353697 | |||
| d742f8b88f | |||
| 22bf036a66 | |||
| c45351beff | |||
| 6d1d0751e8 | |||
| 15012ec58c | |||
| fed91ff5a1 | |||
| 0228ec796b | |||
| 5b92af6a90 | |||
| 442a1ba50d | |||
| c3f6aa17ee | |||
| 69de7b4045 | |||
| 8dc278f1a0 | |||
| 5f907d4219 | |||
| c39c5f254f | |||
| 0dfc4ed696 | |||
| 950a0df8b1 | |||
| 2a0dd4cf55 | |||
| 575c381e65 | |||
| 87061bcce8 | |||
| a6d3995013 | |||
| d0d40f4fce | |||
| ce7d81325d | |||
| 7cfecab7e2 | |||
| 8f8da51808 | |||
| f94fd7d5fc | |||
| befc41ae54 | |||
| 02092926ab | |||
| a49b4ab93a | |||
| bd7549bc8b | |||
| 47e1d209db | |||
| 5d2f5ec12f | |||
| 2d2dc7f14a | |||
| 43bd2a060c | |||
| b518d66aa2 | |||
| 2ba59cebe3 | |||
| f165c85e69 | |||
| fca454bba3 | |||
| 3dc1adfad4 | |||
| 38754e0598 | |||
| 8fb4446d82 | |||
| 3725ac145b | |||
| 7df0d06005 | |||
| 4e855b638b | |||
| 9783aba09c | |||
| 1936b20309 | |||
| 69de9687d0 | |||
| bdeeca7d43 | |||
| a7ba3cad85 | |||
| ef5fcad8cf | |||
| d8de6c8f7b | |||
| c3239da266 | |||
| 1edf948e49 | |||
| 224c4a717b | |||
| 6202436bfd | |||
| 122144857e | |||
| 92bcf672fb | |||
| 6f4ffa0758 | |||
| 82186c8a7f | |||
| 50596e1a6a | |||
| 9edcbbb9a8 | |||
| a59805d739 | |||
| b96c06ffdc | |||
| 8abe358c1e | |||
| 2142b2aea3 | |||
| 53ba3ced06 | |||
| a0f336c31f | |||
| 081fa2209a | |||
| ca67d3fb2c | |||
| 5a6b43da46 | |||
| 7d3fa41911 | |||
| b8f3f5e8d2 | |||
| 4849d5413f | |||
| 8b8bf6f97d | |||
| 9eea958e17 | |||
| f8a151c2a5 | |||
| 1013c32316 | |||
| d9ed7e1fb2 | |||
| 689da4c479 | |||
| 87d954a322 | |||
| 74f601b352 | |||
| a3359b62d4 | |||
| 064708a354 | |||
| 066a46d7aa | |||
| 333660e628 | |||
| 81f80a6b22 | |||
| dd613ac86c | |||
| 73c28890d7 | |||
| 61dd94ceb0 | |||
| 1fec5a873e | |||
| 9c4abcc927 | |||
| b74e38ef63 | |||
| 86f640627f | |||
| e27568a9d8 | |||
| 149133cc44 | |||
| 1b2d5a357f | |||
| ecc6371733 | |||
| 0c66180cf3 | |||
| 5954c64cc3 | |||
| d0b7a52202 | |||
| c18085d173 | |||
| 67f88ea97a | |||
| 14353afa78 | |||
| a77618cc6b | |||
| cac2c363fa | |||
| ced1ce340a | |||
| 1d99b7d0f9 | |||
| 5c47a75f63 | |||
| 1ef2eeb456 | |||
| c32f8e972a | |||
| 04492e75b2 | |||
| 8d0ca7f5c1 | |||
| 0a4f82bc22 | |||
| 5ee7f8037d | |||
| 12728c0fcc | |||
| 362f0895f4 | |||
| 4e2ccfc091 | |||
| e4b1e1118b | |||
| fb64ac942b | |||
| 3fc40f45b3 | |||
| ca5ccc8799 | |||
| 057cc2538e | |||
| ed22789a1a | |||
| 2abf22e37b | |||
| 9b08b51ad8 | |||
| 83cdf76636 | |||
| f545113840 | |||
| f86bc71c43 | |||
| 8af9875d45 | |||
| 8a9b31eccd | |||
| b4a5f66f29 | |||
| e105ea660b | |||
| 1149393789 | |||
| d4655660f4 | |||
| e656063771 | |||
| 825c059c2e | |||
| 8e8f4dbdd3 | |||
| 865c253922 | |||
| cd6e06c86e | |||
| 422f225e8e | |||
| 9921c54882 | |||
| 20fca07d8f | |||
| 8ee40ade45 | |||
| 30ead79e11 | |||
| 5c859d929b | |||
| c89058788e | |||
| 35c3868c56 | |||
| 85689ebc1c | |||
| ba2e798f7d | |||
| 4fcc9dd587 | |||
| 85edef8394 | |||
| 05f19d574a | |||
| 1a24559729 | |||
| 7a51c9d540 | |||
| 1d22377cad | |||
| 559f6e2791 | |||
| 90aaaa50fc | |||
| bffb3120c1 | |||
| 3fcf6559ab | |||
| 85f4a8daea | |||
| 2595479e43 | |||
| b603771242 | |||
| 9c1183bc59 | |||
| 6b78b1c882 | |||
| ee3d46c8fa | |||
| 59e52bb601 | |||
| 553dbccec7 | |||
| 2e06eb0e7b | |||
| 31c4d35932 | |||
| eb03382b2d | |||
| fcd0c1d606 | |||
| 276ef6cdde | |||
| c5088e6b66 | |||
| 62f05964b4 | |||
| b6a65ce125 | |||
| 315421037f | |||
| 4ff200d315 | |||
| 5700f789e2 | |||
| 689767e3ca | |||
| 66efc9a469 | |||
| 4c3e477667 | |||
| 8cdae5f56e | |||
| 347295ecaf | |||
| 7272204d58 |
+2
-1
@@ -14,10 +14,11 @@ MANIFEST.in
|
|||||||
README.md
|
README.md
|
||||||
freqtrade.service
|
freqtrade.service
|
||||||
freqtrade.egg-info
|
freqtrade.egg-info
|
||||||
|
.venv/
|
||||||
|
|
||||||
config.json*
|
config.json*
|
||||||
*.sqlite
|
*.sqlite
|
||||||
user_data
|
user_data/
|
||||||
*.log
|
*.log
|
||||||
|
|
||||||
.vscode
|
.vscode
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
name: Bug report
|
name: Bug report
|
||||||
about: Create a report to help us improve
|
about: Create a report to help us improve. Do not use this for strategy assistance.
|
||||||
title: ''
|
title: ''
|
||||||
labels: "Triage Needed"
|
labels: "Triage Needed"
|
||||||
assignees: ''
|
assignees: ''
|
||||||
@@ -12,6 +12,10 @@ Have you searched for similar issues before posting it?
|
|||||||
If you have discovered a bug in the bot, please [search the issue tracker](https://github.com/freqtrade/freqtrade/issues?q=is%3Aissue).
|
If you have discovered a bug in the bot, please [search the issue tracker](https://github.com/freqtrade/freqtrade/issues?q=is%3Aissue).
|
||||||
If it hasn't been reported, please create a new issue.
|
If it hasn't been reported, please create a new issue.
|
||||||
|
|
||||||
|
Has your strategy or configuration been generated by an AI model, and is now not working?
|
||||||
|
This is almost certainly NOT a bug in Freqtrade, but a problem with the code your AI model generated.
|
||||||
|
Please consult the documentation. We'll close such issues and point to the documentation.
|
||||||
|
|
||||||
Please do not use the bug report template to request new features.
|
Please do not use the bug report template to request new features.
|
||||||
-->
|
-->
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
name: Feature request
|
name: Feature request
|
||||||
about: Suggest an idea for this project
|
about: Suggest a new feature or idea for this project
|
||||||
title: ''
|
title: ''
|
||||||
labels: ''
|
labels: ''
|
||||||
assignees: ''
|
assignees: ''
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
name: Question
|
name: Question
|
||||||
about: Ask a question you could not find an answer in the docs
|
about: Ask a question you could not find an answer in the docs. Use this template if you've got problems with your strategy.
|
||||||
title: ''
|
title: ''
|
||||||
labels: "Question"
|
labels: "Question"
|
||||||
assignees: ''
|
assignees: ''
|
||||||
|
|||||||
@@ -1,5 +1,10 @@
|
|||||||
<!-- Thank you for sending your pull request. But first, have you included
|
<!-- Thank you for sending your pull request. But first, have you included
|
||||||
unit tests, and is your code PEP8 conformant? [More details](https://github.com/freqtrade/freqtrade/blob/develop/CONTRIBUTING.md)
|
unit tests, and is your code PEP8 conformant? [More details](https://github.com/freqtrade/freqtrade/blob/develop/CONTRIBUTING.md)
|
||||||
|
|
||||||
|
Did you use AI to create your changes?
|
||||||
|
If so, please state it clearly in the PR description (failing to do so may result in your PR being closed).
|
||||||
|
|
||||||
|
Also, please do a self review of the changes made before submitting the PR to make sure only relevant changes are included.
|
||||||
-->
|
-->
|
||||||
## Summary
|
## Summary
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,92 @@
|
|||||||
|
name: 'docker-tags'
|
||||||
|
description: 'Set Docker default Tag environment variables'
|
||||||
|
# inputs:
|
||||||
|
outputs:
|
||||||
|
BRANCH_NAME:
|
||||||
|
description: 'The branch name'
|
||||||
|
value: ${{ steps.tags.outputs.BRANCH_NAME }}
|
||||||
|
TAG:
|
||||||
|
description: 'The Docker tag'
|
||||||
|
value: ${{ steps.tags.outputs.TAG }}
|
||||||
|
TAG_PLOT:
|
||||||
|
description: 'The Docker tag for the plot'
|
||||||
|
value: ${{ steps.tags.outputs.TAG_PLOT }}
|
||||||
|
TAG_FREQAI:
|
||||||
|
description: 'The Docker tag for the freqai'
|
||||||
|
value: ${{ steps.tags.outputs.TAG_FREQAI }}
|
||||||
|
TAG_FREQAI_RL:
|
||||||
|
description: 'The Docker tag for the freqai_rl'
|
||||||
|
value: ${{ steps.tags.outputs.TAG_FREQAI_RL }}
|
||||||
|
TAG_FREQAI_TORCH:
|
||||||
|
description: 'The Docker tag for the freqai_torch'
|
||||||
|
value: ${{ steps.tags.outputs.TAG_FREQAI_TORCH }}
|
||||||
|
TAG_ARM:
|
||||||
|
description: 'The Docker tag for the arm'
|
||||||
|
value: ${{ steps.tags.outputs.TAG_ARM }}
|
||||||
|
TAG_PLOT_ARM:
|
||||||
|
description: 'The Docker tag for the plot arm'
|
||||||
|
value: ${{ steps.tags.outputs.TAG_PLOT_ARM }}
|
||||||
|
TAG_FREQAI_ARM:
|
||||||
|
description: 'The Docker tag for the freqai arm'
|
||||||
|
value: ${{ steps.tags.outputs.TAG_FREQAI_ARM }}
|
||||||
|
TAG_FREQAI_RL_ARM:
|
||||||
|
description: 'The Docker tag for the freqai_rl arm'
|
||||||
|
value: ${{ steps.tags.outputs.TAG_FREQAI_RL_ARM }}
|
||||||
|
TAG_PI:
|
||||||
|
description: 'The Docker tag for the pi'
|
||||||
|
value: ${{ steps.tags.outputs.TAG_PI }}
|
||||||
|
CACHE_TAG_PI:
|
||||||
|
description: 'The Docker cache tag for the pi'
|
||||||
|
value: ${{ steps.tags.outputs.CACHE_TAG_PI }}
|
||||||
|
runs:
|
||||||
|
using: "composite"
|
||||||
|
steps:
|
||||||
|
- name: Extract branch name
|
||||||
|
shell: bash
|
||||||
|
id: tags
|
||||||
|
env:
|
||||||
|
BRANCH_NAME_INPUT: ${{ github.event.inputs.branch_name }}
|
||||||
|
run: |
|
||||||
|
if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then
|
||||||
|
BRANCH_NAME="${BRANCH_NAME_INPUT}"
|
||||||
|
else
|
||||||
|
BRANCH_NAME="${GITHUB_REF##*/}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Replace / with _ to create a valid tag
|
||||||
|
TAG=$(echo "${BRANCH_NAME}" | sed -e "s/\//_/g")
|
||||||
|
TAG_PLOT=${TAG}_plot
|
||||||
|
TAG_FREQAI=${TAG}_freqai
|
||||||
|
TAG_FREQAI_RL=${TAG_FREQAI}rl
|
||||||
|
TAG_FREQAI_TORCH=${TAG_FREQAI}torch
|
||||||
|
|
||||||
|
TAG_ARM=${TAG}_arm
|
||||||
|
TAG_PLOT_ARM=${TAG_PLOT}_arm
|
||||||
|
TAG_FREQAI_ARM=${TAG_FREQAI}_arm
|
||||||
|
TAG_FREQAI_RL_ARM=${TAG_FREQAI_RL}_arm
|
||||||
|
|
||||||
|
TAG_PI="${TAG}_pi"
|
||||||
|
|
||||||
|
CACHE_TAG_PI=${CACHE_IMAGE}:${TAG_PI}_cache
|
||||||
|
|
||||||
|
echo "BRANCH_NAME=${BRANCH_NAME}" >> "$GITHUB_OUTPUT"
|
||||||
|
echo "TAG=${TAG}" >> "$GITHUB_OUTPUT"
|
||||||
|
echo "TAG_PLOT=${TAG_PLOT}" >> "$GITHUB_OUTPUT"
|
||||||
|
echo "TAG_FREQAI=${TAG_FREQAI}" >> "$GITHUB_OUTPUT"
|
||||||
|
echo "TAG_FREQAI_RL=${TAG_FREQAI_RL}" >> "$GITHUB_OUTPUT"
|
||||||
|
echo "TAG_FREQAI_TORCH=${TAG_FREQAI_TORCH}" >> "$GITHUB_OUTPUT"
|
||||||
|
echo "TAG_ARM=${TAG_ARM}" >> "$GITHUB_OUTPUT"
|
||||||
|
echo "TAG_PLOT_ARM=${TAG_PLOT_ARM}" >> "$GITHUB_OUTPUT"
|
||||||
|
echo "TAG_FREQAI_ARM=${TAG_FREQAI_ARM}" >> "$GITHUB_OUTPUT"
|
||||||
|
echo "TAG_FREQAI_RL_ARM=${TAG_FREQAI_RL_ARM}" >> "$GITHUB_OUTPUT"
|
||||||
|
echo "TAG_PI=${TAG_PI}" >> "$GITHUB_OUTPUT"
|
||||||
|
|
||||||
|
echo "CACHE_TAG_PI=${CACHE_TAG_PI}" >> "$GITHUB_OUTPUT"
|
||||||
|
|
||||||
|
cat "$GITHUB_OUTPUT"
|
||||||
|
|
||||||
|
- name: Save commit SHA to file
|
||||||
|
shell: bash
|
||||||
|
# Add commit to docker container
|
||||||
|
run: |
|
||||||
|
echo "${GITHUB_SHA}" > freqtrade_commit
|
||||||
@@ -29,6 +29,10 @@ updates:
|
|||||||
mkdocs:
|
mkdocs:
|
||||||
patterns:
|
patterns:
|
||||||
- "mkdocs*"
|
- "mkdocs*"
|
||||||
|
scipy:
|
||||||
|
patterns:
|
||||||
|
- "scipy"
|
||||||
|
- "scipy-stubs"
|
||||||
|
|
||||||
- package-ecosystem: "github-actions"
|
- package-ecosystem: "github-actions"
|
||||||
directory: "/"
|
directory: "/"
|
||||||
|
|||||||
@@ -15,11 +15,11 @@ jobs:
|
|||||||
environment:
|
environment:
|
||||||
name: develop
|
name: develop
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v5
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
|
|
||||||
- uses: actions/setup-python@v5
|
- uses: actions/setup-python@v6
|
||||||
with:
|
with:
|
||||||
python-version: "3.12"
|
python-version: "3.12"
|
||||||
|
|
||||||
|
|||||||
+94
-379
@@ -19,52 +19,43 @@ concurrency:
|
|||||||
permissions:
|
permissions:
|
||||||
repository-projects: read
|
repository-projects: read
|
||||||
jobs:
|
jobs:
|
||||||
build-linux:
|
tests:
|
||||||
|
name: "Tests and Linting"
|
||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
os: [ "ubuntu-22.04", "ubuntu-24.04" ]
|
os: [ "ubuntu-22.04", "ubuntu-24.04", "macos-14", "macos-15" , "windows-2022", "windows-2025" ]
|
||||||
python-version: ["3.10", "3.11", "3.12"]
|
python-version: ["3.11", "3.12", "3.13"]
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v5
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
|
|
||||||
- name: Set up Python
|
- name: Set up Python
|
||||||
uses: actions/setup-python@v5
|
uses: actions/setup-python@v6
|
||||||
with:
|
with:
|
||||||
python-version: ${{ matrix.python-version }}
|
python-version: ${{ matrix.python-version }}
|
||||||
|
|
||||||
- name: Install uv
|
- name: Install uv
|
||||||
uses: astral-sh/setup-uv@c7f87aa956e4c323abf06d5dec078e358f6b4d04 # v6.0.0
|
uses: astral-sh/setup-uv@b75a909f75acd358c2196fb9a5f1299a9a8868a4 # v6.7.0
|
||||||
with:
|
with:
|
||||||
activate-environment: true
|
activate-environment: true
|
||||||
enable-cache: true
|
enable-cache: true
|
||||||
python-version: ${{ matrix.python-version }}
|
python-version: ${{ matrix.python-version }}
|
||||||
cache-dependency-glob: "requirements**.txt"
|
cache-dependency-glob: "requirements**.txt"
|
||||||
cache-suffix: "${{ matrix.python-version }}"
|
cache-suffix: "${{ matrix.python-version }}"
|
||||||
prune-cache: false
|
|
||||||
|
|
||||||
- name: Cache_dependencies
|
- name: Installation - macOS (Brew)
|
||||||
uses: actions/cache@v4
|
if: ${{ runner.os == 'macOS' }}
|
||||||
id: cache
|
|
||||||
with:
|
|
||||||
path: ~/dependencies/
|
|
||||||
key: ${{ runner.os }}-dependencies
|
|
||||||
|
|
||||||
- name: TA binary *nix
|
|
||||||
if: steps.cache.outputs.cache-hit != 'true'
|
|
||||||
run: |
|
run: |
|
||||||
cd build_helpers && ./install_ta-lib.sh ${HOME}/dependencies/; cd ..
|
# brew update
|
||||||
|
# TODO: Should be the brew upgrade
|
||||||
|
brew install libomp
|
||||||
|
|
||||||
- name: Installation - *nix
|
- name: Installation (python)
|
||||||
run: |
|
run: |
|
||||||
uv pip install --upgrade wheel
|
uv pip install --upgrade wheel
|
||||||
export LD_LIBRARY_PATH=${HOME}/dependencies/lib:$LD_LIBRARY_PATH
|
|
||||||
export TA_LIBRARY_PATH=${HOME}/dependencies/lib
|
|
||||||
export TA_INCLUDE_PATH=${HOME}/dependencies/include
|
|
||||||
uv pip install -r requirements-dev.txt
|
uv pip install -r requirements-dev.txt
|
||||||
uv pip install -e ft_client/
|
uv pip install -e ft_client/
|
||||||
uv pip install -e .
|
uv pip install -e .
|
||||||
@@ -76,7 +67,7 @@ jobs:
|
|||||||
- name: Tests
|
- name: Tests
|
||||||
if: (!(runner.os == 'Linux' && matrix.python-version == '3.12' && matrix.os == 'ubuntu-24.04'))
|
if: (!(runner.os == 'Linux' && matrix.python-version == '3.12' && matrix.os == 'ubuntu-24.04'))
|
||||||
run: |
|
run: |
|
||||||
pytest --random-order
|
pytest --random-order --durations 20 -n auto
|
||||||
|
|
||||||
- name: Tests with Coveralls
|
- name: Tests with Coveralls
|
||||||
if: (runner.os == 'Linux' && matrix.python-version == '3.12' && matrix.os == 'ubuntu-24.04')
|
if: (runner.os == 'Linux' && matrix.python-version == '3.12' && matrix.os == 'ubuntu-24.04')
|
||||||
@@ -90,6 +81,7 @@ jobs:
|
|||||||
COVERALLS_REPO_TOKEN: 6D1m0xupS3FgutfuGao8keFf9Hc0FpIXu
|
COVERALLS_REPO_TOKEN: 6D1m0xupS3FgutfuGao8keFf9Hc0FpIXu
|
||||||
run: |
|
run: |
|
||||||
# Allow failure for coveralls
|
# Allow failure for coveralls
|
||||||
|
uv pip install coveralls
|
||||||
coveralls || true
|
coveralls || true
|
||||||
|
|
||||||
- name: Run json schema extract
|
- name: Run json schema extract
|
||||||
@@ -102,7 +94,9 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
python build_helpers/create_command_partials.py
|
python build_helpers/create_command_partials.py
|
||||||
|
|
||||||
- name: Check for repository changes
|
- name: Check for repository changes - *nix
|
||||||
|
# TODO: python 3.13 slightly changed the output of argparse.
|
||||||
|
if: ${{ (matrix.python-version != '3.13') && (runner.os != 'Windows') }}
|
||||||
run: |
|
run: |
|
||||||
if [ -n "$(git status --porcelain)" ]; then
|
if [ -n "$(git status --porcelain)" ]; then
|
||||||
echo "Repository is dirty, changes detected:"
|
echo "Repository is dirty, changes detected:"
|
||||||
@@ -113,13 +107,27 @@ jobs:
|
|||||||
echo "Repository is clean, no changes detected."
|
echo "Repository is clean, no changes detected."
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
- name: Check for repository changes - Windows
|
||||||
|
if: ${{ runner.os == 'Windows' && (matrix.python-version != '3.13') }}
|
||||||
|
run: |
|
||||||
|
if (git status --porcelain) {
|
||||||
|
Write-Host "Repository is dirty, changes detected:"
|
||||||
|
git status
|
||||||
|
git diff
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Write-Host "Repository is clean, no changes detected."
|
||||||
|
}
|
||||||
|
|
||||||
- name: Backtesting (multi)
|
- name: Backtesting (multi)
|
||||||
run: |
|
run: |
|
||||||
cp tests/testdata/config.tests.json config.json
|
|
||||||
freqtrade create-userdir --userdir user_data
|
freqtrade create-userdir --userdir user_data
|
||||||
|
cp tests/testdata/config.tests.json user_data/config.json
|
||||||
freqtrade new-strategy -s AwesomeStrategy
|
freqtrade new-strategy -s AwesomeStrategy
|
||||||
freqtrade new-strategy -s AwesomeStrategyMin --template minimal
|
freqtrade new-strategy -s AwesomeStrategyMin --template minimal
|
||||||
freqtrade backtesting --datadir tests/testdata --strategy-list AwesomeStrategy AwesomeStrategyMin -i 5m
|
freqtrade new-strategy -s AwesomeStrategyAdv --template advanced
|
||||||
|
freqtrade backtesting --datadir tests/testdata --strategy-list AwesomeStrategy AwesomeStrategyMin AwesomeStrategyAdv -i 5m
|
||||||
|
|
||||||
- name: Hyperopt
|
- name: Hyperopt
|
||||||
run: |
|
run: |
|
||||||
@@ -140,221 +148,13 @@ jobs:
|
|||||||
ruff format --check
|
ruff format --check
|
||||||
|
|
||||||
- name: Mypy
|
- name: Mypy
|
||||||
if: matrix.os == 'ubuntu-24.04'
|
if: ${{ matrix.os == 'ubuntu-24.04' || matrix.os == 'macos-15' }}
|
||||||
run: |
|
|
||||||
mypy freqtrade scripts tests
|
|
||||||
|
|
||||||
- name: Discord notification
|
|
||||||
uses: rjstone/discord-webhook-notify@1399c1b2d57cc05894d506d2cfdc33c5f012b993 #v1.1.1
|
|
||||||
if: failure() && ( github.event_name != 'pull_request' || github.event.pull_request.head.repo.fork == false)
|
|
||||||
with:
|
|
||||||
severity: error
|
|
||||||
details: Freqtrade CI failed on ${{ matrix.os }}
|
|
||||||
webhookUrl: ${{ secrets.DISCORD_WEBHOOK }}
|
|
||||||
|
|
||||||
build-macos:
|
|
||||||
runs-on: ${{ matrix.os }}
|
|
||||||
strategy:
|
|
||||||
matrix:
|
|
||||||
os: [ "macos-13", "macos-14", "macos-15" ]
|
|
||||||
python-version: ["3.10", "3.11", "3.12"]
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
with:
|
|
||||||
persist-credentials: false
|
|
||||||
|
|
||||||
- name: Set up Python
|
|
||||||
uses: actions/setup-python@v5
|
|
||||||
with:
|
|
||||||
python-version: ${{ matrix.python-version }}
|
|
||||||
check-latest: true
|
|
||||||
|
|
||||||
- name: Install uv
|
|
||||||
uses: astral-sh/setup-uv@c7f87aa956e4c323abf06d5dec078e358f6b4d04 # v6.0.0
|
|
||||||
with:
|
|
||||||
activate-environment: true
|
|
||||||
enable-cache: true
|
|
||||||
python-version: ${{ matrix.python-version }}
|
|
||||||
cache-dependency-glob: "requirements**.txt"
|
|
||||||
cache-suffix: "${{ matrix.python-version }}"
|
|
||||||
prune-cache: false
|
|
||||||
|
|
||||||
- name: Cache_dependencies
|
|
||||||
uses: actions/cache@v4
|
|
||||||
id: cache
|
|
||||||
with:
|
|
||||||
path: ~/dependencies/
|
|
||||||
key: ${{ matrix.os }}-dependencies
|
|
||||||
|
|
||||||
- name: TA binary *nix
|
|
||||||
if: steps.cache.outputs.cache-hit != 'true'
|
|
||||||
run: |
|
|
||||||
cd build_helpers && ./install_ta-lib.sh ${HOME}/dependencies/; cd ..
|
|
||||||
|
|
||||||
- name: Installation - macOS (Brew)
|
|
||||||
run: |
|
|
||||||
# brew update
|
|
||||||
# TODO: Should be the brew upgrade
|
|
||||||
# homebrew fails to update python due to unlinking failures
|
|
||||||
# https://github.com/actions/runner-images/issues/6817
|
|
||||||
rm /usr/local/bin/2to3 || true
|
|
||||||
rm /usr/local/bin/2to3-3.11 || true
|
|
||||||
rm /usr/local/bin/2to3-3.12 || true
|
|
||||||
rm /usr/local/bin/idle3 || true
|
|
||||||
rm /usr/local/bin/idle3.11 || true
|
|
||||||
rm /usr/local/bin/idle3.12 || true
|
|
||||||
rm /usr/local/bin/pydoc3 || true
|
|
||||||
rm /usr/local/bin/pydoc3.11 || true
|
|
||||||
rm /usr/local/bin/pydoc3.12 || true
|
|
||||||
rm /usr/local/bin/python3 || true
|
|
||||||
rm /usr/local/bin/python3.11 || true
|
|
||||||
rm /usr/local/bin/python3.12 || true
|
|
||||||
rm /usr/local/bin/python3-config || true
|
|
||||||
rm /usr/local/bin/python3.11-config || true
|
|
||||||
rm /usr/local/bin/python3.12-config || true
|
|
||||||
|
|
||||||
brew install libomp
|
|
||||||
|
|
||||||
- name: Installation (python)
|
|
||||||
run: |
|
|
||||||
uv pip install wheel
|
|
||||||
export LD_LIBRARY_PATH=${HOME}/dependencies/lib:$LD_LIBRARY_PATH
|
|
||||||
export TA_LIBRARY_PATH=${HOME}/dependencies/lib
|
|
||||||
export TA_INCLUDE_PATH=${HOME}/dependencies/include
|
|
||||||
uv pip install -r requirements-dev.txt
|
|
||||||
uv pip install -e ft_client/
|
|
||||||
uv pip install -e .
|
|
||||||
|
|
||||||
- name: Tests
|
|
||||||
run: |
|
|
||||||
pytest --random-order
|
|
||||||
|
|
||||||
- name: Check for repository changes
|
|
||||||
run: |
|
|
||||||
if [ -n "$(git status --porcelain)" ]; then
|
|
||||||
echo "Repository is dirty, changes detected:"
|
|
||||||
git status
|
|
||||||
git diff
|
|
||||||
exit 1
|
|
||||||
else
|
|
||||||
echo "Repository is clean, no changes detected."
|
|
||||||
fi
|
|
||||||
|
|
||||||
- name: Backtesting
|
|
||||||
run: |
|
|
||||||
cp tests/testdata/config.tests.json config.json
|
|
||||||
freqtrade create-userdir --userdir user_data
|
|
||||||
freqtrade new-strategy -s AwesomeStrategyAdv --template advanced
|
|
||||||
freqtrade backtesting --datadir tests/testdata --strategy AwesomeStrategyAdv
|
|
||||||
|
|
||||||
- name: Hyperopt
|
|
||||||
run: |
|
|
||||||
cp tests/testdata/config.tests.json config.json
|
|
||||||
freqtrade create-userdir --userdir user_data
|
|
||||||
freqtrade hyperopt --datadir tests/testdata -e 5 --strategy SampleStrategy --hyperopt-loss SharpeHyperOptLossDaily --print-all
|
|
||||||
|
|
||||||
- name: Sort imports (isort)
|
|
||||||
run: |
|
|
||||||
isort --check .
|
|
||||||
|
|
||||||
- name: Run Ruff
|
|
||||||
run: |
|
|
||||||
ruff check --output-format=github
|
|
||||||
|
|
||||||
- name: Run Ruff format check
|
|
||||||
run: |
|
|
||||||
ruff format --check
|
|
||||||
|
|
||||||
- name: Mypy
|
|
||||||
if: matrix.os == 'macos-15'
|
|
||||||
run: |
|
|
||||||
mypy freqtrade scripts
|
|
||||||
|
|
||||||
- name: Discord notification
|
|
||||||
uses: rjstone/discord-webhook-notify@1399c1b2d57cc05894d506d2cfdc33c5f012b993 #v1.1.1
|
|
||||||
if: failure() && ( github.event_name != 'pull_request' || github.event.pull_request.head.repo.fork == false)
|
|
||||||
with:
|
|
||||||
severity: info
|
|
||||||
details: Test Succeeded!
|
|
||||||
webhookUrl: ${{ secrets.DISCORD_WEBHOOK }}
|
|
||||||
|
|
||||||
build-windows:
|
|
||||||
|
|
||||||
runs-on: ${{ matrix.os }}
|
|
||||||
strategy:
|
|
||||||
matrix:
|
|
||||||
os: [ windows-latest ]
|
|
||||||
python-version: ["3.10", "3.11", "3.12"]
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
with:
|
|
||||||
persist-credentials: false
|
|
||||||
|
|
||||||
- name: Set up Python
|
|
||||||
uses: actions/setup-python@v5
|
|
||||||
with:
|
|
||||||
python-version: ${{ matrix.python-version }}
|
|
||||||
|
|
||||||
- name: Install uv
|
|
||||||
uses: astral-sh/setup-uv@c7f87aa956e4c323abf06d5dec078e358f6b4d04 # v6.0.0
|
|
||||||
with:
|
|
||||||
activate-environment: true
|
|
||||||
enable-cache: true
|
|
||||||
python-version: ${{ matrix.python-version }}
|
|
||||||
cache-dependency-glob: "requirements**.txt"
|
|
||||||
cache-suffix: "${{ matrix.python-version }}"
|
|
||||||
prune-cache: false
|
|
||||||
|
|
||||||
- name: Installation
|
|
||||||
run: |
|
|
||||||
function uvpipFunction { uv pip $args }
|
|
||||||
Set-Alias -name pip -value uvpipFunction
|
|
||||||
|
|
||||||
./build_helpers/install_windows.ps1
|
|
||||||
|
|
||||||
- name: Tests
|
|
||||||
run: |
|
|
||||||
pytest --random-order --durations 20 -n auto
|
|
||||||
|
|
||||||
- name: Check for repository changes
|
|
||||||
run: |
|
|
||||||
if (git status --porcelain) {
|
|
||||||
Write-Host "Repository is dirty, changes detected:"
|
|
||||||
git status
|
|
||||||
git diff
|
|
||||||
exit 1
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
Write-Host "Repository is clean, no changes detected."
|
|
||||||
}
|
|
||||||
|
|
||||||
- name: Backtesting
|
|
||||||
run: |
|
|
||||||
cp tests/testdata/config.tests.json config.json
|
|
||||||
freqtrade create-userdir --userdir user_data
|
|
||||||
freqtrade backtesting --datadir tests/testdata --strategy SampleStrategy
|
|
||||||
|
|
||||||
- name: Hyperopt
|
|
||||||
run: |
|
|
||||||
cp tests/testdata/config.tests.json config.json
|
|
||||||
freqtrade create-userdir --userdir user_data
|
|
||||||
freqtrade hyperopt --datadir tests/testdata -e 5 --strategy SampleStrategy --hyperopt-loss SharpeHyperOptLossDaily --print-all
|
|
||||||
|
|
||||||
- name: Run Ruff
|
|
||||||
run: |
|
|
||||||
ruff check --output-format=github
|
|
||||||
|
|
||||||
- name: Run Ruff format check
|
|
||||||
run: |
|
|
||||||
ruff format --check
|
|
||||||
|
|
||||||
- name: Mypy
|
|
||||||
run: |
|
run: |
|
||||||
mypy freqtrade scripts tests
|
mypy freqtrade scripts tests
|
||||||
|
|
||||||
- name: Run Pester tests (PowerShell)
|
- name: Run Pester tests (PowerShell)
|
||||||
|
if: ${{ runner.os == 'Windows' }}
|
||||||
|
shell: powershell
|
||||||
run: |
|
run: |
|
||||||
$PSVersionTable
|
$PSVersionTable
|
||||||
Set-PSRepository psgallery -InstallationPolicy trusted
|
Set-PSRepository psgallery -InstallationPolicy trusted
|
||||||
@@ -363,25 +163,24 @@ jobs:
|
|||||||
Invoke-Pester -Path "tests" -CI
|
Invoke-Pester -Path "tests" -CI
|
||||||
if ($Error.Length -gt 0) {exit 1}
|
if ($Error.Length -gt 0) {exit 1}
|
||||||
|
|
||||||
shell: powershell
|
|
||||||
|
|
||||||
- name: Discord notification
|
- name: Discord notification
|
||||||
uses: rjstone/discord-webhook-notify@1399c1b2d57cc05894d506d2cfdc33c5f012b993 #v1.1.1
|
uses: rjstone/discord-webhook-notify@c2597273488aeda841dd1e891321952b51f7996f #v2.2.1
|
||||||
if: failure() && ( github.event_name != 'pull_request' || github.event.pull_request.head.repo.fork == false)
|
if: ${{ failure() && ( github.event_name != 'pull_request' || github.event.pull_request.head.repo.fork == false) }}
|
||||||
with:
|
with:
|
||||||
severity: error
|
severity: error
|
||||||
details: Test Failed
|
details: Freqtrade CI failed on ${{ matrix.os }} with Python ${{ matrix.python-version }}!
|
||||||
webhookUrl: ${{ secrets.DISCORD_WEBHOOK }}
|
webhookUrl: ${{ secrets.DISCORD_WEBHOOK }}
|
||||||
|
|
||||||
mypy-version-check:
|
mypy-version-check:
|
||||||
runs-on: ubuntu-22.04
|
name: "Mypy Version Check"
|
||||||
|
runs-on: ubuntu-24.04
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v5
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
|
|
||||||
- name: Set up Python
|
- name: Set up Python
|
||||||
uses: actions/setup-python@v5
|
uses: actions/setup-python@v6
|
||||||
with:
|
with:
|
||||||
python-version: "3.12"
|
python-version: "3.12"
|
||||||
|
|
||||||
@@ -391,21 +190,23 @@ jobs:
|
|||||||
python build_helpers/pre_commit_update.py
|
python build_helpers/pre_commit_update.py
|
||||||
|
|
||||||
pre-commit:
|
pre-commit:
|
||||||
|
name: "Pre-commit checks"
|
||||||
runs-on: ubuntu-22.04
|
runs-on: ubuntu-22.04
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v5
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
|
|
||||||
- uses: actions/setup-python@v5
|
- uses: actions/setup-python@v6
|
||||||
with:
|
with:
|
||||||
python-version: "3.12"
|
python-version: "3.12"
|
||||||
- uses: pre-commit/action@2c7b3805fd2a0fd8c1884dcaebf91fc102a13ecd # v3.0.1
|
- uses: pre-commit/action@2c7b3805fd2a0fd8c1884dcaebf91fc102a13ecd # v3.0.1
|
||||||
|
|
||||||
docs-check:
|
docs-check:
|
||||||
|
name: "Documentation build"
|
||||||
runs-on: ubuntu-22.04
|
runs-on: ubuntu-22.04
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v5
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
|
|
||||||
@@ -414,7 +215,7 @@ jobs:
|
|||||||
./tests/test_docs.sh
|
./tests/test_docs.sh
|
||||||
|
|
||||||
- name: Set up Python
|
- name: Set up Python
|
||||||
uses: actions/setup-python@v5
|
uses: actions/setup-python@v6
|
||||||
with:
|
with:
|
||||||
python-version: "3.12"
|
python-version: "3.12"
|
||||||
|
|
||||||
@@ -424,7 +225,7 @@ jobs:
|
|||||||
mkdocs build
|
mkdocs build
|
||||||
|
|
||||||
- name: Discord notification
|
- name: Discord notification
|
||||||
uses: rjstone/discord-webhook-notify@1399c1b2d57cc05894d506d2cfdc33c5f012b993 #v1.1.1
|
uses: rjstone/discord-webhook-notify@c2597273488aeda841dd1e891321952b51f7996f #v2.2.1
|
||||||
if: failure() && ( github.event_name != 'pull_request' || github.event.pull_request.head.repo.fork == false)
|
if: failure() && ( github.event_name != 'pull_request' || github.event.pull_request.head.repo.fork == false)
|
||||||
with:
|
with:
|
||||||
severity: error
|
severity: error
|
||||||
@@ -434,46 +235,30 @@ jobs:
|
|||||||
|
|
||||||
build-linux-online:
|
build-linux-online:
|
||||||
# Run pytest with "live" checks
|
# Run pytest with "live" checks
|
||||||
runs-on: ubuntu-22.04
|
name: "Tests and Linting - Online tests"
|
||||||
|
runs-on: ubuntu-24.04
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v5
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
|
|
||||||
- name: Set up Python
|
- name: Set up Python
|
||||||
uses: actions/setup-python@v5
|
uses: actions/setup-python@v6
|
||||||
with:
|
with:
|
||||||
python-version: "3.12"
|
python-version: "3.12"
|
||||||
|
|
||||||
- name: Install uv
|
- name: Install uv
|
||||||
uses: astral-sh/setup-uv@c7f87aa956e4c323abf06d5dec078e358f6b4d04 # v6.0.0
|
uses: astral-sh/setup-uv@b75a909f75acd358c2196fb9a5f1299a9a8868a4 # v6.7.0
|
||||||
with:
|
with:
|
||||||
activate-environment: true
|
activate-environment: true
|
||||||
enable-cache: true
|
enable-cache: true
|
||||||
python-version: "3.12"
|
python-version: "3.12"
|
||||||
cache-dependency-glob: "requirements**.txt"
|
cache-dependency-glob: "requirements**.txt"
|
||||||
cache-suffix: "3.12"
|
cache-suffix: "3.12"
|
||||||
prune-cache: false
|
|
||||||
|
|
||||||
- name: Cache_dependencies
|
|
||||||
uses: actions/cache@v4
|
|
||||||
id: cache
|
|
||||||
with:
|
|
||||||
path: ~/dependencies/
|
|
||||||
key: ${{ runner.os }}-dependencies
|
|
||||||
|
|
||||||
|
|
||||||
- name: TA binary *nix
|
|
||||||
if: steps.cache.outputs.cache-hit != 'true'
|
|
||||||
run: |
|
|
||||||
cd build_helpers && ./install_ta-lib.sh ${HOME}/dependencies/; cd ..
|
|
||||||
|
|
||||||
- name: Installation - *nix
|
- name: Installation - *nix
|
||||||
run: |
|
run: |
|
||||||
uv pip install --upgrade wheel
|
uv pip install --upgrade wheel
|
||||||
export LD_LIBRARY_PATH=${HOME}/dependencies/lib:$LD_LIBRARY_PATH
|
|
||||||
export TA_LIBRARY_PATH=${HOME}/dependencies/lib
|
|
||||||
export TA_INCLUDE_PATH=${HOME}/dependencies/include
|
|
||||||
uv pip install -r requirements-dev.txt
|
uv pip install -r requirements-dev.txt
|
||||||
uv pip install -e ft_client/
|
uv pip install -e ft_client/
|
||||||
uv pip install -e .
|
uv pip install -e .
|
||||||
@@ -488,9 +273,7 @@ jobs:
|
|||||||
# Notify only once - when CI completes (and after deploy) in case it's successful
|
# Notify only once - when CI completes (and after deploy) in case it's successful
|
||||||
notify-complete:
|
notify-complete:
|
||||||
needs: [
|
needs: [
|
||||||
build-linux,
|
tests,
|
||||||
build-macos,
|
|
||||||
build-windows,
|
|
||||||
docs-check,
|
docs-check,
|
||||||
mypy-version-check,
|
mypy-version-check,
|
||||||
pre-commit,
|
pre-commit,
|
||||||
@@ -505,15 +288,16 @@ jobs:
|
|||||||
|
|
||||||
- name: Check user permission
|
- name: Check user permission
|
||||||
id: check
|
id: check
|
||||||
uses: scherermichael-oss/action-has-permission@136e061bfe093832d87f090dd768e14e27a740d3 # 1.0.6
|
continue-on-error: true
|
||||||
|
uses: prince-chrismc/check-actor-permissions-action@d504e74ba31658f4cdf4fcfeb509d4c09736d88e # v3.0.2
|
||||||
with:
|
with:
|
||||||
required-permission: write
|
permission: "write"
|
||||||
env:
|
env:
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
- name: Discord notification
|
- name: Discord notification
|
||||||
uses: rjstone/discord-webhook-notify@1399c1b2d57cc05894d506d2cfdc33c5f012b993 #v1.1.1
|
uses: rjstone/discord-webhook-notify@c2597273488aeda841dd1e891321952b51f7996f #v2.2.1
|
||||||
if: always() && steps.check.outputs.has-permission && ( github.event_name != 'pull_request' || github.event.pull_request.head.repo.fork == false)
|
if: steps.check.outputs.permitted == 'true' && ( github.event_name != 'pull_request' || github.event.pull_request.head.repo.fork == false)
|
||||||
with:
|
with:
|
||||||
severity: info
|
severity: info
|
||||||
details: Test Completed!
|
details: Test Completed!
|
||||||
@@ -521,16 +305,16 @@ jobs:
|
|||||||
|
|
||||||
build:
|
build:
|
||||||
name: "Build"
|
name: "Build"
|
||||||
needs: [ build-linux, build-macos, build-windows, docs-check, mypy-version-check, pre-commit ]
|
needs: [ tests, docs-check, mypy-version-check, pre-commit ]
|
||||||
runs-on: ubuntu-22.04
|
runs-on: ubuntu-22.04
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v5
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
|
|
||||||
- name: Set up Python
|
- name: Set up Python
|
||||||
uses: actions/setup-python@v5
|
uses: actions/setup-python@v6
|
||||||
with:
|
with:
|
||||||
python-version: "3.12"
|
python-version: "3.12"
|
||||||
|
|
||||||
@@ -572,19 +356,19 @@ jobs:
|
|||||||
id-token: write
|
id-token: write
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v5
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
|
|
||||||
- name: Download artifact 📦
|
- name: Download artifact 📦
|
||||||
uses: actions/download-artifact@v4
|
uses: actions/download-artifact@v5
|
||||||
with:
|
with:
|
||||||
pattern: freqtrade*-build
|
pattern: freqtrade*-build
|
||||||
path: dist
|
path: dist
|
||||||
merge-multiple: true
|
merge-multiple: true
|
||||||
|
|
||||||
- name: Publish to PyPI (Test)
|
- name: Publish to PyPI (Test)
|
||||||
uses: pypa/gh-action-pypi-publish@76f52bc884231f62b9a034ebfe128415bbaabdfc # v1.12.4
|
uses: pypa/gh-action-pypi-publish@ed0c53931b1dc9bd32cbe73a98c7f6766f8a527e # v1.13.0
|
||||||
with:
|
with:
|
||||||
repository-url: https://test.pypi.org/legacy/
|
repository-url: https://test.pypi.org/legacy/
|
||||||
|
|
||||||
@@ -601,115 +385,46 @@ jobs:
|
|||||||
id-token: write
|
id-token: write
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v5
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
|
|
||||||
- name: Download artifact 📦
|
- name: Download artifact 📦
|
||||||
uses: actions/download-artifact@v4
|
uses: actions/download-artifact@v5
|
||||||
with:
|
with:
|
||||||
pattern: freqtrade*-build
|
pattern: freqtrade*-build
|
||||||
path: dist
|
path: dist
|
||||||
merge-multiple: true
|
merge-multiple: true
|
||||||
|
|
||||||
- name: Publish to PyPI
|
- name: Publish to PyPI
|
||||||
uses: pypa/gh-action-pypi-publish@76f52bc884231f62b9a034ebfe128415bbaabdfc # v1.12.4
|
uses: pypa/gh-action-pypi-publish@ed0c53931b1dc9bd32cbe73a98c7f6766f8a527e # v1.13.0
|
||||||
|
|
||||||
|
|
||||||
deploy-docker:
|
docker-build:
|
||||||
needs: [ build-linux, build-macos, build-windows, docs-check, mypy-version-check, pre-commit ]
|
name: "Docker Build and Deploy"
|
||||||
runs-on: ubuntu-22.04
|
needs: [
|
||||||
|
tests,
|
||||||
|
docs-check,
|
||||||
|
mypy-version-check,
|
||||||
|
pre-commit
|
||||||
|
]
|
||||||
if: (github.event_name == 'push' || github.event_name == 'schedule' || github.event_name == 'release') && github.repository == 'freqtrade/freqtrade'
|
if: (github.event_name == 'push' || github.event_name == 'schedule' || github.event_name == 'release') && github.repository == 'freqtrade/freqtrade'
|
||||||
|
uses: ./.github/workflows/docker-build.yml
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
with:
|
|
||||||
persist-credentials: false
|
|
||||||
|
|
||||||
- name: Set up Python
|
|
||||||
uses: actions/setup-python@v5
|
|
||||||
with:
|
|
||||||
python-version: "3.12"
|
|
||||||
|
|
||||||
- name: Extract branch name
|
|
||||||
id: extract-branch
|
|
||||||
run: |
|
|
||||||
echo "GITHUB_REF='${GITHUB_REF}'"
|
|
||||||
echo "branch=${GITHUB_REF##*/}" >> "$GITHUB_OUTPUT"
|
|
||||||
|
|
||||||
- name: Dockerhub login
|
|
||||||
env:
|
|
||||||
DOCKER_PASSWORD: ${{ secrets.DOCKER_PASSWORD }}
|
|
||||||
DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }}
|
|
||||||
run: |
|
|
||||||
echo "${DOCKER_PASSWORD}" | docker login --username ${DOCKER_USERNAME} --password-stdin
|
|
||||||
|
|
||||||
# We need docker experimental to pull the ARM image.
|
|
||||||
- name: Switch docker to experimental
|
|
||||||
run: |
|
|
||||||
docker version -f '{{.Server.Experimental}}'
|
|
||||||
echo $'{\n "experimental": true\n}' | sudo tee /etc/docker/daemon.json
|
|
||||||
sudo systemctl restart docker
|
|
||||||
docker version -f '{{.Server.Experimental}}'
|
|
||||||
|
|
||||||
- name: Set up QEMU
|
|
||||||
uses: docker/setup-qemu-action@29109295f81e9208d7d86ff1c6c12d2833863392 # v3.6.0
|
|
||||||
|
|
||||||
- name: Set up Docker Buildx
|
|
||||||
id: buildx
|
|
||||||
uses: docker/setup-buildx-action@b5ca514318bd6ebac0fb2aedd5d36ec1b5c232a2 #v3.10.0
|
|
||||||
|
|
||||||
- name: Available platforms
|
|
||||||
run: echo ${PLATFORMS}
|
|
||||||
env:
|
|
||||||
PLATFORMS: ${{ steps.buildx.outputs.platforms }}
|
|
||||||
|
|
||||||
- name: Build and test and push docker images
|
|
||||||
env:
|
|
||||||
BRANCH_NAME: ${{ steps.extract-branch.outputs.branch }}
|
|
||||||
run: |
|
|
||||||
build_helpers/publish_docker_multi.sh
|
|
||||||
|
|
||||||
deploy-arm:
|
|
||||||
name: "Deploy Docker"
|
|
||||||
permissions:
|
permissions:
|
||||||
packages: write
|
packages: write
|
||||||
needs: [ deploy-docker ]
|
contents: read
|
||||||
# Only run on 64bit machines
|
secrets:
|
||||||
runs-on: [self-hosted, linux, ARM64]
|
DOCKER_PASSWORD: ${{ secrets.DOCKER_PASSWORD }}
|
||||||
if: (github.event_name == 'push' || github.event_name == 'schedule' || github.event_name == 'release') && github.repository == 'freqtrade/freqtrade'
|
DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }}
|
||||||
|
DISCORD_WEBHOOK: ${{ secrets.DISCORD_WEBHOOK }}
|
||||||
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
with:
|
|
||||||
persist-credentials: false
|
|
||||||
|
|
||||||
- name: Extract branch name
|
packages-cleanup:
|
||||||
id: extract-branch
|
name: "Docker Package Cleanup"
|
||||||
run: |
|
uses: ./.github/workflows/packages-cleanup.yml
|
||||||
echo "GITHUB_REF='${GITHUB_REF}'"
|
# Only run on push, schedule, or release events
|
||||||
echo "branch=${GITHUB_REF##*/}" >> "$GITHUB_OUTPUT"
|
if: (github.event_name == 'push' || github.event_name == 'schedule') && github.repository == 'freqtrade/freqtrade'
|
||||||
|
permissions:
|
||||||
- name: Dockerhub login
|
packages: write
|
||||||
env:
|
with:
|
||||||
DOCKER_PASSWORD: ${{ secrets.DOCKER_PASSWORD }}
|
package_name: 'freqtrade'
|
||||||
DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }}
|
|
||||||
run: |
|
|
||||||
echo "${DOCKER_PASSWORD}" | docker login --username ${DOCKER_USERNAME} --password-stdin
|
|
||||||
|
|
||||||
- name: Build and test and push docker images
|
|
||||||
env:
|
|
||||||
BRANCH_NAME: ${{ steps.extract-branch.outputs.branch }}
|
|
||||||
GHCR_USERNAME: ${{ github.actor }}
|
|
||||||
GHCR_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
run: |
|
|
||||||
build_helpers/publish_docker_arm64.sh
|
|
||||||
|
|
||||||
- name: Discord notification
|
|
||||||
uses: rjstone/discord-webhook-notify@1399c1b2d57cc05894d506d2cfdc33c5f012b993 #v1.1.1
|
|
||||||
if: always() && ( github.event_name != 'pull_request' || github.event.pull_request.head.repo.fork == false) && (github.event_name != 'schedule')
|
|
||||||
with:
|
|
||||||
severity: info
|
|
||||||
details: Deploy Succeeded!
|
|
||||||
webhookUrl: ${{ secrets.DISCORD_WEBHOOK }}
|
|
||||||
|
|||||||
@@ -19,12 +19,12 @@ jobs:
|
|||||||
name: Deploy Docs through mike
|
name: Deploy Docs through mike
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v5
|
||||||
with:
|
with:
|
||||||
persist-credentials: true
|
persist-credentials: true
|
||||||
|
|
||||||
- name: Set up Python
|
- name: Set up Python
|
||||||
uses: actions/setup-python@v5
|
uses: actions/setup-python@v6
|
||||||
with:
|
with:
|
||||||
python-version: '3.12'
|
python-version: '3.12'
|
||||||
|
|
||||||
|
|||||||
@@ -24,11 +24,11 @@ jobs:
|
|||||||
packages: write
|
packages: write
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v5
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
- name: Login to GitHub Container Registry
|
- name: Login to GitHub Container Registry
|
||||||
uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3.4.0
|
uses: docker/login-action@184bdaa0721073962dff0199f1fb9940f07167d1 # v3.5.0
|
||||||
with:
|
with:
|
||||||
registry: ghcr.io
|
registry: ghcr.io
|
||||||
username: ${{ github.actor }}
|
username: ${{ github.actor }}
|
||||||
|
|||||||
@@ -0,0 +1,295 @@
|
|||||||
|
name: Docker Build and Deploy
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_call:
|
||||||
|
secrets:
|
||||||
|
DOCKER_PASSWORD:
|
||||||
|
required: true
|
||||||
|
DOCKER_USERNAME:
|
||||||
|
required: true
|
||||||
|
DISCORD_WEBHOOK:
|
||||||
|
required: false
|
||||||
|
workflow_dispatch:
|
||||||
|
inputs:
|
||||||
|
branch_name:
|
||||||
|
description: 'Branch name to build Docker images for'
|
||||||
|
required: false
|
||||||
|
default: 'develop'
|
||||||
|
type: string
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
|
||||||
|
env:
|
||||||
|
IMAGE_NAME: "freqtradeorg/freqtrade"
|
||||||
|
CACHE_IMAGE: "freqtradeorg/freqtrade_cache"
|
||||||
|
GHCR_IMAGE_NAME: "ghcr.io/freqtrade/freqtrade"
|
||||||
|
PI_PLATFORM: "linux/arm/v7"
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
deploy-docker:
|
||||||
|
name: "Deploy Docker x64 and armv7l"
|
||||||
|
runs-on: ubuntu-22.04
|
||||||
|
if: github.repository == 'freqtrade/freqtrade'
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v5
|
||||||
|
with:
|
||||||
|
persist-credentials: false
|
||||||
|
|
||||||
|
- name: Set docker tag names
|
||||||
|
id: tags
|
||||||
|
uses: ./.github/actions/docker-tags
|
||||||
|
|
||||||
|
- name: Login to Docker Hub
|
||||||
|
uses: docker/login-action@184bdaa0721073962dff0199f1fb9940f07167d1 # v3.5.0
|
||||||
|
with:
|
||||||
|
username: ${{ secrets.DOCKER_USERNAME }}
|
||||||
|
password: ${{ secrets.DOCKER_PASSWORD }}
|
||||||
|
|
||||||
|
- name: Set up QEMU
|
||||||
|
uses: docker/setup-qemu-action@29109295f81e9208d7d86ff1c6c12d2833863392 # v3.6.0
|
||||||
|
with:
|
||||||
|
cache-image: false
|
||||||
|
|
||||||
|
- name: Set up Docker Buildx
|
||||||
|
id: buildx
|
||||||
|
uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 #v3.11.1
|
||||||
|
|
||||||
|
- name: Available platforms
|
||||||
|
run: echo ${PLATFORMS}
|
||||||
|
env:
|
||||||
|
PLATFORMS: ${{ steps.buildx.outputs.platforms }}
|
||||||
|
|
||||||
|
- name: Build image without cache
|
||||||
|
if: github.event_name == 'schedule'
|
||||||
|
env:
|
||||||
|
TAG: ${{ steps.tags.outputs.TAG }}
|
||||||
|
run: |
|
||||||
|
docker build -t ${CACHE_IMAGE}:${TAG} .
|
||||||
|
|
||||||
|
- name: Build ARMHF image without cache
|
||||||
|
if: github.event_name == 'schedule'
|
||||||
|
env:
|
||||||
|
TAG_PI: ${{ steps.tags.outputs.TAG_PI }}
|
||||||
|
CACHE_TAG_PI: ${{ steps.tags.outputs.CACHE_TAG_PI }}
|
||||||
|
run: |
|
||||||
|
docker buildx build \
|
||||||
|
--cache-to=type=registry,ref=${CACHE_TAG_PI} \
|
||||||
|
-f docker/Dockerfile.armhf \
|
||||||
|
--platform ${PI_PLATFORM} \
|
||||||
|
-t ${IMAGE_NAME}:${TAG_PI} \
|
||||||
|
--push \
|
||||||
|
--provenance=false \
|
||||||
|
.
|
||||||
|
|
||||||
|
- name: Build image with cache
|
||||||
|
if: github.event_name != 'schedule'
|
||||||
|
env:
|
||||||
|
TAG: ${{ steps.tags.outputs.TAG }}
|
||||||
|
run: |
|
||||||
|
docker pull ${IMAGE_NAME}:${TAG} || true
|
||||||
|
docker build --cache-from ${IMAGE_NAME}:${TAG} -t ${CACHE_IMAGE}:${TAG} .
|
||||||
|
|
||||||
|
- name: Build ARMHF image with cache
|
||||||
|
if: github.event_name != 'schedule'
|
||||||
|
# disable provenance due to https://github.com/docker/buildx/issues/1509
|
||||||
|
env:
|
||||||
|
TAG_PI: ${{ steps.tags.outputs.TAG_PI }}
|
||||||
|
CACHE_TAG_PI: ${{ steps.tags.outputs.CACHE_TAG_PI }}
|
||||||
|
run: |
|
||||||
|
docker buildx build \
|
||||||
|
--cache-from=type=registry,ref=${CACHE_TAG_PI} \
|
||||||
|
--cache-to=type=registry,ref=${CACHE_TAG_PI} \
|
||||||
|
-f docker/Dockerfile.armhf \
|
||||||
|
--platform ${PI_PLATFORM} \
|
||||||
|
-t ${IMAGE_NAME}:${TAG_PI} \
|
||||||
|
--push \
|
||||||
|
--provenance=false \
|
||||||
|
.
|
||||||
|
|
||||||
|
- name: Run build for AI images
|
||||||
|
env:
|
||||||
|
TAG: ${{ steps.tags.outputs.TAG }}
|
||||||
|
TAG_PLOT: ${{ steps.tags.outputs.TAG_PLOT }}
|
||||||
|
TAG_FREQAI: ${{ steps.tags.outputs.TAG_FREQAI }}
|
||||||
|
TAG_FREQAI_RL: ${{ steps.tags.outputs.TAG_FREQAI_RL }}
|
||||||
|
run: |
|
||||||
|
docker build --build-arg sourceimage=${CACHE_IMAGE} --build-arg sourcetag=${TAG} -t ${CACHE_IMAGE}:${TAG_PLOT} -f docker/Dockerfile.plot .
|
||||||
|
docker build --build-arg sourceimage=${CACHE_IMAGE} --build-arg sourcetag=${TAG} -t ${CACHE_IMAGE}:${TAG_FREQAI} -f docker/Dockerfile.freqai .
|
||||||
|
docker build --build-arg sourceimage=${CACHE_IMAGE} --build-arg sourcetag=${TAG_FREQAI} -t ${CACHE_IMAGE}:${TAG_FREQAI_RL} -f docker/Dockerfile.freqai_rl .
|
||||||
|
|
||||||
|
|
||||||
|
- name: Run backtest in Docker
|
||||||
|
env:
|
||||||
|
TAG: ${{ steps.tags.outputs.TAG }}
|
||||||
|
run: |
|
||||||
|
docker run --rm -v $(pwd)/tests/testdata/config.tests.json:/freqtrade/config.json:ro -v $(pwd)/tests:/tests ${CACHE_IMAGE}:${TAG} backtesting --datadir /tests/testdata --strategy-path /tests/strategy/strats/ --strategy StrategyTestV3
|
||||||
|
|
||||||
|
- name: Push cache images
|
||||||
|
env:
|
||||||
|
TAG: ${{ steps.tags.outputs.TAG }}
|
||||||
|
TAG_PLOT: ${{ steps.tags.outputs.TAG_PLOT }}
|
||||||
|
TAG_FREQAI: ${{ steps.tags.outputs.TAG_FREQAI }}
|
||||||
|
TAG_FREQAI_RL: ${{ steps.tags.outputs.TAG_FREQAI_RL }}
|
||||||
|
run: |
|
||||||
|
docker push ${CACHE_IMAGE}:$TAG
|
||||||
|
docker push ${CACHE_IMAGE}:$TAG_PLOT
|
||||||
|
docker push ${CACHE_IMAGE}:$TAG_FREQAI
|
||||||
|
docker push ${CACHE_IMAGE}:$TAG_FREQAI_RL
|
||||||
|
|
||||||
|
- name: list Images
|
||||||
|
run: |
|
||||||
|
docker images
|
||||||
|
|
||||||
|
deploy-arm:
|
||||||
|
name: "Deploy Docker ARM64"
|
||||||
|
permissions:
|
||||||
|
packages: write
|
||||||
|
needs: [ deploy-docker ]
|
||||||
|
# Only run on 64bit machines
|
||||||
|
runs-on: [self-hosted, linux, ARM64]
|
||||||
|
if: github.repository == 'freqtrade/freqtrade'
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v5
|
||||||
|
with:
|
||||||
|
persist-credentials: false
|
||||||
|
|
||||||
|
- name: Set docker tag names
|
||||||
|
id: tags
|
||||||
|
uses: ./.github/actions/docker-tags
|
||||||
|
|
||||||
|
- name: Login to Docker Hub
|
||||||
|
uses: docker/login-action@184bdaa0721073962dff0199f1fb9940f07167d1 # v3.5.0
|
||||||
|
with:
|
||||||
|
username: ${{ secrets.DOCKER_USERNAME }}
|
||||||
|
password: ${{ secrets.DOCKER_PASSWORD }}
|
||||||
|
|
||||||
|
- name: Login to github
|
||||||
|
uses: docker/login-action@184bdaa0721073962dff0199f1fb9940f07167d1 # v3.5.0
|
||||||
|
with:
|
||||||
|
registry: ghcr.io
|
||||||
|
username: ${{ github.actor }}
|
||||||
|
password: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
|
- name: Build image without cache
|
||||||
|
if: github.event_name == 'schedule'
|
||||||
|
env:
|
||||||
|
TAG_ARM: ${{ steps.tags.outputs.TAG_ARM }}
|
||||||
|
run: |
|
||||||
|
docker build -t ${IMAGE_NAME}:${TAG_ARM} .
|
||||||
|
|
||||||
|
- name: Build image with cache
|
||||||
|
if: github.event_name != 'schedule'
|
||||||
|
env:
|
||||||
|
TAG_ARM: ${{ steps.tags.outputs.TAG_ARM }}
|
||||||
|
run: |
|
||||||
|
docker pull ${IMAGE_NAME}:${TAG_ARM} || true
|
||||||
|
docker build --cache-from ${IMAGE_NAME}:${TAG_ARM} -t ${CACHE_IMAGE}:${TAG_ARM} .
|
||||||
|
|
||||||
|
- name: Run build for AI images
|
||||||
|
env:
|
||||||
|
TAG_ARM: ${{ steps.tags.outputs.TAG_ARM }}
|
||||||
|
TAG_PLOT_ARM: ${{ steps.tags.outputs.TAG_PLOT_ARM }}
|
||||||
|
TAG_FREQAI_ARM: ${{ steps.tags.outputs.TAG_FREQAI_ARM }}
|
||||||
|
TAG_FREQAI_RL_ARM: ${{ steps.tags.outputs.TAG_FREQAI_RL_ARM }}
|
||||||
|
run: |
|
||||||
|
docker build --build-arg sourceimage=${CACHE_IMAGE} --build-arg sourcetag=${TAG_ARM} -t ${CACHE_IMAGE}:${TAG_PLOT_ARM} -f docker/Dockerfile.plot .
|
||||||
|
docker build --build-arg sourceimage=${CACHE_IMAGE} --build-arg sourcetag=${TAG_ARM} -t ${CACHE_IMAGE}:${TAG_FREQAI_ARM} -f docker/Dockerfile.freqai .
|
||||||
|
docker build --build-arg sourceimage=${CACHE_IMAGE} --build-arg sourcetag=${TAG_FREQAI_ARM} -t ${CACHE_IMAGE}:${TAG_FREQAI_RL_ARM} -f docker/Dockerfile.freqai_rl .
|
||||||
|
|
||||||
|
|
||||||
|
- name: Run backtest in Docker
|
||||||
|
env:
|
||||||
|
TAG_ARM: ${{ steps.tags.outputs.TAG_ARM }}
|
||||||
|
run: |
|
||||||
|
docker run --rm -v $(pwd)/tests/testdata/config.tests.json:/freqtrade/config.json:ro -v $(pwd)/tests:/tests ${CACHE_IMAGE}:${TAG_ARM} backtesting --datadir /tests/testdata --strategy-path /tests/strategy/strats/ --strategy StrategyTestV3
|
||||||
|
|
||||||
|
- name: Docker images
|
||||||
|
run: |
|
||||||
|
docker images
|
||||||
|
|
||||||
|
- name: Push cache images
|
||||||
|
env:
|
||||||
|
TAG_ARM: ${{ steps.tags.outputs.TAG_ARM }}
|
||||||
|
TAG_PLOT_ARM: ${{ steps.tags.outputs.TAG_PLOT_ARM }}
|
||||||
|
TAG_FREQAI_ARM: ${{ steps.tags.outputs.TAG_FREQAI_ARM }}
|
||||||
|
TAG_FREQAI_RL_ARM: ${{ steps.tags.outputs.TAG_FREQAI_RL_ARM }}
|
||||||
|
run: |
|
||||||
|
docker push ${CACHE_IMAGE}:$TAG_PLOT_ARM
|
||||||
|
docker push ${CACHE_IMAGE}:$TAG_FREQAI_ARM
|
||||||
|
docker push ${CACHE_IMAGE}:$TAG_FREQAI_RL_ARM
|
||||||
|
docker push ${CACHE_IMAGE}:$TAG_ARM
|
||||||
|
|
||||||
|
- name: Create manifests
|
||||||
|
env:
|
||||||
|
TAG_ARM: ${{ steps.tags.outputs.TAG_ARM }}
|
||||||
|
TAG: ${{ steps.tags.outputs.TAG }}
|
||||||
|
TAG_PI: ${{ steps.tags.outputs.TAG_PI }}
|
||||||
|
run: |
|
||||||
|
docker buildx imagetools create \
|
||||||
|
--tag ${IMAGE_NAME}:${TAG} \
|
||||||
|
--tag ${GHCR_IMAGE_NAME}:${TAG} \
|
||||||
|
${CACHE_IMAGE}:${TAG} ${CACHE_IMAGE}:${TAG_ARM} ${IMAGE_NAME}:${TAG_PI}
|
||||||
|
|
||||||
|
- name: Create multiarch image - Plot
|
||||||
|
env:
|
||||||
|
TAG_PLOT: ${{ steps.tags.outputs.TAG_PLOT }}
|
||||||
|
TAG_PLOT_ARM: ${{ steps.tags.outputs.TAG_PLOT_ARM }}
|
||||||
|
run: |
|
||||||
|
docker buildx imagetools create \
|
||||||
|
--tag ${IMAGE_NAME}:${TAG_PLOT} \
|
||||||
|
--tag ${GHCR_IMAGE_NAME}:${TAG_PLOT} \
|
||||||
|
${CACHE_IMAGE}:${TAG_PLOT} ${CACHE_IMAGE}:${TAG_PLOT_ARM}
|
||||||
|
|
||||||
|
- name: Create multiarch image - FreqAI
|
||||||
|
env:
|
||||||
|
TAG_FREQAI: ${{ steps.tags.outputs.TAG_FREQAI }}
|
||||||
|
TAG_FREQAI_ARM: ${{ steps.tags.outputs.TAG_FREQAI_ARM }}
|
||||||
|
run: |
|
||||||
|
docker buildx imagetools create \
|
||||||
|
--tag ${IMAGE_NAME}:${TAG_FREQAI} \
|
||||||
|
--tag ${GHCR_IMAGE_NAME}:${TAG_FREQAI} \
|
||||||
|
${CACHE_IMAGE}:${TAG_FREQAI} ${CACHE_IMAGE}:${TAG_FREQAI_ARM}
|
||||||
|
|
||||||
|
- name: Create multiarch image - FreqAI RL
|
||||||
|
env:
|
||||||
|
TAG_FREQAI_RL: ${{ steps.tags.outputs.TAG_FREQAI_RL }}
|
||||||
|
TAG_FREQAI_RL_ARM: ${{ steps.tags.outputs.TAG_FREQAI_RL_ARM }}
|
||||||
|
TAG_FREQAI_TORCH: ${{ steps.tags.outputs.TAG_FREQAI_TORCH }}
|
||||||
|
run: |
|
||||||
|
# Create special Torch tag - which is identical to the RL tag.
|
||||||
|
docker buildx imagetools create \
|
||||||
|
--tag ${IMAGE_NAME}:${TAG_FREQAI_RL} \
|
||||||
|
--tag ${GHCR_IMAGE_NAME}:${TAG_FREQAI_RL} \
|
||||||
|
--tag ${IMAGE_NAME}:${TAG_FREQAI_TORCH} \
|
||||||
|
--tag ${GHCR_IMAGE_NAME}:${TAG_FREQAI_TORCH} \
|
||||||
|
${CACHE_IMAGE}:${TAG_FREQAI_RL} ${CACHE_IMAGE}:${TAG_FREQAI_RL_ARM}
|
||||||
|
|
||||||
|
- name: Tag latest
|
||||||
|
if: env.TAG == 'develop'
|
||||||
|
env:
|
||||||
|
TAG: ${{ steps.tags.outputs.TAG }}
|
||||||
|
run: |
|
||||||
|
# Tag image as latest
|
||||||
|
docker buildx imagetools create \
|
||||||
|
--tag ${GHCR_IMAGE_NAME}:${TAG} \
|
||||||
|
--tag ${GHCR_IMAGE_NAME}:latest \
|
||||||
|
${IMAGE_NAME}:${TAG}
|
||||||
|
|
||||||
|
- name: Docker images
|
||||||
|
run: |
|
||||||
|
docker images
|
||||||
|
|
||||||
|
- name: Image cleanup
|
||||||
|
run: |
|
||||||
|
docker image prune -a --force --filter "until=24h"
|
||||||
|
|
||||||
|
- name: Discord notification
|
||||||
|
uses: rjstone/discord-webhook-notify@c2597273488aeda841dd1e891321952b51f7996f #v2.2.1
|
||||||
|
if: always() && ( github.event_name != 'pull_request' || github.event.pull_request.head.repo.fork == false) && (github.event_name != 'schedule')
|
||||||
|
with:
|
||||||
|
severity: info
|
||||||
|
details: Deploy Succeeded!
|
||||||
|
webhookUrl: ${{ secrets.DISCORD_WEBHOOK }}
|
||||||
@@ -11,7 +11,7 @@ jobs:
|
|||||||
dockerHubDescription:
|
dockerHubDescription:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v5
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,46 @@
|
|||||||
|
name: Cleanup Packages
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_call:
|
||||||
|
inputs:
|
||||||
|
package_name:
|
||||||
|
description: 'Package name to clean up'
|
||||||
|
required: false
|
||||||
|
default: 'freqtrade'
|
||||||
|
type: string
|
||||||
|
|
||||||
|
workflow_dispatch:
|
||||||
|
inputs:
|
||||||
|
package_name:
|
||||||
|
description: 'Package name to clean up'
|
||||||
|
required: false
|
||||||
|
default: 'freqtrade'
|
||||||
|
type: choice
|
||||||
|
options:
|
||||||
|
- 'freqtrade'
|
||||||
|
- 'freqtrade-devcontainer'
|
||||||
|
delete-untagged:
|
||||||
|
description: 'Whether to delete only untagged images'
|
||||||
|
required: false
|
||||||
|
default: true
|
||||||
|
type: boolean
|
||||||
|
|
||||||
|
env:
|
||||||
|
PACKAGE_NAME: "freqtrade"
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
deploy-docker:
|
||||||
|
name: "Delete Packages"
|
||||||
|
runs-on: ubuntu-24.04
|
||||||
|
if: github.repository == 'freqtrade/freqtrade'
|
||||||
|
permissions:
|
||||||
|
packages: write
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: "Delete untagged Package Versions"
|
||||||
|
uses: actions/delete-package-versions@v5
|
||||||
|
with:
|
||||||
|
package-name: ${{ inputs.package_name || env.PACKAGE_NAME }}
|
||||||
|
package-type: 'container'
|
||||||
|
min-versions-to-keep: 10
|
||||||
|
delete-only-untagged-versions: ${{ inputs.delete-untagged || 'true' }}
|
||||||
@@ -13,11 +13,11 @@ jobs:
|
|||||||
auto-update:
|
auto-update:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v5
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
|
|
||||||
- uses: actions/setup-python@v5
|
- uses: actions/setup-python@v6
|
||||||
with:
|
with:
|
||||||
python-version: "3.12"
|
python-version: "3.12"
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,29 @@
|
|||||||
|
name: GitHub Actions Security Analysis with zizmor 🌈
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- develop
|
||||||
|
- stable
|
||||||
|
pull_request:
|
||||||
|
branches:
|
||||||
|
- develop
|
||||||
|
- stable
|
||||||
|
|
||||||
|
permissions: {}
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
zizmor:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
permissions:
|
||||||
|
security-events: write
|
||||||
|
# contents: read # only needed for private repos
|
||||||
|
# actions: read # only needed for private repos
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@ff7abcd0c3c05ccf6adc123a8cd1fd4fb30fb493 # v4.2.2
|
||||||
|
with:
|
||||||
|
persist-credentials: false
|
||||||
|
|
||||||
|
- name: Run zizmor 🌈
|
||||||
|
uses: zizmorcore/zizmor-action@e673c3917a1aef3c65c972347ed84ccd013ecda4 # v0.2.0
|
||||||
+11
-10
@@ -14,24 +14,25 @@ repos:
|
|||||||
additional_dependencies: ["python-rapidjson", "jsonschema"]
|
additional_dependencies: ["python-rapidjson", "jsonschema"]
|
||||||
|
|
||||||
- repo: https://github.com/pycqa/flake8
|
- repo: https://github.com/pycqa/flake8
|
||||||
rev: "7.2.0"
|
rev: "7.3.0"
|
||||||
hooks:
|
hooks:
|
||||||
- id: flake8
|
- id: flake8
|
||||||
additional_dependencies: [Flake8-pyproject]
|
additional_dependencies: [Flake8-pyproject]
|
||||||
# stages: [push]
|
# stages: [push]
|
||||||
|
|
||||||
- repo: https://github.com/pre-commit/mirrors-mypy
|
- repo: https://github.com/pre-commit/mirrors-mypy
|
||||||
rev: "v1.15.0"
|
rev: "v1.18.2"
|
||||||
hooks:
|
hooks:
|
||||||
- id: mypy
|
- id: mypy
|
||||||
exclude: build_helpers
|
exclude: build_helpers
|
||||||
additional_dependencies:
|
additional_dependencies:
|
||||||
- types-cachetools==5.5.0.20240820
|
- types-cachetools==6.2.0.20250827
|
||||||
- types-filelock==3.2.7
|
- types-filelock==3.2.7
|
||||||
- types-requests==2.32.0.20250328
|
- types-requests==2.32.4.20250913
|
||||||
- types-tabulate==0.9.0.20241207
|
- types-tabulate==0.9.0.20241207
|
||||||
- types-python-dateutil==2.9.0.20241206
|
- types-python-dateutil==2.9.0.20250822
|
||||||
- SQLAlchemy==2.0.40
|
- scipy-stubs==1.16.2.0
|
||||||
|
- SQLAlchemy==2.0.43
|
||||||
# stages: [push]
|
# stages: [push]
|
||||||
|
|
||||||
- repo: https://github.com/pycqa/isort
|
- repo: https://github.com/pycqa/isort
|
||||||
@@ -43,13 +44,13 @@ repos:
|
|||||||
|
|
||||||
- repo: https://github.com/charliermarsh/ruff-pre-commit
|
- repo: https://github.com/charliermarsh/ruff-pre-commit
|
||||||
# Ruff version.
|
# Ruff version.
|
||||||
rev: 'v0.11.7'
|
rev: 'v0.13.1'
|
||||||
hooks:
|
hooks:
|
||||||
- id: ruff
|
- id: ruff
|
||||||
- id: ruff-format
|
- id: ruff-format
|
||||||
|
|
||||||
- repo: https://github.com/pre-commit/pre-commit-hooks
|
- repo: https://github.com/pre-commit/pre-commit-hooks
|
||||||
rev: v5.0.0
|
rev: v6.0.0
|
||||||
hooks:
|
hooks:
|
||||||
- id: end-of-file-fixer
|
- id: end-of-file-fixer
|
||||||
exclude: |
|
exclude: |
|
||||||
@@ -69,7 +70,7 @@ repos:
|
|||||||
)$
|
)$
|
||||||
|
|
||||||
- repo: https://github.com/stefmolin/exif-stripper
|
- repo: https://github.com/stefmolin/exif-stripper
|
||||||
rev: 0.6.2
|
rev: 1.1.0
|
||||||
hooks:
|
hooks:
|
||||||
- id: strip-exif
|
- id: strip-exif
|
||||||
|
|
||||||
@@ -82,6 +83,6 @@ repos:
|
|||||||
|
|
||||||
# Ensure github actions remain safe
|
# Ensure github actions remain safe
|
||||||
- repo: https://github.com/woodruffw/zizmor-pre-commit
|
- repo: https://github.com/woodruffw/zizmor-pre-commit
|
||||||
rev: v1.6.0
|
rev: v1.13.0
|
||||||
hooks:
|
hooks:
|
||||||
- id: zizmor
|
- id: zizmor
|
||||||
|
|||||||
+31
-29
@@ -9,8 +9,10 @@ Issues labeled [good first issue](https://github.com/freqtrade/freqtrade/labels/
|
|||||||
Few pointers for contributions:
|
Few pointers for contributions:
|
||||||
|
|
||||||
- Create your PR against the `develop` branch, not `stable`.
|
- Create your PR against the `develop` branch, not `stable`.
|
||||||
- New features need to contain unit tests, must conform to PEP8 (max-line-length = 100) and should be documented with the introduction PR.
|
- Stick to english in both commit messages, PR descriptions and code comments and variable names.
|
||||||
- PR's can be declared as `[WIP]` - which signify Work in Progress Pull Requests (which are not finished).
|
- New features need to contain unit tests, must pass CI (run pre-commit and pytest to get an early feedback) and should be documented with the introduction PR.
|
||||||
|
- PR's can be declared as draft - signaling Work in Progress for Pull Requests (which are not finished). We'll still aim to provide feedback on draft PR's in a timely manner.
|
||||||
|
- If you're using AI for your PR, please both mention it in the PR description and do a thorough review of the generated code. The final responsibility for the code with the PR author, not with the AI.
|
||||||
|
|
||||||
If you are unsure, discuss the feature on our [discord server](https://discord.gg/p7nuUNVfP7) or in a [issue](https://github.com/freqtrade/freqtrade/issues) before a Pull Request.
|
If you are unsure, discuss the feature on our [discord server](https://discord.gg/p7nuUNVfP7) or in a [issue](https://github.com/freqtrade/freqtrade/issues) before a Pull Request.
|
||||||
|
|
||||||
@@ -43,43 +45,43 @@ pytest tests/test_<file_name>.py
|
|||||||
pytest tests/test_<file_name>.py::test_<method_name>
|
pytest tests/test_<file_name>.py::test_<method_name>
|
||||||
```
|
```
|
||||||
|
|
||||||
### 2. Test if your code is PEP8 compliant
|
### 2. Test if your code corresponds to our style guide
|
||||||
|
|
||||||
#### Run Ruff
|
We receive a lot of code that fails preliminary CI checks.
|
||||||
|
To help with that, we encourage contributors to install the git pre-commit hook that will let you know immediately when you try to commit code that fails these checks.
|
||||||
|
|
||||||
|
You can manually run pre-commit with `pre-commit run -a` - or install the git hook with `pre-commit install` to have it run automatically on each commit.
|
||||||
|
|
||||||
|
Running `pre-commit run -a` will run all checks, including `ruff`, `mypy` and `codespell` (among others).
|
||||||
|
|
||||||
|
#### Additional styles applied
|
||||||
|
|
||||||
|
- Have docstrings on all public methods
|
||||||
|
- Use double-quotes for docstrings
|
||||||
|
- Multiline docstrings should be indented to the level of the first quote
|
||||||
|
- Doc-strings should follow the reST format (`:param xxx: ...`, `:return: ...`, `:raises KeyError: ...`)
|
||||||
|
|
||||||
|
#### Manually run the individual checks
|
||||||
|
|
||||||
|
The following sections describe how to run the individual checks that are running as part of the pre-commit hook.
|
||||||
|
|
||||||
|
##### Run ruff
|
||||||
|
|
||||||
|
Check your code with ruff to ensure that it follows the style guide.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
ruff check .
|
ruff check .
|
||||||
|
ruff format .
|
||||||
```
|
```
|
||||||
|
|
||||||
We receive a lot of code that fails the `ruff` checks.
|
##### Run mypy
|
||||||
To help with that, we encourage you to install the git pre-commit
|
|
||||||
hook that will warn you when you try to commit code that fails these checks.
|
|
||||||
|
|
||||||
you can manually run pre-commit with `pre-commit run -a`.
|
Check your code with mypy to ensure that it follows the type-hinting rules.
|
||||||
|
|
||||||
##### Additional styles applied
|
|
||||||
|
|
||||||
* Have docstrings on all public methods
|
|
||||||
* Use double-quotes for docstrings
|
|
||||||
* Multiline docstrings should be indented to the level of the first quote
|
|
||||||
* Doc-strings should follow the reST format (`:param xxx: ...`, `:return: ...`, `:raises KeyError: ... `)
|
|
||||||
|
|
||||||
### 3. Test if all type-hints are correct
|
|
||||||
|
|
||||||
#### Run mypy
|
|
||||||
|
|
||||||
``` bash
|
``` bash
|
||||||
mypy freqtrade
|
mypy freqtrade
|
||||||
```
|
```
|
||||||
|
|
||||||
### 4. Ensure formatting is correct
|
|
||||||
|
|
||||||
#### Run ruff
|
|
||||||
|
|
||||||
``` bash
|
|
||||||
ruff format .
|
|
||||||
```
|
|
||||||
|
|
||||||
## (Core)-Committer Guide
|
## (Core)-Committer Guide
|
||||||
|
|
||||||
### Process: Pull Requests
|
### Process: Pull Requests
|
||||||
@@ -118,7 +120,7 @@ Exceptions:
|
|||||||
- Ensure cross-platform compatibility for every change that's accepted. Windows, Mac & Linux.
|
- Ensure cross-platform compatibility for every change that's accepted. Windows, Mac & Linux.
|
||||||
- Ensure no malicious code is introduced into the core code.
|
- Ensure no malicious code is introduced into the core code.
|
||||||
- Create issues for any major changes and enhancements that you wish to make. Discuss things transparently and get community feedback.
|
- Create issues for any major changes and enhancements that you wish to make. Discuss things transparently and get community feedback.
|
||||||
- Keep feature versions as small as possible, preferably one new feature per version.
|
- Keep feature PR's as small as possible, preferably one new feature per PR.
|
||||||
- Be welcoming to newcomers and encourage diverse new contributors from all backgrounds. See the Python Community Code of Conduct (https://www.python.org/psf/codeofconduct/).
|
- Be welcoming to newcomers and encourage diverse new contributors from all backgrounds. See the Python Community Code of Conduct (https://www.python.org/psf/codeofconduct/).
|
||||||
|
|
||||||
### Becoming a Committer
|
### Becoming a Committer
|
||||||
@@ -130,6 +132,6 @@ Contributors may be given commit privileges. Preference will be given to those w
|
|||||||
1. Access to resources for cross-platform development and testing.
|
1. Access to resources for cross-platform development and testing.
|
||||||
1. Time to devote to the project regularly.
|
1. Time to devote to the project regularly.
|
||||||
|
|
||||||
Being a Committer does not grant write permission on `develop` or `stable` for security reasons (Users trust Freqtrade with their Exchange API keys).
|
Being a Committer does not automatically grant write permission on `develop` or `stable` for security reasons (Users trust Freqtrade with their Exchange API keys).
|
||||||
|
|
||||||
After being Committer for some time, a Committer may be named Core Committer and given full repository access.
|
After being Committer for some time, a Committer may be named Core Committer and given full repository access.
|
||||||
|
|||||||
+10
-15
@@ -1,10 +1,10 @@
|
|||||||
FROM python:3.12.10-slim-bookworm as base
|
FROM python:3.13.7-slim-bookworm AS base
|
||||||
|
|
||||||
# Setup env
|
# Setup env
|
||||||
ENV LANG C.UTF-8
|
ENV LANG=C.UTF-8
|
||||||
ENV LC_ALL C.UTF-8
|
ENV LC_ALL=C.UTF-8
|
||||||
ENV PYTHONDONTWRITEBYTECODE 1
|
ENV PYTHONDONTWRITEBYTECODE=1
|
||||||
ENV PYTHONFAULTHANDLER 1
|
ENV PYTHONFAULTHANDLER=1
|
||||||
ENV PATH=/home/ftuser/.local/bin:$PATH
|
ENV PATH=/home/ftuser/.local/bin:$PATH
|
||||||
ENV FT_APP_ENV="docker"
|
ENV FT_APP_ENV="docker"
|
||||||
|
|
||||||
@@ -21,27 +21,22 @@ RUN mkdir /freqtrade \
|
|||||||
WORKDIR /freqtrade
|
WORKDIR /freqtrade
|
||||||
|
|
||||||
# Install dependencies
|
# Install dependencies
|
||||||
FROM base as python-deps
|
FROM base AS python-deps
|
||||||
RUN apt-get update \
|
RUN apt-get update \
|
||||||
&& apt-get -y install build-essential libssl-dev git libffi-dev libgfortran5 pkg-config cmake gcc \
|
&& apt-get -y install build-essential libssl-dev git libffi-dev libgfortran5 pkg-config cmake gcc \
|
||||||
&& apt-get clean \
|
&& apt-get clean \
|
||||||
&& pip install --upgrade pip wheel
|
&& pip install --upgrade pip wheel
|
||||||
|
|
||||||
# Install TA-lib
|
|
||||||
COPY build_helpers/* /tmp/
|
|
||||||
RUN cd /tmp && /tmp/install_ta-lib.sh && rm -r /tmp/*ta-lib*
|
|
||||||
ENV LD_LIBRARY_PATH /usr/local/lib
|
|
||||||
|
|
||||||
# Install dependencies
|
# Install dependencies
|
||||||
COPY --chown=ftuser:ftuser requirements.txt requirements-hyperopt.txt /freqtrade/
|
COPY --chown=ftuser:ftuser requirements.txt requirements-hyperopt.txt /freqtrade/
|
||||||
USER ftuser
|
USER ftuser
|
||||||
RUN pip install --user --no-cache-dir "numpy<2.0" \
|
RUN pip install --user --no-cache-dir "numpy<3.0" \
|
||||||
&& pip install --user --no-cache-dir -r requirements-hyperopt.txt
|
&& pip install --user --no-cache-dir -r requirements-hyperopt.txt
|
||||||
|
|
||||||
# Copy dependencies to runtime-image
|
# Copy dependencies to runtime-image
|
||||||
FROM base as runtime-image
|
FROM base AS runtime-image
|
||||||
COPY --from=python-deps /usr/local/lib /usr/local/lib
|
COPY --from=python-deps /usr/local/lib /usr/local/lib
|
||||||
ENV LD_LIBRARY_PATH /usr/local/lib
|
ENV LD_LIBRARY_PATH=/usr/local/lib
|
||||||
|
|
||||||
COPY --from=python-deps --chown=ftuser:ftuser /home/ftuser/.local /home/ftuser/.local
|
COPY --from=python-deps --chown=ftuser:ftuser /home/ftuser/.local /home/ftuser/.local
|
||||||
|
|
||||||
@@ -49,7 +44,7 @@ USER ftuser
|
|||||||
# Install and execute
|
# Install and execute
|
||||||
COPY --chown=ftuser:ftuser . /freqtrade/
|
COPY --chown=ftuser:ftuser . /freqtrade/
|
||||||
|
|
||||||
RUN pip install -e . --user --no-cache-dir --no-build-isolation \
|
RUN pip install -e . --user --no-cache-dir \
|
||||||
&& mkdir /freqtrade/user_data/ \
|
&& mkdir /freqtrade/user_data/ \
|
||||||
&& freqtrade install-ui
|
&& freqtrade install-ui
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,6 @@
|
|||||||
[](https://doi.org/10.21105/joss.04864)
|
[](https://doi.org/10.21105/joss.04864)
|
||||||
[](https://coveralls.io/github/freqtrade/freqtrade?branch=develop)
|
[](https://coveralls.io/github/freqtrade/freqtrade?branch=develop)
|
||||||
[](https://www.freqtrade.io)
|
[](https://www.freqtrade.io)
|
||||||
[](https://codeclimate.com/github/freqtrade/freqtrade/maintainability)
|
|
||||||
|
|
||||||
Freqtrade is a free and open source crypto trading bot written in Python. It is designed to support all major exchanges and be controlled via Telegram or webUI. It contains backtesting, plotting and money management tools as well as strategy optimization by machine learning.
|
Freqtrade is a free and open source crypto trading bot written in Python. It is designed to support all major exchanges and be controlled via Telegram or webUI. It contains backtesting, plotting and money management tools as well as strategy optimization by machine learning.
|
||||||
|
|
||||||
@@ -64,13 +63,12 @@ Please find the complete documentation on the [freqtrade website](https://www.fr
|
|||||||
|
|
||||||
## Features
|
## Features
|
||||||
|
|
||||||
- [x] **Based on Python 3.10+**: For botting on any operating system - Windows, macOS and Linux.
|
- [x] **Based on Python 3.11+**: For botting on any operating system - Windows, macOS and Linux.
|
||||||
- [x] **Persistence**: Persistence is achieved through sqlite.
|
- [x] **Persistence**: Persistence is achieved through sqlite.
|
||||||
- [x] **Dry-run**: Run the bot without paying money.
|
- [x] **Dry-run**: Run the bot without paying money.
|
||||||
- [x] **Backtesting**: Run a simulation of your buy/sell strategy.
|
- [x] **Backtesting**: Run a simulation of your buy/sell strategy.
|
||||||
- [x] **Strategy Optimization by machine learning**: Use machine learning to optimize your buy/sell strategy parameters with real exchange data.
|
- [x] **Strategy Optimization by machine learning**: Use machine learning to optimize your buy/sell strategy parameters with real exchange data.
|
||||||
- [X] **Adaptive prediction modeling**: Build a smart strategy with FreqAI that self-trains to the market via adaptive machine learning methods. [Learn more](https://www.freqtrade.io/en/stable/freqai/)
|
- [X] **Adaptive prediction modeling**: Build a smart strategy with FreqAI that self-trains to the market via adaptive machine learning methods. [Learn more](https://www.freqtrade.io/en/stable/freqai/)
|
||||||
- [x] **Edge position sizing** Calculate your win rate, risk reward ratio, the best stoploss and adjust your position size before taking a position for each specific market. [Learn more](https://www.freqtrade.io/en/stable/edge/).
|
|
||||||
- [x] **Whitelist crypto-currencies**: Select which crypto-currency you want to trade or use dynamic whitelists.
|
- [x] **Whitelist crypto-currencies**: Select which crypto-currency you want to trade or use dynamic whitelists.
|
||||||
- [x] **Blacklist crypto-currencies**: Select which crypto-currency you want to avoid.
|
- [x] **Blacklist crypto-currencies**: Select which crypto-currency you want to avoid.
|
||||||
- [x] **Builtin WebUI**: Builtin web UI to manage your bot.
|
- [x] **Builtin WebUI**: Builtin web UI to manage your bot.
|
||||||
@@ -112,7 +110,6 @@ positional arguments:
|
|||||||
backtesting-show Show past Backtest results
|
backtesting-show Show past Backtest results
|
||||||
backtesting-analysis
|
backtesting-analysis
|
||||||
Backtest Analysis module.
|
Backtest Analysis module.
|
||||||
edge Edge module.
|
|
||||||
hyperopt Hyperopt module.
|
hyperopt Hyperopt module.
|
||||||
hyperopt-list List Hyperopt results
|
hyperopt-list List Hyperopt results
|
||||||
hyperopt-show Show details of Hyperopt results
|
hyperopt-show Show details of Hyperopt results
|
||||||
@@ -148,6 +145,8 @@ Telegram is not mandatory. However, this is a great way to control your bot. Mor
|
|||||||
- `/stopentry`: Stop entering new trades.
|
- `/stopentry`: Stop entering new trades.
|
||||||
- `/status <trade_id>|[table]`: Lists all or specific open trades.
|
- `/status <trade_id>|[table]`: Lists all or specific open trades.
|
||||||
- `/profit [<n>]`: Lists cumulative profit from all finished trades, over the last n days.
|
- `/profit [<n>]`: Lists cumulative profit from all finished trades, over the last n days.
|
||||||
|
- `/profit_long [<n>]`: Lists cumulative profit from all finished long trades, over the last n days.
|
||||||
|
- `/profit_short [<n>]`: Lists cumulative profit from all finished short trades, over the last n days.
|
||||||
- `/forceexit <trade_id>|all`: Instantly exits the given trade (Ignoring `minimum_roi`).
|
- `/forceexit <trade_id>|all`: Instantly exits the given trade (Ignoring `minimum_roi`).
|
||||||
- `/fx <trade_id>|all`: Alias to `/forceexit`
|
- `/fx <trade_id>|all`: Alias to `/forceexit`
|
||||||
- `/performance`: Show performance of each finished trade grouped by pair
|
- `/performance`: Show performance of each finished trade grouped by pair
|
||||||
@@ -156,6 +155,7 @@ Telegram is not mandatory. However, this is a great way to control your bot. Mor
|
|||||||
- `/help`: Show help message.
|
- `/help`: Show help message.
|
||||||
- `/version`: Show version.
|
- `/version`: Show version.
|
||||||
|
|
||||||
|
|
||||||
## Development branches
|
## Development branches
|
||||||
|
|
||||||
The project is currently setup in two main branches:
|
The project is currently setup in two main branches:
|
||||||
@@ -221,7 +221,7 @@ To run this bot we recommend you a cloud instance with a minimum of:
|
|||||||
|
|
||||||
### Software requirements
|
### Software requirements
|
||||||
|
|
||||||
- [Python >= 3.10](http://docs.python-guide.org/en/latest/starting/installation/)
|
- [Python >= 3.11](http://docs.python-guide.org/en/latest/starting/installation/)
|
||||||
- [pip](https://pip.pypa.io/en/stable/installing/)
|
- [pip](https://pip.pypa.io/en/stable/installing/)
|
||||||
- [git](https://git-scm.com/book/en/v2/Getting-Started-Installing-Git)
|
- [git](https://git-scm.com/book/en/v2/Getting-Started-Installing-Git)
|
||||||
- [TA-Lib](https://ta-lib.github.io/ta-lib-python/)
|
- [TA-Lib](https://ta-lib.github.io/ta-lib-python/)
|
||||||
|
|||||||
@@ -1,35 +0,0 @@
|
|||||||
if [ -z "$1" ]; then
|
|
||||||
INSTALL_LOC=/usr/local
|
|
||||||
else
|
|
||||||
INSTALL_LOC=${1}
|
|
||||||
fi
|
|
||||||
echo "Installing to ${INSTALL_LOC}"
|
|
||||||
if [ -n "$2" ] || [ ! -f "${INSTALL_LOC}/lib/libta_lib.a" ]; then
|
|
||||||
tar zxvf ta-lib-0.4.0-src.tar.gz
|
|
||||||
cd ta-lib \
|
|
||||||
&& sed -i.bak "s|0.00000001|0.000000000000000001 |g" src/ta_func/ta_utility.h \
|
|
||||||
&& echo "Downloading gcc config.guess and config.sub" \
|
|
||||||
&& curl -s 'https://raw.githubusercontent.com/gcc-mirror/gcc/master/config.guess' -o config.guess \
|
|
||||||
&& curl -s 'https://raw.githubusercontent.com/gcc-mirror/gcc/master/config.sub' -o config.sub \
|
|
||||||
&& ./configure --prefix=${INSTALL_LOC}/ \
|
|
||||||
&& make
|
|
||||||
if [ $? -ne 0 ]; then
|
|
||||||
echo "Failed building ta-lib."
|
|
||||||
cd .. && rm -rf ./ta-lib/
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
if [ -z "$2" ]; then
|
|
||||||
which sudo && sudo make install || make install
|
|
||||||
if [ -x "$(command -v apt-get)" ]; then
|
|
||||||
echo "Updating library path using ldconfig"
|
|
||||||
sudo ldconfig
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
# Don't install with sudo
|
|
||||||
make install
|
|
||||||
fi
|
|
||||||
|
|
||||||
cd .. && rm -rf ./ta-lib/
|
|
||||||
else
|
|
||||||
echo "TA-lib already installed, skipping installation"
|
|
||||||
fi
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
# vendored Wheels compiled via https://github.com/xmatthias/ta-lib-python/tree/ta_bundled_040
|
|
||||||
|
|
||||||
python -m pip install --upgrade pip
|
|
||||||
python -c "import sys; print(f'{sys.version_info.major}.{sys.version_info.minor}')"
|
|
||||||
|
|
||||||
pip install -U wheel "numpy<2"
|
|
||||||
pip install --only-binary ta-lib --find-links=build_helpers\ ta-lib
|
|
||||||
|
|
||||||
pip install -r requirements-dev.txt
|
|
||||||
pip install -e .
|
|
||||||
@@ -16,10 +16,12 @@ with require_dev.open("r") as rfile:
|
|||||||
with require.open("r") as rfile:
|
with require.open("r") as rfile:
|
||||||
requirements.extend(rfile.readlines())
|
requirements.extend(rfile.readlines())
|
||||||
|
|
||||||
# Extract types only
|
# Extract relevant types only
|
||||||
type_reqs = [
|
supported = ("types-", "SQLAlchemy", "scipy-stubs")
|
||||||
r.strip("\n") for r in requirements if r.startswith("types-") or r.startswith("SQLAlchemy")
|
|
||||||
]
|
# Find relevant dependencies
|
||||||
|
# Only keep the first part of the line up to the first space
|
||||||
|
type_reqs = [r.strip("\n").split()[0] for r in requirements if r.startswith(supported)]
|
||||||
|
|
||||||
with pre_commit_file.open("r") as file:
|
with pre_commit_file.open("r") as file:
|
||||||
f = yaml.load(file, Loader=yaml.SafeLoader)
|
f = yaml.load(file, Loader=yaml.SafeLoader)
|
||||||
|
|||||||
@@ -1,119 +0,0 @@
|
|||||||
#!/bin/sh
|
|
||||||
|
|
||||||
# Use BuildKit, otherwise building on ARM fails
|
|
||||||
export DOCKER_BUILDKIT=1
|
|
||||||
|
|
||||||
IMAGE_NAME=freqtradeorg/freqtrade
|
|
||||||
CACHE_IMAGE=freqtradeorg/freqtrade_cache
|
|
||||||
GHCR_IMAGE_NAME=ghcr.io/freqtrade/freqtrade
|
|
||||||
|
|
||||||
# Replace / with _ to create a valid tag
|
|
||||||
TAG=$(echo "${BRANCH_NAME}" | sed -e "s/\//_/g")
|
|
||||||
TAG_PLOT=${TAG}_plot
|
|
||||||
TAG_FREQAI=${TAG}_freqai
|
|
||||||
TAG_FREQAI_RL=${TAG_FREQAI}rl
|
|
||||||
TAG_FREQAI_TORCH=${TAG_FREQAI}torch
|
|
||||||
TAG_PI="${TAG}_pi"
|
|
||||||
|
|
||||||
TAG_ARM=${TAG}_arm
|
|
||||||
TAG_PLOT_ARM=${TAG_PLOT}_arm
|
|
||||||
TAG_FREQAI_ARM=${TAG_FREQAI}_arm
|
|
||||||
TAG_FREQAI_RL_ARM=${TAG_FREQAI_RL}_arm
|
|
||||||
|
|
||||||
echo "Running for ${TAG}"
|
|
||||||
|
|
||||||
# Add commit and commit_message to docker container
|
|
||||||
echo "${GITHUB_SHA}" > freqtrade_commit
|
|
||||||
|
|
||||||
if [ "${GITHUB_EVENT_NAME}" = "schedule" ]; then
|
|
||||||
echo "event ${GITHUB_EVENT_NAME}: full rebuild - skipping cache"
|
|
||||||
# Build regular image
|
|
||||||
docker build -t freqtrade:${TAG_ARM} .
|
|
||||||
|
|
||||||
else
|
|
||||||
echo "event ${GITHUB_EVENT_NAME}: building with cache"
|
|
||||||
# Build regular image
|
|
||||||
docker pull ${IMAGE_NAME}:${TAG_ARM}
|
|
||||||
docker build --cache-from ${IMAGE_NAME}:${TAG_ARM} -t freqtrade:${TAG_ARM} .
|
|
||||||
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ $? -ne 0 ]; then
|
|
||||||
echo "failed building multiarch images"
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
docker build --build-arg sourceimage=freqtrade --build-arg sourcetag=${TAG_ARM} -t freqtrade:${TAG_PLOT_ARM} -f docker/Dockerfile.plot .
|
|
||||||
docker build --build-arg sourceimage=freqtrade --build-arg sourcetag=${TAG_ARM} -t freqtrade:${TAG_FREQAI_ARM} -f docker/Dockerfile.freqai .
|
|
||||||
docker build --build-arg sourceimage=freqtrade --build-arg sourcetag=${TAG_FREQAI_ARM} -t freqtrade:${TAG_FREQAI_RL_ARM} -f docker/Dockerfile.freqai_rl .
|
|
||||||
|
|
||||||
# Tag image for upload and next build step
|
|
||||||
docker tag freqtrade:$TAG_ARM ${CACHE_IMAGE}:$TAG_ARM
|
|
||||||
docker tag freqtrade:$TAG_PLOT_ARM ${CACHE_IMAGE}:$TAG_PLOT_ARM
|
|
||||||
docker tag freqtrade:$TAG_FREQAI_ARM ${CACHE_IMAGE}:$TAG_FREQAI_ARM
|
|
||||||
docker tag freqtrade:$TAG_FREQAI_RL_ARM ${CACHE_IMAGE}:$TAG_FREQAI_RL_ARM
|
|
||||||
|
|
||||||
# Run backtest
|
|
||||||
docker run --rm -v $(pwd)/tests/testdata/config.tests.json:/freqtrade/config.json:ro -v $(pwd)/tests:/tests freqtrade:${TAG_ARM} backtesting --datadir /tests/testdata --strategy-path /tests/strategy/strats/ --strategy StrategyTestV3
|
|
||||||
|
|
||||||
if [ $? -ne 0 ]; then
|
|
||||||
echo "failed running backtest"
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
docker images
|
|
||||||
|
|
||||||
docker push ${CACHE_IMAGE}:$TAG_PLOT_ARM
|
|
||||||
docker push ${CACHE_IMAGE}:$TAG_FREQAI_ARM
|
|
||||||
docker push ${CACHE_IMAGE}:$TAG_FREQAI_RL_ARM
|
|
||||||
docker push ${CACHE_IMAGE}:$TAG_ARM
|
|
||||||
|
|
||||||
# Create multi-arch image
|
|
||||||
# Make sure that all images contained here are pushed to github first.
|
|
||||||
# Otherwise installation might fail.
|
|
||||||
echo "create manifests"
|
|
||||||
|
|
||||||
docker manifest create ${IMAGE_NAME}:${TAG} ${CACHE_IMAGE}:${TAG} ${CACHE_IMAGE}:${TAG_ARM} ${IMAGE_NAME}:${TAG_PI}
|
|
||||||
docker manifest push -p ${IMAGE_NAME}:${TAG}
|
|
||||||
|
|
||||||
docker manifest create ${IMAGE_NAME}:${TAG_PLOT} ${CACHE_IMAGE}:${TAG_PLOT} ${CACHE_IMAGE}:${TAG_PLOT_ARM}
|
|
||||||
docker manifest push -p ${IMAGE_NAME}:${TAG_PLOT}
|
|
||||||
|
|
||||||
docker manifest create ${IMAGE_NAME}:${TAG_FREQAI} ${CACHE_IMAGE}:${TAG_FREQAI} ${CACHE_IMAGE}:${TAG_FREQAI_ARM}
|
|
||||||
docker manifest push -p ${IMAGE_NAME}:${TAG_FREQAI}
|
|
||||||
|
|
||||||
docker manifest create ${IMAGE_NAME}:${TAG_FREQAI_RL} ${CACHE_IMAGE}:${TAG_FREQAI_RL} ${CACHE_IMAGE}:${TAG_FREQAI_RL_ARM}
|
|
||||||
docker manifest push -p ${IMAGE_NAME}:${TAG_FREQAI_RL}
|
|
||||||
|
|
||||||
# Create special Torch tag - which is identical to the RL tag.
|
|
||||||
docker manifest create ${IMAGE_NAME}:${TAG_FREQAI_TORCH} ${CACHE_IMAGE}:${TAG_FREQAI_RL} ${CACHE_IMAGE}:${TAG_FREQAI_RL_ARM}
|
|
||||||
docker manifest push -p ${IMAGE_NAME}:${TAG_FREQAI_TORCH}
|
|
||||||
|
|
||||||
# copy images to ghcr.io
|
|
||||||
|
|
||||||
alias crane="docker run --rm -i -v $(pwd)/.crane:/home/nonroot/.docker/ gcr.io/go-containerregistry/crane"
|
|
||||||
mkdir .crane
|
|
||||||
chmod a+rwx .crane
|
|
||||||
|
|
||||||
echo "${GHCR_TOKEN}" | crane auth login ghcr.io -u "${GHCR_USERNAME}" --password-stdin
|
|
||||||
|
|
||||||
crane copy ${IMAGE_NAME}:${TAG_FREQAI_RL} ${GHCR_IMAGE_NAME}:${TAG_FREQAI_RL}
|
|
||||||
crane copy ${IMAGE_NAME}:${TAG_FREQAI_RL} ${GHCR_IMAGE_NAME}:${TAG_FREQAI_TORCH}
|
|
||||||
crane copy ${IMAGE_NAME}:${TAG_FREQAI} ${GHCR_IMAGE_NAME}:${TAG_FREQAI}
|
|
||||||
crane copy ${IMAGE_NAME}:${TAG_PLOT} ${GHCR_IMAGE_NAME}:${TAG_PLOT}
|
|
||||||
crane copy ${IMAGE_NAME}:${TAG} ${GHCR_IMAGE_NAME}:${TAG}
|
|
||||||
|
|
||||||
# Tag as latest for develop builds
|
|
||||||
if [ "${TAG}" = "develop" ]; then
|
|
||||||
echo 'Tagging image as latest'
|
|
||||||
docker manifest create ${IMAGE_NAME}:latest ${CACHE_IMAGE}:${TAG_ARM} ${IMAGE_NAME}:${TAG_PI} ${CACHE_IMAGE}:${TAG}
|
|
||||||
docker manifest push -p ${IMAGE_NAME}:latest
|
|
||||||
|
|
||||||
crane copy ${IMAGE_NAME}:latest ${GHCR_IMAGE_NAME}:latest
|
|
||||||
fi
|
|
||||||
|
|
||||||
docker images
|
|
||||||
rm -rf .crane
|
|
||||||
|
|
||||||
# Cleanup old images from arm64 node.
|
|
||||||
docker image prune -a --force --filter "until=24h"
|
|
||||||
@@ -1,89 +0,0 @@
|
|||||||
#!/bin/sh
|
|
||||||
|
|
||||||
# The below assumes a correctly setup docker buildx environment
|
|
||||||
|
|
||||||
IMAGE_NAME=freqtradeorg/freqtrade
|
|
||||||
CACHE_IMAGE=freqtradeorg/freqtrade_cache
|
|
||||||
# Replace / with _ to create a valid tag
|
|
||||||
TAG=$(echo "${BRANCH_NAME}" | sed -e "s/\//_/g")
|
|
||||||
TAG_PLOT=${TAG}_plot
|
|
||||||
TAG_FREQAI=${TAG}_freqai
|
|
||||||
TAG_FREQAI_RL=${TAG_FREQAI}rl
|
|
||||||
TAG_PI="${TAG}_pi"
|
|
||||||
|
|
||||||
PI_PLATFORM="linux/arm/v7"
|
|
||||||
echo "Running for ${TAG}"
|
|
||||||
CACHE_TAG=${CACHE_IMAGE}:${TAG_PI}_cache
|
|
||||||
|
|
||||||
# Add commit and commit_message to docker container
|
|
||||||
echo "${GITHUB_SHA}" > freqtrade_commit
|
|
||||||
|
|
||||||
if [ "${GITHUB_EVENT_NAME}" = "schedule" ]; then
|
|
||||||
echo "event ${GITHUB_EVENT_NAME}: full rebuild - skipping cache"
|
|
||||||
# Build regular image
|
|
||||||
docker build -t freqtrade:${TAG} .
|
|
||||||
# Build PI image
|
|
||||||
docker buildx build \
|
|
||||||
--cache-to=type=registry,ref=${CACHE_TAG} \
|
|
||||||
-f docker/Dockerfile.armhf \
|
|
||||||
--platform ${PI_PLATFORM} \
|
|
||||||
-t ${IMAGE_NAME}:${TAG_PI} \
|
|
||||||
--push \
|
|
||||||
--provenance=false \
|
|
||||||
.
|
|
||||||
else
|
|
||||||
echo "event ${GITHUB_EVENT_NAME}: building with cache"
|
|
||||||
# Build regular image
|
|
||||||
docker pull ${IMAGE_NAME}:${TAG}
|
|
||||||
docker build --cache-from ${IMAGE_NAME}:${TAG} -t freqtrade:${TAG} .
|
|
||||||
|
|
||||||
# Pull last build to avoid rebuilding the whole image
|
|
||||||
# docker pull --platform ${PI_PLATFORM} ${IMAGE_NAME}:${TAG}
|
|
||||||
# disable provenance due to https://github.com/docker/buildx/issues/1509
|
|
||||||
docker buildx build \
|
|
||||||
--cache-from=type=registry,ref=${CACHE_TAG} \
|
|
||||||
--cache-to=type=registry,ref=${CACHE_TAG} \
|
|
||||||
-f docker/Dockerfile.armhf \
|
|
||||||
--platform ${PI_PLATFORM} \
|
|
||||||
-t ${IMAGE_NAME}:${TAG_PI} \
|
|
||||||
--push \
|
|
||||||
--provenance=false \
|
|
||||||
.
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ $? -ne 0 ]; then
|
|
||||||
echo "failed building multiarch images"
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
# Tag image for upload and next build step
|
|
||||||
docker tag freqtrade:$TAG ${CACHE_IMAGE}:$TAG
|
|
||||||
|
|
||||||
docker build --build-arg sourceimage=freqtrade --build-arg sourcetag=${TAG} -t freqtrade:${TAG_PLOT} -f docker/Dockerfile.plot .
|
|
||||||
docker build --build-arg sourceimage=freqtrade --build-arg sourcetag=${TAG} -t freqtrade:${TAG_FREQAI} -f docker/Dockerfile.freqai .
|
|
||||||
docker build --build-arg sourceimage=freqtrade --build-arg sourcetag=${TAG_FREQAI} -t freqtrade:${TAG_FREQAI_RL} -f docker/Dockerfile.freqai_rl .
|
|
||||||
|
|
||||||
docker tag freqtrade:$TAG_PLOT ${CACHE_IMAGE}:$TAG_PLOT
|
|
||||||
docker tag freqtrade:$TAG_FREQAI ${CACHE_IMAGE}:$TAG_FREQAI
|
|
||||||
docker tag freqtrade:$TAG_FREQAI_RL ${CACHE_IMAGE}:$TAG_FREQAI_RL
|
|
||||||
|
|
||||||
# Run backtest
|
|
||||||
docker run --rm -v $(pwd)/tests/testdata/config.tests.json:/freqtrade/config.json:ro -v $(pwd)/tests:/tests freqtrade:${TAG} backtesting --datadir /tests/testdata --strategy-path /tests/strategy/strats/ --strategy StrategyTestV3
|
|
||||||
|
|
||||||
if [ $? -ne 0 ]; then
|
|
||||||
echo "failed running backtest"
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
docker images
|
|
||||||
|
|
||||||
docker push ${CACHE_IMAGE}:$TAG
|
|
||||||
docker push ${CACHE_IMAGE}:$TAG_PLOT
|
|
||||||
docker push ${CACHE_IMAGE}:$TAG_FREQAI
|
|
||||||
docker push ${CACHE_IMAGE}:$TAG_FREQAI_RL
|
|
||||||
|
|
||||||
docker images
|
|
||||||
|
|
||||||
if [ $? -ne 0 ]; then
|
|
||||||
echo "failed building image"
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
BIN
Binary file not shown.
+43
-62
@@ -180,6 +180,16 @@
|
|||||||
"description": "Offset for profit exit. \nUsually specified in the strategy and missing in the configuration.",
|
"description": "Offset for profit exit. \nUsually specified in the strategy and missing in the configuration.",
|
||||||
"type": "number"
|
"type": "number"
|
||||||
},
|
},
|
||||||
|
"recursive_strategy_search": {
|
||||||
|
"description": "Enable recursive strategy search.",
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"user_data_dir": {
|
||||||
|
"description": "Path to the user data directory."
|
||||||
|
},
|
||||||
|
"datadir": {
|
||||||
|
"description": "Path to the data directory."
|
||||||
|
},
|
||||||
"fee": {
|
"fee": {
|
||||||
"description": "Trading fee percentage. Can help to simulate slippage in backtesting",
|
"description": "Trading fee percentage. Can help to simulate slippage in backtesting",
|
||||||
"type": "number",
|
"type": "number",
|
||||||
@@ -538,10 +548,6 @@
|
|||||||
"description": "Exchange configuration.",
|
"description": "Exchange configuration.",
|
||||||
"$ref": "#/definitions/exchange"
|
"$ref": "#/definitions/exchange"
|
||||||
},
|
},
|
||||||
"edge": {
|
|
||||||
"description": "Edge configuration.",
|
|
||||||
"$ref": "#/definitions/edge"
|
|
||||||
},
|
|
||||||
"log_config": {
|
"log_config": {
|
||||||
"description": "Logging configuration.",
|
"description": "Logging configuration.",
|
||||||
"$ref": "#/definitions/logging"
|
"$ref": "#/definitions/logging"
|
||||||
@@ -566,6 +572,7 @@
|
|||||||
"pairlists": {
|
"pairlists": {
|
||||||
"description": "Configuration for pairlists.",
|
"description": "Configuration for pairlists.",
|
||||||
"type": "array",
|
"type": "array",
|
||||||
|
"minItems": 1,
|
||||||
"items": {
|
"items": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
@@ -580,6 +587,7 @@
|
|||||||
"RemotePairList",
|
"RemotePairList",
|
||||||
"MarketCapPairList",
|
"MarketCapPairList",
|
||||||
"AgeFilter",
|
"AgeFilter",
|
||||||
|
"DelistFilter",
|
||||||
"FullTradesFilter",
|
"FullTradesFilter",
|
||||||
"OffsetFilter",
|
"OffsetFilter",
|
||||||
"PerformanceFilter",
|
"PerformanceFilter",
|
||||||
@@ -610,11 +618,11 @@
|
|||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
"chat_id": {
|
"chat_id": {
|
||||||
"description": "Telegram chat or group ID",
|
"description": "Telegram chat or group ID. Recommended to be set via environment variable FREQTRADE__TELEGRAM__CHAT_ID",
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
"topic_id": {
|
"topic_id": {
|
||||||
"description": "Telegram topic ID - only applicable for group chats",
|
"description": "Telegram topic ID - only applicable for group chats. Recommended to be set via environment variable FREQTRADE__TELEGRAM__TOPIC_ID",
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
"authorized_users": {
|
"authorized_users": {
|
||||||
@@ -773,9 +781,11 @@
|
|||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
"enabled": {
|
"enabled": {
|
||||||
|
"description": "Enable webhook notifications.",
|
||||||
"type": "boolean"
|
"type": "boolean"
|
||||||
},
|
},
|
||||||
"url": {
|
"url": {
|
||||||
|
"description": "Webhook URL. Recommended to be set via environment variable FREQTRADE__WEBHOOK__URL",
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
"format": {
|
"format": {
|
||||||
@@ -853,6 +863,7 @@
|
|||||||
"type": "boolean"
|
"type": "boolean"
|
||||||
},
|
},
|
||||||
"webhook_url": {
|
"webhook_url": {
|
||||||
|
"description": "Discord webhook URL. Recommended to be set via environment variable FREQTRADE__DISCORD__WEBHOOK_URL",
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
"exit_fill": {
|
"exit_fill": {
|
||||||
@@ -1168,28 +1179,35 @@
|
|||||||
"description": "Name of the exchange.",
|
"description": "Name of the exchange.",
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
"enable_ws": {
|
|
||||||
"description": "Enable WebSocket connections to the exchange.",
|
|
||||||
"type": "boolean",
|
|
||||||
"default": true
|
|
||||||
},
|
|
||||||
"key": {
|
"key": {
|
||||||
"description": "API key for the exchange.",
|
"description": "API key for the exchange. Recommended to be set via environment variable FREQTRADE__EXCHANGE__KEY",
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"default": ""
|
"default": ""
|
||||||
},
|
},
|
||||||
"secret": {
|
"secret": {
|
||||||
"description": "API secret for the exchange.",
|
"description": "API secret for the exchange. Recommended to be set via environment variable FREQTRADE__EXCHANGE__SECRET",
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"default": ""
|
"default": ""
|
||||||
},
|
},
|
||||||
"password": {
|
"password": {
|
||||||
"description": "Password for the exchange, if required.",
|
"description": "Password for the exchange, if required. Recommended to be set via environment variable FREQTRADE__EXCHANGE__PASSWORD",
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"default": ""
|
"default": ""
|
||||||
},
|
},
|
||||||
"uid": {
|
"uid": {
|
||||||
"description": "User ID for the exchange, if required.",
|
"description": "User ID for the exchange, if required. Recommended to be set via environment variable FREQTRADE__EXCHANGE__UID",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"account_id": {
|
||||||
|
"description": "Account ID for the exchange, if required. Recommended to be set via environment variable FREQTRADE__EXCHANGE__ACCOUNT_ID",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"wallet_address": {
|
||||||
|
"description": "Wallet address for the exchange, if required. Usually used by DEX exchanges. Recommended to be set via environment variable FREQTRADE__EXCHANGE__WALLET_ADDRESS",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"private_key": {
|
||||||
|
"description": "Private key for the exchange, if required. Usually used by DEX exchanges. Recommended to be set via environment variable FREQTRADE__EXCHANGE__PRIVATE_KEY",
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
"pair_whitelist": {
|
"pair_whitelist": {
|
||||||
@@ -1213,6 +1231,11 @@
|
|||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"default": false
|
"default": false
|
||||||
},
|
},
|
||||||
|
"enable_ws": {
|
||||||
|
"description": "Enable WebSocket connections to the exchange.",
|
||||||
|
"type": "boolean",
|
||||||
|
"default": true
|
||||||
|
},
|
||||||
"unknown_fee_rate": {
|
"unknown_fee_rate": {
|
||||||
"description": "Fee rate for unknown markets.",
|
"description": "Fee rate for unknown markets.",
|
||||||
"type": "number"
|
"type": "number"
|
||||||
@@ -1232,7 +1255,11 @@
|
|||||||
"type": "object"
|
"type": "object"
|
||||||
},
|
},
|
||||||
"ccxt_async_config": {
|
"ccxt_async_config": {
|
||||||
"description": "CCXT asynchronous configuration settings.",
|
"description": "CCXT asynchronous configuration settings.Usually ccxt_config should be used instead.",
|
||||||
|
"type": "object"
|
||||||
|
},
|
||||||
|
"ccxt_sync_config": {
|
||||||
|
"description": "CCXT synchronous configuration settings. Usually ccxt_config should be used instead.",
|
||||||
"type": "object"
|
"type": "object"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -1240,52 +1267,6 @@
|
|||||||
"name"
|
"name"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"edge": {
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"enabled": {
|
|
||||||
"type": "boolean"
|
|
||||||
},
|
|
||||||
"process_throttle_secs": {
|
|
||||||
"type": "integer",
|
|
||||||
"minimum": 600
|
|
||||||
},
|
|
||||||
"calculate_since_number_of_days": {
|
|
||||||
"type": "integer"
|
|
||||||
},
|
|
||||||
"allowed_risk": {
|
|
||||||
"type": "number"
|
|
||||||
},
|
|
||||||
"stoploss_range_min": {
|
|
||||||
"type": "number"
|
|
||||||
},
|
|
||||||
"stoploss_range_max": {
|
|
||||||
"type": "number"
|
|
||||||
},
|
|
||||||
"stoploss_range_step": {
|
|
||||||
"type": "number"
|
|
||||||
},
|
|
||||||
"minimum_winrate": {
|
|
||||||
"type": "number"
|
|
||||||
},
|
|
||||||
"minimum_expectancy": {
|
|
||||||
"type": "number"
|
|
||||||
},
|
|
||||||
"min_trade_number": {
|
|
||||||
"type": "number"
|
|
||||||
},
|
|
||||||
"max_trade_duration_minute": {
|
|
||||||
"type": "integer"
|
|
||||||
},
|
|
||||||
"remove_pumps": {
|
|
||||||
"type": "boolean"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"required": [
|
|
||||||
"process_throttle_secs",
|
|
||||||
"allowed_risk"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"logging": {
|
"logging": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -2,7 +2,7 @@
|
|||||||
"$schema": "https://schema.freqtrade.io/schema.json",
|
"$schema": "https://schema.freqtrade.io/schema.json",
|
||||||
"max_open_trades": 3,
|
"max_open_trades": 3,
|
||||||
"stake_currency": "USDT",
|
"stake_currency": "USDT",
|
||||||
"stake_amount": 0.05,
|
"stake_amount": 30,
|
||||||
"tradable_balance_ratio": 0.99,
|
"tradable_balance_ratio": 0.99,
|
||||||
"fiat_display_currency": "USD",
|
"fiat_display_currency": "USD",
|
||||||
"timeframe": "5m",
|
"timeframe": "5m",
|
||||||
|
|||||||
@@ -25,10 +25,10 @@
|
|||||||
"trading_mode": "spot",
|
"trading_mode": "spot",
|
||||||
"margin_mode": "",
|
"margin_mode": "",
|
||||||
"minimal_roi": {
|
"minimal_roi": {
|
||||||
"40": 0.0,
|
"40": 0.0,
|
||||||
"30": 0.01,
|
"30": 0.01,
|
||||||
"20": 0.02,
|
"20": 0.02,
|
||||||
"0": 0.04
|
"0": 0.04
|
||||||
},
|
},
|
||||||
"stoploss": -0.10,
|
"stoploss": -0.10,
|
||||||
"unfilledtimeout": {
|
"unfilledtimeout": {
|
||||||
@@ -47,7 +47,7 @@
|
|||||||
"bids_to_ask_delta": 1
|
"bids_to_ask_delta": 1
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"exit_pricing":{
|
"exit_pricing": {
|
||||||
"price_side": "same",
|
"price_side": "same",
|
||||||
"use_order_book": true,
|
"use_order_book": true,
|
||||||
"order_book_top": 1,
|
"order_book_top": 1,
|
||||||
@@ -70,18 +70,38 @@
|
|||||||
"exit": "GTC"
|
"exit": "GTC"
|
||||||
},
|
},
|
||||||
"pairlists": [
|
"pairlists": [
|
||||||
{"method": "StaticPairList"},
|
{
|
||||||
{"method": "FullTradesFilter"},
|
"method": "StaticPairList"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"method": "DelistFilter",
|
||||||
|
"max_days_from_now": 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"method": "FullTradesFilter"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"method": "VolumePairList",
|
"method": "VolumePairList",
|
||||||
"number_assets": 20,
|
"number_assets": 20,
|
||||||
"sort_key": "quoteVolume",
|
"sort_key": "quoteVolume",
|
||||||
"refresh_period": 1800
|
"refresh_period": 1800
|
||||||
},
|
},
|
||||||
{"method": "AgeFilter", "min_days_listed": 10},
|
{
|
||||||
{"method": "PrecisionFilter"},
|
"method": "AgeFilter",
|
||||||
{"method": "PriceFilter", "low_price_ratio": 0.01, "min_price": 0.00000010},
|
"min_days_listed": 10
|
||||||
{"method": "SpreadFilter", "max_spread_ratio": 0.005},
|
},
|
||||||
|
{
|
||||||
|
"method": "PrecisionFilter"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"method": "PriceFilter",
|
||||||
|
"low_price_ratio": 0.01,
|
||||||
|
"min_price": 0.00000010
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"method": "SpreadFilter",
|
||||||
|
"max_spread_ratio": 0.005
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"method": "RangeStabilityFilter",
|
"method": "RangeStabilityFilter",
|
||||||
"lookback_days": 10,
|
"lookback_days": 10,
|
||||||
@@ -121,20 +141,6 @@
|
|||||||
"outdated_offset": 5,
|
"outdated_offset": 5,
|
||||||
"markets_refresh_interval": 60
|
"markets_refresh_interval": 60
|
||||||
},
|
},
|
||||||
"edge": {
|
|
||||||
"enabled": false,
|
|
||||||
"process_throttle_secs": 3600,
|
|
||||||
"calculate_since_number_of_days": 7,
|
|
||||||
"allowed_risk": 0.01,
|
|
||||||
"stoploss_range_min": -0.01,
|
|
||||||
"stoploss_range_max": -0.1,
|
|
||||||
"stoploss_range_step": -0.01,
|
|
||||||
"minimum_winrate": 0.60,
|
|
||||||
"minimum_expectancy": 0.20,
|
|
||||||
"min_trade_number": 10,
|
|
||||||
"max_trade_duration_minute": 1440,
|
|
||||||
"remove_pumps": false
|
|
||||||
},
|
|
||||||
"telegram": {
|
"telegram": {
|
||||||
"enabled": false,
|
"enabled": false,
|
||||||
"token": "your_telegram_token",
|
"token": "your_telegram_token",
|
||||||
@@ -180,12 +186,12 @@
|
|||||||
"external_message_consumer": {
|
"external_message_consumer": {
|
||||||
"enabled": false,
|
"enabled": false,
|
||||||
"producers": [
|
"producers": [
|
||||||
{
|
{
|
||||||
"name": "default",
|
"name": "default",
|
||||||
"host": "127.0.0.2",
|
"host": "127.0.0.2",
|
||||||
"port": 8080,
|
"port": 8080,
|
||||||
"ws_token": "secret_ws_t0ken."
|
"ws_token": "secret_ws_t0ken."
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"wait_timeout": 300,
|
"wait_timeout": 300,
|
||||||
"ping_timeout": 10,
|
"ping_timeout": 10,
|
||||||
@@ -209,4 +215,4 @@
|
|||||||
"reduce_df_footprint": false,
|
"reduce_df_footprint": false,
|
||||||
"dataformat_ohlcv": "feather",
|
"dataformat_ohlcv": "feather",
|
||||||
"dataformat_trades": "feather"
|
"dataformat_trades": "feather"
|
||||||
}
|
}
|
||||||
+10
-11
@@ -1,10 +1,10 @@
|
|||||||
FROM python:3.11.12-slim-bookworm as base
|
FROM python:3.11.13-slim-bookworm AS base
|
||||||
|
|
||||||
# Setup env
|
# Setup env
|
||||||
ENV LANG C.UTF-8
|
ENV LANG=C.UTF-8
|
||||||
ENV LC_ALL C.UTF-8
|
ENV LC_ALL=C.UTF-8
|
||||||
ENV PYTHONDONTWRITEBYTECODE 1
|
ENV PYTHONDONTWRITEBYTECODE=1
|
||||||
ENV PYTHONFAULTHANDLER 1
|
ENV PYTHONFAULTHANDLER=1
|
||||||
ENV PATH=/home/ftuser/.local/bin:$PATH
|
ENV PATH=/home/ftuser/.local/bin:$PATH
|
||||||
ENV FT_APP_ENV="docker"
|
ENV FT_APP_ENV="docker"
|
||||||
|
|
||||||
@@ -22,7 +22,7 @@ RUN mkdir /freqtrade \
|
|||||||
WORKDIR /freqtrade
|
WORKDIR /freqtrade
|
||||||
|
|
||||||
# Install dependencies
|
# Install dependencies
|
||||||
FROM base as python-deps
|
FROM base AS python-deps
|
||||||
RUN apt-get update \
|
RUN apt-get update \
|
||||||
&& apt-get -y install build-essential libssl-dev libffi-dev libgfortran5 pkg-config cmake gcc \
|
&& apt-get -y install build-essential libssl-dev libffi-dev libgfortran5 pkg-config cmake gcc \
|
||||||
&& apt-get clean \
|
&& apt-get clean \
|
||||||
@@ -34,14 +34,13 @@ COPY build_helpers/* /tmp/
|
|||||||
# Install dependencies
|
# Install dependencies
|
||||||
COPY --chown=ftuser:ftuser requirements.txt /freqtrade/
|
COPY --chown=ftuser:ftuser requirements.txt /freqtrade/
|
||||||
USER ftuser
|
USER ftuser
|
||||||
RUN pip install --user --no-cache-dir "numpy<2" \
|
RUN pip install --user --only-binary=:all: --find-links /tmp/ pyarrow TA-Lib \
|
||||||
&& pip install --user --no-index --find-links /tmp/ pyarrow TA-Lib \
|
|
||||||
&& pip install --user --no-cache-dir -r requirements.txt
|
&& pip install --user --no-cache-dir -r requirements.txt
|
||||||
|
|
||||||
# Copy dependencies to runtime-image
|
# Copy dependencies to runtime-image
|
||||||
FROM base as runtime-image
|
FROM base AS runtime-image
|
||||||
COPY --from=python-deps /usr/local/lib /usr/local/lib
|
COPY --from=python-deps /usr/local/lib /usr/local/lib
|
||||||
ENV LD_LIBRARY_PATH /usr/local/lib
|
ENV LD_LIBRARY_PATH=/usr/local/lib
|
||||||
|
|
||||||
COPY --from=python-deps --chown=ftuser:ftuser /home/ftuser/.local /home/ftuser/.local
|
COPY --from=python-deps --chown=ftuser:ftuser /home/ftuser/.local /home/ftuser/.local
|
||||||
|
|
||||||
@@ -49,7 +48,7 @@ USER ftuser
|
|||||||
# Install and execute
|
# Install and execute
|
||||||
COPY --chown=ftuser:ftuser . /freqtrade/
|
COPY --chown=ftuser:ftuser . /freqtrade/
|
||||||
|
|
||||||
RUN pip install -e . --user --no-cache-dir --no-build-isolation\
|
RUN pip install -e . --user --no-cache-dir \
|
||||||
&& mkdir /freqtrade/user_data/ \
|
&& mkdir /freqtrade/user_data/ \
|
||||||
&& freqtrade install-ui
|
&& freqtrade install-ui
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +0,0 @@
|
|||||||
FROM freqtradeorg/freqtrade:develop
|
|
||||||
|
|
||||||
# Install dependencies
|
|
||||||
COPY requirements-dev.txt /freqtrade/
|
|
||||||
|
|
||||||
RUN pip install numpy --user --no-cache-dir \
|
|
||||||
&& pip install -r requirements-dev.txt --user --no-cache-dir
|
|
||||||
|
|
||||||
# Empty the ENTRYPOINT to allow all commands
|
|
||||||
ENTRYPOINT []
|
|
||||||
@@ -46,29 +46,32 @@ ranging from the simplest (0) to the most detailed per pair, per buy and per sel
|
|||||||
|
|
||||||
More options are available by running with the `-h` option.
|
More options are available by running with the `-h` option.
|
||||||
|
|
||||||
### Using export-filename
|
### Using backtest-filename
|
||||||
|
|
||||||
Normally, `backtesting-analysis` uses the latest backtest results, but if you wanted to go
|
By default, `backtesting-analysis` processes the most recent backtest results in the `user_data/backtest_results` directory.
|
||||||
back to a previous backtest output, you need to supply the `--export-filename` option.
|
If you want to analyze results from an earlier backtest, use the `--backtest-filename` option to specify the desired file. This lets you revisit and re-analyze historical backtest outputs at any time by providing the filename of the relevant backtest result:
|
||||||
You can supply the same parameter to `backtest-analysis` with the name of the final backtest
|
|
||||||
output file. This allows you to keep historical versions of backtest results and re-analyse
|
|
||||||
them at a later date:
|
|
||||||
|
|
||||||
``` bash
|
``` bash
|
||||||
freqtrade backtesting -c <config.json> --timeframe <tf> --strategy <strategy_name> --timerange=<timerange> --export=signals --export-filename=/tmp/mystrat_backtest.json
|
freqtrade backtesting-analysis -c <config.json> --timeframe <tf> --strategy <strategy_name> --timerange <timerange> --export signals --backtest-filename backtest-result-2025-03-05_20-38-34.zip
|
||||||
```
|
```
|
||||||
|
|
||||||
You should see some output similar to below in the logs with the name of the timestamped
|
You should see some output similar to below in the logs with the name of the timestamped
|
||||||
filename that was exported:
|
filename that was exported:
|
||||||
|
|
||||||
```
|
```
|
||||||
2022-06-14 16:28:32,698 - freqtrade.misc - INFO - dumping json to "/tmp/mystrat_backtest-2022-06-14_16-28-32.json"
|
2022-06-14 16:28:32,698 - freqtrade.misc - INFO - dumping json to "mystrat_backtest-2022-06-14_16-28-32.json"
|
||||||
```
|
```
|
||||||
|
|
||||||
You can then use that filename in `backtesting-analysis`:
|
You can then use that filename in `backtesting-analysis`:
|
||||||
|
|
||||||
```
|
```
|
||||||
freqtrade backtesting-analysis -c <config.json> --export-filename=/tmp/mystrat_backtest-2022-06-14_16-28-32.json
|
freqtrade backtesting-analysis -c <config.json> --backtest-filename=mystrat_backtest-2022-06-14_16-28-32.json
|
||||||
|
```
|
||||||
|
|
||||||
|
To use a result from a different results directory, you can use `--backtest-directory` to specify the directory
|
||||||
|
|
||||||
|
``` bash
|
||||||
|
freqtrade backtesting-analysis -c <config.json> --backtest-directory custom_results/ --backtest-filename mystrat_backtest-2022-06-14_16-28-32.json
|
||||||
```
|
```
|
||||||
|
|
||||||
### Tuning the buy tags and sell tags to display
|
### Tuning the buy tags and sell tags to display
|
||||||
|
|||||||
+35
-38
@@ -161,56 +161,53 @@ class MyAwesomeStrategy(IStrategy):
|
|||||||
|
|
||||||
### Overriding Base estimator
|
### Overriding Base estimator
|
||||||
|
|
||||||
You can define your own estimator for Hyperopt by implementing `generate_estimator()` in the Hyperopt subclass.
|
You can define your own optuna sampler for Hyperopt by implementing `generate_estimator()` in the Hyperopt subclass.
|
||||||
|
|
||||||
```python
|
```python
|
||||||
class MyAwesomeStrategy(IStrategy):
|
class MyAwesomeStrategy(IStrategy):
|
||||||
class HyperOpt:
|
class HyperOpt:
|
||||||
def generate_estimator(dimensions: List['Dimension'], **kwargs):
|
def generate_estimator(dimensions: List['Dimension'], **kwargs):
|
||||||
return "RF"
|
return "NSGAIIISampler"
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Possible values are either one of "GP", "RF", "ET", "GBRT" (Details can be found in the [scikit-optimize documentation](https://scikit-optimize.github.io/)), or "an instance of a class that inherits from `RegressorMixin` (from sklearn) and where the `predict` method has an optional `return_std` argument, which returns `std(Y | x)` along with `E[Y | x]`".
|
Possible values are either one of "NSGAIISampler", "TPESampler", "GPSampler", "CmaEsSampler", "NSGAIIISampler", "QMCSampler" (Details can be found in the [optuna-samplers documentation](https://optuna.readthedocs.io/en/stable/reference/samplers/index.html)), or "an instance of a class that inherits from `optuna.samplers.BaseSampler`".
|
||||||
|
|
||||||
Some research will be necessary to find additional Regressors.
|
Some research will be necessary to find additional Samplers (from optunahub) for example.
|
||||||
|
|
||||||
Example for `ExtraTreesRegressor` ("ET") with additional parameters:
|
|
||||||
|
|
||||||
```python
|
|
||||||
class MyAwesomeStrategy(IStrategy):
|
|
||||||
class HyperOpt:
|
|
||||||
def generate_estimator(dimensions: List['Dimension'], **kwargs):
|
|
||||||
from skopt.learning import ExtraTreesRegressor
|
|
||||||
# Corresponds to "ET" - but allows additional parameters.
|
|
||||||
return ExtraTreesRegressor(n_estimators=100)
|
|
||||||
|
|
||||||
```
|
|
||||||
|
|
||||||
The `dimensions` parameter is the list of `skopt.space.Dimension` objects corresponding to the parameters to be optimized. It can be used to create isotropic kernels for the `skopt.learning.GaussianProcessRegressor` estimator. Here's an example:
|
|
||||||
|
|
||||||
```python
|
|
||||||
class MyAwesomeStrategy(IStrategy):
|
|
||||||
class HyperOpt:
|
|
||||||
def generate_estimator(dimensions: List['Dimension'], **kwargs):
|
|
||||||
from skopt.utils import cook_estimator
|
|
||||||
from skopt.learning.gaussian_process.kernels import (Matern, ConstantKernel)
|
|
||||||
kernel_bounds = (0.0001, 10000)
|
|
||||||
kernel = (
|
|
||||||
ConstantKernel(1.0, kernel_bounds) *
|
|
||||||
Matern(length_scale=np.ones(len(dimensions)), length_scale_bounds=[kernel_bounds for d in dimensions], nu=2.5)
|
|
||||||
)
|
|
||||||
kernel += (
|
|
||||||
ConstantKernel(1.0, kernel_bounds) *
|
|
||||||
Matern(length_scale=np.ones(len(dimensions)), length_scale_bounds=[kernel_bounds for d in dimensions], nu=1.5)
|
|
||||||
)
|
|
||||||
|
|
||||||
return cook_estimator("GP", space=dimensions, kernel=kernel, n_restarts_optimizer=2)
|
|
||||||
```
|
|
||||||
|
|
||||||
!!! Note
|
!!! Note
|
||||||
While custom estimators can be provided, it's up to you as User to do research on possible parameters and analyze / understand which ones should be used.
|
While custom estimators can be provided, it's up to you as User to do research on possible parameters and analyze / understand which ones should be used.
|
||||||
If you're unsure about this, best use one of the Defaults (`"ET"` has proven to be the most versatile) without further parameters.
|
If you're unsure about this, best use one of the Defaults (`"NSGAIIISampler"` has proven to be the most versatile) without further parameters.
|
||||||
|
|
||||||
|
??? Example "Using `AutoSampler` from Optunahub"
|
||||||
|
|
||||||
|
[AutoSampler docs](https://hub.optuna.org/samplers/auto_sampler/)
|
||||||
|
|
||||||
|
Install the necessary dependencies
|
||||||
|
``` bash
|
||||||
|
pip install optunahub cmaes torch scipy
|
||||||
|
```
|
||||||
|
Implement `generate_estimator()` in your strategy
|
||||||
|
|
||||||
|
``` python
|
||||||
|
# ...
|
||||||
|
from freqtrade.strategy.interface import IStrategy
|
||||||
|
from typing import List
|
||||||
|
import optunahub
|
||||||
|
# ...
|
||||||
|
|
||||||
|
class my_strategy(IStrategy):
|
||||||
|
class HyperOpt:
|
||||||
|
def generate_estimator(dimensions: List["Dimension"], **kwargs):
|
||||||
|
if "random_state" in kwargs.keys():
|
||||||
|
return optunahub.load_module("samplers/auto_sampler").AutoSampler(seed=kwargs["random_state"])
|
||||||
|
else:
|
||||||
|
return optunahub.load_module("samplers/auto_sampler").AutoSampler()
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
Obviously the same approach will work for all other Samplers optuna supports.
|
||||||
|
|
||||||
|
|
||||||
## Space options
|
## Space options
|
||||||
|
|
||||||
|
|||||||
+8
-11
@@ -315,7 +315,6 @@ $RepeatedMsgReduction on
|
|||||||
|
|
||||||
The syslog address can be either a Unix domain socket (socket filename) or a UDP socket specification, consisting of IP address and UDP port, separated by the `:` character.
|
The syslog address can be either a Unix domain socket (socket filename) or a UDP socket specification, consisting of IP address and UDP port, separated by the `:` character.
|
||||||
|
|
||||||
|
|
||||||
So, the following are the examples of possible addresses:
|
So, the following are the examples of possible addresses:
|
||||||
|
|
||||||
* `"address": "/dev/log"` -- log to syslog (rsyslog) using the `/dev/log` socket, suitable for most systems.
|
* `"address": "/dev/log"` -- log to syslog (rsyslog) using the `/dev/log` socket, suitable for most systems.
|
||||||
@@ -323,20 +322,18 @@ So, the following are the examples of possible addresses:
|
|||||||
* `"address": "localhost:514"` -- log to local syslog using UDP socket, if it listens on port 514.
|
* `"address": "localhost:514"` -- log to local syslog using UDP socket, if it listens on port 514.
|
||||||
* `"address": "<ip>:514"` -- log to remote syslog at IP address and port 514. This may be used on Windows for remote logging to an external syslog server.
|
* `"address": "<ip>:514"` -- log to remote syslog at IP address and port 514. This may be used on Windows for remote logging to an external syslog server.
|
||||||
|
|
||||||
|
|
||||||
??? Info "Deprecated - configure syslog via command line"
|
??? Info "Deprecated - configure syslog via command line"
|
||||||
|
`--logfile syslog:<syslog_address>` -- send log messages to `syslog` service using the `<syslog_address>` as the syslog address.
|
||||||
|
|
||||||
`--logfile syslog:<syslog_address>` -- send log messages to `syslog` service using the `<syslog_address>` as the syslog address.
|
The syslog address can be either a Unix domain socket (socket filename) or a UDP socket specification, consisting of IP address and UDP port, separated by the `:` character.
|
||||||
|
|
||||||
The syslog address can be either a Unix domain socket (socket filename) or a UDP socket specification, consisting of IP address and UDP port, separated by the `:` character.
|
So, the following are the examples of possible usages:
|
||||||
|
|
||||||
So, the following are the examples of possible usages:
|
* `--logfile syslog:/dev/log` -- log to syslog (rsyslog) using the `/dev/log` socket, suitable for most systems.
|
||||||
|
* `--logfile syslog` -- same as above, the shortcut for `/dev/log`.
|
||||||
* `--logfile syslog:/dev/log` -- log to syslog (rsyslog) using the `/dev/log` socket, suitable for most systems.
|
* `--logfile syslog:/var/run/syslog` -- log to syslog (rsyslog) using the `/var/run/syslog` socket. Use this on MacOS.
|
||||||
* `--logfile syslog` -- same as above, the shortcut for `/dev/log`.
|
* `--logfile syslog:localhost:514` -- log to local syslog using UDP socket, if it listens on port 514.
|
||||||
* `--logfile syslog:/var/run/syslog` -- log to syslog (rsyslog) using the `/var/run/syslog` socket. Use this on MacOS.
|
* `--logfile syslog:<ip>:514` -- log to remote syslog at IP address and port 514. This may be used on Windows for remote logging to an external syslog server.
|
||||||
* `--logfile syslog:localhost:514` -- log to local syslog using UDP socket, if it listens on port 514.
|
|
||||||
* `--logfile syslog:<ip>:514` -- log to remote syslog at IP address and port 514. This may be used on Windows for remote logging to an external syslog server.
|
|
||||||
|
|
||||||
### Logging to journald
|
### Logging to journald
|
||||||
|
|
||||||
|
|||||||
Binary file not shown.
|
After Width: | Height: | Size: 111 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 109 KiB |
+243
-203
@@ -5,6 +5,8 @@ This page explains how to validate your strategy performance by using Backtestin
|
|||||||
Backtesting requires historic data to be available.
|
Backtesting requires historic data to be available.
|
||||||
To learn how to get data for the pairs and exchange you're interested in, head over to the [Data Downloading](data-download.md) section of the documentation.
|
To learn how to get data for the pairs and exchange you're interested in, head over to the [Data Downloading](data-download.md) section of the documentation.
|
||||||
|
|
||||||
|
Backtesting is also available in [webserver mode](freq-ui.md#backtesting), which allows you to run backtests via the web interface.
|
||||||
|
|
||||||
## Backtesting command reference
|
## Backtesting command reference
|
||||||
|
|
||||||
--8<-- "commands/backtesting.md"
|
--8<-- "commands/backtesting.md"
|
||||||
@@ -103,12 +105,14 @@ Only use this if you're sure you'll not want to plot or analyze your results fur
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
Exporting trades to file specifying a custom filename
|
Exporting trades to file specifying a custom directory
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
freqtrade backtesting --strategy backtesting --export trades --export-filename=backtest_samplestrategy.json
|
freqtrade backtesting --strategy backtesting --export trades --backtest-directory=user_data/custom-backtest-results
|
||||||
```
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
Please also read about the [strategy startup period](strategy-customization.md#strategy-startup-period).
|
Please also read about the [strategy startup period](strategy-customization.md#strategy-startup-period).
|
||||||
|
|
||||||
---
|
---
|
||||||
@@ -156,117 +160,136 @@ The most important in the backtesting is to understand the result.
|
|||||||
A backtesting result will look like that:
|
A backtesting result will look like that:
|
||||||
|
|
||||||
```
|
```
|
||||||
================================================ BACKTESTING REPORT =================================================
|
BACKTESTING REPORT
|
||||||
| Pair | Trades | Avg Profit % | Tot Profit BTC | Tot Profit % | Avg Duration | Wins Draws Loss Win% |
|
┏━━━━━━━━━━━━━━━┳━━━━━━━━┳━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓
|
||||||
|----------+--------+----------------+------------------+----------------+--------------+--------------------------|
|
┃ Pair ┃ Trades ┃ Avg Profit % ┃ Tot Profit USDT ┃ Tot Profit % ┃ Avg Duration ┃ Win Draw Loss Win% ┃
|
||||||
| ADA/BTC | 35 | -0.11 | -0.00019428 | -1.94 | 4:35:00 | 14 0 21 40.0 |
|
┡━━━━━━━━━━━━━━━╇━━━━━━━━╇━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━┩
|
||||||
| ARK/BTC | 11 | -0.41 | -0.00022647 | -2.26 | 2:03:00 | 3 0 8 27.3 |
|
│ LTC/USDT:USDT │ 16 │ 1.0 │ 56.176 │ 5.62 │ 16:16:00 │ 16 0 0 100 │
|
||||||
| BTS/BTC | 32 | 0.31 | 0.00048938 | 4.89 | 5:05:00 | 18 0 14 56.2 |
|
│ ETC/USDT:USDT │ 12 │ 0.72 │ 30.936 │ 3.09 │ 9:55:00 │ 11 0 1 91.7 │
|
||||||
| DASH/BTC | 13 | -0.08 | -0.00005343 | -0.53 | 4:39:00 | 6 0 7 46.2 |
|
│ ETH/USDT:USDT │ 8 │ 0.66 │ 17.864 │ 1.79 │ 1 day, 13:55:00 │ 7 0 1 87.5 │
|
||||||
| ENG/BTC | 18 | 1.36 | 0.00122807 | 12.27 | 2:50:00 | 8 0 10 44.4 |
|
│ XLM/USDT:USDT │ 10 │ 0.31 │ 11.054 │ 1.11 │ 12:08:00 │ 9 0 1 90.0 │
|
||||||
| EOS/BTC | 36 | 0.08 | 0.00015304 | 1.53 | 3:34:00 | 16 0 20 44.4 |
|
│ BTC/USDT:USDT │ 8 │ 0.21 │ 7.289 │ 0.73 │ 3 days, 1:24:00 │ 6 0 2 75.0 │
|
||||||
| ETC/BTC | 26 | 0.37 | 0.00047576 | 4.75 | 6:14:00 | 11 0 15 42.3 |
|
│ XRP/USDT:USDT │ 9 │ -0.14 │ -7.261 │ -0.73 │ 21:18:00 │ 8 0 1 88.9 │
|
||||||
| ETH/BTC | 33 | 0.30 | 0.00049856 | 4.98 | 7:31:00 | 16 0 17 48.5 |
|
│ DOT/USDT:USDT │ 6 │ -0.4 │ -9.187 │ -0.92 │ 5:35:00 │ 4 0 2 66.7 │
|
||||||
| IOTA/BTC | 32 | 0.03 | 0.00005444 | 0.54 | 3:12:00 | 14 0 18 43.8 |
|
│ ADA/USDT:USDT │ 8 │ -1.76 │ -52.098 │ -5.21 │ 11:38:00 │ 6 0 2 75.0 │
|
||||||
| LSK/BTC | 15 | 1.75 | 0.00131413 | 13.13 | 2:58:00 | 6 0 9 40.0 |
|
│ TOTAL │ 77 │ 0.22 │ 54.774 │ 5.48 │ 22:12:00 │ 67 0 10 87.0 │
|
||||||
| LTC/BTC | 32 | -0.04 | -0.00006886 | -0.69 | 4:49:00 | 11 0 21 34.4 |
|
└───────────────┴────────┴──────────────┴─────────────────┴──────────────┴─────────────────┴────────────────────────┘
|
||||||
| NANO/BTC | 17 | 1.26 | 0.00107058 | 10.70 | 1:55:00 | 10 0 7 58.5 |
|
LEFT OPEN TRADES REPORT
|
||||||
| NEO/BTC | 23 | 0.82 | 0.00094936 | 9.48 | 2:59:00 | 10 0 13 43.5 |
|
┏━━━━━━━━━━━━━━━┳━━━━━━━━┳━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓
|
||||||
| REQ/BTC | 9 | 1.17 | 0.00052734 | 5.27 | 3:47:00 | 4 0 5 44.4 |
|
┃ Pair ┃ Trades ┃ Avg Profit % ┃ Tot Profit USDT ┃ Tot Profit % ┃ Avg Duration ┃ Win Draw Loss Win% ┃
|
||||||
| XLM/BTC | 16 | 1.22 | 0.00097800 | 9.77 | 3:15:00 | 7 0 9 43.8 |
|
┡━━━━━━━━━━━━━━━╇━━━━━━━━╇━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━┩
|
||||||
| XMR/BTC | 23 | -0.18 | -0.00020696 | -2.07 | 5:30:00 | 12 0 11 52.2 |
|
│ BTC/USDT:USDT │ 1 │ -4.14 │ -9.930 │ -0.99 │ 17 days, 8:00:00 │ 0 0 1 0 │
|
||||||
| XRP/BTC | 35 | 0.66 | 0.00114897 | 11.48 | 3:49:00 | 12 0 23 34.3 |
|
│ ETC/USDT:USDT │ 1 │ -4.24 │ -15.365 │ -1.54 │ 10:40:00 │ 0 0 1 0 │
|
||||||
| ZEC/BTC | 22 | -0.46 | -0.00050971 | -5.09 | 2:22:00 | 7 0 15 31.8 |
|
│ DOT/USDT:USDT │ 1 │ -5.29 │ -19.125 │ -1.91 │ 11:30:00 │ 0 0 1 0 │
|
||||||
| TOTAL | 429 | 0.36 | 0.00762792 | 76.20 | 4:12:00 | 186 0 243 43.4 |
|
│ TOTAL │ 3 │ -4.56 │ -44.420 │ -4.44 │ 6 days, 2:03:00 │ 0 0 3 0 │
|
||||||
============================================= LEFT OPEN TRADES REPORT =============================================
|
└───────────────┴────────┴──────────────┴─────────────────┴──────────────┴──────────────────┴────────────────────────┘
|
||||||
| Pair | Trades | Avg Profit % | Tot Profit BTC | Tot Profit % | Avg Duration | Win Draw Loss Win% |
|
ENTER TAG STATS
|
||||||
|----------+---------+----------------+------------------+----------------+----------------+---------------------|
|
┏━━━━━━━━━━━┳━━━━━━━━━┳━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓
|
||||||
| ADA/BTC | 1 | 0.89 | 0.00004434 | 0.44 | 6:00:00 | 1 0 0 100 |
|
┃ Enter Tag ┃ Entries ┃ Avg Profit % ┃ Tot Profit USDT ┃ Tot Profit % ┃ Avg Duration ┃ Win Draw Loss Win% ┃
|
||||||
| LTC/BTC | 1 | 0.68 | 0.00003421 | 0.34 | 2:00:00 | 1 0 0 100 |
|
┡━━━━━━━━━━━╇━━━━━━━━━╇━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━┩
|
||||||
| TOTAL | 2 | 0.78 | 0.00007855 | 0.78 | 4:00:00 | 2 0 0 100 |
|
│ OTHER │ 77 │ 0.22 │ 54.774 │ 5.48 │ 22:12:00 │ 67 0 10 87.0 │
|
||||||
==================== EXIT REASON STATS ====================
|
│ TOTAL │ 77 │ 0.22 │ 54.774 │ 5.48 │ 22:12:00 │ 67 0 10 87.0 │
|
||||||
| Exit Reason | Exits | Wins | Draws | Losses |
|
└───────────┴─────────┴──────────────┴─────────────────┴──────────────┴──────────────┴────────────────────────┘
|
||||||
|--------------------+---------+-------+--------+---------|
|
EXIT REASON STATS
|
||||||
| trailing_stop_loss | 205 | 150 | 0 | 55 |
|
┏━━━━━━━━━━━━━┳━━━━━━━┳━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓
|
||||||
| stop_loss | 166 | 0 | 0 | 166 |
|
┃ Exit Reason ┃ Exits ┃ Avg Profit % ┃ Tot Profit USDT ┃ Tot Profit % ┃ Avg Duration ┃ Win Draw Loss Win% ┃
|
||||||
| exit_signal | 56 | 36 | 0 | 20 |
|
┡━━━━━━━━━━━━━╇━━━━━━━╇━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━┩
|
||||||
| force_exit | 2 | 0 | 0 | 2 |
|
│ roi │ 67 │ 1.05 │ 242.179 │ 24.22 │ 15:49:00 │ 67 0 0 100 │
|
||||||
|
│ exit_signal │ 4 │ -2.23 │ -31.217 │ -3.12 │ 1 day, 8:38:00 │ 0 0 4 0 │
|
||||||
|
│ force_exit │ 3 │ -4.56 │ -44.420 │ -4.44 │ 6 days, 2:03:00 │ 0 0 3 0 │
|
||||||
|
│ stop_loss │ 3 │ -10.14 │ -111.768 │ -11.18 │ 1 day, 3:05:00 │ 0 0 3 0 │
|
||||||
|
│ TOTAL │ 77 │ 0.22 │ 54.774 │ 5.48 │ 22:12:00 │ 67 0 10 87.0 │
|
||||||
|
└─────────────┴───────┴──────────────┴─────────────────┴──────────────┴─────────────────┴────────────────────────┘
|
||||||
|
MIXED TAG STATS
|
||||||
|
┏━━━━━━━━━━━┳━━━━━━━━━━━━━┳━━━━━━━━┳━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓
|
||||||
|
┃ Enter Tag ┃ Exit Reason ┃ Trades ┃ Avg Profit % ┃ Tot Profit USDT ┃ Tot Profit % ┃ Avg Duration ┃ Win Draw Loss Win% ┃
|
||||||
|
┡━━━━━━━━━━━╇━━━━━━━━━━━━━╇━━━━━━━━╇━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━┩
|
||||||
|
│ │ roi │ 67 │ 1.05 │ 242.179 │ 24.22 │ 15:49:00 │ 67 0 0 100 │
|
||||||
|
│ │ exit_signal │ 4 │ -2.23 │ -31.217 │ -3.12 │ 1 day, 8:38:00 │ 0 0 4 0 │
|
||||||
|
│ │ force_exit │ 3 │ -4.56 │ -44.420 │ -4.44 │ 6 days, 2:03:00 │ 0 0 3 0 │
|
||||||
|
│ │ stop_loss │ 3 │ -10.14 │ -111.768 │ -11.18 │ 1 day, 3:05:00 │ 0 0 3 0 │
|
||||||
|
│ TOTAL │ │ 77 │ 0.22 │ 54.774 │ 5.48 │ 22:12:00 │ 67 0 10 87.0 │
|
||||||
|
└───────────┴─────────────┴────────┴──────────────┴─────────────────┴──────────────┴─────────────────┴────────────────────────┘
|
||||||
|
SUMMARY METRICS
|
||||||
|
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
|
||||||
|
┃ Metric ┃ Value ┃
|
||||||
|
┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┩
|
||||||
|
│ Backtesting from │ 2025-07-01 00:00:00 │
|
||||||
|
│ Backtesting to │ 2025-08-01 00:00:00 │
|
||||||
|
│ Trading Mode │ Isolated Futures │
|
||||||
|
│ Max open trades │ 3 │
|
||||||
|
│ │ │
|
||||||
|
│ Total/Daily Avg Trades │ 77 / 2.48 │
|
||||||
|
│ Starting balance │ 1000 USDT │
|
||||||
|
│ Final balance │ 1054.774 USDT │
|
||||||
|
│ Absolute profit │ 54.774 USDT │
|
||||||
|
│ Total profit % │ 5.48% │
|
||||||
|
│ CAGR % │ 87.36% │
|
||||||
|
│ Sortino │ 2.48 │
|
||||||
|
│ Sharpe │ 3.75 │
|
||||||
|
│ Calmar │ 40.99 │
|
||||||
|
│ SQN │ 0.69 │
|
||||||
|
│ Profit factor │ 1.29 │
|
||||||
|
│ Expectancy (Ratio) │ 0.71 (0.04) │
|
||||||
|
│ Avg. daily profit │ 1.767 USDT │
|
||||||
|
│ Avg. stake amount │ 345.016 USDT │
|
||||||
|
│ Total trade volume │ 53316.954 USDT │
|
||||||
|
│ │ │
|
||||||
|
│ Long / Short trades │ 67 / 10 │
|
||||||
|
│ Long / Short profit % │ 8.94% / -3.47% │
|
||||||
|
│ Long / Short profit USDT │ 89.425 / -34.651 │
|
||||||
|
│ │ │
|
||||||
|
│ Best Pair │ LTC/USDT:USDT 5.62% │
|
||||||
|
│ Worst Pair │ ADA/USDT:USDT -5.21% │
|
||||||
|
│ Best trade │ ETC/USDT:USDT 2.00% │
|
||||||
|
│ Worst trade │ ADA/USDT:USDT -10.17% │
|
||||||
|
│ Best day │ 26.91 USDT │
|
||||||
|
│ Worst day │ -47.741 USDT │
|
||||||
|
│ Days win/draw/lose │ 20 / 6 / 5 │
|
||||||
|
│ Min/Max/Avg. Duration Winners │ 0d 00:35 / 5d 18:15 / 0d 15:49 │
|
||||||
|
│ Min/Max/Avg. Duration Losers │ 0d 10:40 / 17d 08:00 / 2d 17:00 │
|
||||||
|
│ Max Consecutive Wins / Loss │ 36 / 3 │
|
||||||
|
│ Rejected Entry signals │ 258 │
|
||||||
|
│ Entry/Exit Timeouts │ 0 / 0 │
|
||||||
|
│ │ │
|
||||||
|
│ Min balance │ 1003.168 USDT │
|
||||||
|
│ Max balance │ 1149.421 USDT │
|
||||||
|
│ Max % of account underwater │ 8.23% │
|
||||||
|
│ Absolute drawdown │ 94.647 USDT (8.23%) │
|
||||||
|
│ Drawdown duration │ 9 days 08:50:00 │
|
||||||
|
│ Profit at drawdown start │ 149.421 USDT │
|
||||||
|
│ Profit at drawdown end │ 54.774 USDT │
|
||||||
|
│ Drawdown start │ 2025-07-22 15:10:00 │
|
||||||
|
│ Drawdown end │ 2025-08-01 00:00:00 │
|
||||||
|
│ Market change │ 30.51% │
|
||||||
|
└───────────────────────────────┴─────────────────────────────────┘
|
||||||
|
|
||||||
================== SUMMARY METRICS ==================
|
Backtested 2025-07-01 00:00:00 -> 2025-08-01 00:00:00 | Max open trades : 3
|
||||||
| Metric | Value |
|
STRATEGY SUMMARY
|
||||||
|-----------------------------+---------------------|
|
┏━━━━━━━━━━━━━━━━┳━━━━━━━━┳━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━┓
|
||||||
| Backtesting from | 2019-01-01 00:00:00 |
|
┃ Strategy ┃ Trades ┃ Avg Profit % ┃ Tot Profit USDT ┃ Tot Profit % ┃ Avg Duration ┃ Win Draw Loss Win% ┃ Drawdown ┃
|
||||||
| Backtesting to | 2019-05-01 00:00:00 |
|
┡━━━━━━━━━━━━━━━━╇━━━━━━━━╇━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━┩
|
||||||
| Trading Mode | Spot |
|
│ SampleStrategy │ 77 │ 0.22 │ 54.774 │ 5.48 │ 22:12:00 │ 67 0 10 87.0 │ 94.647 USDT 8.23% │
|
||||||
| Max open trades | 3 |
|
└────────────────┴────────┴──────────────┴─────────────────┴──────────────┴──────────────┴────────────────────────┴────────────────────┘
|
||||||
| | |
|
|
||||||
| Total/Daily Avg Trades | 429 / 3.575 |
|
|
||||||
| Starting balance | 0.01000000 BTC |
|
|
||||||
| Final balance | 0.01762792 BTC |
|
|
||||||
| Absolute profit | 0.00762792 BTC |
|
|
||||||
| Total profit % | 76.2% |
|
|
||||||
| CAGR % | 460.87% |
|
|
||||||
| Sortino | 1.88 |
|
|
||||||
| Sharpe | 2.97 |
|
|
||||||
| Calmar | 6.29 |
|
|
||||||
| SQN | 2.45 |
|
|
||||||
| Profit factor | 1.11 |
|
|
||||||
| Expectancy (Ratio) | -0.15 (-0.05) |
|
|
||||||
| Avg. stake amount | 0.001 BTC |
|
|
||||||
| Total trade volume | 0.429 BTC |
|
|
||||||
| | |
|
|
||||||
| Long / Short | 352 / 77 |
|
|
||||||
| Total profit Long % | 1250.58% |
|
|
||||||
| Total profit Short % | -15.02% |
|
|
||||||
| Absolute profit Long | 0.00838792 BTC |
|
|
||||||
| Absolute profit Short | -0.00076 BTC |
|
|
||||||
| | |
|
|
||||||
| Best Pair | LSK/BTC 26.26% |
|
|
||||||
| Worst Pair | ZEC/BTC -10.18% |
|
|
||||||
| Best Trade | LSK/BTC 4.25% |
|
|
||||||
| Worst Trade | ZEC/BTC -10.25% |
|
|
||||||
| Best day | 0.00076 BTC |
|
|
||||||
| Worst day | -0.00036 BTC |
|
|
||||||
| Days win/draw/lose | 12 / 82 / 25 |
|
|
||||||
| Avg. Duration Winners | 4:23:00 |
|
|
||||||
| Avg. Duration Loser | 6:55:00 |
|
|
||||||
| Max Consecutive Wins / Loss | 3 / 4 |
|
|
||||||
| Rejected Entry signals | 3089 |
|
|
||||||
| Entry/Exit Timeouts | 0 / 0 |
|
|
||||||
| Canceled Trade Entries | 34 |
|
|
||||||
| Canceled Entry Orders | 123 |
|
|
||||||
| Replaced Entry Orders | 89 |
|
|
||||||
| | |
|
|
||||||
| Min balance | 0.00945123 BTC |
|
|
||||||
| Max balance | 0.01846651 BTC |
|
|
||||||
| Max % of account underwater | 25.19% |
|
|
||||||
| Absolute Drawdown (Account) | 13.33% |
|
|
||||||
| Drawdown | 0.0015 BTC |
|
|
||||||
| Drawdown high | 0.0013 BTC |
|
|
||||||
| Drawdown low | -0.0002 BTC |
|
|
||||||
| Drawdown Start | 2019-02-15 14:10:00 |
|
|
||||||
| Drawdown End | 2019-04-11 18:15:00 |
|
|
||||||
| Market change | -5.88% |
|
|
||||||
=====================================================
|
|
||||||
```
|
```
|
||||||
|
|
||||||
### Backtesting report table
|
### Backtesting report table
|
||||||
|
|
||||||
The 1st table contains all trades the bot made, including "left open trades".
|
The first table contains all trades the bot made, including "left open trades".
|
||||||
|
|
||||||
The last line will give you the overall performance of your strategy,
|
The last line will give you the overall performance of your strategy,
|
||||||
here:
|
here:
|
||||||
|
|
||||||
```
|
```
|
||||||
| TOTAL | 429 | 0.36 | 152.41 | 0.00762792 | 76.20 | 4:12:00 | 186 0 243 43.4 |
|
│ TOTAL │ 77 │ 0.22 │ 54.774 │ 5.48 │ 22:12:00 │ 67 0 10 87.0 │
|
||||||
```
|
```
|
||||||
|
|
||||||
The bot has made `429` trades for an average duration of `4:12:00`, with a performance of `76.20%` (profit), that means it has
|
The bot has made `77` trades for an average duration of `22:12:00`, with a performance of `5.48%` (profit), that means it has earned a total of `54.774 USDT` starting with a capital of 1000 USDT.
|
||||||
earned a total of `0.00762792 BTC` starting with a capital of 0.01 BTC.
|
|
||||||
|
|
||||||
The column `Avg Profit %` shows the average profit for all trades made.
|
The column `Avg Profit %` shows the average profit for all trades made.
|
||||||
The column `Tot Profit %` shows instead the total profit % in relation to the starting balance.
|
The column `Tot Profit %` shows instead the total profit % in relation to the starting balance.
|
||||||
In the above results, we have a starting balance of 0.01 BTC and an absolute profit of 0.00762792 BTC - so the `Tot Profit %` will be `(0.00762792 / 0.01) * 100 ~= 76.2%`.
|
|
||||||
|
In the above results, we have a starting balance of 1000 USDT and an absolute profit of 54.774 USDT - so the `Tot Profit %` will be `(54.774 / 1000) * 100 ~= 5.48%`.
|
||||||
|
|
||||||
Your strategy performance is influenced by your entry strategy, your exit strategy, and also by the `minimal_roi` and `stop_loss` you have set.
|
Your strategy performance is influenced by your entry strategy, your exit strategy, and also by the `minimal_roi` and `stop_loss` you have set.
|
||||||
|
|
||||||
@@ -282,85 +305,83 @@ On the other hand, if you set a too high `minimal_roi` like `"0": 0.55`
|
|||||||
(55%), there is almost no chance that the bot will ever reach this profit.
|
(55%), there is almost no chance that the bot will ever reach this profit.
|
||||||
Hence, keep in mind that your performance is an integral mix of all different elements of the strategy, your configuration, and the crypto-currency pairs you have set up.
|
Hence, keep in mind that your performance is an integral mix of all different elements of the strategy, your configuration, and the crypto-currency pairs you have set up.
|
||||||
|
|
||||||
### Exit reasons table
|
|
||||||
|
|
||||||
The 2nd table contains a recap of exit reasons.
|
|
||||||
This table can tell you which area needs some additional work (e.g. all or many of the `exit_signal` trades are losses, so you should work on improving the exit signal, or consider disabling it).
|
|
||||||
|
|
||||||
### Left open trades table
|
### Left open trades table
|
||||||
|
|
||||||
The 3rd table contains all trades the bot had to `force_exit` at the end of the backtesting period to present you the full picture.
|
The second table contains all trades the bot had to `force_exit` at the end of the backtesting period to present you the full picture.
|
||||||
This is necessary to simulate realistic behavior, since the backtest period has to end at some point, while realistically, you could leave the bot running forever.
|
This is necessary to simulate realistic behavior, since the backtest period has to end at some point, while realistically, you could leave the bot running forever.
|
||||||
These trades are also included in the first table, but are also shown separately in this table for clarity.
|
These trades are also included in the first table, but are also shown separately in this table for clarity.
|
||||||
|
|
||||||
|
### Enter tag stats table
|
||||||
|
|
||||||
|
The third table provides a breakdown of trades by their entry tags (e.g., `enter_long`, `enter_short`), showing the number of entries, average profit percentage, total profit in the stake currency, total profit percentage, average duration, and the number of wins, draws, and losses for each tag.
|
||||||
|
|
||||||
|
### Exit reason stats table
|
||||||
|
|
||||||
|
The fourth table contains a recap of exit reasons (e.g., `exit_signal`, `roi`, `stop_loss`, `force_exit`). This table can tell you which area needs additional work (e.g., if many `exit_signal` trades are losses, you should work on improving the exit signal or consider disabling it).
|
||||||
|
|
||||||
|
### Mixed tag stats table
|
||||||
|
|
||||||
|
The fifth table combines entry tags and exit reasons, providing a detailed view of how different entry tags performed with specific exit reasons. This can help identify which combinations of entry and exit strategies are most effective.
|
||||||
|
|
||||||
### Summary metrics
|
### Summary metrics
|
||||||
|
|
||||||
The last element of the backtest report is the summary metrics table.
|
The last element of the backtest report is the summary metrics table.
|
||||||
It contains some useful key metrics about performance of your strategy on backtesting data.
|
It contains key metrics about the performance of your strategy on backtesting data.
|
||||||
|
|
||||||
```
|
```
|
||||||
================== SUMMARY METRICS ==================
|
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
|
||||||
| Metric | Value |
|
┃ Metric ┃ Value ┃
|
||||||
|-----------------------------+---------------------|
|
┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┩
|
||||||
| Backtesting from | 2019-01-01 00:00:00 |
|
│ Backtesting from │ 2025-07-01 00:00:00 │
|
||||||
| Backtesting to | 2019-05-01 00:00:00 |
|
│ Backtesting to │ 2025-08-01 00:00:00 │
|
||||||
| Trading Mode | Spot |
|
│ Trading Mode │ Isolated Futures │
|
||||||
| Max open trades | 3 |
|
│ Max open trades │ 3 │
|
||||||
| | |
|
│ │ │
|
||||||
| Total/Daily Avg Trades | 429 / 3.575 |
|
│ Total/Daily Avg Trades │ 72 / 2.32 │
|
||||||
| Starting balance | 0.01000000 BTC |
|
│ Starting balance │ 1000 USDT │
|
||||||
| Final balance | 0.01762792 BTC |
|
│ Final balance │ 1106.734 USDT │
|
||||||
| Absolute profit | 0.00762792 BTC |
|
│ Absolute profit │ 106.734 USDT │
|
||||||
| Total profit % | 76.2% |
|
│ Total profit % │ 10.67% │
|
||||||
| CAGR % | 460.87% |
|
│ CAGR % │ 230.04% │
|
||||||
| Sortino | 1.88 |
|
│ Sortino │ 4.99 │
|
||||||
| Sharpe | 2.97 |
|
│ Sharpe │ 8.00 │
|
||||||
| Calmar | 6.29 |
|
│ Calmar │ 77.76 │
|
||||||
| SQN | 2.45 |
|
│ SQN │ 1.52 │
|
||||||
| Profit factor | 1.11 |
|
│ Profit factor │ 1.79 │
|
||||||
| Expectancy (Ratio) | -0.15 (-0.05) |
|
│ Expectancy (Ratio) │ 1.48 (0.07) │
|
||||||
| Avg. stake amount | 0.001 BTC |
|
│ Avg. daily profit │ 3.443 USDT │
|
||||||
| Total trade volume | 0.429 BTC |
|
│ Avg. stake amount │ 363.133 USDT │
|
||||||
| | |
|
│ Total trade volume │ 52466.174 USDT │
|
||||||
| Long / Short | 352 / 77 |
|
│ │ │
|
||||||
| Total profit Long % | 1250.58% |
|
│ Best Pair │ LTC/USDT:USDT 4.48% │
|
||||||
| Total profit Short % | -15.02% |
|
│ Worst Pair │ ADA/USDT:USDT -1.78% │
|
||||||
| Absolute profit Long | 0.00838792 BTC |
|
│ Best trade │ ETC/USDT:USDT 2.00% │
|
||||||
| Absolute profit Short | -0.00076 BTC |
|
│ Worst trade │ ADA/USDT:USDT -10.17% │
|
||||||
| | |
|
│ Best day │ 23.535 USDT │
|
||||||
| Best Pair | LSK/BTC 26.26% |
|
│ Worst day │ -49.813 USDT │
|
||||||
| Worst Pair | ZEC/BTC -10.18% |
|
│ Days win/draw/lose │ 21 / 6 / 4 │
|
||||||
| Best Trade | LSK/BTC 4.25% |
|
│ Min/Max/Avg. Duration Winners │ 0d 00:35 / 5d 18:15 / 0d 15:30 │
|
||||||
| Worst Trade | ZEC/BTC -10.25% |
|
│ Min/Max/Avg. Duration Losers │ 0d 12:00 / 17d 08:00 / 3d 23:28 │
|
||||||
| Best day | 0.00076 BTC |
|
│ Max Consecutive Wins / Loss │ 58 / 4 │
|
||||||
| Worst day | -0.00036 BTC |
|
│ Rejected Entry signals │ 254 │
|
||||||
| Days win/draw/lose | 12 / 82 / 25 |
|
│ Entry/Exit Timeouts │ 0 / 0 │
|
||||||
| Avg. Duration Winners | 4:23:00 |
|
│ │ │
|
||||||
| Avg. Duration Loser | 6:55:00 |
|
│ Min balance │ 1003.168 USDT │
|
||||||
| Max Consecutive Wins / Loss | 3 / 4 |
|
│ Max balance │ 1209 USDT │
|
||||||
| Rejected Entry signals | 3089 |
|
│ Max % of account underwater │ 8.46% │
|
||||||
| Entry/Exit Timeouts | 0 / 0 |
|
│ Absolute drawdown │ 102.266 USDT (8.46%) │
|
||||||
| Canceled Trade Entries | 34 |
|
│ Drawdown duration │ 9 days 08:50:00 │
|
||||||
| Canceled Entry Orders | 123 |
|
│ Profit at drawdown start │ 209 USDT │
|
||||||
| Replaced Entry Orders | 89 |
|
│ Profit at drawdown end │ 106.734 USDT │
|
||||||
| | |
|
│ Drawdown start │ 2025-07-22 15:10:00 │
|
||||||
| Min balance | 0.00945123 BTC |
|
│ Drawdown end │ 2025-08-01 00:00:00 │
|
||||||
| Max balance | 0.01846651 BTC |
|
│ Market change │ 30.51% │
|
||||||
| Max % of account underwater | 25.19% |
|
└───────────────────────────────┴─────────────────────────────────┘
|
||||||
| Absolute Drawdown (Account) | 13.33% |
|
|
||||||
| Drawdown | 0.0015 BTC |
|
|
||||||
| Drawdown high | 0.0013 BTC |
|
|
||||||
| Drawdown low | -0.0002 BTC |
|
|
||||||
| Drawdown Start | 2019-02-15 14:10:00 |
|
|
||||||
| Drawdown End | 2019-04-11 18:15:00 |
|
|
||||||
| Market change | -5.88% |
|
|
||||||
=====================================================
|
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
- `Backtesting from` / `Backtesting to`: Backtesting range (usually defined with the `--timerange` option).
|
- `Backtesting from` / `Backtesting to`: Backtesting range (usually defined with the `--timerange` option).
|
||||||
- `Max open trades`: Setting of `max_open_trades` (or `--max-open-trades`) - or number of pairs in the pairlist (whatever is lower).
|
|
||||||
- `Trading Mode`: Spot or Futures trading.
|
- `Trading Mode`: Spot or Futures trading.
|
||||||
|
- `Max open trades`: Setting of `max_open_trades` (or `--max-open-trades`) - or number of pairs in the pairlist (whatever is lower).
|
||||||
- `Total/Daily Avg Trades`: Identical to the total trades of the backtest output table / Total trades divided by the backtesting duration in days (this will give you information about how many trades to expect from the strategy).
|
- `Total/Daily Avg Trades`: Identical to the total trades of the backtest output table / Total trades divided by the backtesting duration in days (this will give you information about how many trades to expect from the strategy).
|
||||||
- `Starting balance`: Start balance - as given by dry-run-wallet (config or command line).
|
- `Starting balance`: Start balance - as given by dry-run-wallet (config or command line).
|
||||||
- `Final balance`: Final balance - starting balance + absolute profit.
|
- `Final balance`: Final balance - starting balance + absolute profit.
|
||||||
@@ -371,56 +392,71 @@ It contains some useful key metrics about performance of your strategy on backte
|
|||||||
- `Sharpe`: Annualized Sharpe ratio.
|
- `Sharpe`: Annualized Sharpe ratio.
|
||||||
- `Calmar`: Annualized Calmar ratio.
|
- `Calmar`: Annualized Calmar ratio.
|
||||||
- `SQN`: System Quality Number (SQN) - by Van Tharp.
|
- `SQN`: System Quality Number (SQN) - by Van Tharp.
|
||||||
- `Profit factor`: profit / loss.
|
- `Profit factor`: Sum of the profits of all winning trades divided by the sum of the losses of all losing trades.
|
||||||
|
- `Expectancy (Ratio)`: Expectancy ratio, which is the average profit or loss per trade. A negative expectancy ratio means that your strategy is not profitable.
|
||||||
|
- `Avg. daily profit`: Average profit per day, calculated as `(Total Profit / Backtest Days)`.
|
||||||
- `Avg. stake amount`: Average stake amount, either `stake_amount` or the average when using dynamic stake amount.
|
- `Avg. stake amount`: Average stake amount, either `stake_amount` or the average when using dynamic stake amount.
|
||||||
- `Total trade volume`: Volume generated on the exchange to reach the above profit.
|
- `Total trade volume`: Volume generated on the exchange to reach the above profit.
|
||||||
- `Best Pair` / `Worst Pair`: Best and worst performing pair, and it's corresponding `Tot Profit %`.
|
- `Long / Short trades`: Split long/short trade counts (only shown when short trades were made).
|
||||||
- `Best Trade` / `Worst Trade`: Biggest single winning trade and biggest single losing trade.
|
- `Long / Short profit %`: Profit percentage for long and short trades (only shown when short trades were made).
|
||||||
|
- `Long / Short profit USDT`: Profit in stake currency for long and short trades (only shown when short trades were made).
|
||||||
|
- `Best Pair` / `Worst Pair`: Best and worst performing pair (based on total profit percentage), and its corresponding `Tot Profit %`.
|
||||||
|
- `Best trade` / `Worst trade`: Biggest single winning trade and biggest single losing trade.
|
||||||
- `Best day` / `Worst day`: Best and worst day based on daily profit.
|
- `Best day` / `Worst day`: Best and worst day based on daily profit.
|
||||||
- `Days win/draw/lose`: Winning / Losing days (draws are usually days without closed trade).
|
- `Days win/draw/lose`: Winning / Losing days (draws are usually days without closed trades).
|
||||||
- `Avg. Duration Winners` / `Avg. Duration Loser`: Average durations for winning and losing trades.
|
- `Min/Max/Avg. Duration Winners`: Minimum, maximum, and average durations for winning trades.
|
||||||
|
- `Min/Max/Avg. Duration Losers`: Minimum, maximum, and average durations for losing trades.
|
||||||
- `Max Consecutive Wins / Loss`: Maximum consecutive wins/losses in a row.
|
- `Max Consecutive Wins / Loss`: Maximum consecutive wins/losses in a row.
|
||||||
- `Rejected Entry signals`: Trade entry signals that could not be acted upon due to `max_open_trades` being reached.
|
- `Rejected Entry signals`: Trade entry signals that could not be acted upon due to `max_open_trades` being reached.
|
||||||
- `Entry/Exit Timeouts`: Entry/exit orders which did not fill (only applicable if custom pricing is used).
|
- `Entry/Exit Timeouts`: Entry/exit orders which did not fill (only applicable if custom pricing is used).
|
||||||
- `Canceled Trade Entries`: Number of trades that have been canceled by user request via `adjust_entry_price`.
|
|
||||||
- `Canceled Entry Orders`: Number of entry orders that have been canceled by user request via `adjust_entry_price`.
|
|
||||||
- `Replaced Entry Orders`: Number of entry orders that have been replaced by user request via `adjust_entry_price`.
|
|
||||||
- `Min balance` / `Max balance`: Lowest and Highest Wallet balance during the backtest period.
|
- `Min balance` / `Max balance`: Lowest and Highest Wallet balance during the backtest period.
|
||||||
- `Max % of account underwater`: Maximum percentage your account has decreased from the top since the simulation started.
|
- `Max % of account underwater`: Maximum percentage your account has decreased from the top since the simulation started. Calculated as the maximum of `(Max Balance - Current Balance) / (Max Balance)`.
|
||||||
Calculated as the maximum of `(Max Balance - Current Balance) / (Max Balance)`.
|
- `Absolute drawdown`: Maximum absolute drawdown experienced, including percentage relative to the account calculated as `(Absolute Drawdown) / (DrawdownHigh + startingBalance)`..
|
||||||
- `Absolute Drawdown (Account)`: Maximum Account Drawdown experienced. Calculated as `(Absolute Drawdown) / (DrawdownHigh + startingBalance)`.
|
- `Drawdown duration`: Duration of the largest drawdown period.
|
||||||
- `Drawdown`: Maximum, absolute drawdown experienced. Difference between Drawdown High and Subsequent Low point.
|
- `Profit at drawdown start` / `Profit at drawdown end`: Profit at the beginning and end of the largest drawdown period.
|
||||||
- `Drawdown high` / `Drawdown low`: Profit at the beginning and end of the largest drawdown period. A negative low value means initial capital lost.
|
- `Drawdown start` / `Drawdown end`: Start and end datetime for the largest drawdown (can also be visualized via the `plot-dataframe` sub-command).
|
||||||
- `Drawdown Start` / `Drawdown End`: Start and end datetime for this largest drawdown (can also be visualized via the `plot-dataframe` sub-command).
|
- `Market change`: Change of the market during the backtest period. Calculated as the average of all pairs' changes from the first to the last candle using the "close" column.
|
||||||
- `Market change`: Change of the market during the backtest period. Calculated as average of all pairs changes from the first to the last candle using the "close" column.
|
|
||||||
- `Long / Short`: Split long/short values (Only shown when short trades were made).
|
|
||||||
- `Total profit Long %` / `Absolute profit Long`: Profit long trades only (Only shown when short trades were made).
|
|
||||||
- `Total profit Short %` / `Absolute profit Short`: Profit short trades only (Only shown when short trades were made).
|
|
||||||
|
|
||||||
### Daily / Weekly / Monthly breakdown
|
### Daily / Weekly / Monthly / Yearly breakdown
|
||||||
|
|
||||||
You can get an overview over daily / weekly or monthly results by using the `--breakdown <>` switch.
|
You can get an overview over daily, weekly, monthly, or yearly results by using the `--breakdown <>` switch.
|
||||||
|
|
||||||
To visualize daily and weekly breakdowns, you can use the following:
|
To visualize monthly and yearly breakdowns, you can use the following:
|
||||||
|
|
||||||
``` bash
|
``` bash
|
||||||
freqtrade backtesting --strategy MyAwesomeStrategy --breakdown day week
|
freqtrade backtesting --strategy MyAwesomeStrategy --breakdown month year
|
||||||
```
|
```
|
||||||
|
|
||||||
``` output
|
``` output
|
||||||
======================== DAY BREAKDOWN =========================
|
MONTH BREAKDOWN
|
||||||
| Day | Tot Profit USDT | Wins | Draws | Losses |
|
┏━━━━━━━━━━━━┳━━━━━━━━┳━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓
|
||||||
|------------+-------------------+--------+---------+----------|
|
┃ Month ┃ Trades ┃ Tot Profit USDT ┃ Profit Factor ┃ Win Draw Loss Win% ┃
|
||||||
| 03/07/2021 | 200.0 | 2 | 0 | 0 |
|
┡━━━━━━━━━━━━╇━━━━━━━━╇━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━┩
|
||||||
| 04/07/2021 | -50.31 | 0 | 0 | 2 |
|
│ 31/01/2020 │ 12 │ 44.451 │ 7.28 │ 10 0 2 83.3 │
|
||||||
| 05/07/2021 | 220.611 | 3 | 2 | 0 |
|
│ 29/02/2020 │ 30 │ 45.41 │ 2.36 │ 17 0 13 56.7 │
|
||||||
| 06/07/2021 | 150.974 | 3 | 0 | 2 |
|
│ 31/03/2020 │ 35 │ 142.024 │ 2.42 │ 14 0 21 40.0 │
|
||||||
| 07/07/2021 | -70.193 | 1 | 0 | 2 |
|
│ 30/04/2020 │ 67 │ -23.692 │ 0.81 │ 24 0 43 35.8 │
|
||||||
| 08/07/2021 | 212.413 | 2 | 0 | 3 |
|
...
|
||||||
|
...
|
||||||
|
│ 30/04/2025 │ 203 │ -63.43 │ 0.81 │ 73 0 130 36.0 │
|
||||||
|
│ 31/05/2025 │ 142 │ 104.675 │ 1.28 │ 59 0 83 41.5 │
|
||||||
|
│ 30/06/2025 │ 177 │ -1.014 │ 1.0 │ 85 0 92 48.0 │
|
||||||
|
│ 31/07/2025 │ 155 │ 232.762 │ 1.6 │ 63 0 92 40.6 │
|
||||||
|
└────────────┴────────┴─────────────────┴───────────────┴────────────────────────┘
|
||||||
|
YEAR BREAKDOWN
|
||||||
|
┏━━━━━━━━━━━━┳━━━━━━━━┳━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓
|
||||||
|
┃ Year ┃ Trades ┃ Tot Profit USDT ┃ Profit Factor ┃ Win Draw Loss Win% ┃
|
||||||
|
┡━━━━━━━━━━━━╇━━━━━━━━╇━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━┩
|
||||||
|
│ 31/12/2020 │ 896 │ 868.889 │ 1.46 │ 351 0 545 39.2 │
|
||||||
|
│ 31/12/2021 │ 1778 │ 4487.163 │ 1.93 │ 745 0 1033 41.9 │
|
||||||
|
│ 31/12/2022 │ 1736 │ 938.27 │ 1.27 │ 698 0 1038 40.2 │
|
||||||
|
│ 31/12/2023 │ 1712 │ 1677.126 │ 1.68 │ 670 0 1042 39.1 │
|
||||||
|
│ 31/12/2024 │ 1609 │ 3198.424 │ 2.22 │ 773 0 836 48.0 │
|
||||||
|
│ 31/12/2025 │ 1042 │ 716.174 │ 1.33 │ 420 0 622 40.3 │
|
||||||
|
└────────────┴────────┴─────────────────┴───────────────┴────────────────────────┘
|
||||||
```
|
```
|
||||||
|
|
||||||
The output will show a table containing the realized absolute Profit (in stake currency) for the given timeperiod, as well as wins, draws and losses that materialized (closed) on this day. Below that there will be a second table for the summarized values of weeks indicated by the date of the closing Sunday. The same would apply to a monthly breakdown indicated by the last day of the month.
|
The output will display tables containing the realized absolute profit (in stake currency) for the selected period, along with additional statistics such as number of trades, profit factor, and distribution of wins, draws, and losses that materialized (closed) on this period.
|
||||||
|
|
||||||
### Backtest result caching
|
### Backtest result caching
|
||||||
|
|
||||||
@@ -435,15 +471,19 @@ To save time, by default backtest will reuse a cached result from within the las
|
|||||||
To further analyze your backtest results, freqtrade will export the trades to file by default.
|
To further analyze your backtest results, freqtrade will export the trades to file by default.
|
||||||
You can then load the trades to perform further analysis as shown in the [data analysis](strategy_analysis_example.md#load-backtest-results-to-pandas-dataframe) backtesting section.
|
You can then load the trades to perform further analysis as shown in the [data analysis](strategy_analysis_example.md#load-backtest-results-to-pandas-dataframe) backtesting section.
|
||||||
|
|
||||||
|
Also, you can use freqtrade in [webserver mode](freq-ui.md#backtesting) to visualize the backtest results in a web interface.
|
||||||
|
This mode also allows you to load existing backtest results, so you can analyze them without running the backtest again.
|
||||||
|
For this mode - `--notes "<notes>"` can be used to add notes to the backtest results, which will be shown in the web interface.
|
||||||
|
|
||||||
### Backtest output file
|
### Backtest output file
|
||||||
|
|
||||||
The output file freqtrade produces is a zip file containing the following files:
|
The output file freqtrade produces is a zip file containing the following files:
|
||||||
|
|
||||||
- The backtest report in json format
|
- The backtest report in json format
|
||||||
- the market change data in feather format
|
- The market change data in feather format
|
||||||
- a copy of the strategy file
|
- A copy of the strategy file
|
||||||
- a copy of the strategy parameters (if a parameter file was used)
|
- A copy of the strategy parameters (if a parameter file was used)
|
||||||
- a sanitized copy of the config file
|
- A sanitized copy of the config file
|
||||||
|
|
||||||
This will ensure results are reproducible - under the assumption that the same data is available.
|
This will ensure results are reproducible - under the assumption that the same data is available.
|
||||||
|
|
||||||
@@ -461,7 +501,7 @@ Since backtesting lacks some detailed information about what happens within a ca
|
|||||||
- Exit-signal is favored over Stoploss, because exit-signals are assumed to trigger on candle's open
|
- Exit-signal is favored over Stoploss, because exit-signals are assumed to trigger on candle's open
|
||||||
- ROI
|
- ROI
|
||||||
- Exits are compared to high - but the ROI value is used (e.g. ROI = 2%, high=5% - so the exit will be at 2%)
|
- Exits are compared to high - but the ROI value is used (e.g. ROI = 2%, high=5% - so the exit will be at 2%)
|
||||||
- Exits are never "below the candle", so a ROI of 2% may result in a exit at 2.4% if low was at 2.4% profit
|
- Exits are never "below the candle", so a ROI of 2% may result in an exit at 2.4% if low was at 2.4% profit
|
||||||
- ROI entries which came into effect on the triggering candle (e.g. `120: 0.02` for 1h candles, from `60: 0.05`) will use the candle's open as exit rate
|
- ROI entries which came into effect on the triggering candle (e.g. `120: 0.02` for 1h candles, from `60: 0.05`) will use the candle's open as exit rate
|
||||||
- Force-exits caused by `<N>=-1` ROI entries use low as exit value, unless N falls on the candle open (e.g. `120: -1` for 1h candles)
|
- Force-exits caused by `<N>=-1` ROI entries use low as exit value, unless N falls on the candle open (e.g. `120: -1` for 1h candles)
|
||||||
- Stoploss exits happen exactly at stoploss price, even if low was lower, but the loss will be `2 * fees` higher than the stoploss price
|
- Stoploss exits happen exactly at stoploss price, even if low was lower, but the loss will be `2 * fees` higher than the stoploss price
|
||||||
@@ -527,7 +567,7 @@ freqtrade backtesting --strategy AwesomeStrategy --timeframe 1h --timeframe-deta
|
|||||||
|
|
||||||
This will load 1h data (the main timeframe) as well as 5m data (detail timeframe) for the selected timerange.
|
This will load 1h data (the main timeframe) as well as 5m data (detail timeframe) for the selected timerange.
|
||||||
The strategy will be analyzed with the 1h timeframe.
|
The strategy will be analyzed with the 1h timeframe.
|
||||||
Candles where activity may take place (there's an active signal, the pair is in a trade) are evaluated at the 5m timeframe.
|
Candles where activity may take place (there's an active signal, the pair is in a trade) are evaluated at the 5m timeframe.
|
||||||
This will allow for a more accurate simulation of intra-candle movements - and can lead to different results, especially on higher timeframes.
|
This will allow for a more accurate simulation of intra-candle movements - and can lead to different results, especially on higher timeframes.
|
||||||
|
|
||||||
Entries will generally still happen at the main candle's open, however freed trade slots may be freed earlier (if the exit signal is triggered on the 5m candle), which can then be used for a new trade of a different pair.
|
Entries will generally still happen at the main candle's open, however freed trade slots may be freed earlier (if the exit signal is triggered on the 5m candle), which can then be used for a new trade of a different pair.
|
||||||
@@ -590,5 +630,5 @@ Detailed output for all strategies one after the other will be available, so mak
|
|||||||
|
|
||||||
## Next step
|
## Next step
|
||||||
|
|
||||||
Great, your strategy is profitable. What if the bot can give your the optimal parameters to use for your strategy?
|
Great, your strategy is profitable. What if the bot can give you the optimal parameters to use for your strategy?
|
||||||
Your next step is to learn [how to find optimal parameters with Hyperopt](hyperopt.md)
|
Your next step is to learn [how to find optimal parameters with Hyperopt](hyperopt.md)
|
||||||
|
|||||||
@@ -2,7 +2,8 @@
|
|||||||
usage: freqtrade backtesting-analysis [-h] [-v] [--no-color] [--logfile FILE]
|
usage: freqtrade backtesting-analysis [-h] [-v] [--no-color] [--logfile FILE]
|
||||||
[-V] [-c PATH] [-d PATH]
|
[-V] [-c PATH] [-d PATH]
|
||||||
[--userdir PATH]
|
[--userdir PATH]
|
||||||
[--export-filename PATH]
|
[--backtest-filename PATH]
|
||||||
|
[--backtest-directory PATH]
|
||||||
[--analysis-groups {0,1,2,3,4,5} [{0,1,2,3,4,5} ...]]
|
[--analysis-groups {0,1,2,3,4,5} [{0,1,2,3,4,5} ...]]
|
||||||
[--enter-reason-list ENTER_REASON_LIST [ENTER_REASON_LIST ...]]
|
[--enter-reason-list ENTER_REASON_LIST [ENTER_REASON_LIST ...]]
|
||||||
[--exit-reason-list EXIT_REASON_LIST [EXIT_REASON_LIST ...]]
|
[--exit-reason-list EXIT_REASON_LIST [EXIT_REASON_LIST ...]]
|
||||||
@@ -14,10 +15,15 @@ usage: freqtrade backtesting-analysis [-h] [-v] [--no-color] [--logfile FILE]
|
|||||||
|
|
||||||
options:
|
options:
|
||||||
-h, --help show this help message and exit
|
-h, --help show this help message and exit
|
||||||
--export-filename PATH, --backtest-filename PATH
|
--backtest-filename PATH, --export-filename PATH
|
||||||
Use this filename for backtest results.Requires
|
Use this filename for backtest results.Example:
|
||||||
`--export` to be set as well. Example: `--export-filen
|
`--backtest-
|
||||||
ame=user_data/backtest_results/backtest_today.json`
|
filename=backtest_results_2020-09-27_16-20-48.json`.
|
||||||
|
Assumes either `user_data/backtest_results/` or
|
||||||
|
`--export-directory` as base directory.
|
||||||
|
--backtest-directory PATH, --export-directory PATH
|
||||||
|
Directory to use for backtest results. Example:
|
||||||
|
`--export-directory=user_data/backtest_results/`.
|
||||||
--analysis-groups {0,1,2,3,4,5} [{0,1,2,3,4,5} ...]
|
--analysis-groups {0,1,2,3,4,5} [{0,1,2,3,4,5} ...]
|
||||||
grouping output - 0: simple wins/losses by enter tag,
|
grouping output - 0: simple wins/losses by enter tag,
|
||||||
1: by enter_tag, 2: by enter_tag and exit_tag, 3: by
|
1: by enter_tag, 2: by enter_tag and exit_tag, 3: by
|
||||||
|
|||||||
@@ -1,15 +1,22 @@
|
|||||||
```
|
```
|
||||||
usage: freqtrade backtesting-show [-h] [-v] [--no-color] [--logfile FILE] [-V]
|
usage: freqtrade backtesting-show [-h] [-v] [--no-color] [--logfile FILE] [-V]
|
||||||
[-c PATH] [-d PATH] [--userdir PATH]
|
[-c PATH] [-d PATH] [--userdir PATH]
|
||||||
[--export-filename PATH] [--show-pair-list]
|
[--backtest-filename PATH]
|
||||||
|
[--backtest-directory PATH]
|
||||||
|
[--show-pair-list]
|
||||||
[--breakdown {day,week,month,year} [{day,week,month,year} ...]]
|
[--breakdown {day,week,month,year} [{day,week,month,year} ...]]
|
||||||
|
|
||||||
options:
|
options:
|
||||||
-h, --help show this help message and exit
|
-h, --help show this help message and exit
|
||||||
--export-filename PATH, --backtest-filename PATH
|
--backtest-filename PATH, --export-filename PATH
|
||||||
Use this filename for backtest results.Requires
|
Use this filename for backtest results.Example:
|
||||||
`--export` to be set as well. Example: `--export-filen
|
`--backtest-
|
||||||
ame=user_data/backtest_results/backtest_today.json`
|
filename=backtest_results_2020-09-27_16-20-48.json`.
|
||||||
|
Assumes either `user_data/backtest_results/` or
|
||||||
|
`--export-directory` as base directory.
|
||||||
|
--backtest-directory PATH, --export-directory PATH
|
||||||
|
Directory to use for backtest results. Example:
|
||||||
|
`--export-directory=user_data/backtest_results/`.
|
||||||
--show-pair-list Show backtesting pairlist sorted by profit.
|
--show-pair-list Show backtesting pairlist sorted by profit.
|
||||||
--breakdown {day,week,month,year} [{day,week,month,year} ...]
|
--breakdown {day,week,month,year} [{day,week,month,year} ...]
|
||||||
Show backtesting breakdown per [day, week, month,
|
Show backtesting breakdown per [day, week, month,
|
||||||
|
|||||||
@@ -10,14 +10,16 @@ usage: freqtrade backtesting [-h] [-v] [--no-color] [--logfile FILE] [-V]
|
|||||||
[--stake-amount STAKE_AMOUNT] [--fee FLOAT]
|
[--stake-amount STAKE_AMOUNT] [--fee FLOAT]
|
||||||
[-p PAIRS [PAIRS ...]] [--eps]
|
[-p PAIRS [PAIRS ...]] [--eps]
|
||||||
[--enable-protections]
|
[--enable-protections]
|
||||||
|
[--enable-dynamic-pairlist]
|
||||||
[--dry-run-wallet DRY_RUN_WALLET]
|
[--dry-run-wallet DRY_RUN_WALLET]
|
||||||
[--timeframe-detail TIMEFRAME_DETAIL]
|
[--timeframe-detail TIMEFRAME_DETAIL]
|
||||||
[--strategy-list STRATEGY_LIST [STRATEGY_LIST ...]]
|
[--strategy-list STRATEGY_LIST [STRATEGY_LIST ...]]
|
||||||
[--export {none,trades,signals}]
|
[--export {none,trades,signals}]
|
||||||
[--export-filename PATH]
|
[--backtest-filename PATH]
|
||||||
|
[--backtest-directory PATH]
|
||||||
[--breakdown {day,week,month,year} [{day,week,month,year} ...]]
|
[--breakdown {day,week,month,year} [{day,week,month,year} ...]]
|
||||||
[--cache {none,day,week,month}]
|
[--cache {none,day,week,month}]
|
||||||
[--freqai-backtest-live-models]
|
[--freqai-backtest-live-models] [--notes TEXT]
|
||||||
|
|
||||||
options:
|
options:
|
||||||
-h, --help show this help message and exit
|
-h, --help show this help message and exit
|
||||||
@@ -43,9 +45,14 @@ options:
|
|||||||
Allow buying the same pair multiple times (position
|
Allow buying the same pair multiple times (position
|
||||||
stacking).
|
stacking).
|
||||||
--enable-protections, --enableprotections
|
--enable-protections, --enableprotections
|
||||||
Enable protections for backtesting.Will slow
|
Enable protections for backtesting. Will slow
|
||||||
backtesting down by a considerable amount, but will
|
backtesting down by a considerable amount, but will
|
||||||
include configured protections
|
include configured protections
|
||||||
|
--enable-dynamic-pairlist
|
||||||
|
Enables dynamic pairlist refreshes in backtesting. The
|
||||||
|
pairlist will be generated for each new candle if
|
||||||
|
you're using a pairlist handler that supports this
|
||||||
|
feature, for example, ShuffleFilter.
|
||||||
--dry-run-wallet DRY_RUN_WALLET, --starting-balance DRY_RUN_WALLET
|
--dry-run-wallet DRY_RUN_WALLET, --starting-balance DRY_RUN_WALLET
|
||||||
Starting balance, used for backtesting / hyperopt and
|
Starting balance, used for backtesting / hyperopt and
|
||||||
dry-runs.
|
dry-runs.
|
||||||
@@ -61,10 +68,15 @@ options:
|
|||||||
becomes `backtest-data-SampleStrategy.json`
|
becomes `backtest-data-SampleStrategy.json`
|
||||||
--export {none,trades,signals}
|
--export {none,trades,signals}
|
||||||
Export backtest results (default: trades).
|
Export backtest results (default: trades).
|
||||||
--export-filename PATH, --backtest-filename PATH
|
--backtest-filename PATH, --export-filename PATH
|
||||||
Use this filename for backtest results.Requires
|
Use this filename for backtest results.Example:
|
||||||
`--export` to be set as well. Example: `--export-filen
|
`--backtest-
|
||||||
ame=user_data/backtest_results/backtest_today.json`
|
filename=backtest_results_2020-09-27_16-20-48.json`.
|
||||||
|
Assumes either `user_data/backtest_results/` or
|
||||||
|
`--export-directory` as base directory.
|
||||||
|
--backtest-directory PATH, --export-directory PATH
|
||||||
|
Directory to use for backtest results. Example:
|
||||||
|
`--export-directory=user_data/backtest_results/`.
|
||||||
--breakdown {day,week,month,year} [{day,week,month,year} ...]
|
--breakdown {day,week,month,year} [{day,week,month,year} ...]
|
||||||
Show backtesting breakdown per [day, week, month,
|
Show backtesting breakdown per [day, week, month,
|
||||||
year].
|
year].
|
||||||
@@ -73,6 +85,7 @@ options:
|
|||||||
age (default: day).
|
age (default: day).
|
||||||
--freqai-backtest-live-models
|
--freqai-backtest-live-models
|
||||||
Run backtest with ready models.
|
Run backtest with ready models.
|
||||||
|
--notes TEXT Add notes to the backtest results.
|
||||||
|
|
||||||
Common arguments:
|
Common arguments:
|
||||||
-v, --verbose Verbose mode (-vv for more, -vvv to get all messages).
|
-v, --verbose Verbose mode (-vv for more, -vvv to get all messages).
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ usage: freqtrade download-data [-h] [-v] [--no-color] [--logfile FILE] [-V]
|
|||||||
[-p PAIRS [PAIRS ...]] [--pairs-file FILE]
|
[-p PAIRS [PAIRS ...]] [--pairs-file FILE]
|
||||||
[--days INT] [--new-pairs-days INT]
|
[--days INT] [--new-pairs-days INT]
|
||||||
[--include-inactive-pairs]
|
[--include-inactive-pairs]
|
||||||
|
[--no-parallel-download]
|
||||||
[--timerange TIMERANGE] [--dl-trades]
|
[--timerange TIMERANGE] [--dl-trades]
|
||||||
[--convert] [--exchange EXCHANGE]
|
[--convert] [--exchange EXCHANGE]
|
||||||
[-t TIMEFRAMES [TIMEFRAMES ...]] [--erase]
|
[-t TIMEFRAMES [TIMEFRAMES ...]] [--erase]
|
||||||
@@ -24,6 +25,9 @@ options:
|
|||||||
Default: `None`.
|
Default: `None`.
|
||||||
--include-inactive-pairs
|
--include-inactive-pairs
|
||||||
Also download data from inactive pairs.
|
Also download data from inactive pairs.
|
||||||
|
--no-parallel-download
|
||||||
|
Disable parallel startup download. Only use this if
|
||||||
|
you experience issues.
|
||||||
--timerange TIMERANGE
|
--timerange TIMERANGE
|
||||||
Specify what timerange of data to use.
|
Specify what timerange of data to use.
|
||||||
--dl-trades Download trades instead of OHLCV data.
|
--dl-trades Download trades instead of OHLCV data.
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ usage: freqtrade edge [-h] [-v] [--no-color] [--logfile FILE] [-V] [-c PATH]
|
|||||||
[--data-format-ohlcv {json,jsongz,feather,parquet}]
|
[--data-format-ohlcv {json,jsongz,feather,parquet}]
|
||||||
[--max-open-trades INT] [--stake-amount STAKE_AMOUNT]
|
[--max-open-trades INT] [--stake-amount STAKE_AMOUNT]
|
||||||
[--fee FLOAT] [-p PAIRS [PAIRS ...]]
|
[--fee FLOAT] [-p PAIRS [PAIRS ...]]
|
||||||
[--stoplosses STOPLOSS_RANGE]
|
|
||||||
|
|
||||||
options:
|
options:
|
||||||
-h, --help show this help message and exit
|
-h, --help show this help message and exit
|
||||||
@@ -29,11 +28,6 @@ options:
|
|||||||
-p PAIRS [PAIRS ...], --pairs PAIRS [PAIRS ...]
|
-p PAIRS [PAIRS ...], --pairs PAIRS [PAIRS ...]
|
||||||
Limit command to these pairs. Pairs are space-
|
Limit command to these pairs. Pairs are space-
|
||||||
separated.
|
separated.
|
||||||
--stoplosses STOPLOSS_RANGE
|
|
||||||
Defines a range of stoploss values against which edge
|
|
||||||
will assess the strategy. The format is "min,max,step"
|
|
||||||
(without any space). Example:
|
|
||||||
`--stoplosses=-0.01,-0.1,-0.001`
|
|
||||||
|
|
||||||
Common arguments:
|
Common arguments:
|
||||||
-v, --verbose Verbose mode (-vv for more, -vvv to get all messages).
|
-v, --verbose Verbose mode (-vv for more, -vvv to get all messages).
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ usage: freqtrade hyperopt [-h] [-v] [--no-color] [--logfile FILE] [-V]
|
|||||||
[--random-state INT] [--min-trades INT]
|
[--random-state INT] [--min-trades INT]
|
||||||
[--hyperopt-loss NAME] [--disable-param-export]
|
[--hyperopt-loss NAME] [--disable-param-export]
|
||||||
[--ignore-missing-spaces] [--analyze-per-epoch]
|
[--ignore-missing-spaces] [--analyze-per-epoch]
|
||||||
|
[--early-stop INT]
|
||||||
|
|
||||||
options:
|
options:
|
||||||
-h, --help show this help message and exit
|
-h, --help show this help message and exit
|
||||||
@@ -43,7 +44,7 @@ options:
|
|||||||
Allow buying the same pair multiple times (position
|
Allow buying the same pair multiple times (position
|
||||||
stacking).
|
stacking).
|
||||||
--enable-protections, --enableprotections
|
--enable-protections, --enableprotections
|
||||||
Enable protections for backtesting.Will slow
|
Enable protections for backtesting. Will slow
|
||||||
backtesting down by a considerable amount, but will
|
backtesting down by a considerable amount, but will
|
||||||
include configured protections
|
include configured protections
|
||||||
--dry-run-wallet DRY_RUN_WALLET, --starting-balance DRY_RUN_WALLET
|
--dry-run-wallet DRY_RUN_WALLET, --starting-balance DRY_RUN_WALLET
|
||||||
@@ -87,6 +88,8 @@ options:
|
|||||||
Suppress errors for any requested Hyperopt spaces that
|
Suppress errors for any requested Hyperopt spaces that
|
||||||
do not contain any parameters.
|
do not contain any parameters.
|
||||||
--analyze-per-epoch Run populate_indicators once per epoch.
|
--analyze-per-epoch Run populate_indicators once per epoch.
|
||||||
|
--early-stop INT Early stop hyperopt if no improvement after (default:
|
||||||
|
0) epochs.
|
||||||
|
|
||||||
Common arguments:
|
Common arguments:
|
||||||
-v, --verbose Verbose mode (-vv for more, -vvv to get all messages).
|
-v, --verbose Verbose mode (-vv for more, -vvv to get all messages).
|
||||||
|
|||||||
@@ -1,11 +1,16 @@
|
|||||||
```
|
```
|
||||||
usage: freqtrade list-exchanges [-h] [-v] [--no-color] [--logfile FILE] [-V]
|
usage: freqtrade list-exchanges [-h] [-v] [--no-color] [--logfile FILE] [-V]
|
||||||
[-c PATH] [-d PATH] [--userdir PATH] [-1] [-a]
|
[-c PATH] [-d PATH] [--userdir PATH] [-1] [-a]
|
||||||
|
[--trading-mode {spot,margin,futures}]
|
||||||
|
[--dex-exchanges]
|
||||||
|
|
||||||
options:
|
options:
|
||||||
-h, --help show this help message and exit
|
-h, --help show this help message and exit
|
||||||
-1, --one-column Print output in one column.
|
-1, --one-column Print output in one column.
|
||||||
-a, --all Print all exchanges known to the ccxt library.
|
-a, --all Print all exchanges known to the ccxt library.
|
||||||
|
--trading-mode {spot,margin,futures}, --tradingmode {spot,margin,futures}
|
||||||
|
Select Trading mode
|
||||||
|
--dex-exchanges Print only DEX exchanges.
|
||||||
|
|
||||||
Common arguments:
|
Common arguments:
|
||||||
-v, --verbose Verbose mode (-vv for more, -vvv to get all messages).
|
-v, --verbose Verbose mode (-vv for more, -vvv to get all messages).
|
||||||
|
|||||||
@@ -11,15 +11,18 @@ usage: freqtrade lookahead-analysis [-h] [-v] [--no-color] [--logfile FILE]
|
|||||||
[--stake-amount STAKE_AMOUNT]
|
[--stake-amount STAKE_AMOUNT]
|
||||||
[--fee FLOAT] [-p PAIRS [PAIRS ...]]
|
[--fee FLOAT] [-p PAIRS [PAIRS ...]]
|
||||||
[--enable-protections]
|
[--enable-protections]
|
||||||
|
[--enable-dynamic-pairlist]
|
||||||
[--dry-run-wallet DRY_RUN_WALLET]
|
[--dry-run-wallet DRY_RUN_WALLET]
|
||||||
[--timeframe-detail TIMEFRAME_DETAIL]
|
[--timeframe-detail TIMEFRAME_DETAIL]
|
||||||
[--strategy-list STRATEGY_LIST [STRATEGY_LIST ...]]
|
[--strategy-list STRATEGY_LIST [STRATEGY_LIST ...]]
|
||||||
[--export {none,trades,signals}]
|
[--export {none,trades,signals}]
|
||||||
[--export-filename PATH]
|
[--backtest-filename PATH]
|
||||||
|
[--backtest-directory PATH]
|
||||||
[--freqai-backtest-live-models]
|
[--freqai-backtest-live-models]
|
||||||
[--minimum-trade-amount INT]
|
[--minimum-trade-amount INT]
|
||||||
[--targeted-trade-amount INT]
|
[--targeted-trade-amount INT]
|
||||||
[--lookahead-analysis-exportfilename LOOKAHEAD_ANALYSIS_EXPORTFILENAME]
|
[--lookahead-analysis-exportfilename LOOKAHEAD_ANALYSIS_EXPORTFILENAME]
|
||||||
|
[--allow-limit-orders]
|
||||||
|
|
||||||
options:
|
options:
|
||||||
-h, --help show this help message and exit
|
-h, --help show this help message and exit
|
||||||
@@ -42,9 +45,14 @@ options:
|
|||||||
Limit command to these pairs. Pairs are space-
|
Limit command to these pairs. Pairs are space-
|
||||||
separated.
|
separated.
|
||||||
--enable-protections, --enableprotections
|
--enable-protections, --enableprotections
|
||||||
Enable protections for backtesting.Will slow
|
Enable protections for backtesting. Will slow
|
||||||
backtesting down by a considerable amount, but will
|
backtesting down by a considerable amount, but will
|
||||||
include configured protections
|
include configured protections
|
||||||
|
--enable-dynamic-pairlist
|
||||||
|
Enables dynamic pairlist refreshes in backtesting. The
|
||||||
|
pairlist will be generated for each new candle if
|
||||||
|
you're using a pairlist handler that supports this
|
||||||
|
feature, for example, ShuffleFilter.
|
||||||
--dry-run-wallet DRY_RUN_WALLET, --starting-balance DRY_RUN_WALLET
|
--dry-run-wallet DRY_RUN_WALLET, --starting-balance DRY_RUN_WALLET
|
||||||
Starting balance, used for backtesting / hyperopt and
|
Starting balance, used for backtesting / hyperopt and
|
||||||
dry-runs.
|
dry-runs.
|
||||||
@@ -60,10 +68,15 @@ options:
|
|||||||
becomes `backtest-data-SampleStrategy.json`
|
becomes `backtest-data-SampleStrategy.json`
|
||||||
--export {none,trades,signals}
|
--export {none,trades,signals}
|
||||||
Export backtest results (default: trades).
|
Export backtest results (default: trades).
|
||||||
--export-filename PATH, --backtest-filename PATH
|
--backtest-filename PATH, --export-filename PATH
|
||||||
Use this filename for backtest results.Requires
|
Use this filename for backtest results.Example:
|
||||||
`--export` to be set as well. Example: `--export-filen
|
`--backtest-
|
||||||
ame=user_data/backtest_results/backtest_today.json`
|
filename=backtest_results_2020-09-27_16-20-48.json`.
|
||||||
|
Assumes either `user_data/backtest_results/` or
|
||||||
|
`--export-directory` as base directory.
|
||||||
|
--backtest-directory PATH, --export-directory PATH
|
||||||
|
Directory to use for backtest results. Example:
|
||||||
|
`--export-directory=user_data/backtest_results/`.
|
||||||
--freqai-backtest-live-models
|
--freqai-backtest-live-models
|
||||||
Run backtest with ready models.
|
Run backtest with ready models.
|
||||||
--minimum-trade-amount INT
|
--minimum-trade-amount INT
|
||||||
@@ -73,6 +86,8 @@ options:
|
|||||||
--lookahead-analysis-exportfilename LOOKAHEAD_ANALYSIS_EXPORTFILENAME
|
--lookahead-analysis-exportfilename LOOKAHEAD_ANALYSIS_EXPORTFILENAME
|
||||||
Use this csv-filename to store lookahead-analysis-
|
Use this csv-filename to store lookahead-analysis-
|
||||||
results
|
results
|
||||||
|
--allow-limit-orders Allow limit orders in lookahead analysis (could cause
|
||||||
|
false positives in lookahead analysis results).
|
||||||
|
|
||||||
Common arguments:
|
Common arguments:
|
||||||
-v, --verbose Verbose mode (-vv for more, -vvv to get all messages).
|
-v, --verbose Verbose mode (-vv for more, -vvv to get all messages).
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ positional arguments:
|
|||||||
backtesting-show Show past Backtest results
|
backtesting-show Show past Backtest results
|
||||||
backtesting-analysis
|
backtesting-analysis
|
||||||
Backtest Analysis module.
|
Backtest Analysis module.
|
||||||
edge Edge module.
|
edge Edge module. No longer part of Freqtrade
|
||||||
hyperopt Hyperopt module.
|
hyperopt Hyperopt module.
|
||||||
hyperopt-list List Hyperopt results
|
hyperopt-list List Hyperopt results
|
||||||
hyperopt-show Show details of Hyperopt results
|
hyperopt-show Show details of Hyperopt results
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ usage: freqtrade plot-dataframe [-h] [-v] [--no-color] [--logfile FILE] [-V]
|
|||||||
[--plot-limit INT] [--db-url PATH]
|
[--plot-limit INT] [--db-url PATH]
|
||||||
[--trade-source {DB,file}]
|
[--trade-source {DB,file}]
|
||||||
[--export {none,trades,signals}]
|
[--export {none,trades,signals}]
|
||||||
[--export-filename PATH]
|
[--backtest-filename PATH]
|
||||||
[--timerange TIMERANGE] [-i TIMEFRAME]
|
[--timerange TIMERANGE] [-i TIMEFRAME]
|
||||||
[--no-trades]
|
[--no-trades]
|
||||||
|
|
||||||
@@ -38,10 +38,12 @@ options:
|
|||||||
(backtest file)) Default: file
|
(backtest file)) Default: file
|
||||||
--export {none,trades,signals}
|
--export {none,trades,signals}
|
||||||
Export backtest results (default: trades).
|
Export backtest results (default: trades).
|
||||||
--export-filename PATH, --backtest-filename PATH
|
--backtest-filename PATH, --export-filename PATH
|
||||||
Use this filename for backtest results.Requires
|
Use this filename for backtest results.Example:
|
||||||
`--export` to be set as well. Example: `--export-filen
|
`--backtest-
|
||||||
ame=user_data/backtest_results/backtest_today.json`
|
filename=backtest_results_2020-09-27_16-20-48.json`.
|
||||||
|
Assumes either `user_data/backtest_results/` or
|
||||||
|
`--export-directory` as base directory.
|
||||||
--timerange TIMERANGE
|
--timerange TIMERANGE
|
||||||
Specify what timerange of data to use.
|
Specify what timerange of data to use.
|
||||||
-i TIMEFRAME, --timeframe TIMEFRAME
|
-i TIMEFRAME, --timeframe TIMEFRAME
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ usage: freqtrade plot-profit [-h] [-v] [--no-color] [--logfile FILE] [-V]
|
|||||||
[--freqaimodel NAME] [--freqaimodel-path PATH]
|
[--freqaimodel NAME] [--freqaimodel-path PATH]
|
||||||
[-p PAIRS [PAIRS ...]] [--timerange TIMERANGE]
|
[-p PAIRS [PAIRS ...]] [--timerange TIMERANGE]
|
||||||
[--export {none,trades,signals}]
|
[--export {none,trades,signals}]
|
||||||
[--export-filename PATH] [--db-url PATH]
|
[--backtest-filename PATH] [--db-url PATH]
|
||||||
[--trade-source {DB,file}] [-i TIMEFRAME]
|
[--trade-source {DB,file}] [-i TIMEFRAME]
|
||||||
[--auto-open]
|
[--auto-open]
|
||||||
|
|
||||||
@@ -19,10 +19,12 @@ options:
|
|||||||
Specify what timerange of data to use.
|
Specify what timerange of data to use.
|
||||||
--export {none,trades,signals}
|
--export {none,trades,signals}
|
||||||
Export backtest results (default: trades).
|
Export backtest results (default: trades).
|
||||||
--export-filename PATH, --backtest-filename PATH
|
--backtest-filename PATH, --export-filename PATH
|
||||||
Use this filename for backtest results.Requires
|
Use this filename for backtest results.Example:
|
||||||
`--export` to be set as well. Example: `--export-filen
|
`--backtest-
|
||||||
ame=user_data/backtest_results/backtest_today.json`
|
filename=backtest_results_2020-09-27_16-20-48.json`.
|
||||||
|
Assumes either `user_data/backtest_results/` or
|
||||||
|
`--export-directory` as base directory.
|
||||||
--db-url PATH Override trades database URL, this is useful in custom
|
--db-url PATH Override trades database URL, this is useful in custom
|
||||||
deployments (default: `sqlite:///tradesv3.sqlite` for
|
deployments (default: `sqlite:///tradesv3.sqlite` for
|
||||||
Live Run mode, `sqlite:///tradesv3.dryrun.sqlite` for
|
Live Run mode, `sqlite:///tradesv3.dryrun.sqlite` for
|
||||||
|
|||||||
@@ -180,7 +180,7 @@ Mandatory parameters are marked as **Required**, which means that they are requi
|
|||||||
| `minimal_roi` | **Required.** Set the threshold as ratio the bot will use to exit a trade. [More information below](#understand-minimal_roi). [Strategy Override](#parameters-in-the-strategy). <br> **Datatype:** Dict
|
| `minimal_roi` | **Required.** Set the threshold as ratio the bot will use to exit a trade. [More information below](#understand-minimal_roi). [Strategy Override](#parameters-in-the-strategy). <br> **Datatype:** Dict
|
||||||
| `stoploss` | **Required.** Value as ratio of the stoploss used by the bot. More details in the [stoploss documentation](stoploss.md). [Strategy Override](#parameters-in-the-strategy). <br> **Datatype:** Float (as ratio)
|
| `stoploss` | **Required.** Value as ratio of the stoploss used by the bot. More details in the [stoploss documentation](stoploss.md). [Strategy Override](#parameters-in-the-strategy). <br> **Datatype:** Float (as ratio)
|
||||||
| `trailing_stop` | Enables trailing stoploss (based on `stoploss` in either configuration or strategy file). More details in the [stoploss documentation](stoploss.md#trailing-stop-loss). [Strategy Override](#parameters-in-the-strategy). <br> **Datatype:** Boolean
|
| `trailing_stop` | Enables trailing stoploss (based on `stoploss` in either configuration or strategy file). More details in the [stoploss documentation](stoploss.md#trailing-stop-loss). [Strategy Override](#parameters-in-the-strategy). <br> **Datatype:** Boolean
|
||||||
| `trailing_stop_positive` | Changes stoploss once profit has been reached. More details in the [stoploss documentation](stoploss.md#trailing-stop-loss-custom-positive-loss). [Strategy Override](#parameters-in-the-strategy). <br> **Datatype:** Float
|
| `trailing_stop_positive` | Changes stoploss once profit has been reached. More details in the [stoploss documentation](stoploss.md#trailing-stop-loss-different-positive-loss). [Strategy Override](#parameters-in-the-strategy). <br> **Datatype:** Float
|
||||||
| `trailing_stop_positive_offset` | Offset on when to apply `trailing_stop_positive`. Percentage value which should be positive. More details in the [stoploss documentation](stoploss.md#trailing-stop-loss-only-once-the-trade-has-reached-a-certain-offset). [Strategy Override](#parameters-in-the-strategy). <br>*Defaults to `0.0` (no offset).* <br> **Datatype:** Float
|
| `trailing_stop_positive_offset` | Offset on when to apply `trailing_stop_positive`. Percentage value which should be positive. More details in the [stoploss documentation](stoploss.md#trailing-stop-loss-only-once-the-trade-has-reached-a-certain-offset). [Strategy Override](#parameters-in-the-strategy). <br>*Defaults to `0.0` (no offset).* <br> **Datatype:** Float
|
||||||
| `trailing_only_offset_is_reached` | Only apply trailing stoploss when the offset is reached. [stoploss documentation](stoploss.md). [Strategy Override](#parameters-in-the-strategy). <br>*Defaults to `false`.* <br> **Datatype:** Boolean
|
| `trailing_only_offset_is_reached` | Only apply trailing stoploss when the offset is reached. [stoploss documentation](stoploss.md). [Strategy Override](#parameters-in-the-strategy). <br>*Defaults to `false`.* <br> **Datatype:** Boolean
|
||||||
| `fee` | Fee used during backtesting / dry-runs. Should normally not be configured, which has freqtrade fall back to the exchange default fee. Set as ratio (e.g. 0.001 = 0.1%). Fee is applied twice for each trade, once when buying, once when selling. <br> **Datatype:** Float (as ratio)
|
| `fee` | Fee used during backtesting / dry-runs. Should normally not be configured, which has freqtrade fall back to the exchange default fee. Set as ratio (e.g. 0.001 = 0.1%). Fee is applied twice for each trade, once when buying, once when selling. <br> **Datatype:** Float (as ratio)
|
||||||
@@ -234,7 +234,6 @@ Mandatory parameters are marked as **Required**, which means that they are requi
|
|||||||
| `exchange.only_from_ccxt` | Prevent data-download from data.binance.vision. Leaving this as false can greatly speed up downloads, but may be problematic if the site is not available.<br>*Defaults to `false`*<br> **Datatype:** Boolean
|
| `exchange.only_from_ccxt` | Prevent data-download from data.binance.vision. Leaving this as false can greatly speed up downloads, but may be problematic if the site is not available.<br>*Defaults to `false`*<br> **Datatype:** Boolean
|
||||||
| `experimental.block_bad_exchanges` | Block exchanges known to not work with freqtrade. Leave on default unless you want to test if that exchange works now. <br>*Defaults to `true`.* <br> **Datatype:** Boolean
|
| `experimental.block_bad_exchanges` | Block exchanges known to not work with freqtrade. Leave on default unless you want to test if that exchange works now. <br>*Defaults to `true`.* <br> **Datatype:** Boolean
|
||||||
| | **Plugins**
|
| | **Plugins**
|
||||||
| `edge.*` | Please refer to [edge configuration document](edge.md) for detailed explanation of all possible configuration options.
|
|
||||||
| `pairlists` | Define one or more pairlists to be used. [More information](plugins.md#pairlists-and-pairlist-handlers). <br>*Defaults to `StaticPairList`.* <br> **Datatype:** List of Dicts
|
| `pairlists` | Define one or more pairlists to be used. [More information](plugins.md#pairlists-and-pairlist-handlers). <br>*Defaults to `StaticPairList`.* <br> **Datatype:** List of Dicts
|
||||||
| | **Telegram**
|
| | **Telegram**
|
||||||
| `telegram.enabled` | Enable the usage of Telegram. <br> **Datatype:** Boolean
|
| `telegram.enabled` | Enable the usage of Telegram. <br> **Datatype:** Boolean
|
||||||
@@ -567,8 +566,8 @@ Configuration:
|
|||||||
|
|
||||||
### Understand order_time_in_force
|
### Understand order_time_in_force
|
||||||
|
|
||||||
The `order_time_in_force` configuration parameter defines the policy by which the order
|
The `order_time_in_force` configuration parameter defines the policy by which the order is executed on the exchange.
|
||||||
is executed on the exchange. Three commonly used time in force are:
|
Commonly used time in force are:
|
||||||
|
|
||||||
**GTC (Good Till Canceled):**
|
**GTC (Good Till Canceled):**
|
||||||
|
|
||||||
@@ -590,11 +589,13 @@ is automatically cancelled by the exchange.
|
|||||||
Post only order. The order is either placed as a maker order, or it is canceled.
|
Post only order. The order is either placed as a maker order, or it is canceled.
|
||||||
This means the order must be placed on orderbook for at least time in an unfilled state.
|
This means the order must be placed on orderbook for at least time in an unfilled state.
|
||||||
|
|
||||||
|
Please check the [Exchange documentation](exchanges.md) for supported time in force values for your exchange.
|
||||||
|
|
||||||
#### time_in_force config
|
#### time_in_force config
|
||||||
|
|
||||||
The `order_time_in_force` parameter contains a dict with entry and exit time in force policy values.
|
The `order_time_in_force` parameter contains a dict with entry and exit time in force policy values.
|
||||||
This can be set in the configuration file or in the strategy.
|
This can be set in the configuration file or in the strategy.
|
||||||
Values set in the configuration file overwrites values set in the strategy.
|
Values set in the configuration file overwrite values from in the strategy, following the regular [precedence rules](#configuration-option-prevalence).
|
||||||
|
|
||||||
The possible values are: `GTC` (default), `FOK` or `IOC`.
|
The possible values are: `GTC` (default), `FOK` or `IOC`.
|
||||||
|
|
||||||
@@ -606,9 +607,9 @@ The possible values are: `GTC` (default), `FOK` or `IOC`.
|
|||||||
```
|
```
|
||||||
|
|
||||||
!!! Warning
|
!!! Warning
|
||||||
This is ongoing work. For now, it is supported only for binance, gate and kucoin.
|
|
||||||
Please don't change the default value unless you know what you are doing and have researched the impact of using different values for your particular exchange.
|
Please don't change the default value unless you know what you are doing and have researched the impact of using different values for your particular exchange.
|
||||||
|
|
||||||
|
|
||||||
### Fiat conversion
|
### Fiat conversion
|
||||||
|
|
||||||
Freqtrade uses the Coingecko API to convert the coin value to it's corresponding fiat value for the Telegram reports.
|
Freqtrade uses the Coingecko API to convert the coin value to it's corresponding fiat value for the Telegram reports.
|
||||||
@@ -672,7 +673,7 @@ Should you experience problems you suspect are caused by websockets, you can dis
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Should you be required to use a proxy, please refer to the [proxy section](#using-proxy-with-freqtrade) for more information.
|
Should you be required to use a proxy, please refer to the [proxy section](#using-a-proxy-with-freqtrade) for more information.
|
||||||
|
|
||||||
!!! Info "Rollout"
|
!!! Info "Rollout"
|
||||||
We're implementing this out slowly, ensuring stability of your bots.
|
We're implementing this out slowly, ensuring stability of your bots.
|
||||||
|
|||||||
@@ -93,3 +93,8 @@ Please use the [`convert-data` subcommand](data-download.md#sub-command-convert-
|
|||||||
|
|
||||||
Configuring syslog and journald via `--logfile systemd` and `--logfile journald` respectively has been deprecated in 2025.3.
|
Configuring syslog and journald via `--logfile systemd` and `--logfile journald` respectively has been deprecated in 2025.3.
|
||||||
Please use configuration based [log setup](advanced-setup.md#advanced-logging) instead.
|
Please use configuration based [log setup](advanced-setup.md#advanced-logging) instead.
|
||||||
|
|
||||||
|
## Removal of the edge module
|
||||||
|
|
||||||
|
The edge module has been deprecated in 2023.9 and removed in 2025.6.
|
||||||
|
All functionalities of edge have been removed, and having edge configured will result in an error.
|
||||||
|
|||||||
+23
-1
@@ -304,6 +304,13 @@ The `IProtection` parent class provides a helper method for this in `calculate_l
|
|||||||
|
|
||||||
Most exchanges supported by CCXT should work out of the box.
|
Most exchanges supported by CCXT should work out of the box.
|
||||||
|
|
||||||
|
If you need to implement a specific exchange class, these are found in the `freqtrade/exchange` source folder. You'll also need to add the import to `freqtrade/exchange/__init__.py` to make the loading logic aware of the new exchange.
|
||||||
|
We recommend looking at existing exchange implementations to get an idea of what might be required.
|
||||||
|
|
||||||
|
!!! Warning
|
||||||
|
Implementing and testing an exchange can be a lot of trial and error, so please bear this in mind.
|
||||||
|
You should also have some development experience, as this is not a beginner task.
|
||||||
|
|
||||||
To quickly test the public endpoints of an exchange, add a configuration for your exchange to `tests/exchange_online/conftest.py` and run these tests with `pytest --longrun tests/exchange_online/test_ccxt_compat.py`.
|
To quickly test the public endpoints of an exchange, add a configuration for your exchange to `tests/exchange_online/conftest.py` and run these tests with `pytest --longrun tests/exchange_online/test_ccxt_compat.py`.
|
||||||
Completing these tests successfully a good basis point (it's a requirement, actually), however these won't guarantee correct exchange functioning, as this only tests public endpoints, but no private endpoint (like generate order or similar).
|
Completing these tests successfully a good basis point (it's a requirement, actually), however these won't guarantee correct exchange functioning, as this only tests public endpoints, but no private endpoint (like generate order or similar).
|
||||||
|
|
||||||
@@ -401,6 +408,22 @@ jupyter nbconvert --ClearOutputPreprocessor.enabled=True --inplace freqtrade/tem
|
|||||||
jupyter nbconvert --ClearOutputPreprocessor.enabled=True --to markdown freqtrade/templates/strategy_analysis_example.ipynb --stdout > docs/strategy_analysis_example.md
|
jupyter nbconvert --ClearOutputPreprocessor.enabled=True --to markdown freqtrade/templates/strategy_analysis_example.ipynb --stdout > docs/strategy_analysis_example.md
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Backtest documentation results
|
||||||
|
|
||||||
|
To generate backtest outputs, please use the following commands:
|
||||||
|
|
||||||
|
``` bash
|
||||||
|
# Assume a dedicated user directory for this output
|
||||||
|
freqtrade create-userdir --userdir user_data_bttest/
|
||||||
|
# set can_short = True
|
||||||
|
sed -i "s/can_short: bool = False/can_short: bool = True/" user_data_bttest/strategies/sample_strategy.py
|
||||||
|
|
||||||
|
freqtrade download-data --timerange 20250625-20250801 --config tests/testdata/config.tests.usdt.json --userdir user_data_bttest/ -t 5m
|
||||||
|
|
||||||
|
freqtrade backtesting --config tests/testdata/config.tests.usdt.json -s SampleStrategy --userdir user_data_bttest/ --cache none --timerange 20250701-20250801
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
## Continuous integration
|
## Continuous integration
|
||||||
|
|
||||||
This documents some decisions taken for the CI Pipeline.
|
This documents some decisions taken for the CI Pipeline.
|
||||||
@@ -411,7 +434,6 @@ This documents some decisions taken for the CI Pipeline.
|
|||||||
* Docker images contain a file, `/freqtrade/freqtrade_commit` containing the commit this image is based of.
|
* Docker images contain a file, `/freqtrade/freqtrade_commit` containing the commit this image is based of.
|
||||||
* Full docker image rebuilds are run once a week via schedule.
|
* Full docker image rebuilds are run once a week via schedule.
|
||||||
* Deployments run on ubuntu.
|
* Deployments run on ubuntu.
|
||||||
* ta-lib binaries are contained in the build_helpers directory to avoid fails related to external unavailability.
|
|
||||||
* All tests must pass for a PR to be merged to `stable` or `develop`.
|
* All tests must pass for a PR to be merged to `stable` or `develop`.
|
||||||
|
|
||||||
## Creating a release
|
## Creating a release
|
||||||
|
|||||||
-300
@@ -1,300 +0,0 @@
|
|||||||
# Edge positioning
|
|
||||||
|
|
||||||
The `Edge Positioning` module uses probability to calculate your win rate and risk reward ratio. It will use these statistics to control your strategy trade entry points, position size and, stoploss.
|
|
||||||
|
|
||||||
!!! Danger "Deprecated functionality"
|
|
||||||
`Edge positioning` (or short Edge) is currently in maintenance mode only (we keep existing functionality alive) and should be considered as deprecated.
|
|
||||||
It will currently not receive new features until either someone stepped forward to take up ownership of that module - or we'll decide to remove edge from freqtrade.
|
|
||||||
|
|
||||||
!!! Warning
|
|
||||||
When using `Edge positioning` with a dynamic whitelist (VolumePairList), make sure to also use `AgeFilter` and set it to at least `calculate_since_number_of_days` to avoid problems with missing data.
|
|
||||||
|
|
||||||
!!! Note
|
|
||||||
`Edge Positioning` only considers *its own* buy/sell/stoploss signals. It ignores the stoploss, trailing stoploss, and ROI settings in the strategy configuration file.
|
|
||||||
`Edge Positioning` improves the performance of some trading strategies and *decreases* the performance of others.
|
|
||||||
|
|
||||||
|
|
||||||
## Introduction
|
|
||||||
|
|
||||||
Trading strategies are not perfect. They are frameworks that are susceptible to the market and its indicators. Because the market is not at all predictable, sometimes a strategy will win and sometimes the same strategy will lose.
|
|
||||||
|
|
||||||
To obtain an edge in the market, a strategy has to make more money than it loses. Making money in trading is not only about *how often* the strategy makes or loses money.
|
|
||||||
|
|
||||||
!!! tip "It doesn't matter how often, but how much!"
|
|
||||||
A bad strategy might make 1 penny in *ten* transactions but lose 1 dollar in *one* transaction. If one only checks the number of winning trades, it would be misleading to think that the strategy is actually making a profit.
|
|
||||||
|
|
||||||
The Edge Positioning module seeks to improve a strategy's winning probability and the money that the strategy will make *on the long run*.
|
|
||||||
|
|
||||||
We raise the following question[^1]:
|
|
||||||
|
|
||||||
!!! Question "Which trade is a better option?"
|
|
||||||
a) A trade with 80% of chance of losing 100\$ and 20% chance of winning 200\$<br/>
|
|
||||||
b) A trade with 100% of chance of losing 30\$
|
|
||||||
|
|
||||||
???+ Info "Answer"
|
|
||||||
The expected value of *a)* is smaller than the expected value of *b)*.<br/>
|
|
||||||
Hence, *b*) represents a smaller loss in the long run.<br/>
|
|
||||||
However, the answer is: *it depends*
|
|
||||||
|
|
||||||
Another way to look at it is to ask a similar question:
|
|
||||||
|
|
||||||
!!! Question "Which trade is a better option?"
|
|
||||||
a) A trade with 80% of chance of winning 100\$ and 20% chance of losing 200\$<br/>
|
|
||||||
b) A trade with 100% of chance of winning 30\$
|
|
||||||
|
|
||||||
Edge positioning tries to answer the hard questions about risk/reward and position size automatically, seeking to minimizes the chances of losing of a given strategy.
|
|
||||||
|
|
||||||
### Trading, winning and losing
|
|
||||||
|
|
||||||
Let's call $o$ the return of a single transaction $o$ where $o \in \mathbb{R}$. The collection $O = \{o_1, o_2, ..., o_N\}$ is the set of all returns of transactions made during a trading session. We say that $N$ is the cardinality of $O$, or, in lay terms, it is the number of transactions made in a trading session.
|
|
||||||
|
|
||||||
!!! Example
|
|
||||||
In a session where a strategy made three transactions we can say that $O = \{3.5, -1, 15\}$. That means that $N = 3$ and $o_1 = 3.5$, $o_2 = -1$, $o_3 = 15$.
|
|
||||||
|
|
||||||
A winning trade is a trade where a strategy *made* money. Making money means that the strategy closed the position in a value that returned a profit, after all deducted fees. Formally, a winning trade will have a return $o_i > 0$. Similarly, a losing trade will have a return $o_j \leq 0$. With that, we can discover the set of all winning trades, $T_{win}$, as follows:
|
|
||||||
|
|
||||||
$$ T_{win} = \{ o \in O | o > 0 \} $$
|
|
||||||
|
|
||||||
Similarly, we can discover the set of losing trades $T_{lose}$ as follows:
|
|
||||||
|
|
||||||
$$ T_{lose} = \{o \in O | o \leq 0\} $$
|
|
||||||
|
|
||||||
!!! Example
|
|
||||||
In a section where a strategy made four transactions $O = \{3.5, -1, 15, 0\}$:<br>
|
|
||||||
$T_{win} = \{3.5, 15\}$<br>
|
|
||||||
$T_{lose} = \{-1, 0\}$<br>
|
|
||||||
|
|
||||||
### Win Rate and Lose Rate
|
|
||||||
|
|
||||||
The win rate $W$ is the proportion of winning trades with respect to all the trades made by a strategy. We use the following function to compute the win rate:
|
|
||||||
|
|
||||||
$$W = \frac{|T_{win}|}{N}$$
|
|
||||||
|
|
||||||
Where $W$ is the win rate, $N$ is the number of trades and, $T_{win}$ is the set of all trades where the strategy made money.
|
|
||||||
|
|
||||||
Similarly, we can compute the rate of losing trades:
|
|
||||||
|
|
||||||
$$
|
|
||||||
L = \frac{|T_{lose}|}{N}
|
|
||||||
$$
|
|
||||||
|
|
||||||
Where $L$ is the lose rate, $N$ is the amount of trades made and, $T_{lose}$ is the set of all trades where the strategy lost money. Note that the above formula is the same as calculating $L = 1 – W$ or $W = 1 – L$
|
|
||||||
|
|
||||||
### Risk Reward Ratio
|
|
||||||
|
|
||||||
Risk Reward Ratio ($R$) is a formula used to measure the expected gains of a given investment against the risk of loss. It is basically what you potentially win divided by what you potentially lose. Formally:
|
|
||||||
|
|
||||||
$$ R = \frac{\text{potential_profit}}{\text{potential_loss}} $$
|
|
||||||
|
|
||||||
???+ Example "Worked example of $R$ calculation"
|
|
||||||
Let's say that you think that the price of *stonecoin* today is 10.0\$. You believe that, because they will start mining stonecoin, it will go up to 15.0\$ tomorrow. There is the risk that the stone is too hard, and the GPUs can't mine it, so the price might go to 0\$ tomorrow. You are planning to invest 100\$, which will give you 10 shares (100 / 10).
|
|
||||||
|
|
||||||
Your potential profit is calculated as:
|
|
||||||
|
|
||||||
$\begin{aligned}
|
|
||||||
\text{potential_profit} &= (\text{potential_price} - \text{entry_price}) * \frac{\text{investment}}{\text{entry_price}} \\
|
|
||||||
&= (15 - 10) * (100 / 10) \\
|
|
||||||
&= 50
|
|
||||||
\end{aligned}$
|
|
||||||
|
|
||||||
Since the price might go to 0\$, the 100\$ dollars invested could turn into 0.
|
|
||||||
|
|
||||||
We do however use a stoploss of 15% - so in the worst case, we'll sell 15% below entry price (or at 8.5$\).
|
|
||||||
|
|
||||||
$\begin{aligned}
|
|
||||||
\text{potential_loss} &= (\text{entry_price} - \text{stoploss}) * \frac{\text{investment}}{\text{entry_price}} \\
|
|
||||||
&= (10 - 8.5) * (100 / 10)\\
|
|
||||||
&= 15
|
|
||||||
\end{aligned}$
|
|
||||||
|
|
||||||
We can compute the Risk Reward Ratio as follows:
|
|
||||||
|
|
||||||
$\begin{aligned}
|
|
||||||
R &= \frac{\text{potential_profit}}{\text{potential_loss}}\\
|
|
||||||
&= \frac{50}{15}\\
|
|
||||||
&= 3.33
|
|
||||||
\end{aligned}$<br>
|
|
||||||
What it effectively means is that the strategy have the potential to make 3.33\$ for each 1\$ invested.
|
|
||||||
|
|
||||||
On a long horizon, that is, on many trades, we can calculate the risk reward by dividing the strategy' average profit on winning trades by the strategy' average loss on losing trades. We can calculate the average profit, $\mu_{win}$, as follows:
|
|
||||||
|
|
||||||
$$ \text{average_profit} = \mu_{win} = \frac{\text{sum_of_profits}}{\text{count_winning_trades}} = \frac{\sum^{o \in T_{win}} o}{|T_{win}|} $$
|
|
||||||
|
|
||||||
Similarly, we can calculate the average loss, $\mu_{lose}$, as follows:
|
|
||||||
|
|
||||||
$$ \text{average_loss} = \mu_{lose} = \frac{\text{sum_of_losses}}{\text{count_losing_trades}} = \frac{\sum^{o \in T_{lose}} o}{|T_{lose}|} $$
|
|
||||||
|
|
||||||
Finally, we can calculate the Risk Reward ratio, $R$, as follows:
|
|
||||||
|
|
||||||
$$ R = \frac{\text{average_profit}}{\text{average_loss}} = \frac{\mu_{win}}{\mu_{lose}}\\ $$
|
|
||||||
|
|
||||||
|
|
||||||
???+ Example "Worked example of $R$ calculation using mean profit/loss"
|
|
||||||
Let's say the strategy that we are using makes an average win $\mu_{win} = 2.06$ and an average loss $\mu_{loss} = 4.11$.<br>
|
|
||||||
We calculate the risk reward ratio as follows:<br>
|
|
||||||
$R = \frac{\mu_{win}}{\mu_{loss}} = \frac{2.06}{4.11} = 0.5012...$
|
|
||||||
|
|
||||||
|
|
||||||
### Expectancy
|
|
||||||
|
|
||||||
By combining the Win Rate $W$ and the Risk Reward ratio $R$ to create an expectancy ratio $E$. A expectance ratio is the expected return of the investment made in a trade. We can compute the value of $E$ as follows:
|
|
||||||
|
|
||||||
$$E = R * W - L$$
|
|
||||||
|
|
||||||
!!! Example "Calculating $E$"
|
|
||||||
Let's say that a strategy has a win rate $W = 0.28$ and a risk reward ratio $R = 5$. What this means is that the strategy is expected to make 5 times the investment around on 28% of the trades it makes. Working out the example:<br>
|
|
||||||
$E = R * W - L = 5 * 0.28 - 0.72 = 0.68$
|
|
||||||
<br>
|
|
||||||
|
|
||||||
The expectancy worked out in the example above means that, on average, this strategy' trades will return 1.68 times the size of its losses. Said another way, the strategy makes 1.68\$ for every 1\$ it loses, on average.
|
|
||||||
|
|
||||||
This is important for two reasons: First, it may seem obvious, but you know right away that you have a positive return. Second, you now have a number you can compare to other candidate systems to make decisions about which ones you employ.
|
|
||||||
|
|
||||||
It is important to remember that any system with an expectancy greater than 0 is profitable using past data. The key is finding one that will be profitable in the future.
|
|
||||||
|
|
||||||
You can also use this value to evaluate the effectiveness of modifications to this system.
|
|
||||||
|
|
||||||
!!! Note
|
|
||||||
It's important to keep in mind that Edge is testing your expectancy using historical data, there's no guarantee that you will have a similar edge in the future. It's still vital to do this testing in order to build confidence in your methodology but be wary of "curve-fitting" your approach to the historical data as things are unlikely to play out the exact same way for future trades.
|
|
||||||
|
|
||||||
## How does it work?
|
|
||||||
|
|
||||||
Edge combines dynamic stoploss, dynamic positions, and whitelist generation into one isolated module which is then applied to the trading strategy. If enabled in config, Edge will go through historical data with a range of stoplosses in order to find buy and sell/stoploss signals. It then calculates win rate and expectancy over *N* trades for each stoploss. Here is an example:
|
|
||||||
|
|
||||||
| Pair | Stoploss | Win Rate | Risk Reward Ratio | Expectancy |
|
|
||||||
|----------|:-------------:|-------------:|------------------:|-----------:|
|
|
||||||
| XZC/ETH | -0.01 | 0.50 |1.176384 | 0.088 |
|
|
||||||
| XZC/ETH | -0.02 | 0.51 |1.115941 | 0.079 |
|
|
||||||
| XZC/ETH | -0.03 | 0.52 |1.359670 | 0.228 |
|
|
||||||
| XZC/ETH | -0.04 | 0.51 |1.234539 | 0.117 |
|
|
||||||
|
|
||||||
The goal here is to find the best stoploss for the strategy in order to have the maximum expectancy. In the above example stoploss at $3%$ leads to the maximum expectancy according to historical data.
|
|
||||||
|
|
||||||
Edge module then forces stoploss value it evaluated to your strategy dynamically.
|
|
||||||
|
|
||||||
### Position size
|
|
||||||
|
|
||||||
Edge dictates the amount at stake for each trade to the bot according to the following factors:
|
|
||||||
|
|
||||||
- Allowed capital at risk
|
|
||||||
- Stoploss
|
|
||||||
|
|
||||||
Allowed capital at risk is calculated as follows:
|
|
||||||
|
|
||||||
```
|
|
||||||
Allowed capital at risk = (Capital available_percentage) X (Allowed risk per trade)
|
|
||||||
```
|
|
||||||
|
|
||||||
Stoploss is calculated as described above with respect to historical data.
|
|
||||||
|
|
||||||
The position size is calculated as follows:
|
|
||||||
|
|
||||||
```
|
|
||||||
Position size = (Allowed capital at risk) / Stoploss
|
|
||||||
```
|
|
||||||
|
|
||||||
Example:
|
|
||||||
|
|
||||||
Let's say the stake currency is **ETH** and there is $10$ **ETH** on the wallet. The capital available percentage is $50%$ and the allowed risk per trade is $1\%$. Thus, the available capital for trading is $10 * 0.5 = 5$ **ETH** and the allowed capital at risk would be $5 * 0.01 = 0.05$ **ETH**.
|
|
||||||
|
|
||||||
- **Trade 1:** The strategy detects a new buy signal in the **XLM/ETH** market. `Edge Positioning` calculates a stoploss of $2\%$ and a position of $0.05 / 0.02 = 2.5$ **ETH**. The bot takes a position of $2.5$ **ETH** in the **XLM/ETH** market.
|
|
||||||
|
|
||||||
- **Trade 2:** The strategy detects a buy signal on the **BTC/ETH** market while **Trade 1** is still open. `Edge Positioning` calculates the stoploss of $4\%$ on this market. Thus, **Trade 2** position size is $0.05 / 0.04 = 1.25$ **ETH**.
|
|
||||||
|
|
||||||
!!! Tip "Available Capital $\neq$ Available in wallet"
|
|
||||||
The available capital for trading didn't change in **Trade 2** even with **Trade 1** still open. The available capital **is not** the free amount in the wallet.
|
|
||||||
|
|
||||||
- **Trade 3:** The strategy detects a buy signal in the **ADA/ETH** market. `Edge Positioning` calculates a stoploss of $1\%$ and a position of $0.05 / 0.01 = 5$ **ETH**. Since **Trade 1** has $2.5$ **ETH** blocked and **Trade 2** has $1.25$ **ETH** blocked, there is only $5 - 1.25 - 2.5 = 1.25$ **ETH** available. Hence, the position size of **Trade 3** is $1.25$ **ETH**.
|
|
||||||
|
|
||||||
!!! Tip "Available Capital Updates"
|
|
||||||
The available capital does not change before a position is sold. After a trade is closed the Available Capital goes up if the trade was profitable or goes down if the trade was a loss.
|
|
||||||
|
|
||||||
- The strategy detects a sell signal in the **XLM/ETH** market. The bot exits **Trade 1** for a profit of $1$ **ETH**. The total capital in the wallet becomes $11$ **ETH** and the available capital for trading becomes $5.5$ **ETH**.
|
|
||||||
|
|
||||||
- **Trade 4** The strategy detects a new buy signal int the **XLM/ETH** market. `Edge Positioning` calculates the stoploss of $2\%$, and the position size of $0.055 / 0.02 = 2.75$ **ETH**.
|
|
||||||
|
|
||||||
## Edge command reference
|
|
||||||
|
|
||||||
--8<-- "commands/edge.md"
|
|
||||||
|
|
||||||
## Configurations
|
|
||||||
|
|
||||||
Edge module has following configuration options:
|
|
||||||
|
|
||||||
| Parameter | Description |
|
|
||||||
|------------|-------------|
|
|
||||||
| `enabled` | If true, then Edge will run periodically. <br>*Defaults to `false`.* <br> **Datatype:** Boolean
|
|
||||||
| `process_throttle_secs` | How often should Edge run in seconds. <br>*Defaults to `3600` (once per hour).* <br> **Datatype:** Integer
|
|
||||||
| `calculate_since_number_of_days` | Number of days of data against which Edge calculates Win Rate, Risk Reward and Expectancy. <br> **Note** that it downloads historical data so increasing this number would lead to slowing down the bot. <br>*Defaults to `7`.* <br> **Datatype:** Integer
|
|
||||||
| `allowed_risk` | Ratio of allowed risk per trade. <br>*Defaults to `0.01` (1%)).* <br> **Datatype:** Float
|
|
||||||
| `stoploss_range_min` | Minimum stoploss. <br>*Defaults to `-0.01`.* <br> **Datatype:** Float
|
|
||||||
| `stoploss_range_max` | Maximum stoploss. <br>*Defaults to `-0.10`.* <br> **Datatype:** Float
|
|
||||||
| `stoploss_range_step` | As an example if this is set to -0.01 then Edge will test the strategy for `[-0.01, -0,02, -0,03 ..., -0.09, -0.10]` ranges. <br> **Note** than having a smaller step means having a bigger range which could lead to slow calculation. <br> If you set this parameter to -0.001, you then slow down the Edge calculation by a factor of 10. <br>*Defaults to `-0.001`.* <br> **Datatype:** Float
|
|
||||||
| `minimum_winrate` | It filters out pairs which don't have at least minimum_winrate. <br>This comes handy if you want to be conservative and don't comprise win rate in favour of risk reward ratio. <br>*Defaults to `0.60`.* <br> **Datatype:** Float
|
|
||||||
| `minimum_expectancy` | It filters out pairs which have the expectancy lower than this number. <br>Having an expectancy of 0.20 means if you put 10\$ on a trade you expect a 12\$ return. <br>*Defaults to `0.20`.* <br> **Datatype:** Float
|
|
||||||
| `min_trade_number` | When calculating *W*, *R* and *E* (expectancy) against historical data, you always want to have a minimum number of trades. The more this number is the more Edge is reliable. <br>Having a win rate of 100% on a single trade doesn't mean anything at all. But having a win rate of 70% over past 100 trades means clearly something. <br>*Defaults to `10` (it is highly recommended not to decrease this number).* <br> **Datatype:** Integer
|
|
||||||
| `max_trade_duration_minute` | Edge will filter out trades with long duration. If a trade is profitable after 1 month, it is hard to evaluate the strategy based on it. But if most of trades are profitable and they have maximum duration of 30 minutes, then it is clearly a good sign.<br>**NOTICE:** While configuring this value, you should take into consideration your timeframe. As an example filtering out trades having duration less than one day for a strategy which has 4h interval does not make sense. Default value is set assuming your strategy interval is relatively small (1m or 5m, etc.).<br>*Defaults to `1440` (one day).* <br> **Datatype:** Integer
|
|
||||||
| `remove_pumps` | Edge will remove sudden pumps in a given market while going through historical data. However, given that pumps happen very often in crypto markets, we recommend you keep this off.<br>*Defaults to `false`.* <br> **Datatype:** Boolean
|
|
||||||
|
|
||||||
## Running Edge independently
|
|
||||||
|
|
||||||
You can run Edge independently in order to see in details the result. Here is an example:
|
|
||||||
|
|
||||||
``` bash
|
|
||||||
freqtrade edge
|
|
||||||
```
|
|
||||||
|
|
||||||
An example of its output:
|
|
||||||
|
|
||||||
| **pair** | **stoploss** | **win rate** | **risk reward ratio** | **required risk reward** | **expectancy** | **total number of trades** | **average duration (min)** |
|
|
||||||
|:----------|-----------:|-----------:|--------------------:|-----------------------:|-------------:|-----------------:|---------------:|
|
|
||||||
| **AGI/BTC** | -0.02 | 0.64 | 5.86 | 0.56 | 3.41 | 14 | 54 |
|
|
||||||
| **NXS/BTC** | -0.03 | 0.64 | 2.99 | 0.57 | 1.54 | 11 | 26 |
|
|
||||||
| **LEND/BTC** | -0.02 | 0.82 | 2.05 | 0.22 | 1.50 | 11 | 36 |
|
|
||||||
| **VIA/BTC** | -0.01 | 0.55 | 3.01 | 0.83 | 1.19 | 11 | 48 |
|
|
||||||
| **MTH/BTC** | -0.09 | 0.56 | 2.82 | 0.80 | 1.12 | 18 | 52 |
|
|
||||||
| **ARDR/BTC** | -0.04 | 0.42 | 3.14 | 1.40 | 0.73 | 12 | 42 |
|
|
||||||
| **BCPT/BTC** | -0.01 | 0.71 | 1.34 | 0.40 | 0.67 | 14 | 30 |
|
|
||||||
| **WINGS/BTC** | -0.02 | 0.56 | 1.97 | 0.80 | 0.65 | 27 | 42 |
|
|
||||||
| **VIBE/BTC** | -0.02 | 0.83 | 0.91 | 0.20 | 0.59 | 12 | 35 |
|
|
||||||
| **MCO/BTC** | -0.02 | 0.79 | 0.97 | 0.27 | 0.55 | 14 | 31 |
|
|
||||||
| **GNT/BTC** | -0.02 | 0.50 | 2.06 | 1.00 | 0.53 | 18 | 24 |
|
|
||||||
| **HOT/BTC** | -0.01 | 0.17 | 7.72 | 4.81 | 0.50 | 209 | 7 |
|
|
||||||
| **SNM/BTC** | -0.03 | 0.71 | 1.06 | 0.42 | 0.45 | 17 | 38 |
|
|
||||||
| **APPC/BTC** | -0.02 | 0.44 | 2.28 | 1.27 | 0.44 | 25 | 43 |
|
|
||||||
| **NEBL/BTC** | -0.03 | 0.63 | 1.29 | 0.58 | 0.44 | 19 | 59 |
|
|
||||||
|
|
||||||
Edge produced the above table by comparing `calculate_since_number_of_days` to `minimum_expectancy` to find `min_trade_number` historical information based on the config file. The timerange Edge uses for its comparisons can be further limited by using the `--timerange` switch.
|
|
||||||
|
|
||||||
In live and dry-run modes, after the `process_throttle_secs` has passed, Edge will again process `calculate_since_number_of_days` against `minimum_expectancy` to find `min_trade_number`. If no `min_trade_number` is found, the bot will return "whitelist empty". Depending on the trade strategy being deployed, "whitelist empty" may be return much of the time - or *all* of the time. The use of Edge may also cause trading to occur in bursts, though this is rare.
|
|
||||||
|
|
||||||
If you encounter "whitelist empty" a lot, condsider tuning `calculate_since_number_of_days`, `minimum_expectancy` and `min_trade_number` to align to the trading frequency of your strategy.
|
|
||||||
|
|
||||||
### Update cached pairs with the latest data
|
|
||||||
|
|
||||||
Edge requires historic data the same way as backtesting does.
|
|
||||||
Please refer to the [Data Downloading](data-download.md) section of the documentation for details.
|
|
||||||
|
|
||||||
### Precising stoploss range
|
|
||||||
|
|
||||||
```bash
|
|
||||||
freqtrade edge --stoplosses=-0.01,-0.1,-0.001 #min,max,step
|
|
||||||
```
|
|
||||||
|
|
||||||
### Advanced use of timerange
|
|
||||||
|
|
||||||
```bash
|
|
||||||
freqtrade edge --timerange=20181110-20181113
|
|
||||||
```
|
|
||||||
|
|
||||||
Doing `--timerange=-20190901` will get all available data until September 1st (excluding September 1st 2019).
|
|
||||||
|
|
||||||
The full timerange specification:
|
|
||||||
|
|
||||||
* Use tickframes till 2018/01/31: `--timerange=-20180131`
|
|
||||||
* Use tickframes since 2018/01/31: `--timerange=20180131-`
|
|
||||||
* Use tickframes since 2018/01/31 till 2018/03/01 : `--timerange=20180131-20180301`
|
|
||||||
* Use tickframes between POSIX timestamps 1527595200 1527618600: `--timerange=1527595200-1527618600`
|
|
||||||
|
|
||||||
|
|
||||||
[^1]: Question extracted from MIT Opencourseware S096 - Mathematics with applications in Finance: https://ocw.mit.edu/courses/mathematics/18-s096-topics-in-mathematics-with-applications-in-finance-fall-2013/
|
|
||||||
+78
-11
@@ -2,6 +2,10 @@
|
|||||||
|
|
||||||
This page combines common gotchas and Information which are exchange-specific and most likely don't apply to other exchanges.
|
This page combines common gotchas and Information which are exchange-specific and most likely don't apply to other exchanges.
|
||||||
|
|
||||||
|
## Quick overview of supported exchange features
|
||||||
|
|
||||||
|
--8<-- "includes/exchange-features.md"
|
||||||
|
|
||||||
## Exchange configuration
|
## Exchange configuration
|
||||||
|
|
||||||
Freqtrade is based on [CCXT library](https://github.com/ccxt/ccxt) that supports over 100 cryptocurrency
|
Freqtrade is based on [CCXT library](https://github.com/ccxt/ccxt) that supports over 100 cryptocurrency
|
||||||
@@ -227,7 +231,7 @@ Kucoin requires a passphrase for each api key, you will therefore need to add th
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Kucoin supports [time_in_force](configuration.md#understand-order_time_in_force).
|
Kucoin supports [time_in_force](configuration.md#understand-order_time_in_force) with settings "GTC" (good till cancelled), "FOK" (full-or-cancel) and "IOC" (immediate-or-cancel) settings.
|
||||||
|
|
||||||
!!! Tip "Stoploss on Exchange"
|
!!! Tip "Stoploss on Exchange"
|
||||||
Kucoin supports `stoploss_on_exchange` and can use both stop-loss-market and stop-loss-limit orders. It provides great advantages, so we recommend to benefit from it.
|
Kucoin supports `stoploss_on_exchange` and can use both stop-loss-market and stop-loss-limit orders. It provides great advantages, so we recommend to benefit from it.
|
||||||
@@ -271,7 +275,9 @@ Using the wrong exchange will result in the error "OKX Error 50119: API key does
|
|||||||
## Gate.io
|
## Gate.io
|
||||||
|
|
||||||
!!! Tip "Stoploss on Exchange"
|
!!! Tip "Stoploss on Exchange"
|
||||||
Gate.io supports `stoploss_on_exchange` and uses `stop-loss-limit` orders. It provides great advantages, so we recommend to benefit from it by enabling stoploss on exchange..
|
Gate.io supports `stoploss_on_exchange` and uses `stop-loss-limit` orders. It provides great advantages, so we recommend to benefit from it by enabling stoploss on exchange.
|
||||||
|
|
||||||
|
Gate.io supports [time_in_force](configuration.md#understand-order_time_in_force) with settings "GTC" (good till cancelled), and "IOC" (immediate-or-cancel) settings.
|
||||||
|
|
||||||
Gate.io allows the use of `POINT` to pay for fees. As this is not a tradable currency (no regular market available), automatic fee calculations will fail (and default to a fee of 0).
|
Gate.io allows the use of `POINT` to pay for fees. As this is not a tradable currency (no regular market available), automatic fee calculations will fail (and default to a fee of 0).
|
||||||
The configuration parameter `exchange.unknown_fee_rate` can be used to specify the exchange rate between Point and the stake currency. Obviously, changing the stake-currency will also require changes to this value.
|
The configuration parameter `exchange.unknown_fee_rate` can be used to specify the exchange rate between Point and the stake currency. Obviously, changing the stake-currency will also require changes to this value.
|
||||||
@@ -286,9 +292,15 @@ Without these permissions, the bot will not start correctly and show errors like
|
|||||||
|
|
||||||
## Bybit
|
## Bybit
|
||||||
|
|
||||||
Futures trading on bybit is currently supported for USDT markets, and will use isolated futures mode.
|
!!! Tip "Stoploss on Exchange"
|
||||||
|
Bybit (futures only) supports `stoploss_on_exchange` and uses `stop-loss-limit` orders. It provides great advantages, so we recommend to benefit from it by enabling stoploss on exchange.
|
||||||
|
On futures, Bybit supports both `stop-limit` as well as `stop-market` orders. You can use either `"limit"` or `"market"` in the `order_types.stoploss` configuration setting to decide which type to use.
|
||||||
|
|
||||||
On startup, freqtrade will set the position mode to "One-way Mode" for the whole (sub)account. This avoids making this call over and over again (slowing down bot operations), but means that changes to this setting may result in exceptions and errors.
|
Bybit supports [time_in_force](configuration.md#understand-order_time_in_force) with settings "GTC" (good till cancelled), "FOK" (full-or-cancel), "IOC" (immediate-or-cancel) and "PO" (Post only) settings.
|
||||||
|
|
||||||
|
Futures trading on bybit is currently supported for isolated futures mode.
|
||||||
|
|
||||||
|
On startup, freqtrade will set the position mode to "One-way Mode" for the whole (sub)account. This avoids making this call over and over again (slowing down bot operations), but means that manual changes to this setting may result in exceptions and errors.
|
||||||
|
|
||||||
As bybit doesn't provide funding rate history, the dry-run calculation is used for live trades as well.
|
As bybit doesn't provide funding rate history, the dry-run calculation is used for live trades as well.
|
||||||
|
|
||||||
@@ -305,11 +317,6 @@ We do strongly recommend to limit all API keys to the IP you're going to use it
|
|||||||
We therefore recommend the usage of one subaccount per bot. This is especially important when using unified accounts.
|
We therefore recommend the usage of one subaccount per bot. This is especially important when using unified accounts.
|
||||||
Other configurations (multiple bots on one account, manual non-bot trades on the bot account) are not supported and may lead to unexpected behavior.
|
Other configurations (multiple bots on one account, manual non-bot trades on the bot account) are not supported and may lead to unexpected behavior.
|
||||||
|
|
||||||
|
|
||||||
!!! Tip "Stoploss on Exchange"
|
|
||||||
Bybit (futures only) supports `stoploss_on_exchange` and uses `stop-loss-limit` orders. It provides great advantages, so we recommend to benefit from it by enabling stoploss on exchange.
|
|
||||||
On futures, Bybit supports both `stop-limit` as well as `stop-market` orders. You can use either `"limit"` or `"market"` in the `order_types.stoploss` configuration setting to decide which type to use.
|
|
||||||
|
|
||||||
## Bitmart
|
## Bitmart
|
||||||
|
|
||||||
Bitmart requires the API key Memo (the name you give the API key) to go along with the exchange key and secret.
|
Bitmart requires the API key Memo (the name you give the API key) to go along with the exchange key and secret.
|
||||||
@@ -328,6 +335,26 @@ It's therefore required to pass the UID as well.
|
|||||||
!!! Warning "Necessary Verification"
|
!!! Warning "Necessary Verification"
|
||||||
Bitmart requires Verification Lvl2 to successfully trade on the spot market through the API - even though trading via UI works just fine with just Lvl1 verification.
|
Bitmart requires Verification Lvl2 to successfully trade on the spot market through the API - even though trading via UI works just fine with just Lvl1 verification.
|
||||||
|
|
||||||
|
## Bitget
|
||||||
|
|
||||||
|
Bitget requires a passphrase for each api key, you will therefore need to add this key into the configuration so your exchange section looks as follows:
|
||||||
|
|
||||||
|
```json
|
||||||
|
"exchange": {
|
||||||
|
"name": "bitget",
|
||||||
|
"key": "your_exchange_key",
|
||||||
|
"secret": "your_exchange_secret",
|
||||||
|
"password": "your_exchange_api_key_password",
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Bitget supports [time_in_force](configuration.md#understand-order_time_in_force) with settings "GTC" (good till cancelled), "FOK" (full-or-cancel), "IOC" (immediate-or-cancel) and "PO" (Post only) settings.
|
||||||
|
|
||||||
|
!!! Tip "Stoploss on Exchange"
|
||||||
|
Bitget supports `stoploss_on_exchange` and can use both stop-loss-market and stop-loss-limit orders. It provides great advantages, so we recommend to benefit from it.
|
||||||
|
You can use either `"limit"` or `"market"` in the `order_types.stoploss` configuration setting to decide which type of stoploss shall be used.
|
||||||
|
|
||||||
## Hyperliquid
|
## Hyperliquid
|
||||||
|
|
||||||
!!! Tip "Stoploss on Exchange"
|
!!! Tip "Stoploss on Exchange"
|
||||||
@@ -339,13 +366,13 @@ This needs to be configured like this:
|
|||||||
```json
|
```json
|
||||||
"exchange": {
|
"exchange": {
|
||||||
"name": "hyperliquid",
|
"name": "hyperliquid",
|
||||||
"walletAddress": "your_eth_wallet_address",
|
"walletAddress": "your_eth_wallet_address", // This should NOT be your API Wallet Address!
|
||||||
"privateKey": "your_api_private_key",
|
"privateKey": "your_api_private_key",
|
||||||
// ...
|
// ...
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
* walletAddress in hex format: `0x<40 hex characters>` - Can be easily copied from your wallet - and should be your wallet address, not your API Wallet Address.
|
* walletAddress in hex format: `0x<40 hex characters>` - Can be easily copied from your wallet - and should be your main wallet address, not your API Wallet Address.
|
||||||
* privateKey in hex format: `0x<64 hex characters>` - Use the key the API Wallet shows on creation.
|
* privateKey in hex format: `0x<64 hex characters>` - Use the key the API Wallet shows on creation.
|
||||||
|
|
||||||
Hyperliquid handles deposits and withdrawals on the Arbitrum One chain, a Layer 2 scaling solution built on top of Ethereum. Hyperliquid uses USDC as quote / collateral. The process of depositing USDC on Hyperliquid requires a couple of steps, see [how to start trading](https://hyperliquid.gitbook.io/hyperliquid-docs/onboarding/how-to-start-trading) for details on what steps are needed.
|
Hyperliquid handles deposits and withdrawals on the Arbitrum One chain, a Layer 2 scaling solution built on top of Ethereum. Hyperliquid uses USDC as quote / collateral. The process of depositing USDC on Hyperliquid requires a couple of steps, see [how to start trading](https://hyperliquid.gitbook.io/hyperliquid-docs/onboarding/how-to-start-trading) for details on what steps are needed.
|
||||||
@@ -363,10 +390,50 @@ Hyperliquid handles deposits and withdrawals on the Arbitrum One chain, a Layer
|
|||||||
* Create a different software wallet, only transfer the funds you want to trade with to that wallet, and use that wallet to trade on Hyperliquid.
|
* Create a different software wallet, only transfer the funds you want to trade with to that wallet, and use that wallet to trade on Hyperliquid.
|
||||||
* If you have funds you don't want to use for trading (after making a profit for example), transfer them back to your hardware wallet.
|
* If you have funds you don't want to use for trading (after making a profit for example), transfer them back to your hardware wallet.
|
||||||
|
|
||||||
|
### Hyperliquid Vault / Subaccount
|
||||||
|
|
||||||
|
Hyperliquid allows you to create either a vault or a subaccount.
|
||||||
|
To use these with Freqtrade, you will need to use the following configuration pattern:
|
||||||
|
|
||||||
|
``` json
|
||||||
|
"exchange": {
|
||||||
|
"name": "hyperliquid",
|
||||||
|
"walletAddress": "your_vault_address", // Vault or subaccount address
|
||||||
|
"privateKey": "your_api_private_key",
|
||||||
|
"ccxt_config": {
|
||||||
|
"options": {
|
||||||
|
"vaultAddress": "your_vault_address" // Optional, only if you want to use a vault or subaccount
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Your balance and trades will now be used from your vault / subaccount - and no longer from your main account.
|
||||||
|
|
||||||
### Historic Hyperliquid data
|
### Historic Hyperliquid data
|
||||||
|
|
||||||
The Hyperliquid API does not provide historic data beyond the single call to fetch current data, so downloading data is not possible, as the downloaded data would not constitute proper historic data.
|
The Hyperliquid API does not provide historic data beyond the single call to fetch current data, so downloading data is not possible, as the downloaded data would not constitute proper historic data.
|
||||||
|
|
||||||
|
## Bitvavo
|
||||||
|
|
||||||
|
If your account is required to use an operatorId, you can set it in the configuration file as follows:
|
||||||
|
|
||||||
|
``` json
|
||||||
|
"exchange": {
|
||||||
|
"name": "bitvavo",
|
||||||
|
"key": "",
|
||||||
|
"secret": "",
|
||||||
|
"ccxt_config": {
|
||||||
|
"options": {
|
||||||
|
"operatorId": "123567"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Bitvavo expects the `operatorId` to be an integer.
|
||||||
|
|
||||||
## All exchanges
|
## All exchanges
|
||||||
|
|
||||||
Should you experience constant errors with Nonce (like `InvalidNonce`), it is best to regenerate the API keys. Resetting Nonce is difficult and it's usually easier to regenerate the API keys.
|
Should you experience constant errors with Nonce (like `InvalidNonce`), it is best to regenerate the API keys. Resetting Nonce is difficult and it's usually easier to regenerate the API keys.
|
||||||
|
|||||||
+24
-18
@@ -102,6 +102,14 @@ You can use "current" market data by using the [dataprovider](strategy-customiza
|
|||||||
|
|
||||||
You can use the `/stopentry` command in Telegram to prevent future trade entry, followed by `/forceexit all` (sell all open trades).
|
You can use the `/stopentry` command in Telegram to prevent future trade entry, followed by `/forceexit all` (sell all open trades).
|
||||||
|
|
||||||
|
### I sold the bot's capital and now there's errors in the log
|
||||||
|
|
||||||
|
Freqtrade assumes that the trades it opens are managed only though the bot.
|
||||||
|
If you happen to (accidentally) sell the bot's capital, freqtrade will try to recover by trying to re-find on-exchange orders.
|
||||||
|
|
||||||
|
This is a best-effort approach, and will not work in all cases, especially when using order types that are not supported by freqtrade (OCO, iceberg, etc.), or when working with older trades (where the exchange no longer provides full order information).
|
||||||
|
The exact limits will vary between exchanges - with the details usually being documented in the exchange's API documentation.
|
||||||
|
|
||||||
### I want to run multiple bots on the same machine
|
### I want to run multiple bots on the same machine
|
||||||
|
|
||||||
Please look at the [advanced setup documentation Page](advanced-setup.md#running-multiple-instances-of-freqtrade).
|
Please look at the [advanced setup documentation Page](advanced-setup.md#running-multiple-instances-of-freqtrade).
|
||||||
@@ -151,6 +159,14 @@ This warning can point to one of the below problems:
|
|||||||
* Barely traded pair -> Check the pair on the exchange webpage, look at the timeframe your strategy uses. If the pair does not have any volume in some candles (usually visualized with a "volume 0" bar, and a "_" as candle), this pair did not have any trades in this timeframe. These pairs should ideally be avoided, as they can cause problems with order-filling.
|
* Barely traded pair -> Check the pair on the exchange webpage, look at the timeframe your strategy uses. If the pair does not have any volume in some candles (usually visualized with a "volume 0" bar, and a "_" as candle), this pair did not have any trades in this timeframe. These pairs should ideally be avoided, as they can cause problems with order-filling.
|
||||||
* API problem -> API returns wrong data (this only here for completeness, and should not happen with supported exchanges).
|
* API problem -> API returns wrong data (this only here for completeness, and should not happen with supported exchanges).
|
||||||
|
|
||||||
|
### I get the message "Couldn't reuse watch for xxx" in the log
|
||||||
|
|
||||||
|
This is an informational message that the bot tried to use candles from the websocket, but the exchange didn't provide the right information.
|
||||||
|
This can happen if there was an interruption to the websocket connection - or if the pair didn't have any trades happen in the timeframe you are using.
|
||||||
|
|
||||||
|
Freqtrade will handle this gracefully by falling back to the REST api.
|
||||||
|
While this makes the iteration slightly slower (due to the REST Api call) - it will not cause any problems to the bot's operation.
|
||||||
|
|
||||||
### I'm getting the "Exchange XXX does not support market orders." message and cannot run my strategy
|
### I'm getting the "Exchange XXX does not support market orders." message and cannot run my strategy
|
||||||
|
|
||||||
As the message says, your exchange does not support market orders and you have one of the [order types](configuration.md/#understand-order_types) set to "market". Your strategy was probably written with other exchanges in mind and sets "market" orders for "stoploss" orders, which is correct and preferable for most of the exchanges supporting market orders (but not for Gate.io).
|
As the message says, your exchange does not support market orders and you have one of the [order types](configuration.md/#understand-order_types) set to "market". Your strategy was probably written with other exchanges in mind and sets "market" orders for "stoploss" orders, which is correct and preferable for most of the exchanges supporting market orders (but not for Gate.io).
|
||||||
@@ -219,10 +235,7 @@ On Windows, the `--logfile` option is also supported by Freqtrade and you can us
|
|||||||
First of all, most indicator libraries don't have GPU support - as such, there would be little benefit for indicator calculations.
|
First of all, most indicator libraries don't have GPU support - as such, there would be little benefit for indicator calculations.
|
||||||
The GPU improvements would only apply to pandas-native calculations - or ones written by yourself.
|
The GPU improvements would only apply to pandas-native calculations - or ones written by yourself.
|
||||||
|
|
||||||
For hyperopt, freqtrade is using scikit-optimize, which is built on top of scikit-learn.
|
GPU's are only good at crunching numbers (floating point operations).
|
||||||
Their statement about GPU support is [pretty clear](https://scikit-learn.org/stable/faq.html#will-you-add-gpu-support).
|
|
||||||
|
|
||||||
GPU's also are only good at crunching numbers (floating point operations).
|
|
||||||
For hyperopt, we need both number-crunching (find next parameters) and running python code (running backtesting).
|
For hyperopt, we need both number-crunching (find next parameters) and running python code (running backtesting).
|
||||||
As such, GPU's are not too well suited for most parts of hyperopt.
|
As such, GPU's are not too well suited for most parts of hyperopt.
|
||||||
|
|
||||||
@@ -271,20 +284,6 @@ Example: 4% profit 650 times vs 0,3% profit a trade 10000 times in a year. If we
|
|||||||
Example:
|
Example:
|
||||||
`freqtrade --config config.json --strategy SampleStrategy --hyperopt SampleHyperopt -e 1000 --timerange 20190601-20200601`
|
`freqtrade --config config.json --strategy SampleStrategy --hyperopt SampleHyperopt -e 1000 --timerange 20190601-20200601`
|
||||||
|
|
||||||
## Edge module
|
|
||||||
|
|
||||||
### Edge implements interesting approach for controlling position size, is there any theory behind it?
|
|
||||||
|
|
||||||
The Edge module is mostly a result of brainstorming of [@mishaker](https://github.com/mishaker) and [@creslinux](https://github.com/creslinux) freqtrade team members.
|
|
||||||
|
|
||||||
You can find further info on expectancy, win rate, risk management and position size in the following sources:
|
|
||||||
|
|
||||||
- https://www.tradeciety.com/ultimate-math-guide-for-traders/
|
|
||||||
- https://samuraitradingacademy.com/trading-expectancy/
|
|
||||||
- https://www.learningmarkets.com/determining-expectancy-in-your-trading/
|
|
||||||
- https://www.lonestocktrader.com/make-money-trading-positive-expectancy/
|
|
||||||
- https://www.babypips.com/trading/trade-expectancy-matter
|
|
||||||
|
|
||||||
## Official channels
|
## Official channels
|
||||||
|
|
||||||
Freqtrade is using exclusively the following official channels:
|
Freqtrade is using exclusively the following official channels:
|
||||||
@@ -298,6 +297,13 @@ Should you be asked to expose your exchange keys or send funds to some random wa
|
|||||||
|
|
||||||
Failing to follow these guidelines will not be responsibility of freqtrade.
|
Failing to follow these guidelines will not be responsibility of freqtrade.
|
||||||
|
|
||||||
|
## Support policy
|
||||||
|
|
||||||
|
We provide free support for Freqtrade on our [Discord server](https://discord.gg/p7nuUNVfP7) and via GitHub issues.
|
||||||
|
We only support the most recent release (e.g. 2025.8) and the current development branch (e.g. 2025.9-dev).
|
||||||
|
|
||||||
|
If you're on an older version, please follow the [upgrade instructions](updating.md) and see if your problem has already been addressed.
|
||||||
|
|
||||||
## "Freqtrade token"
|
## "Freqtrade token"
|
||||||
|
|
||||||
Freqtrade does not have a Crypto token offering.
|
Freqtrade does not have a Crypto token offering.
|
||||||
|
|||||||
+11
-2
@@ -4,7 +4,7 @@ Freqtrade provides a builtin webserver, which can serve [FreqUI](https://github.
|
|||||||
|
|
||||||
By default, the UI is automatically installed as part of the installation (script, docker).
|
By default, the UI is automatically installed as part of the installation (script, docker).
|
||||||
freqUI can also be manually installed by using the `freqtrade install-ui` command.
|
freqUI can also be manually installed by using the `freqtrade install-ui` command.
|
||||||
This same command can also be used to update freqUI to new new releases.
|
This same command can also be used to update freqUI to new releases.
|
||||||
|
|
||||||
Once the bot is started in trade / dry-run mode (with `freqtrade trade`) - the UI will be available under the configured API port (by default `http://127.0.0.1:8080`).
|
Once the bot is started in trade / dry-run mode (with `freqtrade trade`) - the UI will be available under the configured API port (by default `http://127.0.0.1:8080`).
|
||||||
|
|
||||||
@@ -70,7 +70,16 @@ Things you can change (among others):
|
|||||||

|

|
||||||

|

|
||||||
|
|
||||||
## Backtesting
|
## Webserver mode
|
||||||
|
|
||||||
|
when freqtrade is started in [webserver mode](utils.md#webserver-mode) (freqtrade started with `freqtrade webserver`), the webserver will start in a special mode allowing for additional features, for example:
|
||||||
|
|
||||||
|
* Downloading data
|
||||||
|
* Testing pairlists
|
||||||
|
* [Backtesting strategies](#backtesting)
|
||||||
|
* ... to be expanded
|
||||||
|
|
||||||
|
### Backtesting
|
||||||
|
|
||||||
When freqtrade is started in [webserver mode](utils.md#webserver-mode) (freqtrade started with `freqtrade webserver`), the backtesting view becomes available.
|
When freqtrade is started in [webserver mode](utils.md#webserver-mode) (freqtrade started with `freqtrade webserver`), the backtesting view becomes available.
|
||||||
This view allows you to backtest strategies and visualize the results.
|
This view allows you to backtest strategies and visualize the results.
|
||||||
|
|||||||
@@ -181,7 +181,7 @@ You can ask for each of the defined features to be included also for informative
|
|||||||
In total, the number of features the user of the presented example strategy has created is: length of `include_timeframes` * no. features in `feature_engineering_expand_*()` * length of `include_corr_pairlist` * no. `include_shifted_candles` * length of `indicator_periods_candles`
|
In total, the number of features the user of the presented example strategy has created is: length of `include_timeframes` * no. features in `feature_engineering_expand_*()` * length of `include_corr_pairlist` * no. `include_shifted_candles` * length of `indicator_periods_candles`
|
||||||
$= 3 * 3 * 3 * 2 * 2 = 108$.
|
$= 3 * 3 * 3 * 2 * 2 = 108$.
|
||||||
|
|
||||||
!!! note "Learn more about creative feature engineering"
|
!!! note "Learn more about creative feature engineering"
|
||||||
Check out our [medium article](https://emergentmethods.medium.com/freqai-from-price-to-prediction-6fadac18b665) geared toward helping users learn how to creatively engineer features.
|
Check out our [medium article](https://emergentmethods.medium.com/freqai-from-price-to-prediction-6fadac18b665) geared toward helping users learn how to creatively engineer features.
|
||||||
|
|
||||||
### Gain finer control over `feature_engineering_*` functions with `metadata`
|
### Gain finer control over `feature_engineering_*` functions with `metadata`
|
||||||
@@ -310,7 +310,7 @@ class MyCoolTransform(BaseTransform):
|
|||||||
|
|
||||||
If you have created your own custom `IFreqaiModel` with a custom `train()`/`predict()` function, *and* you still rely on `data_cleaning_train/predict()`, then you will need to migrate to the new pipeline. If your model does *not* rely on `data_cleaning_train/predict()`, then you do not need to worry about this migration.
|
If you have created your own custom `IFreqaiModel` with a custom `train()`/`predict()` function, *and* you still rely on `data_cleaning_train/predict()`, then you will need to migrate to the new pipeline. If your model does *not* rely on `data_cleaning_train/predict()`, then you do not need to worry about this migration.
|
||||||
|
|
||||||
More details about the migration can be found [here](strategy_migration.md#freqai---new-data-pipeline).
|
More details about the migration can be found [here](strategy_migration.md#freqai-new-data-pipeline).
|
||||||
|
|
||||||
## Outlier detection
|
## Outlier detection
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -79,7 +79,7 @@ pip install -r requirements-freqai.txt
|
|||||||
If you are using docker, a dedicated tag with FreqAI dependencies is available as `:freqai`. As such - you can replace the image line in your docker compose file with `image: freqtradeorg/freqtrade:stable_freqai`. This image contains the regular FreqAI dependencies. Similar to native installs, Catboost will not be available on ARM based devices. If you would like to use PyTorch or Reinforcement learning, you should use the torch or RL tags, `image: freqtradeorg/freqtrade:stable_freqaitorch`, `image: freqtradeorg/freqtrade:stable_freqairl`.
|
If you are using docker, a dedicated tag with FreqAI dependencies is available as `:freqai`. As such - you can replace the image line in your docker compose file with `image: freqtradeorg/freqtrade:stable_freqai`. This image contains the regular FreqAI dependencies. Similar to native installs, Catboost will not be available on ARM based devices. If you would like to use PyTorch or Reinforcement learning, you should use the torch or RL tags, `image: freqtradeorg/freqtrade:stable_freqaitorch`, `image: freqtradeorg/freqtrade:stable_freqairl`.
|
||||||
|
|
||||||
!!! note "docker-compose-freqai.yml"
|
!!! note "docker-compose-freqai.yml"
|
||||||
We do provide an explicit docker-compose file for this in `docker/docker-compose-freqai.yml` - which can be used via `docker compose -f docker/docker-compose-freqai.yml run ...` - or can be copied to replace the original docker file. This docker-compose file also contains a (disabled) section to enable GPU resources within docker containers. This obviously assumes the system has GPU resources available.
|
We do provide an explicit docker-compose file for this in `docker/docker-compose-freqai.yml` - which can be used via `docker compose -f docker/docker-compose-freqai.yml run ...` - or can be copied to replace the original docker file. This docker-compose file also contains a (disabled) section to enable GPU resources within docker containers. This obviously assumes the system has GPU resources available.
|
||||||
|
|
||||||
### FreqAI position in open-source machine learning landscape
|
### FreqAI position in open-source machine learning landscape
|
||||||
|
|
||||||
|
|||||||
+5
-3
@@ -1,10 +1,10 @@
|
|||||||
# Hyperopt
|
# Hyperopt
|
||||||
|
|
||||||
This page explains how to tune your strategy by finding the optimal
|
This page explains how to tune your strategy by finding the optimal
|
||||||
parameters, a process called hyperparameter optimization. The bot uses algorithms included in the `scikit-optimize` package to accomplish this.
|
parameters, a process called hyperparameter optimization. The bot uses algorithms included in the `optuna` package to accomplish this.
|
||||||
The search will burn all your CPU cores, make your laptop sound like a fighter jet and still take a long time.
|
The search will burn all your CPU cores, make your laptop sound like a fighter jet and still take a long time.
|
||||||
|
|
||||||
In general, the search for best parameters starts with a few random combinations (see [below](#reproducible-results) for more details) and then uses Bayesian search with a ML regressor algorithm (currently ExtraTreesRegressor) to quickly find a combination of parameters in the search hyperspace that minimizes the value of the [loss function](#loss-functions).
|
In general, the search for best parameters starts with a few random combinations (see [below](#reproducible-results) for more details) and then uses one of optuna's sampler algorithms (currently NSGAIIISampler) to quickly find a combination of parameters in the search hyperspace that minimizes the value of the [loss function](#loss-functions).
|
||||||
|
|
||||||
Hyperopt requires historic data to be available, just as backtesting does (hyperopt runs backtesting many times with different parameters).
|
Hyperopt requires historic data to be available, just as backtesting does (hyperopt runs backtesting many times with different parameters).
|
||||||
To learn how to get data for the pairs and exchange you're interested in, head over to the [Data Downloading](data-download.md) section of the documentation.
|
To learn how to get data for the pairs and exchange you're interested in, head over to the [Data Downloading](data-download.md) section of the documentation.
|
||||||
@@ -490,6 +490,8 @@ freqtrade hyperopt --config config.json --hyperopt-loss <hyperoptlossname> --str
|
|||||||
```
|
```
|
||||||
|
|
||||||
The `-e` option will set how many evaluations hyperopt will do. Since hyperopt uses Bayesian search, running too many epochs at once may not produce greater results. Experience has shown that best results are usually not improving much after 500-1000 epochs.
|
The `-e` option will set how many evaluations hyperopt will do. Since hyperopt uses Bayesian search, running too many epochs at once may not produce greater results. Experience has shown that best results are usually not improving much after 500-1000 epochs.
|
||||||
|
The `--early-stop` option will set after how many epochs with no improvements hyperopt will stop. A good value is 20-30% of the total epochs. Any value greater than 0 and lower than 20 it will be replaced by 20. Early stop is by default disabled (`--early-stop=0`)
|
||||||
|
|
||||||
Doing multiple runs (executions) with a few 1000 epochs and different random state will most likely produce different results.
|
Doing multiple runs (executions) with a few 1000 epochs and different random state will most likely produce different results.
|
||||||
|
|
||||||
The `--spaces all` option determines that all possible parameters should be optimized. Possibilities are listed below.
|
The `--spaces all` option determines that all possible parameters should be optimized. Possibilities are listed below.
|
||||||
@@ -532,7 +534,7 @@ Legal values are:
|
|||||||
* `trailing`: search for the best trailing stop values
|
* `trailing`: search for the best trailing stop values
|
||||||
* `trades`: search for the best max open trades values
|
* `trades`: search for the best max open trades values
|
||||||
* `protection`: search for the best protection parameters (read the [protections section](#optimizing-protections) on how to properly define these)
|
* `protection`: search for the best protection parameters (read the [protections section](#optimizing-protections) on how to properly define these)
|
||||||
* `default`: `all` except `trailing` and `protection`
|
* `default`: `all` except `trailing`, `trades` and `protection`
|
||||||
* space-separated list of any of the above values for example `--spaces roi stoploss`
|
* space-separated list of any of the above values for example `--spaces roi stoploss`
|
||||||
|
|
||||||
The default Hyperopt Search Space, used when no `--space` command line option is specified, does not include the `trailing` hyperspace. We recommend you to run optimization for the `trailing` hyperspace separately, when the best parameters for other hyperspaces were found, validated and pasted into your custom strategy.
|
The default Hyperopt Search Space, used when no `--space` command line option is specified, does not include the `trailing` hyperspace. We recommend you to run optimization for the `trailing` hyperspace separately, when the best parameters for other hyperspaces were found, validated and pasted into your custom strategy.
|
||||||
|
|||||||
@@ -0,0 +1,19 @@
|
|||||||
|
|
||||||
|
| Exchange | Mode | Margin mode | Stoploss type |
|
||||||
|
|---------|---------|------|------------------|
|
||||||
|
| [Binance](exchanges.md#binance) | spot | | limit |
|
||||||
|
| [Binance](exchanges.md#binance) | futures | isolated, cross | market, limit |
|
||||||
|
| [Bingx](exchanges.md#bingx) | spot | | market, limit |
|
||||||
|
| [Bitmart](exchanges.md#bitmart) | spot | | ❌ (not supported) |
|
||||||
|
| [Bybit](exchanges.md#bybit) | spot | | ❌ (not supported) |
|
||||||
|
| [Bybit](exchanges.md#bybit) | futures | isolated | market, limit |
|
||||||
|
| [Gate.io](exchanges.md#gateio) | spot | | limit |
|
||||||
|
| [Gate.io](exchanges.md#gateio) | futures | isolated | limit |
|
||||||
|
| [HTX](exchanges.md#htx) | spot | | limit |
|
||||||
|
| [Hyperliquid](exchanges.md#hyperliquid) | spot | | ❌ (not supported) |
|
||||||
|
| [Hyperliquid](exchanges.md#hyperliquid) | futures | isolated | limit |
|
||||||
|
| [Kraken](exchanges.md#kraken) | spot | | market, limit |
|
||||||
|
| [OKX](exchanges.md#okx) | spot | | limit |
|
||||||
|
| [OKX](exchanges.md#okx) | futures | isolated | limit |
|
||||||
|
| [Bitvavo](exchanges.md#bitvavo) | spot | | ❌ (not supported) |
|
||||||
|
| [Kucoin](exchanges.md#kucoin) | spot | | market, limit |
|
||||||
@@ -4,7 +4,7 @@ Pairlist Handlers define the list of pairs (pairlist) that the bot should trade.
|
|||||||
|
|
||||||
In your configuration, you can use Static Pairlist (defined by the [`StaticPairList`](#static-pair-list) Pairlist Handler) and Dynamic Pairlist (defined by the [`VolumePairList`](#volume-pair-list) and [`PercentChangePairList`](#percent-change-pair-list) Pairlist Handlers).
|
In your configuration, you can use Static Pairlist (defined by the [`StaticPairList`](#static-pair-list) Pairlist Handler) and Dynamic Pairlist (defined by the [`VolumePairList`](#volume-pair-list) and [`PercentChangePairList`](#percent-change-pair-list) Pairlist Handlers).
|
||||||
|
|
||||||
Additionally, [`AgeFilter`](#agefilter), [`PrecisionFilter`](#precisionfilter), [`PriceFilter`](#pricefilter), [`ShuffleFilter`](#shufflefilter), [`SpreadFilter`](#spreadfilter) and [`VolatilityFilter`](#volatilityfilter) act as Pairlist Filters, removing certain pairs and/or moving their positions in the pairlist.
|
Additionally, [`AgeFilter`](#agefilter), [`DelistFilter`](#delistfilter), [`PrecisionFilter`](#precisionfilter), [`PriceFilter`](#pricefilter), [`ShuffleFilter`](#shufflefilter), [`SpreadFilter`](#spreadfilter) and [`VolatilityFilter`](#volatilityfilter) act as Pairlist Filters, removing certain pairs and/or moving their positions in the pairlist.
|
||||||
|
|
||||||
If multiple Pairlist Handlers are used, they are chained and a combination of all Pairlist Handlers forms the resulting pairlist the bot uses for trading and backtesting. Pairlist Handlers are executed in the sequence they are configured. You can define either `StaticPairList`, `VolumePairList`, `ProducerPairList`, `RemotePairList`, `MarketCapPairList` or `PercentChangePairList` as the starting Pairlist Handler.
|
If multiple Pairlist Handlers are used, they are chained and a combination of all Pairlist Handlers forms the resulting pairlist the bot uses for trading and backtesting. Pairlist Handlers are executed in the sequence they are configured. You can define either `StaticPairList`, `VolumePairList`, `ProducerPairList`, `RemotePairList`, `MarketCapPairList` or `PercentChangePairList` as the starting Pairlist Handler.
|
||||||
|
|
||||||
@@ -27,6 +27,7 @@ You may also use something like `.*DOWN/BTC` or `.*UP/BTC` to exclude leveraged
|
|||||||
* [`RemotePairList`](#remotepairlist)
|
* [`RemotePairList`](#remotepairlist)
|
||||||
* [`MarketCapPairList`](#marketcappairlist)
|
* [`MarketCapPairList`](#marketcappairlist)
|
||||||
* [`AgeFilter`](#agefilter)
|
* [`AgeFilter`](#agefilter)
|
||||||
|
* [`DelistFilter`](#delistfilter)
|
||||||
* [`FullTradesFilter`](#fulltradesfilter)
|
* [`FullTradesFilter`](#fulltradesfilter)
|
||||||
* [`OffsetFilter`](#offsetfilter)
|
* [`OffsetFilter`](#offsetfilter)
|
||||||
* [`PerformanceFilter`](#performancefilter)
|
* [`PerformanceFilter`](#performancefilter)
|
||||||
@@ -38,7 +39,7 @@ You may also use something like `.*DOWN/BTC` or `.*UP/BTC` to exclude leveraged
|
|||||||
* [`VolatilityFilter`](#volatilityfilter)
|
* [`VolatilityFilter`](#volatilityfilter)
|
||||||
|
|
||||||
!!! Tip "Testing pairlists"
|
!!! Tip "Testing pairlists"
|
||||||
Pairlist configurations can be quite tricky to get right. Best use the [`test-pairlist`](utils.md#test-pairlist) utility sub-command to test your configuration quickly.
|
Pairlist configurations can be quite tricky to get right. Best use freqUI in [webserver mode](freq-ui.md#webserver-mode) or the [`test-pairlist`](utils.md#test-pairlist) utility sub-command to test your Pairlist configuration quickly.
|
||||||
|
|
||||||
#### Static Pair List
|
#### Static Pair List
|
||||||
|
|
||||||
@@ -180,7 +181,7 @@ More sophisticated approach can be used, by using `lookback_timeframe` for candl
|
|||||||
* `refresh_period`: Defines the interval (in seconds) at which the pairlist will be refreshed. The default is 1800 seconds (30 minutes).
|
* `refresh_period`: Defines the interval (in seconds) at which the pairlist will be refreshed. The default is 1800 seconds (30 minutes).
|
||||||
* `lookback_days`: Number of days to look back. When `lookback_days` is selected, the `lookback_timeframe` is defaulted to 1 day.
|
* `lookback_days`: Number of days to look back. When `lookback_days` is selected, the `lookback_timeframe` is defaulted to 1 day.
|
||||||
* `lookback_timeframe`: Timeframe to use for the lookback period.
|
* `lookback_timeframe`: Timeframe to use for the lookback period.
|
||||||
* `lookback_period`: Number of periods to look back at.
|
* `lookback_period`: Number of periods to look back at.
|
||||||
|
|
||||||
When PercentChangePairList is used after other Pairlist Handlers, it will operate on the outputs of those handlers. If it is the leading Pairlist Handler, it will select pairs from all available markets with the specified stake currency.
|
When PercentChangePairList is used after other Pairlist Handlers, it will operate on the outputs of those handlers. If it is the leading Pairlist Handler, it will select pairs from all available markets with the specified stake currency.
|
||||||
|
|
||||||
@@ -270,7 +271,6 @@ You can limit the length of the pairlist with the optional parameter `number_ass
|
|||||||
],
|
],
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
!!! Tip "Combining pairlists"
|
!!! Tip "Combining pairlists"
|
||||||
This pairlist can be combined with all other pairlists and filters for further pairlist reduction, and can also act as an "additional" pairlist, on top of already defined pairs.
|
This pairlist can be combined with all other pairlists and filters for further pairlist reduction, and can also act as an "additional" pairlist, on top of already defined pairs.
|
||||||
`ProducerPairList` can also be used multiple times in sequence, combining the pairs from multiple producers.
|
`ProducerPairList` can also be used multiple times in sequence, combining the pairs from multiple producers.
|
||||||
@@ -312,7 +312,7 @@ The `pairlist_url` option specifies the URL of the remote server where the pairl
|
|||||||
The `save_to_file` option, when provided with a valid filename, saves the processed pairlist to that file in JSON format. This option is optional, and by default, the pairlist is not saved to a file.
|
The `save_to_file` option, when provided with a valid filename, saves the processed pairlist to that file in JSON format. This option is optional, and by default, the pairlist is not saved to a file.
|
||||||
|
|
||||||
??? Example "Multi bot with shared pairlist example"
|
??? Example "Multi bot with shared pairlist example"
|
||||||
|
|
||||||
`save_to_file` can be used to save the pairlist to a file with Bot1:
|
`save_to_file` can be used to save the pairlist to a file with Bot1:
|
||||||
|
|
||||||
```json
|
```json
|
||||||
@@ -389,6 +389,8 @@ The `refresh_period` setting defines the interval (in seconds) at which the mark
|
|||||||
The `categories` setting specifies the [coingecko categories](https://www.coingecko.com/en/categories) from which to select coins from. The default is an empty list `[]`, meaning no category filtering is applied.
|
The `categories` setting specifies the [coingecko categories](https://www.coingecko.com/en/categories) from which to select coins from. The default is an empty list `[]`, meaning no category filtering is applied.
|
||||||
If an incorrect category string is chosen, the plugin will print the available categories from CoinGecko and fail. The category should be the ID of the category, for example, for `https://www.coingecko.com/en/categories/layer-1`, the category ID would be `layer-1`. You can pass multiple categories such as `["layer-1", "meme-token"]` to select from several categories.
|
If an incorrect category string is chosen, the plugin will print the available categories from CoinGecko and fail. The category should be the ID of the category, for example, for `https://www.coingecko.com/en/categories/layer-1`, the category ID would be `layer-1`. You can pass multiple categories such as `["layer-1", "meme-token"]` to select from several categories.
|
||||||
|
|
||||||
|
Coins like 1000PEPE/USDT or KPEPE/USDT:USDT are detected on a best effort basis, with the prefixes `1000` and `K` being used to identify them.
|
||||||
|
|
||||||
!!! Warning "Many categories"
|
!!! Warning "Many categories"
|
||||||
Each added category corresponds to one API call to CoinGecko. The more categories you add, the longer the pairlist generation will take, potentially causing rate limit issues.
|
Each added category corresponds to one API call to CoinGecko. The more categories you add, the longer the pairlist generation will take, potentially causing rate limit issues.
|
||||||
|
|
||||||
@@ -405,6 +407,16 @@ be caught out buying before the pair has finished dropping in price.
|
|||||||
|
|
||||||
This filter allows freqtrade to ignore pairs until they have been listed for at least `min_days_listed` days and listed before `max_days_listed`.
|
This filter allows freqtrade to ignore pairs until they have been listed for at least `min_days_listed` days and listed before `max_days_listed`.
|
||||||
|
|
||||||
|
#### DelistFilter
|
||||||
|
|
||||||
|
Removes pairs that will be delisted on the exchange maximum `max_days_from_now` days from now (defaults to `0` which remove all future delisted pairs no matter how far from now). Currently this filter only supports following exchanges:
|
||||||
|
|
||||||
|
!!! Note "Available exchanges"
|
||||||
|
Delist filter is only available on Binance, where Binance Futures will work for both dry and live modes, while Binance Spot is limited to live mode (for technical reasons).
|
||||||
|
|
||||||
|
!!! Warning "Backtesting"
|
||||||
|
`DelistFilter` does not support backtesting mode.
|
||||||
|
|
||||||
#### FullTradesFilter
|
#### FullTradesFilter
|
||||||
|
|
||||||
Shrink whitelist to consist only in-trade pairs when the trade slots are full (when `max_open_trades` isn't being set to `-1` in the config).
|
Shrink whitelist to consist only in-trade pairs when the trade slots are full (when `max_open_trades` isn't being set to `-1` in the config).
|
||||||
@@ -436,7 +448,7 @@ Example to remove the first 10 pairs from the pairlist, and takes the next 20 (t
|
|||||||
```
|
```
|
||||||
|
|
||||||
!!! Warning
|
!!! Warning
|
||||||
When `OffsetFilter` is used to split a larger pairlist among multiple bots in combination with `VolumeFilter`
|
When `OffsetFilter` is used to split a larger pairlist among multiple bots in combination with `VolumeFilter`
|
||||||
it can not be guaranteed that pairs won't overlap due to slightly different refresh intervals for the
|
it can not be guaranteed that pairs won't overlap due to slightly different refresh intervals for the
|
||||||
`VolumeFilter`.
|
`VolumeFilter`.
|
||||||
|
|
||||||
@@ -599,7 +611,7 @@ Adding `"sort_direction": "asc"` or `"sort_direction": "desc"` enables sorting m
|
|||||||
|
|
||||||
### Full example of Pairlist Handlers
|
### Full example of Pairlist Handlers
|
||||||
|
|
||||||
The below example blacklists `BNB/BTC`, uses `VolumePairList` with `20` assets, sorting pairs by `quoteVolume` and applies [`PrecisionFilter`](#precisionfilter) and [`PriceFilter`](#pricefilter), filtering all assets where 1 price unit is > 1%. Then the [`SpreadFilter`](#spreadfilter) and [`VolatilityFilter`](#volatilityfilter) is applied and pairs are finally shuffled with the random seed set to some predefined value.
|
The below example blacklists `BNB/BTC`, uses `VolumePairList` with `20` assets, sorting pairs by `quoteVolume`, then filter future delisted pairs using [`DelistFilter`](#delistfilter) and [`AgeFilter`](#agefilter) to remove pairs that are listed less than 10 days ago. After that [`PrecisionFilter`](#precisionfilter) and [`PriceFilter`](#pricefilter) are applied, filtering all assets where 1 price unit is > 1%. Then the [`SpreadFilter`](#spreadfilter) and [`VolatilityFilter`](#volatilityfilter) are applied and pairs are finally shuffled with the random seed set to some predefined value.
|
||||||
|
|
||||||
```json
|
```json
|
||||||
"exchange": {
|
"exchange": {
|
||||||
@@ -612,6 +624,10 @@ The below example blacklists `BNB/BTC`, uses `VolumePairList` with `20` assets,
|
|||||||
"number_assets": 20,
|
"number_assets": 20,
|
||||||
"sort_key": "quoteVolume"
|
"sort_key": "quoteVolume"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"method": "DelistFilter",
|
||||||
|
"max_days_from_now": 0,
|
||||||
|
},
|
||||||
{"method": "AgeFilter", "min_days_listed": 10},
|
{"method": "AgeFilter", "min_days_listed": 10},
|
||||||
{"method": "PrecisionFilter"},
|
{"method": "PrecisionFilter"},
|
||||||
{"method": "PriceFilter", "low_price_ratio": 0.01},
|
{"method": "PriceFilter", "low_price_ratio": 0.01},
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
This section will highlight a few projects from members of the community.
|
This section will highlight a few projects from members of the community.
|
||||||
!!! Note
|
!!! Note
|
||||||
The projects below are for the most part not maintained by the freqtrade , therefore use your own caution before using them.
|
The projects below are for the most part not maintained by the freqtrade team, therefore use your own caution before using them.
|
||||||
|
|
||||||
- [Example freqtrade strategies](https://github.com/freqtrade/freqtrade-strategies/)
|
- [Example freqtrade strategies](https://github.com/freqtrade/freqtrade-strategies/)
|
||||||
- [FrequentHippo - Statistics of dry/live runs and backtests](http://frequenthippo.ddns.net) (by hippocritical).
|
- [FrequentHippo - Statistics of dry/live runs and backtests](http://frequenthippo.ddns.net) (by hippocritical).
|
||||||
- [Online pairlist generator](https://remotepairlist.com/) (by Blood4rc).
|
- [Online pairlist generator](https://remotepairlist.com/) (by Blood4rc).
|
||||||
- [Freqtrade Backtesting Project](https://strat.ninja/) (by Blood4rc).
|
- [Freqtrade Backtesting Project](https://strat.ninja/) (by Blood4rc).
|
||||||
- [Freqtrade analysis notebook](https://github.com/froggleston/freqtrade_analysis_notebook) (by Froggleston).
|
- [Freqtrade analysis notebook](https://github.com/froggleston/freqtrade_analysis_notebook) (by Froggleston).
|
||||||
- [TUI for freqtrade](https://github.com/froggleston/freqtrade-frogtrade9000) (by Froggleston).
|
- [FTUI - Terminal UI for freqtrade](https://github.com/freqtrade/ftui) (by Froggleston).
|
||||||
- [Bot Academy](https://botacademy.ddns.net/) (by stash86) - Blog about crypto bot projects.
|
- [Bot Academy](https://botacademy.ddns.net/) (by stash86) - Blog about crypto bot projects.
|
||||||
|
|||||||
@@ -0,0 +1,18 @@
|
|||||||
|
## Exit logic comparisons
|
||||||
|
|
||||||
|
Freqtrade allows your strategy to implement different exit logic using signal-based or callback-based functions.
|
||||||
|
This section aims to compare each different function, helping you to choose the one that best fits your needs.
|
||||||
|
|
||||||
|
* **`populate_exit_trend()`** - Vectorized signal-based exit logic using indicators in the main dataframe
|
||||||
|
✅ **Use** to define exit signals based on indicators or other data that can be calculated in a vectorized manner.
|
||||||
|
🚫 **Don't use** to customize exit conditions for each individual trade, or if trade data is necessary to make an exit decision.
|
||||||
|
* **`custom_exit()`** - Custom exit logic that will fully exit a trade immediately, called for every open trade at every bot loop iteration until a trade is closed.
|
||||||
|
✅ **Use** to specify exit conditions for each individual trade (including any additional adjusted orders using `adjust_trade_position()`), or if trade data is necessary to make an exit decision, e.g. using profit data to exit.
|
||||||
|
🚫 **Don't use** when you want to exit using vectorised indicator-based data (use a `populate_exit_trend()` signal instead), or as a proxy for `custom_stoploss()`, and be aware that rate-based exits in backtesting can be inaccurate.
|
||||||
|
* **`custom_stoploss()`** - Custom trailing stoploss, called for every open trade every iteration until a trade is closed. The value returned here is also used for [stoploss on exchange](stoploss.md#stop-loss-on-exchangefreqtrade).
|
||||||
|
✅ **Use** to customize the stoploss logic to set a dynamic stoploss based on trade data or other conditions.
|
||||||
|
🚫 **Don't use** to exit a trade immediately based on a specific condition. Use `custom_exit()` for that purpose.
|
||||||
|
* **`custom_roi()`** - Custom ROI, called for every open trade every iteration until a trade is closed.
|
||||||
|
✅ **Use** to specify a minimum ROI threshold ("take-profit") to exit a trade at this ROI level at some point within the trade duration, based on profit or other conditions.
|
||||||
|
🚫 **Don't use** to exit a trade immediately based on a specific condition. Use `custom_exit()`.
|
||||||
|
🚫 **Don't use** for static ROI. Use `minimal_roi`.
|
||||||
+5
-7
@@ -3,12 +3,11 @@
|
|||||||
[](https://github.com/freqtrade/freqtrade/actions/)
|
[](https://github.com/freqtrade/freqtrade/actions/)
|
||||||
[](https://doi.org/10.21105/joss.04864)
|
[](https://doi.org/10.21105/joss.04864)
|
||||||
[](https://coveralls.io/github/freqtrade/freqtrade?branch=develop)
|
[](https://coveralls.io/github/freqtrade/freqtrade?branch=develop)
|
||||||
[](https://codeclimate.com/github/freqtrade/freqtrade/maintainability)
|
|
||||||
|
|
||||||
<!-- Place this tag where you want the button to render. -->
|
<!-- GitHub action buttons -->
|
||||||
<a class="github-button" href="https://github.com/freqtrade/freqtrade" data-icon="octicon-star" data-size="large" aria-label="Star freqtrade/freqtrade on GitHub">Star</a>
|
[:octicons-star-16: Star](https://github.com/freqtrade/freqtrade){ .md-button .md-button--sm }
|
||||||
<a class="github-button" href="https://github.com/freqtrade/freqtrade/fork" data-icon="octicon-repo-forked" data-size="large" aria-label="Fork freqtrade/freqtrade on GitHub">Fork</a>
|
[:octicons-repo-forked-16: Fork](https://github.com/freqtrade/freqtrade/fork){ .md-button .md-button--sm }
|
||||||
<a class="github-button" href="https://github.com/freqtrade/freqtrade/archive/stable.zip" data-icon="octicon-cloud-download" data-size="large" aria-label="Download freqtrade/freqtrade on GitHub">Download</a>
|
[:octicons-download-16: Download](https://github.com/freqtrade/freqtrade/archive/stable.zip){ .md-button .md-button--sm }
|
||||||
|
|
||||||
## Introduction
|
## Introduction
|
||||||
|
|
||||||
@@ -31,7 +30,6 @@ Freqtrade is a free and open source crypto trading bot written in Python. It is
|
|||||||
- Optimize: Find the best parameters for your strategy using hyperoptimization which employs machine learning methods. You can optimize buy, sell, take profit (ROI), stop-loss and trailing stop-loss parameters for your strategy.
|
- Optimize: Find the best parameters for your strategy using hyperoptimization which employs machine learning methods. You can optimize buy, sell, take profit (ROI), stop-loss and trailing stop-loss parameters for your strategy.
|
||||||
- Select markets: Create your static list or use an automatic one based on top traded volumes and/or prices (not available during backtesting). You can also explicitly blacklist markets you don't want to trade.
|
- Select markets: Create your static list or use an automatic one based on top traded volumes and/or prices (not available during backtesting). You can also explicitly blacklist markets you don't want to trade.
|
||||||
- Run: Test your strategy with simulated money (Dry-Run mode) or deploy it with real money (Live-Trade mode).
|
- Run: Test your strategy with simulated money (Dry-Run mode) or deploy it with real money (Live-Trade mode).
|
||||||
- Run using Edge (optional module): The concept is to find the best historical [trade expectancy](edge.md#expectancy) by markets based on variation of the stop-loss and then allow/reject markets to trade. The sizing of the trade is based on a risk of a percentage of your capital.
|
|
||||||
- Control/Monitor: Use Telegram or a WebUI (start/stop the bot, show profit/loss, daily summary, current open trades results, etc.).
|
- Control/Monitor: Use Telegram or a WebUI (start/stop the bot, show profit/loss, daily summary, current open trades results, etc.).
|
||||||
- Analyze: Further analysis can be performed on either Backtesting data or Freqtrade trading history (SQL database), including automated standard plots, and methods to load the data into [interactive environments](data-analysis.md).
|
- Analyze: Further analysis can be performed on either Backtesting data or Freqtrade trading history (SQL database), including automated standard plots, and methods to load the data into [interactive environments](data-analysis.md).
|
||||||
|
|
||||||
@@ -88,7 +86,7 @@ To run this bot we recommend you a linux cloud instance with a minimum of:
|
|||||||
|
|
||||||
Alternatively
|
Alternatively
|
||||||
|
|
||||||
- Python 3.10+
|
- Python 3.11+
|
||||||
- pip (pip3)
|
- pip (pip3)
|
||||||
- git
|
- git
|
||||||
- TA-Lib
|
- TA-Lib
|
||||||
|
|||||||
+5
-45
@@ -24,7 +24,7 @@ The easiest way to install and run Freqtrade is to clone the bot Github reposito
|
|||||||
The `stable` branch contains the code of the last release (done usually once per month on an approximately one week old snapshot of the `develop` branch to prevent packaging bugs, so potentially it's more stable).
|
The `stable` branch contains the code of the last release (done usually once per month on an approximately one week old snapshot of the `develop` branch to prevent packaging bugs, so potentially it's more stable).
|
||||||
|
|
||||||
!!! Note
|
!!! Note
|
||||||
Python3.10 or higher and the corresponding `pip` are assumed to be available. The install-script will warn you and stop if that's not the case. `git` is also needed to clone the Freqtrade repository.
|
Python3.11 or higher and the corresponding `pip` are assumed to be available. The install-script will warn you and stop if that's not the case. `git` is also needed to clone the Freqtrade repository.
|
||||||
Also, python headers (`python<yourversion>-dev` / `python<yourversion>-devel`) must be available for the installation to complete successfully.
|
Also, python headers (`python<yourversion>-dev` / `python<yourversion>-devel`) must be available for the installation to complete successfully.
|
||||||
|
|
||||||
!!! Warning "Up-to-date clock"
|
!!! Warning "Up-to-date clock"
|
||||||
@@ -42,11 +42,10 @@ These requirements apply to both [Script Installation](#script-installation) and
|
|||||||
|
|
||||||
### Install guide
|
### Install guide
|
||||||
|
|
||||||
* [Python >= 3.10](http://docs.python-guide.org/en/latest/starting/installation/)
|
* [Python >= 3.11](http://docs.python-guide.org/en/latest/starting/installation/)
|
||||||
* [pip](https://pip.pypa.io/en/stable/installing/)
|
* [pip](https://pip.pypa.io/en/stable/installing/)
|
||||||
* [git](https://git-scm.com/book/en/v2/Getting-Started-Installing-Git)
|
* [git](https://git-scm.com/book/en/v2/Getting-Started-Installing-Git)
|
||||||
* [virtualenv](https://virtualenv.pypa.io/en/stable/installation.html) (Recommended)
|
* [virtualenv](https://virtualenv.pypa.io/en/stable/installation.html) (Recommended)
|
||||||
* [TA-Lib](https://ta-lib.github.io/ta-lib-python/) (install instructions [below](#install-ta-lib))
|
|
||||||
|
|
||||||
### Install code
|
### Install code
|
||||||
|
|
||||||
@@ -54,7 +53,7 @@ We've included/collected install instructions for Ubuntu, MacOS, and Windows. Th
|
|||||||
OS Specific steps are listed first, the common section below is necessary for all systems.
|
OS Specific steps are listed first, the common section below is necessary for all systems.
|
||||||
|
|
||||||
!!! Note
|
!!! Note
|
||||||
Python3.10 or higher and the corresponding pip are assumed to be available.
|
Python3.11 or higher and the corresponding pip are assumed to be available.
|
||||||
|
|
||||||
=== "Debian/Ubuntu"
|
=== "Debian/Ubuntu"
|
||||||
#### Install necessary dependencies
|
#### Install necessary dependencies
|
||||||
@@ -87,7 +86,7 @@ OS Specific steps are listed first, the common section below is necessary for al
|
|||||||
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
sudo apt-get install python3-venv libatlas-base-dev cmake curl
|
sudo apt-get install python3-venv libatlas-base-dev cmake curl libffi-dev
|
||||||
# Use piwheels.org to speed up installation
|
# Use piwheels.org to speed up installation
|
||||||
sudo echo "[global]\nextra-index-url=https://www.piwheels.org/simple" > tee /etc/pip.conf
|
sudo echo "[global]\nextra-index-url=https://www.piwheels.org/simple" > tee /etc/pip.conf
|
||||||
|
|
||||||
@@ -179,7 +178,7 @@ You can as well update, configure and reset the codebase of your bot with `./scr
|
|||||||
** --install **
|
** --install **
|
||||||
|
|
||||||
With this option, the script will install the bot and most dependencies:
|
With this option, the script will install the bot and most dependencies:
|
||||||
You will need to have git and python3.10+ installed beforehand for this to work.
|
You will need to have git and python3.11+ installed beforehand for this to work.
|
||||||
|
|
||||||
* Mandatory software as: `ta-lib`
|
* Mandatory software as: `ta-lib`
|
||||||
* Setup your virtualenv under `.venv/`
|
* Setup your virtualenv under `.venv/`
|
||||||
@@ -201,35 +200,6 @@ This option will hard reset your branch (only if you are on either `stable` or `
|
|||||||
|
|
||||||
Make sure you fulfill the [Requirements](#requirements) and have downloaded the [Freqtrade repository](#freqtrade-repository).
|
Make sure you fulfill the [Requirements](#requirements) and have downloaded the [Freqtrade repository](#freqtrade-repository).
|
||||||
|
|
||||||
### Install TA-Lib
|
|
||||||
|
|
||||||
#### TA-Lib script installation
|
|
||||||
|
|
||||||
```bash
|
|
||||||
sudo ./build_helpers/install_ta-lib.sh
|
|
||||||
```
|
|
||||||
|
|
||||||
!!! Note
|
|
||||||
This will use the ta-lib tar.gz included in this repository.
|
|
||||||
|
|
||||||
##### TA-Lib manual installation
|
|
||||||
|
|
||||||
[Official installation guide](https://ta-lib.github.io/ta-lib-python/install.html)
|
|
||||||
|
|
||||||
```bash
|
|
||||||
wget http://prdownloads.sourceforge.net/ta-lib/ta-lib-0.4.0-src.tar.gz
|
|
||||||
tar xvzf ta-lib-0.4.0-src.tar.gz
|
|
||||||
cd ta-lib
|
|
||||||
sed -i.bak "s|0.00000001|0.000000000000000001 |g" src/ta_func/ta_utility.h
|
|
||||||
./configure --prefix=/usr/local
|
|
||||||
make
|
|
||||||
sudo make install
|
|
||||||
# On debian based systems (debian, ubuntu, ...) - updating ldconfig might be necessary.
|
|
||||||
sudo ldconfig
|
|
||||||
cd ..
|
|
||||||
rm -rf ./ta-lib*
|
|
||||||
```
|
|
||||||
|
|
||||||
### Setup Python virtual environment (virtualenv)
|
### Setup Python virtual environment (virtualenv)
|
||||||
|
|
||||||
You will run freqtrade in separated `virtual environment`
|
You will run freqtrade in separated `virtual environment`
|
||||||
@@ -332,16 +302,6 @@ python3 -m pip install -r requirements.txt
|
|||||||
python3 -m pip install -e .
|
python3 -m pip install -e .
|
||||||
```
|
```
|
||||||
|
|
||||||
Patch conda libta-lib (Linux only)
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Ensure that the environment is active!
|
|
||||||
conda activate freqtrade
|
|
||||||
|
|
||||||
cd build_helpers
|
|
||||||
bash install_ta-lib.sh ${CONDA_PREFIX} nosudo
|
|
||||||
```
|
|
||||||
|
|
||||||
[You are now ready](#you-are-ready) to run the bot.
|
[You are now ready](#you-are-ready) to run the bot.
|
||||||
|
|
||||||
### Important shortcuts
|
### Important shortcuts
|
||||||
|
|||||||
+72
-36
@@ -1,72 +1,108 @@
|
|||||||
# Lookahead analysis
|
# Lookahead analysis
|
||||||
|
|
||||||
This page explains how to validate your strategy in terms of look ahead bias.
|
This page explains how to validate your strategy in terms of lookahead bias.
|
||||||
|
|
||||||
Checking look ahead bias is the bane of any strategy since it is sometimes very easy to introduce backtest bias -
|
Lookahead bias is the bane of any strategy since it is sometimes very easy to introduce this bias, but can be very hard to detect.
|
||||||
but very hard to detect.
|
|
||||||
|
|
||||||
Backtesting initializes all timestamps at once and calculates all indicators in the beginning.
|
Backtesting initializes all timestamps (loads the whole dataframe into memory) and calculates all indicators at once.
|
||||||
This means that if your indicators or entry/exit signals could look into future candles and falsify your backtest.
|
This means that if your indicators or entry/exit signals look into future candles, this will falsify your backtest.
|
||||||
|
|
||||||
Lookahead-analysis requires historic data to be available.
|
The `lookahead-analysis` command requires historic data to be available.
|
||||||
To learn how to get data for the pairs and exchange you're interested in,
|
To learn how to get data for the pairs and exchange you're interested in,
|
||||||
head over to the [Data Downloading](data-download.md) section of the documentation.
|
head over to the [Data Downloading](data-download.md) section of the documentation.
|
||||||
|
`lookahead-analysis` also supports freqai strategies.
|
||||||
|
|
||||||
This command is built upon backtesting since it internally chains backtests and pokes at the strategy to provoke it to show look ahead bias.
|
This command internally chains backtests and pokes at the strategy to provoke it to show lookahead bias.
|
||||||
This is done by not looking at the strategy itself - but at the results it returned.
|
This is done by not looking at the strategy code itself, but at changed indicator values and moved entries/exits compared to the full backtest.
|
||||||
The results are things like changed indicator-values and moved entries/exits compared to the full backtest.
|
|
||||||
|
|
||||||
You can use commands of [Backtesting](backtesting.md).
|
`lookahead-analysis` can use the typical options of [Backtesting](backtesting.md), but forces the following options:
|
||||||
It also supports the lookahead-analysis of freqai strategies.
|
|
||||||
|
|
||||||
- `--cache` is forced to "none".
|
- `--cache` is forced to "none".
|
||||||
- `--max-open-trades` is forced to be at least equal to the number of pairs.
|
- `--max-open-trades` is forced to be at least equal to the number of pairs.
|
||||||
- `--dry-run-wallet` is forced to be basically infinite (1 billion).
|
- `--dry-run-wallet` is forced to be basically infinite (1 billion).
|
||||||
- `--stake-amount` is forced to be a static 10000 (10k).
|
- `--stake-amount` is forced to be a static 10000 (10k).
|
||||||
- `--enable-protections` is forced to be off.
|
- `--enable-protections` is forced to be off.
|
||||||
|
- `order_types` are forced to be "market" (late entries) unless `--lookahead-allow-limit-orders` is set.
|
||||||
|
|
||||||
Those are set to avoid users accidentally generating false positives.
|
These are set to avoid users accidentally generating false positives.
|
||||||
|
|
||||||
## Lookahead-analysis command reference
|
## Lookahead-analysis command reference
|
||||||
|
|
||||||
--8<-- "commands/lookahead-analysis.md"
|
--8<-- "commands/lookahead-analysis.md"
|
||||||
|
|
||||||
!!! Note ""
|
!!! Note
|
||||||
The above Output was reduced to options `lookahead-analysis` adds on top of regular backtesting commands.
|
The above output was reduced to options that `lookahead-analysis` adds on top of regular backtesting commands.
|
||||||
|
|
||||||
### Summary
|
|
||||||
|
|
||||||
Checks a given strategy for look ahead bias via lookahead-analysis
|
|
||||||
Look ahead bias means that the backtest uses data from future candles thereby not making it viable beyond backtesting
|
|
||||||
and producing false hopes for the one backtesting.
|
|
||||||
|
|
||||||
### Introduction
|
### Introduction
|
||||||
|
|
||||||
Many strategies - without the programmer knowing - have fallen prey to look ahead bias.
|
Many strategies, without the programmer knowing, have fallen prey to lookahead bias.
|
||||||
|
This typically makes the strategy backtest look profitable, sometimes to extremes, but this is not realistic as the strategy is "cheating" by looking at data it would not have in dry or live modes.
|
||||||
|
|
||||||
Any backtest will populate the full dataframe including all time stamps at the beginning.
|
The reason why strategies can "cheat" is because the freqtrade backtesting process populates the full dataframe including all candle timestamps at the outset.
|
||||||
If the programmer is not careful or oblivious how things work internally
|
If the programmer is not careful or oblivious how things work internally
|
||||||
(which sometimes can be really hard to find out) then it will just look into the future making the strategy amazing
|
(which sometimes can be really hard to find out) then the strategy will look into the future.
|
||||||
but not realistic.
|
|
||||||
|
|
||||||
This command is made to try to verify the validity in the form of the aforementioned look ahead bias.
|
This command is made to try to verify the validity in the form of the aforementioned lookahead bias.
|
||||||
|
|
||||||
### How does the command work?
|
### How does the command work?
|
||||||
|
|
||||||
It will start with a backtest of all pairs to generate a baseline for indicators and entries/exits.
|
It will start with a backtest of all pairs to generate a baseline for indicators and entries/exits.
|
||||||
After the backtest ran, it will look if the `minimum-trade-amount` is met
|
After this initial backtest runs, it will look if the `minimum-trade-amount` is met and if not cancel the lookahead-analysis for this strategy.
|
||||||
and if not cancel the lookahead-analysis for this strategy.
|
If this happens, use a wider timerange to get more trades for the analysis, or use a timerange where more trades occur.
|
||||||
|
|
||||||
After setting the baseline it will then do additional runs for every entry and exit separately.
|
After setting the baseline it will then do additional backtest runs for every entry and exit separately.
|
||||||
When a verification-backtest is done, it will compare the indicators as the signal (either entry or exit) and report the bias.
|
When these verification backtests complete, it will compare both dataframes (baseline and sliced) for any difference in columns' value and report the bias.
|
||||||
After all signals have been verified or falsified a result-table will be generated for the user to see.
|
After all signals have been verified or falsified a result table will be generated for the user to see.
|
||||||
|
|
||||||
|
### How to find and remove bias? How can I salvage a biased strategy?
|
||||||
|
|
||||||
|
If you found a biased strategy online and want to have the same results, just without bias,
|
||||||
|
then you will be out of luck most of the time.
|
||||||
|
Usually the bias in the strategy is THE driving factor for "too good to be true" profits.
|
||||||
|
Removing conditions or indicators that push the profits up from bias will usually make the strategy significantly worse.
|
||||||
|
You might be able to salvage it partially if the biased indicators or conditions are not the core of the strategy, or there
|
||||||
|
are other entry and exit signals that are not biased.
|
||||||
|
|
||||||
|
### Examples of lookahead-bias
|
||||||
|
|
||||||
|
- `shift(-10)` looks 10 candles into the future.
|
||||||
|
- Using `iloc[]` in populate_* functions to access a specific row in the dataframe.
|
||||||
|
- For-loops are prone to introduce lookahead bias if you don't tightly control which numbers are looped through.
|
||||||
|
- Aggregation functions like `.mean()`, `.min()` and `.max()`, without a rolling window,
|
||||||
|
will calculate the value over the **whole** dataframe, so the signal candle will "see" a value including future candles.
|
||||||
|
A non-biased example would be to look back candles using `rolling()` instead:
|
||||||
|
e.g. `dataframe['volume_mean_12'] = dataframe['volume'].rolling(12).mean()`
|
||||||
|
- `ta.MACD(dataframe, 12, 26, 1)` will introduce bias with a signalperiod of 1.
|
||||||
|
|
||||||
|
### What do the columns in the results table mean?
|
||||||
|
|
||||||
|
- `filename`: name of the checked strategy file
|
||||||
|
- `strategy`: checked strategy class name
|
||||||
|
- `has_bias`: result of the lookahead-analysis. `No` would be good, `Yes` would be bad.
|
||||||
|
- `total_signals`: number of checked signals (default is 20)
|
||||||
|
- `biased_entry_signals`: found bias in that many entries
|
||||||
|
- `biased_exit_signals`: found bias in that many exits
|
||||||
|
- `biased_indicators`: shows you the indicators themselves that are defined in populate_indicators
|
||||||
|
|
||||||
|
You might get false positives in the `biased_exit_signals` if you have biased entry signals paired with those exits.
|
||||||
|
However, a biased entry will usually result in a biased exit too,
|
||||||
|
even if the exit itself does not produce the bias -
|
||||||
|
especially if your entry and exit conditions use the same biased indicator.
|
||||||
|
|
||||||
|
**Address the bias in the entries first, then address the exits.**
|
||||||
|
|
||||||
### Caveats
|
### Caveats
|
||||||
|
|
||||||
- `lookahead-analysis` can only verify / falsify the trades it calculated and verified.
|
- `lookahead-analysis` can only verify / falsify the trades it calculated and verified.
|
||||||
If the strategy has many different signals / signal types, it's up to you to select appropriate parameters to ensure that all signals have triggered at least once. Not triggered signals will not have been verified.
|
If the strategy has many different signals / signal types, it's up to you to select appropriate parameters to ensure that all signals have triggered at least once. Signals that are not triggered will not have been verified.
|
||||||
This could lead to a false-negative (the strategy will then be reported as non-biased).
|
This would lead to a false-negative, i.e. the strategy will be reported as non-biased.
|
||||||
- `lookahead-analysis` has access to everything that backtesting has too.
|
- `lookahead-analysis` has access to the same backtesting options and this can introduce problems.
|
||||||
Please don't provoke any configs like enabling position stacking.
|
Please don't use any options like enabling position stacking as this will distort the number of checked signals.
|
||||||
If you decide to do so, then make doubly sure that you won't ever run out of `max_open_trades` amount and neither leftover money in your wallet.
|
If you decide to do so, then make doubly sure that you won't ever run out of `max_open_trades` slots,
|
||||||
- In the results table, the `biased_indicators` column will falsely flag FreqAI target indicators defined in `set_freqai_targets()` as biased. These are not biased and can safely be ignored.
|
and that you have enough capital in the backtest wallet configuration.
|
||||||
|
- limit orders in combination with `custom_entry_price()` and `custom_exit_price()` callbacks can cause late / delayed entries and exists, causing false positives.
|
||||||
|
To avoid this - market orders are forced for this command. This implicitly means that `custom_entry_price()` and `custom_exit_price()` callbacks are not called.
|
||||||
|
Using `--lookahead-allow-limit-orders` will skip the override and use your configured order types - however has shown to eventually produce false positives.
|
||||||
|
- In the results table, the `biased_indicators` column
|
||||||
|
will falsely flag FreqAI target indicators defined in `set_freqai_targets()` as biased.
|
||||||
|
**These are not biased and can safely be ignored.**
|
||||||
|
|||||||
@@ -37,7 +37,6 @@
|
|||||||
{{ super() }}
|
{{ super() }}
|
||||||
|
|
||||||
<!-- Place this tag in your head or just before your close body tag. -->
|
<!-- Place this tag in your head or just before your close body tag. -->
|
||||||
<script async defer src="https://buttons.github.io/buttons.js"></script>
|
|
||||||
<script src="https://code.jquery.com/jquery-3.4.1.min.js"
|
<script src="https://code.jquery.com/jquery-3.4.1.min.js"
|
||||||
integrity="sha256-CSXorXvZcTkaix6Yvo6HppcZGetbYMGWSFlBw8HfCJo=" crossorigin="anonymous"></script>
|
integrity="sha256-CSXorXvZcTkaix6Yvo6HppcZGetbYMGWSFlBw8HfCJo=" crossorigin="anonymous"></script>
|
||||||
|
|
||||||
|
|||||||
@@ -50,6 +50,7 @@ Enable subscribing to an instance by adding the `external_message_consumer` sect
|
|||||||
| `ping_timeout` | Ping timeout <br>*Defaults to `10`.*<br> **Datatype:** Integer - in seconds.
|
| `ping_timeout` | Ping timeout <br>*Defaults to `10`.*<br> **Datatype:** Integer - in seconds.
|
||||||
| `sleep_time` | Sleep time before retrying to connect.<br>*Defaults to `10`.*<br> **Datatype:** Integer - in seconds.
|
| `sleep_time` | Sleep time before retrying to connect.<br>*Defaults to `10`.*<br> **Datatype:** Integer - in seconds.
|
||||||
| `remove_entry_exit_signals` | Remove signal columns from the dataframe (set them to 0) on dataframe receipt.<br>*Defaults to `false`.*<br> **Datatype:** Boolean.
|
| `remove_entry_exit_signals` | Remove signal columns from the dataframe (set them to 0) on dataframe receipt.<br>*Defaults to `false`.*<br> **Datatype:** Boolean.
|
||||||
|
| `initial_candle_limit` | Initial candles to expect from the Producer.<br>*Defaults to `1500`.*<br> **Datatype:** Integer - Number of candles.
|
||||||
| `message_size_limit` | Size limit per message<br>*Defaults to `8`.*<br> **Datatype:** Integer - Megabytes.
|
| `message_size_limit` | Size limit per message<br>*Defaults to `8`.*<br> **Datatype:** Integer - Megabytes.
|
||||||
|
|
||||||
Instead of (or as well as) calculating indicators in `populate_indicators()` the follower instance listens on the connection to a producer instance's messages (or multiple producer instances in advanced configurations) and requests the producer's most recently analyzed dataframes for each pair in the active whitelist.
|
Instead of (or as well as) calculating indicators in `populate_indicators()` the follower instance listens on the connection to a producer instance's messages (or multiple producer instances in advanced configurations) and requests the producer's most recently analyzed dataframes for each pair in the active whitelist.
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
markdown==3.8
|
markdown==3.9
|
||||||
mkdocs==1.6.1
|
mkdocs==1.6.1
|
||||||
mkdocs-material==9.6.12
|
mkdocs-material==9.6.20
|
||||||
mdx_truly_sane_lists==1.3
|
mdx_truly_sane_lists==1.3
|
||||||
pymdown-extensions==10.15
|
pymdown-extensions==10.16.1
|
||||||
jinja2==3.1.6
|
jinja2==3.1.6
|
||||||
mike==2.1.3
|
mike==2.1.3
|
||||||
|
|||||||
+54
-53
@@ -140,6 +140,11 @@ This method will work for all arguments - check the "show" command for a list of
|
|||||||
# Get the status of the bot
|
# Get the status of the bot
|
||||||
ping = client.ping()
|
ping = client.ping()
|
||||||
print(ping)
|
print(ping)
|
||||||
|
|
||||||
|
# Add pairs to blacklist
|
||||||
|
client.blacklist("BTC/USDT", "ETH/USDT")
|
||||||
|
# Add pairs to blacklist by supplying a list
|
||||||
|
client.blacklist(*listPairs)
|
||||||
# ...
|
# ...
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -155,66 +160,63 @@ freqtrade-client help
|
|||||||
Possible commands:
|
Possible commands:
|
||||||
|
|
||||||
available_pairs
|
available_pairs
|
||||||
Return available pair (backtest data) based on timeframe / stake_currency selection
|
Return available pair (backtest data) based on timeframe / stake_currency selection
|
||||||
|
|
||||||
:param timeframe: Only pairs with this timeframe available.
|
:param timeframe: Only pairs with this timeframe available.
|
||||||
:param stake_currency: Only pairs that include this timeframe
|
:param stake_currency: Only pairs that include this timeframe
|
||||||
|
|
||||||
balance
|
balance
|
||||||
Get the account balance.
|
Get the account balance.
|
||||||
|
|
||||||
blacklist
|
blacklist
|
||||||
Show the current blacklist.
|
Show the current blacklist.
|
||||||
|
|
||||||
:param add: List of coins to add (example: "BNB/BTC")
|
:param add: List of coins to add (example: "BNB/BTC")
|
||||||
|
|
||||||
cancel_open_order
|
cancel_open_order
|
||||||
Cancel open order for trade.
|
Cancel open order for trade.
|
||||||
|
|
||||||
:param trade_id: Cancels open orders for this trade.
|
:param trade_id: Cancels open orders for this trade.
|
||||||
|
|
||||||
count
|
count
|
||||||
Return the amount of open trades.
|
Return the amount of open trades.
|
||||||
|
|
||||||
daily
|
daily
|
||||||
Return the profits for each day, and amount of trades.
|
Return the profits for each day, and amount of trades.
|
||||||
|
|
||||||
delete_lock
|
delete_lock
|
||||||
Delete (disable) lock from the database.
|
Delete (disable) lock from the database.
|
||||||
|
|
||||||
:param lock_id: ID for the lock to delete
|
:param lock_id: ID for the lock to delete
|
||||||
|
|
||||||
delete_trade
|
delete_trade
|
||||||
Delete trade from the database.
|
Delete trade from the database.
|
||||||
Tries to close open orders. Requires manual handling of this asset on the exchange.
|
Tries to close open orders. Requires manual handling of this asset on the exchange.
|
||||||
|
|
||||||
:param trade_id: Deletes the trade with this ID from the database.
|
:param trade_id: Deletes the trade with this ID from the database.
|
||||||
|
|
||||||
edge
|
|
||||||
Return information about edge.
|
|
||||||
|
|
||||||
forcebuy
|
forcebuy
|
||||||
Buy an asset.
|
Buy an asset.
|
||||||
|
|
||||||
:param pair: Pair to buy (ETH/BTC)
|
:param pair: Pair to buy (ETH/BTC)
|
||||||
:param price: Optional - price to buy
|
:param price: Optional - price to buy
|
||||||
|
|
||||||
forceenter
|
forceenter
|
||||||
Force entering a trade
|
Force entering a trade
|
||||||
|
|
||||||
:param pair: Pair to buy (ETH/BTC)
|
:param pair: Pair to buy (ETH/BTC)
|
||||||
:param side: 'long' or 'short'
|
:param side: 'long' or 'short'
|
||||||
:param price: Optional - price to buy
|
:param price: Optional - price to buy
|
||||||
|
|
||||||
forceexit
|
forceexit
|
||||||
Force-exit a trade.
|
Force-exit a trade.
|
||||||
|
|
||||||
:param tradeid: Id of the trade (can be received via status command)
|
:param tradeid: Id of the trade (can be received via status command)
|
||||||
:param ordertype: Order type to use (must be market or limit)
|
:param ordertype: Order type to use (must be market or limit)
|
||||||
:param amount: Amount to sell. Full sell if not given
|
:param amount: Amount to sell. Full sell if not given
|
||||||
|
|
||||||
health
|
health
|
||||||
Provides a quick health check of the running bot.
|
Provides a quick health check of the running bot.
|
||||||
|
|
||||||
lock_add
|
lock_add
|
||||||
Manually lock a specific pair
|
Manually lock a specific pair
|
||||||
@@ -225,22 +227,22 @@ lock_add
|
|||||||
:param reason: Reason for the lock
|
:param reason: Reason for the lock
|
||||||
|
|
||||||
locks
|
locks
|
||||||
Return current locks
|
Return current locks
|
||||||
|
|
||||||
logs
|
logs
|
||||||
Show latest logs.
|
Show latest logs.
|
||||||
|
|
||||||
:param limit: Limits log messages to the last <limit> logs. No limit to get the entire log.
|
:param limit: Limits log messages to the last <limit> logs. No limit to get the entire log.
|
||||||
|
|
||||||
pair_candles
|
pair_candles
|
||||||
Return live dataframe for <pair><timeframe>.
|
Return live dataframe for <pair><timeframe>.
|
||||||
|
|
||||||
:param pair: Pair to get data for
|
:param pair: Pair to get data for
|
||||||
:param timeframe: Only pairs with this timeframe available.
|
:param timeframe: Only pairs with this timeframe available.
|
||||||
:param limit: Limit result to the last n candles.
|
:param limit: Limit result to the last n candles.
|
||||||
|
|
||||||
pair_history
|
pair_history
|
||||||
Return historic, analyzed dataframe
|
Return historic, analyzed dataframe
|
||||||
|
|
||||||
:param pair: Pair to get data for
|
:param pair: Pair to get data for
|
||||||
:param timeframe: Only pairs with this timeframe available.
|
:param timeframe: Only pairs with this timeframe available.
|
||||||
@@ -248,59 +250,59 @@ pair_history
|
|||||||
:param timerange: Timerange to get data for (same format than --timerange endpoints)
|
:param timerange: Timerange to get data for (same format than --timerange endpoints)
|
||||||
|
|
||||||
performance
|
performance
|
||||||
Return the performance of the different coins.
|
Return the performance of the different coins.
|
||||||
|
|
||||||
ping
|
ping
|
||||||
simple ping
|
simple ping
|
||||||
|
|
||||||
plot_config
|
plot_config
|
||||||
Return plot configuration if the strategy defines one.
|
Return plot configuration if the strategy defines one.
|
||||||
|
|
||||||
profit
|
profit
|
||||||
Return the profit summary.
|
Return the profit summary.
|
||||||
|
|
||||||
reload_config
|
reload_config
|
||||||
Reload configuration.
|
Reload configuration.
|
||||||
|
|
||||||
show_config
|
show_config
|
||||||
Returns part of the configuration, relevant for trading operations.
|
Returns part of the configuration, relevant for trading operations.
|
||||||
|
|
||||||
start
|
start
|
||||||
Start the bot if it's in the stopped state.
|
Start the bot if it's in the stopped state.
|
||||||
|
|
||||||
pause
|
pause
|
||||||
Pause the bot if it's in the running state. If triggered on stopped state will handle open positions.
|
Pause the bot if it's in the running state. If triggered on stopped state will handle open positions.
|
||||||
|
|
||||||
stats
|
stats
|
||||||
Return the stats report (durations, sell-reasons).
|
Return the stats report (durations, sell-reasons).
|
||||||
|
|
||||||
status
|
status
|
||||||
Get the status of open trades.
|
Get the status of open trades.
|
||||||
|
|
||||||
stop
|
stop
|
||||||
Stop the bot. Use `start` to restart.
|
Stop the bot. Use `start` to restart.
|
||||||
|
|
||||||
stopbuy
|
stopbuy
|
||||||
Stop buying (but handle sells gracefully). Use `reload_config` to reset.
|
Stop buying (but handle sells gracefully). Use `reload_config` to reset.
|
||||||
|
|
||||||
strategies
|
strategies
|
||||||
Lists available strategies
|
Lists available strategies
|
||||||
|
|
||||||
strategy
|
strategy
|
||||||
Get strategy details
|
Get strategy details
|
||||||
|
|
||||||
:param strategy: Strategy class name
|
:param strategy: Strategy class name
|
||||||
|
|
||||||
sysinfo
|
sysinfo
|
||||||
Provides system information (CPU, RAM usage)
|
Provides system information (CPU, RAM usage)
|
||||||
|
|
||||||
trade
|
trade
|
||||||
Return specific trade
|
Return specific trade
|
||||||
|
|
||||||
:param trade_id: Specify which trade to get.
|
:param trade_id: Specify which trade to get.
|
||||||
|
|
||||||
trades
|
trades
|
||||||
Return trades history, sorted by id
|
Return trades history, sorted by id
|
||||||
|
|
||||||
:param limit: Limits trades to the X last trades. Max 500 trades.
|
:param limit: Limits trades to the X last trades. Max 500 trades.
|
||||||
:param offset: Offset by this amount of trades.
|
:param offset: Offset by this amount of trades.
|
||||||
@@ -319,10 +321,10 @@ list_custom_data
|
|||||||
:param key: str, optional - Key of the custom-data
|
:param key: str, optional - Key of the custom-data
|
||||||
|
|
||||||
version
|
version
|
||||||
Return the version of the bot.
|
Return the version of the bot.
|
||||||
|
|
||||||
whitelist
|
whitelist
|
||||||
Show the current whitelist.
|
Show the current whitelist.
|
||||||
|
|
||||||
|
|
||||||
```
|
```
|
||||||
@@ -342,33 +344,32 @@ All endpoints in the below table need to be prefixed with the base URL of the AP
|
|||||||
| `/reload_config` | POST | Reloads the configuration file.
|
| `/reload_config` | POST | Reloads the configuration file.
|
||||||
| `/trades` | GET | List last trades. Limited to 500 trades per call.
|
| `/trades` | GET | List last trades. Limited to 500 trades per call.
|
||||||
| `/trade/<tradeid>` | GET | Get specific trade.<br/>*Params:*<br/>- `tradeid` (`int`)
|
| `/trade/<tradeid>` | GET | Get specific trade.<br/>*Params:*<br/>- `tradeid` (`int`)
|
||||||
| `/trades/<tradeid>` | DELETE | Remove trade from the database. Tries to close open orders. Requires manual handling of this trade on the exchange.<br/>*Params:*<br/>- `tradeid` (`int`)
|
| `/trades/<tradeid>` | DELETE | Remove trade from the database. Tries to close open orders. Requires manual handling of this trade on the exchange.<br/>*Params:*<br/>- `tradeid` (`int`)
|
||||||
| `/trades/<tradeid>/open-order` | DELETE | Cancel open order for this trade.<br/>*Params:*<br/>- `tradeid` (`int`)
|
| `/trades/<tradeid>/open-order` | DELETE | Cancel open order for this trade.<br/>*Params:*<br/>- `tradeid` (`int`)
|
||||||
| `/trades/<tradeid>/reload` | POST | Reload a trade from the Exchange. Only works in live, and can potentially help recover a trade that was manually sold on the exchange.<br/>*Params:*<br/>- `tradeid` (`int`)
|
| `/trades/<tradeid>/reload` | POST | Reload a trade from the Exchange. Only works in live, and can potentially help recover a trade that was manually sold on the exchange.<br/>*Params:*<br/>- `tradeid` (`int`)
|
||||||
| `/show_config` | GET | Shows part of the current configuration with relevant settings to operation.
|
| `/show_config` | GET | Shows part of the current configuration with relevant settings to operation.
|
||||||
| `/logs` | GET | Shows last log messages.
|
| `/logs` | GET | Shows last log messages.
|
||||||
| `/status` | GET | Lists all open trades.
|
| `/status` | GET | Lists all open trades.
|
||||||
| `/count` | GET | Displays number of trades used and available.
|
| `/count` | GET | Displays number of trades used and available.
|
||||||
| `/entries` | GET | Shows profit statistics for each enter tags for given pair (or all pairs if pair isn't given). Pair is optional.<br/>*Params:*<br/>- `pair` (`str`)
|
| `/entries` | GET | Shows profit statistics for each enter tags for given pair (or all pairs if pair isn't given). Pair is optional.<br/>*Params:*<br/>- `pair` (`str`)
|
||||||
| `/exits` | GET | Shows profit statistics for each exit reasons for given pair (or all pairs if pair isn't given). Pair is optional.<br/>*Params:*<br/>- `pair` (`str`)
|
| `/exits` | GET | Shows profit statistics for each exit reasons for given pair (or all pairs if pair isn't given). Pair is optional.<br/>*Params:*<br/>- `pair` (`str`)
|
||||||
| `/mix_tags` | GET | Shows profit statistics for each combinations of enter tag + exit reasons for given pair (or all pairs if pair isn't given). Pair is optional.<br/>*Params:*<br/>- `pair` (`str`)
|
| `/mix_tags` | GET | Shows profit statistics for each combinations of enter tag + exit reasons for given pair (or all pairs if pair isn't given). Pair is optional.<br/>*Params:*<br/>- `pair` (`str`)
|
||||||
| `/locks` | GET | Displays currently locked pairs.
|
| `/locks` | GET | Displays currently locked pairs.
|
||||||
| `/locks` | POST | Locks a pair until "until". (Until will be rounded up to the nearest timeframe). Side is optional and is either `long` or `short` (default is `long`). Reason is optional.<br/>*Params:*<br/>- `<pair>` (`str`)<br/>- `<until>` (`datetime`)<br/>- `[side]` (`str`)<br/>- `[reason]` (`str`)
|
| `/locks` | POST | Locks a pair until "until". (Until will be rounded up to the nearest timeframe). Side is optional and is either `long` or `short` (default is `long`). Reason is optional.<br/>*Params:*<br/>- `<pair>` (`str`)<br/>- `<until>` (`datetime`)<br/>- `[side]` (`str`)<br/>- `[reason]` (`str`)
|
||||||
| `/locks/<lockid>` | DELETE | Deletes (disables) the lock by id.<br/>*Params:*<br/>- `lockid` (`int`)
|
| `/locks/<lockid>` | DELETE | Deletes (disables) the lock by id.<br/>*Params:*<br/>- `lockid` (`int`)
|
||||||
| `/profit` | GET | Display a summary of your profit/loss from close trades and some stats about your performance.
|
| `/profit` | GET | Display a summary of your profit/loss from close trades and some stats about your performance.
|
||||||
| `/forceexit` | POST | Instantly exits the given trade (ignoring `minimum_roi`), using the given order type ("market" or "limit", uses your config setting if not specified), and the chosen amount (full sell if not specified). If `all` is supplied as the `tradeid`, then all currently open trades will be forced to exit.<br/>*Params:*<br/>- `<tradeid>` (`int` or `str`)<br/>- `<ordertype>` (`str`)<br/>- `[amount]` (`float`)
|
| `/forceexit` | POST | Instantly exits the given trade (ignoring `minimum_roi`), using the given order type ("market" or "limit", uses your config setting if not specified), and the chosen amount (full sell if not specified). If `all` is supplied as the `tradeid`, then all currently open trades will be forced to exit.<br/>*Params:*<br/>- `<tradeid>` (`int` or `str`)<br/>- `<ordertype>` (`str`)<br/>- `[amount]` (`float`)
|
||||||
| `/forceenter` | POST | Instantly enters the given pair. Side is optional and is either `long` or `short` (default is `long`). Rate is optional. (`force_entry_enable` must be set to True)<br/>*Params:*<br/>- `<pair>` (`str`)<br/>- `<side>` (`str`)<br/>- `[rate]` (`float`)
|
| `/forceenter` | POST | Instantly enters the given pair. Side is optional and is either `long` or `short` (default is `long`). Rate is optional. (`force_entry_enable` must be set to True)<br/>*Params:*<br/>- `<pair>` (`str`)<br/>- `<side>` (`str`)<br/>- `[rate]` (`float`)
|
||||||
| `/performance` | GET | Show performance of each finished trade grouped by pair.
|
| `/performance` | GET | Show performance of each finished trade grouped by pair.
|
||||||
| `/balance` | GET | Show account balance per currency.
|
| `/balance` | GET | Show account balance per currency.
|
||||||
| `/daily` | GET | Shows profit or loss per day, over the last n days (n defaults to 7).<br/>*Params:*<br/>- `<n>` (`int`)
|
| `/daily` | GET | Shows profit or loss per day, over the last n days (n defaults to 7).<br/>*Params:*<br/>- `timescale` (`int`)
|
||||||
| `/weekly` | GET | Shows profit or loss per week, over the last n days (n defaults to 4).<br/>*Params:*<br/>- `<n>` (`int`)
|
| `/weekly` | GET | Shows profit or loss per week, over the last n days (n defaults to 4).<br/>*Params:*<br/>- `timescale` (`int`)
|
||||||
| `/monthly` | GET | Shows profit or loss per month, over the last n days (n defaults to 3).<br/>*Params:*<br/>- `<n>` (`int`)
|
| `/monthly` | GET | Shows profit or loss per month, over the last n days (n defaults to 3).<br/>*Params:*<br/>- `timescale` (`int`)
|
||||||
| `/stats` | GET | Display a summary of profit / loss reasons as well as average holding times.
|
| `/stats` | GET | Display a summary of profit / loss reasons as well as average holding times.
|
||||||
| `/whitelist` | GET | Show the current whitelist.
|
| `/whitelist` | GET | Show the current whitelist.
|
||||||
| `/blacklist` | GET | Show the current blacklist.
|
| `/blacklist` | GET | Show the current blacklist.
|
||||||
| `/blacklist` | POST | Adds the specified pair to the blacklist.<br/>*Params:*<br/>- `pair` (`str`)
|
| `/blacklist` | POST | Adds the specified pair to the blacklist.<br/>*Params:*<br/>- `blacklist` (`str`)
|
||||||
| `/blacklist` | DELETE | Deletes the specified list of pairs from the blacklist.<br/>*Params:*<br/>- `[pair,pair]` (`list[str]`)
|
| `/blacklist` | DELETE | Deletes the specified list of pairs from the blacklist.<br/>*Params:*<br/>- `[pair,pair]` (`list[str]`)
|
||||||
| `/edge` | GET | Show validated pairs by Edge if it is enabled.
|
|
||||||
| `/pair_candles` | GET | Returns dataframe for a pair / timeframe combination while the bot is running. **Alpha**
|
| `/pair_candles` | GET | Returns dataframe for a pair / timeframe combination while the bot is running. **Alpha**
|
||||||
| `/pair_candles` | POST | Returns dataframe for a pair / timeframe combination while the bot is running, filtered by a provided list of columns to return. **Alpha**<br/>*Params:*<br/>- `<column_list>` (`list[str]`)
|
| `/pair_candles` | POST | Returns dataframe for a pair / timeframe combination while the bot is running, filtered by a provided list of columns to return. **Alpha**<br/>*Params:*<br/>- `<column_list>` (`list[str]`)
|
||||||
| `/pair_history` | GET | Returns an analyzed dataframe for a given timerange, analyzed by a given strategy. **Alpha**
|
| `/pair_history` | GET | Returns an analyzed dataframe for a given timerange, analyzed by a given strategy. **Alpha**
|
||||||
@@ -492,7 +493,7 @@ To properly configure your reverse proxy (securely), please consult it's documen
|
|||||||
### OpenAPI interface
|
### OpenAPI interface
|
||||||
|
|
||||||
To enable the builtin openAPI interface (Swagger UI), specify `"enable_openapi": true` in the api_server configuration.
|
To enable the builtin openAPI interface (Swagger UI), specify `"enable_openapi": true` in the api_server configuration.
|
||||||
This will enable the Swagger UI at the `/docs` endpoint. By default, that's running at http://localhost:8080/docs - but it'll depend on your settings.
|
This will enable the Swagger UI at the `/docs` endpoint. By default, that's running at <http://localhost:8080/docs> - but it'll depend on your settings.
|
||||||
|
|
||||||
### Advanced API usage using JWT tokens
|
### Advanced API usage using JWT tokens
|
||||||
|
|
||||||
|
|||||||
+4
-12
@@ -26,17 +26,9 @@ These modes can be configured with these values:
|
|||||||
Stoploss on exchange is only supported for the following exchanges, and not all exchanges support both stop-limit and stop-market.
|
Stoploss on exchange is only supported for the following exchanges, and not all exchanges support both stop-limit and stop-market.
|
||||||
The Order-type will be ignored if only one mode is available.
|
The Order-type will be ignored if only one mode is available.
|
||||||
|
|
||||||
| Exchange | stop-loss type |
|
??? info "Supported exchanges and stoploss types"
|
||||||
|----------|-------------|
|
|
||||||
| Binance | limit |
|
--8<-- "includes/exchange-features.md"
|
||||||
| Binance Futures | market, limit |
|
|
||||||
| Bingx | market, limit |
|
|
||||||
| HTX | limit |
|
|
||||||
| kraken | market, limit |
|
|
||||||
| Gate | limit |
|
|
||||||
| Okx | limit |
|
|
||||||
| Kucoin | stop-limit, stop-market|
|
|
||||||
| Hyperliquid (futures only) | limit |
|
|
||||||
|
|
||||||
!!! Note "Tight stoploss"
|
!!! Note "Tight stoploss"
|
||||||
<ins>Do not set too low/tight stoploss value when using stop loss on exchange!</ins>
|
<ins>Do not set too low/tight stoploss value when using stop loss on exchange!</ins>
|
||||||
@@ -256,4 +248,4 @@ The new stoploss value will be applied to open trades (and corresponding log-mes
|
|||||||
|
|
||||||
### Limitations
|
### Limitations
|
||||||
|
|
||||||
Stoploss values cannot be changed if `trailing_stop` is enabled and the stoploss has already been adjusted, or if [Edge](edge.md) is enabled (since Edge would recalculate stoploss based on the current market situation).
|
Stoploss values cannot be changed if `trailing_stop` is enabled and the stoploss has already been adjusted.
|
||||||
|
|||||||
+37
-14
@@ -174,17 +174,27 @@ class AwesomeStrategy(IStrategy):
|
|||||||
|
|
||||||
## Enter Tag
|
## Enter Tag
|
||||||
|
|
||||||
When your strategy has multiple buy signals, you can name the signal that triggered.
|
When your strategy has multiple entry signals, you can name the signal that triggered.
|
||||||
Then you can access your buy signal on `custom_exit`
|
Then you can access your entry signal on `custom_exit`
|
||||||
|
|
||||||
```python
|
```python
|
||||||
def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||||
|
dataframe["enter_tag"] = ""
|
||||||
|
signal_rsi = (qtpylib.crossed_above(dataframe["rsi"], 35))
|
||||||
|
signal_bblower = (dataframe["bb_lowerband"] < dataframe["close"])
|
||||||
|
# Additional conditions
|
||||||
dataframe.loc[
|
dataframe.loc[
|
||||||
(
|
(
|
||||||
(dataframe['rsi'] < 35) &
|
signal_rsi
|
||||||
(dataframe['volume'] > 0)
|
| signal_bblower
|
||||||
),
|
# ... additional signals to enter a long position
|
||||||
['enter_long', 'enter_tag']] = (1, 'buy_signal_rsi')
|
)
|
||||||
|
& (dataframe["volume"] > 0)
|
||||||
|
, "enter_long"
|
||||||
|
] = 1
|
||||||
|
# Concatenate the tags so all signals are kept
|
||||||
|
dataframe.loc[signal_rsi, "enter_tag"] += "long_signal_rsi "
|
||||||
|
dataframe.loc[signal_bblower, "enter_tag"] += "long_signal_bblower "
|
||||||
|
|
||||||
return dataframe
|
return dataframe
|
||||||
|
|
||||||
@@ -192,14 +202,17 @@ def custom_exit(self, pair: str, trade: Trade, current_time: datetime, current_r
|
|||||||
current_profit: float, **kwargs):
|
current_profit: float, **kwargs):
|
||||||
dataframe, _ = self.dp.get_analyzed_dataframe(pair, self.timeframe)
|
dataframe, _ = self.dp.get_analyzed_dataframe(pair, self.timeframe)
|
||||||
last_candle = dataframe.iloc[-1].squeeze()
|
last_candle = dataframe.iloc[-1].squeeze()
|
||||||
if trade.enter_tag == 'buy_signal_rsi' and last_candle['rsi'] > 80:
|
if "long_signal_rsi" in trade.enter_tag and last_candle["rsi"] > 80:
|
||||||
return 'sell_signal_rsi'
|
return "exit_signal_rsi"
|
||||||
|
if "long_signal_bblower" in trade.enter_tag and last_candle["high"] > last_candle["bb_upperband"]:
|
||||||
|
return "exit_signal_bblower"
|
||||||
|
# ...
|
||||||
return None
|
return None
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
!!! Note
|
!!! Note
|
||||||
`enter_tag` is limited to 100 characters, remaining data will be truncated.
|
`enter_tag` is limited to 255 characters, remaining data will be truncated.
|
||||||
|
|
||||||
!!! Warning
|
!!! Warning
|
||||||
There is only one `enter_tag` column, which is used for both long and short trades.
|
There is only one `enter_tag` column, which is used for both long and short trades.
|
||||||
@@ -213,17 +226,27 @@ Similar to [Entry Tagging](#enter-tag), you can also specify an exit tag.
|
|||||||
|
|
||||||
``` python
|
``` python
|
||||||
def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||||
|
dataframe["exit_tag"] = ""
|
||||||
|
rsi_exit_signal = (dataframe["rsi"] > 70)
|
||||||
|
ema_exit_signal = (dataframe["ema20"] < dataframe["ema50"])
|
||||||
|
# Additional conditions
|
||||||
dataframe.loc[
|
dataframe.loc[
|
||||||
(
|
(
|
||||||
(dataframe['rsi'] > 70) &
|
rsi_exit_signal
|
||||||
(dataframe['volume'] > 0)
|
| ema_exit_signal
|
||||||
),
|
# ... additional signals to exit a long position
|
||||||
['exit_long', 'exit_tag']] = (1, 'exit_rsi')
|
) &
|
||||||
|
(dataframe["volume"] > 0)
|
||||||
|
,
|
||||||
|
"exit_long"] = 1
|
||||||
|
# Concatenate the tags so all signals are kept
|
||||||
|
dataframe.loc[rsi_exit_signal, "exit_tag"] += "exit_signal_rsi "
|
||||||
|
dataframe.loc[rsi_exit_signal2, "exit_tag"] += "exit_signal_rsi "
|
||||||
|
|
||||||
return dataframe
|
return dataframe
|
||||||
```
|
```
|
||||||
|
|
||||||
The provided exit-tag is then used as sell-reason - and shown as such in backtest results.
|
The provided exit-tag is then used as exit-reason - and shown as such in backtest results.
|
||||||
|
|
||||||
!!! Note
|
!!! Note
|
||||||
`exit_reason` is limited to 100 characters, remaining data will be truncated.
|
`exit_reason` is limited to 100 characters, remaining data will be truncated.
|
||||||
|
|||||||
+267
-10
@@ -12,6 +12,7 @@ Currently available callbacks:
|
|||||||
* [`custom_stake_amount()`](#stake-size-management)
|
* [`custom_stake_amount()`](#stake-size-management)
|
||||||
* [`custom_exit()`](#custom-exit-signal)
|
* [`custom_exit()`](#custom-exit-signal)
|
||||||
* [`custom_stoploss()`](#custom-stoploss)
|
* [`custom_stoploss()`](#custom-stoploss)
|
||||||
|
* [`custom_roi()`](#custom-roi)
|
||||||
* [`custom_entry_price()` and `custom_exit_price()`](#custom-order-price-rules)
|
* [`custom_entry_price()` and `custom_exit_price()`](#custom-order-price-rules)
|
||||||
* [`check_entry_timeout()` and `check_exit_timeout()`](#custom-order-timeout-rules)
|
* [`check_entry_timeout()` and `check_exit_timeout()`](#custom-order-timeout-rules)
|
||||||
* [`confirm_trade_entry()`](#trade-entry-buy-order-confirmation)
|
* [`confirm_trade_entry()`](#trade-entry-buy-order-confirmation)
|
||||||
@@ -26,6 +27,9 @@ Currently available callbacks:
|
|||||||
|
|
||||||
--8<-- "includes/strategy-imports.md"
|
--8<-- "includes/strategy-imports.md"
|
||||||
|
|
||||||
|
--8<-- "includes/strategy-exit-comparisons.md"
|
||||||
|
|
||||||
|
|
||||||
## Bot start
|
## Bot start
|
||||||
|
|
||||||
A simple callback which is called once when the strategy is loaded.
|
A simple callback which is called once when the strategy is loaded.
|
||||||
@@ -121,7 +125,7 @@ Freqtrade will fall back to the `proposed_stake` value should your code raise an
|
|||||||
|
|
||||||
Called for open trade every throttling iteration (roughly every 5 seconds) until a trade is closed.
|
Called for open trade every throttling iteration (roughly every 5 seconds) until a trade is closed.
|
||||||
|
|
||||||
Allows to define custom exit signals, indicating that specified position should be sold. This is very useful when we need to customize exit conditions for each individual trade, or if you need trade data to make an exit decision.
|
Allows to define custom exit signals, indicating that specified position should be closed (full exit). This is very useful when we need to customize exit conditions for each individual trade, or if you need trade data to make an exit decision.
|
||||||
|
|
||||||
For example you could implement a 1:2 risk-reward ROI with `custom_exit()`.
|
For example you could implement a 1:2 risk-reward ROI with `custom_exit()`.
|
||||||
|
|
||||||
@@ -178,6 +182,8 @@ Returning `None` will be interpreted as "no desire to change", and is the only s
|
|||||||
|
|
||||||
Stoploss on exchange works similar to `trailing_stop`, and the stoploss on exchange is updated as configured in `stoploss_on_exchange_interval` ([More details about stoploss on exchange](stoploss.md#stop-loss-on-exchangefreqtrade)).
|
Stoploss on exchange works similar to `trailing_stop`, and the stoploss on exchange is updated as configured in `stoploss_on_exchange_interval` ([More details about stoploss on exchange](stoploss.md#stop-loss-on-exchangefreqtrade)).
|
||||||
|
|
||||||
|
If you're on futures markets, please take note of the [stoploss and leverage](stoploss.md#stoploss-and-leverage) section, as the stoploss value returned from `custom_stoploss` is the risk for this trade - not the relative price movement.
|
||||||
|
|
||||||
!!! Note "Use of dates"
|
!!! Note "Use of dates"
|
||||||
All time-based calculations should be done based on `current_time` - using `datetime.now()` or `datetime.utcnow()` is discouraged, as this will break backtesting support.
|
All time-based calculations should be done based on `current_time` - using `datetime.now()` or `datetime.utcnow()` is discouraged, as this will break backtesting support.
|
||||||
|
|
||||||
@@ -233,7 +239,7 @@ class AwesomeStrategy(IStrategy):
|
|||||||
:param **kwargs: Ensure to keep this here so updates to this won't break your strategy.
|
:param **kwargs: Ensure to keep this here so updates to this won't break your strategy.
|
||||||
:return float: New stoploss value, relative to the current_rate
|
:return float: New stoploss value, relative to the current_rate
|
||||||
"""
|
"""
|
||||||
return -0.04
|
return -0.04 * trade.leverage
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Time based trailing stop
|
#### Time based trailing stop
|
||||||
@@ -255,9 +261,9 @@ class AwesomeStrategy(IStrategy):
|
|||||||
|
|
||||||
# Make sure you have the longest interval first - these conditions are evaluated from top to bottom.
|
# Make sure you have the longest interval first - these conditions are evaluated from top to bottom.
|
||||||
if current_time - timedelta(minutes=120) > trade.open_date_utc:
|
if current_time - timedelta(minutes=120) > trade.open_date_utc:
|
||||||
return -0.05
|
return -0.05 * trade.leverage
|
||||||
elif current_time - timedelta(minutes=60) > trade.open_date_utc:
|
elif current_time - timedelta(minutes=60) > trade.open_date_utc:
|
||||||
return -0.10
|
return -0.10 * trade.leverage
|
||||||
return None
|
return None
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -284,9 +290,9 @@ class AwesomeStrategy(IStrategy):
|
|||||||
return stoploss_from_open(0.10, current_profit, is_short=trade.is_short, leverage=trade.leverage)
|
return stoploss_from_open(0.10, current_profit, is_short=trade.is_short, leverage=trade.leverage)
|
||||||
# Make sure you have the longest interval first - these conditions are evaluated from top to bottom.
|
# Make sure you have the longest interval first - these conditions are evaluated from top to bottom.
|
||||||
if current_time - timedelta(minutes=120) > trade.open_date_utc:
|
if current_time - timedelta(minutes=120) > trade.open_date_utc:
|
||||||
return -0.05
|
return -0.05 * trade.leverage
|
||||||
elif current_time - timedelta(minutes=60) > trade.open_date_utc:
|
elif current_time - timedelta(minutes=60) > trade.open_date_utc:
|
||||||
return -0.10
|
return -0.10 * trade.leverage
|
||||||
return None
|
return None
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -309,10 +315,10 @@ class AwesomeStrategy(IStrategy):
|
|||||||
**kwargs) -> float | None:
|
**kwargs) -> float | None:
|
||||||
|
|
||||||
if pair in ("ETH/BTC", "XRP/BTC"):
|
if pair in ("ETH/BTC", "XRP/BTC"):
|
||||||
return -0.10
|
return -0.10 * trade.leverage
|
||||||
elif pair in ("LTC/BTC"):
|
elif pair in ("LTC/BTC"):
|
||||||
return -0.05
|
return -0.05 * trade.leverage
|
||||||
return -0.15
|
return -0.15 * trade.leverage
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Trailing stoploss with positive offset
|
#### Trailing stoploss with positive offset
|
||||||
@@ -341,7 +347,7 @@ class AwesomeStrategy(IStrategy):
|
|||||||
desired_stoploss = current_profit / 2
|
desired_stoploss = current_profit / 2
|
||||||
|
|
||||||
# Use a minimum of 2.5% and a maximum of 5%
|
# Use a minimum of 2.5% and a maximum of 5%
|
||||||
return max(min(desired_stoploss, 0.05), 0.025)
|
return max(min(desired_stoploss, 0.05), 0.025) * trade.leverage
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Stepped stoploss
|
#### Stepped stoploss
|
||||||
@@ -497,6 +503,135 @@ The helper function `stoploss_from_absolute()` can be used to convert from an ab
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
## Custom ROI
|
||||||
|
|
||||||
|
Called for open trade every iteration (roughly every 5 seconds) until a trade is closed.
|
||||||
|
|
||||||
|
The usage of the custom ROI method must be enabled by setting `use_custom_roi=True` on the strategy object.
|
||||||
|
|
||||||
|
This method allows you to define a custom minimum ROI threshold for exiting a trade, expressed as a ratio (e.g., `0.05` for 5% profit). If both `minimal_roi` and `custom_roi` are defined, the lower of the two thresholds will trigger an exit. For example, if `minimal_roi` is set to `{"0": 0.10}` (10% at 0 minutes) and `custom_roi` returns `0.05`, the trade will exit when the profit reaches 5%. Also, if `custom_roi` returns `0.10` and `minimal_roi` is set to `{"0": 0.05}` (5% at 0 minutes), the trade will be closed when the profit reaches 5%.
|
||||||
|
|
||||||
|
The method must return a float representing the new ROI threshold as a ratio, or `None` to fall back to the `minimal_roi` logic. Returning `NaN` or `inf` values is considered invalid and will be treated as `None`, causing the bot to use the `minimal_roi` configuration.
|
||||||
|
|
||||||
|
### Custom ROI examples
|
||||||
|
|
||||||
|
The following examples illustrate how to use the `custom_roi` function to implement different ROI logics.
|
||||||
|
|
||||||
|
#### Custom ROI per side
|
||||||
|
|
||||||
|
Use different ROI thresholds depending on the `side`. In this example, 5% for long entries and 2% for short entries.
|
||||||
|
|
||||||
|
```python
|
||||||
|
# Default imports
|
||||||
|
|
||||||
|
class AwesomeStrategy(IStrategy):
|
||||||
|
|
||||||
|
use_custom_roi = True
|
||||||
|
|
||||||
|
# ... populate_* methods
|
||||||
|
|
||||||
|
def custom_roi(self, pair: str, trade: Trade, current_time: datetime, trade_duration: int,
|
||||||
|
entry_tag: str | None, side: str, **kwargs) -> float | None:
|
||||||
|
"""
|
||||||
|
Custom ROI logic, returns a new minimum ROI threshold (as a ratio, e.g., 0.05 for +5%).
|
||||||
|
Only called when use_custom_roi is set to True.
|
||||||
|
|
||||||
|
If used at the same time as minimal_roi, an exit will be triggered when the lower
|
||||||
|
threshold is reached. Example: If minimal_roi = {"0": 0.01} and custom_roi returns 0.05,
|
||||||
|
an exit will be triggered if profit reaches 5%.
|
||||||
|
|
||||||
|
:param pair: Pair that's currently analyzed.
|
||||||
|
:param trade: trade object.
|
||||||
|
:param current_time: datetime object, containing the current datetime.
|
||||||
|
:param trade_duration: Current trade duration in minutes.
|
||||||
|
:param entry_tag: Optional entry_tag (buy_tag) if provided with the buy signal.
|
||||||
|
:param side: 'long' or 'short' - indicating the direction of the current trade.
|
||||||
|
:param **kwargs: Ensure to keep this here so updates to this won't break your strategy.
|
||||||
|
:return float: New ROI value as a ratio, or None to fall back to minimal_roi logic.
|
||||||
|
"""
|
||||||
|
return 0.05 if side == "long" else 0.02
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Custom ROI per pair
|
||||||
|
|
||||||
|
Use different ROI thresholds depending on the `pair`.
|
||||||
|
|
||||||
|
```python
|
||||||
|
# Default imports
|
||||||
|
|
||||||
|
class AwesomeStrategy(IStrategy):
|
||||||
|
|
||||||
|
use_custom_roi = True
|
||||||
|
|
||||||
|
# ... populate_* methods
|
||||||
|
|
||||||
|
def custom_roi(self, pair: str, trade: Trade, current_time: datetime, trade_duration: int,
|
||||||
|
entry_tag: str | None, side: str, **kwargs) -> float | None:
|
||||||
|
|
||||||
|
stake = trade.stake_currency
|
||||||
|
roi_map = {
|
||||||
|
f"BTC/{stake}": 0.02, # 2% for BTC
|
||||||
|
f"ETH/{stake}": 0.03, # 3% for ETH
|
||||||
|
f"XRP/{stake}": 0.04, # 4% for XRP
|
||||||
|
}
|
||||||
|
|
||||||
|
return roi_map.get(pair, 0.01) # 1% for any other pair
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Custom ROI per entry tag
|
||||||
|
|
||||||
|
Use different ROI thresholds depending on the `entry_tag` provided with the buy signal.
|
||||||
|
|
||||||
|
```python
|
||||||
|
# Default imports
|
||||||
|
|
||||||
|
class AwesomeStrategy(IStrategy):
|
||||||
|
|
||||||
|
use_custom_roi = True
|
||||||
|
|
||||||
|
# ... populate_* methods
|
||||||
|
|
||||||
|
def custom_roi(self, pair: str, trade: Trade, current_time: datetime, trade_duration: int,
|
||||||
|
entry_tag: str | None, side: str, **kwargs) -> float | None:
|
||||||
|
|
||||||
|
roi_by_tag = {
|
||||||
|
"breakout": 0.08, # 8% if tag is "breakout"
|
||||||
|
"rsi_overbought": 0.05, # 5% if tag is "rsi_overbought"
|
||||||
|
"mean_reversion": 0.03, # 3% if tag is "mean_reversion"
|
||||||
|
}
|
||||||
|
|
||||||
|
return roi_by_tag.get(entry_tag, 0.01) # 1% if tag is unknown
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Custom ROI based on ATR
|
||||||
|
|
||||||
|
ROI value may be derived from indicators stored in dataframe. This example uses the ATR ratio as ROI.
|
||||||
|
|
||||||
|
``` python
|
||||||
|
# Default imports
|
||||||
|
# <...>
|
||||||
|
import talib.abstract as ta
|
||||||
|
|
||||||
|
class AwesomeStrategy(IStrategy):
|
||||||
|
|
||||||
|
use_custom_roi = True
|
||||||
|
|
||||||
|
def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||||
|
# <...>
|
||||||
|
dataframe["atr"] = ta.ATR(dataframe, timeperiod=10)
|
||||||
|
|
||||||
|
def custom_roi(self, pair: str, trade: Trade, current_time: datetime, trade_duration: int,
|
||||||
|
entry_tag: str | None, side: str, **kwargs) -> float | None:
|
||||||
|
|
||||||
|
dataframe, _ = self.dp.get_analyzed_dataframe(pair, self.timeframe)
|
||||||
|
last_candle = dataframe.iloc[-1].squeeze()
|
||||||
|
atr_ratio = last_candle["atr"] / last_candle["close"]
|
||||||
|
|
||||||
|
return atr_ratio # Returns the ATR value as ratio
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## Custom order price rules
|
## Custom order price rules
|
||||||
|
|
||||||
By default, freqtrade use the orderbook to automatically set an order price([Relevant documentation](configuration.md#prices-used-for-orders)), you also have the option to create custom order prices based on your strategy.
|
By default, freqtrade use the orderbook to automatically set an order price([Relevant documentation](configuration.md#prices-used-for-orders)), you also have the option to create custom order prices based on your strategy.
|
||||||
@@ -1107,3 +1242,125 @@ class AwesomeStrategy(IStrategy):
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
!!! Tip "Learn more about storing data"
|
||||||
|
You can learn more about storing data on the [Storing custom trade data](strategy-advanced.md#storing-information-persistent) section.
|
||||||
|
Please keep in mind that this is considered advanced usage, and should be used with care.
|
||||||
|
|
||||||
|
## Plot annotations callback
|
||||||
|
|
||||||
|
The plot annotations callback is called whenever freqUI requests data to display a chart.
|
||||||
|
This callback has no meaning in the trade cycle context and is only used for charting purposes.
|
||||||
|
|
||||||
|
The strategy can then return a list of `AnnotationType` objects to be displayed on the chart.
|
||||||
|
Depending on the content returned - the chart can display horizontal areas, vertical areas, or boxes.
|
||||||
|
|
||||||
|
The full object looks like this:
|
||||||
|
|
||||||
|
``` json
|
||||||
|
{
|
||||||
|
"type": "area", // Type of the annotation, currently only "area" is supported
|
||||||
|
"start": "2024-01-01 15:00:00", // Start date of the area
|
||||||
|
"end": "2024-01-01 16:00:00", // End date of the area
|
||||||
|
"y_start": 94000.2, // Price / y axis value
|
||||||
|
"y_end": 98000, // Price / y axis value
|
||||||
|
"color": "",
|
||||||
|
"z_level": 5, // z-level, higher values are drawn on top of lower values. Positions relative to the Chart elements need to be set in freqUI.
|
||||||
|
"label": "some label"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
The below example will mark the chart with areas for the hours 8 and 15, with a grey color, highlighting the market open and close hours.
|
||||||
|
This is obviously a very basic example.
|
||||||
|
|
||||||
|
``` python
|
||||||
|
# Default imports
|
||||||
|
|
||||||
|
class AwesomeStrategy(IStrategy):
|
||||||
|
def plot_annotations(
|
||||||
|
self, pair: str, start_date: datetime, end_date: datetime, dataframe: DataFrame, **kwargs
|
||||||
|
) -> list[AnnotationType]:
|
||||||
|
"""
|
||||||
|
Retrieve area annotations for a chart.
|
||||||
|
Must be returned as array, with type, label, color, start, end, y_start, y_end.
|
||||||
|
All settings except for type are optional - though it usually makes sense to include either
|
||||||
|
"start and end" or "y_start and y_end" for either horizontal or vertical plots
|
||||||
|
(or all 4 for boxes).
|
||||||
|
:param pair: Pair that's currently analyzed
|
||||||
|
:param start_date: Start date of the chart data being requested
|
||||||
|
:param end_date: End date of the chart data being requested
|
||||||
|
:param dataframe: DataFrame with the analyzed data for the chart
|
||||||
|
:param **kwargs: Ensure to keep this here so updates to this won't break your strategy.
|
||||||
|
:return: List of AnnotationType objects
|
||||||
|
"""
|
||||||
|
annotations = []
|
||||||
|
while start_dt < end_date:
|
||||||
|
start_dt += timedelta(hours=1)
|
||||||
|
if start_dt.hour in (8, 15):
|
||||||
|
annotations.append(
|
||||||
|
{
|
||||||
|
"type": "area",
|
||||||
|
"label": "Trade open and close hours",
|
||||||
|
"start": start_dt,
|
||||||
|
"end": start_dt + timedelta(hours=1),
|
||||||
|
# Omitting y_start and y_end will result in a vertical area spanning the whole height of the main Chart
|
||||||
|
"color": "rgba(133, 133, 133, 0.4)",
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
return annotations
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
Entries will be validated, and won't be passed to the UI if they don't correspond to the expected schema and will log an error if they don't.
|
||||||
|
|
||||||
|
!!! Warning "Many annotations"
|
||||||
|
Using too many annotations can cause the UI to hang, especially when plotting large amounts of historic data.
|
||||||
|
Use the annotation feature with care.
|
||||||
|
|
||||||
|
### Plot annotations example
|
||||||
|
|
||||||
|

|
||||||
|

|
||||||
|
|
||||||
|
??? Info "Code used for the plot above"
|
||||||
|
This is an example code and should be treated as such.
|
||||||
|
|
||||||
|
``` python
|
||||||
|
# Default imports
|
||||||
|
|
||||||
|
class AwesomeStrategy(IStrategy):
|
||||||
|
def plot_annotations(
|
||||||
|
self, pair: str, start_date: datetime, end_date: datetime, dataframe: DataFrame, **kwargs
|
||||||
|
) -> list[AnnotationType]:
|
||||||
|
annotations = []
|
||||||
|
while start_dt < end_date:
|
||||||
|
start_dt += timedelta(hours=1)
|
||||||
|
if (start_dt.hour % 4) == 0:
|
||||||
|
mark_areas.append(
|
||||||
|
{
|
||||||
|
"type": "area",
|
||||||
|
"label": "4h",
|
||||||
|
"start": start_dt,
|
||||||
|
"end": start_dt + timedelta(hours=1),
|
||||||
|
"color": "rgba(133, 133, 133, 0.4)",
|
||||||
|
}
|
||||||
|
)
|
||||||
|
elif (start_dt.hour % 2) == 0:
|
||||||
|
price = dataframe.loc[dataframe["date"] == start_dt, ["close"]].mean()
|
||||||
|
mark_areas.append(
|
||||||
|
{
|
||||||
|
"type": "area",
|
||||||
|
"label": "2h",
|
||||||
|
"start": start_dt,
|
||||||
|
"end": start_dt + timedelta(hours=1),
|
||||||
|
"y_end": price * 1.01,
|
||||||
|
"y_start": price * 0.99,
|
||||||
|
"color": "rgba(0, 255, 0, 0.4)",
|
||||||
|
"z_level": 5,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
return annotations
|
||||||
|
|
||||||
|
```
|
||||||
|
|||||||
@@ -84,6 +84,7 @@ Check the [configuration documentation](configuration.md) about how to set the b
|
|||||||
**Always use dry mode when testing as this gives you an idea of how your strategy will work in reality without risking capital.**
|
**Always use dry mode when testing as this gives you an idea of how your strategy will work in reality without risking capital.**
|
||||||
|
|
||||||
## Diving in deeper
|
## Diving in deeper
|
||||||
|
|
||||||
**For the following section we will use the [user_data/strategies/sample_strategy.py](https://github.com/freqtrade/freqtrade/blob/develop/freqtrade/templates/sample_strategy.py)
|
**For the following section we will use the [user_data/strategies/sample_strategy.py](https://github.com/freqtrade/freqtrade/blob/develop/freqtrade/templates/sample_strategy.py)
|
||||||
file as reference.**
|
file as reference.**
|
||||||
|
|
||||||
@@ -99,9 +100,9 @@ file as reference.**
|
|||||||
Some common patterns for this are listed in the [Common Mistakes](#common-mistakes-when-developing-strategies) section of this document.
|
Some common patterns for this are listed in the [Common Mistakes](#common-mistakes-when-developing-strategies) section of this document.
|
||||||
|
|
||||||
??? Hint "Lookahead and recursive analysis"
|
??? Hint "Lookahead and recursive analysis"
|
||||||
Freqtrade includes two helpful commands to help assess common lookahead (using future data) and
|
Freqtrade includes two helpful commands to help assess common lookahead (using future data) and
|
||||||
recursive bias (variance in indicator values) issues. Before running a strategy in dry or live more,
|
recursive bias (variance in indicator values) issues. Before running a strategy in dry or live more,
|
||||||
you should always use these commands first. Please check the relevant documentation for
|
you should always use these commands first. Please check the relevant documentation for
|
||||||
[lookahead](lookahead-analysis.md) and [recursive](recursive-analysis.md) analysis.
|
[lookahead](lookahead-analysis.md) and [recursive](recursive-analysis.md) analysis.
|
||||||
|
|
||||||
### Dataframe
|
### Dataframe
|
||||||
@@ -154,7 +155,7 @@ Vectorized operations perform calculations across the whole range of data and ar
|
|||||||
|
|
||||||
!!! Warning "Trade order assumptions"
|
!!! Warning "Trade order assumptions"
|
||||||
In backtesting, signals are generated on candle close. Trades are then initiated immeditely on next candle open.
|
In backtesting, signals are generated on candle close. Trades are then initiated immeditely on next candle open.
|
||||||
|
|
||||||
In dry and live, this may be delayed due to all pair dataframes needing to be analysed first, then trade processing
|
In dry and live, this may be delayed due to all pair dataframes needing to be analysed first, then trade processing
|
||||||
for each of those pairs happens. This means that in dry/live you need to be mindful of having as low a computation
|
for each of those pairs happens. This means that in dry/live you need to be mindful of having as low a computation
|
||||||
delay as possible, usually by running a low number of pairs and having a CPU with a good clock speed.
|
delay as possible, usually by running a low number of pairs and having a CPU with a good clock speed.
|
||||||
@@ -284,7 +285,7 @@ It's important to always return the dataframe without removing/modifying the col
|
|||||||
|
|
||||||
This method will also define a new column, `"enter_long"` (`"enter_short"` for shorts), which needs to contain `1` for entries, and `0` for "no action". `enter_long` is a mandatory column that must be set even if the strategy is shorting only.
|
This method will also define a new column, `"enter_long"` (`"enter_short"` for shorts), which needs to contain `1` for entries, and `0` for "no action". `enter_long` is a mandatory column that must be set even if the strategy is shorting only.
|
||||||
|
|
||||||
You can name your entry signals by using the `"enter_tag"` column, which can help debug and assess your strategy later.
|
You can name your entry signals by using the `"enter_tag"` column, which can help debug and assess your strategy later.
|
||||||
|
|
||||||
Sample from `user_data/strategies/sample_strategy.py`:
|
Sample from `user_data/strategies/sample_strategy.py`:
|
||||||
|
|
||||||
@@ -555,7 +556,7 @@ A full sample can be found [in the DataProvider section](#complete-dataprovider-
|
|||||||
|
|
||||||
??? Note "Alternative candle types"
|
??? Note "Alternative candle types"
|
||||||
Informative_pairs can also provide a 3rd tuple element defining the candle type explicitly.
|
Informative_pairs can also provide a 3rd tuple element defining the candle type explicitly.
|
||||||
Availability of alternative candle-types will depend on the trading-mode and the exchange.
|
Availability of alternative candle-types will depend on the trading-mode and the exchange.
|
||||||
In general, spot pairs cannot be used in futures markets, and futures candles can't be used as informative pairs for spot bots.
|
In general, spot pairs cannot be used in futures markets, and futures candles can't be used as informative pairs for spot bots.
|
||||||
Details about this may vary, if they do, this can be found in the exchange documentation.
|
Details about this may vary, if they do, this can be found in the exchange documentation.
|
||||||
|
|
||||||
@@ -783,6 +784,8 @@ Please always check the mode of operation to select the correct method to get da
|
|||||||
- `ohlcv(pair, timeframe)` - Currently cached candle (OHLCV) data for the pair, returns DataFrame or empty DataFrame.
|
- `ohlcv(pair, timeframe)` - Currently cached candle (OHLCV) data for the pair, returns DataFrame or empty DataFrame.
|
||||||
- [`orderbook(pair, maximum)`](#orderbookpair-maximum) - Returns latest orderbook data for the pair, a dict with bids/asks with a total of `maximum` entries.
|
- [`orderbook(pair, maximum)`](#orderbookpair-maximum) - Returns latest orderbook data for the pair, a dict with bids/asks with a total of `maximum` entries.
|
||||||
- [`ticker(pair)`](#tickerpair) - Returns current ticker data for the pair. See [ccxt documentation](https://github.com/ccxt/ccxt/wiki/Manual#price-tickers) for more details on the Ticker data structure.
|
- [`ticker(pair)`](#tickerpair) - Returns current ticker data for the pair. See [ccxt documentation](https://github.com/ccxt/ccxt/wiki/Manual#price-tickers) for more details on the Ticker data structure.
|
||||||
|
- [`check_delisting(pair)`](#check_delistingpair) - Return Datetime of the pair delisting schedule if any, otherwise return None
|
||||||
|
- [`funding_rate(pair)`](#funding_ratepair) - Returns current funding rate data for the pair.
|
||||||
- `runmode` - Property containing the current runmode.
|
- `runmode` - Property containing the current runmode.
|
||||||
|
|
||||||
### Example Usages
|
### Example Usages
|
||||||
@@ -854,6 +857,8 @@ dataframe, last_updated = self.dp.get_analyzed_dataframe(pair=metadata['pair'],
|
|||||||
|
|
||||||
### *orderbook(pair, maximum)*
|
### *orderbook(pair, maximum)*
|
||||||
|
|
||||||
|
Retrieve the current order book for a pair.
|
||||||
|
|
||||||
``` python
|
``` python
|
||||||
if self.dp.runmode.value in ('live', 'dry_run'):
|
if self.dp.runmode.value in ('live', 'dry_run'):
|
||||||
ob = self.dp.orderbook(metadata['pair'], 1)
|
ob = self.dp.orderbook(metadata['pair'], 1)
|
||||||
@@ -903,6 +908,69 @@ if self.dp.runmode.value in ('live', 'dry_run'):
|
|||||||
!!! Warning "Warning about backtesting"
|
!!! Warning "Warning about backtesting"
|
||||||
This method will always return up-to-date / real-time values. As such, usage during backtesting / hyperopt without runmode checks will lead to wrong results, e.g. your whole dataframe will contain the same single value in all rows.
|
This method will always return up-to-date / real-time values. As such, usage during backtesting / hyperopt without runmode checks will lead to wrong results, e.g. your whole dataframe will contain the same single value in all rows.
|
||||||
|
|
||||||
|
### *check_delisting(pair)*
|
||||||
|
|
||||||
|
```python
|
||||||
|
def custom_exit(self, pair: str, trade: Trade, current_time: datetime, current_rate: float, current_profit: float, **kwargs):
|
||||||
|
if self.dp.runmode.value in ('live', 'dry_run'):
|
||||||
|
delisting_dt = self.dp.check_delisting(pair)
|
||||||
|
if delisting_dt is not None:
|
||||||
|
return "delist"
|
||||||
|
```
|
||||||
|
|
||||||
|
!!! Note "Availabiity of delisting information"
|
||||||
|
This method is only available for certain exchanges and will return `None` in cases this is not available or if the pair is not scheduled for delisting.
|
||||||
|
|
||||||
|
!!! Warning "Warning about backtesting"
|
||||||
|
This method will always return up-to-date / real-time values. As such, usage during backtesting / hyperopt without runmode checks will lead to wrong results, e.g. your whole dataframe will contain the same single value in all rows.
|
||||||
|
|
||||||
|
### *funding_rate(pair)*
|
||||||
|
|
||||||
|
Retrieves the current funding rate for the pair and only works for futures pairs in the format of `base/quote:settle` (e.g. `ETH/USDT:USDT`).
|
||||||
|
|
||||||
|
``` python
|
||||||
|
if self.dp.runmode.value in ('live', 'dry_run'):
|
||||||
|
funding_rate = self.dp.funding_rate(metadata['pair'])
|
||||||
|
dataframe['current_funding_rate'] = funding_rate['fundingRate']
|
||||||
|
dataframe['next_funding_timestamp'] = funding_rate['fundingTimestamp']
|
||||||
|
dataframe['next_funding_datetime'] = funding_rate['fundingDatetime']
|
||||||
|
```
|
||||||
|
|
||||||
|
The funding rate structure is aligned with the funding rate structure from [ccxt](https://github.com/ccxt/ccxt/wiki/Manual#funding-rate-structure), so the result will be formatted as follows:
|
||||||
|
|
||||||
|
``` python
|
||||||
|
{
|
||||||
|
"info": {
|
||||||
|
# ...
|
||||||
|
},
|
||||||
|
"symbol": "BTC/USDT:USDT",
|
||||||
|
"markPrice": 110730.7,
|
||||||
|
"indexPrice": 110782.52,
|
||||||
|
"interestRate": 0.0001,
|
||||||
|
"estimatedSettlePrice": 110822.67200153,
|
||||||
|
"timestamp": 1757146321001,
|
||||||
|
"datetime": "2025-09-06T08:12:01.001Z",
|
||||||
|
"fundingRate": 5.609e-05,
|
||||||
|
"fundingTimestamp": 1757174400000,
|
||||||
|
"fundingDatetime": "2025-09-06T16:00:00.000Z",
|
||||||
|
"nextFundingRate": None,
|
||||||
|
"nextFundingTimestamp": None,
|
||||||
|
"nextFundingDatetime": None,
|
||||||
|
"previousFundingRate": None,
|
||||||
|
"previousFundingTimestamp": None,
|
||||||
|
"previousFundingDatetime": None,
|
||||||
|
"interval": None,
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Therefore, using `funding_rate['fundingRate']` as demonstrated above will use the current funding rate.
|
||||||
|
Actually available data will vary between exchanges, so this code may not work as expected across exchanges.
|
||||||
|
|
||||||
|
!!! Warning "Warning about backtesting"
|
||||||
|
Current funding-rate is not part of the historic data which means backtesting and hyperopt will not work correctly if this method is used, as the method will return up-to-date values.
|
||||||
|
We recommend to use the historically available funding rate for backtesting (which is automatically downloaded, and is at the frequency of what the exchange provides, usually 4h or 8h).
|
||||||
|
`self.dp.get_pair_dataframe(pair=metadata['pair'], timeframe='8h', candle_type="funding_rate")`
|
||||||
|
|
||||||
### Send Notification
|
### Send Notification
|
||||||
|
|
||||||
The dataprovider `.send_msg()` function allows you to send custom notifications from your strategy.
|
The dataprovider `.send_msg()` function allows you to send custom notifications from your strategy.
|
||||||
@@ -1068,7 +1136,7 @@ To verify if a pair is currently locked, use `self.is_pair_locked(pair)`.
|
|||||||
``` python
|
``` python
|
||||||
from freqtrade.persistence import Trade
|
from freqtrade.persistence import Trade
|
||||||
from datetime import timedelta, datetime, timezone
|
from datetime import timedelta, datetime, timezone
|
||||||
# Put the above lines a the top of the strategy file, next to all the other imports
|
# Put the above lines at the top of the strategy file, next to all the other imports
|
||||||
# --------
|
# --------
|
||||||
|
|
||||||
# Within populate indicators (or populate_entry_trend):
|
# Within populate indicators (or populate_entry_trend):
|
||||||
|
|||||||
@@ -19,3 +19,36 @@
|
|||||||
#available-endpoints ~ .md-typeset__scrollwrap .md-typeset__table th:first-of-type {
|
#available-endpoints ~ .md-typeset__scrollwrap .md-typeset__table th:first-of-type {
|
||||||
width: 35% !important;
|
width: 35% !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.md-typeset .md-button--sm {
|
||||||
|
padding: 0.2em 1em;
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: 600;
|
||||||
|
background-color: #f6f8fa;
|
||||||
|
color: #24292f;
|
||||||
|
border: 1px solid #d0d7de;
|
||||||
|
border-radius: 0.25em;
|
||||||
|
text-decoration: none;
|
||||||
|
display: inline-block;
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.md-typeset .md-button--sm:hover {
|
||||||
|
background-color: #e5eaee;
|
||||||
|
border-color: #d1d9e0;
|
||||||
|
text-decoration: none;
|
||||||
|
color: #24292f;
|
||||||
|
}
|
||||||
|
|
||||||
|
.md-typeset .md-button--sm:active {
|
||||||
|
background-color: #ebecf0;
|
||||||
|
border-color: #afb8c1;
|
||||||
|
box-shadow: inset 0 1px 0 rgba(175, 184, 193, 0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.md-grid {
|
||||||
|
/* default is max-width: 61rem; */
|
||||||
|
max-width: 75rem;
|
||||||
|
}
|
||||||
|
|||||||
+4
-17
@@ -188,7 +188,7 @@ You can create your own keyboard in `config.json`:
|
|||||||
!!! Note "Supported Commands"
|
!!! Note "Supported Commands"
|
||||||
Only the following commands are allowed. Command arguments are not supported!
|
Only the following commands are allowed. Command arguments are not supported!
|
||||||
|
|
||||||
`/start`, `/pause`, `/stop`, `/status`, `/status table`, `/trades`, `/profit`, `/performance`, `/daily`, `/stats`, `/count`, `/locks`, `/balance`, `/stopentry`, `/reload_config`, `/show_config`, `/logs`, `/whitelist`, `/blacklist`, `/edge`, `/help`, `/version`, `/marketdir`
|
`/start`, `/pause`, `/stop`, `/status`, `/status table`, `/trades`, `/profit`, `/performance`, `/daily`, `/stats`, `/count`, `/locks`, `/balance`, `/stopentry`, `/reload_config`, `/show_config`, `/logs`, `/whitelist`, `/blacklist`, `/help`, `/version`, `/marketdir`
|
||||||
|
|
||||||
## Telegram commands
|
## Telegram commands
|
||||||
|
|
||||||
@@ -229,6 +229,7 @@ official commands. You can ask at any moment for help with `/help`.
|
|||||||
| `/cancel_open_order <trade_id> | /coo <trade_id>` | Cancel an open order for a trade.
|
| `/cancel_open_order <trade_id> | /coo <trade_id>` | Cancel an open order for a trade.
|
||||||
| **Metrics** |
|
| **Metrics** |
|
||||||
| `/profit [<n>]` | Display a summary of your profit/loss from close trades and some stats about your performance, over the last n days (all trades by default)
|
| `/profit [<n>]` | Display a summary of your profit/loss from close trades and some stats about your performance, over the last n days (all trades by default)
|
||||||
|
| `/profit_[long|short] [<n>]` | Display a summary of your profit/loss from close trades in one direction and some stats about your performance, over the last n days (all trades by default)
|
||||||
| `/performance` | Show performance of each finished trade grouped by pair
|
| `/performance` | Show performance of each finished trade grouped by pair
|
||||||
| `/balance` | Show bot managed balance per currency
|
| `/balance` | Show bot managed balance per currency
|
||||||
| `/balance full` | Show account balance per currency
|
| `/balance full` | Show account balance per currency
|
||||||
@@ -240,7 +241,6 @@ official commands. You can ask at any moment for help with `/help`.
|
|||||||
| `/entries` | Shows Wins / losses by Exit reason as well as Avg. holding durations for buys and sells
|
| `/entries` | Shows Wins / losses by Exit reason as well as Avg. holding durations for buys and sells
|
||||||
| `/whitelist [sorted] [baseonly]` | Show the current whitelist. Optionally display in alphabetical order and/or with just the base currency of each pairing.
|
| `/whitelist [sorted] [baseonly]` | Show the current whitelist. Optionally display in alphabetical order and/or with just the base currency of each pairing.
|
||||||
| `/blacklist [pair]` | Show the current blacklist, or adds a pair to the blacklist.
|
| `/blacklist [pair]` | Show the current blacklist, or adds a pair to the blacklist.
|
||||||
| `/edge` | Show validated pairs by Edge if it is enabled.
|
|
||||||
|
|
||||||
## Telegram commands in action
|
## Telegram commands in action
|
||||||
|
|
||||||
@@ -310,6 +310,8 @@ current max
|
|||||||
|
|
||||||
### /profit
|
### /profit
|
||||||
|
|
||||||
|
Also available as `/profit_long` and `/profit_short` to show profit for long or short trades only.
|
||||||
|
|
||||||
Return a summary of your profit/loss and performance.
|
Return a summary of your profit/loss and performance.
|
||||||
|
|
||||||
> **ROI:** Close trades
|
> **ROI:** Close trades
|
||||||
@@ -451,21 +453,6 @@ Use `/reload_config` to reset the blacklist.
|
|||||||
> Using blacklist `StaticPairList` with 2 pairs
|
> Using blacklist `StaticPairList` with 2 pairs
|
||||||
>`DODGE/BTC`, `HOT/BTC`.
|
>`DODGE/BTC`, `HOT/BTC`.
|
||||||
|
|
||||||
### /edge
|
|
||||||
|
|
||||||
Shows pairs validated by Edge along with their corresponding win-rate, expectancy and stoploss values.
|
|
||||||
|
|
||||||
> **Edge only validated following pairs:**
|
|
||||||
```
|
|
||||||
Pair Winrate Expectancy Stoploss
|
|
||||||
-------- --------- ------------ ----------
|
|
||||||
DOCK/ETH 0.522727 0.881821 -0.03
|
|
||||||
PHX/ETH 0.677419 0.560488 -0.03
|
|
||||||
HOT/ETH 0.733333 0.490492 -0.03
|
|
||||||
HC/ETH 0.588235 0.280988 -0.02
|
|
||||||
ARDR/ETH 0.366667 0.143059 -0.01
|
|
||||||
```
|
|
||||||
|
|
||||||
### /version
|
### /version
|
||||||
|
|
||||||
> **Version:** `0.14.3`
|
> **Version:** `0.14.3`
|
||||||
|
|||||||
@@ -134,15 +134,17 @@ Most properties here can be None as they are dependent on the exchange response.
|
|||||||
|------------|-------------|-------------|
|
|------------|-------------|-------------|
|
||||||
| `trade` | Trade | Trade object this order is attached to |
|
| `trade` | Trade | Trade object this order is attached to |
|
||||||
| `ft_pair` | string | Pair this order is for |
|
| `ft_pair` | string | Pair this order is for |
|
||||||
| `ft_is_open` | boolean | is the order filled? |
|
| `ft_is_open` | boolean | is the order still open? |
|
||||||
| `order_type` | string | Order type as defined on the exchange - usually market, limit or stoploss |
|
| `order_type` | string | Order type as defined on the exchange - usually market, limit or stoploss |
|
||||||
| `status` | string | Status as defined by ccxt. Usually open, closed, expired or canceled |
|
| `status` | string | Status as defined by [ccxt's order structure](https://docs.ccxt.com/#/README?id=order-structure). Usually open, closed, expired, canceled or rejected |
|
||||||
| `side` | string | Buy or Sell |
|
| `side` | string | buy or sell |
|
||||||
| `price` | float | Price the order was placed at |
|
| `price` | float | Price the order was placed at |
|
||||||
| `average` | float | Average price the order filled at |
|
| `average` | float | Average price the order filled at |
|
||||||
| `amount` | float | Amount in base currency |
|
| `amount` | float | Amount in base currency |
|
||||||
| `filled` | float | Filled amount (in base currency) |
|
| `filled` | float | Filled amount (in base currency) (use `safe_filled` instead) |
|
||||||
| `remaining` | float | Remaining amount |
|
| `safe_filled` | float | Filled amount (in base currency) - guaranteed to not be None |
|
||||||
|
| `remaining` | float | Remaining amount (use `safe_remaining` instead) |
|
||||||
|
| `safe_remaining` | float | Remaining amount - either taken from the exchange or calculated. |
|
||||||
| `cost` | float | Cost of the order - usually average * filled (*Exchange dependent on futures, may contain the cost with or without leverage and may be in contracts.*) |
|
| `cost` | float | Cost of the order - usually average * filled (*Exchange dependent on futures, may contain the cost with or without leverage and may be in contracts.*) |
|
||||||
| `stake_amount` | float | Stake amount used for this order. *Added in 2023.7.* |
|
| `stake_amount` | float | Stake amount used for this order. *Added in 2023.7.* |
|
||||||
| `stake_amount_filled` | float | Filled Stake amount used for this order. *Added in 2024.11.* |
|
| `stake_amount_filled` | float | Filled Stake amount used for this order. *Added in 2024.11.* |
|
||||||
|
|||||||
@@ -42,7 +42,3 @@ freqtrade install-ui
|
|||||||
|
|
||||||
Update-problems usually come missing dependencies (you didn't follow the above instructions) - or from updated dependencies, which fail to install (for example TA-lib).
|
Update-problems usually come missing dependencies (you didn't follow the above instructions) - or from updated dependencies, which fail to install (for example TA-lib).
|
||||||
Please refer to the corresponding installation sections (common problems linked below)
|
Please refer to the corresponding installation sections (common problems linked below)
|
||||||
|
|
||||||
Common problems and their solutions:
|
|
||||||
|
|
||||||
* [ta-lib update on windows](windows_installation.md#2-install-ta-lib)
|
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
# Utility Subcommands
|
# Utility Subcommands
|
||||||
|
|
||||||
Besides the Live-Trade and Dry-Run run modes, the `backtesting`, `edge` and `hyperopt` optimization subcommands, and the `download-data` subcommand which prepares historical data, the bot contains a number of utility subcommands. They are described in this section.
|
Besides the Live-Trade and Dry-Run run modes, the `backtesting` and `hyperopt` optimization subcommands, and the `download-data` subcommand which prepares historical data, the bot contains a number of utility subcommands. They are described in this section.
|
||||||
|
|
||||||
## Create userdir
|
## Create userdir
|
||||||
|
|
||||||
|
|||||||
+32
-52
@@ -80,6 +80,29 @@ When using the Form-Encoded or JSON-Encoded configuration you can configure any
|
|||||||
|
|
||||||
The result would be a POST request with e.g. `Status: running` body and `Content-Type: text/plain` header.
|
The result would be a POST request with e.g. `Status: running` body and `Content-Type: text/plain` header.
|
||||||
|
|
||||||
|
### Nested Webhook Configuration
|
||||||
|
|
||||||
|
Some webhook targets require a nested structure.
|
||||||
|
This can be accomplished by setting the content as dictionary or list instead of as text directly.
|
||||||
|
|
||||||
|
This is only supported for the JSON format.
|
||||||
|
|
||||||
|
```json
|
||||||
|
"webhook": {
|
||||||
|
"enabled": true,
|
||||||
|
"url": "https://<yourhookurl>",
|
||||||
|
"format": "json",
|
||||||
|
"status": {
|
||||||
|
"msgtype": "text",
|
||||||
|
"text": {
|
||||||
|
"content": "Status update: {status}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
The result would be a POST request with e.g. `{"msgtype":"text","text":{"content":"Status update: running"}}` body and `Content-Type: application/json` header.
|
||||||
|
|
||||||
## Additional configurations
|
## Additional configurations
|
||||||
|
|
||||||
The `webhook.retries` parameter can be set for the maximum number of retries the webhook request should attempt if it is unsuccessful (i.e. HTTP response status is not 200). By default this is set to `0` which is disabled. An additional `webhook.retry_delay` parameter can be set to specify the time in seconds between retry attempts. By default this is set to `0.1` (i.e. 100ms). Note that increasing the number of retries or retry delay may slow down the trader if there are connectivity issues with the webhook.
|
The `webhook.retries` parameter can be set for the maximum number of retries the webhook request should attempt if it is unsuccessful (i.e. HTTP response status is not 200). By default this is set to `0` which is disabled. An additional `webhook.retry_delay` parameter can be set to specify the time in seconds between retry attempts. By default this is set to `0.1` (i.e. 100ms). Note that increasing the number of retries or retry delay may slow down the trader if there are connectivity issues with the webhook.
|
||||||
@@ -117,9 +140,9 @@ Different payloads can be configured for different events. Not all fields are ne
|
|||||||
|
|
||||||
## Webhook Message types
|
## Webhook Message types
|
||||||
|
|
||||||
### Entry
|
### Entry / Entry fill
|
||||||
|
|
||||||
The fields in `webhook.entry` are filled when the bot executes a long/short. Parameters are filled using string.format.
|
The fields in `webhook.entry` and `webhook.entry_fill` are filled when the bot places a long/short Order to increase a position, or when that order fills respectively. Parameters are filled using string.format.
|
||||||
Possible parameters are:
|
Possible parameters are:
|
||||||
|
|
||||||
* `trade_id`
|
* `trade_id`
|
||||||
@@ -162,31 +185,9 @@ Possible parameters are:
|
|||||||
* `current_rate`
|
* `current_rate`
|
||||||
* `enter_tag`
|
* `enter_tag`
|
||||||
|
|
||||||
### Entry fill
|
### Exit / Exit fill
|
||||||
|
|
||||||
The fields in `webhook.entry_fill` are filled when the bot filled a long/short order. Parameters are filled using string.format.
|
The fields in `webhook.exit` and `webhook.exit_fill` are filled when the bot places an exit order, or when that exit order fills respectively. Parameters are filled using string.format.
|
||||||
Possible parameters are:
|
|
||||||
|
|
||||||
* `trade_id`
|
|
||||||
* `exchange`
|
|
||||||
* `pair`
|
|
||||||
* `direction`
|
|
||||||
* `leverage`
|
|
||||||
* `open_rate`
|
|
||||||
* `amount`
|
|
||||||
* `open_date`
|
|
||||||
* `stake_amount`
|
|
||||||
* `stake_currency`
|
|
||||||
* `base_currency`
|
|
||||||
* `quote_currency`
|
|
||||||
* `fiat_currency`
|
|
||||||
* `order_type`
|
|
||||||
* `current_rate`
|
|
||||||
* `enter_tag`
|
|
||||||
|
|
||||||
### Exit
|
|
||||||
|
|
||||||
The fields in `webhook.exit` are filled when the bot exits a trade. Parameters are filled using string.format.
|
|
||||||
Possible parameters are:
|
Possible parameters are:
|
||||||
|
|
||||||
* `trade_id`
|
* `trade_id`
|
||||||
@@ -195,34 +196,9 @@ Possible parameters are:
|
|||||||
* `direction`
|
* `direction`
|
||||||
* `leverage`
|
* `leverage`
|
||||||
* `gain`
|
* `gain`
|
||||||
* `limit`
|
|
||||||
* `amount`
|
* `amount`
|
||||||
* `open_rate`
|
* `open_rate`
|
||||||
* `profit_amount`
|
|
||||||
* `profit_ratio`
|
|
||||||
* `stake_currency`
|
|
||||||
* `base_currency`
|
|
||||||
* `quote_currency`
|
|
||||||
* `fiat_currency`
|
|
||||||
* `exit_reason`
|
|
||||||
* `order_type`
|
|
||||||
* `open_date`
|
|
||||||
* `close_date`
|
|
||||||
|
|
||||||
### Exit fill
|
|
||||||
|
|
||||||
The fields in `webhook.exit_fill` are filled when the bot fills a exit order (closes a Trade). Parameters are filled using string.format.
|
|
||||||
Possible parameters are:
|
|
||||||
|
|
||||||
* `trade_id`
|
|
||||||
* `exchange`
|
|
||||||
* `pair`
|
|
||||||
* `direction`
|
|
||||||
* `leverage`
|
|
||||||
* `gain`
|
|
||||||
* `close_rate`
|
* `close_rate`
|
||||||
* `amount`
|
|
||||||
* `open_rate`
|
|
||||||
* `current_rate`
|
* `current_rate`
|
||||||
* `profit_amount`
|
* `profit_amount`
|
||||||
* `profit_ratio`
|
* `profit_ratio`
|
||||||
@@ -230,10 +206,14 @@ Possible parameters are:
|
|||||||
* `base_currency`
|
* `base_currency`
|
||||||
* `quote_currency`
|
* `quote_currency`
|
||||||
* `fiat_currency`
|
* `fiat_currency`
|
||||||
|
* `enter_tag`
|
||||||
* `exit_reason`
|
* `exit_reason`
|
||||||
* `order_type`
|
* `order_type`
|
||||||
* `open_date`
|
* `open_date`
|
||||||
* `close_date`
|
* `close_date`
|
||||||
|
* `sub_trade`
|
||||||
|
* `is_final_exit`
|
||||||
|
|
||||||
|
|
||||||
### Exit cancel
|
### Exit cancel
|
||||||
|
|
||||||
@@ -246,7 +226,7 @@ Possible parameters are:
|
|||||||
* `direction`
|
* `direction`
|
||||||
* `leverage`
|
* `leverage`
|
||||||
* `gain`
|
* `gain`
|
||||||
* `limit`
|
* `order_rate`
|
||||||
* `amount`
|
* `amount`
|
||||||
* `open_rate`
|
* `open_rate`
|
||||||
* `current_rate`
|
* `current_rate`
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ We **strongly** recommend that Windows users use [Docker](docker_quickstart.md)
|
|||||||
If that is not possible, try using the Windows Linux subsystem (WSL) - for which the Ubuntu instructions should work.
|
If that is not possible, try using the Windows Linux subsystem (WSL) - for which the Ubuntu instructions should work.
|
||||||
Otherwise, please follow the instructions below.
|
Otherwise, please follow the instructions below.
|
||||||
|
|
||||||
All instructions assume that python 3.10+ is installed and available.
|
All instructions assume that python 3.11+ is installed and available.
|
||||||
|
|
||||||
## Clone the git repository
|
## Clone the git repository
|
||||||
|
|
||||||
@@ -38,30 +38,6 @@ cd freqtrade
|
|||||||
!!! Hint
|
!!! Hint
|
||||||
Using the [Anaconda Distribution](https://www.anaconda.com/distribution/) under Windows can greatly help with installation problems. Check out the [Anaconda installation section](installation.md#installation-with-conda) in the documentation for more information.
|
Using the [Anaconda Distribution](https://www.anaconda.com/distribution/) under Windows can greatly help with installation problems. Check out the [Anaconda installation section](installation.md#installation-with-conda) in the documentation for more information.
|
||||||
|
|
||||||
### Install ta-lib
|
|
||||||
|
|
||||||
Install ta-lib according to the [ta-lib documentation](https://github.com/TA-Lib/ta-lib-python#windows).
|
|
||||||
|
|
||||||
As compiling from source on windows has heavy dependencies (requires a partial visual studio installation), Freqtrade provides these dependencies (in the binary wheel format) for the latest 3 Python versions (3.10, 3.11 and 3.12) and for 64bit Windows.
|
|
||||||
These Wheels are also used by CI running on windows, and are therefore tested together with freqtrade.
|
|
||||||
|
|
||||||
Other versions must be downloaded from the above link.
|
|
||||||
|
|
||||||
``` powershell
|
|
||||||
cd \path\freqtrade
|
|
||||||
python -m venv .venv
|
|
||||||
.venv\Scripts\activate.ps1
|
|
||||||
# optionally install ta-lib from wheel
|
|
||||||
# Eventually adjust the below filename to match the downloaded wheel
|
|
||||||
pip install --find-links build_helpers\ TA-Lib -U
|
|
||||||
pip install -r requirements.txt
|
|
||||||
pip install -e .
|
|
||||||
freqtrade
|
|
||||||
```
|
|
||||||
|
|
||||||
!!! Note "Use Powershell"
|
|
||||||
The above installation script assumes you're using powershell on a 64bit windows.
|
|
||||||
Commands for the legacy CMD windows console may differ.
|
|
||||||
|
|
||||||
### Error during installation on Windows
|
### Error during installation on Windows
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
"""Freqtrade bot"""
|
"""Freqtrade bot"""
|
||||||
|
|
||||||
__version__ = "2025.4"
|
__version__ = "2025.9.1"
|
||||||
|
|
||||||
if "dev" in __version__:
|
if "dev" in __version__:
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
__main__.py for Freqtrade
|
__main__.py for Freqtrade
|
||||||
To launch Freqtrade as a module
|
To launch Freqtrade as a module
|
||||||
|
|
||||||
> python -m freqtrade (with Python >= 3.10)
|
> python -m freqtrade (with Python >= 3.11)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from freqtrade import main
|
from freqtrade import main
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ def start_analysis_entries_exits(args: dict[str, Any]) -> None:
|
|||||||
from freqtrade.data.entryexitanalysis import process_entry_exit_reasons
|
from freqtrade.data.entryexitanalysis import process_entry_exit_reasons
|
||||||
|
|
||||||
# Initialize configuration
|
# Initialize configuration
|
||||||
config = setup_utils_configuration(args, RunMode.BACKTEST)
|
config = setup_utils_configuration(args, RunMode.UTIL_NO_EXCHANGE)
|
||||||
|
|
||||||
logger.info("Starting freqtrade in analysis mode")
|
logger.info("Starting freqtrade in analysis mode")
|
||||||
|
|
||||||
|
|||||||
@@ -49,14 +49,17 @@ ARGS_BACKTEST = [
|
|||||||
*ARGS_COMMON_OPTIMIZE,
|
*ARGS_COMMON_OPTIMIZE,
|
||||||
"position_stacking",
|
"position_stacking",
|
||||||
"enable_protections",
|
"enable_protections",
|
||||||
|
"enable_dynamic_pairlist",
|
||||||
"dry_run_wallet",
|
"dry_run_wallet",
|
||||||
"timeframe_detail",
|
"timeframe_detail",
|
||||||
"strategy_list",
|
"strategy_list",
|
||||||
"export",
|
"export",
|
||||||
"exportfilename",
|
"exportfilename",
|
||||||
|
"exportdirectory",
|
||||||
"backtest_breakdown",
|
"backtest_breakdown",
|
||||||
"backtest_cache",
|
"backtest_cache",
|
||||||
"freqai_backtest_live_models",
|
"freqai_backtest_live_models",
|
||||||
|
"backtest_notes",
|
||||||
]
|
]
|
||||||
|
|
||||||
ARGS_HYPEROPT = [
|
ARGS_HYPEROPT = [
|
||||||
@@ -78,9 +81,10 @@ ARGS_HYPEROPT = [
|
|||||||
"disableparamexport",
|
"disableparamexport",
|
||||||
"hyperopt_ignore_missing_space",
|
"hyperopt_ignore_missing_space",
|
||||||
"analyze_per_epoch",
|
"analyze_per_epoch",
|
||||||
|
"early_stop",
|
||||||
]
|
]
|
||||||
|
|
||||||
ARGS_EDGE = [*ARGS_COMMON_OPTIMIZE, "stoploss_range"]
|
ARGS_EDGE = [*ARGS_COMMON_OPTIMIZE]
|
||||||
|
|
||||||
ARGS_LIST_STRATEGIES = [
|
ARGS_LIST_STRATEGIES = [
|
||||||
"strategy_path",
|
"strategy_path",
|
||||||
@@ -92,9 +96,14 @@ ARGS_LIST_FREQAIMODELS = ["freqaimodel_path", "print_one_column"]
|
|||||||
|
|
||||||
ARGS_LIST_HYPEROPTS = ["hyperopt_path", "print_one_column"]
|
ARGS_LIST_HYPEROPTS = ["hyperopt_path", "print_one_column"]
|
||||||
|
|
||||||
ARGS_BACKTEST_SHOW = ["exportfilename", "backtest_show_pair_list", "backtest_breakdown"]
|
ARGS_BACKTEST_SHOW = [
|
||||||
|
"exportfilename",
|
||||||
|
"exportdirectory",
|
||||||
|
"backtest_show_pair_list",
|
||||||
|
"backtest_breakdown",
|
||||||
|
]
|
||||||
|
|
||||||
ARGS_LIST_EXCHANGES = ["print_one_column", "list_exchanges_all"]
|
ARGS_LIST_EXCHANGES = ["print_one_column", "list_exchanges_all", "trading_mode", "dex_exchanges"]
|
||||||
|
|
||||||
ARGS_LIST_TIMEFRAMES = ["exchange", "print_one_column"]
|
ARGS_LIST_TIMEFRAMES = ["exchange", "print_one_column"]
|
||||||
|
|
||||||
@@ -156,6 +165,7 @@ ARGS_DOWNLOAD_DATA = [
|
|||||||
"days",
|
"days",
|
||||||
"new_pairs_days",
|
"new_pairs_days",
|
||||||
"include_inactive",
|
"include_inactive",
|
||||||
|
"no_parallel_download",
|
||||||
"timerange",
|
"timerange",
|
||||||
"download_trades",
|
"download_trades",
|
||||||
"convert_trades",
|
"convert_trades",
|
||||||
@@ -231,6 +241,7 @@ ARGS_HYPEROPT_SHOW = [
|
|||||||
|
|
||||||
ARGS_ANALYZE_ENTRIES_EXITS = [
|
ARGS_ANALYZE_ENTRIES_EXITS = [
|
||||||
"exportfilename",
|
"exportfilename",
|
||||||
|
"exportdirectory",
|
||||||
"analysis_groups",
|
"analysis_groups",
|
||||||
"enter_reason_list",
|
"enter_reason_list",
|
||||||
"exit_reason_list",
|
"exit_reason_list",
|
||||||
@@ -249,31 +260,38 @@ ARGS_STRATEGY_UPDATER = ["strategy_list", "strategy_path", "recursive_strategy_s
|
|||||||
ARGS_LOOKAHEAD_ANALYSIS = [
|
ARGS_LOOKAHEAD_ANALYSIS = [
|
||||||
a
|
a
|
||||||
for a in ARGS_BACKTEST
|
for a in ARGS_BACKTEST
|
||||||
if a not in ("position_stacking", "backtest_cache", "backtest_breakdown")
|
if a not in ("position_stacking", "backtest_cache", "backtest_breakdown", "backtest_notes")
|
||||||
] + ["minimum_trade_amount", "targeted_trade_amount", "lookahead_analysis_exportfilename"]
|
] + [
|
||||||
|
"minimum_trade_amount",
|
||||||
|
"targeted_trade_amount",
|
||||||
|
"lookahead_analysis_exportfilename",
|
||||||
|
"lookahead_allow_limit_orders",
|
||||||
|
]
|
||||||
|
|
||||||
ARGS_RECURSIVE_ANALYSIS = ["timeframe", "timerange", "dataformat_ohlcv", "pairs", "startup_candle"]
|
ARGS_RECURSIVE_ANALYSIS = ["timeframe", "timerange", "dataformat_ohlcv", "pairs", "startup_candle"]
|
||||||
|
|
||||||
# Command level configs - keep at the bottom of the above definitions
|
# Command level configs - keep at the bottom of the above definitions
|
||||||
NO_CONF_REQURIED = [
|
NO_CONF_REQURIED = [
|
||||||
|
"backtest-filter",
|
||||||
|
"backtesting-show",
|
||||||
"convert-data",
|
"convert-data",
|
||||||
"convert-trade-data",
|
"convert-trade-data",
|
||||||
"download-data",
|
"download-data",
|
||||||
"list-timeframes",
|
"hyperopt-list",
|
||||||
|
"hyperopt-show",
|
||||||
|
"list-data",
|
||||||
|
"list-freqaimodels",
|
||||||
|
"list-hyperoptloss",
|
||||||
"list-markets",
|
"list-markets",
|
||||||
"list-pairs",
|
"list-pairs",
|
||||||
"list-strategies",
|
"list-strategies",
|
||||||
"list-freqaimodels",
|
"list-timeframes",
|
||||||
"list-hyperoptloss",
|
|
||||||
"list-data",
|
|
||||||
"hyperopt-list",
|
|
||||||
"hyperopt-show",
|
|
||||||
"backtest-filter",
|
|
||||||
"plot-dataframe",
|
"plot-dataframe",
|
||||||
"plot-profit",
|
"plot-profit",
|
||||||
"show-trades",
|
"show-trades",
|
||||||
"trades-to-ohlcv",
|
"install-ui",
|
||||||
"strategy-updater",
|
"strategy-updater",
|
||||||
|
"trades-to-ohlcv",
|
||||||
]
|
]
|
||||||
|
|
||||||
NO_CONF_ALLOWED = ["create-userdir", "list-exchanges", "new-strategy"]
|
NO_CONF_ALLOWED = ["create-userdir", "list-exchanges", "new-strategy"]
|
||||||
@@ -309,8 +327,6 @@ class Arguments:
|
|||||||
# (see https://bugs.python.org/issue16399)
|
# (see https://bugs.python.org/issue16399)
|
||||||
# Allow no-config for certain commands (like downloading / plotting)
|
# Allow no-config for certain commands (like downloading / plotting)
|
||||||
if "config" in parsed_arg and parsed_arg.config is None:
|
if "config" in parsed_arg and parsed_arg.config is None:
|
||||||
conf_required = "command" in parsed_arg and parsed_arg.command in NO_CONF_REQURIED
|
|
||||||
|
|
||||||
if "user_data_dir" in parsed_arg and parsed_arg.user_data_dir is not None:
|
if "user_data_dir" in parsed_arg and parsed_arg.user_data_dir is not None:
|
||||||
user_dir = parsed_arg.user_data_dir
|
user_dir = parsed_arg.user_data_dir
|
||||||
else:
|
else:
|
||||||
@@ -323,7 +339,9 @@ class Arguments:
|
|||||||
else:
|
else:
|
||||||
# Else use "config.json".
|
# Else use "config.json".
|
||||||
cfgfile = Path.cwd() / DEFAULT_CONFIG
|
cfgfile = Path.cwd() / DEFAULT_CONFIG
|
||||||
if cfgfile.is_file() or not conf_required:
|
conf_optional = "command" in parsed_arg and parsed_arg.command in NO_CONF_REQURIED
|
||||||
|
if cfgfile.is_file() or not conf_optional:
|
||||||
|
# Only inject config if the file exists, or if the config is required
|
||||||
parsed_arg.config = [DEFAULT_CONFIG]
|
parsed_arg.config = [DEFAULT_CONFIG]
|
||||||
|
|
||||||
return parsed_arg
|
return parsed_arg
|
||||||
@@ -504,7 +522,9 @@ class Arguments:
|
|||||||
|
|
||||||
# Add edge subcommand
|
# Add edge subcommand
|
||||||
edge_cmd = subparsers.add_parser(
|
edge_cmd = subparsers.add_parser(
|
||||||
"edge", help="Edge module.", parents=[_common_parser, _strategy_parser]
|
"edge",
|
||||||
|
help="Edge module. No longer part of Freqtrade",
|
||||||
|
parents=[_common_parser, _strategy_parser],
|
||||||
)
|
)
|
||||||
edge_cmd.set_defaults(func=start_edge)
|
edge_cmd.set_defaults(func=start_edge)
|
||||||
self._build_args(optionlist=ARGS_EDGE, parser=edge_cmd)
|
self._build_args(optionlist=ARGS_EDGE, parser=edge_cmd)
|
||||||
|
|||||||
@@ -184,12 +184,20 @@ AVAILABLE_CLI_OPTIONS = {
|
|||||||
"enable_protections": Arg(
|
"enable_protections": Arg(
|
||||||
"--enable-protections",
|
"--enable-protections",
|
||||||
"--enableprotections",
|
"--enableprotections",
|
||||||
help="Enable protections for backtesting."
|
help="Enable protections for backtesting. "
|
||||||
"Will slow backtesting down by a considerable amount, but will include "
|
"Will slow backtesting down by a considerable amount, but will include "
|
||||||
"configured protections",
|
"configured protections",
|
||||||
action="store_true",
|
action="store_true",
|
||||||
default=False,
|
default=False,
|
||||||
),
|
),
|
||||||
|
"enable_dynamic_pairlist": Arg(
|
||||||
|
"--enable-dynamic-pairlist",
|
||||||
|
help="Enables dynamic pairlist refreshes in backtesting. "
|
||||||
|
"The pairlist will be generated for each new candle if you're using a "
|
||||||
|
"pairlist handler that supports this feature, for example, ShuffleFilter.",
|
||||||
|
action="store_true",
|
||||||
|
default=False,
|
||||||
|
),
|
||||||
"strategy_list": Arg(
|
"strategy_list": Arg(
|
||||||
"--strategy-list",
|
"--strategy-list",
|
||||||
help="Provide a space-separated list of strategies to backtest. "
|
help="Provide a space-separated list of strategies to backtest. "
|
||||||
@@ -199,17 +207,29 @@ AVAILABLE_CLI_OPTIONS = {
|
|||||||
"(so `backtest-data.json` becomes `backtest-data-SampleStrategy.json`",
|
"(so `backtest-data.json` becomes `backtest-data-SampleStrategy.json`",
|
||||||
nargs="+",
|
nargs="+",
|
||||||
),
|
),
|
||||||
|
"backtest_notes": Arg(
|
||||||
|
"--notes",
|
||||||
|
help="Add notes to the backtest results.",
|
||||||
|
metavar="TEXT",
|
||||||
|
),
|
||||||
"export": Arg(
|
"export": Arg(
|
||||||
"--export",
|
"--export",
|
||||||
help="Export backtest results (default: trades).",
|
help="Export backtest results (default: trades).",
|
||||||
choices=constants.EXPORT_OPTIONS,
|
choices=constants.EXPORT_OPTIONS,
|
||||||
),
|
),
|
||||||
|
"exportdirectory": Arg(
|
||||||
|
"--backtest-directory",
|
||||||
|
"--export-directory",
|
||||||
|
help="Directory to use for backtest results. "
|
||||||
|
"Example: `--export-directory=user_data/backtest_results/`. ",
|
||||||
|
metavar="PATH",
|
||||||
|
),
|
||||||
"exportfilename": Arg(
|
"exportfilename": Arg(
|
||||||
"--export-filename",
|
|
||||||
"--backtest-filename",
|
"--backtest-filename",
|
||||||
|
"--export-filename",
|
||||||
help="Use this filename for backtest results."
|
help="Use this filename for backtest results."
|
||||||
"Requires `--export` to be set as well. "
|
"Example: `--backtest-filename=backtest_results_2020-09-27_16-20-48.json`. "
|
||||||
"Example: `--export-filename=user_data/backtest_results/backtest_today.json`",
|
"Assumes either `user_data/backtest_results/` or `--export-directory` as base directory.",
|
||||||
metavar="PATH",
|
metavar="PATH",
|
||||||
),
|
),
|
||||||
"disableparamexport": Arg(
|
"disableparamexport": Arg(
|
||||||
@@ -235,13 +255,6 @@ AVAILABLE_CLI_OPTIONS = {
|
|||||||
default=constants.BACKTEST_CACHE_DEFAULT,
|
default=constants.BACKTEST_CACHE_DEFAULT,
|
||||||
choices=constants.BACKTEST_CACHE_AGE,
|
choices=constants.BACKTEST_CACHE_AGE,
|
||||||
),
|
),
|
||||||
# Edge
|
|
||||||
"stoploss_range": Arg(
|
|
||||||
"--stoplosses",
|
|
||||||
help="Defines a range of stoploss values against which edge will assess the strategy. "
|
|
||||||
'The format is "min,max,step" (without any space). '
|
|
||||||
"Example: `--stoplosses=-0.01,-0.1,-0.001`",
|
|
||||||
),
|
|
||||||
# Hyperopt
|
# Hyperopt
|
||||||
"hyperopt": Arg(
|
"hyperopt": Arg(
|
||||||
"--hyperopt",
|
"--hyperopt",
|
||||||
@@ -262,6 +275,13 @@ AVAILABLE_CLI_OPTIONS = {
|
|||||||
metavar="INT",
|
metavar="INT",
|
||||||
default=constants.HYPEROPT_EPOCH,
|
default=constants.HYPEROPT_EPOCH,
|
||||||
),
|
),
|
||||||
|
"early_stop": Arg(
|
||||||
|
"--early-stop",
|
||||||
|
help="Early stop hyperopt if no improvement after (default: %(default)d) epochs.",
|
||||||
|
type=check_int_positive,
|
||||||
|
metavar="INT",
|
||||||
|
default=0, # 0 to disable by default
|
||||||
|
),
|
||||||
"spaces": Arg(
|
"spaces": Arg(
|
||||||
"--spaces",
|
"--spaces",
|
||||||
help="Specify which parameters to hyperopt. Space-separated list.",
|
help="Specify which parameters to hyperopt. Space-separated list.",
|
||||||
@@ -364,6 +384,11 @@ AVAILABLE_CLI_OPTIONS = {
|
|||||||
help="Print all exchanges known to the ccxt library.",
|
help="Print all exchanges known to the ccxt library.",
|
||||||
action="store_true",
|
action="store_true",
|
||||||
),
|
),
|
||||||
|
"dex_exchanges": Arg(
|
||||||
|
"--dex-exchanges",
|
||||||
|
help="Print only DEX exchanges.",
|
||||||
|
action="store_true",
|
||||||
|
),
|
||||||
# List pairs / markets
|
# List pairs / markets
|
||||||
"list_pairs_all": Arg(
|
"list_pairs_all": Arg(
|
||||||
"-a",
|
"-a",
|
||||||
@@ -437,6 +462,11 @@ AVAILABLE_CLI_OPTIONS = {
|
|||||||
help="Also download data from inactive pairs.",
|
help="Also download data from inactive pairs.",
|
||||||
action="store_true",
|
action="store_true",
|
||||||
),
|
),
|
||||||
|
"no_parallel_download": Arg(
|
||||||
|
"--no-parallel-download",
|
||||||
|
help="Disable parallel startup download. Only use this if you experience issues.",
|
||||||
|
action="store_true",
|
||||||
|
),
|
||||||
"new_pairs_days": Arg(
|
"new_pairs_days": Arg(
|
||||||
"--new-pairs-days",
|
"--new-pairs-days",
|
||||||
help="Download data of new pairs for given number of days. Default: `%(default)s`.",
|
help="Download data of new pairs for given number of days. Default: `%(default)s`.",
|
||||||
@@ -784,6 +814,14 @@ AVAILABLE_CLI_OPTIONS = {
|
|||||||
help="Specify startup candles to be checked (`199`, `499`, `999`, `1999`).",
|
help="Specify startup candles to be checked (`199`, `499`, `999`, `1999`).",
|
||||||
nargs="+",
|
nargs="+",
|
||||||
),
|
),
|
||||||
|
"lookahead_allow_limit_orders": Arg(
|
||||||
|
"--allow-limit-orders",
|
||||||
|
help=(
|
||||||
|
"Allow limit orders in lookahead analysis (could cause false positives "
|
||||||
|
"in lookahead analysis results)."
|
||||||
|
),
|
||||||
|
action="store_true",
|
||||||
|
),
|
||||||
"show_sensitive": Arg(
|
"show_sensitive": Arg(
|
||||||
"--show-sensitive",
|
"--show-sensitive",
|
||||||
help="Show secrets in the output.",
|
help="Show secrets in the output.",
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ from typing import Any
|
|||||||
from freqtrade.constants import DATETIME_PRINT_FORMAT, DL_DATA_TIMEFRAMES, Config
|
from freqtrade.constants import DATETIME_PRINT_FORMAT, DL_DATA_TIMEFRAMES, Config
|
||||||
from freqtrade.enums import CandleType, RunMode, TradingMode
|
from freqtrade.enums import CandleType, RunMode, TradingMode
|
||||||
from freqtrade.exceptions import ConfigurationError
|
from freqtrade.exceptions import ConfigurationError
|
||||||
from freqtrade.plugins.pairlist.pairlist_helpers import dynamic_expand_pairlist
|
from freqtrade.plugins.pairlist.pairlist_helpers import dynamic_expand_pairlist, expand_pairlist
|
||||||
|
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
@@ -134,7 +134,8 @@ def start_list_data(args: dict[str, Any]) -> None:
|
|||||||
config["datadir"], config.get("trading_mode", TradingMode.SPOT)
|
config["datadir"], config.get("trading_mode", TradingMode.SPOT)
|
||||||
)
|
)
|
||||||
if args["pairs"]:
|
if args["pairs"]:
|
||||||
paircombs = [comb for comb in paircombs if comb[0] in args["pairs"]]
|
pl = expand_pairlist(args["pairs"], [p[0] for p in paircombs], keep_invalid=True)
|
||||||
|
paircombs = [comb for comb in paircombs if comb[0] in pl]
|
||||||
title = f"Found {len(paircombs)} pair / timeframe combinations."
|
title = f"Found {len(paircombs)} pair / timeframe combinations."
|
||||||
if not config.get("show_timerange"):
|
if not config.get("show_timerange"):
|
||||||
groupedpair = defaultdict(list)
|
groupedpair = defaultdict(list)
|
||||||
@@ -197,7 +198,8 @@ def start_list_trades_data(args: dict[str, Any]) -> None:
|
|||||||
)
|
)
|
||||||
|
|
||||||
if args["pairs"]:
|
if args["pairs"]:
|
||||||
paircombs = [comb for comb in paircombs if comb in args["pairs"]]
|
pl = expand_pairlist(args["pairs"], [p for p in paircombs], keep_invalid=True)
|
||||||
|
paircombs = [comb for comb in paircombs if comb in pl]
|
||||||
|
|
||||||
title = f"Found trades data for {len(paircombs)} {plural(len(paircombs), 'pair')}."
|
title = f"Found trades data for {len(paircombs)} {plural(len(paircombs), 'pair')}."
|
||||||
if not config.get("show_timerange"):
|
if not config.get("show_timerange"):
|
||||||
|
|||||||
@@ -46,7 +46,18 @@ def start_list_exchanges(args: dict[str, Any]) -> None:
|
|||||||
table.add_column("Markets")
|
table.add_column("Markets")
|
||||||
table.add_column("Reason")
|
table.add_column("Reason")
|
||||||
|
|
||||||
|
trading_mode = args.get("trading_mode", None)
|
||||||
|
dex_only = args.get("dex_exchanges", False)
|
||||||
|
|
||||||
for exchange in available_exchanges:
|
for exchange in available_exchanges:
|
||||||
|
if trading_mode and not any(
|
||||||
|
a["trading_mode"] == trading_mode for a in exchange["trade_modes"]
|
||||||
|
):
|
||||||
|
# If trading_mode is specified, only show exchanges that support it
|
||||||
|
continue
|
||||||
|
if dex_only and not exchange.get("dex", False):
|
||||||
|
# If dex_only is specified, only show DEX exchanges
|
||||||
|
continue
|
||||||
name = Text(exchange["name"])
|
name = Text(exchange["name"])
|
||||||
if exchange["supported"]:
|
if exchange["supported"]:
|
||||||
name.append(" (Supported)", style="italic")
|
name.append(" (Supported)", style="italic")
|
||||||
@@ -55,7 +66,7 @@ def start_list_exchanges(args: dict[str, Any]) -> None:
|
|||||||
if exchange["is_alias"]:
|
if exchange["is_alias"]:
|
||||||
name.stylize("strike")
|
name.stylize("strike")
|
||||||
classname.stylize("strike")
|
classname.stylize("strike")
|
||||||
classname.append(f" (use {exchange['alias_for']})", style="italic")
|
classname.append(f"\n -> use {exchange['alias_for']}", style="italic")
|
||||||
|
|
||||||
trade_modes = Text(
|
trade_modes = Text(
|
||||||
", ".join(
|
", ".join(
|
||||||
@@ -135,6 +146,9 @@ def start_list_strategies(args: dict[str, Any]) -> None:
|
|||||||
strategy_objs = StrategyResolver.search_all_objects(
|
strategy_objs = StrategyResolver.search_all_objects(
|
||||||
config, not args["print_one_column"], config.get("recursive_strategy_search", False)
|
config, not args["print_one_column"], config.get("recursive_strategy_search", False)
|
||||||
)
|
)
|
||||||
|
if not strategy_objs:
|
||||||
|
logger.warning("No strategies found.")
|
||||||
|
return
|
||||||
# Sort alphabetically
|
# Sort alphabetically
|
||||||
strategy_objs = sorted(strategy_objs, key=lambda x: x["name"])
|
strategy_objs = sorted(strategy_objs, key=lambda x: x["name"])
|
||||||
for obj in strategy_objs:
|
for obj in strategy_objs:
|
||||||
|
|||||||
@@ -72,7 +72,7 @@ def start_backtesting_show(args: dict[str, Any]) -> None:
|
|||||||
from freqtrade.data.btanalysis import load_backtest_stats
|
from freqtrade.data.btanalysis import load_backtest_stats
|
||||||
from freqtrade.optimize.optimize_reports import show_backtest_results, show_sorted_pairlist
|
from freqtrade.optimize.optimize_reports import show_backtest_results, show_sorted_pairlist
|
||||||
|
|
||||||
results = load_backtest_stats(config["exportfilename"])
|
results = load_backtest_stats(config["exportdirectory"], config["exportfilename"])
|
||||||
|
|
||||||
show_backtest_results(config, results)
|
show_backtest_results(config, results)
|
||||||
show_sorted_pairlist(config, results)
|
show_sorted_pairlist(config, results)
|
||||||
@@ -129,15 +129,10 @@ def start_edge(args: dict[str, Any]) -> None:
|
|||||||
:param args: Cli args from Arguments()
|
:param args: Cli args from Arguments()
|
||||||
:return: None
|
:return: None
|
||||||
"""
|
"""
|
||||||
from freqtrade.optimize.edge_cli import EdgeCli
|
raise ConfigurationError(
|
||||||
|
"The Edge module has been deprecated in 2023.9 and removed in 2025.6. "
|
||||||
# Initialize configuration
|
"All functionalities of edge have been removed."
|
||||||
config = setup_optimize_configuration(args, RunMode.EDGE)
|
)
|
||||||
logger.info("Starting freqtrade in Edge mode")
|
|
||||||
|
|
||||||
# Initialize Edge object
|
|
||||||
edge_cli = EdgeCli(config)
|
|
||||||
edge_cli.start()
|
|
||||||
|
|
||||||
|
|
||||||
def start_lookahead_analysis(args: dict[str, Any]) -> None:
|
def start_lookahead_analysis(args: dict[str, Any]) -> None:
|
||||||
|
|||||||
@@ -26,6 +26,8 @@ __MESSAGE_TYPE_DICT: dict[str, dict[str, str]] = {x: {"type": "object"} for x in
|
|||||||
|
|
||||||
__IN_STRATEGY = "\nUsually specified in the strategy and missing in the configuration."
|
__IN_STRATEGY = "\nUsually specified in the strategy and missing in the configuration."
|
||||||
|
|
||||||
|
__VIA_ENV = "Recommended to be set via environment variable"
|
||||||
|
|
||||||
CONF_SCHEMA = {
|
CONF_SCHEMA = {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
@@ -155,6 +157,16 @@ CONF_SCHEMA = {
|
|||||||
"description": f"Offset for profit exit. {__IN_STRATEGY}",
|
"description": f"Offset for profit exit. {__IN_STRATEGY}",
|
||||||
"type": "number",
|
"type": "number",
|
||||||
},
|
},
|
||||||
|
"recursive_strategy_search": {
|
||||||
|
"description": "Enable recursive strategy search.",
|
||||||
|
"type": "boolean",
|
||||||
|
},
|
||||||
|
"user_data_dir": {
|
||||||
|
"description": "Path to the user data directory.",
|
||||||
|
},
|
||||||
|
"datadir": {
|
||||||
|
"description": "Path to the data directory.",
|
||||||
|
},
|
||||||
"fee": {
|
"fee": {
|
||||||
"description": "Trading fee percentage. Can help to simulate slippage in backtesting",
|
"description": "Trading fee percentage. Can help to simulate slippage in backtesting",
|
||||||
"type": "number",
|
"type": "number",
|
||||||
@@ -421,10 +433,6 @@ CONF_SCHEMA = {
|
|||||||
"description": "Exchange configuration.",
|
"description": "Exchange configuration.",
|
||||||
"$ref": "#/definitions/exchange",
|
"$ref": "#/definitions/exchange",
|
||||||
},
|
},
|
||||||
"edge": {
|
|
||||||
"description": "Edge configuration.",
|
|
||||||
"$ref": "#/definitions/edge",
|
|
||||||
},
|
|
||||||
"log_config": {
|
"log_config": {
|
||||||
"description": "Logging configuration.",
|
"description": "Logging configuration.",
|
||||||
"$ref": "#/definitions/logging",
|
"$ref": "#/definitions/logging",
|
||||||
@@ -445,6 +453,7 @@ CONF_SCHEMA = {
|
|||||||
"pairlists": {
|
"pairlists": {
|
||||||
"description": "Configuration for pairlists.",
|
"description": "Configuration for pairlists.",
|
||||||
"type": "array",
|
"type": "array",
|
||||||
|
"minItems": 1,
|
||||||
"items": {
|
"items": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
@@ -468,11 +477,16 @@ CONF_SCHEMA = {
|
|||||||
},
|
},
|
||||||
"token": {"description": "Telegram bot token.", "type": "string"},
|
"token": {"description": "Telegram bot token.", "type": "string"},
|
||||||
"chat_id": {
|
"chat_id": {
|
||||||
"description": "Telegram chat or group ID",
|
"description": (
|
||||||
|
f"Telegram chat or group ID. {__VIA_ENV} FREQTRADE__TELEGRAM__CHAT_ID"
|
||||||
|
),
|
||||||
"type": "string",
|
"type": "string",
|
||||||
},
|
},
|
||||||
"topic_id": {
|
"topic_id": {
|
||||||
"description": "Telegram topic ID - only applicable for group chats",
|
"description": (
|
||||||
|
"Telegram topic ID - only applicable for group chats. "
|
||||||
|
f"{__VIA_ENV} FREQTRADE__TELEGRAM__TOPIC_ID"
|
||||||
|
),
|
||||||
"type": "string",
|
"type": "string",
|
||||||
},
|
},
|
||||||
"authorized_users": {
|
"authorized_users": {
|
||||||
@@ -574,8 +588,11 @@ CONF_SCHEMA = {
|
|||||||
"description": "Webhook settings.",
|
"description": "Webhook settings.",
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
"enabled": {"type": "boolean"},
|
"enabled": {"description": "Enable webhook notifications.", "type": "boolean"},
|
||||||
"url": {"type": "string"},
|
"url": {
|
||||||
|
"description": f"Webhook URL. {__VIA_ENV} FREQTRADE__WEBHOOK__URL",
|
||||||
|
"type": "string",
|
||||||
|
},
|
||||||
"format": {"type": "string", "enum": WEBHOOK_FORMAT_OPTIONS, "default": "form"},
|
"format": {"type": "string", "enum": WEBHOOK_FORMAT_OPTIONS, "default": "form"},
|
||||||
"retries": {"type": "integer", "minimum": 0},
|
"retries": {"type": "integer", "minimum": 0},
|
||||||
"retry_delay": {"type": "number", "minimum": 0},
|
"retry_delay": {"type": "number", "minimum": 0},
|
||||||
@@ -587,7 +604,12 @@ CONF_SCHEMA = {
|
|||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
"enabled": {"type": "boolean"},
|
"enabled": {"type": "boolean"},
|
||||||
"webhook_url": {"type": "string"},
|
"webhook_url": {
|
||||||
|
"description": (
|
||||||
|
f"Discord webhook URL. {__VIA_ENV} FREQTRADE__DISCORD__WEBHOOK_URL"
|
||||||
|
),
|
||||||
|
"type": "string",
|
||||||
|
},
|
||||||
"exit_fill": {
|
"exit_fill": {
|
||||||
"type": "array",
|
"type": "array",
|
||||||
"items": {"type": "object"},
|
"items": {"type": "object"},
|
||||||
@@ -806,27 +828,57 @@ CONF_SCHEMA = {
|
|||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
"name": {"description": "Name of the exchange.", "type": "string"},
|
"name": {"description": "Name of the exchange.", "type": "string"},
|
||||||
"enable_ws": {
|
|
||||||
"description": "Enable WebSocket connections to the exchange.",
|
|
||||||
"type": "boolean",
|
|
||||||
"default": True,
|
|
||||||
},
|
|
||||||
"key": {
|
"key": {
|
||||||
"description": "API key for the exchange.",
|
"description": (
|
||||||
|
f"API key for the exchange. {__VIA_ENV} FREQTRADE__EXCHANGE__KEY"
|
||||||
|
),
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"default": "",
|
"default": "",
|
||||||
},
|
},
|
||||||
"secret": {
|
"secret": {
|
||||||
"description": "API secret for the exchange.",
|
"description": (
|
||||||
|
f"API secret for the exchange. {__VIA_ENV} FREQTRADE__EXCHANGE__SECRET"
|
||||||
|
),
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"default": "",
|
"default": "",
|
||||||
},
|
},
|
||||||
"password": {
|
"password": {
|
||||||
"description": "Password for the exchange, if required.",
|
"description": (
|
||||||
|
"Password for the exchange, if required. "
|
||||||
|
f"{__VIA_ENV} FREQTRADE__EXCHANGE__PASSWORD"
|
||||||
|
),
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"default": "",
|
"default": "",
|
||||||
},
|
},
|
||||||
"uid": {"description": "User ID for the exchange, if required.", "type": "string"},
|
"uid": {
|
||||||
|
"description": (
|
||||||
|
"User ID for the exchange, if required. "
|
||||||
|
f"{__VIA_ENV} FREQTRADE__EXCHANGE__UID"
|
||||||
|
),
|
||||||
|
"type": "string",
|
||||||
|
},
|
||||||
|
"account_id": {
|
||||||
|
"description": (
|
||||||
|
"Account ID for the exchange, if required. "
|
||||||
|
f"{__VIA_ENV} FREQTRADE__EXCHANGE__ACCOUNT_ID"
|
||||||
|
),
|
||||||
|
"type": "string",
|
||||||
|
},
|
||||||
|
"wallet_address": {
|
||||||
|
"description": (
|
||||||
|
"Wallet address for the exchange, if required. "
|
||||||
|
"Usually used by DEX exchanges. "
|
||||||
|
f"{__VIA_ENV} FREQTRADE__EXCHANGE__WALLET_ADDRESS"
|
||||||
|
),
|
||||||
|
"type": "string",
|
||||||
|
},
|
||||||
|
"private_key": {
|
||||||
|
"description": (
|
||||||
|
"Private key for the exchange, if required. Usually used by DEX exchanges. "
|
||||||
|
f"{__VIA_ENV} FREQTRADE__EXCHANGE__PRIVATE_KEY"
|
||||||
|
),
|
||||||
|
"type": "string",
|
||||||
|
},
|
||||||
"pair_whitelist": {
|
"pair_whitelist": {
|
||||||
"description": "List of whitelisted trading pairs.",
|
"description": "List of whitelisted trading pairs.",
|
||||||
"type": "array",
|
"type": "array",
|
||||||
@@ -847,6 +899,11 @@ CONF_SCHEMA = {
|
|||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"default": False,
|
"default": False,
|
||||||
},
|
},
|
||||||
|
"enable_ws": {
|
||||||
|
"description": "Enable WebSocket connections to the exchange.",
|
||||||
|
"type": "boolean",
|
||||||
|
"default": True,
|
||||||
|
},
|
||||||
"unknown_fee_rate": {
|
"unknown_fee_rate": {
|
||||||
"description": "Fee rate for unknown markets.",
|
"description": "Fee rate for unknown markets.",
|
||||||
"type": "number",
|
"type": "number",
|
||||||
@@ -863,30 +920,22 @@ CONF_SCHEMA = {
|
|||||||
},
|
},
|
||||||
"ccxt_config": {"description": "CCXT configuration settings.", "type": "object"},
|
"ccxt_config": {"description": "CCXT configuration settings.", "type": "object"},
|
||||||
"ccxt_async_config": {
|
"ccxt_async_config": {
|
||||||
"description": "CCXT asynchronous configuration settings.",
|
"description": (
|
||||||
|
"CCXT asynchronous configuration settings."
|
||||||
|
"Usually ccxt_config should be used instead."
|
||||||
|
),
|
||||||
|
"type": "object",
|
||||||
|
},
|
||||||
|
"ccxt_sync_config": {
|
||||||
|
"description": (
|
||||||
|
"CCXT synchronous configuration settings. "
|
||||||
|
"Usually ccxt_config should be used instead."
|
||||||
|
),
|
||||||
"type": "object",
|
"type": "object",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"required": ["name"],
|
"required": ["name"],
|
||||||
},
|
},
|
||||||
"edge": {
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"enabled": {"type": "boolean"},
|
|
||||||
"process_throttle_secs": {"type": "integer", "minimum": 600},
|
|
||||||
"calculate_since_number_of_days": {"type": "integer"},
|
|
||||||
"allowed_risk": {"type": "number"},
|
|
||||||
"stoploss_range_min": {"type": "number"},
|
|
||||||
"stoploss_range_max": {"type": "number"},
|
|
||||||
"stoploss_range_step": {"type": "number"},
|
|
||||||
"minimum_winrate": {"type": "number"},
|
|
||||||
"minimum_expectancy": {"type": "number"},
|
|
||||||
"min_trade_number": {"type": "number"},
|
|
||||||
"max_trade_duration_minute": {"type": "integer"},
|
|
||||||
"remove_pumps": {"type": "boolean"},
|
|
||||||
},
|
|
||||||
"required": ["process_throttle_secs", "allowed_risk"],
|
|
||||||
},
|
|
||||||
"logging": {
|
"logging": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
@@ -1333,6 +1382,7 @@ SCHEMA_TRADE_REQUIRED = [
|
|||||||
"entry_pricing",
|
"entry_pricing",
|
||||||
"stoploss",
|
"stoploss",
|
||||||
"minimal_roi",
|
"minimal_roi",
|
||||||
|
"pairlists",
|
||||||
"internals",
|
"internals",
|
||||||
"dataformat_ohlcv",
|
"dataformat_ohlcv",
|
||||||
"dataformat_trades",
|
"dataformat_trades",
|
||||||
@@ -1342,6 +1392,7 @@ SCHEMA_BACKTEST_REQUIRED = [
|
|||||||
"exchange",
|
"exchange",
|
||||||
"stake_currency",
|
"stake_currency",
|
||||||
"stake_amount",
|
"stake_amount",
|
||||||
|
"pairlists",
|
||||||
"dry_run_wallet",
|
"dry_run_wallet",
|
||||||
"dataformat_ohlcv",
|
"dataformat_ohlcv",
|
||||||
"dataformat_trades",
|
"dataformat_trades",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
# flake8: noqa: F401
|
# flake8: noqa: F401
|
||||||
|
|
||||||
from freqtrade.configuration.config_secrets import sanitize_config
|
from freqtrade.configuration.config_secrets import remove_exchange_credentials, sanitize_config
|
||||||
from freqtrade.configuration.config_setup import setup_utils_configuration
|
from freqtrade.configuration.config_setup import setup_utils_configuration
|
||||||
from freqtrade.configuration.config_validation import validate_config_consistency
|
from freqtrade.configuration.config_validation import validate_config_consistency
|
||||||
from freqtrade.configuration.configuration import Configuration
|
from freqtrade.configuration.configuration import Configuration
|
||||||
|
|||||||
@@ -1,6 +1,27 @@
|
|||||||
from copy import deepcopy
|
from copy import deepcopy
|
||||||
|
|
||||||
from freqtrade.constants import Config
|
from freqtrade.constants import Config, ExchangeConfig
|
||||||
|
|
||||||
|
|
||||||
|
_SENSITIVE_KEYS = [
|
||||||
|
"exchange.key",
|
||||||
|
"exchange.api_key",
|
||||||
|
"exchange.apiKey",
|
||||||
|
"exchange.secret",
|
||||||
|
"exchange.password",
|
||||||
|
"exchange.uid",
|
||||||
|
"exchange.account_id",
|
||||||
|
"exchange.accountId",
|
||||||
|
"exchange.wallet_address",
|
||||||
|
"exchange.walletAddress",
|
||||||
|
"exchange.private_key",
|
||||||
|
"exchange.privateKey",
|
||||||
|
"telegram.token",
|
||||||
|
"telegram.chat_id",
|
||||||
|
"discord.webhook_url",
|
||||||
|
"api_server.password",
|
||||||
|
"webhook.url",
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
def sanitize_config(config: Config, *, show_sensitive: bool = False) -> Config:
|
def sanitize_config(config: Config, *, show_sensitive: bool = False) -> Config:
|
||||||
@@ -12,26 +33,8 @@ def sanitize_config(config: Config, *, show_sensitive: bool = False) -> Config:
|
|||||||
"""
|
"""
|
||||||
if show_sensitive:
|
if show_sensitive:
|
||||||
return config
|
return config
|
||||||
keys_to_remove = [
|
|
||||||
"exchange.key",
|
|
||||||
"exchange.api_key",
|
|
||||||
"exchange.apiKey",
|
|
||||||
"exchange.secret",
|
|
||||||
"exchange.password",
|
|
||||||
"exchange.uid",
|
|
||||||
"exchange.account_id",
|
|
||||||
"exchange.accountId",
|
|
||||||
"exchange.wallet_address",
|
|
||||||
"exchange.walletAddress",
|
|
||||||
"exchange.private_key",
|
|
||||||
"exchange.privateKey",
|
|
||||||
"telegram.token",
|
|
||||||
"telegram.chat_id",
|
|
||||||
"discord.webhook_url",
|
|
||||||
"api_server.password",
|
|
||||||
]
|
|
||||||
config = deepcopy(config)
|
config = deepcopy(config)
|
||||||
for key in keys_to_remove:
|
for key in _SENSITIVE_KEYS:
|
||||||
if "." in key:
|
if "." in key:
|
||||||
nested_keys = key.split(".")
|
nested_keys = key.split(".")
|
||||||
nested_config = config
|
nested_config = config
|
||||||
@@ -44,3 +47,21 @@ def sanitize_config(config: Config, *, show_sensitive: bool = False) -> Config:
|
|||||||
config[key] = "REDACTED"
|
config[key] = "REDACTED"
|
||||||
|
|
||||||
return config
|
return config
|
||||||
|
|
||||||
|
|
||||||
|
def remove_exchange_credentials(exchange_config: ExchangeConfig, dry_run: bool) -> None:
|
||||||
|
"""
|
||||||
|
Removes exchange keys from the configuration and specifies dry-run
|
||||||
|
Used for backtesting / hyperopt and utils.
|
||||||
|
Modifies the input dict!
|
||||||
|
:param exchange_config: Exchange configuration
|
||||||
|
:param dry_run: If True, remove sensitive keys from the exchange configuration
|
||||||
|
"""
|
||||||
|
if not dry_run:
|
||||||
|
return
|
||||||
|
|
||||||
|
for key in [k for k in _SENSITIVE_KEYS if k.startswith("exchange.")]:
|
||||||
|
if "." in key:
|
||||||
|
key1 = key.removeprefix("exchange.")
|
||||||
|
if key1 in exchange_config:
|
||||||
|
exchange_config[key1] = ""
|
||||||
|
|||||||
@@ -66,7 +66,8 @@ def validate_config_schema(conf: dict[str, Any], preliminary: bool = False) -> d
|
|||||||
return conf
|
return conf
|
||||||
except ValidationError as e:
|
except ValidationError as e:
|
||||||
logger.critical(f"Invalid configuration. Reason: {e}")
|
logger.critical(f"Invalid configuration. Reason: {e}")
|
||||||
raise ValidationError(best_match(Draft4Validator(conf_schema).iter_errors(conf)).message)
|
result = best_match(FreqtradeValidator(conf_schema).iter_errors(conf))
|
||||||
|
raise ConfigurationError(result.message)
|
||||||
|
|
||||||
|
|
||||||
def validate_config_consistency(conf: dict[str, Any], *, preliminary: bool = False) -> None:
|
def validate_config_consistency(conf: dict[str, Any], *, preliminary: bool = False) -> None:
|
||||||
@@ -99,14 +100,12 @@ def validate_config_consistency(conf: dict[str, Any], *, preliminary: bool = Fal
|
|||||||
|
|
||||||
def _validate_unlimited_amount(conf: dict[str, Any]) -> None:
|
def _validate_unlimited_amount(conf: dict[str, Any]) -> None:
|
||||||
"""
|
"""
|
||||||
If edge is disabled, either max_open_trades or stake_amount need to be set.
|
Either max_open_trades or stake_amount need to be set.
|
||||||
:raise: ConfigurationError if config validation failed
|
:raise: ConfigurationError if config validation failed
|
||||||
"""
|
"""
|
||||||
if (
|
if (
|
||||||
not conf.get("edge", {}).get("enabled")
|
conf.get("max_open_trades") == float("inf") or conf.get("max_open_trades") == -1
|
||||||
and conf.get("max_open_trades") == float("inf")
|
) and conf.get("stake_amount") == UNLIMITED_STAKE_AMOUNT:
|
||||||
and conf.get("stake_amount") == UNLIMITED_STAKE_AMOUNT
|
|
||||||
):
|
|
||||||
raise ConfigurationError("`max_open_trades` and `stake_amount` cannot both be unlimited.")
|
raise ConfigurationError("`max_open_trades` and `stake_amount` cannot both be unlimited.")
|
||||||
|
|
||||||
|
|
||||||
@@ -114,7 +113,6 @@ def _validate_price_config(conf: dict[str, Any]) -> None:
|
|||||||
"""
|
"""
|
||||||
When using market orders, price sides must be using the "other" side of the price
|
When using market orders, price sides must be using the "other" side of the price
|
||||||
"""
|
"""
|
||||||
# TODO: The below could be an enforced setting when using market orders
|
|
||||||
if conf.get("order_types", {}).get("entry") == "market" and conf.get("entry_pricing", {}).get(
|
if conf.get("order_types", {}).get("entry") == "market" and conf.get("entry_pricing", {}).get(
|
||||||
"price_side"
|
"price_side"
|
||||||
) not in ("ask", "other"):
|
) not in ("ask", "other"):
|
||||||
@@ -164,12 +162,9 @@ def _validate_edge(conf: dict[str, Any]) -> None:
|
|||||||
Edge and Dynamic whitelist should not both be enabled, since edge overrides dynamic whitelists.
|
Edge and Dynamic whitelist should not both be enabled, since edge overrides dynamic whitelists.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if not conf.get("edge", {}).get("enabled"):
|
if conf.get("edge", {}).get("enabled"):
|
||||||
return
|
|
||||||
|
|
||||||
if not conf.get("use_exit_signal", True):
|
|
||||||
raise ConfigurationError(
|
raise ConfigurationError(
|
||||||
"Edge requires `use_exit_signal` to be True, otherwise no sells will happen."
|
"Edge is no longer supported and has been removed from Freqtrade with 2025.6."
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,6 @@
|
|||||||
This module contains the configuration class
|
This module contains the configuration class
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import ast
|
|
||||||
import logging
|
import logging
|
||||||
import warnings
|
import warnings
|
||||||
from collections.abc import Callable
|
from collections.abc import Callable
|
||||||
@@ -88,9 +87,6 @@ class Configuration:
|
|||||||
if "internals" not in config:
|
if "internals" not in config:
|
||||||
config["internals"] = {}
|
config["internals"] = {}
|
||||||
|
|
||||||
if "pairlists" not in config:
|
|
||||||
config["pairlists"] = []
|
|
||||||
|
|
||||||
# Keep a copy of the original configuration file
|
# Keep a copy of the original configuration file
|
||||||
config["original_config"] = deepcopy(config)
|
config["original_config"] = deepcopy(config)
|
||||||
|
|
||||||
@@ -216,13 +212,31 @@ class Configuration:
|
|||||||
config.update({"datadir": create_datadir(config, self.args.get("datadir"))})
|
config.update({"datadir": create_datadir(config, self.args.get("datadir"))})
|
||||||
logger.info("Using data directory: %s ...", config.get("datadir"))
|
logger.info("Using data directory: %s ...", config.get("datadir"))
|
||||||
|
|
||||||
|
self._args_to_config(
|
||||||
|
config, argname="exportdirectory", logstring="Using {} as backtest directory ..."
|
||||||
|
)
|
||||||
|
|
||||||
if self.args.get("exportfilename"):
|
if self.args.get("exportfilename"):
|
||||||
self._args_to_config(
|
self._args_to_config(
|
||||||
config, argname="exportfilename", logstring="Storing backtest results to {} ..."
|
config, argname="exportfilename", logstring="Storing backtest results to {} ..."
|
||||||
)
|
)
|
||||||
config["exportfilename"] = Path(config["exportfilename"])
|
config["exportfilename"] = Path(config["exportfilename"])
|
||||||
else:
|
if config.get("exportdirectory") and Path(config["exportdirectory"]).is_dir():
|
||||||
config["exportfilename"] = config["user_data_dir"] / "backtest_results"
|
logger.warning(
|
||||||
|
"DEPRECATED: Using `--export-filename` with directories is deprecated, "
|
||||||
|
"use `--backtest-directory` instead."
|
||||||
|
)
|
||||||
|
if config.get("exportdirectory") is None:
|
||||||
|
# Fallback - assign export-directory directly.
|
||||||
|
config["exportdirectory"] = config["exportfilename"]
|
||||||
|
if not config.get("exportdirectory"):
|
||||||
|
config["exportdirectory"] = config["user_data_dir"] / "backtest_results"
|
||||||
|
if not config.get("exportfilename"):
|
||||||
|
config["exportfilename"] = None
|
||||||
|
if config.get("exportfilename"):
|
||||||
|
# ensure exportfilename is a Path object
|
||||||
|
config["exportfilename"] = Path(config["exportfilename"])
|
||||||
|
config["exportdirectory"] = Path(config["exportdirectory"])
|
||||||
|
|
||||||
if self.args.get("show_sensitive"):
|
if self.args.get("show_sensitive"):
|
||||||
logger.warning(
|
logger.warning(
|
||||||
@@ -248,7 +262,13 @@ class Configuration:
|
|||||||
self._args_to_config(
|
self._args_to_config(
|
||||||
config,
|
config,
|
||||||
argname="enable_protections",
|
argname="enable_protections",
|
||||||
logstring="Parameter --enable-protections detected, enabling Protections. ...",
|
logstring="Parameter --enable-protections detected, enabling Protections ...",
|
||||||
|
)
|
||||||
|
|
||||||
|
self._args_to_config(
|
||||||
|
config,
|
||||||
|
argname="enable_dynamic_pairlist",
|
||||||
|
logstring="Parameter --enable-dynamic-pairlist detected, enabling dynamic pairlist ...",
|
||||||
)
|
)
|
||||||
|
|
||||||
if self.args.get("max_open_trades"):
|
if self.args.get("max_open_trades"):
|
||||||
@@ -304,23 +324,15 @@ class Configuration:
|
|||||||
"recursive_strategy_search",
|
"recursive_strategy_search",
|
||||||
"Recursively searching for a strategy in the strategies folder.",
|
"Recursively searching for a strategy in the strategies folder.",
|
||||||
),
|
),
|
||||||
("timeframe", "Overriding timeframe with Command line argument"),
|
|
||||||
("export", "Parameter --export detected: {} ..."),
|
("export", "Parameter --export detected: {} ..."),
|
||||||
("backtest_breakdown", "Parameter --breakdown detected ..."),
|
("backtest_breakdown", "Parameter --breakdown detected ..."),
|
||||||
("backtest_cache", "Parameter --cache={} detected ..."),
|
("backtest_cache", "Parameter --cache={} detected ..."),
|
||||||
("disableparamexport", "Parameter --disableparamexport detected: {} ..."),
|
("disableparamexport", "Parameter --disableparamexport detected: {} ..."),
|
||||||
("freqai_backtest_live_models", "Parameter --freqai-backtest-live-models detected ..."),
|
("freqai_backtest_live_models", "Parameter --freqai-backtest-live-models detected ..."),
|
||||||
|
("backtest_notes", "Parameter --notes detected: {} ..."),
|
||||||
]
|
]
|
||||||
self._args_to_config_loop(config, configurations)
|
self._args_to_config_loop(config, configurations)
|
||||||
|
|
||||||
# Edge section:
|
|
||||||
if self.args.get("stoploss_range"):
|
|
||||||
txt_range = ast.literal_eval(self.args["stoploss_range"])
|
|
||||||
config["edge"].update({"stoploss_range_min": txt_range[0]})
|
|
||||||
config["edge"].update({"stoploss_range_max": txt_range[1]})
|
|
||||||
config["edge"].update({"stoploss_range_step": txt_range[2]})
|
|
||||||
logger.info("Parameter --stoplosses detected: %s ...", self.args["stoploss_range"])
|
|
||||||
|
|
||||||
# Hyperopt section
|
# Hyperopt section
|
||||||
|
|
||||||
configurations = [
|
configurations = [
|
||||||
@@ -334,6 +346,19 @@ class Configuration:
|
|||||||
("print_all", "Parameter --print-all detected ..."),
|
("print_all", "Parameter --print-all detected ..."),
|
||||||
]
|
]
|
||||||
self._args_to_config_loop(config, configurations)
|
self._args_to_config_loop(config, configurations)
|
||||||
|
es_epochs = self.args.get("early_stop", 0)
|
||||||
|
if es_epochs > 0:
|
||||||
|
if es_epochs < 20:
|
||||||
|
logger.warning(
|
||||||
|
f"Early stop epochs {es_epochs} lower than 20. It will be replaced with 20."
|
||||||
|
)
|
||||||
|
config.update({"early_stop": 20})
|
||||||
|
else:
|
||||||
|
config.update({"early_stop": self.args["early_stop"]})
|
||||||
|
logger.info(
|
||||||
|
f"Parameter --early-stop detected ... Will early stop hyperopt if no improvement "
|
||||||
|
f"after {config.get('early_stop')} epochs ..."
|
||||||
|
)
|
||||||
|
|
||||||
configurations = [
|
configurations = [
|
||||||
("print_json", "Parameter --print-json detected ..."),
|
("print_json", "Parameter --print-json detected ..."),
|
||||||
@@ -377,6 +402,7 @@ class Configuration:
|
|||||||
("timeframes", "timeframes --timeframes: {}"),
|
("timeframes", "timeframes --timeframes: {}"),
|
||||||
("days", "Detected --days: {}"),
|
("days", "Detected --days: {}"),
|
||||||
("include_inactive", "Detected --include-inactive-pairs: {}"),
|
("include_inactive", "Detected --include-inactive-pairs: {}"),
|
||||||
|
("no_parallel_download", "Detected --no-parallel-download: {}"),
|
||||||
("download_trades", "Detected --dl-trades: {}"),
|
("download_trades", "Detected --dl-trades: {}"),
|
||||||
("convert_trades", "Detected --convert: {} - Converting Trade data to OHCV {}"),
|
("convert_trades", "Detected --convert: {} - Converting Trade data to OHCV {}"),
|
||||||
("dataformat_ohlcv", 'Using "{}" to store OHLCV data.'),
|
("dataformat_ohlcv", 'Using "{}" to store OHLCV data.'),
|
||||||
@@ -392,6 +418,9 @@ class Configuration:
|
|||||||
self._args_to_config(
|
self._args_to_config(
|
||||||
config, argname="trading_mode", logstring="Detected --trading-mode: {}"
|
config, argname="trading_mode", logstring="Detected --trading-mode: {}"
|
||||||
)
|
)
|
||||||
|
# TODO: The following 3 lines (candle_type_def, trading_mode, margin_mode) are actually
|
||||||
|
# set in the exchange class. They're however necessary as fallback to avoid
|
||||||
|
# random errors in commands that don't initialize an exchange.
|
||||||
config["candle_type_def"] = CandleType.get_default(
|
config["candle_type_def"] = CandleType.get_default(
|
||||||
config.get("trading_mode", "spot") or "spot"
|
config.get("trading_mode", "spot") or "spot"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -159,16 +159,6 @@ def process_temporary_deprecated_settings(config: Config) -> None:
|
|||||||
process_removed_setting(
|
process_removed_setting(
|
||||||
config, "ask_strategy", "ignore_roi_if_buy_signal", None, "ignore_roi_if_entry_signal"
|
config, "ask_strategy", "ignore_roi_if_buy_signal", None, "ignore_roi_if_entry_signal"
|
||||||
)
|
)
|
||||||
if config.get("edge", {}).get(
|
|
||||||
"enabled", False
|
|
||||||
) and "capital_available_percentage" in config.get("edge", {}):
|
|
||||||
raise ConfigurationError(
|
|
||||||
"DEPRECATED: "
|
|
||||||
"Using 'edge.capital_available_percentage' has been deprecated in favor of "
|
|
||||||
"'tradable_balance_ratio'. Please migrate your configuration to "
|
|
||||||
"'tradable_balance_ratio' and remove 'capital_available_percentage' "
|
|
||||||
"from the edge configuration."
|
|
||||||
)
|
|
||||||
if "ticker_interval" in config:
|
if "ticker_interval" in config:
|
||||||
raise ConfigurationError(
|
raise ConfigurationError(
|
||||||
"DEPRECATED: 'ticker_interval' detected. "
|
"DEPRECATED: 'ticker_interval' detected. "
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user