diff --git a/assets/hierarchy.js b/assets/hierarchy.js index 673a96c45186a61cdbe9bb2f609d0b647d6d76e6..ac7d441885af7df81cca4ce9d71f7eb70b6b12c7 100644 --- a/assets/hierarchy.js +++ b/assets/hierarchy.js @@ -1 +1 @@ -window.hierarchyData = "eJylmV1v2zYYhf+LrtmOpMQP+651MSBYOhjJsF4MveAkRhEsS4VId8uK/PeBpuKQCmWR6k2cWDo6j/S+/NDJj2zoe62y7V+I5RCgDSYAwyIHGFIIMGTmN04ARhADjBACGGEOMCI5wIia75g5ej5lQwHGkACMEQMYY/NnzgHGBQM4ZxBgQnOAKaMAU25+bAggELKvIBvkQytL3fSdyrY/MpTj3Hx24iizbfZx6A9y+CiUzEB2aLoq2xqM7DS02TYrW6GUVL/op29SvX899/2jPrYZsMezbaZV9c6I39kvnkFmbtqxubHaiwcm9MWj6bQcHkR5sRnPnfW4CMzBx6atBtmZx5zj/Ktx5hvqOt/2dZztbV9HeBqHDSYThzr23uy5yffGN9Tcm2kg13kvB9Uo7ZXvqr0jSGXICWWWgcIQwyDFQX6X3U2ntOjKRKCpOpmOwtzSsdAT2omuauUqNF+azoXHynES4Loxqu+iXUU2FaezFfzMhiAOsN329SosR5dOxKAlQihA9FkKdRrWlXGiTSfjtr8Q5kGyYz88rQRzpclcDBLLRUJ9/3uvm4emFGb6X0UXukA6Yz72GQ312V4Mulk5BCbadDIyVpWFRuedLGWnV4H50nQuZmcNFJw17hp1WEflCJOZOBzHpr++jpe+Lx9ldVo5x07F6WzYsmEYel73Uqm1A2CiTSfLN5YMsRBZU3crW9+XpnNRZLlwsJpa6JWldJXpVHysYx6aZe91P4h6LZenTSbbjN2Pi2Ad9SC0rNetAFNxOhuyawDm/hpw+rttStsnd/0/kUy+KJUF57w4s+TM2yWamWf3KMvDh6FWcSSeJJmjGMddzospR+IT8SRxbwjGfer6p2ib6ryO7sVT24sq3v2NNJaCemP7ZZat7N3sTK/FP4Y5dSQLgfwKy1qKNR1aULu2EuqNFnvBT7qPBHk5PdmfmFd/Mm4nCQtAvGzsE2EcWWxReMA9vharS4C5eQTQ7gppUfgQ/zVdvReDOKoPf9zFoniiyNunhMw5/9r8K6u9HMwuTtSR8/mVC8QS0Vmi32TbPqVznGWx7oy+dTcj7igSK3ERJbcGLez6Qfksy0/UJniBdEZi11u6CVTLWiRXy5Gl81DLw6k3x34R7UEOd1KdWh255nqSuK4xuZDjGoqkZhPFmDjqEimaiCdgNJs7LbpGZ04Ogrdbvh4uLflHBkuOecHfms8mSEv20emRA+Dt6a7EREveMRGRY8sDdZ/LgpasY3OgV3vmvVNeD3yW3aPCHsc8D9T8aqqzhJCU6DggJFCEuehmiSE2tnHsWWDgzeQzS+6R2cyrOYeBvg+GMIvWMQGMY4wDxrNJy5J5dMriAHjvMQtxyqJ/ZJTi2FMUsA9nJovucXmJY85DDz8YjCx6R4Uir9abUMPNpR/L5nHJh2OPAjPebMSx7B8Zb1wAzH8uHQC7Kdn1x2+t1HLXd3oQpY7a0ISlyRssTjkgsDgnQObzDZwpcKN0U6rPfSXbBLaJMmbP9fz8P6WAOEA=" \ No newline at end of file +window.hierarchyData = "eJylmV1v2zYYhf+LrtlOfElJlO9aFwOCpYORDOvF0AtOYhTBslSIdLesyH8faDoOqVAWqd7Yhq2j85Avv3T8IxmHQclk8xdmBSBIGUMAaY4AgCAAoj9R/V2eIYCCIoASIyA4R0AgQ0AIQ0D0JSQrEZBcf2KpfikR0BQjoDhFkBGCoIAcASMlAkb1S8ZQhsv8K0pG8dCJSrVDL5PNjwSTrNDvPT+IZJN8HIe9GD9yKRKU7Nu+TjYYGEqOY5dskqrjUgr5i3r6JuT712vfP6pDlyDze7JJlKzfafE788UzSnSjLZsbo714QJa/eLS9EuMDry4252tnPS4C/eNj29Wj6HU3k6z4+owSSLPSdr4dmjDb26EJ8Dw5MDZxaELbZq6NbZtu06ltkOa2806MspXKKd9Ve0sQy0AKkhoGID6GUfC9+C76m14q3leRQFN1PF2eGzri66Et7+tOrEJzpfFc7Fw5yjxcN1r1nXeryKbiaDaGsWHLMw/b7dCswrJ08USEGKKCeog+Cy6P47oyTrTxZPQ8vkrsJTsM49NKMFsaz5WzExfBvnH/+6Dah7bievlfRee7QTRjmZpxRsA3znZ8VO3KKTDRxpNhU1VCfLPzTlSiV6vAXGk8FzGrBvGuGnet3K+jsoTxTLmZm8TdX8+3vq8eRX1cucZOxfFs7MyW+/rrXki5dgJMtLFkNE3BkLHUR9Y2/cqh70rjuYCeubzVVFytLKWtjKeipo409a2y92oYebOWy9HGk51HP8XeOqqRK9Gs2wGm4ni2wuwBlLp7wPHvrq3MOLkb/glkckXRJ9WMmlN4RpxTol55to+i2n8YGxlG4kiiOfLzvMtoMeWI7BFHEviEkKcwdf2Td2192kd3/KkbeB3u/kYaSgHO3H5ZZWvTmq0ea+HdMKcOZSnwFZa1FGtGaA5mby3AmS3mhp/UEAjycnm0f6Ef/YvzcbIgHoiXg30kjCULLEpBPe7htVhdAkpzpEfEqQtYWrgQ/7V9s+MjP8gPf9yFojiiwOYzzOacf23/FfVOjPoUx5vA9fzKDUKJYJboN9F1T/EcJ1moOynfuusZd+CRlbiIoocGS83+wegsy0/UxnuDeEZs9luWeaplLKKrZcnieeDEQ1LirLFfeLcX452Qx04F7rmOJGzU6FzIcvVFUrOJYkgcdYkUdcTjMZrNnRZdgzMnC8E5LV8Pl5b8A4OlV3OG8Vvz2QRpyT44PbIAnDPdlZhoyTskIrJsqafuc1nQknVoDmTZO8+U1wOfZfegsOfVvEw9Nb+a6iwhRCU6Fgj2FGEuulliCI1tLHvimXgz+cySe2A2Y5nnnnHvDWEWrUMCGMuYeYxnk5Yl8+CU5QKg0wsPwEycsugfGKVY9kA99v7MZNE9LC+xzKmv873ByKJ3UChiWfsG3Fz6sWwelnxY9oVnxZuNOJb9A+ONC4D+59ICMIeS7XD41gkltkOvRl6poAONXxodL6YEowzMc6N+fwOnC9xK1Vby81CLLoJtogw5cz0//w+UIjig" \ No newline at end of file diff --git a/assets/navigation.js b/assets/navigation.js index 4621c0a0b15d4d0275121dcf0157c2ee38bbdae8..98869c1dff9da481721ee28bbd302015e34d4d1a 100644 --- a/assets/navigation.js +++ b/assets/navigation.js @@ -1 +1 @@ -window.navigationData = "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" \ No newline at end of file +window.navigationData = "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" \ No newline at end of file diff --git a/assets/search.js b/assets/search.js index e21478a0e9d5e704ef3eb94756d321b14a3e8d27..c5446a033d132fecc5bc6cd5933d984bfbfd9559 100644 --- a/assets/search.js +++ b/assets/search.js @@ -1 +1 @@ -window.searchData = "eJy8vdmS3DiWrvsuqXPZeSqlTOXQd0oNXeqWKrUldaW1tW1zo9wRHuygk75JekiR2867HwMHJ0hi+NfAuKosxVr4P8IxYwH4v9/V1dfmu3/97//73V1eHr77119//PXXn3/49V++K7OT+e5fv3v37n3z3b98d6mL7/71u0O1v5xM2TZ/s//8/962p+K7f/luX2RNY5rv/vW77/6/fwmlc6j2vnTsP5PSyeo23xfmbz883RVVdbfLbk122H3JM1/qg/FubczTfLZrzL4qD7uqPph6t7/Nqqisz56n/ONuX2SXg9m1dXYwdUx0YcrT+2lXndu8Kne35nDMy2NMcGnLU3y+y/Jd09ZZa44Pu69VfXdTVF9jun4PnvrPs7S+FBdzrvOyjckHXHj6v9jESvO16X61vDzumvxYZkW0eAWdeAy/2uSK/P9c8kPePuxus/reNG3ixw868Rh+253z0jT7Oj+3u6LaZ8XulNV3po1mRNiLRfH0h91hn+2ye1Nnxy5bh185whD0IRF8Mce8tG3bua7+x+zbXXVv6vvc+OpBZ7vz2HIUn+2Opm177qxuzWG3r8qb/HipM1u1w/IJRw7Lj7vmoWnNaZfV+9u8Nfv2UhsgJ+J+HJKfdkVx2t1UtdlnTbsz5TEvza6ojvk+jBFx4jA8n5I652dT2MSqS2v/N8wQceIw/LzLDvd5U9VN39z0lWt3yNoszBBx4jD80qdyY9r9rS1u+6z/3+4f7J/CJElXDs+vu6ooslO221enc2FsYY8g+Kw5qr9NTf3Y89yYL7tnPzz7OdZKDRSIN4Pq6Q9Dx7M7mtL0FX/XmLLNrfrulJ3P/l6kx8LcOVxPd+eqybv0ivzG7B9sS22+5W2iDqccOSzPdl+y/V1rmnZ3qg6Xwuxu6uxkwHYWc+dw/WiLQH3J6oe+HOyzxuya9nJ42J1NfVPVp6zch5sa0J9D9tP0yXd523+vHeWFWUIeHPXn17RsfTHfzP7SlYfanKs6MCoaMJKuHJ6fx0rStFlrdqeuDYv8Ln57jvIvuyK/N9em41QdIrIeY47mr7s6b+52p6zMjsYKhBVXphy932aDeTufOeV/9S3R16y48864Bv2kK4Pn2Q87821/m5VHs8vL1hyHVrGv+uF+JuHHIXm62++/tVOy2SE7t5H8CDlwtJ/tmofTl6oAG8mAPUf5x92xqJomq8O9qWNDXgn5W2f5txd7y/d71vgqlLXbdXa7yU6m9LIqS9P91yc7KPY26yvZlZOUoTYk9au5TPdDXX3z/Zgrxc5QpvVpf2tOGeErZw4y7X9mRX7IiL/xyonL8PvQ8b2sTqesPEAIfh8pwTs7UPtQ5/dZi5W3iKMOy+VLke8ZKK6flOR9Vt8dqq9Y2Qg4SRk+dsMgEsHMRar/n23uXVfz6HambL3aZHfm3lCb3bCfmOTfiupLVtAoZj5iAloBDHiJKShF0OsjJkAK4cyWr1jdmfpFcNQ2E3RMZXrpMc1kx1V6me1vDZCPkx1bqchN2fZdZULLsZSpvR7Gz4jeaCtTfGOny4hcZyjT+pg3vnn8SsrayZQ+5X/5J+srrd6SrVYVlxN19BVw4jPYaQ+ZweskYGjarER62ZkpW6+ukMb0asbVeXU5naFW1DHkao31mThwCLrJOcA5m8dBqk2YS3ldpPpA2ZqZSvWItTfoxuXoGndiwfP7CAnAIre0FqkSCtvaXqRM/Nn9PlyCv5uMNjP0OEi0CcPxlblEF6jbVzO2Tn68NU37oa5ucmImRzxVaCjZHvRTIUF+iJU9V/lt2Zr6PisA0ZkpV+9dfm8o62Fre4kyeR0s4CRnwNe//D4SAlLF8zhItAnVbGUu0QXK99WMrVMdoUHxZCdQOpoay0XXlK9X3V3OSB5OhlytsbBBWbkwlmq+yQuTXq1ZWotVq+KArBKt7aXKwC86M5Xq/VnnLbj+5nXh6397VWdfbXqkxi/sp0BCaApDXgoUUBGYW7NVzamqH7Bf3zWV6Y3bFwTdhYtM33YrBG3HnKv7j6rNb/J9NxmClD0OGtqknI84arD83RRnsMcMumlwwKUh4MRl+GBjs7OCuJYR8hJSEHbefB5CdVIP4PcREhBafp+HUB1o8V1Ltlo0YNIVY0ZG+rVov27QT4GE8isHvAQUTd606SGlYyjVGjdo33b7GMAXe720KJBC7nMR6r/MykNhSFkwd1HRxz/esRcqj6tDpG9fOikx4N+vsqY1pPWuOpI+3rGXK+OfPBoLNd+brLnUtKK+8NEhwL/cdRBr27E68eNdFxV9yqdf7YXK7riU9P0+R0UWPC9WXkKKYbBEyoyFjw4BngVK4zub1EezN2VL+vi5i4o+/umOvVQ5b+5o3+04KGgTvnm0FqraHV57doL01UsnJQb862ceUnXTNNSGb+GjQ0D4fMdBqt0doqJ9/MxFRZ/w6ZO9VNmeG6N9uOuhoU747Ku5WLeqsyP1u2c+OgSUb58cxNr9MTbi58+dlBgoGeB4sNWHA78JxcFKqvIp/wv6hZfmbN0635v3psVim5bWXNV+4AGt/c5MZXqkNXivi0wfXu9emfN1bwqzR0aEriVfzS7XgV/omMr00gt7k51MCcrGq6FMi7A77HFga+fNHXFbxOsi0SdsiKzMJbqkxXKPg0SbsDy+MpfoEsJaV+YSXaQmSedpNgFi8KzXhas/TrVI5SrgJGUglC+vi1Qf+L1VZqbD/A5qNue2QkXS0MLvIySABxdre7Zydy6K2F8EnGQMhD7D4yDTJrShHgeZNrF9CzixGezcGitzjqVIjVbPPB4idbyOLaz5qt0MHtR0bYWKxHz2+QgJCHm9tOcr98sF1BYt5CbnAI86eRyk2rRRi99JykAZtfhcpPqUlt3nItVHRk0aK1xjItTeJOTG5ngo97Ryt3aQaFPK29Jcoov8zqMZX8fegAopXQ25Wp/zE76kuDDmav7Z3ahGOU3l85Cpk09UBd00OPBTVSEvGQWpJntdZPqE2uxxkGkTeg6Pg0wbqOOOoUyL2GMEnEgM+yL/W22yg/dGkn2R7/o/0tKsyr05t/Z+7VNVVvY6zt05q7OiMMV0TadPr3fcxR15LM92f5m62plvZ7Nv+9saTbPPzt7vHjmCTrTf2dgrQm12RC7X7o12jhFL49nuztjbhjN7Kbe33A46c0OW1o+73G5FFkWfM1l52DWmvZwjqiEXlv5Pu/9zyfd3/Y3ou+Ml916YOkp7rFmqz3f7qu4uBLZlJJbFC0uW2s/Ovbb2kteY3sqWpfjLeKHtdCMzUGwjXiyKX7sbvKvS3kxdm2PeXfwa2DYeEEIuLP3fdq05nas6K3Z5UznF1T5w8n3/wMm5trHdCSpaQhzWpz/MbuIPsywMWVpPd0X2YOpdbZpzVTb5l7zI2zxWLIMuLP1nu4M5m/Jgyv3DLi//p18hGF4kiEBE/VgkP9qK3ZpvrX0Y4pwdE8XTb89S/mnXFZf0R88NWVrPd+duDLvLznYscGNqE4hXGTT9Diztn+f3C+9uLuU+dP//KB/0YRH8EmhSIJS0M4vp1+ny9eycR/Tnhiyt3+a3jMf11sYczWc/DNd5x9VmZiydp/befBvWZMvn7tImG7KQB0v92XRxN1CWvOYs3R+HJqHoPsPUMdGVLUvxJ6caNN28LKbpsWapPp+uik+Lro1Zmj9PP1Jac23M0vxleJ8iLbiwZKkNbwCkxeaGLK3fdk23vwaoLU05ej9eG5Sk3sqUpfd0fMMAkvRYs1Sf7fbdJZy73L6PYzWyRNsTdGHp/zgkFnlEZ9RdmrL0fhoSMZFrXge9pSlL7/mQyE3oktdBbGbHUvp5SKEOXPE6CLlmLJ1fxp8heMHroDQ3ZGn9OiRx7g8RRcQWliy134Y0rjUrorey5Sj+9MOu6dfo+ilRWG9pyVJ7ek0DfeFtVE94smie2ZF5Oc67+uQjzY7fnqX849BiIqorW5biT7v766osouq1Zyk/t4+lfLHPEaVVV7YsxZ/7t7oQwaUpS++X7oU7u6+BSHqsWaq/rta3IqJrY5bmb7OnpWJfubDkqD33vQ5n16mmkhkGAJxZTE+72mjjGA+Rh1pHCI81S/XZ+DHOdC8i6zNn6f64O5fFbp8V+0uRyvCVLUvxJ/cFtYjazI6lNL3V5ixSB14eHlWDPiyCn3f2ocN+DjSV0oi834Gl/cvuJmva72+q+mtW28J5Sv/CQR8Wwa+zxZmI7NyQpTUsBMG/s9eeo/zzD7t9nTW3u9rs7VglMrtYmbL0ntrt0eJ7W07sjmXeVnU0dwMOLO1n3ctz9oaRXXtbV619dTYm7bVnKf84Tn8DTxSOijM7ltJPYwpoWQp5sNSdZSG7KJXVeROrsX57lvLP41f0T1lGOr2VKUvvF+AZyFFwZctSHBaIzvaaaf9Li6PewpKl9lufBjKUWdtyFH/5YXrZtq2z/V20bvqsWapPp7dPu+FXVmbFQ5vvI/kb9mERPJvG232yUF8bdWNx/Oi+irs7mbaO54LXnqX8UzcIzxubhdhgLujC0n++G9ZE+ipjn1JuGqQQxh1ZLD/vbk3WnrIzVBI91izVX5LvmI6KvwheMB3Vfh1n0aio34Gl/Zu7bmAjpU6mje7phDw46r/+YAfIttlAlH3WLNWnu31dNc33+0vbtVldeE0dW8EOurD0n9lFjGO325DYf1+ZsvR+3Jm6rurdrb1PL1qDV6YsvZ9mu5yJdUqfNUv1+S473Nu297Brq3O0nVjbshR/3u0vTVudvC85R9SjfiySX8YU3ay0U19THmL5EPVjkfw6prgYAsUogj4sgt92p0vR5t8PD0wPA+rovnzYh0Pw2w+7LP/+XH01tV1G8r03HkYBnFlM7u4fFusVdGHpP9sdsjbb7auiGBbkz/nZFHkZIwg7sRh+3BXFCauja1uW4k/ufO6ArRpFnFgMz+0ALC9tH3Lf7IYVuF1t251IlYi6kTjMt8zu+trg5aPpe88ugNYcPOqD8W5tzNN8trvJ66a9LgPGJJe2PMUfd5fyYGp7wVIXxBRedL4KB1x4+j+llumusj/x1+muas+Baf9VcGXM0/x5l+Wp1vSquTLmaf7SNQdAps4M6Wc5xtCsv2WHg/vgfOgYx2i/W9jLlOfPMyLacw+ZuvNeHyLtmMt0pwtVENnJWqbqXkGA6Lr2QuXZEVlIe+YhU3ePWSHarr1AeW+fmO4vFg+eybrKusYSzVuzv4M1HWOJZnU65d3z1t0pxnFXMy3v95OT3JvuSoKLd0fFh3B1EGtfL9EHpa/2YuWXdo5ZUHN/4SWnKKrGfDBlaN/Oh+C4yPVrY8tSN6pB9R0Xsf5wofS7qgGq39JDU/1l5R2BJgislxZF/ygnjaH30SWg58TkJybpi1V30zraGrkuYv3PdZbbxbVPbeU96ejRd11U9Qk/xNJNjeNzdhc8pxxgsC6q+ox8GN0kHE4z111RlEZYegjUD5fT+cXRXuZaNl/Dt/pctRf2QuXXdqEZ0uwshWr/Hth4X4n9O3nHfaX10eyrOt3ZT6ZCvc/ZF38w4Uqus5SqmW/pmjIaCrS6rdS2u+A4KefYihX/1yUr27xN9wxzc4Hu0bSkuf7CXqh8PNbmmLXm8LnOAqfDV+oLHyFBP9LHfumFvUx5vCDt8xilh8ivnIQM8OTENZZponPRyVSo180m0N93shaqVsXl5N94Wkn2plI9uxmPyVlLsVqLtMSTqUzvFTI6GeyESuYmuxSUn2/uoaSO/pgzB5k2cd115SFTp6y7zs1luu/sgYMWXB5Y2MuUnbejX+X9kxgfygKaCkS9t6D6YGr7BkHmP4CIsU1pCAnz8tKa5lNe7o37a/SrNumRbzoJIV8gqngFQY4qXir9w3yj9KaOuUz3j/pg6t+ryntuc6l6NZZpDsuBeEWdOQi1h+DWbmHaDIUHYvA56rC8rC5la2sYA2fpq0M0VnkG0MJVh+f1zY3p8h0e+/k9lWjsEWZargwuevoPf9ybusjSy34BPyWSps1PWcupRwtXHZ6/58db07idFqEbTiayISOtUwaTUuXlZ+QWuSfNsg3zqdteIE3G4ylsQMcYoyLpbEsq+73DqW1AzWgOff4bkJH7z7X3BlR2BaxpsxOpN/OnoEP3trw3TWsO1Nrh+mmTXPxH4dIoF+q5uBDLO3NvwhcQ+yB6Dx11p5dj1K+1tzoVozXdaoyhMbjYdlThpk5tk5a+6kSs9sjnr0M2BC4wRvxzT1UaUu0bfZQI6BVNtXZN1YGIMHjpUPyZ5TasndEWzj1lNB+zr4Rlq8laqIpH2M6shaqX0t6W8La8qSDZyVymew3gw1fMFi5C/f5duVdZC2W3Yy7UJYSzzM2luoRI6oW9UJkWSb3yUFJvs/YC1ee5h1C9OzIHqXaWMjVSF6/Un3+u2qzrhrqNaWh3Y+GioD/0QUSEmZeMghSvv7AXKN9mzT8q2s7D2kWqT23JfU4yhi7OBt3yX9gLlPt7m/u9kw9I9PjSQVH7j8AdalH9P8g3qfkYblpTvy7T1W5urqZL+XLHRaw/Rjp9qKtjbYDgeb+bnMPc2HcU7TlQFGHy0FQn/BALLznFuK784j7LCyjgM+S4AQslY7zOYqZXVXl97xQkcV1U9Qm5sXRT4bAvrxL0rbmaLvHbRxcV/X7IQVDvHRS1iV8/OYkZsGh6x1au+A04SDSZivVmGweg8MxHl4DwU6/8xCRvDwVlPDaaq+kSPt51Ees7i7WgvOOhqU7IgIWXmMI5GUgdC/hcN+EhZE/IXYurr3XMnFo4b8REzy1PAnK26fZCFGbyEKt/DLxB4ZH9SH6HIqBHyPfRXKw7rgoQWm/XRVWf8P1LNzkHtpLiGitpEmcJcydlBsovsHJUYiHMFiYHRW1yHqjNGUjnwNcuqvrkXJjclDjIBDraw1bEy+5oNao/c1JmoOTDylHO8lDuUfWHcq+iR/niwVys+8/oRdoe5X8yb9P2aJPWCZTWCPpkXlb2ljBgX9TnpMRA+LUV1yf6pIgryXMnIQPxcN3aRahPOV63sBcqvzenyv+SxUq0NxXqEcI85uZCXVIAwNJBqk0LAVi7CPVJ27NLB4G2ffmkzg+GdIGBz0mBgVjD/W4KHJSa7vFRICDUwLWLgj6pJvqcNBhoNdLvpsBBqpk+JwFDbbID2PpPpiK9U3VvYMXJWKJ5Kd+W76v9HRoesXQQaDfGXowNfq9rLNKEr0ZoNG62aOCbLRqFmy0a076rjkdgeH61lKlRoiQbrSjJhhYl2WhFSTa3lxbaPBkNJVptdf4UeaN5rucYCzSHtwPSOToaCrS+Znn7pqo/muyQ/j7XWKRZn9C4bcdWoljnLdqgO7Z0xe5puZtsb/62unw2vjZ0ddwFHDdg6Rbf8n10/SLJ5SYiZuxW5m2HVmd7NKtmPiKCIeqMoL/wEKlfbwqGC8rCQ1OdWDQi3hKqcZ/g0/VVMHvXSXC/ZQIKOIpYplA4vIB4nEQMq6gz2u8U91chQwvvwkFRm5klyiV3ShYuK0sXFf3X95GTYh7xzl5FmV5pA54SmsUl5Gjp9Lqpc9BKajIJEZ9zUzqcSSsfXQJi9kT9RWTd5BMsxI6xSLPO23yfFV2QIzEjQq4ynuEGH0R/MJXq/b0b9mOCva1E0Uay4o21ay1R/Xv/0Ce5rfT7iUjc8E48I7xuahxg77X2USOg/zIRbwnV236bIQ0wGCpovcyKwj4jFpylr0SvHgrqH+zzqLh0b66gG1/jXulyV7fXuolVprUye6Vpoe2Z1X/0Py7v4fA7y5ny9gHscOb2MuX5leCx5VRXf+0lo1hMp8EfY+0lovg9P4DfP1jK1FJ3lrl6/NvJfIqUTF476TCgOe3aC5WrSPTQTLJiRQ45Wi+dB8jgVn3tJGSwKYHZPBnLNJ1H0PDvXjnJGMZy+nvWAGPpub1IeTgxgw8llx4i9VeX0zmxleooO9Zi1bdlf88fKDuai3RfR9/6cBRfM1/5cLWGQBNEbTBV0aOMRlc+KgRwHZ47qGjDo1JpHNBM2+wv3bAerkhLF5H+m9hjJo7oG977JUslSgGbO8i14aLlWMtV4UIliutyVIdlC2ysNRmLNN9VwZgPR+xdxYj3mKug05XRVKoXCS+Zq7GiSxyt91l9173BcDmd/zjb2o2UVI+XCsXnrD4apC2aO8i0u3AAQs8+dxBqt7fVAW+CZ/Yi5fKmYqw/e91EHG5C8K+/dlJj+M82D99AGUDofEQE1/cvwEnMzF6k/CGrG/OiPuKTmIWHjvpH01wK5KdfeEjV7VFlTNVaaqiBv7BjraHav9KLr4X43DQ4xr0EMsnCUcZi6iZvWnDW7FirqI7LPIQeJ+SqwdMvR9Bh5n4aJG/tv9xnBZ1l6alB86460kEcJw2G9yZrLjXjx1k46rAQh0lePw0St+ul8/i8NaiGdooOtHDUYPlo7J2adJS5nwpJ3twxOBwvDYpxD4tOsvRUoekD9Bkwc0cVli5on4Ey81MhsQcHGCCumw5HZbfaOCQzRx2WfheYAzP3lNEM17sPt/2/yw4HaHnC66dC8in/y7z4/BGfs/j81Eje5N/MYXrHgkXlTUON8D9MUTywuBxPGc3lS5HvSTt1SxcF/b7ZAicecw+Ret+xomsLjrVQ9VzVLW1lb+WjQACv67jmMt3IXV2uHuueroXOcFBlqDOg6txJzEDZ3pjZy5XtlrZdj0GVR3sdZULBXriI9eHmdDIWa340/2O6+DB4vczjJaaAt5YkJ/aXmoSWe2YvVk7fA7SQltwDFNR+Q1d/o6n/IXsoqix4wXwQYvCTkVwIu9STsVQz9STPXJT/Is9a9SMYg+Gai3QXL0GMsZ9YdQs7azL1R2RYRFdXTR4WiZiBvHSguWYw5KY9jAN+/cxBQftVi9TGq62C4ri0TFF2fBQIKFktz+W/Ire+zuT+Yt31utJ6mRX7S5G1w4z3xeePsPraVZ8H3CMK+uoTLRYKuHCLZPQ5u4UDLl3nrMMEz4sWHgrq9CKtWZJlxWWrUsIpHLplop+QUH6Vq4eaOqlZmVzU9LmlwuutRkUrFY6PjIC48aC349ClBC8jONZC1W6f4jpgQMuix02Vox+lF+G3AyMwV19douhThjEc5muGEZY/zqZksfSOqizXSQ0D5+qrQYQuqLvmQl34HKfKCc7r9d2UcczSR4XgQ/mOoP2hfKeiCi9zzh1UtOFVTul9nB7tz/n+rv+UfqOAQLF0VeahtdJBb20qvKX2uyrzvIUutwg4KrMQeg6/qzIPrfcIeitTDU/Xs5gGXxHR5zrLCzuqbaszJTzW66dC8jm7MxySmZ+IZHhcgND3LTwU1PtfGNce7BWU4f5HdhPzWpfa9/rchBzXe0Hh2dHKR0Jg3+8hXw7jcZIwOI/y4cesPU5KDOBtPUsPJXXyjxH2FRGZpsmOBmVwrGWqbZ3v7WcAFcExlmgOQcngr+5aK6jOXlqkHVBLpaBEh16jt3JR1Wdnje4derOE0ZbK46TAsHh1kpVBkTTUCInlx3VSZhBk0SaliHpHnddNgYPc4/j9RCTT46WE/Fg7KTHQcyToKyIa3toar4EmZE3AU4NmfAeNyjL3k5B08Y2wvmstVQUHCVdTqd41nJHWdgVdpTzkiuFxkjBcl0TAH2Jur6FMuwvK56VBQf4dAo4ilm6f4/95Coh3lrunCmrPYLVncjVUS650XSym1fOIswKTXS0mFPW1kxIDL1NWngo03SgQ20ReesjV7bkgvLZZa40aZ+N8qYXA9dEh4JSApZ+cxO4RUPPC9dEh4NWHtaechtgXrnzkBNf+nZMlXmcFpodyT2kjRnsd5a7dY+WGz1mHyZY9LtLSV0Q0rNujg0fXXEOXPmrzO4pYHso9+v2jqVSP/t1rJwmD3b4Ev/lqKtJbbVQCwisfXQJa/Yv7a5BNW6c4zeSjS8DLG7+/hGw4SmawM6autYJqXpWMW/IizhKmca3odC5MS5iE+P00SKgEWsrkttPrpsFRnam54PqQCM7Z/i47muZvN3VVtt3Dyd4bdEe7XWe36+14Ssc6O98CSp2dSOlUlccKUOrsREpVUWSnDJDqDUVa57w0bQNo9YYirSY/mLt8fweojaZCPTsaRT5usGSp1d1R0r+Nxh6V3mI3WLBSH5+HjaV/tWEpXBuBmMRkRNJo+vFwbpq/Zed69+yHZz95RCar3WglVPkZUvmZq3Iwe+v/PK4yWnFVbswX6+9bQXJURiuhSiLHRiuuyv9kJaAyWnFVThny649WXJVq3wK/y2jFVrk39X1ufNGNrspgRR8vtA/n/vHjqvxHFr7u3prtJjOuTmSA3CuwxsRd2tBbNp2I8BWbQc0+SzO9eZS4e2LQ9fqICK7fggMsXUT6TowMTrB20mDo4yvIFDM3EYezgYFTrJ0UGOziGxXB8VEgGF5CpULM3UQc7lIIjuHxUqGwiw50CseLS3HZ35k22bJPZkyd7rmsN3lh3gyD0Kjcylqq+h/mIdm3LI3Zmqn7AQc1/p2Ajs54TwegNZpy9bqXg19W5U0ePGLSqzmGIq0mvCvqCDWc3dCZSjD2YKbCiDuYqfwIqfwoVPHNm9YqtHnTWsU3o1mr0GY0axXf+HytQhufr1V+gVR+Ear8Cqn8KlT5DVL5TaiSaNgGFXa7Nqh8gVS+yFQQDbaC3UJA+vSZJVetnl43jos5hkytV3lzztr9baJ5Hs3Y7fOYAKTC1air85u8btrUx4x2/K8ZU8B0mCr9A4pv4wVuNGJrXE6J9C8nbtrD84DJEalryNTqXo2DBlAzS4la8rOuVlyVYcCcKM6jGbs0X3Xig6erDnf0BE0XhLOEfzP9Ffzh+0k7lcmMq1NUX2zoYHIE7Roytd6OJwTeVcd8/6Ffnv9kFwHDFwR12jFHLkvyCHavLDhx3evY46vk7w04cRmGRiI5/3MNhVrwtNrnoKCNTK499lzl/lL7F8DnupZcNe/dfnFZr4tMH5fVUIsf23fVuCf2B7XFxUoJxYU1X7UPvhsbuvglAaO2z0dKMF2/galP9lzlPn6D3EYG3Zgc/2EeUos71oQ9OrHOydSZab+rjsnGfbBhKowPwyYHi64hV6t/ZS35RY4dW8k+ogYIjWZsne7Kgo9V+PqiQehqJ1P6XFWFnVEjaqMtU9ENw0vm5NJYQTMaqrYSZUao9aqJKeY/2DNM4A3TTkH0eqmr9M7cJzLNNeRqTQeV++szPj+c4+Xf68FVL4t+sSyuOFoxVfo3hZI/3GTG1rFP+CRb38mMrdO0VW0+ldm5ua3iY4CFLVcxb6LPM/dSg5FA4312Tkq8z84ChfSvMxgJNK4nrZNCV0uuWv8IRvqnmeyYSuPZqKSUa8jVMlm9v/1kWnuzXHw8Njdl63XvRKQ/bbJjK0ErRp+kK0bTkc+4ztVMpAMthc5NRXruWAHZJwl6iSi6X+jz5ZwYLi6NZZr2TF4i6N5VdczZuna6nmw1JzOujs2gdIEdrdgq3VIAoHO1kyklNlSuVmyVfoLfL1Ulh25rc6Hu8LqQyZpEZ+dzkGp3T+sQpCd7qXJ6yDo3FevZ9W2s3ntdhPpAdZkMhVrplsYxFGrZ1uSSGF/MTLl6D+UeraEzU6be5xfIVt5gxV4r+wyspH8WraEP3i/bKvjisqti7WRKwPr1zJKrxt1jiznqsPTv/tJRXD82yRg/nhAezfg6NhQ2XaomO66SfUp4fC0lrbe05qqOEQ5xtdFKqoLUmbktX9HsL11F79+4hIppwInL0IVZxBU7E1H6SJY6hlwtzq53yEnOgLc8fh82QXVMV83BiKsx7rfEboHphVxLDbX0py2t2ard/kvqLalBc2arowh86cqeq+wuJXQP66TFvS5c/WHdP644GLE1TN3kTfRys0FnMlTQSufkwliqOY4m8HIU8xTSjAcuiChrNyHHuExHJvE5ClneVUcyxsJHSDDsYZMpPH5iElqTF3QTcritGZkm5CxkGto7Mo7HT0jSbySSQdZuUo68uaNTLJyEDON2EJnD5yhlmb8HjqOs/aQkw2YIFWTlJuVw3/PEMZZeYop+FZzOsfITk/TLfQyUtSOXpW8HwHHlwpivaWMS0oO9yU6uhHyca8tWzJu71FqoteGvhFrvdPqS1JElgcmOqzQ0dC8O2bk1id9mbitUxOubYlvc71mmSkZvxS8bvT+iIVNASohC7PXnrvHHSohjKVIjlA6tnsl9NReRnVvzVfteJFkmBztBqUw85jvXkapAZVP4kmyvyItTD7tpcOArmyEvGQWS+7J3FDu1Pok+JDQq5hqKtJJ7xZMZTcecqr99Gfa3wpf8WbPdaMa54a/X6XaZUiqdEVvDDPsvCZXRjK1T5PcpDWvCTr86t/kp/6tbOUjouKZsvdQdlp0Sfn/ls2vqtnROgQenyk50+6IdjzF4+mwi7DeiZ0P2wWdIaDLwpPkv352z2t6APcJMIs+fTqD7qmza+rJ3u8CoypO5R0TR8XS/8IdnP13VG19QSFx+dCl7F5n+zerodVy8s1dRztYX58WlewcV7bFJA5Udc7Lusx9+mgp0Xuao5mAq02vmb/okytVorKH5zn3WHtEtegcN7d9pv27vpPYbfxk3Ta5vTKKlbHTMHEcZy9n75iXIMzifO2d1ptkbrjSiomoaRZ5hvjh/tD4BYkPxHR85gbWCa4x1yEYHufbbA/4L5OUxPyjkeu09RBIXtz614yMjOOTNuUJHFk8ma7rq859nI5pu7jUWnsV7ENMl0Q6Hx4E23PH0uzzFJxma976PjABZcyeQnA5l/5gjVZEAtr/U1v1D7c5qaWhDEuchCUW4c1kwmXpPTRST3fVdDJfIZHfnMQFFsNP0TDyT7JR9O0wpaOZZ1eSCeui4a0LZYmovs+VSWf+q99fG6u5zFRUym0qb3ZktSlqXuL341g5rJIBNW52LPg1FvKrOj7m9I1glJ8fUNs3RGbIwZ2fA2+TwdTT4gpur1xQy7bLZXwzNBhv8tbGah9OXituHXZ0noLY5fJ833+flranzthuWCwF9SzNEzNBSjTqs8V0OSIMdk9gedr3oRCP1L0KpY65WiWiU3hUF/VLaB8xwx869+2LkrA5pT+Y3bXY6Myld/y0xqzYrXpdtnRtuV9MlYa5JbA07RPaJaM9TGhvizvpzwRhz1pevxpobVS9R5doWsKxabjM6uOrCAasd3ucWUfTEc4voKkjrHlNlaz8ZkmEMi2aZEIDM6a36GpG7KoIA8tt1T1Z623hVXHaHvqYlbBcwYZnj4zWqZ6ysCyoZJ3twadubTGjReHkNHRw76+Y0d6znyWXfuE8VVrCsu8aVLvEiwOwluTWubHkOgmUPozy0smU7GFew8BSAli4+wejsBagAuGwRCsHWWvJbf4Dq8h/5UxR/CcVlQfJnKFXd+GxId6wnmRx7hnuhibI+NHuSHKD2Tph12xzG5p6npeFu9EGI/E0/D6lwAxABlmwGronFG4NgMfhganv6KTtqjFLPZXF209sQW3N4Uj5G8zZCd3eoKVLvCyxshI/9slKZ0Z7LYl9tOaE9l4rdx7ncvvOYmjjV4nxt6x6jVM8/Qa1wz79h6zJ+/Qiton7F37jET7mv2oxPuf8Yrfn1IxRr7/ULNq/ETrevWYud/v8RqvHyI7Tq8fIrNq7Izmco1WTnA7atyu4voFmX3V/gESqz8xl6tdn5hs2rsyTOxrMKKo25wRpQbvyNr+EUxeIguKKo1zWxPAIWgWbtgq5hVzuiujlbm6xVKrlDWsoFYbV5az7Y59qW1zL7sWe2gq1ZaONrLUbY55p/lXxbywdD3MWCkAibVh4k6h4VhISGcnl4KEcJMZiDe4s3zDF46SAQWk8PCrWxhJDAXW8PDmWTG0JB4wU8LKTwgBDMrH27aU39ujwArdvCcsu2zScFtmzL75G1a34QQqsG4oBtmheH0qKBOEh75mWBWzMQBKi1Xg60zoIYYHvmRaG0ZiDO19vo7N2LMfhoyCPtl5cBbr3CILO2697Y23h+vwyvYERwFpZbHhz0SYEnBpffIyuNXhBKaURx4osYfgxgmQKUNzc3pu/tgIUtL8w1BXgNC0SLb2B6WYDdSlQc2Zr0M8D7kCAKtunoZSHsMKL5kg5w8ucKGM2EYnBLq3ohhUNjwjh4/AsFCghyCSOhkSwgED2QyIvGjBriQHJzjxUPBAJi65ZeLMIiJdxAplckA+0juPyI5kpqOuTPENbhPxQJmx75wQTH/dA+H5su+Xt7wQE/EA+ZPnnZ2Ef6QDBgOuXl4h7iQ0tbOqLbX9KYx/ZALGSe4+ViH9RDwbAgRD+b4GgeBQ8INwzzcQ/jcfpJzhhMfPyOVDF41WIjpMQekxeIc8QujBNbAgAP1UW8tjtNlxKFjtHFvpdzfi4JlT5rwkBitKyCo3IMQHpHyT8cx8Cjjhi5x+E4aKyRo+wAHAOTN4KUHXnj5CZ5ZMQ/5MbA461EysIjOJikFUoPHn21EiqDgpVLT0mUrmIqHn9Jt92Ecy9cTPoIVHjShQFKX4zkH7Pk4GkUzC3LI3vxUnyUkgtLX5YTHp5kgIoXO9WOS0rhNXJbY0FU+2QkDXqrykfZ3mIdzONAMba9JEfxGIis7TDR4TvejwuFeCM/Mx7TzQRV6aYIB+wEmKlDCzAndEqBB5o4loAgbjRkhk7PIXzbjT1p5+UILdGmpZN2Qo5KvVlZRc/EEYC3Krm0U3CUHN60dSWceyMwb1f9iCfdKL3slhWQeraNzL1VFcRPs1GQN6qE1PNrpFzeshqSTqxRqLeriLSNIt4pJM6KKicERXRmjtXqkkNTBKfkOCuqwCGu9LIqenoLA/xxes1s9fbRfVbn9p2cEW40oO32uTuPYwr2JdK8afN98746mMiEOOAgOUYxvDEVa3Vjqtc3p5JtbehjY8uv/RvmkXYqitYl0VyTUIT7mpcvq0vJzbOvebkf3BWh7JKShMr6b4D1NS8/ZrFmPJVVdZZsxIlI2f3xQ2zdKUqU3R/Tq06cws5H6ncYtKGa9vDK3HObhfZw6Jw1gW6z+mw+2jabS9WlUA8paJaosrxkRf6XOXwSQ05pbYa7N3Wb5WX7IOG8JrIBoPl2NvvWHP7LZHXx8NG0l7rkdgNjWg9dWvU1LeUGxU5yRY2Kndhq1+Hs/vgmKwRNS3Z/vMmKDRqXqm7zshJV5j6JLapHVpyyWlQ3uhQ2QKvNvro39cObbPbMLo1uTOQmA17eZdXcrNw/iKrrkIBuVXh1qRNRfam6cJhSUEQ7mUOelfxK2vtv0Xi8rMrG7C82JOTPXECY3R/3U1Jf861h7X6tFq0dF2+B+2deygvk17zcpkxm90ebiXJCm31bVptPrTl/yv/iTjD6RJrWnJs+EUXAL5cHU3+oTdNcai5fl8Z5SkOzDzZFIebrE9kGsPv2T21tymN7K8m/ZkpDPf+EfH0i2wCOv8rb05esyMpYfGWUcUwnd9LRnP3WpoxEp8anvoOvNo7wV+3S2OZH7ZJ+WZU3+cHwf9Iulb2bigxxtqxpbqrafGqzuk1fCeMx3vBWmJAaFsvu+zBRCHsYB49cJ0BhAetBKEKcOgEKOOgYJEKviiHgpE9tBGnAwxoEGCw2PghECIknQMVvjgnCAJfHECCA0z9BEvTQTxzH3SqqTXZn7p1sWe0VjRaCzaIxiRf3WV7YxLGDanG/zY6qAbLIYbXEVzOOqyFgyYMuPCyk0CLZhpZfFiTQAAKMaFvIQkz28gAg1uHz8LC+H4EkDANYqOCIAEClDA54uZo8xgblKHaQjYcIdtcAJqXnZqECp3IQTjScjQmZPNkEMWJnmwT5iBxvgXMTPtgiAE4faYFxwcMsPFjyISIEm3eMSOEDdHKdc5RIAV7eVlCPEzHHWNDpUmiYhZ8vFaCmT5jCrOAZU2a7Ed1NQVqL9BYKDww4rAXxoce1eJjQgS2EEz+yxf6hkbhm8CeHI5r5sEojGfzolgw1EZVPYUXi8dmw8Uh8EBOIwWcDqjTy8DEuaeOkVUzJR7lUwDUKLf04lxRdoQhTjnSJc1qr2aUf65Ki69RF4tEucUesVCcZx7t00BVqJeeIlxheXi9px7zkua1UMzlHvcTwKnWTfNyLhx0/8IWAAke+mOuPyKEvaAkSPvbFbZWTB7+w1hg7+sVcKk0f/oLWScHjXzCkd8dtuD4yTepcWMnbU0u9DOFTwh6GWH6MzhK2i8FZs07crg2tOcyu1cYXGVIXexNWFeYXe1OXEeIgtHUDl4SxUJDIE3w5fpYjxPX3BARhzDajoI7MAAzSivQKhr70DCAR1phXQNTFZMIFyeycEi7WExCZOSdajk/c3Ewaccxub6YPMVLNIT6mmLeGxEFEIkfQjf9ZZnAeOUCBaFv9Myz+EwcgHHFz34UTPHAAwiFhfz4y7vMGIBYh+sWlYj5ugJYyPPRhfYc7+WkDEIoSzORScR82QLFo+38zMv6zBhQ4wo7fio75qAGnP2SMsaRPGpCqA6sybAMErlq4OIznDMIwkUkrMUY0cM3KpgGiwXuTCdGh+K0zUGhoCAmPGyPcM01uRxUiQnE8cocojwUlXMREGw9Ko0AJYJxxoU78Jw7JGh/qRH4ScpI69pHHfBKusOKslulEexIuAqMu28hDKIn3mZOGGgpBqEQ8xuKFWmwnEZW8iKEU1cm8oVwlZ1WWiLYM5oTAHynHhVWNHcNJGA9xJnA60ZtESPJETiluk3TVtaQloG6mqIdrpi8B1gfkbLioRGmSflZSRELkB6aHIdAwNbp3RmQmHRKNpUlRkgJoSJhg1EwEkBIqQ0KTN9f0OEzWtekaxZEfgclGFhdOQewlB1paVFlRl6zcVWlGBfGWHGiF2saNtORdk65Q6yQxlnxoab0TRVeysIU1jxlXycthjboniqhkYctrHz+WEgcmbUnIoigJa3mMgAaV+ElKK0sNdFCInCQsOBLCJoOrjdSYySheYO8pee3T0nTLS5+8WuS1f5ULnwIorHV+lcue/EC8NX35RU9+GviaJxTlkLUZmWJwUgEgbxxwr3VCgUjbfJxLr1AQ2nYo61qnCMqzH3775elzz81Or9wS06WzhLEWCrc7vb430RccZnaSzXlCPk9a9Ezuv0facjsEtGY7Lk9rs10IRoMdR8G3OV0M4s5mFIGwT+ggULcGowjEZtHB4LSJ8dwgTFrd7KBOTtMQpE2yJQp9PywNRNj6WuJQd7miMPytRAdLuHuIA/JyTbRHGIUj7rO5fQBjay2NQthNW7JQN9DwH43eALB3SOP1rv/C19/snfSG2EsMzmZyVgCCdhZdCHwzMSoMLmw4ypS1jPg3E9YG3C+nLgfEBwqkNRR3rEBfNomCEGYMDgV1urBE8I6Z8ffzAh6CcbRNrU28nxdTfdIlgLyfF/raaPtuE0ea1PC7YmZMQgg3uy+3ujPT4zXry3Ltn4lzqdXEzaYxvfr4IXsoquwQmMJ5bfVWpFCxJ7tdZ4TNcPzp9EnA0wwqGjrh4MB5R/9EQNI8gAXpbrBQ4ZAtFQ7UaupGBIMncSy4wPCcykgcoLNRVwN1Dig8VOeVwbI13wTFcHTXR1uNCohs8PgAhXv266JP+D1ztnQHjRmfNaC1/c+fPnN/m6atL7PX2aIqT+Ye6a/uPsDt+X6aPvFrlrdvqvpt6dSzuLr1uKnqvASrVEy9KvsHe+2saTikhEFUZd+x2PnSfnSUsvxRH0z9IS+PMERlPc69h05OdAEErKzoQgXU8mKYXI/ROSSeYfo4BuToEr3rHi3m8PTPFSvRfK6zvMjLo237iTjt4GpbfHUe220yeWxXqcaz2AuGYb6Mfmoky4fcYZSsd/xyeZCw+GYZ18xJTzKWplvOMbxa9CnGKhnxDCMKRplgENHA+UUMjzy9ICKW5us4/JRglubrOADdEnUa1Athp2H9ZrjAFCkGSZohUctlcjgfLZKE0TwRDBjMx8hIY/k0mr/xdcYR6eZ3bbxlAxxQozfBnoTEjXACjtIMk/GGSM3P1Ty+lgo5JNNWWFgtCzWx3BMHhNd76FhYV5bAo3Zm9B863egmfmJKs0vHg1emEpSMpSkeLLA2BaCSFqcYVSbVnaVqDd6hkeGALi1OR+rUELxotzaMrtCObWb+CF3bWo/duc2T0urewoCMDo6CSO3igqD8To6Ci3VzQUhqR0dCI3V1YURmZ0f60eHuLvxzMzo8EiK1ywuT8js9MjDe7cVxOR0frRqBXV+kJpE7Pwog3v0FCTkdYALR3wU6K+jpDnBtvGX3F1Cjd36ehMRdXwKO0vGR8RL9SBwN7kXIWEDDHEcjNcv0XMO6uETuUTs4ei6uIiLJ2QgHRfIBoc4NwCR2bTxYoGMDUEndGhnUGyhM5STFDPMxV0HELE44npj3w5f8rgWJouVBra/lIbPhl/KwEH0X81AZKdfyMDvA1Agw1Qfi4z8yHDD6i9ORxn4IXmzkZ3sadODn2G4/7luKcYd9bjpKo74QGn3Qh8NBY74AGHHIh0PBI74AGGPAR4CDB1IhOsY4iohHGEbFIFmjKCIqPIiKgTLGUARMoMsPwZF6fAIS3uGHyDj9PQ5I6e4DhLzentLyYZ19sPGj9vU4GtzVB9gYPX0ULtbRf+gPSKF9/dx8++7eo8ft8RdJKXX6EUB6v09ChHvZMCKjoyUhktZWwpjM1RVabsLDgkh2MkYGdEjC4CCByhof0IHhIUIClzFKoMECA4UIImmsQAPDhwsRPs6IgYRJGTSEOXnjBhIoaVEtTMpcVqOjwgtrCVbG0hqtuQeHZJGWnjwqIwHCA7MwIWNslkL0D8/cUxHp0ZnHesvBWUiOPjbzpSQemqXwKCMzOuAQNfLpNr+JlbQE5JBKM6SyBSg4PEuAkkdndFBCZH4ClhWcTwdu4eD8BC8nOJ9RYtNTiVRppcwkGCU12bOkCimhY6HjAf1Kgo/UrUCA8V6lm0TAvYpj/Ri9ylKO36u4Kan1KiE8Tq+CAxJ7lQAku1fBQYm9SgCU3avgoKRDVAlc5jkqOjS9ZwkQPw4uoWcJlVhOz0IorXDPEiqojJ4FxyP0LAE+Vs8SBXQuE3qZ7W+nMri8S6j7K/EqIeeKqZdZuTfFp/HqrMWR49V1Sl5zQXeV7eMXcob1nlxdYznu/7xQMe2MY1eURnB652TPRAKK3kEXYUkvk9EwgBetYjToohgJCnrFKkKFL4GRsFIX/kaIPEOv9JvJNDjoOuAYYuhWYGVQ7Gr3CGjwendlUODK9wil/9p3ZcT0NYYRQm/Hpl0qkzdDx0qkb0KgDAjcJB4h9F8oro0I3XUbowyts28Bmr4JN0XqXWVXRiXckxvBjV+Xu0lVElSkLeHiF9tG0Fb328rBkkPg2WMwNOjVgzS8oXE3IRAqPxkSIQ9vkKd6cmqLvcbjDZeh92uZbbYnC8EHIdiozA56TQrOQtmgrLGt53krZImRD8kf43pQ8Vcw2MCCse4amPCsET+HeeM1T+5ii7lsUOZ83vOgmGBur/ciONpe4RETMmDmKE72RjgbWTqakz8Vz0anLwNxnjrn43GXhwTPnrNh+ctGkifQJT898oooXgjgN0RFyGp1jPA0uhg48RYukRi5zUSCHH8HF4cFDihJMLV6Nfj5dIVmTLH4kp9S18JXKsz0Z9UVPkCnaFOeWNfIdcVmmv7cusIHqNVU4tPrGl25Xo1lPMOu9gE6dZbzJLvGJ6jUWtrz7Co5r1dvOU+1a3yCVs0lP9vOhmcsBbOecOcvHaSfIUfXDsDHyCmoy7DDl1l5KEzwBd/pz8Q4Ea/MW5sR95k/xnBuIghL6S5V6GP6kzEpK9stA1L8YmA0yvqrQuXPWkZXrgIcnWN6pQoGia89BCCAxQYcAFldCHHAywkwDrZ+EOAhLBjAQMlF+QALL9oEx8KW4UNwgjgTGBFceA8gSiJMYEQkvCTAx44tgeGAfasAGzeqBC996S2KUMljxpPAaMjGZICNHUmCw2EbESE+QQwJDRHYeogxcqNHYEjKZkMAVBw3Qqws3KqyGVZijhCA4sSKxJDig1IwSiTqt12ISFoWig+JfzUnOAQAYwxhtcJCkGxDY0JYkJyOlR8NwkKkjzq5cSA8POboUxYBwkLljkJlsR+8XGWMqvhRHyxExrzZs2TDnEMrhnogbRAhzoOPyhlpCSM8WLCiEZdCbAcLmri4worq4IGxFl0k8RwsTOZijCiSg/tDQ/sM2E+Oby6wYXVqESV6Q4Sa2jkjsELbZVzYxB4ZholsjHEBVXomPFZD2DhpFVN6lIYGuEahZcRnCNEVijApMkOa01rNLiMmQ4iuUxep0RjSjlipTnLiMFTQFWolKwJDCi+vl8TYC3FuK9VMVtSFFF6lbtLjLVjY1IVUXqQFb7oOhFkgE3Y0xgKFXEU+VMXlVL6sypv86I97cAwEUQ9dKu+rg4nNCycjwdLxnXnAJZ701tGsddADkkX2hfJdT0Z7oexNVZ+yWAFb6l4dhMJ588+8yb8Uscq31M6b+6sPXX5dbG0Zj11BNrMQFKccTX64MCe9ujbzTNwx5TZwkDzSoMUB3Pt5qrJps3IqYqsregYDQcNQ522+z4rXdV3V4KZTyGW7/aaoIrTVFPxMzi5THCddAqkwxhqyeUZvVaSTaZr4ACsONfmrYgEbXHEudG8LAHMrcu1UqFUlrqlVZ9Ua11X5MisKC+9vrhwDSVtRdcPTWP8+mgjagjK+XzVTeIJsSV2xQ3V9GXeaEnUcRML9PmVsrD/XnexFsrddKG20QZnJTvZU2WXp+XuXUly4t+GX0ldVaV5WZVtn+0gz4FoJyiq2x7oSo+yozr5HtCu9xiDsQSMYQFDhmsEfTsgDSDf/a32wxYd+hkTsgucHQCIVAtJO//Lq4sSdLPsX+0dZ//K6bPP2IXC77vhHmoQD/3qoC8EPGA0ECmZ/sb3zy/62z0+mvndvX10Leu1lmfjGlvPoEYeZhUzs34rqS1ZElhVcA3a+/t1k4bmJ/SO/Fbfep+z8qc3avGnzfZNYu/DbC1r2ZN8cUQQ76sA3xoImPkmouhS2QDtXdXtTFXn1uQvsiMUexPiuyfRBHckIBCbkp9usPpuPdrgu5Gy6lOohpa3y83OdHWILwniWtmNKG6C+uD9+sBtM4h8/uz92W0tb/fwv7o9vskKhlGb3x5us2K6cfpi2GsWszibjVrjvnQ0YMa+79bJhQXh1qROLXWhJOEwpbZG35pBnGtnapbNljtoVyW7wdG/+zBWIs/vjfkrya/5Y8N1jNcr03bM1G+L/mZd6BfprXm5bpl/cH20m6xHb7N0W+VN7eGXupYOG9nDoEtkCsKrbvKxUxjZ9UhsObl5mxSmrNVj3XUobon40++re1A9vsn0bW4mHaOshsZsxsQ2AX387m32blfvIWi0Ea9yEtmgFyvKSFflf5qA3LM+uaW4+QH9p6jbLy/ZBpRiPiW0I3BcMc/gvk9XFw0fTXupSOrcwQ5oPXZr1Nc0tJkTdDOaDqS2/dErUpXU29UOflgjXXRXJj7emaRdR7qvlEddKsE7iJpNe9vaai1dJOHrY0qf/80IxP76nqyhIhFerSGDA2cAIFXokkISE7RjEfj5864AEhu2oRMAIWyskMGBzI0KF7nLQfsTE+erYz7c+Yi2ESe+9RHDATZgUULBlfH1vSpSss5XEshBr+6THq+r9t2k00A4JvXWOY9CbGxeG2dbEkZJnToM42DlTHGX1zB6MAj6vR0CJrnmEKNKLGjgAcEAwyIEeCsRxoIOAIR788B8OxBjkOETcEU78J0sfzAj+YuAJDCLM9DAoE2l6XlMXbHwHm4k1Pn6tBkXstB0eTo+9RAl21/i2b8RLEtZjQd/lcL54J5pdIkVOyyLKZnCXnWhRCu8ImzEZBUj3F337oru50F48ecrClDMzwW/W35MYH2CstYbrFYGRxfxzWCdiPPJAvDgknIzp82hjcX2Q/H4ILo2URg+A68VBWJW2+6w1i4tOP1ZfE0x+J3FJ5KtiV37GPpg95E2igWNfBlw2eIjwxkS2AExNpdJ5x7kYkwGa7tSTqMx7FDHYebU9HmtztIfsurXd2VXDHu61tc7ZIlwqfb7D+02xUSGHAhnCU0D+TxvZKgpj9G5aEMDSSRgFXTyhAOXN75cHU7/P7uJ9a7CsNF+s/2nwF2DNKs3v+SFRUQYLQeVIlUxXASuNI3WoBF6yLpQY1XTsibLzvKxNdmfHwMh4YW285TghoAaODzwfJlpTCOIQFhUIUMnuNoTD62ZxMKB7DaFxu9Uo3KI0V/GmqjegRpf/9OtV4muWt2+q+m0ZW1xxZZ5Yj5uqzsvkasqIH5Cuyk/d8LM7bT9cqIohVGU/cO0uzNiPngoodtmLRWIXvXRA/qgPpv6Ql0eYoLIe595DJD3c4Tfux5CyYbi0b7yvRyMnBhy7wMaDsWtrOiif6ywv8vJoF/yILO3gahf7dGHssigTxi6I6sAs2jKY5Mvop4Px4t7U2dH8fnkgcmS945fLAxfEba89D6ysAbjPrJDH1gshfEjtfEZAvoruD6yUgT0BQPQ2P94SRAdzoWgRHUEuNXtroeQ+frXUShS5NwqQvbd3hVB0rw504eUJt7fr4XrnfpXmDdBnldOenByOAEY+0rGSRFKl1+aWQvBinPsdoUHtZX9n2sTq+Qqg90IWzwGEw+V0pn2/9VD5+oNp9nV+TkzH1vozN/FPkJ5XrH8AbBcuIL8q7G+762Sik0DXTDCLsD/di6Mp2xdl8zU6YVkJdj97Zn2z0Tf57dcPi+DYIO86Vf7WJPXopgLxOYte6xRgaLP0xU44Qrq58xD0TioAr+PX3QQIkGtuYIR/b5ItwZrgfxqsHUgC5M053p979K8+LHm3IRiP2yc3bueGm9+i4dOjRHsuP4y3heuDQDZxMfGjafvRT2wj1YdwNO3+6qgA0l9V97/SS7I+mN4ZXZ+lAKWWKMM00Ook/CN1ay6/V9Ud/WfqFl++9K46MIuNA0bRya4pQEfEQTQkKMAHBIcFBDFm7Vl3rUayMXOsBC0ZECS+UoJjw2dfwmu9VtpI0wXI5st7TQBpx0cq37RZ3b7KaJ/eOR0yle835YEqb8qDkjhSz1bycCXzA8xq2HA6Kr51NhlteN5oqYLFsbsfEAu4ix4IX0mDt5gA4g1yNHL96fDhRwABioNeIeAB0OhPkOzhvL8C1qulEb7m5cvqEjtJstL/mpf7wUUoXnTbGjT1fkNDRf5rXn6MN3GeT6+BFi4tnd0faVXP3iGjUvESB/7XdQ453A8I97tiqePmK/neDTpYjmX7nzmluvfXRqgIx4PkfcpAXDzWzv2Zl59au9lEa+i+5mUzuskh7PdzKGwuaGEY4BKBFQN8YQBY71N3SnnrPnR/FAaQvCvKB4DdC4W0A9gdUOuGgHDfE633p3GQ7nHCfpD0hTG+XwS8GAbJi/RdTOtsAO9dwnKAcMeSLyuo9ymRoZJ3JyWosHuS4A6MV2Dw+4/wDo1HQrjXCBnSQFcErQc2+HVAAMQeufpnxYBf8wMg1OCVPisK0vU9SNmg3YCzLiGM226Qnwi82Wb9K1FusYFHIfCNNYEBCe12GmQ2it1Es56PEm6dgXujT605f8r/okzOesemNeemdxSCdHHuH2rTNJeawtH5nSc/afNmioLF0TvqgXTfZUfw5bGNxSB586OZ/FTyg8HRO+qBjDn79vQlKxIxButpbe+bO77i6mvK2F7/utr29hqyjF+j89P7Mbrkusu/D4b2U3See9eTjjJbO35XxeKW31XUR8/cjfSjSRzivqZvN8GAo9odbUCsgD7kSW9Giv6PiB7MlwskOxpqCeflTWxQcNUd7LRkv2Z1bPR8lR3sJLKLQpp4+OZqstVxxFn6wBnEK3KoCYi+uLWQa9MvbCUFz3Ve1fFYgrmo4yASBp6CXCijrz6mMxmIuV7kNBpxnZI+mfa2OqSjV+fyvdf+6iVCMItnNGCKq6MSSFud8z3+EwzWIsmsPsYmKXPFwZgquGyijtE4yt5A0JsmO7gx+VUf5/+cY/h4BtCtXcXWPRtZLt2ZXdVW/RlZLN2FHaeDc3VyxWct5paK91l9ZxdfbdzfH12gcqxUeqwlB4iz6BA3JPZk8It+te+7QiE5eTSgNogx+GlhJCMXgiBYCAMFBbqMLwKEX8dHwQKjQINYlFBQSvkBQrrChQgN7aL8fOmTIuGfDjwxEseZNzHmVNUPwMmBueHmJ5A9cpSTyIvPCqHYyURvSkWxnqfRUwGlMVm9v2Wx9K6aMHYuzUKxjpogtTlV97xfqHfVhckOTJTsoAmSPmHgowDPGIQR3GbDfTT3P9s89qbZ2lbQePSXnn1K3JwckByuTIMuT/Z8IYDUOcWKBwBWjmlo4s2O+nP5Zmf+twFMBA4heEgkERHueuidi/bFSUC11A1jueQh+Hi5G1LBTsRTER/K2OQ9Dtb7auJ8zJtYTFYUp+59NXFSh+WiPNCZOSLQ7Gl0Lth+SGQLwH/aAXBnLEK8vyajC3k0beI6iADW0djTDJkaSHqQEAABxwlREHeocD1slciXmd2WhwzWQuAkff4loZ3j/BDrwTzig4dcOmuih0g80oMHS3r2I6/u7omfJvGZC37y5FVsQT3wMjbv5wWDPuu9KdvP1cvEtR5hqCGJtoJu+qDAgXfFhdEot8VRwJK1NozEuzGOAgfc7RDG494alwD0VT/3Ji+oAi4cHqEK+hRplXD5kUrV0AvGqoggIK0qevEYlRGEQ6ujF0tUIUFAvEp6EYWVMgw5r5ambvKm/T2LF8DJavNl1aUWZU3V/ZrIEtk/s+JC+dxueex+cJIC3GYNWf82a7Tku2VhMkDnpYVwZx5ig8CV+GDPkfUV9XGhA9hRCLk8WiXwCnNqxOqjI9XjapyYDsUhbUrXRSVk3khF7cqkDmuXlDqsp/D1d6/gJW9u/1jFzqPKKHOLb40UuOFGGuwn9MHZRIbbaQg/HgbYlQ0xYZeKJqKncL0d7rvAi9fS47EKmFeXUcRWXxwpZKMt9hv6CW06+fAXwq+IYnaFRIOzS2hD0H7nUidHbUobohaOrQTUpqOM6anC76ojXnsd48equEtJRp11PzFSXd9VR+znWiFZ76I6En4kAKmrUXymzl0FylNo3pusO/gCF5yFw2MVHp8sowAtPzcaC9GZYj+aF68PjOj+QPjtQMQhuEfKOET6bAQ5BrjIc7KPdtkIs5hMBZB9dJAiore6gvFsXvvHq6yi6Db/tybDltCfLhbBRPrhELzbrJHS3WbNRnBOgCAfz4kVVAd0A+QkP+8UK6eOOAUT8gGnuEJ1vPQ+eYQL3CtPAnkaMnd/HW/OfF6P1agFtRlNm/frIw2ca48VszCtTa90/koochTsrlnQ5O4S3AjcU0CHrRC8bC4cHqtY+mQZJXL5uZHCOJhiv6cXz6YyhDMSfkQQsSsncsYuGVVITyH7aOz+K17G5vaPVcQ8qowStvjWSAHrLbHfzsdm06i7fyf8cBheVyqkfF0iioC+gpU3d4Ri5Vg/WqFaanKKlPuVsRaranK8C1qTde3VkAblFwPw+tZKyNe3VXqAngI1vpmMF6qlx2MVLK8uo3CtvjhSwEZb7Af0E9p0mvFlavw3RDG7MqLB2SWkDOorcKZpSHODhcOjFTePLKe0LT43Vth6U/A39OF1Ra3/A+UHxBD7giZm7IvZVpDwtNjLRpsXR5B85b4/QIsX+5n9o5X6tSqn0M+/NVbmO0uwOHnYuhLf/TulLEF4fXkX8vWlXQ/QV7DarKV03675oxWrlSinVM0+NFaorCH4m63BuiLV9lfxwD8YgtYXKBFbX5y2gMMbzjUVsdkM4XjLdmWfvaWU7pnD45XvtSyrhM8/N1rGO1O0JHnw+nLe/YFUmCDEoaxLGYfyrgjpLWT9OVJKKZt7PF4x8+iyytnii6MFrbdFf0UfYV/U+r+QfkYMcyhscs6huKmCzgrcMJW3t+a++PzxQ1Znp2jUs89ectqljR08Das96R3jWeH9NvY5jTAL85gGBS/bd8/X/J68MzaWZX0avrtjtXG7gzR/xJ86j5B27qunzxUgg2X/Tf7NHD70h5SyoyHVA6+voE50X/+prc6JOxwwhj4zm7Y6I/c5pPNEo/5EaOV1iYTNqlcRfL06RvoMan1LFRdp3UvBB+vhf5iieCDVPsdDUOfSr3rFNNEnvkJfGoayTUDq5YEUma330CMERDxSlV+BySs6gMiq3itUvUoNIFOr8opWpQL7QZ/98NsvT58/c6ru5UuR71/Mjyx3yV1RHQvipGTWRnTJ9OdMUuPphamgVUDuLfbK4fcXrz4sgFIlSoSXYlUKBAC3+TF2jakfYHBSASji5/C9+r2Pivw+dfrdC4AddwcR7qviEr1/089wdeNCeGpivx6cuBphbimoh/sqfj7dI/Rk8AG+efqWUN2r82Ne2sPq4MDcxzMmQhuOMwA/Z3cmeT1dGrHN7gx2QR0IOUQ4ve4uNTexa1u9cIO7mdw1oLpnce2F4nn0NV0vUedrrr5qOENgF4/nPDmrl6zUqCRZpvD+KF2aog/r+UtQ+i09VPz6HCWZ4fogpRIK9iC1l4XwKjUIE325w8uwuIIZGaWCPxG3wPKHz+APlpeX1rxu2vxkN80+50CPvvzhuiTMmESbn+iTEgwWvIvcSxm8h1wPD7zB3YsXvL1dDw+5Mt3L5r8uXTHfxpiq6GMw/mybwrG2qrmmPOTlkY42OG4Gll7v8GYYb50DQ9rlzRjsRm56d3nTOL6b4A2jETLa5LcJVltneZGXR9GA/ppKeESviGwS7275EUev7XORP+uY52Ng2qFZJuOPyQcK5PIleUUg+0o6GWhw2gIIX/VaTkC8i16KPcOwQEnuGCa/LbDKKr5x4EMafDYb+fKr4+PUQniPM4io3+DOlrn6MzCpFxkcK0HETX+Rtl0jvzcf8jL24tdScLiEO+t8z71vdCbnflcAxz4Xmtmok+TrECsa+3xo54o9DYHBvO+mO82nvNwbF+xl/zwhka+fPDWNTc1l3V9T4yDPi865qlvsqbGVrWCVNDk+9YuBd3avv0o2KQvBEB7VgpHAaWwAifKgFoyEzA0DPPBjWvhPln5KK/RzgQ9pwShfs+LO1LyM6X2lOTOvy3lzNzTM6cHH2lhSm8Fq5Nek1aP1RworUgCKVJNgKKgqBYjwugTjpJvh0E+GtcMwCDBcDqF4R8wyGGA9NkiD7h0QcYDxZxQJ3cUjYkFj9ygYvneHo9HWrUN4qaVrEaItIp+ByWsIzvrDgRtRrFUf8vLW7O9exB9DntltOg5cCRHanulLQpv1/V366cnDmmJwBScPCAyhF13mCLEDTaIQ+s4FCrXbTKLY97foGNZLDQHttBcMpP4aLaqplyPCJRV6MAJCQRbdPByk5soHsWqp7H7CKRZfNxkJ2iiwBDo6pOI3fARvwW4pvFqrY4nus6Kwj2WkegBX2fURyk/PtFEA5l50hHXpAuLGZnbScxTAkBMKAAh9sXbsmAeIFTlGh4OHnTpRYxBgIvDPQ7MK+wOWhCEUPHzNV6YiwWtagGAom4cuGMimigaEtYXYvEFtWnCUELdU8efEDWGlLxru5itxJXl7EANBQt98PP7ANy0sLAzOwxUKgtMCi4bEeXjoAXFY/pBn7/oxZxAoYZakGG8GoRHmkoqxZhAaOpvSijPD8guKMvNlFz/GDGzD0hFm3iaMGV+G5RayaqMSWwbhgJFlHihJXBmGlo4q82ExY8owJGpEmQ9QJZ4Mw01Fk/nwWLFkjNzjzkO04sjAMhiPIvMWQEYMGQaTiCDzwXDix7CxPriQpRU7hrX42FaYUtwYhIQsQsljxrDckVS7x6htlN06zVixENxqWeuf13WyBN1kKFjYGlblUsVnofXEcUuuzDgfxC+/SwB0IdUrHsnzN3iuv5EcQp8n9SF7KKosNTha2UuOwRJ21vy69B229fcGr1pw90Jf2gsTeIhDLOOQ0H5IaCvQVHMCQUKrsTAgNBMIcPFnBDgePg0OQQqnwzAqYTEhgCpdVIBRwQ2xAKZ3b0wbEV1kCDCKFhtgSMKWbryJXG/taqOiI+UAp2jEHIOc93mXLiTmbXkTu4LIsdo0cGUhg4atON8Qqn62klOURwepcE7L2CeDvVR2X5Wt+RbtoZfKk4tU/OttfJNlqTzYi78ZbBpWH06J9Uhj2A19e+yAguD4MOR9FfojVuA7M0GVvqmrE0XlyeCAfGX/CcEtR5Jsi1aqpegsb68rpsMBFXtdWCLYIeQimSZ0aUSj+aOqT/oE0kH9wc+Ngv0jPnFE0JCJJBUOiRaJs7F3gKmo0T3FOCN9e5H8I8dDNhI/LyN6gwpI2wqN8yrsilLxwTlNnFsyraECg/PFOLBkykgFRuY5cVr2VIect9AWayJr+but5DYW2HhNtLHcPVhyzqbmIolMZa3DUCHBTdo4qmS/lgyc3rpNwDJ3ccmg1A3dBLbK3i75I1LbvAlo1o6vLKehXShKXvN3puhlO74lnCrYjN1hMmJioziByNkzpiIii2JxTPa6GLk3S28qJzoz5v4yFTSxVReH5Ow6s+ZeClX/kWs8ui0NQG/YJcRWKEhrE9ufxggI4kcyPJ+nMIfWmz2rzZs1Z8xbzZU3nCWrz4+3mBmrz4m3mA3rzoPVZ8Dac98NZr268131ma7iHFd3dqs+r91iRqs6l9WexW44f9125qo4Z9WdrW46T916hqo3N1WdlerNR1VnorpzUPXZp+q8U3vGqTbX1JxlbjG/3GhmqT+n3GQ2GZtHLl6aj4B6nrXHw2/pD9P69CgP0i6/LADTmDbxDpUXpDEt8oorCHHkQRxVIdLvdHshwCe6IxCz8tgV2FfRqI+rjWAVI75sMBNYrhb4Pu5KzR6hzyWxeLikLNLDzIXRC+OS0qn+Yy4LBYIkvxZZmVp8LrwgBYljXZMHAb9uAwNBOh4PBnopSRKCuN40R2HcLZcESq3KzQmQN8d8kp6m7K3VuseaNMd226ZtKQQ3ce7XyJq6FQJzLQLFgpvCFRh7rI2iQU3lCos10oZzC25K19nFjp4jwRGaWj+iYBJAAoWbYj8mewqAQnKa6hWqxs4ACgw15StC1v5KBMnT1Cc24RT23oCmPbTHFfw8wVZWYgeLI4k3PIxNReVdMtrmGAcI3QMDt744COgOF7ixxUGA9q+QbSvW92O7U9imFKtGIHtPyJYT6+uxwVxsQ4kji+4bgdtFLARgVwjYDGJJk/d8yFs9LKzkjk5yI0eeG4RhH22bhldGErsxqU0YlmhqryW1xcIRhXZSkA0UVguITt3k2yPSXRGFzRDFPRDdrQ+1HQ/NjQ7f/sYPv/3y9Pkzd3T+V14eX2bF/mIfivqQ1dlpAuxSmtg8poKbRrzpvfj8MZo9fhfBtOFk2tsq3pFGNJ9c3RPVOPCpoes72ppN1Puq4gAjnRgRd/WKmGf77hqV37MitVkXz74+mS/XZDaFxqZ0MV7BklISNV1d3+TfzOGDqe17cVn0rDXi/ujV2KcvqdLL7BD3BigzcTTLR+c1BV5mxWYBhJc1Ed6P2KC5oBQiTtMRLkBqzUj4E9JNyn+YoojPpEJOj958TKqSRqP/4NA1Inn5MX4LXorsa17WwIV4LDTbfn20N+zI+GyjVQ/JKEPy2isHT7GVioLK2iYHeIMWKQrOboccZt3WZ4kbmPSk5zpKUxx8ZqMxoSmq49Gkpw+LYeTVC6h/yVEt2Jqmp1JwCUgi2cvjCOPUBZr1PrveWyBmbf3+UrT5ucjpv1/W1ifXeQvApjNLbjZ46HpP1lEZDC259uSB4q1AYRUg+zbevckvdKfs27hWt3nZO+XlCPwp/4uOmpfXa0J7941zlQU55eeGkMgTaF48/ztoIrBgX0SdtmvP1kl9lHe+Qu+vwGkVqe9C1w+IvyKIyurTvMh6/Ru6jEDtSvwrCCrdCohM6GK8sNLuBi2/gq7HX5y1uyH0Q1hdkv8T9Lon+q8ghtfrtkB4ahfmxVbpzkjrSJTlI51VI1I35kx36Z1XdAZO6rLia1bE3yeKdWf/SJ7ROHxdAjqzmvgaEbUzcpeHVLqgKB6h43HApN1NvMQJOhm3AGp3LXFoVofi4up1I2juMkH1uowoKLWjcBBVugdwoW/x2rdnoY/z1LenB+qTQRb6rpbb71nMpUgbFdP36MxAFiiRWQcfibaKtiAKr6LxgQi9y4JG2rck0aCeZQHF71eSOLxeZVm+9fqUNDCxR1miavQnlFxlQWr0JUlIvCdZ4An7ER9YsGGnrpp5vR6rwReHtvi/WbMjoC5F6aCS2+NNlp5IyIR2WnnpiYQpab+3XnqifQirXd9u6Yn7K4jh9dp+9aWnCLZKn0BaeupdsKUnx/ax+gJmnJL7VUprPCue2BqPBIzcyiuu6QB4hBZdZU0HQJK03tus6SDQrJZae02HlrtMUL22WGlNZ4Wo0u6u1nRmrW2btQa5j8u1Iy7rMG7jWqmR7uKafVP4EqzOjkZxNG3TIrGfCELDQmg0EYBbuNYE6B1cQYDlmmJb1dnRrK81mK8rLqwka4t9Uv/Z5kW0UjpmgiJ/m5WHoovnjB8vXqo96R2r0TGR2c4nRUFeFlXDAtmPjkog0JnrAAt+8hrPl+4SfB7O3vEV49zk5eH3h/hDfCsO6/TlAbiFAwAo8vhFHCvxwUHph3jRv7Sdl0fGLzG8sN07KxdUJtJYViVQ89arv+3iQ/kuSnO1EkyKzmWBDV0Xak/OZUFYc3K+SBITv4KA72oBAbq2k0ywL6DeMo1QFi8Td+R4fgboohxI/HXZ1rmJ95hrfXP1YiB4C/5H01wKJBt6Q0HxR6+jWevR7qSZf1gQJmuRzJ9T9D4K8ifT1vn+n1lxoWZF73k/eCqg3OR1076+N2WbujTJQ9M5G+sMXZoEARUZn8f6ynG8FWWxTR/m4ezWSyqKo8eqKMOHMZeCPBDQjbCQeKd3H7/JxwPguClA2MltN08iUtjp7eingAGtfHgw/MsebAy7AcYomNZNr1Da1N6lBtZ+CGx4jUDY0XFVUn+OyUulftxEz7Z668ZN+hxrSNyz2tBbfs73d4uRxGK9YWknWnFYJtbPcoCcWLoIWun+h+RqPrm6Q7/E6lOD+wpgQ+WHorVXKNT+UtsEukvA2GhDIuchEd1co3W4gbxjdL0oIHqZZBSQdLckERC65zFKh1/7SP1xk0fs4z8rdi0iEWqYzn+OXsoW5RpSaNN3tPHQPvGzbEih0c+1UgBVquPYUVVroFGIn8lJQLfBrY29xzZ+72i8te1TAK4hJaLtxm9+lzXdBC95NWGU85qcnfjh1xamoRMDDmx9O+j1uMOOuSx75DF9s97gY4HGHX8k0dhDkAWgbBSSxrSLm7xasQS1KQkqRPrH5o6Zlj+5aNiUxGSPnBaYssFTEpM3flowCoZQ6Z+bPopa/tDMgVQSjdUNL+D4PXESrzZZI2uwrymoNzedQWJzNNXQdP8X2Sul47GGMUs+/kjGB5gaF6TjAfwujzwimDT5w4H+UxXHAg4UeyAQheKPAhw04RAgDmj/+pHRYLh89r/ZTUYajzk8WRJKxiZRSOok0SVjTRITFYE9TnKrg2yQFAXkj5AcQOHwKArIHBs5dJKBUfzHZYyK3J+VOySKQvHGQw6WYDCUbj6oo41lu8EaacSxeMMMF0wwxliiJQYYbw8FrR5Yh8cdXFwV2UOL7iP1BhYTEHdYEQXiNvAOlqh5j8GxG/cJTta0x+B4DftEJmjWoz8ovVF3fkpmkx4DYg9bJyzZoDUGx+ptJjB+XxPNMVaT7mQXv0FfYCWacyCQ3e/yuE26o8lu1IdP1WvWXShuw56A4jbtMzRR4x4HZDfvLqCsgY8D8pp4l07QyCd+XHozP/tZmQ19HIrd1LtossY+Dshq7l04foOfyDlWkz/LNn6jv0JLNPvYaZ2g1+M2/nNZdvs/fbNeF7BA4/YCaTRuR7AEFPUFSUx2d7DAlPUISUxep7BgFPQL6Z+b3jUsf2hm75BEY3cQC0BZH5HEZHUTC0R+T5HORVZnscxCfn/hA0x0GX9meZs6MhfwedzuwhVldxbj1+p1FTMsbkeRwGJXzhmcrGqmco7bk83zT9SPJRDZvdgMUdaHJRB5PdiMT9B/pX5ieu81/3GZfVcCixfyOiMTxLxicMSgVx8cJ+o1BUfc0ZxjcbY0E0Cs3n1Gxe/bU00wq2eft7/8fn0NN+vVPw+Pmdu3NV9Wp1Peuhd0rEG99lv25mFBsCf3f2Gi0t3mN7GfKwI11rkhBT00sCePoFF6cRJasnmPQPFeCyThAW1DBNDbLiggequhfYmdUg1n9o9RDdeCxGo4/0KdauiB4lRDCI1YDT1onGoIocHV0AMlq4YQHqEaegCl1TCEOKuGf2bFnan7jjN2inZmJzlWn/rF1kLgWHj+JbJpjQeCMpWBUL52RnSQ3k8NA5lFeSjgmRME0d+nQSO4+pAqB4TTVm1WDAPL+PUwHq7OuXGd9QG/mKYdB740OuvZTJ7boL1n/JzWb8OftM+x+HUzwexa3jgjgPI0vsk7TVwzQdNLaHDcuwqo7Y3oJpO1PHKPCSJMavldAHrDHwfBG1yXgtjexhEavGnz3GsDXH2FQIBtvgvgaR+Y4sg9Lmt9+BaXAIKv8g9tcd9SpGlm5ttfbxRUJa0+ez81CIY00n4i4GYwCgpaQj0spJIKwdRZecdCGRwlILNye+ivjXxZlW2d7WNFdmG55azBJwXOG5bfI6swfhBCXQFxwO7Mi0Pp0UAcpFPzssD9GggCLlZ4WSjLFCAOsALgRUGX5kGMFjgu5uWAD4iFQWaNR3lTva7rqv5H1eY3+T5LrMH5zAXNiP0jR+3J4BjNAe+nBUDyWMxZGCN97IYCYawhi2P0VEM5maaJX8cbhpl81XCAWhvmQatuAuhH54K3cnEB431W59mXwqHpDWhVY3WP3JDKq6wNPITpGAhqoVP4o6k/2e3sX4BC7zj2PiHpA/xpg/jgoCT/9da57RmRHxyU5Gtzqu4NLfcnHz6EU5TfuTcELovxO/JdgG7fYr3tCk/etPm+eV8dTGTA6DEWlOjustv4VZghwSedL3Afpu/zYsuX3eW9kYlUEKjzNqO3JlLqXoY4EvRYAwHpa16+rC4l5zf7mpf7wVUJpqiahktjfZVxvublx+gzLrGsqdNPuRBQsvvjh1joTZAkuz+mw26oRZiH0rmqwjTt4ZW5Z6A07eHQOWqB3Gb12Xy0oxcOTeddD95aJaYsL1mR/2UOn0RwUzqbYO5N3WZ52T5w+a4JKIOZb2ezb83hv0xWFw8fTXupYxcsh3u2IZ2HLp36mo5iw2CyO37jYLI71TqZ3R/fZAWzicjujzdZodxIVHWblxW7cvbu2sU+K05ZzS7znbcyUm321b2pH95k+zY2Iw5SjQncjAmo1sSs3Ec2eRPVb3DWK+KvLnVi1SZWxg+TtxLSyRzyrORVut5XuxF4WZWN2V/sXaZ/5kyy7P64n5L5mm8J+a5qGg1KOw7VxvwzL2UF7mte6pe57P5oM01GZrNrq+rwqTXn+BOiiTrRtOa8ekJUBPbl8mDqD7VpmkvN4er8z5O/Vh9p7xaUcPUJ6IN13/uprU15bG+5+dVM/qr5JeDqE9AHG3+Bt6cvWRF/+jXINqaRO2lozR5rU7KWPgY/TQzBr9f56/94XbIvq/ImPxjeT9elsHdT4KO565XVdNhztVxZEQ91Lhfc31XH4Fr78DeawAy8urucI+z2z+zU32f13aH6WgbTHw2Ii6rPfl1JvMkL83vmvFE4JLUQGs1ogs+fTt9kRzJtfZlNAQCtJ3O/WKlbfVKoDx/sZvvpCMroCOynoyy7m7wwHzKnsUBAOq9zlmwiYArb5GQnGsPVR4XgS9aYVzmtaHROh1xQLpIvjSMY+EPjKMnh4oQSIAiDg8Yv8d9/vnj7effmj4+7t/94+3n36b/e//7Hu/9NzpDdTVXvbJbsoDAhnO7j28+vd59evHnNQ7MBxbsmuzFyLl9rWhUHUyPt6dXwUVrUuRqnTZ0+TKFVXeBw2lUfD7c2L3AY9TlJg9ToBQalTvv158Oh974fyB0TuQbiocuftqLVyQFMbyZQ+/aqzr4mxkpXG/7ut5NIOjLTY7xhcGZIDYvP9H2YKPYviEMI/yNAAaF3QSI0+o6Ag4Wxhn8yPJKVAIUFswahCPGsBCggpDVIhEa1Un64xG074Z8MuWaHAJIOjguigKFxcZhAq9fFu0BMnaUkipRUoyc1TnXuv0re8DoU1FY3jkBtTlwQVlsSx+nKeux2+wBK55eMNEQxzlWTxzcG/BiOnwpGbFMnQJDcv4HF7d58Xd3k1Er5pNuYHz01UE6eQRjIcsq+HSZXDRjyIMWh4Y1Q4j+TTcvenEr+laxjdU7Gp5JA7JUFzEJj3dvszqiWnC5Ve52J3e5jITVtdS56Zw0gUufrsNB73iVGoNuFI27DPtsG3iZ04fjbyDdLwnBTeHg0LgS4mnObzG54BbchnL/rR/wvE0cD/l0/Zrx/QBoI98fFY+H2AX0s2j6K4C4+mFNVP4TXHbo/85c2Ovfflw2SX2U0E+wHzdJ5ccjO7vLNYsXKZ7vpOmZQkLKU6f3CUMnOm3PVmE/zWSFMNbhjc0MKV7d+vSh4MFXnfBqd1Zgak9X7Wy5U761PZfscLpP11SfqWx8uU++9BVV24DNlB32iS2PeVXtOtbs0phg8NWk+mLpxB0EUnvPVV5Po1eV0Yvxel8YcBk9Nmt6e22dYqr4QZdcU1Oj2hck4vcrgJuFYjwWtfWQoOP5ZMBI813lV5+0DojCMiRyX9NfKxoQ+eWhICErHR4Q+dXRACALk5cF8I8iP9iriwdOvfm3g7GtMejVSjR49nUykI1SbBtLSOHbbj0yXYuRRqftV4hHpioY+GgV40JHoioY6CgVY4BHoCoY8+gRowJHnioU46gRI4BHnioU82oRooJGmh4U0ygRIoBHmioM0usQokJGlj4MyqsRI0iNKHwc+msQo8JGkj4Y+igSo0iPIdesPjx79+rO14P76ldTqr2MlGD7WVezh5ZXIE2v//dPklzpfEMrkqmzj+8sr7clFKl6brKnKvDzuGBg+ZylQW1XFzl6GGFvYXpHMvKQI+Sk7xq6vXMtfPdS+fhe7xiny/TtghduLsZ6xdWYf3VoxH1hf/y47qTAk9LmqipdZUcTERpsttgvWAviWwdw3PlNp3XvCQIQ2fUUYDeLmUs6fKABBHD8RzGwC1d5W9nxOa761n0x97+5dr6dSa2NBXGN3kWbi5mbHSFDs+js7P0fviFsqDRd9Qj/+9CHBTiZ6AcxKG7n0BZDtthjTZ1lX8p0feIIVwIDOlq8g8DPlAMIJOW28LgLwEWMEIfvGQci+6SGk7pZZqUN3yiDf3h09JlW+wUEofP7tOUG1txZL/kaS/E2lgtmnsT7n0VA9TwWz5w3aPB2kB1UwBsIpLxURsm8chOybCMHpTL1Xny47Uf6FpwGl5D69z1g2aHRTDO4qLI1UPja61Ls01PvI+Rw49JWMObDzmR+yus0jV4EOf5d91JBI8Edz/s4f2Q2JJOK2XattY7ZXSnC89uxLQo1v4rmxtTr0yBginQoTX0tDIeKQNBQe7gHAQ8MhjGRYuAcBCwlH5NPh4Gt5MBQckccijtcIhGhjBMNGMZJK4eggzv50iLMn/8HwZhgACW0OYMBhzTBMOqQ5gAKGMyMgVZ0f8zIrPvBzZ0xCP5dmcJzcmqEp5lofVFy2dfTxHk9f1sURX/1UMAZDOsd5clT9oaiVfPYjaVX2weabvRUtdtuxp4b1/2ImVzFM7ASQByB5+gcRjT/xtVYFXviCvtWUh7w8xh6d9nxx75R8ZhoaZexvzeFSxN+99gw0RjcViPQBkTUBeDgkIO8Z09vG8sV9lhd2ZoI99ZHylIz9oyu6kDDyAEjy29O7HUw4dJBKRsNnTanso82kyKBwqU9w0moCGROciSUgKbMzOiJlxpYCJc/iyLjYzQEYLuEaAXbuohPRVM6SJqdkTGyqlmAkTN/IgKQpbYKTPs0l4+Iz0AQrcaBKB0VXKlKcpNULXn4SpoxIrlKnjzxoeCqJINOmlWRg7gQ9gS6atMs+Qiv3BZN72QdotCHMSS998EhZqUiNH8mrFzxceEUD4aWtctDbE2Bun2pF0Pk+HQ64/QNkRG8D4aJCt4NgrPhtIYIf/YOp96Zso88lwj//2U1sK2C10U+5eaM14nZPlWnx7ofENgJ+Wcknvuey2FebzXvPpVZHcC437gamhkuv2F5bsM1L7xxepxDP6Tcty1d8lSJ9Bd+yZE85rtcsTzm+eet8xdeqn1f2baup02mr1VOn9966oi7xVWrqkn/Lqup8gEZdddA3rKxurqvVVjfXt66uzgco1VeHftsKC20KJmDxjUL6wixh7y61Nkvdz2O02uhOZ7K1Ju1+0pdpa5O1Gnk6JKQJGti2fFmdTuCktTcVbEyCMYELLVJgoPNJwcLUNVqfK7wPcmEG97Yi9jZxKPL6vovEW9BP5BK42DLLGsrqSupHIi2nzH8g+vpJHIa6YOLSsFZIEnlD2bOY5Qx5kyIBQhqIzkjow00AhbhkvwLirM0DWKRF+BUUfbU9jiTZ5HDhxLsaBEx2Dgr3LeKI1CGUC8YaM6WaTMogad5ikkdFiZzBwz5mmbKO82ibw/d5831e3hp7Sc1BAkUN9JihhSI7FAHJoR0uYDCWQxEQeCAiQOd/HkIRjRQP5ZJ5A6A0Sx0lAGZW4nwRL4pgtFA3l8wf26aJRt1IndGFdk61AUlbpytC716pIiJvFz3Yd67GaupVhFlBtoKCl29cpNV6jQwoOmMnRxmv3R4jxDigSowv9nyyLLg4hEWJMMShOG2tSkwxjsjoQDWiiXFA8phSHkdMgOONLbUiiHFQ5hhTK3aYkKP0cZNG1DAOyF5G9K1KS5YUNwkfDqFKlhrV43GD+clc59KPbA4Scte/tgoWjoLyV3e2CROOwnJXebYOEA5BK62jbRsaDME/Ws6Lq58gIpgw6OPNYrVigYmgjNmsWhQwoa0g7UoJ438pYwHGbpVO5C8OydvFUor5Jf3ExFiVyI/NCVChoeoMB1hxvnRQhaEqL8KXhArHV0UgaUFVJDyNJp0T1ctpjpSKpySel42tMa+SRPJywOVFlxnDy8plpWZWFL3LAVepgfy4XVaXq1MTZRG7fHB5XRTG6rLQxbWRHaXLy2md+iiMz2Wha9RISWQuDk3c15HG5BIWPFnRJErRuJRWmB5lohKHS1jsJAXhBlc66RG4UcTgZl7Z1tkeZe2NBRt3pG0UR42xeTJ8mN6WyQyHuVESh2Jsj7hQ3E2ROBQ17MYl8gfeiHBmzwniJMCzggQIxoaGC8PdxohD4bfIzGmIF8ekMIhbuS4JZwM3DkPd+nZpWBveKxxPw9tPI3gXtkV8t46nSEkTgipiOcCPrEgColuxDDy8oKWzkVbuGLBwFU2y0mosAxUcMCRBKeMHDiZlOJGGJY8uGMikwUYSmT724OQyGpWRzmFSaAYDFeuMk5yEvpkBSRrGJFnpoxoGMh4AkeQlLmFxYNFwkjQrKaaEm6+EmAIsd6kBBVxwOJoAw6aFEjCguZEcSXxROIf0Q/R+BUFgh/QjdNoWZogHZ+BJifNIjz3JwR5cZDjiA2OmhX1w2hkg9iPduqABIBxAPAokzUkMBWHgUuJBkrzkoBBeASBskSBFgbo/woRWHDGRA0UEyNimH8xM2PHjQUPbfQguvtfHA1XrLKhhJKJGTbMYcwNK5B+gVajZoSWiT1Aq4owgE1nOazbb7HAT0Sfo1Vle4Imsg1esu/wQFIVPUKq9gmAU2Ufo1F9WWIow9xVrsCBARfYRanWYG6rCwIfiVZLAeNAKZ1GYELmSXhemhq+wWnU0hgVozUmBLJwlYjiaJb0+TAtpwWCD26vDcXaM2jlFv+nVcis10uVysw/TORe6BuKcBkXAGHsNLhZ3cyGRW/CiziyLaKs4qR+MuGwz/7E46zRxIPrCjEvEXIlJ5BFtH2WWQ4yNkwQMcTA7o+EMWQEc8hbCCoq3VwCgETcFVmCc1X/C3TSinFPYbSGgCnJSvJ+SuEKHPASb3aTDG3OlmlXaIGveqjJGVYkcooSxzDJHcCkdBEYPXJnhiS+mQyAZoSoupPxyOgQSj5NdEwovqEPwiDFfLp3skjqoFNICe9b3cHEvqkPgqKF9Lp3wsjoIj74BPCMUX1gHQxK3fFeUskvryP0tc4yndHEdXm3YlWY7MMKykYvFv8AuAJVYHWBEXgfO62wedh2884IYc42fY4IDrkNotOhKwoUhrPZYKc4ax2R1uDoR1oRjf/RxqUZsNQGQOz7Vi6rGYdnjVL14akLOcsZcOpHUlPOe7OVM32q5bGlzo5Dq4BFQ0ZLnBvHJwXxlr7FtEfEdpOSvvW0XQB2FlawobRU6HQXmryxtHzQdAldbw9s6XBr6gEf8BRSqpChKmjBg5M6Q9eKjibCsmbJiZDTpRippy8HZTdskIDp9Wc82oNwdN7U4aNLPTY7FifzwvAAcGq7W8IEZ+0yHVRnqcqOeSbiEeLIIKDWIjISo0+zzIp05TZVacZXFOLPRdeZpsuhmDrxGUWbHNbNyW60ZFkY0c+CVaqUklpnVPWvVTmkUMx9eo36K45dZ+Ao1VBC5zMtxrToqjllm4evUUlm0Mg5O3nOSxykTFluZETJqEcqUVpoTOaMUm0xYaCUGJgdXWTlRyVHMyKYjeNne3Hz76/Y8eqxNHcUr97xI7A0cxWv3fGD8zRqtq/d8VMTL9zAk6Po9Hw1+AR8GwtpokV3Ch4FRbv5hX8SHoZC3oPmX8WFA9K17wYV8QSRPA/2pzdq8afN98746AD/fwl7QRJt7U7bvcuBH8mk+6dyLHP2Zlt8ZXTG3SadHf16sfp18TEAZDFzUDYNRFnMpYNBuThgL37iJQD37dSrbpr6p6lNWOi3kkPiINFnQivCzH36adI6mfeV2C3GNJ0fTIp2BAx/W/WjOVd0SlOvRQah9uDiNWEJ2sKUrPn/6bOrvqrJp68u+rWpUd+7C+GC3nZwsgGHs2lgSJQd0GgFBvMvwfF5w19zc59Wl+SzAGtPYAO9k2jrff45HFoa4eucWiCnEgQ6XOhVgGcJxXJVgwDlICIgyA8GhwPlHCIoy+8ChkLlHiAieeRB+uNRMNviTQfNYHAQYU4dQ0BF1FObZD7/98vT5M1/D/H5d9bsU11yTJbHb9/cI+Og56CNZ5KDWae8IjFe1VcfTCULCmJoH+IrSUocR6a02CNn3TtZYkIt9Is2QiC6gEf7Cij/ufBrQ5E37e9ZEpgGjBa0ekgeoMxnaAPX6DaHML9u8nTcCCfnew7p//1Su/yVrzKsc/nZrfsgVvnt3yGtjs/ABlZ550NVn86Dd0bRv8sJ8yNpbWP9o2pu8MOfeR0jwNcvbN1X9tswj88A5gHW5qeq8TC8CpPVrkx3+mRUXuNhZh/vBQah9mzUk6dusUVL+as9jkbQ7DyX1O/PQoLqDrbCW/ffvLz693v354u3n3Zs/Pu7e/uPt592n/3r/+x/v/jelxu9s0dvdVPXOFr4dOjj10P34bNXA1ya7s13Ii0N2bs3UEt1ndW6v0FmSLeyJQzBPDzMm+LZs2viqk9f8MfoeryajI1p9KjZvoUCRCgfM4xssk6hI42QSm3ceTGGjzYRTbMxexo9G73JQMtudXI3j67ARPpvKl/FP2PIsLf9s6y/H7JJR5ly3pC+z8lAYsBmdGYvb0D41rAGd2z5C6+kRpDediy8UtJs+HEqjiZF0s7j7jMHieKrR4G2kj4jeQAapeK2jD4rcNGJMtkXrLZt0c+Pjsgns+wTwhgbML9uMieC6FPTo1m3g26Hwgq3gwlzcDo7pYS3h0voR2kKvJL01XH1naHXhsr8zicrlR7p6ymh49d2PRK7xKJetsqNtul754WwaY8uN1yw452y9lSJ2iWzHWJtTdS+G7FPZjrJwbLmMNg1VwnU7+q46gk3oZCluPd9VR6zhdAwfoc1cqtGbS/fDpG3TiobcLAE0tjV5Vx3TBXRFYz2L6ogXSyRvbMPBw+lcFXjWNeS9yZpLjU635tbimjIkh9WWhfEj1BifIr3WLD9SMMbwAlGGGGEWXi32ApFrMkhl6+Rgmq5CXjKbwqn/A16T0DyzVVSG1yWxFV8/IpDmn01jK8JiMmXy2RQU6Xyt5amqH+DG0jFWaCttamhT6do+Sku5EuQ0lLMvRG/OgoHQy7IoNH3jm14P8vH0vvhqUJCI23avkRhNN8LUt9zWEqnYa6y+3bb/TqnWCNlt1kjAbrNmG66hN+GTDX3JFmxjTyL5Pft+ZAu64mrJY+v7kC3IDnlzrlJhQD6kyVHCsu7N3COUYJ/mcRH3bG6aWP/m83iEXi4oS+/rvN+MBr0S4fDIV4CM19eE4cg9DoXP9huufbpFCIPatErnr3jrQMpR22xrIXeJbcK8bkuGs1FgMzK3FrcgQ3JY47EwfoR2w6dIbzKWHynYu/UCUTZvURY43sVPRI52AbnwfVwvF30jN8zFa0+9WOSmFKSyLd9gmm6NvGQ2heEmRLwJQvPMNnIyvC4JRb516/jR2GtjwMZxZixuG/vUsKZxbvsILaNHkN4wLr5Q0C76cCjNIkgCt4peHnKjiFHhbaKPit4kYlTrg3AwEuEcHM6DjcV9OLRReJCG11/4gMjdBcZk2/reMt0a+7Csf939O94Ug7llm3kJWpeAGpunl8ibO7SPmEzlPUTe3IH9g2P5GL3DUo7RN7jfFqjTdd7cAU3MCsb6EdoXgITQBq9oGC2wn4jZwqyA6O0LwNONRYcXD4BKvP7N7Eh08CfUYSSnunGoAK0fhWqxrVuXT8PddWALszAXtzJjelhLs7R+hNbGK0lvcVbfKRiP+pEoI1KYBh6TBpjIo1KUDG8T/WT0djFCxmsb/WDk9hHlsm3caJtuiPxwNg3nskuwLYJzzjZ1UsQuEVVGT5tpmgbfHJlby1vMPjmwwZwbP0Z76VFkNJeLj5S3Tz4sRvOEcRFaJx8Xo3HCuMB5sxeKOHEOEzFbSx8TvbHEqLq2sjcF2iEfWddS9n8gNEJgnnXtpAivbyU34oN2tL1YpC3tMI2nxe6CfNAG2zWWt9d9ZBLWXM9sH6O1XgsyGuv5F0pGth4c0rgWI8F7DR8PvdOAqAh9hoeK0WWEqJjtsweK3jxDTF3r3FkCrZ8Hq2ubu38nNH1YbnUtswCtb5e12DztYJu18FTfsZW3gjYxsBF0TR+jDVzpMZrA2eeJYlQ9OLQQVYgFjVD10FADVEM8zHZmDURvZhCirpWxhkBNXjN1bUzbv2KAVmMon7oWho3Vty8bcGFjvjUQbcQXIPG1c1WdHfGWzrVWaOu65NDWbmb8KO3dWpHT4s0/UrQz6kWibY2GebjtjAeJ0dJAVH1b05ki1dpD9v/zdnfNldtYuqD/i32bnSN8A31X5XLPqYlyt4/t6b5wdFTIyp1pHSulHEmZLp/z5ye4wC2Riy/ABYC77jKSH3g3tfiFByTz8YYmtOzZsm2Wjzkj8ebjzmH50B6fL8vFu/xq9gP2+bw+6U6/nvufsteDJnt2e/Y7R+72YKSm+z1pGvkdH87Ufs8nTNZw1weTddz3lZP1HilRsI5DpSxXPlbmeSVHIxQuHy3zlJbDkXDL5ePlWMT5iHlgxtVRawblUrJ5cuNhcfVi4IeH+1+uP0ga+Pp13uovPGcuXWo8XteelV61+DpvY4uNx95Vow0H223DyzPePPXH2/99Kp/nFjO1/RlXLxR/fPjweHp6+vN8LSb4zkRhiYFSEr6Lv9Zw03Gy9JtbTi6N8VpOMK3x9t7SXw8mOhs3RqJXkv/b5Em1F3NXc9Eq3p9XcWS4T48PN6enp9O7sYAvq7lUSJp/IN15+cFY6GjxX9d3v50e5ceK9fwDR4rfaUWyHRE0+nVevmEnZL/0kAMYCtZx+JJFk3xSpJJLjMJNoaSHLJSo6YAli0PHmvnCqv7t3UouWsnTciXHBXw51oyGfFnR5YIKD1uFdC0HrWKkxaVUHoZdvIjKk9sOSJu1/5l3geFWzrM1XqyxT8+Agey0yKqpafLgj/rb7ZfytefrLAOtvL873dS2GU0fWP/qI3Xb1U+T+3uF8vKVz3u8znDJvh/WSsMdyOIHlMbH0xyVfgveeF5AcLLYb7v+XQ/esOyzHvut/v19/aMavN2/Cz+oIWj56fnxdP1R2u7L3M2tNvYA8ZblnT6C1qcOEGm787xjW/nnlk9JoJ/e+BEJSaIf/vrTt3//8U//9m1rnGmL/P3p+v1pIMv25LLZ5dcnl/PkwcPyf9ETVTsH5zxTf0u3T7+VW7h9+q2/02Raev/mZznXwC3P3rXyphnZFfLqNxSanr/WnYeftCSYF3w6LzgaRNYDA7aEvNdFEkNwL7XNIL2DkgSQ3WduMzTcXTbUxc5n4ItlIfn6uyTG9c3z7ZeXZ6++efh837I3fp0XPz95dTMvPhrq8fS/Tjf0+pR3LWFeFtsdBNQU4t8fnpv+Qi8L3j/sn28FQQSfEd6GkH6gVxJg/8uh2/aF4xIKzW/OqbdPv5Vv1+aJY+ci+shl/RfSLANnIeEf8rWZpr9i/gEDJ8BFu+KzX7XRhlPfou3W8179d4tPestf33bGqwaQn20WARpPNdUAwvPtovWWk63k7y84xW3//NLzWzVA88ltkaPvzFaNIz6tLWK0ndNkze+f0FAA4dmsGkF2Jlm03nAa4Q3zA/wPi5//8n62ehC4yMgJoPpx+3qLXz/vf9y+/DMLgW53CrESR1SPTWGEp8faJmo4XTZFk9VtJVlDHTcFk5zXK7HE5/m2UOKTbi1a20m4KaD8pFwJ2HiSbgrYcKiuJGw9dPdF3DuZSQIefzBpPvVXYvZdCjTFlV8qVXI2Xjq17dP8sZzm/Vn2eE5zsE98kF5rsMUKjg02/Rn+49NpINm0hoe8huOj/XT92+n7x4f3t/07Bq3n+fq306fzeo6P+ePzw6e/PdQ0XBLy6fnh093Droo3R/x4e//5+fTt0/Ptx+lxoZ9uB04oeV2n87qeb48/r+SdcOikkldxiTPKzeNp+t1/6q/HeQ3XR1Qiv32YHquaPrp28/Tdw7vTziUXm3lkWOcXGiSwd+mJGvyalr27FV118p9XG+Xzsul2dkoYitbwuFzDQdF++eNHwcUwzPTLH+ILYXmY+fq1L87rwv2BNp2on++nY0q5H/V1ejcYnt8QVETD8wxjA3jg+4+Wv2U5Q3+/8Hkt39/ef9i3SjT3Bc2y2Jzsrg7+tqEbukog+b1cSyzZbVw5VsMdXEssQY9rOZO087Ul0LvlXtKQRfBATUsM2T1OOU7D7U1LrP2+nXIkYbdOSxxBL1g5j7QDbCcQOgaKr38KC1z2GqjWqPg6qPRTa9dC1OtcuQ6qBqM1nM5rODraeZnKPft+uqfFSo4OON0cj6V7OK/h6GjfTI8F3g1uu5vFSg4MOK+Wblh+uK7dylUjLlfzeL17O9cYkvrMRiO+ruQCAb98+K/r2+f6HXs93ZcP03hGwX16e7Q/vfzysYCvW/CQmOjE8G5n5MR6vssOnwBtNZ8T3+2Scq2zESV4WWa8eelNwbvWwRzC5nd7gWEAWdevLMJ+fy+KIOzklUW4r/afoeYF3WWyptuuod/1jasQ/iH2+7fhX0LYqd0QQtKTXYwi7r5uCLTfZ12MI+yoloV5eLz9cHt/fff9yFY6r+QSW2sVsG+rreIduvXy9f3982P1SUF4yqHr+pclD4oyfzSrJ8un10UP/qO1HwBWf7DjDgT5F377j9PN52fJZftqz8sLn14XPiDQfeNpOi9wwCni7uHp9FPftRIte+wF07vPjzsjrVCQxVIHbBG60/nhdP3UGiMv+Xhe8qgorRdQeamjLqBO9+9u7z/UmA2WZ15s19aEF5LnuVpjLD5a0BtkyRX57dhlrcjT+zkkL7/7cDObbxBHwEvPVzbyOn3gbmwxdLC28q///vdpwn7tLpbLi4h6swVNS3qxxY3//uvidCdofJ6/u/FtLVWfKV/MM6BedLv20gMmGy5bWehiA2b32pQMma392I5Bs7uR9neE9kCSjpHdTSU96bfHEwDLXjqps7SH2+1Q2Ysm613pCCYz1914DfTaHlIosHshWyC2Y0vud1rtbkVhD1Z7OEF31l44ad9WRzhxv8FuxrbOg86ogh4EUVBpN0JnzJ17ZlFEyY1ze7z2DqO9sJ29R4PRDyiErn6lwdiDhdHcs9JxqSHrE9u92mjoIOsMKegtE6WUdp21xxR2S+ylbOmj6A05dPKU9l60hxP0Le2Fk3Y0dVx2iLo4dq885P0dHWcjQVfQ7tlI2i/UHm/H2faSSdCtY4fYH6W+v0cIx6nL4oF796kbVzBgdTvzwL36rowXWhPyOPhhY0ZaitMCpfJQdQ4oZRGYQEOE0/Vvwus5kOR0/VvLpZsk0Mfrf/zl8fr3dw+/95TNx+t/vHtd+qhtJL0dA1uo6TZMFEZ8TQjStF0DiuM03BQUQrXeBIijiS/6C8HaLvIlsXpvp7YBh26jmqMObMmB26bmmJ27RudtkiReyzXfNljztZ7sqC+9xkMH/aZrO9HJeZpJeM8Dzs3Tf7Xc6kgiNd3TbjO138uKQ4nvYQup2u5dRQUu6y4Htb3tJn9+evcvt0//cnv/62l6S+W7sWAt3eUgXqmb/NCQTd3l25DFbvJDQ0oeXyolxE8vHRpPrEnbdFCRjq1CKTWACkTEcGg4OROCwwnkwQtsu+4td2iwwi11m4Vvlrg0hOMGGxR8+xv7CbwQRtoNKI7SVtXj8i0O1nSgGjZvcayGM/igdssjtZ67D3Fucbzms/Yhwi3fei3nnGHbFsdq6kkZVm15rKYbx3F9bQtGsw8lu7nb/1B0V7TG7oujxgC0hWzquDhG/8UBRzqDjob1vtCjW3ewb+hCni4Je4H9vbnX4RBGb4vX1P9wDKDL9/f7u+9Pj9MnlK4/9B8y7+8+LVdycMCBWEeHabMf6LztACSK1qpAIFsXBYmrbPiK4f5iB5FzvLHrhjnfRS4d7u++eei/B/p0f3fzcPgt0Kf70QPvp/sLHXZf99PxsnvZYS9WfeuwY0W4TnuRWnyJO1SSL0EvUZmvW3T83Pa6RS92inuJO7o/vWS9zG61OMcM71eLk82ldiwed2jP4nkvsWstAo/sW4uoF9i5llt1eO9abtVL7V6LwIP71yLtZXawVtZFg+J6bPfYYaKFZG1jRMWxRMMbC5HkYxvl/YiNYxeOGKzacKZpGcUwPkxVXvji4aClsm8bC1oLtnkQmBYpPwf8Mnn0WdG/3r9/kA43Xc47AGIyxtg01gIYq191AF2AMK1oIYnUwhXbSM1QIYkkHlKwzSN+H6o4zM7bUAs5JE+RiyO0jFDeRmkeoCyJJDkZbaOIT0PCCC9HtX3OgmFelhdyliSW1HG3gZoEVxJFbN3bLG3KXQiDj/wtgyL4/BceEgGbkw+I2Py67uEQOEhDlR46FKKwWZpL5MhhEDhT8y503BAIHKjx+uHo4Q+FUD3XEUcPfcDRuq4njhz2UNhiLYMepJFaT+vgZqDn1H7kaAwcq2kshjiStCOukKmp760plBznK9EaSb4poBTiK/Ga+F0arnOIA445MsChK/DYVu0f3NAVtn/H6RvYIL4GaRjWULgMaR3U0BRNOqShkq1pQIN4v94fLVDYm4VjBcRBxCMFCnnaxglIYzWMEsC5WscINPzh5JpQ/BM2GkJLuMHTbOvghdZoItuqZ5OLVkM4iWMVY4n1qiHQ0EG1ccBC+8FitMw6Byt0Bh0put6BCu1RB0qwfZBCx5YcPez1DlBojzq273QNTug4sQ3uQ90DE3qjDuxF/YMSOsL270c9AxJ6tubgntQ/GKEj7NC+1DkQQRpTqhgDoN4QpVEzYKge0ThY+ws9aI3WLz9oC6W/dLBucX5xz55U+Qvdek3GXwmFhf+vU5Yvi2dnt8p/nmVU+qezk1T6l/Ne/L1Sm8ZaXiu1+lUHdO5uwzR37EoiCfoMtkmk/QWiAOK+ApCjrZ9AEqehj2Cbp7V/QFQzggsPUCvSKw3Rn0jY8Q/+QC2d/qIo0stbkKXpelYcRt5FXYjU2C0tDibtii7Eaup+loTq7Njfxhvp1G8O2r8V+zvzm0P27RB9nfiScA0XhttYrReFspOM8IIQnWNaLgYlYVp4Y5unmTbEkaSsUcjURBqiKhINsQAF1P+aKFGshqEWINzoS6IkEVuGXGwjDr8iShJRPJxzm2/sBVGScNLxRttsQ6+HElWfcMgKqDw0XOXIaOKhY+AAMvRqKPl2691qR8bCN8Rt74XaLnHhQZCFBuXDIMFv7B4IWQoj7N6SR2mq6PH3QsmDtRyght8LJY8lP2MPvheqIVLj2fqQ90LJ47WeqQ95L1TD1ms42wy/F0oeq6VDYvi9UA2xWu7Fxt8L1Ris7Zb7qJcvNYZsud0+5uVL8oADHRhHv3ypM/To1h3r0rjQy5dEYS+wU7Xexh/y8qXGeC239Me8fEkeUNqxDR94benePuxVS8WDTgOHHP2qpWKmdho5/FVLpWw9THKBF3pV/pyNIyDaAg5fJbQOp2yPJxqVs5dPPh6nKaBkJE4l2mUOHYPngcahlT0HkvGy6xxe2R12rAh7h1j2xB0qyfZhll1bdPyw2DvUsifu6P7UNdyy6yQ4vF91D7nsjzu0Z/UPu+wKPLJv9Qy97Nuqw3tX//DLrsCD+1fnEEx5VMkgzFI48TDMhn6wNtA+4r1GLUfNBtwef69Rwx2edMRj8TavacxjNdhWXb6/vf8gHYa4nPfiwxA3jbUMQ1z9qqFu+m2Mhg56UYyGrnkQprVTXhKppTt+G6m5I14SSQzl2zxt7z2ShJG60zZLkziJqkdIE6ByWlBCEkXMhNssbUAo3y69W+WwGC1Dnbdhmoc6SyIJevi2SaR9e6IA4l49kKOtP08Sp6Enb5untQ9PtH2ErAe2TgvoiaJI7+pAlqabOHEYOTgVIjUSkziYFJUKsZoYSRKqk+m28UaArjlo/1bsR7nmkH07RB/Eic518tsycMJrvCGTHeGFt2LoAN9yEya6LGkASnBl0kqT4khSlCxkauLIQqjt3eCP52poGYYHF7rwSLxym/LBePjHdo/Hq0QSXmU3BRJfbtc2VdN1d1M86T1SJV3TzVJTONmtfyVaQx9AW7CGzoBavNZegaaQLd0DlZDN/QRtW1J4Y1zbii13yE3hpJf4lXBN1/pt4aTXOLV0TRc57fHkF7R7IRuvaNujSi9p94I2XdM2xey8VagEHrln6I9+wJbuv4vojz24q/XdV7RdajRcQteuNlqvpdtDSi+q91I2XV03xZSM96ukEwNu24Fqv0+wdngSdg62RRL3EtaStXUXNgVs6DesJGztQGz9s8pJvv4HbtT45phHXHO0DgjsCikaNCJIKR8v0hpTMlSkHvBiB5nxc0jjEMHOQ84h5dg5UHAk8nBx9g4X7Aw9WqrtgwZ7t+4hh9HeoYOdoQ/Y27oGEPaeRo/Y67qHEQ6FHt3v+gcT9sYe3PN6hhR2b+Ej9r3+gYW9scf3vs7hhW3dZHI7qvWUNSJS2x1TwxiK2p1T62CKppCSkZqVcOLBmm1bTjrysLbZmgYf7sUD4vTH/Q0dPpvECS10aXEqttkgTvDH9otTOZK017olkFycKpuqTZxa4onFqZyuTZxawgnFqRytRZyagrWIUyVeszi1hGwSp3LIdnFq2pJScapsxSZxagnXdBItB2w/ibaElHRDlrOJuyGbIsm7ISvJGrshWwK2dEOWEzZ3Qzb+WRuu4at/4NZr99aY4jvQesq2O8+ekLI7zv2UDXeajTFFd5jVgPI7y8Zo0luzarqmW7K+Q84h5djbDTkQebg4u7sh+0KPlmpHN2Tn1j3kMNrdDdkX+oC9ra8bsvM0esRe198NORJ6dL8b6IbsjD2453V1Q/Zu4SP2vYFuyM7Y43tfbzdk09FCOiCucpBoGhDXFO6I0/AFT76Nw7Z2QrYO12qOKh6mtRO0bXhWS8zeAXHlwEMD4rqjH7ClBwbEdcce3NU6B8Q19YS2DIirdIY2D4hrDikeELeTsm1AXFO3WYNAVXrOWgWq7VpW+DxT9Rq25cGmtr69acYfTtdPQ+dPWsvjeS0HRxTxWDmbnMeatpuYxypbrY3HduLhj5LRUvwVHbTabcqut3NglZsOw60ox5f5J5gcbLKN5Da/dEjkcKCGTn1pnCaPK2ymZo6ThmvROJytGeOk0eQWh4M1Upw4VqPEFcL1QJw0YqvD4YhdDCfeig0KV9iCrQgnjdZqcDheF8FJIwoFDidrAThxoCZ/K+Rq5zdpvEZ9w/l68K3hD9rWcVX803b0V7WEbLnxK2dsvuVrjSjuYq1nbOtZbQgp7VAtxmvqR20I1nC3XMzWeqvcfpA5ogwHwK0z8GhRjnBbe+TBEu3Dto4te8Rhc4Ta2iOP72Pd0NZxwjxgXxtitt7Ig3vbGLJ1hB7b33qJrWfrHrDHjQFbR+jhfW6A18Q3HkMVcJnjbAP4FY5Vrd4njnbANcDlzvztJFWJ2CFRTUFbAKoSs9mdpCEHoA/HHXW+ruDjW3lM+bpCj+1g/cYn7lxtJL5C/2qP8DVFbAG+SsZm3xP3x7XxXqFLrkP35JfPDbhXumxutT1pOKmb4VxNbCa+mGhRs8IVRTOaVcKZBZc9Xy8215frx9vrX+5eU01T20CKr/vPHDVgG+e5GvFLR9zYn95df3o+Pb60Oa8OtTjP2tawU3pxpXj/9Pz4+eb5obm9r9fLVv+u6OcVyu3d7dOnh6dTLoXmTPPSsrd6N6T6cHpeF5s00IfT89O84FFZnnqzPB2f5fPT6W8PNx1/qM9Pp7t5wQOzfH96fLpd7K4NaT69LHpgnr98/vjxj5407+YFD8xCs3ceW6ZIVDrXL8sflezm7nTdceyZlxpIsRl7Mc3+l+vnazzk4jx1YITDYjhBedVf//3v03/vc+TLUnmB4vFU9ovmZue5j2j4918XF/y7Dc9zdzbMz9t/u/2yc10wzTF4vp5WIdifFrNd/DzN22o9Ry9/0uj5eZOl+dwsSCM5L2+CtJyTBRkk5+NNhpZzsSCD5Dy8ydByDpZlEJx/UYqGc68sx+55F6UQn3NlGaTnWxSl9VwrSLR7nt0eO6TnWNz66pj88Ljs5d8ekWn6wL0aLS+4W1vN1zhocnO9QCurXDG8TB/9YTuns5d5BtrJg8gqjeQZRjdZXsuf6MNuPy0HfK63HJ/tmGa/ub6/Od2xgdOo4eWMBzUNhmzDll/nO6jhh48fJ4KvjSaGsx7TfGXveJ1h4JJ67on7kQ8CrDY1X3LOy0qH/y3XUr/ynbu72CWSJNK8pPASSR6I/rL/8/Ppc32H28Sh5f6/ebmjwkwl3rVxaMHDtw3t63d9ic7LHh1q+vLll84aeln2gFCrBwXmOb/9Mi1f7gtezjbyOIBgsPumKfn49tWP6R03vm1fNlRc1LhsdDiI0DAgXBJEOAZ8G6Rl2LckiOSToNsU4q+Biv4o+4PNwR+k7QRTDbD7Kd1t87Kv6EoaF45n30ZoGcIuCTKP9PnpYW9o1jbKvOjzg2gYVkOYH3+9fd90WDxHeZoXHP/z0NmosTjzQscUJ23S1vanZY7bN6YTX2OC82IHbQOBloKtIAVSSQTBk1jbBNKHr0R7xP5YL7A3CId3iQIIBpyABNKxJeIIohFGhSDywUTiOIJxQ4Uw0iFCkijtY7C2oTqHXTXH69piXYOrmqM1l3fzECrRBZFotA+4JpIP8JGdg/fH9KATsHAYj+gy+f3703QmOfX9dV4WP/TPIxzUBu6jGsaxiYMIhq4VkkhHq4lqpfrII6iS/accRRcG9THZ4JpAMAxb0vDOkLJtw5JRZIWGUX/BRAS3T8+3N0/fPbw7CbY9W2CgD+E0xfvbrWTDo0a/puXvJDKFf2p1r5zWLdgVYLC8e57XcGC0fDvw8lb3bx4+S/p6YMa8qpcD/c28qiPDTvcO3+eD+FDSaT3zyeACMeeD1/lhuP6c84rOT8NdKuh0wXNAzOmq5wIhnx+vb++mLv/nh08jKc/rmS7QLhhzusA9IuZ0kXuBmL88nq5/mw4kIxlfVnKBgOe780MOSeeVXfKgdP3lRMb8+Y+hpHktv3z+45iIJZ+blvj8ehZCvpBn+ScZ3aKxIaWb13OU021j9UidLJTQ6kCkZq2TBZJ6HUjULnaySA1mB1J1qZ0oWIvbbYP1yV0p2HJ4xx/3N+WhHX/c3zRi//Iq/4/7mz0RPM9yYQ1cNSOXwJcf0KuA63ZlArjbqEz/WNMN8rcXQKh+6wAt4rcXQKJ969bF0re78feVj2144clpr+Fd3Vs3K5O9vUaFqrduukX09gIIuGDduJQKdhsW9NSxlqWdc6KmRZ3fIIC8w1sUQ9DJDUJIO7b3IrRzwDpMJwU0xWreQl0E0BSpqWybu/53j5Cibn92kJR3+e+WraC7n5WstKt/r2lhjzq7FmnoTRcFEPSkgwTSXvTdzV/tQWcbfr/3fP+vLXglIP9zS98AuNe47IV/69Yb3u+3e3IWveqZnZvlL3bea14wlGDdtnQYwe7vFgyjYL9aOoQCNM1vaORksZ35wlxRaFBOFeDnDTFFKVADUcgjTeeuvW61UqBpWVFnmjwO7Wm9eWjh8UCr2/yn59PHyo3+NHlsXP9Pf358+O30+M3yOcRl58Ziev/DjnNXhmT9X7/MW9uCy9SV3/aXzx8//fX+6XnqHyr/Qj7XZX4nbEX4aze/o/Kb//bwofxT54mX+YXLlQt/2Dls5fd8d/3423Ti/fP1U6Hd5RytO4N9fQT49+vb5397ePzr/eKypN7O+Unn69vn9w+Pt/e7FyfrVWwH5y/jvPu86BsT5ZiXGArAN/7p48PjH/u70Ha+y5RYoR1htYFfU/nty7fV/L/Pt3dP5Z8PZ73MFig3JdwI+GdVtsP8CHB5/1vMMHguWqypvLHZTJfZzKgR4QbmP0Lwe8/cur+j1Za47JYotti4WeBv3d9G31zfv7s7iTfQdvaLbp1Cc22bBvzE/e3y1+ny9Mv1nXjLoAUuum2KDbZtHfhD97fP3x4+iDcNm/eiWwW11bZB+C/b3xbfna6fPj/KdyIw/0W3Sam9tu2CfqVk28iudIqzX3jLjFz3lH/i/nZZXi6It05poYtuo2qjbVuq+KP3t9fckSveVGD+i26lUnttGwj9yv1t88NpejxOvGm2s190yxSaa9sw4CcKtsvt02/yrcJmvuw2QY01bhH+4/a3x3looHiboAUuul2KDbZtG/hDBdvn9PTUcjgG81926xTaa9w44FcKtk0e6iHeNJvZL7tlcHONG2b7EwXbZXqvk3yz8Lkvu1Vga40bZfP7JNuEXrTUsFU28194u+D2WrfM9ldKtk0eetawcbYLXHjrFBps3Tzgh1a2Tz7D73QIspkusx1QI8Lfzn9E9fd+enis9P69Tr9k3ztrpb3nfbGCer/774+3z7Kfeg4xLzDQPNvk4vP7P+3EPnhGbzyVC89V/6ST1NDZqem0NB+pd44tfK5L/WrQivhHs9+BB2b8dHvz285I85dZLjvSfN2MeKT56w/oHP7L2hUN/91tdG94O2tUNLx9v9HdEda8WdkI692G98cas4aFY413G64/hc0aFTyBvdugbFg3a7hhWPf+pt4fpsq3tXB4qqxpyVhiFEA8hlgWY3/sMAohHDO8G6F5dDUL0ze6ui1W8xbqGV3dFqmpbFtHV+9GkY0x5mch+RhjWYD9McYogXCM8f6+k9fz7T9ON5+fT/ITxbzc6XW5sRh7X1jmzYs+qCxptvXvL/5c8n7j89v15FdA55fqDV8Bnd+lJ78eOb9Eb/iSpDqofbuth0/PkoHd/OwsHti93zx6FfZu+7TQMQHefX68broQWywwWGK7z45sSkz27Mj+Va/kqRl+4St+akbwy69/+76lyqeHKMYr/f313V1Ls9P8fc2u7hZXrwmZHoyvBNjMO3D/uHsThxsT3s1tf9XOkbT+VtJSmIZXk8ojCe9ICpFabk3kW6lal6WNs1+cDX+m/Webyn8k4UNO8jiip51KeeSPPTVsn/379dLWEd64y6MIbgxKWaR3Bm1hRPdztUjyG7q2YII7ulos6S2dOFT7XXAhXuftcF/Q/q3YdYMsDim7jClEa7ieaTiI7l/SFY+hwms7+dbZ608tbZhtx+rz07t/uX36l9v7X08TGr0biiV6oUgxXOnNIkdGlL1ypBSx+O6RIyMKXkpSyoffTnJkuP2HdUvZ4FO7h1bffn9/qfJQx/+R0STeU8iG4efQcLKewFK+Upfg4REFfYW1jLDT8MiQLZ27knPq5lru+J2ld1e5WKwdwSqE2lDWYKT6Pf7qk/ENWTefrO+046WP9zT7tcTL67+6EO226di7DbZPr12xuo6+YLNJCb4rZM+JdZtR+GqMvojtV53bgDLa74vXefUJQsrfcdcXtfcqdBu14W14nVu146oKbFHh0IquiL3dkNuYQ12Skqi93ZPbqENdlaKt2tErBrZobw+ZKGLPlRbI2N1zJg7Z1x9UiDrQJyQO3NMvVIjb3TckCXtAr9s29lE9cM0/4JitfkzPXHP48R2xeZBL3+Vg5/0uuCJsGA7TH7XnvreQVTpwpu+40eZc4GjRYV6y64Me/0JXB90WJonZ6WLbnCNGJvxDf58vlK4/DF7FfLq/+7Rc1WXCHnSZcH/hA9M56s4HR1uySj5A2h12Z9CaLKZkJFtvwEMO8vIxb4MHp6PK9OUodeFqXQc/omjXyS9Yuy/RDyjhl9CXq+TXLX3UYfd1S1/46PsS/Zh98SX3JXfJxYn4oH1ycUa+7E7Jox+wV/Lsl9stF+HH98tF7IvtmMutfdCeudzal901F+EP2TcXyS+5c7YK0Tao5MGnvq7SvjEroLd0YPyK7KjcMZYFHY17x7WIukr3384t6icVvrJbHBLhYP4A30fRAODXef8JA4BZY20DgBe/6pCedx6mo7d9P1JbDzuP1NGrLthKko6RzcYRd4ZI/kzyDpDtH6mx02M/TlNHB8/T3rkh2D5i6thsnTbeEESRX3BusjReWQrDtHSqw0jNHejCYPLOchirsWN8P1Q3RfB4Y/zQGLR/K44ww37IpospHq39AkpyEBVfNG2PoW0XSoKtIxyKsdkwIwOABbGahmBswo0PAN6P2Db0gkc8YADwfsSGAcA83+gA4P1w8nFKPNvgAGBB9YmHqmwqb2wA8H60hiFoPNvoAGBBuCYQ3eQbHwAsjCiHUJhxcABw43m17xruqAHA0p2ld1e5WCxZ9w4PNTAAGEaq3+O3DQDGy118AHCl2ZYBwIVfPTAAuBZMPECwLVbX0Xd8AHBbyJ4T6/AA4LaI7VedgwOAG+N1Xn0eMgC4LWrvVeghA4Abt2rHVdXwAOC2iL3dkIcMAG6L2ts9ecgA4Mat2tErNjwAuDFiz5XW+ADgjpB9/UFHDQDuCNzTL3TMAOC2sAf0uh09AHjgBxyz1Y/pmbvQAGBx8IvtkL33u4cMAO6I2nPfe8wA4MbjRptzjQwAbr0+6PGvAwYAt8XsdLEjBgA3/6Fbxrvs/Mmbx7m0hz3oMqF9AHBfVOGoLUnWltFazWFlo7R2YjaMzmoOeMhBvnkAcO/B6agy7R4APBT8iKLtHwDcG/2AEu4ZANy9pY867PYPAO6Nfsy+2DkAuPtEfNA+OTAAeCz6AXvlyADg7vDj+2XfAOD+rX3QnjkyALg7/CH7ZvcA4LbYrUI0NAC4sau0b8zKEQOAW4/KHWNZxgcAN3aVygcAV/tJGwcA74Zc4uB/Tn3aNMO3j48PjzIZrCx0MRbca1NigrUf2wGCu5F2taAj0GmacSDTefmDY308PT1VTx27wV7XcHC0fZfczSZESVk48/qxqP+6vvvt9PrX/HL9eHv9y91Lrjy5bZda7tx5+W8ePn66Oz2fvnm4f368vqlsBzz/wC79O62wboSVRr/OywtksPBLOxm4FknEv21xZJZaC9VgqG3RBCP5arnwaL7RUB9Pz4+3N32JXpY9Lg71S89fvKxeg9Zy0Uqelis5LuAvp9cvcvalm9bw9LqGY6N9N/DnnJa/wJ80b7Hr584/Zt5cefGhUOhgLj2I/1MP3kMH7SOPjoNHxcOOhiNHwWNOXt0nrZ3mRWOUYAj5mCRpFNEeus4g3yslJ6H/vL773LgZ8oJf5gWPCtKT4ZDmW47gQ0fuI89xg+c20R5ye3r66fRU/SpbZS+5nRZ92v82myxS8yXK+KXJ9lzGvsybZ2SlQ+tYZckzjN4D/Uij9/5y/Xy999tf5xw4dbYcJFmD7YfJxW/rHgFZiCIb8yiOITpzbULIz137EfaHBOIQwkGA4hi1gSaFBLtDS6SNiz6qh0PIv60nDTM50k+37XvJtNzz7WF7CP2wnhy04FgQcLR6vn6+fXq+vXn67uHdab9U1rMfcNz64fT0+W7/2go1/HL8enxZh2C7sB88fEcCkxVuTPYftWkKKTzKwU3X83BrU7iWmykYceD50aag4lstmLL3KdKmiLILb5gPXPgeHK7xig+mrF34HRy35fIdZi1exV8gqOx2pxjz8n98cfdVZVPy++TxiH7x9p937/5EL/L58ebX08fXa/L3n+/pv88p2XxtZ7Z1e9/OB679FtdzjrT5b9NhaL/BxWwjrf1w+/TbfmOvc4209ePt/55eNbXb2nK+ofbmXVvQ4mrOkTbnet5tcTlff3t3tx/uf3r467Sfflk81rxpbz1fd3u/nD7c3k936ad/PBcbW8401tLq0ho2M83R3cbN9c2vp2+u79/dLU51vJnlTP0t/Xq6+W23pcVM/S3REI7p8Pfl+pkODzSgptwonn+0/S+nx+sPpz9//mOv4ZcZB1v88+Pp+rfTl8WARdzgy3yD7X1D32uXbl8292jb093j93kQ0l7Di1lHW6UBRT+u359QaHUx62Cr80NAq4fDcKOLOY9rczUec7fdae5j2maP7VRbzvMe2a78V7/OP9h+LhYa+7J3zFjOOtjqefDb9PzhTqvLWQ9sVbCp+ewHtT4N+BO2PM16YKsNv/k8e3/ri0PRdJNR+cl8zu42333++OlPH073z3+6f/p9MVCLt8jmG2rv29UAP9QSzTHUxv+z7PtFTUwzDLXww+nm4bF8Mn2dZaiVn6bRctVGaI6xNmpXyOcZ2lpY9Md9vH1+Pj2+nhE/PkzXFefVnye3rX4xwHB6Xe6X0/fTMefzL//rtBg3wscavjS1WUTQ+MvShRTvn0+P396/k2dYLzCe4DyA83zhNj0QI05TWfiAZKf3D4+nH5+vH5/lgTbLHJDjfDktT8GWGM/w7uH+9OfzxpbGAAsdk+Rvt19OTSkWCxyTYO5ZaMmwWmQ8xfQczB/iAMu5D2h7Os19m2cRtL2Y+4C2/3H7LG/6debxln+9/fDr6ek5X46LtzxaajzL7bu7tnMHW2A8weIRL3GI7TLjOT693hqKc2yXOSxHY3WgpQ7Icnp8//D4ceoQEe8q22UOyPH48OHx9PR0PgnIw+AFj0uUD8bNeVaLjad5nHr8paWymHm85fNTgE3HELDQAUl+/fxMz4lK/xZsgQMS0O1oc43CxY5K05ji4Nany6XGBItFjkqRe5/k1bld6IAks1nlpzblWdBiB6T54/5m7miWR9ksc0yOpgCHtfzl5Tk+cfubRcZT/L56OkScBC52VBrx/vr7seew3+exBQ+fGrfDYpHOFIvuILp0Ya++5D1Ci3m6u53yOv7n5+v759vncif6erbu1j6cyv1bH079HbYfTs+iQR5svqH2Pnx4PH2Ynpb/6fH6XUVowbxD7Wb8rFcGm2+kvfP1wITmNNat1uhm5qGWd3V2OdNIS3vI/jrLUCvEqnt/t9e5htp6uPv88b7+i/IsY63cv78ta/LLHINtVAeOvM4y0spfasgzTx9a/+n99ec7yZ9lPechbe79kVYzjrT47fv3p9ylv3kTFGh2O/dQ27JBd5s5R9qUDLpbzzbS2t+uqd+5PpaCzTfS3nevnVt/uX16njpSvmfvMQStl5c6Pgt4j5Q40euyQ7lu7z8/n55+vL2/OS23ex7MUkbJ/UWHUj28q2+Rh3dDv/rfT/+QnDMXs4209h+P706Pf354+K3W1stMIy2dbyt3d7HVjEMtzg970Vi601wS1ZbRAkck+Obh8z11QzWE4MsckeO8qzbEYIsckWJ9bpKEWC9xSAb2orla43nWo1r94z++nB7vrsujmwrzH9L+0/Ptx+vnln2BLXJEiv+RkWtx6hCc+nYXvlgy2YlQuIoDU7ZvtOO3VO/mudg2IRoT3dzWlzw8U8NVnmT5S+br+4uW13J41obDF1ru8Dzi89h2qcOz/LT5xJg0z8uSR2T66/0Xeu2FtNaX8x/b/uf7xgCf7w9J8LfTl9OdqEbznEe0uTjrNOwj26UOztJwzLvMeX3khH7JM/l37CXZrXmOOoIs1tl0/EDLHZFnfpah4Up5vcSBGUR70HneQ9qV7ywH7iGvpS1seJ77iLb/6/r2+fb+Q8MRa73EUAb62NXNdWX4+WqukbZ+uP5d0LHzOtdQW/sPEa/mGmrrM73C5a/37x+qjb3ONtLayzN7+z1JbNahVk9PT1NvyPLNU6jF19mGWhM8HbOebaw1wUPgbL6h9mQPgW/mPKTN5+vnz9X9bz3nUJvrN8igtmiOkTZEp+tDzs0/TW8RIUCt9rwvZhtv7eHpWdriy6zDrc5nNmHDq7lH2ha9poDN193er9dP//4g65HfzjrWqvT4jWYeaZlGh+yBN5uvu73b+b0OPz6fPn1XPtysZxto7fXm+aeHves4OHf3k2l3t78Ux3Dd3f7Stl7+fZWX1+7/j9P0db4fT49flndJpfa+/vvfp/9YruBXWsHTywpqg8em1eQ1lKKd3571+qGAxmjnFbwONzwq2nkwaXe08wqOj0aDlrpz0dLHh8rDC7tT5cUv8Geka63+PyItfnys6bGC7lDTwsdHuqaDW3eovPjxsW5owE93rLz4JWJNQ58GYk2LHx/r/GjuD6dPD4/PjaHOCz/SwkdFurv9cuqKMy14bJTzozRdcc4LHxtp8QBYV6rF8scGywfkrkx50WPj/Hq67ivqacGD/2S5k7Lvz5WXPTbQy4PnfXv9eeljQ00nqa4804IH7/Yvb/Ht2e1fXt97aKQ/7m/64vxxf3PwnrW0y75dLK8hf8b12HCLZ5e7oi0+YXnwPjefK7+7fvyNnqzuO9V+nBc/8mTbGWla9Og453NmZ6Tz4kfHWpw0O5Mt1nB0uHz27MyVFz460nQO7Qw0LXr4ny+fRHv/dHnpo0O9nEZ7jwjn5Y8ONp1POzNNix5+SJjPp72HhHnxw2P9cX/TG+mP+5vD97jVcKvOXW95Wj464OLE3BlvcWo+fF+cz65/e/hwe/P951/ubm86z8930xo+0RqOPEX3B5uWvkCofN7oj5WXv0Cw9Z/yMb/Ld+RvmVdx/B+zK9rrX/PYWMs/Z1ew5d/z+C02vaDh+v5dx8a6yUseXV19gc5LHxzq5YUFHZHysgcHyp3g//fdwy/Xd1395x9o0SMvaLrCTAseG2W+luxKMy97bKCXq8iuSC9LHxtqGq303en5ujHNtNjH0/P1YX+safBZRw5a7sggNxnFO6LMSx4Z5jGPJusIMy95ZJgz534zvc6zT4JvHh4PO1e9vlCoOc550SPjZGLrCJMXPDIKIXJHElruyCCn1XPynTXzRAsfXTVdkc4LHxvp/evD/T1/sGPD/L4YeNV1eXPwn2sxGrPr6ubYOI8vQ4k7rm6OjXK9eAtR1xHn2DivJ4f7+9PNwGChm5cVHH+i6Iz2ero4Otp8pO7MNR+vD99etOP0by1a/PhY0y7UHWpa+PhI53N+Z6jzmf/oWPPNS3euefnjg73cwnRHe1nD8eFO/zjdfJ7/ntN1fPPxa158vg04rC/39Pzrw7u+THnZgwPdPXz40DxKNS80EGExEPju9kn6rqbtrN3Dj6dVSd7WxOYbau+708eHx/IrFV9nGWpF8BTVerah1kTP4fAZx1qUPYmznXWoVdGTDnzGoRZP8yt9vq99n43PeFiL/3G/OBrstTrNPNry/NWVvTbn2Q5qTfIrF7MOtnp+Geb387vWd1rms4+2/vrhlr2GX+c8rk3BpmZzj7Z9vrb405fr27vqx5pKCxyeQLIR4EKDSf6y+E7NTvvLWQ9sVfDL+ewHtD69s13Q6jTbQa0Jf+d51gNazSccQZt5xsNaFP7S15kHW65/m24xz2g7/6h8MvN1lsFWVm+x2WluNe+R7Qr+hJv5B9v/6/yVnp1mz7Md1Jrghy5nHWx18YaRnUYXcx7XpuDHsrkH2158u1Z6rkWLXCCFYFOUFjsmTd5vGrcKW+giSeRbBiw4muh1QO9ehNc5B9ucbnd3GptmOaAVwZY9zzbY2o+LrxXttLic9cBWBb+Vzz7aev0B/OVMh7QkvGpez3xoy5JtvFngkASCq+fXGQ9rUfx7D7qGFn0zfDvrga2Kf/Hr7Ie0Lm73iBZX34vaa3U186EtS37zZoHRBH/c3+y1+cf9zQGtSH7dPNtga69PY++09zrjYIui+9xD7nH/a/UVK1GL55kPaVnwVzzsrjqvSNgjuZ65u+WHL6fHx9t3J9EXmtDMwy0LvQnPPty6xJ3AvMPtCmRoO+twqyIhQjOPtyyTIjz7cOsiMUIzd7f86frx6fSnxw/l3fhljv428quX/nL7/n25ldd5Rtv56YFeUlZ9ueh21tFW//P67nP5CLycqbulx9P1ux0Pfp1loJWPD19Ou+28ztTf0sPn+3c/3d78Vi6+11n6W/l8/9f77x5uftt7JxqfsbvFp9P1482vO1twOdNAS+Wf8zTwKcSn/Y+/PY1//O1p9+NvT8Mff3s6TY+mfahcBL7MMdKG5LWpT8e8NvVJ9trUp2Nem3r+rnS5nXmG/hbOr5b88dfb99OL+qovCIdzj7Q9Lf/ydkBaaa3t7dz9bU9fep0vH8pNLmbqbun54fu769vpHrXW6beaa6Qt6vud+sb/8lx+TzKbr7+9Ty3VA+ceabuheuDc3W3PryYr/9TzDMMt7L3Km8033t7Dx48Pe322aObhlmXviYVzD7ctfVtsYf7x9oXNjrX2+/Xt8789POZSKTa2mmu0rR9O1+/Kx9flTAMtPX7c20sW8/S383j7vHdhvphH1M5/v/nq9v7d6R9f/ev/+erL6XG6OvnqX7/Sb83b9NWbr97fnu7ePX31rz/nCG++mp5cPtE7d9893Hymf/73PNt/nm6eHx6nmfPc/9fVV29+vnoT0lsT3H//95ufzwvTBPqP8zpe/4cWVF+9+VmhBdVmQbVaUH/15meNFtSbBfVqQfPVm58NWtBsFjSrBe1Xb362aEG7WdCuFnRfvfnZoQXdZkG3WtB/9eZnjxb0mwX9asHw1ZufA1owbBYMqwXjV29+jmjBuFkwrhZMX735OaEF02bBtC6AqR4UrB21LR7FqofKB9cPKKB1BampLhSsIbUtIrWuIjXVhoJ1pLaFpNaVpKb6ULCW1LaY1Lqa1FQjCtaT2haUWleUmupEwZpS26JS66pSU60oWFdqW1hqXVlqqhcFa0tti0utq0tNNaNgfaltgal1hempZjSsML2tML2uMD3VjIYVprcVptkxig5S+CgFDlPrCtNTzWhYYXpbYXpdYXqqGQ0rTG8rTK8rTE81o2GF6W2F6XWF6almNKwwva0wva4wPdWMhhWmtxWm1xWmp5rRsML0tsL0usL0VDMaVpjeVpheV5iZasbACjPbCjPrCjNTzRhYYWZbYWZdYWaqGQMrzGwrzLAzIZ0K8bkQnAzXFWammjGwwsy2wsy6wsxUMwZWmNlWmFlXmJlqxsAKM9sKM+sKM1PNGFhhZlthZl1hZqoZAyvMbCvMrCvMTDVjYIWZbYWZdYXZqWYsrDC7rTC7rjA71YyFFWa3FWbXFWanmrGwwuy2wuy6wuxUMxZWmN1WmGXXW3TBha+4wCXXusLsVDMWVpjdVphdV5idasbCCrPbCrPrCrNTzVhYYXZbYXZdYXaqGQsrzG4rzK4rzE41Y2GF2W2F2XWFualmHKwwt60wt64wN9WMgxXmthXm1hXmpppxsMLctsLcusLcVDMOVpjbVphbV5ibasbBCnPbCnPsqp4u6/F1PbiwX1eYm2rGwQpz2wpz6wpzU804WGFuW2FuXWFuqhkHK8xtK8ytK8xNNeNghblthbl1hfmpZjysML+tML+uMD/VjIcV5rcV5tcV5qea8bDC/LbC/LrC/FQzHlaY31aYX1eYn2rGwwrz2wrz6wrzU814WGF+W2Ge3TvSzSO+ewS3j+sK81PNeFhhflthfl1hfqoZDyvMbyvMryvMTzXjYYX5bYX5dYWFqWYCrLCwrbCwrrAw1UyAFRa2FRbWFRammgmwwsK2wsK6wsJUMwFWWNhWWFhXWJhqJsAKC9sKC+sKC1PNBFhhYVthYV1hYaqZACssbCsssB4K6qLAfRSgk2JdYWGqmQArLGwrLKwrLEw1E2CFhW2FhXWFxalmIqywuK2wuK6wONVMhBUWtxUW1xUWp5qJsMLitsLiusLiVDMRVljcVlhcV1icaibCCovbCovrCotTzURYYXFbYXFdYXGqmQgrLG4rLK4rLE41E2GFxW2FRdYPRh1huCcMdIWtKyxONRNhhcVthcV1haWpZhKssLStsLSusDTVTIIVlrYVltYVlqaaSbDC0rbC0rrC0lQzCVZY2lZYWldYmmomwQpL2wpL6wpLU80kWGFpW2FpXWFpqpkEKyxtKyytKyxNNZNghaVthaV1haWpZhKssLStsMR6W6m7Ffe3gg5X3uOau1wLfa6o05X1ul5Rt+sV7ne9Ah2vV6zn9Yq6Xq9w3+sV6Hy9Yr2vV9T9eoX7X69AB+wV64G9oi7YK9wHewU6Ya9YL+wVdcNe4X7YK9ARe8V6Yq+oK/YK98Vegc7YK9Ybe0XdsVe4P/YKdMhesR7ZK+qSvcJ9slegU/aK9cpeUbfsFe6XvQIds1esEnPnf6H3H3X/b/r/MwAUBAARAKvEjAAFBUAMwB0gQ0BBAhAFcAvIGFDQAMQB3AMyCBREAJEAN4GMAgUVQCzAXSDDQEEGEA1wG8g4UNABxAPcBzIQFIQAEQEzAkXd/gorgQJMoJgTKOr6V1gKFKACxaxA6cxRBY9CIMUqkQhAYTFQgAwUMwNFDKCwGijABoq5gSIKUFgOFKADxexAEQcorAcK8IFifqCIBBQWBAUIQTFDUMQCCiuCAoygmCMoogGFJUEBSlDMEhTxgMKaoAAnKOYJiohAYVFQgBQUMwVFTKCwKijACoq5gjIZRws6iniUVSJxgcK6oAAvKOYLishAYWFQgBgUMwZFbKCwMijADIo5gyI6UFgaFKAGxaxBER8orA0KcINi3qCIEBQWBwXIQTFzUMQICquDAuygmDsoogSF5UEBelDMHhRxgsL6oAA/KOYPikhBYYFQgCAUMwhlM9UXrB5hPatEogWFJUIBilDMIhTxgsIaoQBHKOYRiohBYZFQgCQUMwlFzKCwSijAEoq5hCJqUFgmFKAJxWxCETcorBMK8IRiPqGIHBQWCgWIQjGjUMQOCiuFAkyhmFMoogeFpUIBqlDMKhTxg8JaoQBXKOYVyuWBI4WRI2joCKtEYgiF1UIBtlDMLRRRhMJyoQBdKGYXijhCYb1QgC8U8wtFJKGwYChAGIoZhiKWUFgxFGAMxRxDEU0oLBkKUIZilqGIJxTWDAU4QzHPUEQUCouGAqShmGkoYgqFVUMB1lDMNRRRhcKyoQBtKGYbyudhTIVxTGggE6tEIguFhUMB4lDMOBSxhcLKoQBzKOYciuhCYelQgDoUsw5FfKGwdijAHYp5hyLCUFg8FCAPxcxDEWMorB4KsIdi7qGIMhSWDwXoQzH7UMQZCuuHAvyhmH8oIg2FBUQBAlHMQBSxhsIKogCDKOYgKuRBdYVRdWhYHatE4g2FNUQBDlHMQxQRh8IiogCJKGYiiphDYRVRgEUUcxFF1KGwjChAI4rZiCLuUFhHFOARxXxEEXkoLCQKEIliRqKIPRRWEgWYRDEnUUQfCkuJAlSimJUo4g+FtUQBLlHMSxQRiMJiogCZKGYmKuYhnoUxnmiQJ6tEohCF5UQBOlHMThRxiMJ6ogCfKOYnikhEYUFRgFAUMxRFLKKwoijAKIo5iiIaUVhSFKAUxSxFEY8orCkKcIpinqKISBQWFQVIRTFTUcQkCquKAqyimKsoohKFZUUBWlHMVhRxicK6ogCvKOYrKuUBx4URx2jIMR9znAcdF0Ydo2HHbNwxkYnGxqKBsWhmLJrIRGNj0cBYNDMWTWSisbFoYCyaGYsmMtHYWDQwFs2MRROZaGwsGhiLZsaiiUw0NhYNjEUzY9FEJhobiwbGopmxaCITjY1FA2PRzFg0kYnGxqKBsWhmLJrIRGNj0cBYNDMWrfIQePXG+bfG2jda6fmfbF1oPDwrStITjbVEA27RjFs06YnGWqIBt2jGLZr0RGMt0YBbNOMWTXqisZZowC2acYsmPdFYSzTgFs24RZOeaKwlGnCLZtyiSU801hINuEUzbtGkJ7rwTAXgFs0fycjPZBSeq0BPZfDHMvJzGaVnK0Albh7NyM9m4EqET2ewSszPZxSesUBPaPBHNPIzGoXnLNBTGvwxjfycRuFZC/SkBn9UIz+rUXjeAj2twR/XyM9rFJ65QE9s8Ec28jMbhecu0FMb/LGN/NwG1hKNntxg3KJJTzTWEg24RTNu0aQnGmuJBtyiGbdo0hONtUQDbtGMW7TJTwrhSgTcohm3aNITjbVEA27RjFs06YnGWqIBt2jGLZr0RGMt0YBbNOMWTXqisZZowC2acYsmPdFYSzTgFs24RZOeaKwlGnCLZtyiSU801hINuEUzbtGkJxpriQbcohm3aNITjbVEA27RjFs06YnGWqIBt2jGLdrm59ZwJQJu0YxbNOmJxlqiAbdoxi2a9ERjLdGAWzTjFk16orGWaMAtmnGLJj3RWEs04BbNuEWTnmisJRpwi2bcoklPNNYSDbhFM27RpCcaa4kG3KIZt2jSE421RANu0YxbNOmJxlqiAbdoxi2a9ERjLdGAWzTjFu3yU5S4EgG3aMYtmvREYy3RgFs04xZNeqKxlmjALZpxiyY90VhLNOAWzbhFk55of/Vy6+AVvHUA8qKZvGiCFI3dQwN50UxeNEGKxu6hgbxoJi+aIEVj99BAXjSTF02Qor173Rwebg6AMJohjCZT0VgwNEAYzRBGk6loLBgaIIxmCKN9ftIXVwdAGM0QRvv8tC8+TgGE0QxhNJmKxoKhAcJohjCaTEVjwdAAYTRDGE2morFgaIAwmiGMJlPRWDA0QBjNEEaTqWgsGBogjGYIo8lUNBYMDRBGM4TRZCoaC4YGCKMZwmgyFY0FQwOE0QxhNJmKxoKhAcJohjCaTEVjwdAAYTRDGB3ys+e4EgHCaIYwmkxFY8HQAGE0QxhNpqKxYGiAMJohjCZT0VgwNEAYzRBGk6loLBgaIIxmCKPJVHT0L4fHGODhEXiMZh6jiVc0tggNPEYzj9HEKxpbhAYeo5nHaOIVjS1CA4/RzGM08YrGFqGBx2jmMZp4RWOL0MBjNPMYHfNLEQo1BYqSeYwmXtHYIjTwGM08RhOv6PR6xkz4jAloRjOa0SQtOoXXdUW8LlCqTGk0oYvGPqCB0mimNJrQxRR8ACiNZkqjCV1MwQeA0mimNJrQxRR8ACiNZkqjCV1MwQeA0mimNJrQxRR8ACiNZkqjCV1MwQeA0mimNOYqv7gDv0sCKI1hSmMIXQz2AQOUxjClMYQuBvuAAUpjmNIYQheDfcAApTFMaQyhi8E+YIDSGKY0htDF4GcwDFAaw5TGELoY/AyGAUpjmNIYQheDVcEApTFMaQyhi8GqYIDSGKY0htDFYFUwQGkMUxpD6GKwKhigNIYpjVH5NTK4EgHNGEYzhqTFYFUwgGYMoxlD0mKwKhhAM4bRjCFpMVgVDKAZw2jGkLQYrAoG0IxhNGNIWgxWBQNoxjCaMSQtBquCATRjGM0YkhaDVcEAmjGMZgxJi8GqYADNGEYzhqTFYFUwgGYMoxlD0mKwKhhAM4bRjNH5pUa4EgHNGEYzhqTFYFUwgGYMoxlD0mIKb3QCNGMYzRiSFlN4qxOgGcNoxpC0mNKbnUAlMpoxJC2m8HYnQDOG0YwhaTGFNzwBmjGMZgxJiym85QnQjOFv1cqv1Sq86Qm9WIu/WSu/Wqvwtif0ci3+dq38eq3CG5/QC7Y2b9jKr9jClQhfssUqcX7NFq5E9KIt/qat/KotrAoGvWyLv20rv24Lq4JBL9zib9zKr9zCqmDQS7f4W7fya7ewKhj04i3+5q386i2sCga9fIvRjCFpMVgVDKAZw2jGkLQYrAoG0IxhNGNIWgxWBQNoxjCaMSQtBquCATRjGM0YkhaDVcEAmjGMZozNL33DlQhoxjCaMSQtBquCATRjGM0YkhaDVcEAmjGMZgxJi8GqYADNGEYzhqTFYFUwgGYMoxlD0mKwKhhAM4bRjCFpMVgVDKAZw2jGkLQYrAoG0IxhNGNIWgxWBQNoxjCaMSQtBj+DYQDNGEYzhqTF4GcwDKAZw2jGuPwKQlyJgGYMoxlD0mKwRRhAM4bRjCFpMdgiDKAZw2jGEK8Y/AyGAR5jmMcY4hWDn8EwwGMM8xhDvGKwYBjgMYZ5jCFeMVgwDPAYwzzGkKkYLBgGIIxhCGPIVAwWDAMQxjCEMWQqBguGAQhjGMIYMhWDBcMAhDEMYYzPL8TElQgQxjCEMWQqBguGAQhjGMIYMhWDBcMAhDEMYQyZisGCYQDCGIYwhkzFYMEwAGEMQxhDpmKwYBiAMIYhjCFTMVgwDEAYwxDGkKkYLBgGIIxhCGPIVAwWDAMQxjCEMWQqBguGAQhjGMIYMhWDBcMAhDEMYUzIr2fFlQgQxjCEMWQqBguGAQhjGMIYMhWDn8EwAGEMQxhDpmLwMxgGIIxhCGPIVAx2DwMQxjCEMQQpBruHAfJimLwYghSD3cMAeTFMXgxBisHuYYC8GCYvhiDFYPcwQF4MkxdDkGKwexggL4bJiyFIMdg9DJAXw+TFxPyyYFyJQF4MkxdDkGLwMxgGyIth8mJITwx+BsMAbjGMWwyRicHPYBhgLIYZiyEyMdhYDDAWw4zFEJlYbCwGGIthxmKITCw2FgOMxTBjMUQmFhuLAcZimLEYIhOLjcUAYzHMWAyRicXGYoCxGGYshsjEYmMxwFgMMxZ7lV9djd+mDIzFMmOxRCYWG4sFxmKZsVgiE4uNxQJjscxYLJGJxcZigbFYZiyWyMRiY7HAWCwzFktkYrGxWGAslhmLJTKx2FgsMBbLjMUSmVhsLBYYi2XGYolMLDYWC4zFMmOxRCYWG4sFxmKZsVgiE4uNxQJjscxYrMovUseVCIzFMmOxRCYWG4sFxmKZsVgiE4uNxQJjscxYLJGJxcZigbFYZiyWyMRiY7HAWCwzFktkYrGxWGAslhmLJTKx2FgsMBbLjMUSmVhsLBYYi2XGYolMLDYWC4zFMmOxRCYWG4sFxmKZsVgiE4uNxQJjscxYrM6v9ceVCIzFMmOxRCYWG4sFxmKZsVgiE4uNxQJjscxYLJGJxcZigbFYZiyWyMRiY7HAWCwzFktkYrGxWGAslhmLJTKx2FgsMBbLjMUSmVhsLBYYi2XGYolMLDYWC4zFMmOxRCYWG4sFxmKZsVgiE4uNxQJjscxYrMkfmcCVCIzFMmOxJn9oAlciMBbLjMUSmdjCFzaAsVhmLJbIxBa+sgGMxTJjsUQmtvSlDVCJzFgskYktfG0DGItlxmKJTGzhixvAWCz/wkn+xEnhqxvoIyf8Kyf5MyeFL2+gD53wL53kT50Uvr6BPnbCv3aSP3dS+AIH+uDJ5osnVInYWCz86AmrxPmzJ7gS0YdP+JdP8qdPsLFY9PET/vWT/PkTbCwWfQCFfwElfwIFG4tFH0HhX0HJn0HBxmLRh1CYsVgiE4uNxQJjscxYLJGJxcZigbFYZiyWyMRiY7HAWCwzFktkYrGxWGAslhmLJTKx2FgsMBbLjMUSmVhsLBYYi2XGYl3+CA+uRGAslhmLJTKx2FgsMBbLjMUSmVhsLBYYi2XGYolMLDYWC4zFMmOxRCYWG4sFxmKZsVgiE4uNxQJjscxYLJGJxcZigbFYZiyWyMRiY7HAWCwzFktkYrGxWGAslhmLJTKx2FgsMBbLjMUSmVhsLBYYi2XGYn3+JBSuRGAslhmLJTKx2FgsMBbLjMUSmVhsLBYYi2XGYolMLDYWC4zFMmOxRCYWG4sFxmKZsVgiE4uNxQJjscxYLJGJxcZigbFYZiyWyMRiY7HAWCwzFktkYrGxWGAslhmLJTKx2FgsMBbLjMUSmVhsLBYYi2XGYolMLDYWC4zFMmOxRCYWG4sFxmKZsVgiE4uNxQJjscxYLJGJxcZigbFYZiyWyMRiY7HAWCwzFktkYrGxWGAslhmLJTKx2FgsMBbLjMUSmVhsLBYYi2XGYolMLDYWC4zFMmOxRCYWG4sFxmKZsVgiE4uNxQJjscxYLJGJxcZigbFYZiyWyMRiY7HAWCwzFktkYrGxWGAslhmLJTKx2FgsMBbLjMUSmVhsLBYYi2XGYolMHDYWC4zFMmOxRCYOG4sFxmKZsVgiE4eNxQJjscxYLJGJw8ZigbFYZiyWyMRhY7HAWCwzFktk4rCxWGAslhmLIzJx2FgcMBbHjMURmThsLA4Yi2PG4ohMHDYWB4zFMWNxRCYOG4sDxuKYsTgiE4eNxQFjccxYHJGJw8bigLE4ZiyOyMRhY3HAWBwzFkdk4rCxOGAsjhmLIzJx2FgcMBbHjMURmThsLA4Yi2PG4ohMHDYWB4zFMWNxRCYOG4sDxuKYsTgiE4eNxQFjccxYHJGJw8bigLE4ZiyOyMRhY3HAWBwzFkdk4rCxOGAsjhmLIzJx2FgcMBbHjMURmThsLA4Yi2PG4ohMHDYWB4zFMWNxRCYOG4sDxuKYsTgiE4eNxQFjccxYHJGJw8bigLE4ZiyOyMRhY3HAWBwzFkdk4rCxOGAsjhmLIzJx2FgcMBbHjMURmThsLA4Yi2PG4ohMHDYWB4zFMWNxRCYOG4sDxuKYsTgiE4eNxQFjccxYHJGJw8bigLE4ZiyOyMRhY3HAWBwzFkdk4rCxOGAsjhmLIzJx2FgcMBbHjMURmThsLA4Yi2PG4ohMHDYWB4zFMWNxRCYOG4sDxuKYsTgiE4eNxQFjccxYHJGJw8bigLE4ZiyOyMRhY3HAWBwzFkdk4rCxOGAsjhmLIzJx2FgcMBbHjMURmThsLA4Yi2PG4ohMHDYWB4zFMWNxRCYOG4sDxuKYsTgiE1f40jkwFseMxRGZuMLXzoGxOGYsjsjEFb54DozFMWNxRCau8NVzYCyOGYsjMnGlL5+DSmTG4ohMXOHr58BYHP/afP7cfOEL6OiD8/yL8/mT84WvoKOPzvOvzufPzhe+hI4+PM+/PJ8/PV/4Gjr6+Dz/+nz+/Dw2Foc+QL/5Aj1VIjYWBz9Czypx/gw9rkT0IXr+Jfr8KXpsLA59jJ5/jT5/jh4bi0MfpOdfpM+fpMfG4tBH6ZmxOCITh43FAWNxzFgckYnDxuKAsThmLI7IxGFjccBYHDMWR2TisLE4YCyOGYsjMnHYWBwwFseMxRGZOGwsDhiLY8biiEwcNhYHjMUxY3FEJg4biwPG4pixOCITh43FAWNxzFgckYnDxuKAsThmLI7IxGFjccBYHDMWR2TisLE4YCyOGYsjMnHYWBwwFseMxRGZOGwsDhiLY8biiEwcNhYHjMUxY3FEJg4biwPG4pixOCITh43FAWNxzFgckYnDxuKAsThmLI7IxGFjccBYHDMWR2TisLE4YCyOGYsjMnHYWBwwFseMxRGZOGwsDhiLY8biiEwcNhYHjMUxY3FEJg4biwPG4pixOCITh43FAWNxzFgckYnDxuKAsThmLI7IxGFjccBYHDMWR2TisLE4YCyOGYsjMnHYWBwwFseMxRGZOGwsDhiLY8biiEwcNhYHjMUxY3FEJg4biwPG4pixOCITh43FAWNxzFgckYnDxuKAsThmLI7IxGNjccBYHDMWR2TisbE4YCyOGYsjMvHYWBwwFseMxRGZeGwsDhiLY8biiEw8NhYHjMUxY3FEJh4biwPG4pixeCITj43FA2PxzFg8kYnHxuKBsXhmLJ7IxGNj8cBYPDMWT2TisbF4YCyeGYsnMvHYWDwwFs+MxROZeGwsHhiLZ8biiUw8NhYPjMUzY/FEJh4biwfG4pmxeCITj43FA2PxzFg8kYnHxuKBsXhmLJ7IxGNj8cBYPDMWT2TisbF4YCyeGYsnMvHYWDwwFs+MxROZeGwsHhiLZ8biiUw8NhYPjMUzY/FEJh4biwfG4pmxeCITj43FA2PxzFg8kYnHxuKBsXhmLJ7IxGNj8cBYPDMWT2TisbF4YCyeGYsnMvHYWDwwFs+MxROZeGwsHhiLZ8biiUw8NhYPjMUzY/FEJh4biwfG4pmxeCITj43FA2PxzFg8kYnHxuKBsXhmLJ7IxGNj8cBYPDMWT2TisbF4YCyeGYsnMvHYWDwwFs+MxROZeGwsHhiLZ8biiUw8NhYPjMUzY/FEJh4biwfG4pmxeCITj43FA2PxzFg8kYnHxuKBsXhmLJ7IxGNj8cBYPDMWT2TisbF4YCyeGYsnMvHYWDwwFs+MxROZeGwsHhiLZ8biiUw8NhYPjMUzY/FEJh4biwfG4pmxeCITj43FA2PxzFg8kYnHxuKBsXhmLJ7IxGNj8cBYPDMWT2TisbF4YCyeGYsnMvHYWDwwFs+MxROZeGwsHhiLZ8biiUw8NhYPjMUzY/FEJh4biwfG4pmxeCITj43FA2PxzFg8kYnHxuKBsXhmLJ7IxGNj8cBYPDMWT2TisbF4YCyeGYsnMvHYWDwwFs+MxROZeGwsHhiLZ8biiUw8NhYPjMUzY/FEJh4biwfG4pmxeCITj43FA2PxzFg8kYnHxuKBsXhmLJ7IxGNj8cBYPDMWT2TisbF4YCyeGYsnMvHYWDwwFs+MxROZeGwsHhiLZ8biiUw8NhYPjMUzY/FEJh4biwfG4pmxeCITj43FA2PxzFg8kYnHxuKBsXhmLJ7IxGNj8cBYPDMWT2TisbF4YCyeGYsnMvHYWDwwFs+MxROZeGwsHhiLZ8biiUw8NhYPjMUzY/FEJh4biwfG4pmxeCITj43FA2PxzFg8kYnHxuKBsXhmLJ7IxGNj8cBYPDMWT2TisbF4YCyeGYsnMvHYWDwwFs+MxROZeGwsHhiLZ8biiUw8NhYPjMUzY/FEJh4biwfG4pmxeCITj43FA2PxzFg8kYnHxuKBsXhmLJ7IxGNj8cBYPDMWT2TisbF4YCyeGYsnMvHYWDwwFs+MxROZeGwsHhiLZ8biiUw8NhYPjMUzY/FEJh4biwfG4pmxeCITj43FA2PxzFg8kYnHxuKBsXhmLJ7IxGNj8cBYPDMWT2TisbF4YCyeGYsnMvHYWDwwFs+MxROZeGwsHhiLZ8biiUwCNhYPjMUzY/FEJgEbiwfG4pmxeCKTgI3FA2PxzFg8kUnAxuKBsXhmLJ7IJGBj8cBYPDMWT2QSsLF4YCyeGUsgMgnYWAIwlsCMJRCZBGwsARhLYMYSiEwCNpYAjCUwYwlEJgEbSwDGEpixBCKTgI0lAGMJzFgCkUnAxhKAsQRmLIHIJGBjCcBYAjOWQGQSsLEEYCyBGUsgMgnYWAIwlsCMJRCZBGwsARhLYMYSiEwCNpYAjCUwYwlEJgEbSwDGEpixBCKTgI0lAGMJzFgCkUnAxhKAsQRmLIHIJGBjCcBYAjOWQGQSsLEEYCyBGUsgMgnYWAIwlsCMJRCZBGwsARhLYMYSiEwCNpYAjCUwYwlEJgEbSwDGEpixBCKTgI0lAGMJzFgCkUnAxhKAsQRmLIHIJGBjCcBYAjOWQGQSsLEEYCyBGUsgMgnYWAIwlsCMJRCZBGwsARhLYMYSiEwCNpYAjCUwYwlEJgEbSwDGEpixBCKTgI0lAGMJzFgCkUnAxhKAsQRmLIHIJGBjCcBYAjOWQGQSsLEEYCyBGUsgMgnYWAIwlsCMJRCZBGwsARhLYMYSiEwCNpYAjCUwYwlEJgEbSwDGEpixBCKTgI0lAGMJzFgCkUnAxhKAsQRmLIHIJGBjCcBYAjOWQGQSsLEEYCyBGUsgMgnYWAIwlsCMJRCZBGwsARhLYMYSiEwCNpYAjCUwYwlEJgEbSwDGEpixBCKTgI0lAGMJzFgCkUnAxhKAsQRmLIHIJGBjCcBYAjOWQGQSsLEEYCyBGUsgMgnYWAIwlsCMJRCZBGwsARhLYMYSiEwCNpYAjCUwYwlEJgEbSwDGEpixBCKTgI0lAGMJzFgCkUnAxhKAsQRmLIHIJGBjCcBYAjOWQGQSsLEEYCyBGUsgMgnYWAIwlsCMJRCZBGwsARhLYMYSiEwCNpYAjCUwYwlEJgEbSwDGEpixBCKTgI0lAGMJzFgCkUnAxhKAsQRmLIHIJGBjCcBYAjOWQGQSsLEEYCyBGUsgMgnYWAIwlsCMJRCZBGwsARhLYMYSiEwCNpYAjCUwYwlEJgEbSwDGEpixBCKTgI0lAGMJzFgCkUnAxhKAsQRmLIHIJGBjCcBYAjOWQGQSsLEEYCyBGUsgMgnYWAIwlsCMJRCZBGwsARhLYMYSiEwCNpYAjCUwYwlEJgEbSwDGEpixBCKTgI0lAGMJzFgCkUnAxhKAsQRmLIHIJGBjCcBYAjOWQGQSsLEEYCyBGUsgMgnYWAIwlsCMJRCZBGwsARhLYMYSiEwCNpYAjCUwYwlEJgEbSwDGEpixBCKTgI0lAGMJzFgCkUnAxhKAsQRmLIHIJGBjCcBYAjOWQGQSsLEEYCyBGUsgMgnYWAIwlsCMJRCZBGwsARhLYMYSiEwCNpYAjCUwYwlEJgEbSwDGEpixBCKTgI0lAGMJzFgCkUnAxhKAsQRmLIHIJGJjCcBYAjOWQGQSsbEEYCyBGUsgMonYWAIwlsCMJRCZRGwsARhLYMYSiEwiNpYAjCUwYwlEJhEbSwDGEpixRCKTiI0lAmOJzFgikUnExhKBsURmLJHIJGJjicBYIjOWSGQSsbFEYCyRGUskMonYWCIwlsiMJRKZRGwsERhLZMYSiUwiNpYIjCUyY4lEJhEbSwTGEpmxRCKTiI0lAmOJzFgikUnExhKBsURmLJHIJGJjicBYIjOWSGQSsbFEYCyRGUskMonYWCIwlsiMJRKZRGwsERhLZMYSiUwiNpYIjCUyY4lEJhEbSwTGEpmxRCKTiI0lAmOJzFgikUnExhKBsURmLJHIJGJjicBYIjOWSGQSsbFEYCyRGUskMonYWCIwlsiMJRKZRGwsERhLZMYSiUwiNpYIjCUyY4lEJhEbSwTGEpmxRCKTiI0lAmOJzFgikUnExhKBsURmLJHIJGJjicBYIjOWSGQSsbFEYCyRGUskMonYWCIwlsiMJRKZRGwsERhLZMYSiUwiNpYIjCUyY4lEJhEbSwTGEpmxRCKTiI0lAmOJzFgikUnExhKBsURmLJHIJGJjicBYIjOWSGQSsbFEYCyRGUskMonYWCIwlsiMJRKZRGwsERhLZMYSiUwiNpYIjCUyY4lEJhEbSwTGEpmxRCKTiI0lAmOJzFgikUnExhKBsURmLJHIJGJjicBYIjOWSGQSsbFEYCyRGUskMonYWCIwlsiMJRKZRGwsERhLZMYSiUwiNpYIjCUyY4lEJhEbSwTGEpmxRCKTiI0lAmOJzFgikUnExhKBsURmLJHIJGJjicBYIjOWSGQSsbFEYCyRGUskMonYWCIwlsiMJRKZRGwsERhLZMYSiUwiNpYIjCUyY4lEJhEbSwTGEpmxRCKTiI0lAmOJzFgikUnExhKBsURmLJHIJGJjicBYIjOWSGQSsbFEYCyRGUskMonYWCIwlsiMJRKZRGwsERhLZMYSiUwiNpYIjCUyY4lEJhEbSwTGEpmxRCKTiI0lAmOJzFgikUnExhKBsURmLJHIJGJjicBYIjOWSGQSsbFEYCyRGUskMonYWCIwlsiMJRKZRGwsERhLZMYSiUwiNpYIjCUyY4lEJhEbSwTGEpmxRCKTiI0lAmOJzFgikUnExhKBsURmLJHIJGJjicBYIjOWSGQSsbFEYCyRGUskMonYWCIwlsiMJRKZRGwsERhLZMYSiUwiNpYIjCUyY4lEJhEbSwTGEpmxRCKTiI0lAmOJzFgikUnExhKBsURmLJHIJGJjicBYIjOWSGQSsbFEYCyRGUskMonYWCIwlsiMJRKZRGwsERhLZMYSiUwiNpYIjCUyY4lEJhEbSwTGEpmxRCKTiI0lAmOJzFgikUnExhKBsURmLJHIJGJjicBYIjOWSGQSsbFEYCyRGUskMonYWCIwlsiMJRKZRGwsERhLZMYSiUwSNpYIjCUyY4lEJgkbSwTGEpmxRCKThI0lAmOJzFgikUnCxhKBsURmLJHIJGFjicBYIjOWSGSSsLFEYCyRGUsiMknYWBIwlsSMJRGZJGwsCRhLYsaSiEwSNpYEjCUxY0lEJgkbSwLGkpixJCKThI0lAWNJzFgSkUlS6o1Nb5MybAXbSkzMWBKRSVL6jYlvk1ZsBdtKTMxYEpFJUuaNNW+vvGcr2FZiYsaSiEzSZCz2rfaWrWBbiYkZSyIyScrhn7CtxMSMJRGZJGwsCRhLYsaSiEySCm+cfqtDYisAlciMJRGZJGwsCRhLYsaSiEwSNpYEjCUxY0lEJgkbSwLGkpixJCKThI0lAWNJzFgSkUnCxpKAsSRmLInIJGFjScBYEjOWRGSSsLEkYCyJGUsiMknYWBIwlsSMJRGZJGwsCRhLYsaSiEySDm9cfKvYzgiIJTFiSSQmCRNLAsSSGLEkEpOk03RA0oavABQiI5ZEYpLM1Rsf35qo2QpAITJiSSQmyag39uptSux4AoglMWJJJCbJ6DfWvo1XPAEoREYsicQkGfPG+rfpiicAhciIJZGYJGOnFZgU2ApAITJiSSQmybjpoKwt/yuAQmTEkkhMkvHTCqxmCQCxJEYsicQkmTBtRBXZIREQS2LEkkhMkolTgnjFjuqAWBIjlkRikkx6Y8PbwPcFQCyJEUsiMUn2Cq8AVCIjlkRikqyCdQCIJTFiSSQmyeopgfL8rwAqkRFLIjFJ1rwx/q3iuzMglsSIJZlYuTwAxJIYsSQSk2TtG5PeKhfZCkAlMmJJ9qpyfQGIJTFiSVZVLg8AsSRGLInEJFmHE4BKZMSSSEyS9W+seusi+zMCYkmMWJLNlRimQlKOXeUBYkmMWJLNlRjxCkAlMmJJNldimlbgLf8JoBIZsSQbKpdIgFgSI5ZEYpLcFTykAWJJjFgSiUnCzJQAsSRGLInEJDn9xqm3V5rVASCWxIglkZgkh88LgFgSI5bkdKWQALEkRizJmcq+AIglMWJJzlYOKIBYEiOW5FzlgAKIJTFiSc5XDiiAWBIjluRCZXcGxJIYsSQXK1cogFgSI5bkamdnQCyJEUvytbMzIJbEiCX52tkZEEtixJJ87ewMiCUxYkm+dnYGxJIYsSRfOzsDYkmMWJJ3lUMaIJbEiCV5XzkqA2JJjFiSD5WjMiCWxIgl+Vi5UgXEkhixJJ8qV6qAWBIjlhSuKleqgFgSI5YU8jHRvnHmbWB1BIQlMWFJBCbJuTfOvtWGBwCFyIQlEZgk5/EKQCEyYUkEJsmF6RfwAxoAlsSAJZGXJBfh8qAMma8k4pLkEv4BoAyZryTikuSv8ApAGTJfScQlySu8AlCGzFcScUnyGq8AlCHzlURckryBKwC+kpivJOKS5C1eAahD5iuJuCR5XIfAVxLzlURckjyuQ+AriflKIi5JPuAVgEJkvpKIS5KPeAWgEpmvpOgr9zvAVxLzlRRD5X4H+EpivpJirNz7A19JzFdSTJWrTOAriflKSrkScf8H8JXEfCURlyQ8dCABX0nMV1LSlUs04CuJ+UpKpnKJBnwlMV9J2VcKl2jAVxLzlZR9pXDPB3wlMV9J2VeCmrrBNnUAfCUxX0nZVwqFBHwlMV9J2VcKV9rAVxLzlZR9pXCtD3wlMV9RVxlY8BCQeep6Fcv/PK9DlYtpnrpZh+Lr0OV6mqdu1qH5Oky5pOapm3UYvg5brqp56mYdlq/Dlf+s89TNOhxfhy/X1jx1sw7P10H1Gcwbb97qsMmxLdDlf57XEcsVNk/drCPydVCV4kE+89TNOnidZn7BXcbzVL4Oxes0C0xpmwKCWf7neR1Up8GBS9F54mYVvEwzw0wjjq7exsQ3KXCY5X+e12HLF/Xz1M06eJlmjMHX9fPUzTp4mWaPwZf289TNOniZZpLBd7rz1M06eJlmlcE3u/PUzTp4mWaYwfe789TNOniZZpvBt7zzVL4Ozcs08wy+652nbtbByzQTDb7xnadu1sHrNCsNvlKbp27Wwes0Qw2+WJunbtbB6zRbTen0ArBm+Z/ndVQEe566WQev0yw2pdMLIJvlf57XEWunF6A2y/88r6NC2fPUzTp4nWa6wf1b81S+DsPrNOtN6dQA+Gb5n+d16HL3yDx1sw5ep9lwcA/JPHWzDl6nM+PAfp556mYdvE6z5ODe63nqZh28TjPm4FuLeepmHbxOs+fgAanz1M06eJ1m0sHd2PPUzTp4nWbVwT3Z89TNOnidZtgp1RiQneV/ntdRsZ156mYdvE5t5X5pnrpZB69TW7llmqdu1sHr1Fbumuapm3XwOp2dp7DvA+hZ/ud5HdXLU2A9y/88ryNULqWA9iz/87yKWLuUAuCz/M/zOlLtEATMZ/mf8zqy+pQOQYB9lv95XoeqXQYB+Vn+53kdunYZBPBn+Z/ndZjaZRDwn+V/ntdha5dBgICW/3leh6tdBgEFWv7neR2+dhkEIGj5n+d1hNqpAVjQ8j/P66j0wc9TN+vgdeoq3fDz1M06eJ36Sk/8PJWvw/M69eXO+HniZhW8TH2lP36eulkHL1Nf6ZKfp27WwcvUl3vl54mbVfAq9eWO+XniZhW8SH2lb36eulkHL1Jf6Z6fp27WwYvUV3ro56mbdfAi9ZVO+nnqZh28SEOln36eytcReJGGSlf9PHWzDl6lodJbP0/drINXaah02M9TN+vgVRoqffbz1M06eJmGSrf9PHWzDl6noXptChBp+Z/ndYTaPSVwpOV/ntcRa/eUgJKW/3leRyr3wM9TN+vgdZo9qXRdCUBp+Z/ndeSOfDiUcp66WQev06xK+PGveepmHbxOMyzhJ8DmqZt18DrNtjQ9BIYuxgAuLf/zvA6q0+k5MLgOVKeR12kWpmjeeP/WBF5jgJiW/3leB9Xp9DQYzIHqNPI6zc40PRAG14HqNPI6zdQUPRpGMk/drIPXadam6bEwlANw0/I/z+ugOp2eDIPrQHWaeJ1mc5oeDoPrQHWaeJ1mdpqeD4PrQHWaeJ1meUqFOgX0tPzP8zqoTlOhToE+Lf/zvA6q0+lBMbgOVKeJ12kmqFSoU2BQy/88r4PqNBXqFDDU8j/P66A6TYUbMSBRy//M61CZolKAta4QRSlOUSpTVMJ1qhBFKU5RKlNUwnWqEEUpTlGKXGmissJKQKEqblGKYGmyssJKQKUqjlGKZGnCssJKQKkqrlGKaGnSssJKQK0qzlGKbGnissJKQLEq7lGKcGnyssJKQLUqDlKKdGkCs8JKQLkqLlKKeGkSM7wSRFKKk5QiX5rIrLASVLDcpBQJ02RmhZWgiuUqpVSuWFWoWMRSirOUUrliVaFikUsp7lJK5YrFr/SbJ29Wwis2w1Shw04hmFIcplSGqUKHnUIwpThMqQxThQ47hWBKcZhSGaYKaKAQTCkOU0rXLlYVginFYUrpmp8qBFOKw5TKMFUwaYVgSnGYUroyVH6eulkHr1Q9Vyp8EGyevFkJr1Q9VyqWbYVoSnGaUpmmCl3tCtGU4jSlMk0VutoVoinFaUrpmvQrRFOK05Sq0pRCNKU4TamZpgp7LqIpxWlKZZoq7bmIphSnKTXTVGHPRTSlOE2pmaZwV7tCNKU4TalMU6W9DtGU4jSlMk0V+oUVoinFaUplmir0TytEU4rTlMo0VehbVoimFKcplWmq0LesEE0pTlMq01Shb1khmlKcptRMU7hvWSGaUpymVKapQt+yQjSlOE0pWyNUhWhKcZpStkaoCtGU4jSlbG1IikI0pThNKVsbkqIQTSlOU8rWhqQoRFOK05TKNIX7uBWiKcVpSs2PIuHeQ4VoSnGaUvPTSLj3UCGaUpym1PxAEuzjVkimFJcpNT+SBPu4FYIpxWFKZZgq9HErBFOKw5TKMFXo41YIphSHKZVhqtDHrRBMKQ5TKsNUoY9bIZhSHKZUhqlCH7dCMKU4TKkMU4U+boVgSnGYUhmmCn3cCsGU4jClMkwV+rgVginFYUplmCr0cSsEU4rDlMowVejjVkimFJcpNcsU7uNWSKYUlynla+OmFJIpxWVK+dq4KYVoSnGaUpmmCn3cCtmU4jalfL7xx+8mnydvVsILNeNUYeymQjilOE4pXxm0P0/drIMX6vwgU+EMhXBKcZxS87NMhTMUwinFcUplnCqdoRBOKY5TKuNU6WoM4ZTiOKUyTpWuChFOKY5TKuNU6YoO4ZTiOKUyTpWu6BBOKY5TKuNU6YoO4ZTiOKVmnCpc0SGcUhyn1IxThZ0f4ZTiOKUyTpV2foRTiuOUitW7KIRTiuOUitW7KIRTiuOUitW7KIRTiuOUyjhV6v9AOKU4TqmMU6U7U4RTiuOUirWBUwrhlOI4pebHnwp32QinFMcpNT8BVbjiRzilOE6pjFOlK36EU4rjlMo4Vbp7QTilOE6pjFOFQZMK4ZTiOKUyTpVO2ginFMcplXIfKn6/0zx5sxJeqFmnSl05SKcU1ymVdarUlYN0SnGdUlmnSkWGdEpxnVJZp0o7DNIpxXVKpcqbReapm3XwQk2Vl4vMUzfr4IWaKu8Xmadu1sEKVV/VRkxrpFOa65S+qnWgaqRTmuuUvqqd+DXSKc11Sl/VTvwa4ZTmOKWvaid+jWxKc5vSV7UTv0Y0pTlN6avaiV8jmdJcpvRV7cSvEUxpDlN6flAKHww1cinNXUpf1YaiasRSmrOUVrWhqBqplOYqpecHpfCFskYopTlK6fygVOFCWSOT0tykdH5SqnChrBFJaU5SOj8phbtyNAIpzUFK5welCl05GnmU5h6ls0cVunI08ijNPUpnj8JdORpxlOYcpTNH4a4cjTRKc43SWaMKXTkaaZTmGqWzRhW6cjTSKM01SmeNKnTlaKRRmmuUzhpV6MrRSKM01yidNarQlaORRmmuUTo/JlXoytEIozTHKJ0fkyp05WhkUZpblM4WVejK0ciiNLconS2q0JWjkUVpblE6W1ShK0cji9LcorSuPKU/T92sg9fpbFH4bk4ji9LcovT8mBS+m9PIojS3KJ0tqtCVo5FFaW5R2szAj58L0gijNMcobSqvdpqnbtbBC9VU3u40T92sgxeqqbzgaZ66WQcvVFN5Ke08dbMOXqgZo/A7BOapm3XwQp0xqnBViDBKc4zStsb7GmGU5hilbe15Po0wSnOM0na+jcIDWjXSKM01Stu5UvGIVo04SnOO0vOTUqVfgyqVc5S2tSdPNeIozTlK29qTpxpxlOYcpW3lbWTz1M06eKVmjyrdNyCP0tyjtK1WKvIozT1Ku8pryeapfB0cpLSrvJlsnrpZB69UV3k52Tx1sw5eqK7yfrJ56mYdvE5d5RVl89TNOnidZpEq3TcgkdJcpPT8qFThvgGJlOYipauPSmkkUpqLlHZ5gJ++euPt23C1CYIKlZOUdrWefo1ISnOS0pmkStcPiKQ0Jyntq+d+RFKak5TOJFW6BkEkpTlJaV95peM8dbMOXqg+j5jCL++eJ29WwivV5xFTWr/xV2/TFS93hFKao5SeUUqbwkpQrXKU0j6PRsUv8p4nb1bCi9XPxYp5TCOW0pyldGap0lkGsZTmLKVDtXcKsZTmLKVDtXcKsZTmLKVD5fUoGqmU5iqlZ5UqnKiQSmmuUrqqUhqplOYqpasqpZFKaa5SOsyV6t+4BHZexFKas5TOLFXaeRFLac5SOsyFWrj4Ry6luUvp7FL4OxLz1M06eKHGPGpaxzfWvbWOB0EwpTlM6ZhHTU/f6N1+DmKevFkJL9WYL1Wn7/TClaBi5TSlY75Unb7VC1eCqpXblI75yDp9rxeuBJUrxykd85F1+mYvXAmqV65TOuZ6NfA7G/PkzUp4vcZ8ZJ2+3QtXggqW+5SOuWCn7/fClaCC5UClYx7nP33DF64EVSwXKp1yxeLv+M6T+Uo4UelUe0WaRkSlOVHpVHnF+Dx1sw5er1moSsd4JFSaC5VOc7kW9j5EVJoTlU65XG1h70NGpblR6VQbkqqRUWluVDqF6iEaIZXmSKVrL/Kbp27WwYs15WLFH1ueJ29WworVXNXY3yClMlypzPw6P1xnBimV4UplrvLB1eLrPIOYynCmMpmp8MWEQUpluFKZq9rgaYOUynClMrNS4SozSKkMVyozKxW+IDFIqQxXKpOVqnBBYpBSGa5UZn58qlDtBjGV4Uxlat9Smqdu1sELdX56Cn/Ye57MV8KdyqjaUdUgpzLcqYyqHVUNcirDncrMz06Vqh1BleFQZTJUFaodQZXhUGVU5as289TNOnilqtox1SCoMhyqjKoN8zdIqgyXKqNqw/wNoirDqcqoVK12ZFWGW5WpPjllkFUZblVG5wtW/BX6efJmJbxSde0dVAZhleFYZXTtgRSDsMpwrDK6VqjIqgy3KqOrh1RkVYZbldG1V1AZZFWGW5WZP8KEOyMNsirDrcrM32EqFDuyKsOtysyfYioUO7Iqw63KzFaFOwENsirDrcrMVoU7AQ2yKsOtyszfZMJ9bwZZleFWZebPMuHBAwZRleFUZebnpvDgAYOoynCqMsZVDyDIqgy3KmNqI6kMsirDrcqYfJVqcUeTQVhlOFaZjFWlAwjCKsOxysyfaiocQBBWGY5VJmNV4QCCrMpwqzK29rI0g6zKcKsytvayNIOoynCqMrb2sjSDpMpwqTK29rI0g6TKcKky84NThZ0OSZXhUmXmB6cKOx2SKsOlymSpKu10SKoMlypj69eoiKoMpypjq9eoiKoMpyrj5mtUPCbUIKsy3KqMq16jIqsy3KqMq16jIqsy3KqMq3WrGmRVhluVcdW7KWRVhluVcbVHUQ2yKsOtyrjq3RSyKsOtyrjq3RSyKsOtylRf62cQVRlOVab6Wj+DqMpwqjLV1/oZRFWGU5WZqapw+YCoynCqMjNVFS4fEFUZTlXGm+rej6zKcKsyvjba3yCqMpyqzExVFneZG0RVhlOV8bXXUBgkVYZLlfE1/TcIqgyHKjNDlY34DhVBleFQZXyN/w2CKsOhyoSrWuehQVJluFSZMN9OlVaCipVTlak+QWWQVRluVSbUixVhleFYZUK1WBFWGY5VJuRidfgFbgZpleFaZUK1WBFWGY5VJlSLFWGV4VhlQr1YEVYZjlUmVIsVYZXhWGVmrCp0UhuEVeb/5+tucxzbWS0AT+joVcynPf+JXVVDSXVXFvyNJdRdId62nw1GrNK7JyvDKkWs0rsmK7MqRavSuycrsypFq9K1jkoZVSlSlTZV8Vs2e/grCCZrU5XzLkHKqEqRqvRulanKpEpRqrSlynlLG2VSpShVercXVpRBlSJU6dtKU5U5laJT6dtKU5U5laJT6Xa3VI9+xcBc3a6X6tGvGJiq2w1TPfoVA1N1u2SqR79iYKaulVTKlEpRqfSt0ypDKkWk0rc1+FGGVIpIpW+rUFFmVIpGZZ+tQsWYURkalX22xinGjMrQqKyvnOKlh8aIypCorIhqeEnMmFEZGpV1mz/nh8PGkMoQqayQaig9NIZUhkhlhVRD6aExpDJEKutSKp5kxpDKEKnss2mqMaMyNCr7bC9VGTMqQ6OyKqUaJiFjRGVIVNZExSchY0RlSFS2EpUxojIkKmuiGp5SxojKkKisiGr49RszKkOjsjKq6dfPjMrQqKyb+w2/fmZUhkZlbVT8iWvMqAyNytqohh8MMypDo7K+dYo/cY0RlSFRWREVr3EzJlSGQmVVTTXUuBkDKkOgsgKqocbNGFAZApUVUPEaN2M+ZehTVj7Fa9yM+ZShT1n51FDjZsynDH3KupaK17gZ8ylDn7KupeI1bsZ8ytCnrGupeI2bMZ8y9Ckrnxpq3Iz5lKFPWfnUUONmzKcMfcrKp4YaN2M+ZehT1rVUQ5YynzL0KSufGmrcjPmUoU9Z+dRQ42bMpwx9yqqUalp+MJ4y5Ckrnhpqy4zxlCFPWfOUc54yxlOGPGXaGyl+3G7Mpwx9yrTI3/mpnTGgMgQqK6AatoXGhMpQqMxq2++XtrM2RlSGRGW2WaoxojIkKrPNUo0RlSFRmW2WaoyoDInK1mIqY0RlSFS2FlMZIypDojLbrvEzRlSGRGW2XeNnTKgMhcpWoTImVIZCZb699m8MqAyBynwr+zMGVIZAZb71oDQGVIZAZb71oDQGVIZAZb5d42cMqAyByny7xs8YUBkClfl2VYoxoDIEKvOeU3kVpDGhMhQq8+0eP2NCZShU5ts9fsaEylCoLLZ7/IwJlaFQWWz3+BkTKkOhstjOpowJlaFQWWxnU8aAyhCoLLazKWNAZQhUFls7KmM+ZehT1qVU01OKAZUhUFls/aiMAZUhUFls/aiM+ZShT1ls/aiM+ZShT1n39xueuIynDHnKupBq+MEwnTLUKWudGp64TKcMdcqqkmrYFjKbMrQpK5uatoXMpgxtyqqQatoWMpoypCnru6f4tpDJlKFMWcnUsC1kMGUIU1bN/aZtIXMpQ5eyvnlq2BYylzJ0KavmftO2kLGUIUtZNfebtoVMpQxVykqlpm0hUylDlbJq7jdtCxlKGaKUFUpN20KGUoYoZdXcb9oWMpMyNCmr5n7TtpCRlCFJWZHUtC1kJGVIUlbN/ablBxMpQ5Gyu92QZkykDEXKunQquEobIylDkrJXG6ngWmjMpAxNyrq9X3AtNIZShihlr85Qg9csGFMpQ5Wyrp6K4bSfsZQhS1lXT8Ww32YuZehS9urZH8N+m8GUIUzZ226eMAZThjBlb01XBlOGMGVdPRXDvp/JlKFM+afzlZf6OaMpR5ryoqlhye2Mphxpyoumhr+qM5pypCnvK6iC3wrkzKYcbcrbppLfCuTMphxtysumhoW7M5tytCnvG6iSzwLOcMoRp7xvoEo+CzjTKUed8i6hSj4LOOMpR57yvoEq+SzgzKccfcq7hiqd3nToDKgcgcr7BqrkhbbOhMpRqLxvoEpeaOuMqByJypuohsswnRGVI1F530A13IbpzKgcjcrbqPjuzJlRORqVn+2oyplRORqVn61DlTOjcjQqPxumOjMqR6Pys2GqM6NyNCqXStb74cnKlMpRqbzrqO4wCzCmcmQql0rWO8wCzKkcncqlkvXycntnUuUoVd6XUN1hFmBW5WhV3pdQXb4WcIZVjljlUtPr5WsBZ1rlqFUuNb1e/gx2xlWOXOVy1/mIeZWjV7nU9HqHqYSBlSNYuXbGDlMJEytHsXKtjH18CeyMrBzJyrUy9g1pz8zK0ay8+/+9Ie0ZWjmilWtl7BsefkytHNXKu6rqDWnP2MqRrVwrY9+Q9sytHN3K263ekPbMrf58+BukMvYNac/cytGtvN3qDRnL3MrRrdwqY9+QsQyuHOHKC67OZ8hYBleOcOXVB/B8hoxlcuUoV159AM9nyFhGV4505f8c6udy1SEIy1i0K/8HUT+Xqw5BWMYiXvk/ifq5XHUIwjIW9cr/UdTP5apDEJaxyFdeFVbnM2Qs8ytHv/J/GPVzueoQhGUsApZXidX5DBnLBMtRsNwrY8+QsYywHAnLvTL2DBnLDMvRsNwrY4erS50hliNiuW89Vp0hliNiuW+dAJwhliNiuW9XVThDLEfE8qqymlbBzLAcDcvLsKbVODMsR8PyMqxpJc0My9GwPLarKpwZlqNh+WpYzgzL0bA8OlOHGY0hliNieV9SNXy5DLEcEctjTVSGWI6I5bE1A3aGWI6I5V1kxSHMmWE5GpaXYQ0FFs4My9GwPLZyQGeG5WhYHls5oDPDcjQsz60c0JlhORqWr80AnRmWo2F5bgXWzgzL0bA8twJrZ4jliFieW4G1M8RyRCzP9QyLIZYjYnl1AzzDdcHOGMuRsTxz66DpDLIcIct/2wHyDprOJMtRsjxrATDcDeeMshwpy4uyDm8454yyHCnL73b/jzPKcqQsv/sJFrMsR8vy24//+GkHjr18nVmWo2V5NQM8Q5t2Z5jliFlemDW8wOYMsxwxy+86qzLMcsQsL8zSD327wBlmOWKW361rhTPMcsQsv9u7Vs4wyxGzvDDrDK3NnWGWI2Z5X1U1TO/Mshwty18//3lBoTPLcrQsL8s6MqyZmWU5Wpa/rce6M8pypCwvyjpDW2FnlOVIWV6UdWRYdzPKcqQsr06A89+VZStalr/aWsmwOGOY5YhZXph1ht7EzjDLEbPis73EGsyyAi0r1gurgllWoGXFZ3vlKphlBVpWfLb+1cEoK5CyoijrDL2ag1FWIGXFx7f2tcEsK9Cyoi1raBobzLICLSvasoYeuMEsK9Cyoi1r6IEbzLICLSvasob2tcEsK9Cyoi1raF8bzLICLSvasob2tcEsK9Cyoi1raF8bzLICLSvasob2tcEsK9Cyoi1raF8bzLICLStOz6/8wCgYZgViVpztKCAYZgViVpyaXmX637CERc2K09PrHYKwhEXOitPT6/DTYZ4V6FlRnnWmnw7zrEDPivKsM80EzLMCPSvKs47yh18wzwr0rCjPOsqfW8E8K9CzoiqvhiVjMM4K5Kwozjo/v2HyxkEwzgrkrCjOOjrM9YyzAjkrirOODr8cxlmBnBWy8WswzQrUrCjNOsq3BME0K1CzQjtfh18O06xAzQrtfB1+OUyzAjUrSrPO0FUjmGYFalaUZh0bfjlMswI1K0qzjg1PLqZZgZoVpVnHhicX06xAzYoqwpJkG8dglhVoWVGWdYYeo8EsK9CyQrez1mCUFUhZodvFa8EkK1CyoiTr2PAQZpIVKFnRkmXDQ5hJVqBkRUuWDY8tJlmBkhUtWTb8+JhkBUpWtGQNjWSCSVagZEVLFj+iCAZZgZAVDVlDs6FgkBUIWWHbuy3BHCvQscK2FweDMVYgY4W97SWqYIwVyFjRjDV0tAnGWIGMFc1YQ0ebYIwVyFjxy1j8+2WKFahY0Yrlw1qAKVagYsWqWMEUK1CxohTr580WthRgihWoWFGK9fNOCo3BchUVK3zrahlMsQIVK+peqzN0+QjGWIGMFcVYP68/0f8My1VkrCjG+nn7icVgjBXIWFGMdZX/ZhhjBTJWVCnWHdZ5TLECFStKsW7Q88VgihWoWFH3Wp2hdjkYYwUyVlSzwDPULgdzrEDHiuh5dVjnMcgKhKyoe62O82PKYJIVKFkRnayc5YNRViBlRVHWz7s19AtmyYqUFUVZb0h4RlmBlBVFWW9IeEZZgZQVWdPqUMkQzLICLSuqW+AZKhmCYVYgZkVh1kue8gyzAjErCrN+3jWifxGWrIhZURVZj79dHsyyAi0r2rI+/O3yYJYVaFnRlvWZcoTlKlpWlGV9PlOSsGRFy4qyrJ9341gMZlmBlhVlWW+YFZllBVpWVFnWGx6bjLICKSuqLOsOKcIoK5Cyosqy7pAiTLICJStKst6QIUyyAiUrqlXgGYp/glFWIGVF32r1mb5dlqtoWdG9Aj/T18tyFTEr+larz/T9slxFzYouzfoMszPTrEDNii7N+gyLK8ZZgZwVXZr1GVKNcVYgZ0WXZn2GXGOcFchZ0aVZZ0g25lmBnhVdmnWG6Yh5VqBnRXvWUGkWzLMCPSvas4ZKs2CeFehZ0Z4VQ7Ixzwr0rGjPimEjzjwr0LOyirNO8CdfMtBKBK381B4r+EY8mWglilZ+ejHAV0fJSCuRtLI7B3IJTkZaiaSVdbvVUGqWTLQSRStLtE7y07hkopUoWvnZegglA61E0Mq1c2Ayz0r0rCzPOkOVWDLPSvSsLM86Q5VYMs9K9KwszzpDlVgyz0r0rCzPOkOVWDLPSvSsLM86yfc3yTwr0bPy6DYNJPOsRM/K8qxpGkjmWYmele1Z0zTAPCvRs/LEOg0w0EoErWzQSr7nSwZaiaCVDVrJ93zJQCsRtLJBa6icSwZaiaCVsl0dmMyzEj0rq4vg8DZnMs5K5Kzsa674EXQyzUrUrKwugsPhYjLMSsSsXDErGWYlYlY2Zg3ViMkwKxGzsmuzhncOkmFWImZlY9blr2Ilw6xEzMqqzTr3DEFYsqJmZWvWlSEIS1bUrGzN+jmBYkGYZiVqVrZmXRuCsHRFzcpqJ8jlJpllJVpWtmUNFXzJLCvRsrIta6jgS2ZZiZaVbVlDBV8yy0q0rKzKrDMU3yXTrETNytasofgumWYlalZWZdYZiu+ScVYiZ2VVZp2h+C6ZZyV6VrZnDcV3yTwr0bOyPWsovkvmWYmele1ZQ/FdMs9K9KxszxqK75J5VqJnZXvWUHyXzLMSPSvbsx7fgiYDrUTQSlv0NRlnJXJWdl3WUL+XzLMSPStte9U1mWclelZ2WdZQA5jMsxI9K8uzZKgBTOZZiZ6V5Vky1AAm86xEz8rqLDi8xZjMsxI9K8uzputZk3lWomflevdVMs9K9Kz0rQVmMs9K9Kz07TaBZJ6V6FlZrQVlKKxMBlqJoJVVljV+MyxZ0bPS3/7NsGRF0Mq+/Wr4ZhhoJYJWxnZLWzLQSgStLNCavhkGWomglXX7lQzVqslEK1G0skRrXDAy0UoUrSzRkg9/lzKZaCWKVpZoyYe/xpFMtBJFK6Ozddg2MtFKFK0s0ZIPf40jmWglilb+46kjQ8lrMtJKJK3sG7Cmb4eZVqJpZfbcyt8FSYZaiaiVhVpyhqMfhlqJqJWFWjLUzSZDrUTUytwzlqlWompl3YElh7/NlYy1Elkrq0ZLDn+bK5lrJbpWlmvJUOiVzLUSXSt/a7SmvwnLWHStLNeSM/wAmWslulbWNVhyhh8gg61E2Mq6BkvO8ANkspUoW3k7Y4dzG0ZbibSVtzN2WCEx20q0rbx7xjLcSsStrIuwRIYfINOtRN3K0i0R/iZkMt1K1K0s3ZKhgCaZbiXqVt49Y5luJepWlm6JDD9ApluJupWlWyLDw4vpVqJuZemWyPDbYbqVqFtZuiUy/HaYbiXqVpZuiQzbcqZbibqVb89YpluJupWvM3b4ATLdStStfJ2xw8OL6VaibmXplgzv3yfTrUTdytItGd6/T6ZbibqVpVsy1L8k061E3bpdrUW3oJfZ1kXbumVbMrzCf5ltXbStW7Y1ZclltnXRtm61HpShDucy3LqIW7fqtWSow7lMty7q1i3dkuEd/st066Ju3c96AHsZb13krfvpfOXPv8t866Jv3U/nK//5XeZbF33rfjpf+fPvMt+66Fv3rKvYy3zrom/d8i0ZKgEu862LvnXLt2SoBLjMty761i3fEuPPv8t866Jv3bPOsJf51kXfuuVbMpQTXOZbF33rlm+JDT9A5lsXfeuWb4nxQ77LfOuib92zrgku862LvnXLt2R4kf8y37roW7cKtmR4kf8y4LoIXFc6Y/kO8DLhuihcV/Y5lhHXReK60hnLH6KXGddF47rVgFB8+AEy5LqIXLcuyxoeXYy4LhLXLeKS4f35y4jrInHdbj84/llZviJx3SIucf4wv4y4LhLXLeISH37DjLguEtct4pLhhfHLiOsicd1uPzj9TRhxXSSuWwVb4sOTmCHXReS6hVziw2+YIddF5Lp1Z9aQaoy4LhLXLeKS4SXry4jrInFd3VcEjLguEtct4hIfHuaMuC4S19XO12EaYMR1kbhuEZcMbzdfRlwXievaviJgxHWRuG4Rl8TwMGfEdZG4bhGXxPAbZsR1kbhuEZcMr+BdRlwXiesWcUkMz2FGXBeJ664XZ10mXBeF61bJloT/F/a//CgGYQmLxnWrZGvo53QZcV0krlutB2VoOn+ZcV00rltXZw0NnS4jrovEdX173eUy4booXLeFa/qrMuG6KFzXty5ZlwnXReG63sk6TGpMuC4K1y3huryo5zLhuihc12t2HV6suoy4LhLX7caD01fDchWJ6zZxjV8NS1YkrlvENX41LFeRuK733DrsthhxXSSuG7UWyGGCZsZ10bhubBe9XWZcF43rdu/BoYnDZch1EbludO+hIUkYcl1ErttlW8Mh0mXIdRG5bpdtDYdIlyHXReS6XbY1HCJdhlwXkes2cg1vrl6GXBeR61YDwnR24dNlxHWRuG7fofX5z/J/+bXEYsJ1Ubhu9x98PAYDrovAdbMXrh/++2XAdRG4bm7XEl7mWxd96+Z2LeFlvHWRt25u1xJeplsXdetWzdbQXPIy3LqIW7dqtobmkpfZ1kXburnVwl5GWxdp6/Y9WtO/gyUqytate7SmuZnB1kXYug1byV8/uAy2LsLWrYqt4X3Vy1zromvdqtga3pu9jLUusta92zuvl6nWRdW6VbFlh38xDLUuotatii2Tn1//CfximGldNK171xUAI62LpHWbtHJYzzDSukhat0hL0oYgLFWRtG6T1tBi4DLSukhat0krgwdhpHWRtG6TVuYQhCUrktZt0so7BGHZiqR1m7TyDUFYuiJp3bX/4GWidVG07vOl8e9loHURtO6LpQ/FZZ510bNuXaQ1NLq9jLMuctati7SmfRHTrIuadVuz7rDUZJp1UbNe1WrJ5UuixzzroWe99qzLt/GPedZDz3rlWTLc0/KYZz30rNeeNdzT8phnPfSs99kaYjzGWQ856322btmPadZDzXpVqzU8rx7DrIeY9T5b85bHLOuhZb3PXeorHqOsh5T1mrKu/xf6P8El72OU9ZCy3ulk5UcSj1HWQ8p6Z6t8eUyyHkrWO1vly2OQ9RCy3tlWAY851kPHemfNVMZYDxnrnW1afUyxHirWq66DwxLvMcR6iFivrtAapsTHDOuhYb26QmuYmh8jrIeE9ZqwhqXmY4T1kLBeE9ZQnvEYYT0krNeENZRnPEZYDwnrydbU9THBeihYrwXrPlp+85hgPRSsV1Va0++OAdZDwHqyXff2mGA9FKzXgvX49WaPCdZDwXqyTqsMsB4C1quGg8Pb0I/51UO/evKWddVjfPWQr17z1VA28xhfPeSrV3w1/lUZXz3kq1cVWsPq7DG9eqhXT7fO7o/h1UO8elWhJUMN0GN89ZCvXvPVUAP0GF895Kun68TK9OqhXj3N5aDoMbx6iFevug0OB0WP2dVDu3rVbZCfeT0mVw/l6v3KFT9rekyuHsrVs7OcNT0GVw/h6pksZ02PudVDt3qmy1nTY2z1kK2e2XLW9JhaPVSrV2o1nDU9plYP1epVXdZw1vQYWj1Eq1doNZw1PYZWD9HqNVpND2+GVg/R6hVaTU8ZhlYP0eoVWk1PO4ZWD9Hq+dkeMsysHprVK7MazokeM6uHZvVcl3Oix8jqIVm9tcngY2T1kKxek9VwTvQYWT0kq+exnRM9ZlYPzeq1WQ3nRI+Z1UOzen63c6LH0OohWr1Gq+Gc6DG0eohW7xet+DnRY2j1EK1enO2c6DG1eqhWryqzpvUMQ6uHaPWq1eC0oWFm9dCsXl2YNa1EGFk9JKtXF2ZNmxEmVg/F6tWFWdOmiIHVQ7B6DVZDHfFjYPUQrF5XZT3+ZtFjZPWQrF5s/YYfI6uHZPWyV6vDGQAzq4dm9booa7gI9DGzemhWr4uypl0RQ6uHaPW6KOvdIQjLVlSrl71e5XL9GFs9ZKuX28srj7HVQ7Z6xVbTU4+x1UO2esVW09OXsdVDtnp5190Ic6uHbvVyu4nwMbd66FbvbhWvj7HVQ7Z6d3sb4DG2eshWr8qxdCgTf8ytHrrVK7eaMoS51UO3elWNpUOp+WNw9RCu3l07Cz0mVw/l6t1+MzD+80eWRoyuHtLVq2uzflYk7FSTydVDuXp3PQdgcPUQrt56bdZjbvXQrV65lQ615o+51UO3euVWOpRFP+ZWD93qvc7W4YnF3OqhW71yKx0u8X3MrR661etSLB++YAZXD+HqVSmWDjcBPyZXD+XqvfUkgMnVQ7l6b91hMbl6KFfvLW+uPAZXD+Hqvf2ElcHVA7iST5Vh8cdEj/7/GH8//I2xUECPfsU4GEPmp0SPfsUQjKHzJq1Hv2IoxrB5k9ajXzEMYyxLgB79iuEYI5ZNWg9/BQkMkssmrYe/giQGucsmrYe/glwM8pZNWg9/BcFcbbfim7QexiAHk7VLsPgmrYe/gmC2dgkW36T18FcQTNeSK74g6dGvGJiuJVd8k9ajXzEwXUuu+HaiR79iYLq2XNFNWo9+xcBs3eSqR79iYLJW9ZXyi957+CsIJutZ3rTq0a8YmKvVXJA/I3oUYwimajUXpM+IHvwKgYkqsjwjevgrCCZqNRecnhGErf5++BtjYase/YqBiVpsNT0jCFv9/fA3RmzPCKJWfz/8jZHbM4Ko1d8Pf2Msna969CsG5mlXXU3PCMJWfz/sIM1W0zOCsNXfD3+DnPUZQdjq74e/QWR9RhC3+vvhbxBdnxEErv5++BvE1mcEgau/H/4G8fUZQeDq74e/QZZ7CHv0Kwama8HV9IwgcPX3w98Yy8VDPfoVA9O14Gp6RhC5+vthx7DP9owgcPX3w98Yvbei7wP08FcQTFbbSlp7+CsIJqv13ooeOPXwVxBM1t+ugrQhYA9/BcFktbmktQe/QmCqVsWVHno20sNfQTBXN7zq0a8YmKtbU8Ee/YqBudoFV8NvhtjV3w87RtnV9JshdvX3w98YZ1uKELv6++FvDNl+d8Su/n74G0O33x2xq78f/sawdS1C8Orvh79BfFkTEbr6++FviE5UenbWw19BMFF9TVQiV38//I2xJiqBq78f/sZYE5W41d8PO0asiUrY6u+HvzHWRCVq9ffD3xhrohK1+vvhb4w1UYla/f3wN8aeqISt/n74G2RLVKJWfz/8DdGJSk8Se/grCCZqrIlK1Orvh78x5sOqHvwKgXka656KmNXfDztGbtUrPYxBEhM1l+qVHv2KgYmaS/VKj37FwETN5b3VHv2KgYmaS/VKj37FwDzNpXqlR79iYKLmUr3So18xME9zq17p4a8gmKi5Va/08FcQTNXcqld6+CsI5upvpdWwmSFk9ffD3yBb9UoPfwXBZL1b9UoPfwXBbL1b9UoPfwXBdL1L9UqPfsXAdL3La9Y9+hUD0/Uu1Ss9+hUD0/Uu1Ss9+hUDs/Uu1Ss9+hUDk7VKrfRQKOrhryCYrE1WvH1nD2OQh8naZHWcz86ErP5++BtElv4RPfwVBJP1LcDao18xMFefLeX0PfwVBJO1S62Ghx4Bq78f/sboRQBVrx7+CoLZWr0D5++GpevDdN2KrXr0Kwam63vrV8OyFcnqdK3V8NUcZlYHzep8tvXqYWZ10KxOlVrp4YfNh6HVQbQ6VWo1fTWHqdVBtTqfpZNFj37FMIyxdbLo4a8gjkG2lcBhanVQrc5n62TRw19BEoMsnSx69CvGxRg9t/KDosPQ6iBandNzKz/jOQytDqLVKbRSoRf19fBXEEzXI2umMbQ6iFan+gaq0BtxevgrCKZr9Q1UoYWOPfwVBPO1+gaqKE8T5lYH3eqcbSlwmFsddKtTbQNVbPiHsHxFuDoNVzIkPYOrg3B1quZKJYYgLGFRrk7VXPHKjx7FGChXRzpfh5mR2dVBuzplV2PSM7s6aFdH9umV4dVBvDpia9IzvTqoV0f2fGV8dZCvjqz5yvjqIF8d2fOV+dVBvzqy5ysDrIOAdWTPVwZYBwHr6JqvzK8O+tXRztdhpmd+ddCvju75yvzqoF8d3fOV+dVBvzra+UpbBfXwVxDMV93zlfnVQb86uuYr86uDfnV0z1cGWAcB6+ier0ywDgrW0T1fGWEdJKxja74ywjpIWKcJS7m1HEZYBwnrFGGp8nPwwwjrIGEd2/OVEdZBwjq2z6+MsA4S1jFfFxUMsQ4i1mnEmpKeIdZBxDqNWEPSM8Q6iFjH7pr0TLEOKtaxtyY9Y6yDjHXqaqwx6ZljHXSsU40Dp6RnjnXQsY53vvLj8MMg6yBkHd/zlUnWQck6vucrk6yDknV8n1+ZZR20rOPr/Moo6yBlHd/nV2ZZBy3r+D6/Msw6iFnH9/mVadZBzTqxzq9Msw5q1omeX/mp2mGcdZCzTuz7LeZZBz3rhK6PcgZaB0HrhK2pxkDrIGid2F4TPEy0DorWadGaUo2J1kHROpFrqjHSOkhaJ+6aagy1DqLWqeuxxlRj6YqodQq1VPnZ62GodRC1zm/zQP42ymGqdVC1Tvb8Sq+87uGvIJivVYilP/dP0CAsX9G1Ts5dr3vwKwRma92NpTrsQJlrHXStU3djqQ7bAgZbB2HrFGwpv32ih7+CYLoWbKkNCz4GWwdh6xRsqQ0LPgZbB2HrFGwpvziihzEIwtYp2FIb5lcGWwdh63Qxlg2/HAZbB2HrNGzxxl09/BUE87WrsfjFET38FQQztqqx1PhB/2G0dZC2TtOWMak/TLYOyta5S9PrHv2Kgel6O11p19we/gqC6VrFWJ4//xdE9sNg6yBsnVdvtlwagrHWQdY6zVr8Aowe/gqCqfq2FwYOU62DqnW6EOvn/gs2szLWOshap1hL+f0XPfwVBDO1C7H45RU9/BUEM7Vdy4d5hLnWQdc67Vo+zCPMtQ661inXGr8clqvoWuctJdk9+hUDklXKtT7DewfCXEvQtaR6CCq/RKOHv4IcDCLLukaYawm6lnQLQV473MNfQRSDdLryiVUYbAnClnw6XfnEKgy2BGFLqh5rqJXt4a8ggUE6XfmiRJhsCcqWVD2WOp+QhNGWIG3JP6Ya7jLu0a8YmK+nerPkfy7/k4RXIITBliBsSXUR5EW7PfoVA7P1bJOrMNYSZC05W4mLMNUSVC2pWqzhjS5hqCWIWnK20kFhpiVoWnJ6ZuUPCmGoJYha0qgV/DBbGGoJopZ0H0HaVqlHv2Jgpp6lJLtHv2JgplYxVgzZzkhLkLSkSSv4Q08YaQmSljRpBX/oCSMtQdKSKseafrtMtARFS7oca/jtMtASBC2pcqzpt8s8S9CzpLoI6s+lMyzNGGgJgpZ0F8FhAmCeJehZ0vVYwwTAOEuQs0SWThc9+hUDU1WXW1p6FGOgZome7SfDMEsQs6QxK4Z1BMMsQcySwqyh7L+Hv4JgqtYVWNOPl1mWoGVJW1YM6whmWYKWJWVZ0++OWZagZUnVYk2/O0ZZgpQlujS66NGvGJiqLVkRwzfDchUlS0qyxh8voyxBypJqIzg9I5hkCUqW2LoCYJAlCFli6wqAOZagY4mtKwDGWIKMJdvlVz36FQMztdoIThMAQyxBxBKrywWddlTq4a8gmKpVijX9dhliCSKWNGLxq556+CsIpmrVYk2/XWZYgoYl3Udw+O0ywxI0LPE1UxlhCRKW+JqpTLAEBUt8zVQGWIKAJb5mKvMrQb+S8qtpLmN+JehXUqVYU7YzvhLkK/E1UZleCeqVtF7FsDFjeiWoVxJrojK9EtQriTVRGV4J4pXEmqjMrgTtSmJNVEZXgnQlsSYqkytBuZJYE5XJlaBcSayJyuBKEK4k1kRlbiXoVhJrojK2EmQriU5ULhLC3ErQrSTXRGVsJchWkmuiMrUSVCtZa7GEoZUgWkmuicrMStCsJNdEZWgliFay9Q7s0a8YmKi5JiojK0GyklwTlYmVoFhJronKwEoQrKTBit8C2MNfQTBR75qozKsEvUrumqiMqwS5SurKq+mLYVolqFXSV14Nyc6wShCrpKuwhmRnViVoVXK3TizCqEqQqmS78qpHv2Jgot5cj7oYVglilTRWTUddDKsEsUoKq6ZtDNMqQa2S0qrpZ8e4SpCr5B89jT87plWCWiXdN5BfzdjDX0EwVd96SsW0SlCrpNsG2qVv0AjTKkGtkrceUzGsEsQqeWuuMqsStCp566TKqEqQquRVquZwfsisStCq5K1n/8yqBK1K26qGb0aZVSlalX62w39lVKVIVfpZ7mXp0a8YgjF0+WaUSZWiVGlLVXKJVCZVilKla+NAZVClCFW63XbVo18xAmNUBRa/ZaqHv4IkBrnLM0IZUykylXYFVvL3xZQ5laJTaVdgDa6qDKoUoUq7AuunnpschyiTKkWp0q7ASo6IyqhKkaq0K7Dy0seVMqtStCrtCqzkWwBlWKWIVVoVWGOaMK1S1CpdK7CUYZUiVulZel336FcMTNezpiuzKkWr0q6/4lcJ9vBXEExX+aw5z7RKUatUtvetlWGVIlZpY9XlywBlWKWIVSrbilUZVililXb51fDmizKtUtQq7fKr8c/KkhW5SpurLn/+KuMqRa7Srr+6w6OCeZWiV+naP1CZVyl6lbZXTd8Ny1b0KtWtf7Ayr1L0KtXlgpYe/YqByarb7koZVylyleq6DmBapahVqluPC2VapahV2lrFb9/s4a8gmKpdeSX/+fnfR77+qCxTUatUt95ByrRKUau0Cq8+Mfx4GVcpcpUWV32Sb9GUcZUiV6lt2ytlWqWoVVqFV9M7Wsq4SpGrtAuvLtdIZV6l6FVaXjV9N8yrFL1Ky6vy/Dwkvn80zKsUvUrLq3jr/h79ioG52lVXl780rgysFMFKradV7kTKwEoRrLTLrvhdkT38FQSztcTqI7xPlTKxUhQr9b6jTXkQRlaKZKVVdqV3WOYxs1I0Ky2z+lkGsC+HmZWiWWmZ1c9zk8Zg2Ypmpb41uVBmVopmpWVWPzMr/XewbEWz0jKry8sklJmVollpmdUddhPMrBTNSsusLu/7qcysFM1Kq33gHfYSjKwUyUqLrO4wwTOyUiQrLbJ6w/zOyEqRrLTI6g15yshKkay0yOoNecrISpGstMjq8bcilJGVIllpkdUb8pSRlSJZaZHVG/KUkZUiWWmR1RsmZkZWimSlRVZv2PQyslIkK632gW/IUyZWimKlJVZvyFMmVopipV1o9RkSlZGVIllpFVp9PkOmMrNSNCutQqvPZ0hVhlaKaKV149XnM+QqUytFtdIqtfp8hmRlbKXIVlqlVp/PkK3MrRTdSqvU6vMZ0pXBlSJcaZVafT7DvMrkSlGutOTq8xkSlsmVolxplVp9PkPGMrpSpCutUqvPGTKW2ZWiXWmVWn3OkLEMrxTxSqvU6sTwFTO9UtQr7VKrNxyxML5S5CvtUit+VXMPfwXBjK2Lr5TfbtzDX0EwYxuw+O3GPfwVBDO2+gie83Og/w6ebDC/UvQr7T6C0xOHAZYiYGn3EeS3G/YwBkHB0i64+nnm0CAsYZGwtAmL30zYw19BMGGr4mqqqlVmWIqGpW1Yl9fBKDMsRcPSrrh6vDebMsRSRCztiqvHS8mVKZaiYmlVXBm/Aa+Hv4Jgwr41YZliKSqWvj1hGWMpMpY1Yw3fsDHGMmQsq5Kr6Rs25liGjmXdS3D47xiDLEPIsqq5Mn4rYA9/BVEMUlcK0Tuoe/QrhmEMr38InxuNSZahZNnaS9CYZBlKln1yORY0BlmGkGUFWcORnjHIMoQs+2xHrcYcy9Cx7GxHrcYYy5Cx7GxHrcYUy1CxrOut+MswxhDLELHsbEetxgzL0LCsDMv4HYk9/BUEM7ULroYvlxGWIWHZWROVEZYhYdnZaliMEZYhYVkRlvnw5bJERcKys90nYEywDAXLqtxqeBfGGGAZApbV3VfKjzeNAZYhYJnINpMxvzL0Kyu/miYQ5leGfmVVbDVU1BvjK0O+si624v2mjemVoV5ZNQ8cGvgawytDvDLZ3mIxZleGdmXVO9D4vaQ9/BUEE1XWQ1ZjemWoV6brIasxvjLkK6vmgcZvSO3hryCYq+VXw3G+Mb8y9CsrvxqO8435laFfWbcOHI7ijQGWIWCZ9uOfV1wbAyxDwLJ/GnVsuMrPmGAZCpZpL1f5eb4xwjIkLNNtuWpMsAwFy0qw7ENvOe/hryCYrt068GelyYIwwjIkLCvCOpc3LzNGWIaEZUVY58oQhOUrEpZV78Dzc6JPg7CERcOyvv7q2hCEJSwillXvQDvTH5YlLCqWlWLZmf6wLGFRsawUy870h2UJi4plpVj2cykA2ekZUyxDxbJSLDvTH5ZlLCqWlWLZGeZGpliGimXdPDB50xJjimWoWFaKNU2OTLEMFcu6eeA0OTLGMmQsq+aBNjT0N+ZYho5lvqmrMccydCzzztdhgmWQZQhZ5p2vwwTLJMtQsszXCZZJlqFkme8TLKMsQ8qy2CdYZlmGlmWxT7AMswwxy2KfYJlmGWqWxT7BMs4y5CyLfYJlnmXoWRb7BMtAyxC0LPYJlomWoWhZ7BMsIy1D0rLYJ1hmWoamZbFPsAy1DFHLsidYLvzGVMtQtaxUy4Qf6hlTLUPVslItk+HwiamWoWpZqZbJcHDEVMtQtaxUy2Q4GGCqZahaVqplMmxSmGoZqpaVapkMjz+mWoaqZaVaJsMDg6mWoWpZqZYNHfmNqZahalm+bZPCUMsQtazKsYb30oyZlqFp2e18HR46zLQMTctu5ys/DjdmWoamZWVapsPShJmWoWlZmZYp70FozLQMTcvKtGzojmzMtAxNy8q0TId5jZmWoWlZNRAcvN8YaRmSllVNlg1dUY2ZlqFpWZmW6fDrY6ZlaFpWRVnDmzrGSMuQtKxIy3T4BTPSMiQtK9KyoaOpMdIyJC17na/DL4eRliFp2et8HX45jLQMScuKtGzoaGqMtAxJy4q0bOhoaoy0DEnLmrSGjqbGSMuQtKwqs2zoaGrMtAxNy8q0bOhoasy0DE3Ly7RsaEbqzLQcTcvLtGxoRurMtBxNy8u0zHjGOjMtR9PyNq2h/6Yz03I0La/qLDO+SnKGWo6o5Z+NCpyZlqNp+WfrIeTMtBxNy8u0Bm5wZlqOpuWfreelM9NyNC0v0xq4wZlpOZqWl2kN3ODMtBxNy9cegs5My9G0vCqzzLnhOkMtR9TyQq3hnN8ZajmillcTweGc35lpOZqWl2kN5/zOTMvRtLxMS9/PtbCJBUTOTMvRtLzLsj5DDJaoaFreppU/S87jijFYoqJpeZmW3SEGS1Q0LS/TsvcTIwy/W2Zajqbl0l3aP7QEyRlqOaKWN2pxXHOGWo6o5YVaQ82dM9RyRC0v1BruDXaGWo6o5YVaw/3FzlDLEbVctl5XzlDLEbW8KrJsaGjsTLUcVcurImvY2DhDLUfUctk2WM5My9G0vCuyhscUIy1H0vK1g6Az0XIULdetMtuZaDmKlutWPehMtBxFy3Xrd+EMtBxBy9W3Rx3zLEfP8vas6RHDPMvRs1y391mccZYjZ3n3DxweU4yz/nz4G2N7TcCZZjlqllc91vSoY5jliFne3QOHRx2zLEfL8uoeOD3qGGU5UpZ398DhUccky1GyvKqxpkcMgyxHyPLuHjg8LpljOTqWV/fA6XHJGMuRsbyuwJqeUkyxHBXLq3ng8AqIM8RyRCy3t7wC4sywHA3Lq3cgv1PBmWA5CpZX60D3/9z+J4r/DAZYjoDlBVgeQwyWpghYXmVY/EoFZ3zlyFdeVVj8SgVneOWIV1545W/4n7AkRbzyKsKKzxCDJSnalVcRVpwhBktSpCvvxoEyxGBJinTlVYQVOsRgSYpy5VWEFcZjMLhyhCuvIqwYspS5laNbeRVhxZCljK0c2cqrCCtyiMHSFNXKqwgr7hCD5Smila83XjkzK0ez8irCmpa4jKwcycqrCGtaajOxchQrX/sGOgMrR7DyBqvhyg5nYOUIVr72DXTmVY5e5V2FZfzdL2de5ehVnlvHAGdc5chVXo0Dp8cc0ypHrfJqHDg95hhWOWKVV+PA6THHrMrRqrwbBw5LOkZVjlTlud0d5EyqHKXKq3HgtCxkUOUIVV5QNS0LGVQ5QpUXVE3LQgZVjlDl1TdwWhYyp3J0Kq++gdMMwpjKkam8+gZOMwhTKkel8u4bOOznGFI5IpV338BhP8eMytGo/G4NrpwRlSNReRHV8Bq8M6JyJCrvqqthj8yEylGo/K5HqAyoHIHK37rfZ0DlCFReXQOnbQPzKUef8rrjato2MJ5y5CmvpoHTFojplKNO+duutnCGU4445W998jObcrQpb5sa7qZyZlOONuXVNHA6VGI05UhTXtVW06ESkylHmfLqGTgmGUtUhKn4bP1XgrlUoEtFtQwcJqFgLBXIUvHZOgYHU6lAlYrP1jE4GEoFolRUodXw4w9mUoEmFVVoNa2EgqFUIErFZ2sZHAylAlEqutCKrx6CoVQgSsVnO5gKhlKBKBWFUsPqIRhKBaJUNErx1UMwlApEqWiU4quHYCgViFJRhVbD6iGYSQWaVJxtRg1mUoEmFWVSw9MhmEkFmlR0nRV/OgQzqUCTijYpvtoOZlKBJhVlUsNqO5hJBZpU9LVWfLUdzKQCTSrKpPihUjCSCiSpKJIaDpWCkVQgSUWVWQ2HSsFEKlCkokSKHyoFA6lAkIoGKXqoFMyjAj0qyqOGQ6VgHhXoUVEeNRwqBfOoQI+K8qjhUCmYRwV6VFSR1XCoFIyjAjkqiqOGQ6VgHBXIUVEcNRwqBeOoQI6K4qjhUCkYRwVyVBRHDYdKwTgqkKOiOGo4VArGUYEcFcVRw6FSMI4K5KgojhqWlsE4KpCjQjc3DcZRgRwV1R9w2BIG06hAjYrSqOFQKZhGBWpUVH9AGy4sDcZRgRwVxVHTspBxVCBHRbcHHJaFjKMCOSqKo6ZlIeOoQI6KvsyK702DcVQgR4VtlYDBOCqQo6I4aloVMo4K5KjouqrBPIN5VKBHxXqbVTCPCvSoKI8a9i/BPCrQo6KrqobLaIOBVCBIRYHUsKELBlKBIBUNUsMaholUoEhFidT0B2EiFShS0ZdZDV8ME6lAkYq+zGr45TKSCiSp6Mushl8uM6lAk4q+zGr45TKTCjSpKJOaNnTMpAJNKrqeavrFMJQKRKnw7YbAYCgViFJRKDVtxhhKBaJUxPZ2XzCUCkSpKJSaNnQMpQJRKgqlpg0dQ6lAlIpCqWlDx1AqEKWiUGra0DGUCkSp6Mushg0dQ6lAlIpGqWFDx1AqEKWiUWrY0DGUCkSpKJSaNnQMpQJRKqoz4LShYyYVaFJRJjVt6JhJBZpU1F1Ww4aOiVSgSEWJ1LShYyIVKFJRIjVt6JhIBYpUlEgNGzoGUoEgFQVSw4aOeVSgR0V51LShYx4V6FFRHjVt6JhHBXpU9EVWw4aOeVSgR0V51LShYx4V6FFRHjVt6JhHBXpUlEdNGzrmUYEeFeVR04aOeVSgR0V51LShYx4V6FFRHjVt6JhHBXpUlEdNGzrmUYEeFXe7wCKYRwV6VJRHTRs65lGBHhXlUdOGjnlUoEdFedS0oWMeFehRUU0AzXnpSDCQCgSpKJAa3hIIBlKBIBVVMDWejTORChSpeFv/n2AiFShSUSI1PeaYSAWKVPQtVsNjjolUoEhF3WI1PeYYSAWCVLz1nJ+BVCBIxVvP+RlIBYJUvPWcn4FUIEjlZzvnTwZSiSCVn+2cPxlIJYJUfrZz/mQglQhS2SDFZ5BkIJUIUvnZXulPBlKJIJXrFVbJPCrRo7I8atjPJfOoRI/Kz3YlUDKPSvSoXG+wSuZRiR6V3fiP75GTeVSiR2U3/uP7ymQelehRebb9fjKPSvSobI/i24ZkHpXoUdkexbcNyTwq0aPybC9KJ/OoRI/K8qjhLYFkHpXoUbleXZXMoxI9Kk/v93mNZDKQSgSpPFvpSTKQSgSpPFvpSTKRShSplO1VlGQilShSKVvpSTKRShSplK30JBlJJZJUrhdXJTOpRJNK2UpPkplUokmlbKUnyUwq0aSyrq2aVkLJUCoRpVK20pNkKJWIUlkoNawekqFUIkqlbAdTyVAqEaVSt9KTZCiViFKpW+lJMpRKRKnUrfQkGUololTqVnqSDKUSUSp1nVEZSiWiVOpWepIMpRJRKnUrPUmGUokolbqVniRDqUSUSt1KT5KZVKJJpW6lJ8lMKtGk0pbSk2QklUhSaVvpSTKSSiSptK30JBlJJZJU2lJ6kkykEkUqbSk9SQZSiSCVtpWeJPOoRI9K20pPknlUokelbaUnyTwq0aPSttKTZByVyFFpW+lJMo5K5Kj0rfQkGUclclT6VnqSjKMSOSp9Kz1JxlGJHJW+lZ4k46hEjkrfSk+ScVQiR6VvL6Am46hEjkrfSk+ScVQiR6VvpSfJNCpRo9K30pNkGpWoUdnd/Zx3AUnGUYkclcVR07KQcVQiR2Vx1LQsZByVyFFZHDUtCxlHJXJUFkdNe1PGUYkclbFd/5eMoxI5KoujplUh46hEjspYK6OTeVSiR2VsjamTeVSiR2Vsnf6TeVSiR+VvkRRvNZMMpBJBKvOzNbdOJlKJIpVdJTU0t05mUokmld3VL3ibpmQolYhS2V39gvdXSKZSiSqV3dUvePVZMpdKdKmsrn7n8cudkslUokxld/UL/mZ/MppKpKnsu6qGW0OS2VSiTWVujVOT2VSiTWVdVWXBX8BKhlOJOJV33fkznErEqeyufsHfr0mmU4k6ld3Vb+ill4ynEnkqu6tfBP9umE8l+lTe7a2UZD6V6FN5t7dSkvlUok9l+dT0pGA+lehTebeWU8l8KtGncq2XSuZTiT6V3dEvhtMyBlSJQJUNVDGsJRhQJQJVvnUdwIAqEaiygWqaoBlQJQJV/nb04y0bkwlVolDlb0c/3sYyGVElElV2R78YnnzMqBKNKrtqKofnDUOqRKTKQqppWmRIlYhU2Q39cnhmMaVKVKrshn4pw9+V5Ssy1e2GfskfN5c51UWnut3QL/ksfxlUXYSq+5HtuqzLpOqiVN1q6Cc/t3+Qv8llVHWRqm419JMPv2nuMqu6aFW3iqfkw2+auwyrLmLV/SdPR36uqaBBSMJe1Kr7KQVI/ui7jKsuctX9dMZyeL/Mqy561f10xvIZ9jKwughWt8Bq+P1dBlYXweqerdLvMrC6CFb3bJV+l4HVRbC6Z6v0uwysLoLVrZuqxt8NE6uLYnVPZyvvunoZWV0kq3sqWw+f6C8zq4tmdduskj9ALzOri2Z1T2crf1pchlYX0eoWWo2JxpIV0erKdipwGVpdRKvbnf3S6YLxMrW6qFZXtmOBy9TqolrdfwQ1Zxpjq4tsdaUm18OfWpe51UW3ulLpOrTIvwyuLsLVLbiyy1cDl8HVRbi63d3v8if5ZXJ1Ua6ubDuty+TqolzdurLK7vR3ZemKdHV/r6wavmFmVxft6taVVXKGxyfDq4t4df9J1JEzPD6ZXl3Uq6u1GjjD45Px1UW+utoJy69HvcyvLvrV7Uur7rDMYoB1EbBuN/m7wzKLCdZFwbq6LV8vE6yLgnWrrGpOE5awSFi3Lq0SGZ4WzLAuGtatS6tE+I78MsW6qFi3Lq2yOyyQGGNdZKxbl1bZHRZIzLEuOtYtx5q+HAZZFyHr1p1V40TAKOsiZd2qrRq/YWZZFy3r1p1VIsMszTDrImbdurNKZFjRM826qFm3qqtEhimJcdZFzrrWCTtMScyzLnrW7Tur7rAEZqB1EbSud8IOayQmWhdF63aB1ZBrTLQuitbtAiv+/shlonVRtG5dWXWUX058GWldJK3re74y07poWtc7X4eZnqHWRdS63vk6rKSZal1UreuVr8ORyWWsdZG1brGWDKeVl7HWRda6dWmV6DCbMNe66Fq3XEvyx4LwJZLLWOsia93o6XVY0TPXuuhat66ssjes+BhsXYStW7A1/W4YbF2ErVuwNRxXXgZbF2HrFmyNKc9g6yJs3bqwSnSYXZlsXZStG52tw+zKaOsibd2mrTcspBltXaSt2xdWPc44l9HWRdq6VWw1fcFMti7K1s3tJcHLYOsibN3cXhK8zLUuutbN7SXBy1jrImvd3OdWxloXWesWa4kOS3HGWhdZ62Zn6zBBM9a6yFq3L6t6w1KcudZF17rtWm9YijPXuuha964nWcy1LrrWvetJFmOti6x173qSxVTromrdu55kMdS6iFq3UYtj0mWodRG17l1nVoZaF1Hr3n1mZap1UbXurVy14RHOWOsia926qUpseIQz17roWrdd6w3bG+ZaF13rtmu9YXvDXOuia923zqzMtS661i3Xksdp+zLXuuha963ZyljrImvdt5+7Mta6yFq3WEts2CIx1rrIWrdYS2x4iDPWushaty+qesPGhLnWRde67Vpv2Jgw17roWvet566MtS6y1vts566PqdZD1XqfTWEfQ62HqPU+27HrY6b10LTeZz12fcy0HprWa9Myvnl9zLQemtZr0zL+EH/MtB6a1ivTssdX8o+Z1kPTemVa/uEr+cdM66Fpvc927PoYaT0krdclWFOSkGR9KFqvS7CGJGGi9VC0XonW8Ox8TLQeitY7q8A+RloPSeudOnM1vv99zLQemtYr0xLnD8/HTOuhab2qwuK7zsdE66FovRIt//BNyWOi9VC03ulc5ZuSx0TroWi9s+YqA62HoPXO1sjqMdB6CFpPtkZWj4HWQ9B6sjWyesyzHnrWkz1XGWg9BK1XoCXODzceA62HoPUatJw/wh8DrYeg9Qq0/MM3JY+B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"; \ No newline at end of file +window.searchData = "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"; \ No newline at end of file diff --git a/classes/types.ActionBase.html b/classes/types.ActionBase.html index b60d10b8dead812ea6b817175b240563ae933972..3d870fef02872fefc474ac337a15fea87541d5d1 100644 --- a/classes/types.ActionBase.html +++ b/classes/types.ActionBase.html @@ -40,7 +40,7 @@ Extend this class to implement custom action handlers for:

// Redux state management example
class ReduxAction extends ActionBase {
constructor(
strategyName: StrategyName,
frameName: FrameName,
actionName: ActionName,
private store: Store
) {
super(strategyName, frameName, actionName);
}

signal(event: IStrategyTickResult) {
this.store.dispatch({
type: 'STRATEGY_SIGNAL',
payload: { event, strategyName: this.strategyName, frameName: this.frameName }
});
}

partialProfit(event: PartialProfitContract) {
this.store.dispatch({
type: 'PARTIAL_PROFIT',
payload: { event, strategyName: this.strategyName }
});
}
}
-

Implements

Constructors

Implements

Constructors

Properties

actionName backtest frameName @@ -62,7 +62,7 @@ Extend this class to implement custom action handlers for:

  • frameName: string

    Timeframe identifier this action is attached to

  • actionName: string

    Action identifier

  • backtest: boolean

    If running in backtest

    -
  • Returns ActionBase

    Properties

    actionName: string
    backtest: boolean
    frameName: string
    strategyName: string

    Methods

    • Handles breakeven events when stop-loss is moved to entry price.

      +

    Returns ActionBase

    Properties

    actionName: string
    backtest: boolean
    frameName: string
    strategyName: string

    Methods

    • Handles breakeven events when stop-loss is moved to entry price.

      Called once per signal when price moves far enough to cover fees and slippage. Breakeven threshold: (CC_PERCENT_SLIPPAGE + CC_PERCENT_FEE) * 2 + CC_BREAKEVEN_THRESHOLD

      Triggered by: ActionCoreService.breakevenAvailable() via BreakevenConnectionService @@ -73,7 +73,7 @@ Frequency: Once per signal when threshold reached

    • Optionalsource: string

    Returns void | Promise<void>

    async breakevenAvailable(event: BreakevenContract) {
    await this.telegram.send(
    `[${event.strategyName}] Breakeven reached! ` +
    `Signal: ${event.data.side} @ ${event.currentPrice}`
    );
    }
    -
    • Cleans up resources and subscriptions when action handler is disposed.

      +
    • Cleans up resources and subscriptions when action handler is disposed.

      Called once when strategy execution ends. Guaranteed to run exactly once via singleshot pattern.

      Override to:

      @@ -88,7 +88,7 @@ Guaranteed to run exactly once via singleshot pattern.

      Parameters

      • Optionalsource: string

      Returns void | Promise<void>

      async dispose() {
      super.dispose(); // Keep parent logging
      await this.db?.disconnect();
      await this.telegram?.close();
      await this.cache?.quit();
      console.log('Action disposed successfully');
      }
      -
    • Initializes the action handler.

      +
    • Initializes the action handler.

      Called once after construction. Override to perform async initialization:

      • Establish database connections
      • @@ -100,7 +100,7 @@ Guaranteed to run exactly once via singleshot pattern.

      Parameters

      • Optionalsource: string

      Returns void | Promise<void>

      async init() {
      super.init(); // Keep parent logging
      this.db = await connectToDatabase();
      this.telegram = new TelegramBot(process.env.TOKEN);
      }
      -
    • Handles partial loss level events (-10%, -20%, -30%, etc).

      +
    • Handles partial loss level events (-10%, -20%, -30%, etc).

      Called once per loss level per signal (deduplicated). Use to track loss milestones and implement risk management actions.

      Triggered by: ActionCoreService.partialLossAvailable() via PartialConnectionService @@ -111,7 +111,7 @@ Frequency: Once per loss level per signal

    • Optionalsource: string

    Returns void | Promise<void>

    async partialLossAvailable(event: PartialLossContract) {
    await this.telegram.send(
    `[${event.strategyName}] Loss ${event.level}% reached! ` +
    `Current price: ${event.currentPrice}`
    );
    // Optionally adjust risk management
    }
    -
    • Handles partial profit level events (10%, 20%, 30%, etc).

      +
    • Handles partial profit level events (10%, 20%, 30%, etc).

      Called once per profit level per signal (deduplicated). Use to track profit milestones and adjust position management.

      Triggered by: ActionCoreService.partialProfitAvailable() via PartialConnectionService @@ -122,7 +122,7 @@ Frequency: Once per profit level per signal

    • Optionalsource: string

    Returns void | Promise<void>

    async partialProfitAvailable(event: PartialProfitContract) {
    await this.telegram.send(
    `[${event.strategyName}] Profit ${event.level}% reached! ` +
    `Current price: ${event.currentPrice}`
    );
    // Optionally tighten stop-loss or take partial profit
    }
    -
    • Handles active ping events during active pending signal monitoring.

      +
    • Handles active ping events during active pending signal monitoring.

      Called every minute while a pending signal is active (position open). Use to monitor active positions and track lifecycle.

      Triggered by: ActionCoreService.pingActive() via StrategyConnectionService @@ -133,7 +133,7 @@ Frequency: Every minute while pending signal is active

    • Optionalsource: string

    Returns void | Promise<void>

    pingActive(event: ActivePingContract) {
    const holdTime = getTimestamp() - event.data.pendingAt;
    const holdMinutes = Math.floor(holdTime / 60000);
    console.log(`Active signal holding ${holdMinutes} minutes`);
    }
    -
    • Handles idle ping events when no signal is active.

      +
    • Handles idle ping events when no signal is active.

      Called every tick while no signal is pending or scheduled. Use to monitor idle strategy state and implement entry condition logic.

      Triggered by: ActionCoreService.pingIdle() via StrategyConnectionService @@ -141,7 +141,7 @@ Source: idlePingSubject.next() in CREATE_COMMIT_IDLE_PING_FN callback Frequency: Every tick while no signal is pending or scheduled

      Default implementation: Logs idle ping event.

      Parameters

      • event: IdlePingContract

        Idle ping data with symbol, strategy info, current price, timestamp

        -
      • Optionalsource: string

      Returns void | Promise<void>

    • Handles scheduled ping events during scheduled signal monitoring.

      +
    • Optionalsource: string

    Returns void | Promise<void>

    • Handles scheduled ping events during scheduled signal monitoring.

      Called every minute while a scheduled signal is waiting for activation. Use to monitor pending signals and track wait time.

      Triggered by: ActionCoreService.pingScheduled() via StrategyConnectionService @@ -152,7 +152,7 @@ Frequency: Every minute while scheduled signal is waiting

    • Optionalsource: string

    Returns void | Promise<void>

    pingScheduled(event: SchedulePingContract) {
    const waitTime = getTimestamp() - event.data.timestampScheduled;
    const waitMinutes = Math.floor(waitTime / 60000);
    console.log(`Scheduled signal waiting ${waitMinutes} minutes`);
    }
    -
    • Handles risk rejection events when signals fail risk validation.

      +
    • Handles risk rejection events when signals fail risk validation.

      Called only when signal is rejected (not emitted for allowed signals). Use to track rejected signals and analyze risk management effectiveness.

      Triggered by: ActionCoreService.riskRejection() via RiskConnectionService @@ -163,7 +163,7 @@ Frequency: Only when signal fails risk validation

    • Optionalsource: string

    Returns void | Promise<void>

    async riskRejection(event: RiskContract) {
    await this.telegram.send(
    `[${event.strategyName}] Signal rejected!\n` +
    `Reason: ${event.rejectionNote}\n` +
    `Active positions: ${event.activePositionCount}`
    );
    this.metrics.recordRejection(event.rejectionId);
    }
    -
    • Handles signal events from all modes (live + backtest).

      +
    • Handles signal events from all modes (live + backtest).

      Called every tick/candle when strategy is evaluated. Receives all signal states: idle, scheduled, opened, active, closed, cancelled.

      Triggered by: ActionCoreService.signal() via StrategyConnectionService @@ -174,7 +174,7 @@ Frequency: Every tick/candle

    • Optionalsource: string

    Returns void | Promise<void>

    signal(event: IStrategyTickResult) {
    if (event.action === 'opened') {
    console.log(`Signal opened: ${event.signal.side} at ${event.signal.priceOpen}`);
    }
    if (event.action === 'closed') {
    console.log(`Signal closed: PNL ${event.signal.revenue}%`);
    }
    }
    -
    • Handles signal events from backtest only.

      +
    • Handles signal events from backtest only.

      Called every candle in backtest mode. Use for actions specific to backtesting (e.g., collecting test metrics).

      Triggered by: ActionCoreService.signalBacktest() via StrategyConnectionService @@ -185,7 +185,7 @@ Frequency: Every candle in backtest mode

    • Optionalsource: string

    Returns void | Promise<void>

    signalBacktest(event: IStrategyTickResult) {
    if (event.action === 'closed') {
    this.backtestMetrics.recordTrade(event.signal);
    }
    }
    -
    • Handles signal events from live trading only.

      +
    • Handles signal events from live trading only.

      Called every tick in live mode. Use for actions that should only run in production (e.g., sending real notifications).

      Triggered by: ActionCoreService.signalLive() via StrategyConnectionService @@ -196,7 +196,7 @@ Frequency: Every tick in live mode

    • Optionalsource: string

    Returns void | Promise<void>

    async signalLive(event: IStrategyTickResult) {
    if (event.action === 'opened') {
    await this.telegram.send('Real trade opened!');
    await this.placeRealOrder(event.signal);
    }
    }
    -
    +

    Utilities for calculating take profit and stop loss price levels. Automatically inverts direction based on position type (long/short).

    -

    Constructors

    Constructors

    Properties

    Constructors

    Properties

    bracket: (
        dto: {
            currentPrice: number;
            percentStopLoss: number;
            percentTakeProfit: number;
            position: "long" | "short";
        },
    ) => {
        position: "long"
        | "short";
        priceStopLoss: number;
        priceTakeProfit: number;
    }

    Calculates levels for a bracket order with custom TP and SL.

    @@ -9,12 +9,12 @@ Automatically inverts direction based on position type (long/short).

  • percentTakeProfit: number

    take profit percentage from 0 to 100

  • position: "long" | "short"

    position type: "long" or "short"

  • Returns { position: "long" | "short"; priceStopLoss: number; priceTakeProfit: number }

    priceTakeProfit and priceStopLoss in fiat

    -
    moonbag: (
        dto: {
            currentPrice: number;
            percentStopLoss: number;
            position: "long" | "short";
        },
    ) => {
        position: "long"
        | "short";
        priceStopLoss: number;
        priceTakeProfit: number;
    }

    Calculates levels for the "moonbag" strategy — fixed TP at 50% from the current price.

    +
    moonbag: (
        dto: {
            currentPrice: number;
            percentStopLoss: number;
            position: "long" | "short";
        },
    ) => {
        position: "long"
        | "short";
        priceStopLoss: number;
        priceTakeProfit: number;
    }

    Calculates levels for the "moonbag" strategy — fixed TP at 50% from the current price.

    Type declaration

      • (
            dto: {
                currentPrice: number;
                percentStopLoss: number;
                position: "long" | "short";
            },
        ): {
            position: "long"
            | "short";
            priceStopLoss: number;
            priceTakeProfit: number;
        }
      • Parameters

        • dto: { currentPrice: number; percentStopLoss: number; position: "long" | "short" }
          • currentPrice: number

            current asset price

          • percentStopLoss: number

            stop loss percentage from 0 to 100

          • position: "long" | "short"

            position type: "long" or "short"

        Returns { position: "long" | "short"; priceStopLoss: number; priceTakeProfit: number }

        priceTakeProfit and priceStopLoss in fiat

        -
    +

    🕹️ How to Debug Your Bot's Exchange Connection in an Hour, Not Three Days

    +

    The source code discussed in this article is published in this repository

    +
    +

    cover_manual_control_adapter_debug

    +

    A surgeon isn't allowed into the operating room until they've practiced a suture a hundred times on a trainer. A pilot sits in a full-scale cockpit simulator — same switches, same inertia, same engine failure on takeoff — long before their first live flight. No one would think to teach a pilot to fly by sending them on an actual flight and waiting for something to break.

    +

    But in algotrading, that's exactly what we do.

    +

    The backtest is green. Paper trading is green. The strategy is mathematically sound, look-ahead bias is scrubbed out, the metrics are honest. You write an exchange adapter — the very layer that turns a signal { position: 'long', priceOpen: 66817 } into a real order on the exchange. And you launch the bot in live.

    +

    And then begins what nobody writes about in competitors' READMEs.

    +

    To verify that the adapter even works — that the order goes through, leverage gets set, positionSide in hedge mode isn't mixed up, quantity rounding passes the exchange's filters, TP/SL land on the correct side — you need to wait for a trading signal.

    +

    And the signal may not come. A day. Two. Three days.

    +

    By its very nature, a strategy stays silent most of the time: it waits for conditions, waits for a breakout, waits for news. You sit and stare at a log where nothing is happening. The bot is alive, the bot is healthy, the bot is waiting. And then the moment comes. At 03:47 in the morning the conditions align, the bot forms a signal, pulls the adapter and... catches a bug.

    +
    ExchangeAPIException: -4061 Order's position side does not match user's setting.
    +
    + +

    Congratulations. You spent three days of waiting to learn that in hedge mode you need to send positionSide as LONG, not BOTH. You fix one line. And you wait another three days until the next signal to check that this time the quantity rounding under stepSize won't fall apart.

    +

    The integration debugging cycle is three days per iteration. And the fix itself is a single line.

    +

    The obvious counterargument: "read the adapter code by eye, find the bug before launch."

    +

    Doesn't work. Exchange integration isn't about logic, it's about a hundred micro-mismatches with reality that are impossible to see in code:

    +
      +
    • stepSize and tickSize differ for every pair, and the exchange will reject an order with one extra decimal place;
    • +
    • minimum notional (minNotional) — an order for $4 goes through, but $3.90 doesn't;
    • +
    • in hedge mode you need positionSide, in one-way mode you can't send it at all;
    • +
    • reduceOnly on close, otherwise you'll open a counter-position instead of exiting;
    • +
    • stop_loss_limit on spot vs STOP_MARKET on futures — different order types, different fields;
    • +
    • ghost position: the exchange shows a remainder of 0.0000001 coins, and closePosition goes into an infinite loop.
    • +
    +

    Each of these points is a separate trip to the exchange's documentation, which is verified only by a live call. You won't catch it by eye, because the bug isn't in your logic — the bug is in how your logic meets the specific settings of a specific account on a specific exchange.

    +

    The standard debugging path looks like this:

    +
      +
    1. Write the adapter from the exchange docs
    2. +
    3. Launch live
    4. +
    5. Wait for a signal (hours — days)
    6. +
    7. Signal arrives -> catch -4061 / -1111 / -2010
    8. +
    9. Fix one line
    10. +
    11. GOTO 2
    12. +
    +

    This isn't debugging. It's roulette with a spin interval of a day.

    +

    backtest-kit has a web dashboard (@backtest-kit/ui), and in it — a Manual Control section. This isn't "view the position state." These are physical buttons that pull the very same broker-adapter hooks as the real strategy:

    +

    manual_control_open_position

    +
      +
    • OPEN POSITION — open a position by hand, right now;
    • +
    • COMMIT AVERAGING — average in (the same onAverageBuyCommit);
    • +
    • COMMIT BREAKEVEN — move the stop to breakeven;
    • +
    • CLOSE POSITION — close.
    • +
    +

    manual_control_position_state

    +

    You're not verifying a line of code — you're verifying how the system works as a whole: adapter -> engine -> persistence -> opening a position -> protective orders. It's the difference between "read the function's code" and "watched the function run inside a living organism."

    +

    manual_control_dashboard

    +

    A button that pulls a real hook on a real account is a full-fledged trading instrument. And here's where it suddenly solves problems for which writing a dedicated strategy is impossible, since the conditions can't be reproduced in a backtest.

    +

    manual_control_pnl_overview

    +

    1. A manual hedge against insider info the strategy doesn't see.

    +

    Your strategy trades LONG on minute candles — it catches microstructure, local impulses, but by construction it's blind to the macro picture. And then you learn something before the market does: in an hour there's a rate decision / a delisting court ruling / a major exchange hack — something after which the market will collapse in panic. Rewriting the minute strategy for this is pointless: it's about something else. But you have an open LONG position, and it'll catch the whole crash.

    +

    You manually open a global SHORT on top — with the same OPEN POSITION, with minuteEstimatedTime: Infinity, like an umbrella over the entire portfolio. The minute strategy keeps doing its job as if nothing happened, while the manual short neutralizes the systemic risk exactly for the window until the news plays out. The dashboard meanwhile honestly shows both positions and the total PNL — you see net exposure rather than guessing. After the news, you close the short with a button and return to normal mode.

    +

    2. A way out when the strategy has lost its edge, but the bot is obligated to act.

    +

    The reality of a production deployment at a hedge fund or on a managed account: the bot has to show activity for reporting. And the strategy may go weeks without seeing an effective entry point — the market is ranging, conditions don't align, the edge has temporarily evaporated. Formally everything is correct: better not to trade than to trade garbage. But to an investor/compliance, "the bot did nothing for two weeks" looks like "the bot broke."

    +

    Manual control bridges this gap. You can manually open/close a controlled position for the reporting period, record a meaningful action in the JSONL logs (with a note explaining the reason), and not cripple the automated logic in the process. The strategy stays clean, and the reporting stays alive. This isn't a crutch in the code you'll have to clean up later — it's an operator's decision on top of an unchanged engine.

    +

    3. Grab a local pump by hand, one the strategy isn't built for.

    +

    A strategy is always a specialization. If it's tuned to catch reversions to the mean, by construction it doesn't enter a vertical pump — to it that's "too far from the entry point, the risk/reward doesn't add up." And it's right 95% of the time. But right now, specifically, you can see with your own eyes a coin flying on volume, and you understand the move is real.

    +

    Writing a dedicated pump detector for this (Hawkes, CUSUM, volume z-scores — I have a separate library for that) is overkill for a one-off case. It's easier to hit OPEN POSITION, enter by hand, and then hand the position over to the engine: the same commitBreakeven will drag the stop to breakeven, commitAveraging will average in on a pullback, the trailing will take the profit. You gave the system an entry point the strategy missed — but all position management after entry remained automated and battle-tested.

    +

    In all three cases the same property is at work: the manual action goes through the same engine as the automated one. A position opened by hand isn't an "external trade outside the system" — it's a full-fledged signal in persistent storage, with the same lifecycle, the same rendering, the same protective orders, and the same DCA/breakeven/trailing hooks. The operator and the algorithm work in a single circuit, not in two parallel universes that won't reconcile in the report later.

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Standard pathbacktest-kit
    How to launch an adapter checkWait for a trading signalPress a button
    Time to first errorHours — daysSeconds
    What gets verifiedA single callThe whole chain: adapter, engine, persistence, UI, protective orders
    FidelityThe real path, but you waitThe real path, right now
    +
    + + + + + + + + + diff --git a/documents/data_test-guidelines.html b/documents/data_test-guidelines.html new file mode 100644 index 0000000000000000000000000000000000000000..255bf5c933994ef744ad05868527d810464d9487 --- /dev/null +++ b/documents/data_test-guidelines.html @@ -0,0 +1,76 @@ +data/test-guidelines | backtest-kit

    Test Guidelines

      +
    • src/helpers/getEffectivePriceOpen.ts — cost-basis replay algorithm (DO NOT MODIFY)
    • +
    • src/helpers/toProfitLossDto.ts — weighted PNL with partial close replay (DO NOT MODIFY)
    • +
    • test/spec/dca.test.mjs — 35 unit tests for DCA+partial logic
    • +
    • test/e2e/dca.test.mjs — 9 e2e tests: partial profit/loss interleaved with DCA
    • +
    • test/migration/migrate7.test.mjs — 2 migration tests: trailing stop breakeven, partialLoss
    • +
    • test/e2e/average.test.mjs — reference pattern for e2e backtest tests
    • +
    • test/README.md — comprehensive test writing guide (read before writing e2e tests)
    • +
    +

    Running costBasis through all partials sequentially:

    +
    costBasis = 0
    for each partial[i]:
    newEntries = entryCountAtClose[i] - entryCountAtClose[i-1] (0 for i=0)
    costBasis += newEntries * 100
    dollarValue = (percent[i] / 100) * costBasiscorrect running basis
    costBasis *= (1 - percent[i] / 100) ← reduce after each close
    weight[i] = dollarValue[i] / totalInvested +
    + +
      +
    • snap[0] = hm(entries[0..cnt[0]]) when no prior partials
    • +
    • snap[i≥1] = must use getEff(entries[0..cnt[i]], partials[0..i-1]) — NOT plain harmonic mean +
        +
      • Formula: (remainingCostBasis + newDCA*100) / (remainingCostBasis/snap[i-1] + Σ100/newPrice)
      • +
      +
    • +
    +
    addExchangeSchema({ exchangeName: "binance-X", getCandles, formatPrice, formatQuantity })
    addStrategySchema({ strategyName: "test-X", interval: "1m", getSignal, callbacks: { onActivePing, onClose, ... } })
    addFrameSchema({ frameName: "Nm-X", interval: "1m", startDate, endDate })
    const awaitSubject = new Subject();
    listenDoneBacktest(() => awaitSubject.next());
    const unsubscribeError = listenError((error) => { errorCaught = error; awaitSubject.next(); });
    Backtest.background("BTCUSDT", { strategyName, exchangeName, frameName });
    await awaitSubject.toPromise();
    unsubscribeError(); +
    + +
      +
    • Buffer candles ABOVE priceOpen for LONG (below for SHORT) before startTime — prevent early scheduled activation
    • +
    • All candles rebuilt inside first getSignal call (signalGenerated flag); getCandles returns from allCandles array
    • +
    • LONG activates when candle.low <= priceOpen; SHORT when candle.high >= priceOpen
    • +
    • SL checked BEFORE activation — activation candle low must not hit SL simultaneously
    • +
    • getAveragePrice(symbol) needs min 5 candles
    • +
    • Frame endDate must match candle count exactly (N candles = N minutes with 1m interval)
    • +
    • CC_MAX_STOPLOSS_DISTANCE_PERCENT: 20 — SL can be at most 20% from entry; violations silently break tests
    • +
    • CC_AVG_PRICE_CANDLES_COUNT: 5 — VWAP window; first 4 candles skipped as buffer in pending processing
    • +
    • minuteEstimatedTime must fit within frame; if candles run out before time expires → error thrown
    • +
    • onPartialProfit / onPartialLoss fire based on VWAP (averagePrice), not candle.close
    • +
    • revenuePercent in onPartialProfit = % progress toward TP (0–100), NOT P&L %
    • +
    • revenuePercent in onPartialLoss = % progress toward SL (0–100)
    • +
    +
      +
    • commitPartialProfit(symbol, percentToClose) — close X% at profit; requires currentPrice > effectivePriceOpen for LONG
    • +
    • commitPartialLoss(symbol, percentToClose) — close X% at loss; requires currentPrice < effectivePriceOpen for LONG
    • +
    • commitAverageBuy(symbol) — DCA entry (rejected if price unfavorable direction)
    • +
    • commitTrailingStop(symbol, percentShift, currentPrice) — shift SL by percent from original distance
    • +
    • All called from callbacks (onActivePing, onPartialProfit, onPartialLoss) with await
    • +
    • Backtest.getPendingSignal(symbol, context) — returns current signal state including priceOpen, priceStopLoss
    • +
    +
      +
    • No _entry → returns signal.priceOpen immediately (line 23)
    • +
    • No change in math for plain entries; refactor only affects DCA+partial cases
    • +
    +

    test/index.mjs — import list controls which test files run

    +
    + + + + + + + + + diff --git a/documents/docs.html b/documents/docs.html index 31adf36ef9c00dc58f193d04d4e0afa1c376a65f..8d6cb859087d197fb2adb4da3fc67eba74cc034e 100644 --- a/documents/docs.html +++ b/documents/docs.html @@ -232,6 +232,8 @@
  • hasNoScheduledSignal
  • commitSignalNotify
  • commitCreateSignal
  • +
  • commitCreateTakeProfit
  • +
  • commitCreateStopLoss
  • getStrategyStatus
  • stopStrategy
  • shutdown
  • @@ -293,6 +295,10 @@
  • listenRiskOnce
  • listenSchedulePing
  • listenSchedulePingOnce
  • +
  • listenScheduleEvent
  • +
  • listenScheduleEventOnce
  • +
  • listenSignalEvent
  • +
  • listenSignalEventOnce
  • listenActivePing
  • listenActivePingOnce
  • listenIdlePing
  • @@ -372,6 +378,8 @@
  • PartialProfitContract
  • PartialLossContract
  • SchedulePingContract
  • +
  • ScheduleEventContract
  • +
  • SignalEventContract
  • ActivePingContract
  • IdlePingContract
  • RiskContract
  • @@ -711,6 +719,13 @@
  • BrokerSignalOpenPayload
  • BrokerSignalClosePayload
  • BrokerSignalPendingPayload
  • +
  • BrokerActivePingPayload
  • +
  • BrokerSchedulePingPayload
  • +
  • BrokerIdlePingPayload
  • +
  • BrokerScheduleOpenPayload
  • +
  • BrokerScheduleCancelledPayload
  • +
  • BrokerPendingOpenPayload
  • +
  • BrokerPendingClosePayload
  • BrokerPartialProfitPayload
  • BrokerPartialLossPayload
  • BrokerTrailingStopPayload
  • diff --git a/documents/docs_class_ActionConnectionService.html b/documents/docs_class_ActionConnectionService.html index 5c538f94bdc6d4fe2d651f568bbde551aae583d8..7721737825e68a083c29ffadef2e5c083e141a13 100644 --- a/documents/docs_class_ActionConnectionService.html +++ b/documents/docs_class_ActionConnectionService.html @@ -60,6 +60,14 @@ Cache key includes strategyName, exchangeName and frameName to isolate action pe

    Routes scheduled ping event to appropriate ClientAction instance.

    +
    scheduleEvent: (event: ScheduleEventContract, backtest: boolean, context: { actionName: string; strategyName: string; exchangeName: string; frameName: string; }) => Promise<void>
    +
    + +

    Routes a scheduled signal lifecycle event (creation / cancellation) to the ClientAction instance.

    +
    pendingEvent: (event: SignalEventContract, backtest: boolean, context: { actionName: string; strategyName: string; exchangeName: string; frameName: string; }) => Promise<void>
    +
    + +

    Routes a pending signal lifecycle event (open / close) to the ClientAction instance.

    pingActive: (event: ActivePingContract, backtest: boolean, context: { actionName: string; strategyName: string; exchangeName: string; frameName: string; }) => Promise<void>
     
    @@ -77,10 +85,10 @@ Cache key includes strategyName, exchangeName and frameName to isolate action pe

    Routes signalSync event to appropriate ClientAction instance. NOT wrapped in trycatch — exceptions propagate to CREATE_SYNC_FN.

    -
    orderPing: (event: SignalPingContract, backtest: boolean, context: { actionName: string; strategyName: string; exchangeName: string; frameName: string; }) => Promise<void>
    +
    orderCheck: (event: SignalPingContract, backtest: boolean, context: { actionName: string; strategyName: string; exchangeName: string; frameName: string; }) => Promise<void>
     
    -

    Routes orderPing event to appropriate ClientAction instance. +

    Routes orderCheck event to appropriate ClientAction instance. NOT wrapped in trycatch — exceptions propagate to CREATE_SYNC_PENDING_FN.

    dispose: (backtest: boolean, context: { actionName: string; strategyName: string; exchangeName: string; frameName: string; }) => Promise<void>
     
    @@ -90,7 +98,7 @@ NOT wrapped in trycatch — exceptions propagate to CREATE_SYNC_PENDING_FN.

    Clears the cached ClientAction instance for the given action name.

    -
    +

    Positional-Argument Swap Audit — ./src

    Date: 2026-06-16 +Scope: entire ./src (~250 .ts files), all primitive types (number/number, string/string, boolean). +Goal: find swapped positional arguments of the same primitive type — bugs TypeScript's structural typing cannot catch (f(timestamp, price)f(price, timestamp) when both are number). +Method: signature → call-sites → compare each actual argument's variable name against the parameter name at that position. (Same method that found the one real bug in this session.)

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    ResultCount
    Risky functions/signatures inventoried~40
    Call-sites verified120+
    ❌ Bugs found (this audit)0
    ❌ Bug found & already fixed (commit c7958a73)1
    ⚠️ Suspects needing human review0 (see notes)
    +

    Verdict: no swapped-argument bugs remain in ./src. The single real bug of this class — PROCESS_COMMIT_QUEUE_FN(currentTime, currentPrice) instead of (currentPrice, currentTime) in ClientStrategy.tick() — was already fixed by commit c7958a73 before this audit.

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    DirectoryStatusWhat was checked
    src/math/✅ cleanAll number-only fns (investedCostToPercent, percentToCloseCost, slPriceToPercentShift, tpPriceToPercentShift, slPercentShiftToPrice, tpPercentShiftToPrice, breakevenNew*Price, percentValue, percentDiff) — 30+ call-sites across function/strategy.ts, classes/Backtest.ts, classes/Live.ts.
    src/interfaces/✅ cleanSystem callback signatures vs their ClientStrategy call-sites: onHighestProfit/onMaxDrawdown (signal, currentPrice, timestamp), onSchedulePing/onActivePing/onIdlePing (system), onInit/onDispose (string-quad).
    src/client/✅ cleanClientStrategy.ts fully audited during this session (all CALL_*_FN, PARTIAL_*_FN, sync, ping, breakeven groups). ClientPartial/Breakeven/Risk/Exchange/Frame/Sizing/Action — agent-checked clean.
    src/lib/services/markdown/✅ cleangetStorage memoize + new ReportStorage(...) string-quads in all 12 services + every this.getStorage(...) call-site — order symbol, strategyName, exchangeName, frameName[, backtest] correct everywhere.
    src/lib/services/core + connection✅ cleanbreakeven/trailingStop/trailingTake/partialProfit/partialLoss/averageBuy end-to-end (Core→Connection→ClientStrategy), getStrategy(...) string-quad, getTimestamp/getCurrentPrice(symbol, context, backtest).
    src/function/strategy.ts✅ cleancommit* forwarding to strategyCoreService.* — partial/averageBuy/breakeven/trailing all in correct order.
    src/classes/✅ cleanBacktest/Live commit* facades (breakeven/trailing with new timestamp), Persist adapter triples.
    src/helpers, validation, contract, model, utils, config✅ no risk patternsSpot-checked; no 2+ adjacent same-type positional bugs in hot paths.
    +

    src/client/ClientStrategy.ts tick()PROCESS_COMMIT_QUEUE_FN(self, currentPrice, timestamp):

    +
      +
    • Was: PROCESS_COMMIT_QUEUE_FN(this, currentTime, currentPrice)currentTime passed as currentPrice, currentPrice as timestamp.
    • +
    • Now (commit c7958a73): PROCESS_COMMIT_QUEUE_FN(this, currentPrice, currentTime).
    • +
    • Why it was invisible: both args are number; structural typing accepts either order.
    • +
    +

    These compile-safely accept swapped args — guard future edits here. All are currently correct.

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    FunctionFileAdjacent same-type params
    onHighestProfit / onMaxDrawdowninterfaces/Strategy.interface.tscurrentPrice, timestamp
    PROCESS_COMMIT_QUEUE_FNclient/ClientStrategy.tscurrentPrice, timestamp ← was the bug
    PARTIAL_PROFIT_FN / PARTIAL_LOSS_FNclient/ClientStrategy.tspercentToClose, currentPrice, timestamp (3 in a row)
    AVERAGE_BUY_FNclient/ClientStrategy.tscurrentPrice, timestamp, cost (3 in a row)
    slPriceToPercentShift / tpPriceToPercentShiftmath/newPrice, originalPrice, effectivePriceOpen (3 in a row)
    investedCostToPercent / percentToCloseCostmath/dollarAmount/percentToClose, investedCost — swap = 40–400× error
    readCandlesDataclasses/Persist.ts (iface)limit, sinceTimestamp, untilTimestamp
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    FunctionFileAdjacent strings
    getStorage / new ReportStorageall lib/services/markdown/*.tssymbol, strategyName, exchangeName, frameName
    getStrategylib/services/connection/StrategyConnectionService.tssymbol, strategyName, exchangeName, frameName
    Persist*Instance constructorsclasses/Persist.tssymbol, strategyName, exchangeName
    onInit / onDisposeinterfaces/Strategy.interface.tssymbol, strategyName, exchangeName, frameName
    +

    Where a string discriminant (e.g. closeReason) or a boolean (backtest) sits between two numbers, TypeScript does reject a swap. Examples: CLOSE_*_IN_BACKTEST_FN(..., averagePrice, closeReason, closeTimestamp), the ping callbacks (..., currentPrice, backtest, timestamp). These were verified but are self-defending.

    +

    An exploratory pass flagged 10 markdown getStorage factories as "cache-collision bugs" because the memoize key includes backtest while the ReportStorage constructor receives only 4 args (no backtest). This was reviewed and is not a bug and not in scope: ReportStorage legitimately doesn't need backtest (it isn't stored; each event carries its own backtest), and including backtest in the memo key correctly separates live vs backtest instances (the opposite of a collision). The string order symbol, strategyName, exchangeName, frameName — the only thing relevant to this audit — is correct in all 12 services.

    +

    The codebase has strict: false, no ESLint, no branded types — so this class of bug is undetectable at compile time. To prevent recurrence:

    +
      +
    1. Branded primitives: type Timestamp = number & { readonly __t: 'ms' }, type Price = number & { readonly __t: 'price' }, type Percent = ... — would make onHighestProfit/PROCESS_COMMIT_QUEUE_FN/investedCostToPercent swaps a compile error.
    2. +
    3. Replace positional (symbol, strategyName, exchangeName, frameName) quads with the existing context object pattern (already used in Core/Connection) at the markdown/persist layers.
    4. +
    +
    + + + + + + + + + diff --git a/documents/docs_function_commitCreateStopLoss.html b/documents/docs_function_commitCreateStopLoss.html new file mode 100644 index 0000000000000000000000000000000000000000..abe92552acef34a0515c542081b4f0315964efc0 --- /dev/null +++ b/documents/docs_function_commitCreateStopLoss.html @@ -0,0 +1,52 @@ +docs/function/commitCreateStopLoss | backtest-kit

    commitCreateStopLoss

    declare function commitCreateStopLoss(symbol: string, payload?: Partial<CommitPayload>): Promise<void>;
    +
    + +

    Reports that the pending position's stop-loss order was actually filled on the exchange +(e.g. by candle high/low), forcing a close that bypasses the VWAP-based SL check.

    +

    The exchange and the strategy are parallel states: the framework evaluates TP/SL against VWAP, +but the real order may fill on high/low. The close is deferred and emitted with closeReason +"stop_loss" on the next tick. No-op if no pending signal exists.

    +

    Automatically detects backtest/live mode from execution context.

    + + + + + + + + + + + + + + + + + +
    ParameterDescription
    symbolTrading pair symbol
    payloadOptional commit payload with id and note
    +
    + + + + + + + + + diff --git a/documents/docs_function_commitCreateTakeProfit.html b/documents/docs_function_commitCreateTakeProfit.html new file mode 100644 index 0000000000000000000000000000000000000000..2360025ba56be96a4df65fa4e5d8bc3b36a961b6 --- /dev/null +++ b/documents/docs_function_commitCreateTakeProfit.html @@ -0,0 +1,52 @@ +docs/function/commitCreateTakeProfit | backtest-kit

    commitCreateTakeProfit

    declare function commitCreateTakeProfit(symbol: string, payload?: Partial<CommitPayload>): Promise<void>;
    +
    + +

    Reports that the pending position's take-profit order was actually filled on the exchange +(e.g. by candle high/low), forcing a close that bypasses the VWAP-based TP check.

    +

    The exchange and the strategy are parallel states: the framework evaluates TP/SL against VWAP, +but the real order may fill on high/low. The close is deferred and emitted with closeReason +"take_profit" on the next tick. No-op if no pending signal exists.

    +

    Automatically detects backtest/live mode from execution context.

    + + + + + + + + + + + + + + + + + +
    ParameterDescription
    symbolTrading pair symbol
    payloadOptional commit payload with id and note
    +
    + + + + + + + + + diff --git a/documents/docs_function_listenScheduleEvent.html b/documents/docs_function_listenScheduleEvent.html new file mode 100644 index 0000000000000000000000000000000000000000..d00afc7851a6ffdacea581ca656b281b496da19c --- /dev/null +++ b/documents/docs_function_listenScheduleEvent.html @@ -0,0 +1,48 @@ +docs/function/listenScheduleEvent | backtest-kit

    listenScheduleEvent

    declare function listenScheduleEvent(fn: (event: ScheduleEventContract) => void): () => void;
    +
    + +

    Subscribes to scheduled signal lifecycle events (creation and cancellation) with queued async processing.

    +

    Emitted when a scheduled signal is created (action "scheduled") or cancelled before activation +(action "cancelled" with reason "timeout" / "price_reject" / "user"), in both live and backtest.

    +

    IMPORTANT: The scheduled -> active transition (activation) is NOT reported here. Activation +produces an "opened" event on the regular signal emitters (listenSignal) instead.

    +

    Events are processed sequentially in order received, even if callback is async.

    + + + + + + + + + + + + + +
    ParameterDescription
    fnCallback function to handle scheduled lifecycle events
    +
    + + + + + + + + + diff --git a/documents/docs_function_listenScheduleEventOnce.html b/documents/docs_function_listenScheduleEventOnce.html new file mode 100644 index 0000000000000000000000000000000000000000..23a5c1e6197b512ec9563a4118d0a259597cc18b --- /dev/null +++ b/documents/docs_function_listenScheduleEventOnce.html @@ -0,0 +1,50 @@ +docs/function/listenScheduleEventOnce | backtest-kit

    listenScheduleEventOnce

    declare function listenScheduleEventOnce(filterFn: (event: ScheduleEventContract) => boolean, fn: (event: ScheduleEventContract) => void): () => void;
    +
    + +

    Subscribes to filtered scheduled lifecycle events with one-time execution.

    +

    Listens for events matching the filter predicate, then executes callback once +and automatically unsubscribes. Useful for waiting for a specific scheduled creation +or cancellation.

    + + + + + + + + + + + + + + + + + +
    ParameterDescription
    filterFnPredicate to filter which events trigger the callback
    fnCallback function to handle the filtered event (called only once)
    +
    + + + + + + + + + diff --git a/documents/docs_function_listenSignalEvent.html b/documents/docs_function_listenSignalEvent.html new file mode 100644 index 0000000000000000000000000000000000000000..9f3c48632630067f09136f75e0873707eb803cbb --- /dev/null +++ b/documents/docs_function_listenSignalEvent.html @@ -0,0 +1,47 @@ +docs/function/listenSignalEvent | backtest-kit

    listenSignalEvent

    declare function listenSignalEvent(fn: (event: SignalEventContract) => void): () => void;
    +
    + +

    Subscribes to pending signal lifecycle events (open and close) with queued async processing.

    +

    Emitted when a pending position is opened (action "opened": new signal / immediate / scheduled +or user activation) or closed (action "closed" with closeReason "take_profit" / "stop_loss" / +"time_expired" / "closed"), in both live and backtest.

    +

    Events are processed sequentially in order received, even if callback is async.

    + + + + + + + + + + + + + +
    ParameterDescription
    fnCallback function to handle pending lifecycle events
    +
    + + + + + + + + + diff --git a/documents/docs_function_listenSignalEventOnce.html b/documents/docs_function_listenSignalEventOnce.html new file mode 100644 index 0000000000000000000000000000000000000000..bfa7d954d6106305f3eedb9c671fbd2090aeb9e8 --- /dev/null +++ b/documents/docs_function_listenSignalEventOnce.html @@ -0,0 +1,49 @@ +docs/function/listenSignalEventOnce | backtest-kit

    listenSignalEventOnce

    declare function listenSignalEventOnce(filterFn: (event: SignalEventContract) => boolean, fn: (event: SignalEventContract) => void): () => void;
    +
    + +

    Subscribes to filtered pending lifecycle events with one-time execution.

    +

    Listens for events matching the filter predicate, then executes callback once +and automatically unsubscribes. Useful for waiting for a specific open or close.

    + + + + + + + + + + + + + + + + + +
    ParameterDescription
    filterFnPredicate to filter which events trigger the callback
    fnCallback function to handle the filtered event (called only once)
    +
    + + + + + + + + + diff --git a/documents/docs_interface_IAction.html b/documents/docs_interface_IAction.html index e4bef4151d03116cdc9a6533082788b76229c3d4..ee4da590a7a26625a556ed1708b440bea074c7cf 100644 --- a/documents/docs_interface_IAction.html +++ b/documents/docs_interface_IAction.html @@ -57,6 +57,27 @@ Frequency: Once per loss level per signal (deduplicated)

    Emitted by: StrategyConnectionService via schedulePingSubject Source: CREATE_COMMIT_SCHEDULE_PING_FN callback in StrategyConnectionService Frequency: Every minute while scheduled signal is waiting for activation

    +
    scheduleEvent: (event: ScheduleEventContract) => void | Promise<void>
    +
    + +

    Handles scheduled signal lifecycle events (creation / cancellation).

    +

    Emitted by: StrategyConnectionService via scheduleEventSubject +Source: CREATE_COMMIT_SCHEDULE_EVENT_FN callback in StrategyConnectionService +Frequency: Once when a scheduled signal is created ("scheduled") and once when it is +cancelled before activation ("cancelled": timeout / price_reject / user). The +scheduled -> active transition is NOT reported here.

    +

    Manual wiring — EVENT-BASED: implement the user-facing callback IActionCallbacks.onScheduleEvent (via +addActionSchema) to drive the exchange (commitActivateScheduled / commitCancelScheduled).

    +
    pendingEvent: (event: SignalEventContract) => void | Promise<void>
    +
    + +

    Handles pending signal lifecycle events (open / close).

    +

    Emitted by: StrategyConnectionService via signalEventSubject +Source: CREATE_COMMIT_SIGNAL_EVENT_FN callback in StrategyConnectionService +Frequency: Once when a pending position is opened (action "opened") and once when it is +closed (action "closed" with closeReason take_profit / stop_loss / time_expired / closed).

    +

    Manual wiring — EVENT-BASED: implement the user-facing callback IActionCallbacks.onPendingEvent (via +addActionSchema) to drive the exchange; for per-tick fills use onPingActive.

    pingActive: (event: ActivePingContract) => void | Promise<void>
     
    @@ -84,7 +105,12 @@ Frequency: Only when signal is rejected (not emitted for allowed signals)

    Called when framework attempts to open or close a position via limit order. Throw to reject — framework will retry on next tick.

    NOTE: Exceptions are NOT swallowed here — they propagate to CREATE_SYNC_FN.

    -
    orderPing: (event: SignalPingContract) => void | Promise<void>
    +

    MANUAL WIRING — EXCEPTION-BASED GATE: action-side equivalent of the Broker +onSignalOpenCommit / onSignalCloseCommit. Throw on "signal-open" → open rolls back to idle +(scheduled activation cancelled); throw on "signal-close" → close skipped, position stays open; +retried next tick. Same syncSubject emission as the Broker commit hooks (collapsed to false by +CREATE_SYNC_FN). Live-only. Implement via the IActionCallbacks.onSignalSync callback.

    +
    orderCheck: (event: SignalPingContract) => void | Promise<void>
     

    Called on every live tick while a pending signal is monitored, BEFORE TP/SL/time evaluation, @@ -96,13 +122,18 @@ closeReason "closed".

    normally instead of throwing, otherwise a connectivity blip would wrongly close an open position. Throw exclusively on a confirmed "order not found by id" result.

    NOTE: Exceptions are NOT swallowed here — they propagate to CREATE_SYNC_PENDING_FN.

    +

    MANUAL WIRING — EXCEPTION-BASED GATE: action-side equivalent of the Broker onOrderCheck. A +throw on a confirmed "order not found by id" closes the position with closeReason "closed" +(retried via CREATE_SYNC_PENDING_FN). Throw-driven alternative to the imperative +commitClosePending (call it from pingActive) — pick one, not both. Live-only. Implement via +the IActionCallbacks.onOrderCheck callback.

    dispose: () => void | Promise<void>
     

    Cleans up resources and subscriptions when action handler is no longer needed.

    Called by: Connection services during shutdown Use for: Unsubscribing from observables, closing connections, flushing buffers

    -
    +

    ScheduleEventContract

    Contract for scheduled signal lifecycle events (creation and cancellation).

    +

    Emitted by scheduleEventSubject when a scheduled signal is created (added) or cancelled +during tick()/backtest() processing. Lets consumers track the scheduled phase of a signal +without subscribing to the full signal stream.

    +

    IMPORTANT: The scheduled -> active transition (activation) is intentionally NOT emitted here. +Activation produces an "opened" signal on the regular signal emitters; this contract only +covers a scheduled signal being put in place and being removed before it ever opened.

    +

    Consumers:

    +
      +
    • User callbacks via listenScheduleEvent() / listenScheduleEventOnce()
    • +
    +
    action: "scheduled" | "cancelled"
    +
    + +

    Lifecycle action for the scheduled signal.

    +
      +
    • "scheduled": a new scheduled signal was created (waiting for priceOpen activation)
    • +
    • "cancelled": the scheduled signal was removed before activation (timeout / price reject / user)
    • +
    +
    symbol: string
    +
    + +

    Trading pair symbol (e.g., "BTCUSDT"). +Identifies which market this event belongs to.

    +
    strategyName: string
    +
    + +

    Strategy name that owns this scheduled signal.

    +
    exchangeName: string
    +
    + +

    Exchange name where this scheduled signal lives.

    +
    frameName: string
    +
    + +

    Frame name (timeframe / date range) for the run. Empty string in live mode. +Same value as the signal's frameName (data.frameName).

    +
    data: IPublicSignalRow
    +
    + +

    Complete scheduled signal row data in public form. +Contains all signal information: id, position, priceOpen, priceTakeProfit, priceStopLoss, etc.

    +
    reason: StrategyCancelReason
    +
    + +

    Cancellation reason. Present only when action === "cancelled":

    +
      +
    • "timeout": CC_SCHEDULE_AWAIT_MINUTES elapsed without reaching priceOpen
    • +
    • "price_reject": price hit stop-loss before activation
    • +
    • "user": cancelled via cancelScheduled()
    • +
    +

    Always undefined when action === "scheduled".

    +
    currentPrice: number
    +
    + +

    Current market price of the symbol at the time of the event.

    +
    backtest: boolean
    +
    + +

    Execution mode flag.

    +
      +
    • true: Event from backtest execution (historical candle data)
    • +
    • false: Event from live trading (real-time tick)
    • +
    +
    timestamp: number
    +
    + +

    Event timestamp in milliseconds since Unix epoch.

    +

    Timing semantics:

    +
      +
    • Live mode: when.getTime() at the moment of the event
    • +
    • Backtest mode: candle.timestamp of the candle being processed
    • +
    +
    + + + + + + + + + diff --git a/documents/docs_interface_ScheduledEvent.html b/documents/docs_interface_ScheduledEvent.html index 92b33a9134e84f44c0098cd4b9d42848a42b27dc..92386c2a2c1601b108fb62c0807a1e3bc3505839 100644 --- a/documents/docs_interface_ScheduledEvent.html +++ b/documents/docs_interface_ScheduledEvent.html @@ -4,7 +4,7 @@ Contains all information about scheduled, opened and cancelled events.

    Event timestamp in milliseconds (scheduledAt for scheduled/cancelled events)

    -
    action: "opened" | "scheduled" | "cancelled"
    +
    action: "scheduled" | "cancelled" | "opened"
     

    Event action type

    diff --git a/documents/docs_interface_SignalEventContract.html b/documents/docs_interface_SignalEventContract.html new file mode 100644 index 0000000000000000000000000000000000000000..2ccc1390558e11ba39e506f398d15324c353fb92 --- /dev/null +++ b/documents/docs_interface_SignalEventContract.html @@ -0,0 +1,101 @@ +docs/interface/SignalEventContract | backtest-kit

    SignalEventContract

    Contract for pending signal lifecycle events (open and close).

    +

    Emitted by signalEventSubject when a pending position is opened (action "opened") or closed +(action "closed") during tick()/backtest() processing. Lets consumers track the active phase +of a signal without subscribing to the full signal stream.

    +

    Covers every way a position opens (new signal, immediate entry, scheduled activation, user +activation) and every way it closes (take_profit / stop_loss / time_expired / user-close / +broker fill / order no longer pending).

    +

    Consumers:

    +
      +
    • User callbacks via listenSignalEvent() / listenSignalEventOnce()
    • +
    +
    action: "opened" | "closed"
    +
    + +

    Lifecycle action for the pending signal.

    +
      +
    • "opened": a pending position was opened (new signal / immediate / scheduled or user activation)
    • +
    • "closed": the pending position was closed (TP / SL / time_expired / user / broker fill / ping)
    • +
    +
    symbol: string
    +
    + +

    Trading pair symbol (e.g., "BTCUSDT"). +Identifies which market this event belongs to.

    +
    strategyName: string
    +
    + +

    Strategy name that owns this pending signal.

    +
    exchangeName: string
    +
    + +

    Exchange name where this pending signal lives.

    +
    frameName: string
    +
    + +

    Frame name (timeframe / date range) for the run. Empty string in live mode. +Same value as the signal's frameName (data.frameName).

    +
    data: IPublicSignalRow
    +
    + +

    Complete pending signal row data in public form. +Contains all signal information: id, position, priceOpen, priceTakeProfit, priceStopLoss, +effective entry / trailing SL/TP, PnL, etc.

    +
    closeReason: StrategyCloseReason
    +
    + +

    Close reason. Present only when action === "closed":

    +
      +
    • "take_profit": effective take-profit level reached
    • +
    • "stop_loss": effective stop-loss level reached
    • +
    • "time_expired": position exceeded minuteEstimatedTime
    • +
    • "closed": closed by user (closePending) or because the order is no longer open on the exchange
    • +
    +

    Always undefined when action === "opened".

    +
    currentPrice: number
    +
    + +

    Current market price of the symbol at the time of the event. +For "opened" this is the effective entry (priceOpen); for "closed" the close price.

    +
    backtest: boolean
    +
    + +

    Execution mode flag.

    +
      +
    • true: Event from backtest execution (historical candle data)
    • +
    • false: Event from live trading (real-time tick)
    • +
    +
    timestamp: number
    +
    + +

    Event timestamp in milliseconds since Unix epoch.

    +

    Timing semantics:

    +
      +
    • Live mode: when.getTime() at the moment of the event
    • +
    • Backtest mode: candle.timestamp of the candle being processed
    • +
    +
    + + + + + + + + + diff --git a/documents/docs_interface_SignalPingContract.html b/documents/docs_interface_SignalPingContract.html index 168b47dbe702c652a1c440836cf249a17131a0e9..ff068d8f7b113085c6ef58191d50f8396c28588d 100644 --- a/documents/docs_interface_SignalPingContract.html +++ b/documents/docs_interface_SignalPingContract.html @@ -11,8 +11,8 @@ liquidated externally). The framework closes the pending signal with closeReason

    Backtest never emits this event — there is no live exchange to query.

    Consumers:

    action: "signal-ping"
     
    diff --git a/documents/docs_interface_TickEvent.html b/documents/docs_interface_TickEvent.html index 50f197bdb2313aa91a92febd6d1e04cda49d8f76..e647a8c9852048313d76494e31871443cbeb2e86 100644 --- a/documents/docs_interface_TickEvent.html +++ b/documents/docs_interface_TickEvent.html @@ -4,7 +4,7 @@ Contains all information about a tick event regardless of action type.

    Event timestamp in milliseconds (scheduledAt for scheduled events, pendingAt for opened/closed events)

    -
    action: "closed" | "opened" | "scheduled" | "cancelled" | "idle" | "waiting" | "active"
    +
    action: "scheduled" | "cancelled" | "opened" | "closed" | "idle" | "waiting" | "active"
     

    Event action type

    diff --git a/documents/docs_type_BrokerActivePingPayload.html b/documents/docs_type_BrokerActivePingPayload.html new file mode 100644 index 0000000000000000000000000000000000000000..240e06bb00943aef087d4068c14b27e41e7b5f72 --- /dev/null +++ b/documents/docs_type_BrokerActivePingPayload.html @@ -0,0 +1,32 @@ +docs/type/BrokerActivePingPayload | backtest-kit

    BrokerActivePingPayload

    type BrokerActivePingPayload = {
    symbol: string;
    signalId: string;
    position: "long" | "short";
    currentPrice: number;
    priceOpen: number;
    priceTakeProfit: number;
    priceStopLoss: number;
    pnl: IStrategyPnL;
    context: {
    strategyName: StrategyName;
    exchangeName: ExchangeName;
    frameName?: FrameName;
    };
    backtest: boolean;
    }; +
    + +

    Payload for the active-ping broker event.

    +

    Emitted automatically via activePingSubject on every live tick while a pending (open) signal is +monitored. Forwarded to the registered IBroker adapter via onSignalActivePing. Purely +informational — unlike onOrderCheck a throw here does NOT close the position.

    +
    + + + + + + + + + diff --git a/documents/docs_type_BrokerIdlePingPayload.html b/documents/docs_type_BrokerIdlePingPayload.html new file mode 100644 index 0000000000000000000000000000000000000000..46c798b5a259955db01285fb3bf1601528d48998 --- /dev/null +++ b/documents/docs_type_BrokerIdlePingPayload.html @@ -0,0 +1,32 @@ +docs/type/BrokerIdlePingPayload | backtest-kit

    BrokerIdlePingPayload

    type BrokerIdlePingPayload = {
    symbol: string;
    currentPrice: number;
    context: {
    strategyName: StrategyName;
    exchangeName: ExchangeName;
    frameName?: FrameName;
    };
    backtest: boolean;
    }; +
    + +

    Payload for the idle-ping broker event.

    +

    Emitted automatically via idlePingSubject on every live tick while the strategy has no pending or +scheduled signal. Forwarded to the registered IBroker adapter via onSignalIdlePing. Purely +informational — carries no signal because none is active.

    +
    + + + + + + + + + diff --git a/documents/docs_type_BrokerPendingClosePayload.html b/documents/docs_type_BrokerPendingClosePayload.html new file mode 100644 index 0000000000000000000000000000000000000000..3f0032cbfb31b2ba1c73f909c3a13cc0c9d01a0c --- /dev/null +++ b/documents/docs_type_BrokerPendingClosePayload.html @@ -0,0 +1,32 @@ +docs/type/BrokerPendingClosePayload | backtest-kit

    BrokerPendingClosePayload

    type BrokerPendingClosePayload = {
    symbol: string;
    signalId: string;
    position: "long" | "short";
    currentPrice: number;
    priceOpen: number;
    priceTakeProfit: number;
    priceStopLoss: number;
    closeReason?: StrategyCloseReason;
    context: {
    strategyName: StrategyName;
    exchangeName: ExchangeName;
    frameName?: FrameName;
    };
    backtest: boolean;
    }; +
    + +

    Payload for the pending-signal-close broker event.

    +

    Emitted automatically via signalEventSubject (action "closed") when a pending position is closed. +Forwarded to the registered IBroker adapter via onSignalPendingClose. The closeReason +distinguishes take_profit / stop_loss / time_expired / user-close / broker fill / order gone.

    +
    + + + + + + + + + diff --git a/documents/docs_type_BrokerPendingOpenPayload.html b/documents/docs_type_BrokerPendingOpenPayload.html new file mode 100644 index 0000000000000000000000000000000000000000..1e8f84015aa534776dcbbea2370152c59beac999 --- /dev/null +++ b/documents/docs_type_BrokerPendingOpenPayload.html @@ -0,0 +1,32 @@ +docs/type/BrokerPendingOpenPayload | backtest-kit

    BrokerPendingOpenPayload

    type BrokerPendingOpenPayload = {
    symbol: string;
    signalId: string;
    position: "long" | "short";
    currentPrice: number;
    priceOpen: number;
    priceTakeProfit: number;
    priceStopLoss: number;
    context: {
    strategyName: StrategyName;
    exchangeName: ExchangeName;
    frameName?: FrameName;
    };
    backtest: boolean;
    }; +
    + +

    Payload for the pending-signal-open broker event.

    +

    Emitted automatically via signalEventSubject (action "opened") when a pending position is opened +(new signal / immediate entry / scheduled or user activation). Forwarded to the registered IBroker +adapter via onSignalPendingOpen.

    +
    + + + + + + + + + diff --git a/documents/docs_type_BrokerScheduleCancelledPayload.html b/documents/docs_type_BrokerScheduleCancelledPayload.html new file mode 100644 index 0000000000000000000000000000000000000000..9476770ca37e3bf762a064e5914a50d3c4655774 --- /dev/null +++ b/documents/docs_type_BrokerScheduleCancelledPayload.html @@ -0,0 +1,32 @@ +docs/type/BrokerScheduleCancelledPayload | backtest-kit

    BrokerScheduleCancelledPayload

    type BrokerScheduleCancelledPayload = {
    symbol: string;
    signalId: string;
    position: "long" | "short";
    currentPrice: number;
    priceOpen: number;
    priceTakeProfit: number;
    priceStopLoss: number;
    reason?: StrategyCancelReason;
    context: {
    strategyName: StrategyName;
    exchangeName: ExchangeName;
    frameName?: FrameName;
    };
    backtest: boolean;
    }; +
    + +

    Payload for the scheduled-signal-cancelled broker event.

    +

    Emitted automatically via scheduleEventSubject (action "cancelled") when a scheduled signal is +removed before it ever activated. Forwarded to the registered IBroker adapter via +onSignalScheduleCancelled. The reason distinguishes timeout / price reject / user cancel.

    +
    + + + + + + + + + diff --git a/documents/docs_type_BrokerScheduleOpenPayload.html b/documents/docs_type_BrokerScheduleOpenPayload.html new file mode 100644 index 0000000000000000000000000000000000000000..622cbdde8e9c7e18d97253840bef0de30021ea01 --- /dev/null +++ b/documents/docs_type_BrokerScheduleOpenPayload.html @@ -0,0 +1,33 @@ +docs/type/BrokerScheduleOpenPayload | backtest-kit

    BrokerScheduleOpenPayload

    type BrokerScheduleOpenPayload = {
    symbol: string;
    signalId: string;
    position: "long" | "short";
    currentPrice: number;
    priceOpen: number;
    priceTakeProfit: number;
    priceStopLoss: number;
    context: {
    strategyName: StrategyName;
    exchangeName: ExchangeName;
    frameName?: FrameName;
    };
    backtest: boolean;
    }; +
    + +

    Payload for the scheduled-signal-open broker event.

    +

    Emitted automatically via scheduleEventSubject (action "scheduled") when a new scheduled signal is +created and starts waiting for priceOpen activation. Forwarded to the registered IBroker adapter +via onSignalScheduleOpen. The scheduled -> active transition is NOT reported here — activation +arrives through onSignalOpenCommit.

    +
    + + + + + + + + + diff --git a/documents/docs_type_BrokerSchedulePingPayload.html b/documents/docs_type_BrokerSchedulePingPayload.html new file mode 100644 index 0000000000000000000000000000000000000000..4d16a029e9af6d6a7a21e65fa4f161d55738454e --- /dev/null +++ b/documents/docs_type_BrokerSchedulePingPayload.html @@ -0,0 +1,32 @@ +docs/type/BrokerSchedulePingPayload | backtest-kit

    BrokerSchedulePingPayload

    type BrokerSchedulePingPayload = {
    symbol: string;
    signalId: string;
    position: "long" | "short";
    currentPrice: number;
    priceOpen: number;
    priceTakeProfit: number;
    priceStopLoss: number;
    context: {
    strategyName: StrategyName;
    exchangeName: ExchangeName;
    frameName?: FrameName;
    };
    backtest: boolean;
    }; +
    + +

    Payload for the schedule-ping broker event.

    +

    Emitted automatically via schedulePingSubject on every live tick while a scheduled signal is +monitored (waiting for priceOpen activation). Forwarded to the registered IBroker adapter via +onSignalSchedulePing. Purely informational.

    +
    + + + + + + + + + diff --git a/documents/docs_type_BrokerSignalPendingPayload.html b/documents/docs_type_BrokerSignalPendingPayload.html index 340f27e0e5b2819c46cc2d98dc1a5f0f277b18f1..d22f59b4c8bc75ddaf190106a363919f6efc6d4b 100644 --- a/documents/docs_type_BrokerSignalPendingPayload.html +++ b/documents/docs_type_BrokerSignalPendingPayload.html @@ -4,7 +4,7 @@

    Payload for the pending-order synchronization broker event.

    Emitted automatically via syncPendingSubject on every live tick while a pending signal is monitored, BEFORE the framework evaluates TP/SL/time. Forwarded to the registered IBroker -adapter via onOrderPing.

    +adapter via onOrderCheck.

    The adapter should query the exchange by signalId and THROW ONLY when the order is definitively NOT FOUND by that id (filled, cancelled, or liquidated externally). A throw propagates to CREATE_SYNC_PENDING_FN, which makes the framework close the pending signal with diff --git a/documents/docs_type_StrategyData.html b/documents/docs_type_StrategyData.html index 45044175b4a704f65803605c1d59fc49642a8b28..8ce9ba12d6bb1e57e817d99b6d780dac2edecb3d 100644 --- a/documents/docs_type_StrategyData.html +++ b/documents/docs_type_StrategyData.html @@ -1,4 +1,4 @@ -docs/type/StrategyData | backtest-kit

    StrategyData

    type StrategyData = {
    pendingSignalId: string | null;
    createdSignal: ISignalDto | null;
    commitQueue: ICommitRow[];
    closedSignal: ISignalCloseRow | null;
    cancelledSignal: IScheduledSignalCancelRow | null;
    activatedSignal: IScheduledSignalActivateRow | null;
    }; +docs/type/StrategyData | backtest-kit

    StrategyData

    type StrategyData = {
    pendingSignalId: string | null;
    createdSignal: ISignalDto | null;
    commitQueue: ICommitRow[];
    closedSignal: ISignalCloseRow | null;
    cancelledSignal: IScheduledSignalCancelRow | null;
    activatedSignal: IScheduledSignalActivateRow | null;
    takeProfitSignal: ISignalCloseRow | null;
    stopLossSignal: ISignalCloseRow | null;
    };

    Type for persisted deferred strategy state. diff --git a/documents/docs_type_StrategyStatus.html b/documents/docs_type_StrategyStatus.html index a4ba75424cf1a9630b2acbc46977e1f95af46257..9c4f25b9dece1cb0cc639ef9b6410a8862aafe50 100644 --- a/documents/docs_type_StrategyStatus.html +++ b/documents/docs_type_StrategyStatus.html @@ -1,4 +1,4 @@ -docs/type/StrategyStatus | backtest-kit

    StrategyStatus

    type StrategyStatus = {
    pendingSignalId: string | null;
    createdSignal: ISignalDto | null;
    commitQueue: ICommitRow[];
    closedSignal: ISignalCloseRow | null;
    cancelledSignal: IScheduledSignalCancelRow | null;
    activatedSignal: IScheduledSignalActivateRow | null;
    }; +docs/type/StrategyStatus | backtest-kit

    StrategyStatus

    type StrategyStatus = {
    pendingSignalId: string | null;
    createdSignal: ISignalDto | null;
    commitQueue: ICommitRow[];
    closedSignal: ISignalCloseRow | null;
    cancelledSignal: IScheduledSignalCancelRow | null;
    activatedSignal: IScheduledSignalActivateRow | null;
    takeProfitSignal: ISignalCloseRow | null;
    stopLossSignal: ISignalCloseRow | null;
    };

    Type for persisted deferred strategy state. diff --git a/documents/private_classes.html b/documents/private_classes.html index 50216f46c11aa7e3f351412f2805772e1e114e4c..017548eb7a0191197e1b443ce6b392b8929a8b57 100644 --- a/documents/private_classes.html +++ b/documents/private_classes.html @@ -122,852 +122,810 @@

  • createAwaiter from functools-kit for async coordination
  • Background execution with Backtest.background() and event-driven completion detection
  • -

    backtest-kit classes

    The WalkerValidationService helps you keep track of and make sure your parameter sweep configurations, often called "walkers," are set up correctly. It acts as a central place to register these walkers, ensuring they exist before you try to use them in your backtesting or optimization processes.

    -

    Think of it as a librarian for your walkers – you add them to the registry, and it checks that they're actually there before letting you proceed.

    -

    The service also speeds things up by remembering (memoizing) whether a walker is valid, so it doesn’t have to check again and again.

    -

    You can use it to:

    -
      -
    • Add new walker configurations.
    • -
    • Verify that a walker exists and that all its connected strategies, risks, and actions are also valid.
    • -
    • See a complete list of all the walkers you've registered.
    • -
    -

    The service relies on other helper services like StrategyValidationService to ensure everything is consistent.

    -

    WalkerUtils helps you manage and run "walkers," which are essentially automated trading strategy comparisons. It simplifies the process of running these walkers by handling the underlying setup and logging.

    -

    Think of it as a convenient way to kick off and control these trading strategy tests. The system ensures each symbol and walker combination gets its own dedicated instance, preventing interference.

    -

    Here’s what you can do with WalkerUtils:

    -
      -
    • Run walkers: Start a comparison of strategies for a specific trading symbol and provide extra information.
    • -
    • Run in the background: Execute walkers without constantly checking for updates, useful when you just want to log something or trigger a side effect.
    • -
    • Stop walkers: Halt strategies within a walker from producing new trading signals. This doesn't immediately kill active signals; instead, they'll complete normally before stopping.
    • -
    • Get data: Retrieve the complete results from all strategy comparisons in a walker.
    • -
    • Generate reports: Create markdown reports summarizing the walker's performance.
    • -
    • Save reports: Export those reports to a file on your disk.
    • -
    • List walkers: View a list of all currently running walkers and their status (pending, completed, failed, or ready).
    • -
    -

    WalkerUtils is designed to be easily accessible, making it a central point for interacting with your walker system.

    -

    The WalkerSchemaService helps keep track of different schema templates used by walkers, ensuring they are well-defined and consistent. It uses a specialized system to store these templates in a type-safe way.

    -

    You can add new schema templates using the addWalker() method, and then retrieve them later by their name.

    -

    The service performs a quick check when a new schema is added to make sure it has the essential elements in the right format.

    -

    If you need to update an existing schema template, you can use the override() method to make targeted changes.

    -

    Finally, get() allows you to find a specific schema template by its name.

    -

    WalkerReportService helps you keep track of your strategy optimization experiments. It’s designed to automatically record the results of your strategy tests, saving them to a SQLite database.

    -

    This service listens for updates from your optimization process and saves key information like metrics and statistics for each test run. You can use this logged data to analyze how different parameter settings affect your strategy's performance and identify the best configurations.

    -

    Think of it as a detailed logbook for your optimization experiments, helping you compare strategies and understand what works best.

    -

    To use it, you'll subscribe to receive optimization updates, and when you're done, you'll unsubscribe to stop the data flow. This prevents accidental double-logging of results. The tick property handles the actual processing and logging of these events.

    -

    This service helps generate and save reports about your trading strategies as they're being tested. It listens for updates during the backtesting process, keeping track of how each strategy performs. It then organizes this information into easy-to-read markdown tables that compare the strategies.

    -

    The service uses a special storage system to ensure each walker – each individual simulation of a strategy – has its own separate set of results.

    -

    You can subscribe to receive updates as the backtest progresses, or unsubscribe when you no longer need them. The tick function is automatically called to process these updates.

    -

    You can request data about a specific strategy or generate a full report, which can then be saved as a markdown file in the logs/walker directory. It's also possible to clear the accumulated data, either for a single walker or for all of them.

    -

    This service helps manage and run automated trading strategies, often called "walkers." It's designed to make sure your strategies have the information they need, like the name of the strategy, exchange, and data frame, automatically passed along.

    -

    Think of it as a helpful layer on top of the core walker logic, making it easier to keep things organized and consistent.

    -

    It lets you easily trigger the execution of your trading strategies by providing a symbol and context. This handles the complexities of setting up the environment for each strategy to run, like ensuring all the necessary data is available. Essentially, you give it a symbol, and it orchestrates the backtesting process.

    -

    WalkerLogicPrivateService manages the process of comparing different trading strategies. It handles the execution and tracking of multiple strategies, essentially acting as a coordinator.

    -

    The service follows a specific workflow: it reports on the progress of each strategy as it finishes, keeps an eye on the best performance metric achieved so far, and then delivers a final report that ranks all the strategies involved.

    -

    It uses BacktestLogicPublicService behind the scenes to actually run the individual strategies.

    -

    The run method is your entry point – you provide it with the trading symbol, a list of strategies to compare, the metric you'll use for evaluation (like profit or Sharpe ratio), and some contextual information about the trading environment.

    -

    The run method provides updates as each strategy completes, letting you monitor the process in real-time.

    -

    WalkerCommandService acts as a central access point for walker-related functionalities within the system. It's designed to simplify how you interact with the walker logic, particularly when using dependency injection.

    -

    Think of it as a helpful layer that sits between you and the core walker operations.

    -

    This service has several key components it relies on, including services that handle validation of strategies, exchanges, frames, and the walker itself.

    -

    It also has a built-in validation process that's intentionally checked twice to ensure data integrity - it's a safety measure to prevent errors.

    -

    Finally, the run function allows you to initiate a comparison of a walker against a specific symbol, while also passing along important details like the walker's name, exchange, and frame. This lets the walker operate within a defined context.

    -

    The TimeMetaService helps you keep track of the latest candle timestamps for your trading strategies. It ensures you always know the current time, even when you’re not actively running a trading tick.

    -

    Essentially, it remembers the last timestamp received for each combination of symbol, strategy, exchange, and frame. It’s like a quick reference guide to candle times.

    -

    If you're already in the middle of a trading tick, it uses existing information; otherwise, it will wait for a short time to get that timestamp. The service automatically updates itself after each tick, so you don't have to worry about manual updates.

    -

    You can clear this memory to reset it, either for a specific combination or everything at once. This is particularly important when starting a new trading test or strategy run to avoid using outdated timestamps.

    -

    SystemUtils helps keep backtest sessions separate from each other. It prevents one backtest from accidentally affecting another by temporarily disconnecting from the global event system.

    -

    Essentially, it allows you to pause the event listeners for a backtest, run your test, and then easily resume the listeners afterward.

    -

    The createSnapshot method is key to this – it takes a picture of the current event listeners so they can be perfectly restored once the backtest is complete. This ensures a clean and isolated testing environment.

    -

    SyncUtils helps you analyze and understand the lifecycle of your trading signals. It collects data from signal openings and closures, giving you insights into what’s happening with your strategies.

    -

    Think of it as a tool to monitor how your signals are performing – how many signals you're creating, how many are being closed, and all the details in between.

    -

    You can request statistics to see the overall numbers for a specific strategy and symbol. It's like getting a quick summary of the signal activity.

    -

    Need more detail? You can generate a comprehensive markdown report. This report provides a table showing all the signal events for a given symbol and strategy, including crucial information like entry/exit prices, take profit/stop loss levels, and profit/loss.

    -

    Finally, you can easily export these reports as markdown files to disk, which you can then share or keep for later review. The filenames are designed to be descriptive, making it easy to identify the report's contents.

    -

    The SyncReportService helps you keep track of what's happening with your trading signals. It's like a detailed logbook that records every time a signal is created (when a limit order gets filled) and every time a signal is closed (when a position is exited).

    -

    This service listens for these events and carefully notes down all the important details, such as signal specifics and profit/loss information along with the reason for exiting.

    -

    The information gathered is then stored for auditing and order management purposes. To prevent issues with accidentally logging the same events multiple times, it ensures only one subscription to the signal events is active at a time.

    -

    You can start receiving these reports by subscribing, and stop them with an unsubscribe function. If you’re not subscribed, unsubscribing does nothing.

    -

    This service helps you create and save reports about how signals are opening and closing during a backtest or live trading. It listens for these signal events and organizes them by symbol, strategy, exchange, and timeframe.

    -

    It then builds detailed reports in markdown format, showing the lifecycle of each signal, along with some statistics like total signals, opens, and closes. These reports are saved to disk for later review.

    -

    To start collecting data, you need to subscribe to the signal events. You can unsubscribe at any time to stop collecting data and clear all the accumulated information.

    -

    Each time a signal event happens (open or close), the service records it and adds it to the corresponding report. You can retrieve the accumulated data for a specific combination of symbol, strategy, exchange, and timeframe. It’s also possible to generate a full report in markdown, or directly save the report as a file.

    -

    Finally, you can clear the collected data either for a specific signal combination or clear everything at once, effectively starting fresh.

    -

    The StrategyValidationService helps you keep track of and ensure the correctness of your trading strategies. Think of it as a central hub for managing strategy definitions.

    -

    It allows you to register new strategies, automatically checks if they exist before you use them, and verifies that any associated risk profiles and actions are set up correctly.

    -

    To make things efficient, it remembers the results of its validation checks, so it doesn't have to repeat the work unnecessarily.

    -

    You can use the service to:

    -
      -
    • Add new strategies to its registry.
    • -
    • Validate a specific strategy to confirm it's properly configured.
    • -
    • Get a list of all strategies that have been registered.
    • -
    -

    The service relies on other services, a logger, a risk validation service, and an action validation service, to perform its detailed validation steps.

    -

    StrategyUtils helps you analyze and understand how your trading strategies are performing. It's like a central hub for collecting and presenting data about your strategies' actions, such as closing positions, taking profits, or setting stop-loss orders.

    -

    You can use it to get statistical summaries of your strategy's behavior, showing you how often different actions occur. It can also create detailed markdown reports that list every event the strategy has triggered, including important details like the price, percentage values, and timestamps.

    -

    Furthermore, you can export these reports directly to files, making it easy to track performance over time and share results. The reports are organized by symbol, strategy, and timeframe, and can be customized to show only the columns you are interested in.

    -

    This service helps you keep track of different trading strategy blueprints, ensuring they're well-defined and consistent. It uses a secure system to store these blueprints, making sure they're easy to find and manage.

    -

    You can add new strategy blueprints using the addStrategy() function, and then retrieve them later by their name.

    -

    Before a new strategy blueprint is added, it's checked to make sure it has all the necessary components and is structured correctly.

    -

    If you need to update an existing strategy blueprint, you can use the override() function to make specific changes.

    -

    Finally, the get() function allows you to easily retrieve a strategy blueprint when you need it.

    -

    This service is designed to keep a detailed, persistent record of actions taken by your trading strategies. Think of it as a detailed audit trail for your backtests. It's different from services that build reports in memory; this one writes each event – like canceling a scheduled order, closing a pending order, or taking partial profits – directly to a JSON file as it happens.

    -

    To start using it, you need to "subscribe" to the service. Once subscribed, the service will capture key events and log them. When you're finished with the logging, you need to "unsubscribe" to clean up and stop the logging process.

    -

    The service provides several specific functions to log different types of events:

    +

    backtest-kit classes

    The WalkerValidationService helps you manage and double-check your walker configurations, which are used for things like optimizing strategies and hyperparameter tuning. It keeps track of all your walkers, ensuring they exist before you try to use them.

    +

    To make things efficient, it caches validation results so you don't have to repeat checks.

    +

    Here's what you can do with it:

    +
      +
    • Register walkers: Use addWalker() to add new walker configurations.
    • +
    • Check walker validity: The validate() function confirms a walker exists and that all associated strategies, risks, and actions are also set up correctly.
    • +
    • See all walkers: list() gives you a complete rundown of all registered walkers.
    • +
    +

    The service uses several other services internally like StrategyValidationService, RiskValidationService, and ActionValidationService to handle more specific validations. It also uses WalkerSchemaService and StrategySchemaService for schema-related operations.

    +

    WalkerUtils is a helper tool designed to simplify working with walkers, which are essentially automated systems for analyzing and comparing trading strategies. It provides a convenient way to execute walkers and manage their operations.

    +

    The run function executes a walker for a specific trading symbol and provides results as a stream of data. You can also run a walker in the background using background which is helpful for tasks like logging or triggering side effects without directly handling the results.

    +

    If you need to halt a walker's operations, the stop function can be used. It gracefully stops strategies from generating new signals, allowing existing ones to finish before stopping completely.

    +

    To retrieve comprehensive results or a formatted report summarizing the walker's performance, use getData or getReport, respectively. dump allows you to save the report to a file.

    +

    Finally, list gives you an overview of all active walkers, showing their status like pending, fulfilled, rejected, or ready. WalkerUtils manages these operations using isolated instances for each symbol-walker combination.

    +

    The WalkerSchemaService helps you keep track of different trading strategies, or "walkers," and their configurations in a safe and organized way. It acts like a central hub for managing these walker definitions.

    +

    You can add new walker schemas using addWalker, ensuring they're registered correctly. To find a specific walker, just use its name to retrieve it.

    +

    Before a walker is officially added, validateShallow checks that it has all the necessary components and that they're the right types. This helps prevent errors later on.

    +

    If you need to update an existing walker's details, override lets you make changes while keeping the rest of its definition intact.

    +

    Behind the scenes, it uses a secure storage system from functools-kit to ensure everything stays consistent.

    +

    WalkerReportService helps you keep track of your strategy optimization efforts. It acts like a dedicated record-keeper, capturing the results of each test run and storing them in a database.

    +

    It listens for updates from the optimization process and logs detailed information about each strategy tested, including performance metrics. You can use this information to monitor how your strategies are improving, identify the best-performing configurations, and analyze the optimization process overall.

    +

    The service is designed to avoid accidental double-reporting – once you subscribe to receive updates, you’ll get them reliably, and you can easily stop listening when you’re done.

    +

    It works with a logger for helpful debugging messages.

    +

    The WalkerMarkdownService helps you automatically create detailed reports about your trading strategies as they run. It listens for updates from your trading strategies (called "walkers") and keeps track of their performance.

    +

    These reports are presented in a readable Markdown format, showing comparisons between different strategies. They're saved to your logs directory, making it easy to review and analyze your trading results.

    +

    You can subscribe to the service to receive these updates, and unsubscribe when you no longer need them. The tick function is how the service processes the updates it receives.

    +

    You can retrieve specific data points, generate reports for particular strategies, and even clear all accumulated data when needed. This simplifies the process of monitoring and understanding how your trading strategies are performing over time. The service uses a special storage system to keep the data for each walker separate and organized.

    +

    This service helps manage and run walkers, which are essentially automated trading strategies or simulations. It builds upon a private service to handle the core walker logic, but adds a layer of convenience.

    +

    It automatically passes along important information like the strategy's name, the exchange being used, the frame it's running within, and the walker’s identifier. This avoids having to manually pass this data around each time you run a walker.

    +

    The run method is the main way to use it. You give it a symbol (like "AAPL") and some contextual information, and it will execute the walker comparison process, effectively running backtests for different strategies.

    +

    WalkerLogicPrivateService helps orchestrate and compare different trading strategies. It essentially manages the process of running multiple strategies and keeps track of their performance.

    +

    The service provides updates as each strategy finishes its backtest, so you can monitor progress. It also identifies and remembers the strategy with the best performance metrics in real-time.

    +

    Finally, it delivers a complete report, ranking all the strategies based on their results.

    +

    It relies on BacktestLogicPublicService to perform the actual backtesting for each strategy.

    +

    You can think of it as a conductor, bringing together and organizing different strategies to see how they stack up against each other.

    +

    The constructor doesn’t take any parameters.

    +

    The service uses several other services internally, including a logger and services for handling backtest logic, markdown formatting, and walker schema.

    +

    The run method is the primary way to use the service. You provide the symbol you want to backtest, a list of strategies to compare, the metric you’re using to evaluate performance, and some contextual information. It then runs the backtests one after another and gives you updates as they complete.

    +

    WalkerCommandService acts as a central access point for walker-related functionality, making it easier to use within your applications. It's essentially a convenient layer on top of WalkerLogicPublicService, designed for seamless integration through dependency injection.

    +

    It bundles together several key services needed for walker operations, including those responsible for handling schemas, validations, and managing the overall workflow.

    +

    The validate method ensures that your walker and strategy setups are correct, preventing issues by performing checks and caching results to optimize performance.

    +

    To actually execute a walker comparison, you can use the run method, specifying the trading symbol and relevant context like the walker, exchange, and frame names. This method returns a sequence of results, letting you analyze the comparison step-by-step.

    +

    The TimeMetaService is designed to provide a reliable way to get the current timestamp for your trading strategies, even when you're not actively running a tick. Think of it as a central record of when each symbol, strategy, exchange, and frame last updated.

    +

    It keeps track of these timestamps using a special system that makes sure you always have the most recent data available. If a timestamp hasn't been received yet, it will wait a short time to get it, ensuring you aren't working with old information.

    +

    This service is automatically updated by the system after each tick and offers a way to clear out the stored timestamps when needed, ensuring everything stays fresh. You can either clear all the timestamps or just the ones related to a specific combination of symbol, strategy, exchange, and frame. It's especially useful for tasks that need to know the current candle time, but happen between those regular tick executions.

    +

    SystemUtils helps keep backtest sessions separate and clean. It prevents one backtest from messing with another by temporarily disconnecting everything that's listening for events.

    +

    It provides a way to take a "snapshot" of the current event listeners. This essentially clears out the event listeners, allowing a new backtest session to run without interference. After the new session is complete, you can restore the listeners to their original state using the snapshot.

    +

    SyncUtils helps you analyze and understand the lifecycle of your trading signals. It gathers information about signal openings and closings, giving you insights into how your strategies are performing.

    +

    Think of it as a tool for keeping track of your signals and generating reports.

    +

    You can request statistical data like total signal events, openings, and closures. It also produces detailed markdown reports, which are essentially nicely formatted tables, that show all your signal activity. These tables include crucial details like signal ID, direction, price points, and profit/loss information.

    +

    Finally, you can have these reports automatically saved to files, making it easy to review and share your trading history. The filenames clearly identify the symbol, strategy, exchange, and whether it was a backtest or live trade.

    +

    The SyncReportService helps you keep track of what's happening with your signals. It listens for signals being opened and closed and records those events. This record keeping is really useful for understanding how your trading strategies are performing and for keeping an audit trail.

    +

    It captures details like when a signal is first created (when a limit order is filled), and when it's closed, including information about profits and losses and why it was closed. It then neatly stores this information ready for you to examine later.

    +

    To make sure things don't get messy, the service only allows one subscription at a time. You subscribe to receive the signal events, and when you're done, you can unsubscribe to stop receiving them.

    +

    This service is designed to automatically create and save reports detailing the lifecycle of trading signals. It keeps track of signal events like opens and closes, organizes them by symbol, strategy, exchange, and timeframe, and then generates nicely formatted markdown tables.

    +

    You can tell it to listen for these signal events, and it will begin collecting data. Once it's listening, it handles each event as it comes in, adding a timestamp to each one. If you stop listening, it cleans up all the accumulated data.

    +

    You can request statistics for a specific combination of symbol, strategy, and timeframe, or ask it to generate a complete report in markdown format. It can also write those reports directly to disk, naming them according to whether they represent backtesting or live trading data. Finally, you can clear out the accumulated data, either for a specific set of parameters or completely.

    +

    This service helps you keep track of your trading strategies and make sure they're set up correctly. It essentially acts as a central manager for your strategies, keeping a record of them.

    +

    You can add new strategies using the addStrategy function, providing a name and the details of the strategy. Before you try to use a strategy, this service verifies it exists and confirms that any linked risk profiles or actions are also valid. To improve performance, validation results are cached, so the service doesn't have to repeat checks unnecessarily. Finally, you can view a complete list of all registered strategies with the list function.

    +

    The service relies on other services like riskValidationService and actionValidationService to handle those specific validations.

    +

    StrategyUtils helps you understand and report on how your trading strategies are performing. It's like a central place to gather information about events triggered by your strategies, such as closing positions or adjusting stops.

    +

    This utility provides a way to get statistical summaries of strategy activity, like how many times a particular action was taken.

    +

    You can also generate detailed reports in Markdown format, presenting each event in a clear, organized table. This table includes key information like the symbol traded, the action taken, the price at the time, and timestamps.

    +

    Finally, StrategyUtils can automatically save these reports to files, creating nicely named documents that you can easily share or review later. The reports include a summary of the events and are structured for easy readability.

    +

    The StrategySchemaService helps keep track of different trading strategy blueprints, ensuring they're all structured correctly. It acts like a central library for strategy definitions.

    +

    You can add new strategy blueprints using the addStrategy() method, giving each one a unique name. Later, you can easily find a specific strategy's blueprint by its name using the get() method.

    +

    Before a strategy blueprint is added, the validateShallow() method checks if it has all the necessary parts and that those parts are of the right type.

    +

    If a strategy blueprint already exists, you can update parts of it with the override() method, which allows you to make changes without replacing the entire blueprint.

    +

    The service relies on a logging system, loggerService, to keep track of what's happening, and it uses a secure registry, _registry, to store the strategy blueprints safely.

    +

    This service helps you keep a detailed, persistent audit trail of your trading strategy's actions. It's designed to record events like canceling scheduled orders, closing pending orders, taking partial profits or losses, adjusting stop-loss orders (trailing stops and take-profits), and moving stop-loss to breakeven.

    +

    To use it, you first need to "subscribe" to start logging. Then, it automatically writes each event as a separate JSON file to disk. When you're done, you "unsubscribe" to stop the logging process.

    +

    Unlike other reporting methods, this service immediately writes events to disk, ensuring a reliable record of your strategy's behavior.

    +

    Here's a breakdown of the event types it handles:

    • cancelScheduled: Records when a scheduled order is cancelled.
    • -
    • closePending: Records the closing of a pending order.
    • -
    • partialProfit: Logs when a portion of the position is closed with a profit.
    • -
    • partialLoss: Logs when a portion of the position is closed at a loss.
    • -
    • trailingStop: Tracks adjustments to the stop-loss order (trailing stop).
    • -
    • trailingTake: Tracks adjustments to the take-profit order (trailing take).
    • +
    • closePending: Records when a pending order is closed.
    • +
    • partialProfit: Records when a portion of a position is closed for a profit.
    • +
    • partialLoss: Records when a portion of a position is closed at a loss.
    • +
    • trailingStop: Records adjustments to the trailing stop-loss.
    • +
    • trailingTake: Records adjustments to the trailing take-profit.
    • breakeven: Records when the stop-loss is moved to the entry price.
    • -
    • activateScheduled: Logs a premature activation of a scheduled signal.
    • -
    • averageBuy: Records when a new average buy entry is added (useful for DCA strategies).
    • -
    -

    Each of these functions receives details about the event, including the symbol, context (strategy name, exchange, etc.), timestamp, signal ID, and relevant financial data like P&L, peak profit, and drawdown.

    -

    This service helps you track and report on what your trading strategies are doing during backtests or live trading. It essentially acts as a memory bank for important events like signals being canceled, orders being filled, or take-profit levels being adjusted.

    -

    Instead of writing each event to a file immediately, it holds them temporarily for a more efficient, batch-oriented reporting process. It uses a clever caching system to manage data for different symbols and strategies.

    -

    To start using it, you need to "subscribe" to begin collecting events. Events are automatically logged when things happen in your strategies. Then, you can use functions like getData() to get summary information, or getReport() and dump() to create nicely formatted markdown reports. When you're done, "unsubscribe" to stop the data collection and clear everything.

    -

    There are functions to record various actions your strategy takes, like canceling scheduled signals, closing positions, setting take profits, and more. You can retrieve all of the events for a specific symbol and strategy combination, or generate a full markdown report with customizable columns. The dump() function lets you save these reports to files with timestamped names for easy tracking. You can also clear the temporary storage of events if needed.

    -

    This class, StrategyCoreService, is a central hub for managing trading strategies within the backtest-kit framework. It acts as a middleman, receiving requests and injecting necessary information (like the trading symbol, timestamp, and backtest settings) into the strategy's execution environment.

    -

    Think of it as a coordinator that handles all the behind-the-scenes work, making sure your strategies run smoothly and safely.

    -

    Here's what it does:

    -
      -
    • Validation: It validates strategies and their configurations to ensure they are set up correctly. This validation is cached to avoid repeated checks.
    • -
    • Signal Retrieval: It can fetch the current pending or scheduled signal for a symbol, crucial for monitoring things like stop-loss levels and expiration times.
    • -
    • Position Information: It provides detailed insights into a currently open position, like its overall cost, entry prices (including DCA history), partial close history, and profitability.
    • -
    • State Management: It allows you to query and modify the state of active strategies, from checking if a strategy is stopped to canceling scheduled signals or closing positions.
    • -
    • Simulation and Execution: It handles running strategies in backtesting mode and initiating live trading.
    • -
    • Resource Cleanup: It can clear cached strategies to free up resources when they're no longer needed.
    • -
    -

    Essentially, StrategyCoreService is the engine that powers the execution and monitoring of your trading strategies within the backtest-kit environment. It streamlines operations and provides a consistent interface for interacting with your strategies.

    -

    This service acts as a central hub for managing strategy operations within the backtest kit. It intelligently routes method calls to the correct strategy implementation, ensuring that they're applied to the right symbol and strategy combination.

    -

    Think of it as a smart dispatcher—when you want a strategy to perform an action, this service figures out exactly which strategy is responsible and executes it. To optimize performance, it caches frequently used strategies, preventing redundant creation.

    -

    Here's a breakdown of how it works:

    -
      -
    • Routing: It handles requests for strategy actions (like tick() or backtest()) and makes sure they're directed to the right strategy instance.
    • -
    • Caching: It stores strategy instances in a cache to avoid repeatedly creating them, making the process faster. The cache key takes into account exchange and frame specifics.
    • -
    • Initialization: It ensures the strategy is ready before processing any requests.
    • -
    • Comprehensive Operations: It manages both live trading (tick()) and historical simulation (backtest()) scenarios.
    • -
    -

    The service relies on several other connected services to properly function, including:

    -
      -
    • Logging: Manages logging and context information.
    • -
    • Schema Management: Handles strategy schema definitions.
    • -
    • Risk & Exchange Connections: Integrates with risk and exchange-related services.
    • -
    • Time & Pricing Data: Provides access to time and price information.
    • -
    -

    The service provides a wide range of methods for interacting with strategies, including:

    -
      -
    • Retrieving Signals: It can fetch active signals, scheduled signals, and details related to pending positions (like total cost, percent closed, and entry prices).
    • -
    • Position Management: Methods like partialProfit, partialLoss, and averageBuy allow for modifying and managing active positions.
    • -
    • Control and Monitoring: It allows for stopping a strategy, clearing its cache, and checking its status.
    • -
    • Validation: It can validate potential actions (e.g., partial profit, average buy) before executing them.
    • -
    -

    The StorageLiveAdapter helps manage how trading signals are stored, giving you flexibility to choose different storage methods. It acts as a middleman, allowing you to easily switch between persistent storage (saving to disk), in-memory storage (keeping data only during the current session), or a dummy adapter (which does nothing – useful for testing).

    -

    You can pick your storage method using usePersist, useMemory, or useDummy, and the adapter handles the details of saving and retrieving signals. The getInstance property is a smart shortcut that builds the storage utilities only when needed and reuses them afterward, which helps with performance.

    -

    The adapter also provides methods like handleOpened, handleClosed, findById, and list to manage signals – it passes these actions on to whatever storage method you’ve selected. The clear function is particularly useful when the environment changes between strategy runs, forcing a fresh start for the storage utilities. The handleActivePing and handleSchedulePing methods keep the updatedAt field of the signals up-to-date for active and scheduled signals, respectively.

    -

    The StorageBacktestAdapter provides a flexible way to manage how your backtest data is stored. It allows you to easily switch between different storage methods like persistent storage (saving to disk), in-memory storage, or even a dummy storage that doesn't actually save anything.

    -

    You can choose which storage method to use with convenience functions like usePersist, useMemory, and useDummy. It also handles events like signals being opened, closed, scheduled, or cancelled, relaying these to the currently selected storage adapter.

    -

    If you need to find a specific signal or retrieve a list of all signals, it provides methods for that too. Importantly, there's a clear function to ensure that if your working directory changes, a fresh storage instance is created, preventing potential issues across different backtest runs. Essentially, it decouples the storage logic from the core backtesting process, giving you a lot of control and flexibility.

    -

    The StorageAdapter is the central piece for managing how your trading signals are saved and accessed. It automatically keeps track of signals as they come in, whether they're from a backtest or from a live trading scenario.

    -

    You can turn on signal storage by enabling it, which will subscribe to the signal emitters – but it's designed to only subscribe once, preventing unwanted duplicates.

    -

    Conversely, disabling signal storage unsubscribes from everything, and it’s perfectly safe to disable it multiple times if needed.

    -

    Need to find a specific signal? The findSignalById function lets you search for signals using their unique ID, looking in both backtest and live storage areas.

    -

    If you want to see all the signals from your backtesting runs, use listSignalBacktest. Similarly, listSignalLive displays all the live signals that have been recorded.

    -

    The StateLiveAdapter helps manage the state of your trading strategies, allowing you to easily switch between different storage methods. Think of it as a flexible way to keep track of important data for each trading signal.

    -

    It offers several built-in storage options: a default file-based persistence (great for saving progress between restarts), an in-memory option (fast but not persistent), and a dummy adapter (useful for testing).

    -

    A key feature is that it remembers things like the peak percentage gain and how long a trade has been open, which is really handy for advanced strategies – particularly those involving LLMs – to automatically adjust trades based on specific criteria.

    -

    Here’s what you can do with it:

    -
      -
    • disposeSignal: Clears out old state data when a signal is finished.
    • -
    • getState: Retrieves the current state information.
    • -
    • setState: Updates the state.
    • -
    • useLocal, usePersist, useDummy: Quickly change the storage method being used.
    • -
    • useStateAdapter: Lets you plug in your own custom state management logic.
    • -
    • clear: Clears the cache of stored states, essential when the base path changes.
    • -
    -

    The StateLiveAdapter is designed to be adaptable, making it easier to build and maintain robust trading strategies.

    -

    The StateBacktestAdapter provides a flexible way to manage the state information used during backtesting. It allows you to easily switch between different storage methods – keeping data only in memory, saving it to disk, or using a dummy adapter for testing purposes. This adaptability is key for experimenting with different backtesting scenarios and ensuring data integrity.

    -

    The adapter tracks metrics like peak percentage change and how long a position has been open, allowing you to implement rules, such as automatically exiting trades if they haven't met certain performance thresholds.

    -

    You can switch between storage methods using handy helper functions like useLocal, usePersist, and useDummy. The disposeSignal method is important for cleaning up memoized data when a signal is finished, and clear is useful when the working directory changes, guaranteeing fresh data for each test. It's designed to work with various state instance implementations, making it a central piece for managing data throughout your backtesting framework.

    -

    The StateAdapter acts as a central hub for managing how your backtesting and live trading systems store and access data. It automatically handles cleaning up old data when signals are stopped, preventing issues caused by outdated information.

    -

    It uses a special method to ensure subscriptions only happen once, and provides ways to both turn state storage on and off.

    -

    You can retrieve the current state of a signal using getState, or update it using setState. Importantly, these functions intelligently direct operations to either your backtest environment or your live trading system based on the provided configuration.

    -

    This service helps you keep track of and make sure your position sizing strategies are set up correctly. It acts like a central manager, keeping a record of all your sizing methods.

    -

    You can add new sizing strategies using addSizing, which registers them for use.

    -

    To ensure a sizing strategy exists before you use it, use the validate method. It's designed to catch potential errors early on.

    -

    If you need to see a full list of all the sizing strategies you've registered, the list method provides that information. It remembers previous validation results to speed things up too.

    -

    The SizingSchemaService helps you manage and store sizing schemas, which define how much of an asset to trade. It uses a special registry to keep track of these schemas, ensuring they're all set up correctly.

    -

    You add new sizing schemas using register and can update existing ones with override.

    -

    To use a specific sizing schema, simply request it by name with get.

    -

    Before a sizing schema is added, a quick check (validateShallow) makes sure it has all the necessary information in the right format. This helps prevent errors later on.

    -

    The SizingGlobalService helps determine how much of an asset to trade, essentially figuring out your position size. It acts as a central hub, using a connection service to perform the actual calculations. This service is critical for both how strategies run and the tools available for users.

    -

    It manages several internal components:

    -
      -
    • A logger for tracking and debugging.
    • -
    • A connection service to handle the sizing calculations themselves.
    • -
    • A validation service to ensure the sizing request is valid.
    • -
    -

    The core function, calculate, is how you request a position size. You provide the parameters like risk tolerance and the context of the sizing request, and it returns the suggested size.

    -

    The SizingConnectionService helps manage how your trading strategy determines the size of each position it takes. It acts as a central hub, directing sizing calculations to the correct specialized sizing component based on its name.

    -

    Think of it like a switchboard – you tell it which sizing method you want to use, and it connects you to the right expert.

    -

    To improve speed and efficiency, it remembers which sizing components it's already created, so it doesn't have to build them again.

    -

    When your strategy needs to calculate a position size, it uses this service. The service handles the details of choosing the right sizing method, applying risk management rules, and ultimately returning the calculated position size.

    -

    If your strategy doesn't have a custom sizing configuration, you’ll use an empty string as the sizing name.

    -

    This framework component, SessionLiveAdapter, provides a flexible way to manage and store data during live trading sessions. Think of it as a central hub where your trading strategies can read and write information, and this hub can be configured to store that data in different ways.

    -

    You can easily switch between storage options: keep data only in memory for testing, use a persistent file-based system to survive restarts, or even use a dummy adapter to simply discard data. The adapter uses a default file-based storage but allows for swapping in alternatives.

    -

    It remembers which adapter you're using based on the symbol, strategy name, exchange, and frame, ensuring you're always working with the correct data. If your project directory changes, the clear function can be used to refresh these settings. This allows for robust, configurable data management during your live trading runs.

    -

    This component helps manage and store data during backtesting. Think of it as a flexible system for handling session data – the information that changes as your trading strategy runs.

    -

    It allows you to easily switch between different ways of storing this data, such as keeping it only in memory (fast but temporary), saving it to disk for later use, or even discarding it entirely for testing purposes.

    -

    You can quickly change how the data is handled with convenient commands like useLocal, usePersist, and useDummy. It intelligently caches data to avoid unnecessary creations. If you need to use a custom way of managing data, you can even plug in your own adapter. Finally, clear can be used to refresh the cached data if the program’s working directory changes.

    -

    The SessionAdapter is the central hub for handling data storage during both simulated backtesting and live trading. It intelligently directs data requests and updates to either the backtest storage or the live trading storage, depending on whether you're running a simulation or a real-time operation.

    -

    You can use getData to retrieve the current value of a signal, providing details like the symbol, strategy name, exchange, frame, and a timestamp. Similarly, setData lets you update a signal’s value, ensuring the update is saved to the correct storage location. Essentially, it simplifies data management by abstracting away the difference between backtesting and live environments.

    -

    This class, ScheduleUtils, helps you keep track of and report on scheduled signals – think of it as a way to monitor how your trading strategies are sending out orders. It’s designed to be easy to use, acting as a central place to get information and generate reports about those signals.

    -

    You can request data about signals for specific trading symbols and strategies to see how they're performing.

    -

    It also creates clear, readable reports in Markdown format, which you can then share or store.

    -

    Finally, it offers the ability to save these reports directly to your computer's file system. The class is always available in one single instance, making it very convenient to use.

    -

    The ScheduleReportService helps you keep track of how your scheduled signals are performing. It monitors these signals and records important events like when they're scheduled, when they start, and when they're cancelled.

    -

    Think of it as a detailed logbook for your scheduled orders, noting how long it takes from the initial schedule to when the order actually executes or is cancelled.

    -

    It uses a logger to provide debugging information and works by listening for signal events and then writing those events to a database. To use it, you'll subscribe to receive events, and when you’re finished, you can unsubscribe to stop the monitoring. It’s designed to prevent duplicate subscriptions to avoid issues.

    -

    This service automatically creates reports detailing scheduled and cancelled trading signals. It keeps track of these events for each strategy you're using.

    -

    It works by listening for signal events and then organizing them into tables, providing useful insights like cancellation rates and average wait times.

    -

    These reports are saved as markdown files, making them easy to read and share, usually found in a logs folder under a "schedule" directory.

    -

    You can subscribe to receive these signal events, and the service will handle the rest. It also allows you to fetch data or reports for a specific trading setup or completely clear all accumulated data if needed.

    -

    This service helps you keep track of and verify your risk management setups. Think of it as a central place to register different risk profiles and make sure they're available before you need them.

    -

    It allows you to add new risk profiles using addRisk, ensuring they’re known to the system. You can then use validate to confirm that a specific risk profile exists before proceeding with any actions that depend on it.

    -

    To see what profiles you've registered, you can call list, which returns a comprehensive list of all the risk schemas currently managed. The service is also designed to be efficient; it remembers validation results to avoid unnecessary checks.

    -

    The RiskUtils class offers tools for examining and reporting on risk rejection events, helping you understand and address potential issues in your trading system. It acts as a central point for accessing and summarizing data collected about rejections, primarily by pulling information from the RiskMarkdownService.

    -

    You can use it to get statistical summaries of rejections, broken down by symbol, strategy, and other factors. It can also create detailed markdown reports, formatted as tables showing individual rejection events with key details like price, position, and reason.

    -

    Finally, the class lets you easily save those reports directly to files, automatically creating the necessary directory structure with filenames that clearly identify the symbol and strategy involved. Think of it as your go-to resource for digging into and documenting what's going wrong with your risk management.

    -

    The RiskSchemaService helps you manage and store risk schemas in a type-safe way. It uses a registry to keep track of your risk profiles, ensuring consistency and preventing errors.

    -

    You can add new risk profiles to the registry using the addRisk() method (represented by register here) and retrieve existing ones by their names using get().

    -

    Before adding a risk profile, the service performs a quick check with validateShallow() to make sure it has all the essential information in the correct format.

    -

    If a risk profile already exists, you can update it using override(), which allows you to modify specific properties without replacing the entire schema.

    -

    The service also has internal components like a logger (loggerService) to help track its activity.

    -

    The RiskReportService is designed to keep a record of when trading signals are rejected by the risk management system. Think of it as an audit trail for risk decisions.

    -

    It listens for these rejections and saves them – including why they were rejected and details about the signal itself – into a database.

    -

    You can tell it to start listening for these rejection events, and it will automatically stop listening if you need it to. It also makes sure you don't accidentally subscribe multiple times, which could cause problems.

    -

    The service relies on a logger to provide some debugging information.

    -

    This service is designed to automatically create and save reports detailing rejected trades due to risk management rules. It listens for these rejection events and organizes them, creating easy-to-read markdown tables that summarize the rejections for each symbol and trading strategy.

    -

    Think of it as an automated reporting system that helps you understand why trades are being rejected and identify potential issues.

    -

    Here's a bit more detail:

    -
      -
    • It keeps track of all rejection events, separating them by symbol and strategy.
    • -
    • It generates reports in a standard markdown format, including statistics about the rejections.
    • -
    • The reports are saved to disk so you can review them later.
    • -
    • It’s designed to be flexible, allowing you to clear old data or focus on specific symbol/strategy combinations.
    • -
    • It uses a "storage" system to keep data isolated for each symbol, strategy, exchange, frame and backtest combination.
    • -
    -

    You can subscribe to receive these rejection events, and when you’re done, you can unsubscribe. The dump method allows you to save the generated reports directly to your file system.

    -

    This service manages risk-related operations, acting as a central point for validating risk limits. It works closely with a connection service to ensure that trading actions comply with predefined risk parameters.

    -

    Several components help with this process: a logger for tracking activity, services for validating risk configurations, exchange details, and trading frames. The validate function ensures risk configurations are correct and avoids repeated checks for the same scenarios.

    -

    The checkSignal function determines if a trading signal is permissible based on risk limits, while checkSignalAndReserve provides a safe way to validate signals and temporarily allocate resources, preventing conflicts when multiple trading attempts occur simultaneously.

    -

    Furthermore, there are methods to record open signals (addSignal) and close signals (removeSignal) within the risk management system. Finally, the clear function allows for resetting risk data, either for a specific risk instance or globally.

    -

    This service acts as a central hub for managing risk checks within your trading system. It intelligently connects different parts of your system to the right risk management components.

    -

    It's designed to route risk-related operations to the correct "ClientRisk" instance, making sure that risk assessments are accurate and consistent. To speed things up, it remembers previously used risk management components, avoiding repetitive work.

    -

    Here's a breakdown of what it does:

    -
      -
    • Risk Routing: It uses a riskName to direct risk assessment requests to the appropriate component. If you don't specify a riskName (like for strategies without specific risk settings), it defaults to an empty string.
    • -
    • Caching: It saves previously used risk management components to avoid recreating them, which improves performance.
    • -
    • Signal Validation: It verifies whether a trading signal is safe to execute by checking against predefined risk limits like portfolio drawdown and exposure.
    • -
    • Concurrency Control: checkSignalAndReserve provides a way to validate signals and reserve resources safely, preventing conflicts in concurrent trading scenarios.
    • -
    • Signal Management: It provides methods to register and remove trading signals within the risk management system.
    • -
    • Cache Clearing: You can clear the cached risk management components if needed.
    • -
    -

    The service relies on other services like RiskSchemaService, TimeMetaService and ActionCoreService and includes logging capabilities for monitoring and debugging.

    -

    This component provides a flexible way to manage and store your trading data, like backtest results or live trading information. It acts as a bridge between your trading strategies and different storage options, allowing you to easily switch between them.

    -

    The system automatically keeps track of which storage method is being used for each type of report (e.g., backtest results, walker data), ensuring you don't accidentally mix up your data. It starts with a default JSONL storage option, which appends data to JSONL files.

    -

    You can customize the storage method by providing your own adapter. The adapter remembers these settings, so you don’t have to reconfigure them every time. It also only creates storage instances when it first needs to write data, which optimizes performance.

    -

    For testing or debugging, you can switch to a "dummy" adapter that ignores all data writes, or revert back to the default JSONL adapter. If your working directory changes, it’s a good idea to clear the adapter cache to ensure fresh storage instances are created.

    -

    ReportUtils helps you control which parts of the backtest-kit framework generate detailed reports. Think of it as a way to turn on and off specific data logging for things like backtests, live trading sessions, or performance analysis.

    -

    You can selectively enable these logging features – for instance, just turning on logging for backtests without affecting other areas. When you enable a feature, it starts recording events and writing them to JSONL files, which contain helpful information like timestamps and other details. It’s crucial to remember to stop these processes later to avoid resource problems, which ReportUtils helps with.

    -

    Conversely, you can disable logging for specific services without impacting others, allowing you to focus on the data you need. This is done by simply unsubscribing from those services. The enable method provides a way to subscribe to multiple services simultaneously and provides a function to unsubscribe from all of them at once.

    -

    This class provides a way to efficiently log trading events to JSONL files, making it easier to analyze your backtests later. It’s designed to write data incrementally, one event at a time, to a single file for each report type. The system handles potential delays and errors gracefully, ensuring data isn't lost and processes don't get stuck.

    -

    You can specify where the files are saved and what kind of report you're creating (like order events, trade executions, or portfolio snapshots).

    -

    It automatically sets up the necessary directories and handles writing the data in a structured format, including metadata like the symbol, strategy, and exchange involved. The waitForInit method initializes everything once, and the write method is how you add new event data to the log file. The writing process is also designed to be reliable, with timeout protections and backpressure management to avoid overwhelming the system. The system provides a method to search this logged data with various criteria like symbol, strategy, exchange, frame, signalId and walkerName.

    -

    The ReportAdapter helps you organize and store your trading data in a structured way, allowing for flexible analytics and logging. It acts as a central point for managing how your reports are stored, letting you easily switch between different storage methods without changing your core trading logic. It remembers which storage method is active, ensuring consistency across your tests.

    -

    You can customize the storage method by providing your own adapter, or use the built-in options like the default JSONL-based storage, or even a dummy adapter for testing when you don’t need to save data. It initializes storage only when needed and can also clear its memory if you’re changing the location where your reports are saved. This makes it great for keeping track of what's happening during your backtests and analyzing your trading decisions.

    -

    This utility class, ReflectUtils, provides a centralized way to track key performance metrics for your trading positions, like profit, drawdown, and duration. It's designed to work seamlessly whether you're live trading or running backtests.

    -

    Think of it as a reporting tool that gives you insights into how your strategies are performing. It pulls data related to P&L, peak profit, and drawdown, and it handles all the behind-the-scenes calculations for you.

    -

    Here's a breakdown of what it can do:

    -
      -
    • Real-time Position Metrics: You can retrieve data like unrealized P&L in percentage or dollar terms, the highest profit achieved, and the maximum drawdown experienced.
    • -
    • Timing Information: It lets you know how long a position has been active, when the best profit was recorded, and how long it’s been since the worst loss.
    • -
    • Distance Calculations: It calculates the difference between current prices and the highest profit or deepest drawdown points, expressed as either percentage or dollar values.
    • -
    • Singleton Instance: ReflectUtils is a singleton, meaning you'll only ever have one instance of it, making it easy to access.
    • -
    • Backtest Support: It works for both live and simulated trading scenarios.
    • -
    • Context Awareness: Requires context like strategy, exchange and frame name to retrieve the correct data.
    • -
    -

    Essentially, ReflectUtils simplifies the process of analyzing your strategies' performance and provides critical data for evaluation.

    -

    This component manages recent trading signals, allowing you to choose where that data is stored – either persistently on disk or in memory. It provides a flexible way to work with signals, letting you easily switch between storage methods as needed.

    -

    The system keeps track of a single, cached instance of your chosen storage method for efficiency. You can change which storage method is used with functions like usePersist (for disk storage) and useMemory (for in-memory storage), with the default being persistent storage.

    -

    You can also provide your own storage implementation using useRecentAdapter.

    -

    It offers methods to retrieve the most recent signal, calculate how long ago a signal was created, and react to "active ping" events, all by forwarding requests to the currently selected storage adapter. If the environment changes (like when running different strategies), you can clear the cached storage instance using clear to ensure a fresh start.

    -

    This component provides a flexible way to manage and access recent trading signals, allowing you to choose between storing them in memory or persistently on disk. It acts as a central point for interacting with the signal storage, letting you swap out different storage methods easily.

    -

    Think of it as an adapter pattern – you can plug in different storage solutions without changing the core logic that uses them. By default, it uses in-memory storage for quick access.

    -

    You can switch between in-memory and persistent storage using simple methods like useMemory() and usePersist(). The clear() function is helpful for refreshing the storage connection when your project's working directory changes. The getInstance property makes sure that storage operations are efficient by creating the storage utility instance only once.

    -

    The RecentAdapter manages how recent trading signals are stored and accessed, working for both backtesting and live trading environments. It automatically keeps track of signals by listening for updates and provides a simple way to get the most recent signal for a specific trading context.

    -

    To prevent unnecessary subscriptions, it ensures only one subscription happens at a time. You can easily turn this storage on or off, and it's safe to turn it off multiple times without causing problems.

    -

    When you need to find the newest signal, getLatestSignal looks first in your backtest data and then in live data. It’s designed to avoid "look-ahead bias" – it won't return signals that haven't happened yet based on the specified time.

    -

    Finally, getMinutesSinceLatestSignalCreated tells you how much time has passed since the most recent signal appeared, also respecting that look-ahead bias. It’s useful for understanding how frequently signals are being generated.

    -

    PriceMetaService helps you get the latest market prices for your trading strategies, even when you're not actively executing a trade. It keeps track of prices for each symbol, strategy, exchange, frame, and backtest combination, updating them as new ticks come in.

    -

    Think of it as a central price tracker, ensuring you have the right information whenever you need it, like when a command is triggered outside of the usual trading flow. If a price isn't immediately available, it'll wait a short time to see if it arrives, preventing errors.

    -

    It's designed to be a clean and efficient way to access prices, with the ability to clear out old price data to keep things fresh. The service automatically manages the price tracking, so you don't have to worry about setting it up yourself. You can either clear prices for a specific combination or clear all of them at once, which is especially useful when starting a new backtest or trading session.

    -

    This class helps you figure out how much of an asset to trade, using different strategies. It’s a collection of tools to calculate position sizes, like determining how many shares or contracts to buy or sell.

    -

    Each calculation method—fixed percentage, Kelly Criterion, and ATR-based—is implemented as a function within this class. These functions not only perform the calculations but also make sure the information you provide is suitable for the specific sizing technique.

    -

    For example, the Kelly Criterion needs your win rate and win-loss ratio, while the ATR-based method requires the Average True Range. The class handles checking these inputs so you can be more confident in your position sizing.

    -

    The Position class helps you figure out where to place your take profit and stop loss orders. It intelligently adjusts based on whether you're going long (buying) or short (selling) an asset.

    -

    It offers two main strategies for calculating these levels:

    -
      -
    • -

      moonbag: This calculates a take profit level that's a fixed percentage above (for long positions) or below (for short positions) the current price. Think of it as a simple way to lock in some gains.

      -
    • -
    • -

      bracket: This allows you to define your own custom take profit and stop loss percentages to fit a more specific trading plan. It provides greater flexibility in managing risk and reward.

      -
    • +
    • activateScheduled: Records when a scheduled signal is activated before the intended time.
    • +
    • averageBuy: Records new entries added when using a dollar-cost averaging strategy.
    -

    The moonbag and bracket functions take information about your position—like current price, your stop loss percentage, and whether you're long or short—and return the calculated take profit and stop loss prices.

    -

    This utility class helps manage how a strategy’s state is saved and restored, especially when dealing with delayed actions like queueing trades or signals. It ensures that each strategy's state is persisted correctly, even if things go wrong.

    -

    It uses a clever system to create storage instances for each strategy, symbol, and exchange, creating them only when needed. You can customize how this storage works by providing your own 'constructors' to handle the saving and loading of data.

    -

    The readStrategyData method retrieves this saved data, while writeStrategyData saves any changes. It also provides ways to switch between different storage methods, like using files, a default JSON implementation, or even a dummy version that does nothing for testing purposes.

    -

    If you need to completely refresh the storage, you can clear the cache. This is useful when the working directory changes during testing or development.

    -

    This class helps you save and load the state of your trading strategies to a file. It's designed to be reliable, even if your program crashes unexpectedly.

    -

    It essentially manages the storage of your strategy's data, using a specific identifier ("strategy") within a defined storage area.

    -

    Here's a breakdown:

    -
      -
    • How it works: It automatically handles saving and loading your strategy's data to a file.
    • -
    • Initialization: You need to tell it when to initially set up the storage (using waitForInit).
    • -
    • Saving data: writeStrategyData lets you save the current state of your strategy, or clear it entirely.
    • -
    • Loading data: readStrategyData retrieves the saved strategy state, or returns nothing if there's no data.
    • -
    • Context-aware: It associates the storage with a specific trading symbol, strategy name, and exchange.
    • -
    -

    The STORAGE_KEY is a constant identifier that tells the system where to find or store strategy data. The _storage property is the actual file system component being used to persist your data.

    -

    This class helps manage how signal data is saved and loaded persistently, particularly for backtesting and live trading. It ensures that each signal's information is stored as a separate file, making it organized and easy to manage.

    -

    The system intelligently caches storage instances to avoid repeatedly creating them, which improves performance.

    -

    You can customize how these storage instances are created using a constructor, and it offers a way to switch between different storage methods, like using a standard file system, a dummy storage for testing, or even plugging in your own custom storage solution.

    -

    This is important for keeping track of signal states even if the application crashes or restarts. The readStorageData and writeStorageData functions provide a safe and reliable way to access and update this stored data. The clear function allows you to refresh the storage cache when necessary.

    -

    This class provides a way to store your trading signals persistently using files on your computer. It's designed to be reliable, even if your program crashes unexpectedly.

    -

    Each trading signal is saved as its own JSON file, making it easy to manage and identify them individually. When you need to retrieve all your signals, it scans through all the available files.

    -

    The constructor lets you indicate whether you're in a backtesting mode.

    -

    You can use waitForInit to make sure the storage is ready before you start working with it. readStorageData fetches all your saved signals. writeStorageData saves a collection of signals, ensuring each one is written safely.

    -

    This utility class, PersistStateUtils, helps manage how your trading strategies save and load their data. It keeps track of different storage locations based on identifiers, making sure each strategy's data stays separate and organized.

    -

    You can think of it as a central place to control how your state is persisted, allowing for flexibility in storage methods.

    -

    It's designed to make sure your strategy’s state survives unexpected interruptions like crashes, automatically setting up the necessary storage.

    -

    Here's a quick breakdown of what it offers:

    -
      -
    • Smart Storage: It remembers which storage locations are already in use, so you don’t have to set them up every time.
    • -
    • Customizable: You can swap out the default storage method with your own, tailoring it to your specific needs.
    • -
    • Easy Clean-up: Functions are provided to clear out old storage or clean up after a strategy is finished.
    • -
    • Testing Mode: A 'dummy' mode lets you simulate state persistence without actually saving anything, which is useful for testing.
    • -
    -

    When your strategy needs to save information, this class takes care of the details, so you can focus on the trading logic.

    -

    This class, PersistStateInstance, provides a way to save and load state data persistently, typically to a file. Think of it as a reliable container for keeping track of your trading strategy's progress.

    -

    It's designed to work with a specific signal and a bucket name, essentially creating a unique storage space for each combination. The bucket name acts like an identifier for the data being stored.

    -

    The waitForInit method makes sure the storage is ready before you try to read or write anything.

    -

    Reading and writing state are straightforward with readStateData and writeStateData methods, each using that bucket name to locate the correct data. The writeStateData method also accepts a timestamp to indicate when the data was last updated.

    -

    Finally, dispose doesn’t actually do anything itself; it relies on a separate utility function to clean up related resources.

    -

    This class helps manage how signal data is saved and retrieved, ensuring that each trading strategy has its own persistent storage. It's designed to be reliable, even if your application crashes unexpectedly.

    -

    The PersistSignalUtils system provides a way to customize how this storage works, allowing you to plug in different adapters for various storage needs.

    -

    It automatically handles creating and managing these storage instances, making it easy to work with. You can also clear the existing storage if needed, like when the working directory changes.

    -

    The readSignalData method lets you retrieve previously saved signal data, while writeSignalData allows you to update that data, or even clear it entirely. There are also options to easily switch between different storage methods, such as using files, a dummy implementation for testing, or a custom solution.

    -

    This class, PersistSignalInstance, is designed to reliably store and retrieve signal data, acting as a bridge between your trading strategy and persistent storage. It's built to be robust, handling situations where your application might crash unexpectedly.

    -

    It combines file-based storage with techniques to ensure data integrity, making sure your signals are saved correctly even if something goes wrong. Each signal is uniquely identified by its symbol, the name of the strategy using it, and the exchange involved, keeping everything organized.

    -

    The waitForInit method sets up the initial storage. The readSignalData method fetches the signal data associated with a specific symbol, while writeSignalData saves a signal's data (or clears it if you need to remove it). Essentially, this class provides a safe and predictable way to manage your signal data across sessions.

    -

    This class provides tools for safely saving and loading session data during your trading strategies. Think of it as a way to remember what your strategy learned between runs, like important configurations or intermediate results.

    -

    It manages these saved sessions in a structured way, creating a unique storage location based on your strategy's name, the exchange it's trading on, and a specific "frame" or snapshot in time.

    -

    You can easily swap out how the data is stored, whether it's to a file, a dummy adapter for testing, or a custom solution. The system automatically handles creating and managing these storage locations, and it ensures that writing and reading data happens reliably.

    -

    It also has a way to clear out old data and clean up sessions when they're no longer needed, keeping things tidy and preventing issues. Essentially, it helps to preserve your trading strategy's state across multiple executions.

    -

    This class provides a way to save and load data associated with a specific trading strategy and exchange, persisting it to a file. Think of it as a way to remember the state of your backtest.

    -

    It uses a unique identifier, frameName, to organize this data within a larger storage system.

    -

    The waitForInit method ensures that the storage is ready before you try to use it.

    -

    readSessionData retrieves previously saved data, while writeSessionData saves the current state.

    -

    Finally, dispose doesn’t do anything directly; it relies on a separate utility function to handle any cleanup required, like clearing cached data.

    -

    This utility class helps manage how scheduled signals are saved and loaded, especially for strategies that need to remember their planned actions. It makes sure each strategy has its own dedicated storage space for these signals, and it’s designed to be reliable even if there are unexpected interruptions.

    -

    You can customize how these signals are stored – for example, using files, a database, or even a dummy system that doesn't actually save anything. The class automatically handles creating these storage spaces when needed and ensures changes are written safely.

    -

    If you want to change the storage method, you can use the usePersistScheduleAdapter method to specify a custom storage constructor. You can also easily revert to a default file-based storage using useJson or use a dummy adapter for testing purposes with useDummy. If your program's working directory changes, you'll need to clear the cache using clear to ensure everything loads correctly. Reading data happens on first access and writing works similarly to initialize and write the signal information.

    -

    This class, PersistScheduleInstance, helps reliably store and retrieve schedule data for your trading strategies. It's designed to work with file-based storage, ensuring your data is saved safely even if things go wrong.

    -

    Think of it as a dedicated container for a specific trading strategy's schedule, identified by its symbol (the asset being traded), the name of the strategy, and the exchange it operates on.

    -

    It handles the underlying file storage for you, ensuring that writes happen securely.

    -

    Here's a quick rundown of what you can do with it:

    -
      -
    • It initializes the storage to get things started.
    • -
    • It reads existing schedule data, looking for signals associated with a particular symbol.
    • -
    • It allows you to write new schedule data or clear out existing data, again using the symbol for identification.
    • -
    -

    This class helps manage how active trading positions are saved and loaded, especially for risk management. It keeps track of position data and makes sure it's stored reliably.

    -

    It intelligently creates storage instances based on the risk profile being used, avoiding unnecessary creations.

    -

    You can customize how this storage works by providing your own storage constructors.

    -

    The readPositionData method retrieves previously saved active positions, and writePositionData saves the current positions. These operations happen in a safe and consistent manner.

    -

    If you need to change the storage mechanism, functions like usePersistRiskAdapter, useJson, and useDummy allow you to switch between different storage types, including using a custom adapter or a dummy instance for testing.

    -

    The clear function is useful to reset the stored instances when the working directory changes.

    -

    This class provides a way to save and load trading positions persistently, ensuring your backtesting results aren't lost. It's designed to work reliably even if your program crashes unexpectedly.

    -

    It essentially acts as a manager for your position data, automatically handling the details of saving it to a file. The data is stored under a specific, predefined name ("positions") to keep things organized.

    -

    Here's a breakdown of what it does:

    -
      -
    • It initializes the storage location for your position data.
    • -
    • It retrieves the saved position data from the storage file.
    • -
    • It saves the current position data back to the storage file.
    • -
    -

    The riskName and exchangeName properties help identify the context of the data being stored, making it easy to manage data from different sources. The STORAGE_KEY constant is a fixed identifier used internally.

    -

    This class, PersistRecentUtils, helps manage how recent trading signals are stored and retrieved, ensuring they’re handled consistently across different scenarios. It’s designed to work behind the scenes in backtesting and live trading environments.

    -

    It keeps track of these signal instances based on a combination of factors like the traded symbol, the strategy being used, the exchange involved, and the timeframe.

    -

    The class automatically handles the storage, using a system that remembers which storage method is active and only creates a storage instance once for each unique combination of those factors. You can even swap out the storage method, allowing you to use a file-based system, a simple dummy system for testing, or provide your own custom storage solution.

    -

    The readRecentData method fetches the latest signal, and writeRecentData saves a new one. These operations are designed to be safe, even if there are unexpected interruptions.

    -

    If your working directory changes, you'll need to manually clear the cached storage to ensure data integrity.

    -

    This class helps you save and load the most recent trading signal data for a specific strategy and exchange. It's designed to work with files, making sure the data is written reliably.

    -

    Each instance focuses on a particular symbol (the asset being traded), a strategy name, an exchange, a frame (like a timeframe), and whether it's a backtest or live trading scenario.

    -

    The class automatically manages the underlying file storage, keeping things organized.

    -

    You can use waitForInit to ensure storage is ready before you start, and readRecentData to retrieve the latest signal data. writeRecentData is used to save new data, associating it with the specific symbol for later retrieval.

    -

    This class, PersistPartialUtils, helps manage and safely store information about partial profits and losses for trading strategies. It’s designed to be reliable even if things go wrong, ensuring your strategy's progress isn't lost.

    -

    The system remembers which storage method to use for each trading symbol and strategy, so you don't have to worry about managing those details yourself. You can even customize how the data is stored if you need to, by providing your own storage adapter.

    -

    It handles reading and writing partial data in a way that's designed to be safe and consistent.

    -

    If you need to switch back to a simple file-based storage or just want to test things out without actually saving data, there are convenient options for that as well. The system cleans up its temporary data when necessary, especially when the working directory changes.

    -

    This class helps you save and load pieces of data related to your trading strategies, particularly useful when dealing with incomplete or temporary information. It's designed to work with files, making sure your data is stored reliably.

    -

    It remembers three key pieces of information: the symbol you’re trading, the name of your strategy, and the exchange you’re using.

    -

    The class uses a unique identifier (signalId) to organize data and ensures that writing data happens safely, even if there are interruptions.

    -

    To get started, it needs to be initialized with the symbol, strategy name, and exchange name.

    -

    You can use waitForInit to make sure the storage is ready before you start saving anything.

    -

    readPartialData lets you retrieve any saved partial data associated with a specific signal, and writePartialData allows you to store new partial data. Essentially, it provides a convenient way to manage temporary data associated with your trading signals.

    -

    This class helps manage how notification data is saved and retrieved, particularly for backtesting and live trading environments. It provides a way to store each notification as a separate file, identified by a unique ID, ensuring reliable and safe data handling even if the system crashes.

    -

    It uses a clever system of memoization, meaning it only creates one storage instance per environment (backtest or live) to optimize performance.

    -

    You can customize how notifications are persisted by providing your own storage constructor, or you can easily switch back to the default file-based storage or a dummy storage that doesn't actually save anything – useful for testing.

    -

    The readNotificationData and writeNotificationData functions handle reading and writing notification information, and they automatically set up the necessary storage if it's not already available.

    -

    If you need to refresh the storage, such as when the working directory changes, clear will reset the memoization and force a new instance to be created.

    -

    This class provides a way to save and load notification data persistently, using files on your computer. It’s designed to be reliable, even if your program crashes unexpectedly.

    -

    Each notification is stored as its own JSON file, making it easy to manage individual updates. The system reads all these files when loading data.

    -

    You can control whether this feature is used during backtesting scenarios with a simple boolean setting. The underlying file storage mechanism is handled automatically.

    -

    The waitForInit method prepares the storage, and readNotificationData retrieves all stored notifications. Finally, writeNotificationData saves a collection of notifications, assigning each one a unique identifier for easy access.

    -

    This utility class helps manage how trading memory data is saved and loaded persistently. It intelligently caches storage instances, making sure you don't create unnecessary files or slow down your backtesting process.

    -

    You can customize how these memory instances are created, allowing for different storage solutions. The class also provides methods to read, write, and delete memory entries, all while handling potential errors gracefully.

    -

    It offers a way to check if a specific memory entry exists before attempting to read it, and you can clear the cache when needed, for instance, when the working directory changes. There's also a handy function to list all stored entries for rebuilding indexes. Finally, it provides built-in options to use a default JSON-based storage or even a dummy instance for testing purposes.

    -

    This class provides a way to store and retrieve data persistently, like saving information to a file. It’s designed to work with the backtest-kit framework and specifically manages data related to a particular signal and bucket.

    -

    Think of it as a manager for saving and loading "memory" – data that needs to be kept around between different parts of the system.

    -

    It handles saving data to a file, ensuring that changes are written completely. When data isn’t needed anymore, it doesn’t actually delete it; instead, it marks it as removed, which allows for easy recovery if needed. You can check if data exists, read specific entries by ID, write new data, and list all the available data. Importantly, this class doesn't handle cleaning up the underlying memory cache; that's taken care of by another part of the system.

    -

    This class helps manage cached data from external APIs, ensuring the data is saved reliably and consistently. It creates specialized storage areas for data, organized by a combination of timestamp and symbol.

    -

    You can customize how this caching happens by providing your own storage solutions. The class automatically handles reading, writing, and even soft-deleting data, making sure the process is safe even if the system crashes.

    -

    For testing or development, you can switch to a "dummy" adapter that doesn't actually store anything.

    -

    If your working directory changes between strategy runs, you'll need to clear the cached storage to avoid issues. You can also use built-in options to switch back to a standard file-based storage or a simple dummy.

    -

    This component handles saving and retrieving measure data, essentially acting as a persistent storage system for your trading strategies. It's designed to be reliable, ensuring data is written safely and consistently to a file.

    -

    Data is managed within a "bucket," which acts as a logical grouping for your measure data.

    -

    You can read specific entries using their keys, and if an entry is no longer needed, it's not actually deleted – instead, it's marked as removed, keeping the file intact but excluding it from active use.

    -

    The listMeasureData function provides a way to see only the valid, non-removed data entries.

    -

    This class helps manage how your log data is saved and retrieved. It uses a cached copy of the log instance to make things efficient. You can even customize how the logs are stored by swapping out the default storage mechanism for your own adapter.

    -

    The system automatically handles reading and writing log entries, making sure that updates are reliable. Each log entry is stored as a separate file, and the whole process is designed to be safe even if the system crashes.

    -

    You can easily change the persistence method, for example, to use a default file-based storage, a JSON-based method, or even a dummy method that does nothing. The cached instance is reset when you change persistence methods or when the working directory changes. This ensures that you're always using the correct storage configuration.

    -

    This class helps you store your trading log data persistently, like saving it to a file so you don't lose it. It's a default way to make sure your logs are saved reliably.

    -

    Each log entry gets its own individual file, making it easy to manage and access specific entries. The system reads the logs by looking at a list of all the files it’s managing.

    -

    Importantly, it only adds to the logs – it won’t overwrite anything already there. This is a safeguard against data loss in case of unexpected interruptions. The process is designed to be safe even if your system crashes during storage.

    -

    You can use waitForInit to make sure the storage area is ready before you start writing logs. readLogData pulls all the existing log entries, and writeLogData adds new entries to the log, avoiding overwrites.

    -

    This component manages persistence for tracking when specific time intervals have "fired" within your backtesting process. It essentially keeps a record of which intervals have already occurred.

    -

    It stores these records as files within a designated directory structure, allowing you to prevent repeated actions for the same time period.

    -

    You can customize how this persistence works by providing your own storage mechanisms, such as using a file-based system, a JSON adapter, or even a dummy adapter for testing purposes where no actual storage happens.

    -

    The framework lazily initializes storage for each time period (bucket) only when it's first needed.

    -

    Functions are available to read, write, and delete these interval markers, as well as to clear the internal cache if the working directory changes. You can also iterate through all markers for a given time period to see which intervals have already been processed.

    -

    This class provides a way to store and manage data related to trading intervals using files. It acts as a reliable record-keeper, ensuring your trading logic can consistently track and react to time-based events.

    -

    The system uses a designated "bucket" to organize these interval records. Data is saved as JSON files, and a special "removed" flag allows for soft deletion – essentially marking a record as inactive without permanently deleting it. This lets your trading framework retry operations if a marker appears to have been missed.

    +

    The subscribe method ensures that logging starts cleanly and the unsubscribe method safely shuts down the logging process.

    +

    This service helps you track and analyze what's happening in your trading strategies during backtesting or live trading. It's designed to gather information about various actions like canceling orders, closing positions, and adjusting stop-loss levels.

    +

    Think of it as a detailed logbook for your strategies. Instead of writing each event to a file immediately, it temporarily stores them to create reports later.

    Here's a breakdown of how it works:

    -
      -
    • Initialization: waitForInit sets up the file storage for the bucket.
    • -
    • Reading Data: readIntervalData retrieves a specific interval record; if the record is missing or has been soft-deleted, it returns nothing.
    • -
    • Writing Data: writeIntervalData creates or updates an interval record.
    • -
    • Soft Deletion: removeIntervalData marks a record as deleted without actually removing the file, allowing for retries.
    • -
    • Listing Data: listIntervalData provides a way to iterate through all active (non-deleted) interval records within the bucket.
    • -
    -

    This class helps manage a persistent cache of historical candle data, essentially saving and loading it from files on your computer. Each candle's data is stored in its own file, organized by the exchange, symbol, timeframe, and timestamp.

    -

    It’s designed to be efficient; it only loads cached data if the number of files matches what's expected, and it automatically handles refreshing the cache when needed. It also guarantees that writes to the cache happen reliably.

    -

    You can customize how the cache is stored by providing your own way of creating candle instances, or you can revert to the standard file-based approach or even use a dummy implementation for testing. The clear method is useful when you're restarting your strategy because it resets the cache.

    -

    This class provides a way to persistently store candle data, like opening prices, highs, lows, and volumes, for a specific trading symbol and timeframe. It essentially acts as a file system-based cache for this data.

    -

    Each candle's data is saved as a separate JSON file, making it easy to retrieve individual candles. If a candle's timestamp isn't found, it's treated as a cache miss, meaning the system needs to fetch it from the original source.

    -

    When saving data, the system intelligently skips any incomplete candles, which are those that haven't yet reached their closing time, and avoids overwriting existing data. This ensures a clean and consistent cache of fully completed candles.

    -

    The waitForInit method ensures the underlying storage is ready before any read or write operations. It's designed to be used when you first start using the persistence layer.

    -

    The class's internal storage is specific to the symbol, interval, and exchange it manages, keeping the data neatly organized.

    -

    This utility class helps manage and save breakeven data, which is essential for tracking and optimizing trading strategies. It’s designed to reliably store and retrieve this data to disk, ensuring that your strategies remember their state even across restarts.

    -

    The class uses a clever system to avoid unnecessary file operations; it only creates a storage instance when it's actually needed. It automatically handles saving the data in a specific file structure, so you don't have to worry about the details of where and how the information is stored.

    -

    You can also customize how the data is stored—for example, you might want to use a different file format or even bypass storage entirely for testing purposes. The class provides easy ways to switch between different storage methods, like using a standard JSON file, a custom adapter, or a dummy instance that doesn’t actually save anything. It's like having a built-in assistant for keeping your breakeven information organized and accessible.

    -

    This class provides a way to reliably save and load breakeven data for your trading strategies. It’s designed to be persistent, meaning the data survives even if your application crashes.

    -

    Think of it as a safe keeper for important information about your trading setups. It uses files to store this data, and ensures that writes are done safely to prevent corruption.

    -

    The class needs to know which symbol, strategy, and exchange it’s working with when it’s created. It uses a unique identifier, the signal ID, to track each piece of data.

    -

    The waitForInit method makes sure the storage is ready before you try to save anything. readBreakevenData fetches the breakeven data for a specific signal, while writeBreakevenData allows you to save updated information. Essentially, it handles the reading and writing of your breakeven data persistently.

    -

    PersistBase provides a foundation for reliably saving and loading data to files, ensuring your data remains consistent even if errors occur. It's designed to handle the complexities of managing files, like automatically fixing corrupted files and safely deleting them.

    -

    This class manages files related to a specific type of data (defined by entityName) and stores them in a designated directory (baseDir). The path to that directory is automatically calculated and maintained.

    -

    You can use readValue to retrieve a saved entity, hasValue to check if an entity exists, and writeValue to save new or updated entities. It makes sure writes are atomic, so data isn’t left incomplete in case of interruptions.

    -

    keys() gives you a way to go through all the IDs of the stored entities. waitForInit is used to set up the storage directory and check the integrity of any existing data.

    -

    This service helps you understand how long different parts of your trading strategies take to run. It listens for timing events generated during strategy execution and records them in a database. Think of it as a way to identify performance bottlenecks – where your strategy is spending the most time.

    -

    You can tell it to start listening for these timing events using the subscribe method, which will return a function you can call to stop listening. The unsubscribe method does the same thing, ensuring you don't accidentally subscribe multiple times. It uses a special technique to prevent unwanted multiple subscriptions.

    -

    The service also has a logger for debugging and a way to write the collected data to the database for later analysis. It's designed to be a straightforward way to gain insights into your strategy's performance and find areas for improvement.

    -

    The PerformanceMarkdownService is a tool designed to monitor and report on how your trading strategies are performing. It listens for performance data, organizes it by strategy, and calculates key statistics like averages, minimums, maximums, and percentiles.

    -

    It automatically generates easy-to-read markdown reports, which include a breakdown of potential bottlenecks. These reports are saved directly to your logs directory.

    -

    You can subscribe to receive performance updates, and unsubscribe when you no longer need them. The track function is used to feed it the actual performance data as it's being generated.

    -

    The service provides methods to retrieve specific performance data for a particular strategy, generate reports on demand, and clear out accumulated data when necessary. The storage mechanism ensures each strategy’s data is kept separate and organized.

    -

    The Performance class helps you understand how your trading strategies are performing. It offers tools to analyze performance metrics for specific symbols and strategies, giving you a clear picture of what's working well and where there might be issues.

    -

    You can retrieve detailed performance statistics, which include information like the number of operations, their durations, averages, and outliers. This lets you pinpoint areas where your strategy might be slow or inefficient.

    -

    The class also allows you to generate easy-to-read markdown reports. These reports visualize your performance data, highlighting bottlenecks and important trends, and provide a structured overview.

    -

    Finally, it's simple to save these reports directly to your computer's file system for later review or sharing, with the option to customize the file path and included data columns.

    -

    The PartialUtils class helps you analyze and report on partial profit and loss data gathered during trading. Think of it as a tool to understand how your strategies are performing in terms of smaller, incremental gains and losses.

    -

    It pulls information from the system that tracks these partial events, allowing you to get statistics like total profit/loss counts.

    -

    You can generate detailed reports in markdown format, which displays your partial profit and loss events in a clear, organized table. This table shows important details like the type of event (profit or loss), the symbol traded, the strategy used, the signal ID, position, percentage level, price, and when it occurred. Summary statistics appear at the bottom of this table.

    -

    Finally, it allows you to easily save these reports to a file, automatically creating any necessary folders. The reports are named with the symbol and strategy name, making them easy to identify and manage.

    -

    The PartialReportService is designed to keep track of smaller, partial exits from your trades – those times when you take some profit or cut a loss before the entire position is closed.

    -

    It works by monitoring two streams of data: one for partial profit events and one for partial loss events. Whenever a partial exit occurs, the service records details like the price and level at which it happened.

    -

    This information is then persistently stored in a database, allowing you to analyze how these partial exits impact your overall trading strategy.

    -

    You can tell the service to start listening for these events using the subscribe method, which returns a function you’ll use to stop listening. The unsubscribe method handles stopping the monitoring process, ensuring you don't accumulate unnecessary data.

    -

    The PartialMarkdownService helps you keep track of and report on your trading performance, specifically focusing on partial profits and losses. It listens for these events as they happen and carefully organizes them for each symbol and strategy you're using.

    -

    It builds detailed markdown reports, essentially tables, that show exactly what happened with each profit and loss. You can also get overall statistics like the total number of profit and loss events.

    -

    This service automatically saves these reports to your disk, creating files named after the symbol and strategy.

    -

    To use it, you'll need to subscribe to the profit and loss signals to start collecting data. You can then request reports, statistics, or have the reports saved directly to disk. Finally, you have the option to clear the accumulated data if needed, either for a specific combination of symbol, strategy, exchange, frame, and backtest or to clear everything.

    -

    The PartialGlobalService acts as a central hub for managing partial profit and loss tracking within the backtest-kit framework. It’s designed to keep things organized by handling logging and forwarding requests to a dedicated connection service. Think of it as a gatekeeper – it's where ClientStrategies receive their initial instructions related to partials, ensuring consistent monitoring and a layer of separation between the strategy logic and the underlying connection mechanics.

    -

    Several services, including validation and schema services, are integrated to ensure proper setup and configuration.

    -

    The profit and loss functions handle updates to profit/loss states, notifying the system when new levels are reached. The clear function resets the partial state when a signal is closed. All these functions log actions before passing them on to the connection service for actual execution.

    -

    The PartialConnectionService manages the tracking of partial profits and losses for trading signals. It acts like a central hub, ensuring that each signal has its own dedicated record for this purpose.

    -

    Think of it as a factory – it creates and maintains these records (ClientPartial instances), remembering them for later use. When a signal reaches a profit or loss milestone, this service handles the necessary updates and notifications.

    -

    It's designed to be efficient; it uses a caching system to avoid creating duplicate records and cleans them up when they're no longer needed. The service is integrated into the overall trading system and works closely with other components to ensure accurate and timely updates. When a trade closes, the service clears out the relevant data, preventing lingering information.

    -

    This component helps manage notifications during live trading, providing a flexible way to send updates about your strategies. It acts as a central hub, handling events like signals, profits, losses, and errors, and then sending those updates through a chosen notification method.

    -

    Think of it like a messenger – you tell it what happened (a signal, a partial profit, etc.), and it delivers that message using a specific method.

    -

    You can easily switch between different "messengers" (notification adapters) to control where these updates go – whether it's to memory, a persistent storage, or even a dummy adapter that does nothing.

    -

    It’s designed to be adaptable: you can choose how your notifications are handled, with options for in-memory storage, persistent storage, or even a dummy adapter that ignores them altogether. The use... methods simplify switching between these adapters.

    -

    The getInstance property and its associated clear method are important for maintaining a fresh notification adapter when your environment changes, such as when you change the working directory. This ensures notifications are handled correctly in different iterations of your strategy.

    -

    Essentially, this framework streamlines the process of notifying you about important events happening during your trading strategies, letting you customize how and where that information is delivered.

    -

    This service helps manage and send out important notifications during trading simulations. It’s designed to make sure everything is checked and working correctly before a notification is sent.

    -

    Think of it as a quality control line for signals – it validates details like the trading strategy, exchange, and the timeframe being used. This validation happens only once for each specific combination of strategy, exchange, and timeframe to keep things efficient.

    -

    The service provides a way to trigger these notifications, specifically signal.info events, which are then sent to interested parties and recorded for later review. You’ll typically use this service through the commitSignalNotify() method when you're setting up callbacks in your trading strategies. It ensures that the information being sent is accurate and compliant.

    -

    This component acts as a central point for managing notifications during backtesting. It's designed to be flexible, allowing you to choose different ways to handle those notifications – whether that's storing them in memory, persisting them to disk, or effectively ignoring them altogether for testing purposes.

    -

    Think of it as a pluggable system; you can easily swap out the underlying notification mechanism without changing much of your core backtesting code. It comes with a default "memory" option for simple storage, but you can also use persistent storage or a dummy adapter to suppress notifications.

    -

    The handleSignal, handlePartialProfit, handleRisk, and other handle... methods are all entry points for different types of notifications. These methods simply pass the data along to the currently selected notification adapter. The getData method retrieves any notifications that have been recorded, and dispose clears them out.

    -

    You can switch between notification adapters using methods like useDummy, useMemory, and usePersist. The useNotificationAdapter method provides the most control, allowing you to specify a custom adapter constructor. The clear method is important to call when things change, like when the base directory changes, so you get a fresh notification instance.

    -

    The NotificationAdapter is responsible for handling and managing notifications, both from backtesting and live trading scenarios. It automatically receives and processes notifications by connecting to signal emitters.

    -

    You can think of it as a central hub where all your notifications are collected and accessible in a consistent way. To prevent unnecessary subscriptions, it uses a "singleshot" mechanism that ensures you only subscribe once.

    -

    The enable property lets you activate notification tracking, and disable lets you stop it safely, even if called repeatedly. getData allows you to retrieve all notifications, specifying whether you want backtest or live data, while dispose provides a way to clear out the stored notifications.

    -

    This component, called MemoryLiveAdapter, provides a flexible way to store and manage data during live trading. Think of it as a central memory bank for your trading strategies. It’s designed to be easily swapped out with different storage methods, letting you choose how your data is saved and accessed.

    -

    By default, it saves your data to files, ensuring that your memory persists even if your program restarts. However, you can also choose to store data only in memory for faster access or use a dummy adapter for testing purposes.

    -

    You can interact with this adapter using functions to write new data, search for existing data, list all entries, remove entries, and retrieve specific entries. It also offers convenient commands to quickly switch between different storage methods. If you're canceling a signal, there's a specific function to clear the memoized data related to that signal. When dealing with scenarios where the base directory of your process changes, clearing the memoized cache is helpful to ensure fresh instances are created.

    -

    The MemoryBacktestAdapter provides a flexible way to manage memory storage during backtesting. It allows you to easily switch between different storage implementations, like an in-memory solution, a persistent file-based storage, or even a dummy adapter for testing.

    -

    The default storage is in-memory, providing fast access but without persistence. You can switch to a file-based storage to save your memory data or use a dummy adapter if you just want to test the core logic without actually writing anything to memory.

    -

    You can also plug in your own custom storage implementations.

    -

    When you're finished with a specific signal, use the disposeSignal method to clean up any resources associated with it. You have methods to write, search, list, remove and read memory entries.

    -

    If your working directory changes during strategy iterations, be sure to clear the cache using clear to ensure new instances are created using the updated base path.

    -

    The MemoryAdapter acts as a central hub for managing memory storage within the backtest and live trading environments. It handles subscriptions to signal lifecycle events, automatically cleaning up old data when signals are closed to prevent memory buildup. This adapter intelligently directs memory operations – writing, searching, listing, removing, and reading – to either the backtest or live environment, depending on the specific request. A key feature ensures subscriptions happen only once, preventing unnecessary overhead. The enable property activates this memory management, while disable safely stops it, and you can call disable multiple times without issues.

    -

    This class helps you understand and analyze the maximum drawdown experienced during trading. It's like a tool to review how much your strategy lost from its peak before hitting a new low.

    -

    You can request detailed statistical data about a specific trading setup, including the strategy, exchange, and timeframe. This data provides a comprehensive view of the drawdown performance.

    -

    Need to see the drawdown events laid out clearly? You can generate a markdown report that lists each event.

    -

    Finally, you can automate the process by having these reports saved directly to a file, simplifying your analysis workflow.

    -

    This service keeps track of maximum drawdown events during backtesting and saves that data for later analysis. It listens for updates about drawdown changes and records each one to a database in a format suitable for reporting and analytics.

    -

    The service is initialized with a logger and a tick object, and it's designed to handle individual drawdown records, capturing key details about the situation at the time of the event. These details include timestamps, symbol, strategy name, exchange, frame, the signal ID, position size, current price, and order parameters like take profit and stop loss.

    -

    To start tracking drawdown events, you need to subscribe to the service. This sets up the connection to receive those updates. The subscription also gives you a function to unsubscribe, which is important for cleaning up when you no longer need the service. Unsubscribing effectively stops the recording of drawdown events. The subscription mechanism prevents accidentally setting up multiple listeners.

    -

    This service is designed to automatically create and store reports about maximum drawdown, a key risk metric in trading. It listens for drawdown data and organizes it by symbol, strategy, exchange, and timeframe.

    -

    You need to tell it to start listening for data using subscribe() and can stop it with unsubscribe().

    -

    The service provides several handy methods: getData() lets you retrieve the raw drawdown statistics, getReport() generates a nicely formatted markdown report, and dump() saves that report directly to a file.

    -

    The clear() method is useful for resetting the data. It can either clear all accumulated data or selectively clear data for a specific symbol, strategy, exchange, and timeframe combination.

    -

    This component manages how your backtest results are saved, offering different ways to store the information. It allows you to easily switch between writing reports to individual files, appending them to a single log file, or even disabling markdown output altogether. The system remembers which storage method is active and reuses it, ensuring that data for a specific report type (like backtest or live trading) is consistently handled.

    -

    You can customize how markdown files are created by swapping out the default storage adapter.

    -

    The useMd() function provides the standard approach of creating a separate Markdown file for each report. useJsonl() gathers all your reports into a single, continuously updated JSONL file. useDummy() is handy for temporarily silencing the markdown output during development or debugging. Finally, you can clear the system’s memory of previously used storage methods if your working directory changes.

    -

    MarkdownUtils helps you control which parts of the backtest-kit framework generate markdown reports. You can choose to have reports made for backtests, live trading, strategy performance, and more.

    -

    It's designed to be extended by other classes for even more specialized reporting.

    -

    The enable method lets you turn on markdown reports for specific services, and it's really important to remember to unsubscribe from those services when you're done to avoid issues.

    -

    disable stops report generation for services without needing to unsubscribe – it just cuts off the reporting immediately.

    -

    Finally, clear lets you wipe the data used for reports without completely stopping the report generation process. This allows you to reset reports while keeping the underlying services running.

    -

    This adapter provides a straightforward way to generate backtest reports, creating each report as a separate markdown file within a defined directory structure. Think of it as ideal for keeping your reports organized and easily accessible for human review.

    -

    Each report gets its own .md file, named based on your specified path and file name, for example, ./dump/backtest/BTCUSDT_my-strategy_binance_2024-Q1_backtest-1736601234567.md.

    -

    It handles the creation of necessary directories automatically, so you don't have to worry about setting up the folder structure. Because it writes files directly, there’s no need for complex initialization, making it a simple and reliable solution.

    -

    The constructor simply takes a key related to the target of the markdown, and the dump method is your main tool for creating the report files, writing the content and establishing the file's location.

    -

    The MarkdownFileBase class helps you automatically generate and store markdown reports as JSONL files. Think of it as a tool for consistently logging your trading reports in a structured format. It creates a single JSONL file for each type of report you need (like trade summaries or performance analysis).

    -

    The system handles the details of writing to these files, including creating the necessary directories, managing the writing process to avoid overwhelming the system, and ensuring things don't hang for too long. You can search these reports later by filtering based on criteria like the trading symbol, strategy used, or the timeframe.

    -

    Essentially, this class allows for centralized logging and simplifies post-processing of trading data using standard JSONL tools. The initialization happens only once, and you can safely call the dump method to append new markdown content along with helpful metadata to the files.

    -

    The MarkdownAdapter helps manage how your markdown data is stored, offering flexibility and efficiency. It allows you to easily switch between different storage methods like individual files or a single JSONL file.

    -

    You can customize the adapter's behavior by providing your own storage constructor, ensuring all new markdown instances use your preferred method.

    -

    For convenience, the useMd() method reverts to the default folder-based storage, where each dump creates a new markdown file. useJsonl() switches to the alternative JSONL-based storage, which appends data to a single file. There’s even a useDummy() option that essentially does nothing with the data, useful for testing or situations where you don’t need to persist anything.

    -

    The adapter also remembers the storage instances, so you don't have to recreate them repeatedly, making things faster and more resource-friendly. It only initializes the storage when you first write data.

    -

    The LookupUtils class acts like a central record keeper for what's currently happening in your backtests and live trading sessions. Whenever a backtest or live session starts (like when you run Backtest.run or Live.run), or when a strategy's steps are being executed, an entry is added to this registry. Similarly, when these activities finish, the entry is removed.

    -

    Think of it as a constantly updated list of what's running.

    -

    The addActivity method adds a new activity, and removeActivity cleans up when an activity is done. Importantly, removeActivity should be used even if errors occur during the activity to prevent lingering entries. listActivity gives you a current view of all the activities that are currently running. This class is accessed through the Lookup singleton and doesn’t require any special setup.

    -

    The LoggerService helps standardize logging across the backtest-kit framework. It's designed to automatically add important context to your log messages, like which trading strategy, exchange, or frame is generating the log.

    -

    This means you don't have to manually add these details every time you want to log something.

    -

    If you don't configure a specific logger, it defaults to a "no-op" logger that doesn't actually do anything, so it won’t interfere with your existing setup.

    -

    You can customize the logging behavior by providing your own logger implementation using the setLogger method.

    -

    The service also manages information about the method context (like the strategy name) and the execution context (symbol, timestamp, backtest status), appending this to each log message for increased clarity and traceability.

    -

    The LogAdapter provides a flexible way to manage and store your trading logs. It allows you to easily switch between different logging methods, like storing logs in memory, persisting them to disk, or even suppressing them entirely. Think of it as a central hub for all your log messages, providing different ways to handle them based on your needs.

    -

    You can choose between different log implementations – the default is in-memory, but there are options for persistent storage, a dummy (no-op) logger, and JSONL file logging. usePersist, useMemory, useDummy, and useJsonl let you easily switch between these logging strategies.

    -

    The log, debug, info, warn, and getList methods provide a consistent interface for writing different types of log messages, regardless of the underlying storage mechanism. The clear function ensures you're using the freshest adapter if your working directory changes during backtesting. The useLogger function allows you to customize the logger entirely using a constructor.

    -

    The LiveUtils class provides tools for running and managing live trading operations within the backtest-kit framework. It acts as a central point for interacting with live trading, simplifying processes and providing features like crash recovery and real-time monitoring.

    +

    First, you need to tell the service to start listening for events by calling subscribe(). Then, as your strategy executes, different actions (like partial profit taking or trailing stops) will automatically trigger entries in this logbook.

    +

    You can then ask for summaries or full reports using getData() or getReport(). getReport() lets you customize what details appear in the report. You can also save the reports directly to files with dump().

    +

    Finally, when you're done, unsubscribe() stops the collection and clears everything, like closing the logbook.

    +

    This service also keeps track of statistics like how many times you took partial profits, allowing you to analyze your strategies in detail. The getStorage property handles managing where these temporary logs are kept, creating new storage areas for each unique combination of symbol, strategy, and exchange.

    +

    The StrategyCoreService acts as a central hub for managing trading strategies within the backtest framework. It provides a way to interact with strategies while ensuring data like the trading symbol, time, and backtest parameters are correctly passed along. Think of it as a middleman that simplifies how strategies are executed and monitored.

    +

    It has several key functions:

    +
      +
    • Retrieving Signals & Data: You can use it to get the current pending signal, the percentage of the position that's been closed, its cost basis, and other relevant details about a trade.
    • +
    • Managing Strategy State: It allows you to check if a strategy is stopped, activate scheduled signals early, or even close pending positions without stopping the entire strategy.
    • +
    • Running Backtests & Simulations: The service facilitates executing strategies against historical data, and quickly validating configurations.
    • +
    • Validation and Caching: The validate method ensures strategies and their configurations are correct, using a caching mechanism to avoid repetitive checks.
    • +
    • Monitoring & Performance: Functions for retrieving information like the time elapsed since peak profit or the maximum drawdown can be used to monitor how a strategy is performing.
    • +
    +

    The service relies on other components like StrategyConnectionService and ExecutionContextService to handle the complexities of connecting to the trading platform and managing execution context. It's the core engine for a lot of the backtest framework's functionality.

    +

    This framework manages strategy execution and provides access to key data and functionalities. It intelligently routes strategy operations to the correct implementation based on the symbol, exchange, and frame.

    +

    The service caches strategy instances for efficiency and ensures initialization before any operations are performed. It handles both live trading (ticks) and historical analysis (backtests).

    +

    You can retrieve data like pending signals, total closed position percentage, cost, effective price, entry details, partials and scheduled signals. It also provides methods to manage positions, such as closing pending signals, adjusting stop-loss/take-profit, and adding DCA entries. The framework allows you to check the status of a strategy, validate actions before execution, and clear cached data when needed. Overall, this component acts as a central hub for orchestrating and managing trading strategies within the system.

    +

    The StorageLiveAdapter provides a flexible way to manage how your trading signals are stored, allowing you to easily swap out different storage methods without changing your core trading logic. It acts as a middleman, letting you choose between persistent storage (saving to disk), in-memory storage (data lost when the application restarts), or a dummy adapter for testing.

    +

    The adapter keeps track of a storage utility instance, creating it only when needed and remembering it for future use – this helps improve performance.

    +

    You can easily switch storage types using methods like useDummy, usePersist, and useMemory. If you need to change the underlying storage implementation entirely, use useStorageAdapter.

    +

    The adapter also handles various events related to signals like opening, closing, scheduling, and cancellation, passing these events to the currently selected storage method. It provides handy functions to find signals by ID and list all signals. Remember to call clear() when the base path changes to ensure a fresh storage instance is created.

    +

    The StorageBacktestAdapter provides a flexible way to manage how your backtest data is stored. It allows you to easily switch between different storage methods, such as persistent storage on disk, in-memory storage, or even a dummy storage that doesn't actually save anything.

    +

    You can choose a default storage method or customize it by selecting one of the available adapters. The usePersist(), useMemory(), and useDummy() methods let you quickly change storage implementations.

    +

    The adapter handles various events like signals opening, closing, scheduling, and cancellations, passing these actions onto the selected storage. It also offers methods to find signals by their ID and list all stored signals. The clear() method ensures that a fresh storage instance is used when the working directory changes, preventing potential issues across different strategy runs.

    +

    The StorageAdapter acts as the central hub for managing your trading signals, whether they're from backtesting or live trading. It automatically keeps track of new signals as they arrive.

    +

    It's designed to make it easy to access and work with both backtest and live signals in a consistent way.

    +

    To start using the storage, you enable it, and it will subscribe to the signal emitters. You can safely disable the storage multiple times if needed to unsubscribe.

    +

    Need to find a specific signal? You can search for it by its ID.

    +

    Want a complete list? There are functions to list all backtest signals and all live signals separately.

    +

    The StateLiveAdapter helps manage and track the state of your trading signals, allowing you to swap out different storage methods easily. It's designed to be flexible, letting you use file-based storage (the default), in-memory storage, or even a dummy adapter that simply ignores changes – which is useful for testing.

    +

    The adapter is particularly useful for implementing automated trading rules, like those driven by large language models, where you want to monitor how trades perform over time and automatically exit those that aren't meeting expectations. It keeps track of things like peak profit and how long a trade has been open, persisting this data even if your application restarts.

    +

    When a signal is finished or closed, you need to disposeSignal to clean up the memoized data. You can also clear the entire cache with clear, which is handy if your application's working directory changes.

    +

    If you need a different way to store your state, you can also use useStateAdapter to bring in a custom storage solution. Finally, useLocal, usePersist, and useDummy allow you to quickly change how the state is stored – in memory, to a file, or discarded completely, respectively.

    +

    The StateBacktestAdapter helps manage and store information about your trading strategies during backtesting. It acts as a flexible layer, allowing you to easily change how and where this data is stored—whether that’s in memory, on disk, or even in a dummy adapter for testing purposes.

    +

    Think of it as a central place to track key metrics for each signal, like the highest peak reached and how long a position has been open. This is particularly useful for complex rules, such as automatically exiting a trade if it doesn’t perform as expected after a certain time or if it hasn't reached a certain profit level.

    +

    You can easily switch between different storage methods: the default in-memory option, a persistent disk-based solution, or a dummy adapter for testing without saving data. The disposeSignal method allows you to clean up old data when a signal is finished. The clear function is helpful when the base directory for your project changes during multiple backtesting runs.

    +

    The StateAdapter is the central piece for managing how your backtest and live trading systems store and access data. It automatically handles cleaning up old data when a trading signal is finished, ensuring you don't end up with unnecessary clutter.

    +

    You can think of it as a traffic controller, directing data requests to either the backtest storage or the live trading environment based on whether you're in a testing or production scenario.

    +

    There's an enable function that activates this storage management, and disable to deactivate it – it's perfectly safe to call disable multiple times. You use getState to retrieve data and setState to update it; both functions will intelligently send the request to the right place. The enable function is a bit special because it only runs once to keep things efficient.

    +

    This service helps you keep track of and confirm your position sizing strategies. Think of it as a central place to register your sizing methods, like fixed percentage or Kelly Criterion, and make sure they're available when you need them.

    +

    It provides a way to add new sizing strategies to a registry, ensuring they're properly registered before use.

    +

    You can use it to check if a sizing strategy exists before applying it, and the service remembers these checks to speed things up.

    +

    If you need to see all the sizing strategies you've registered, you can request a list of them. This helps prevent errors and keeps your sizing configuration organized.

    +

    The SizingSchemaService helps you keep track of different sizing strategies you're using in your trading system. It acts like a central repository where you store and retrieve these strategies.

    +

    It uses a special system to ensure that the sizing strategies you register are structured correctly, checking for essential properties and data types.

    +

    You can add new sizing strategies using the register method, and if you need to make changes to an existing one, override lets you update specific parts. To use a sizing strategy, simply request it by name with the get method, and it will be returned for use. The service also has internal components for logging and validation, helping to ensure smooth operation.

    +

    The SizingGlobalService helps determine how much of an asset to trade, acting as a central point for size calculations within the backtest-kit framework. It relies on other services – a connection service to handle the actual sizing logic and a validation service to ensure sizing requests are valid. Think of it as the brains behind deciding how much to buy or sell, using information about risk and trading context.

    +

    It’s designed for internal use by strategies and the public API.

    +

    Here's a breakdown of its key components:

    +
      +
    • It uses a loggerService for logging information.
    • +
    • It has a sizingConnectionService which is responsible for performing the calculations.
    • +
    • A sizingValidationService makes sure the sizing requests are correct.
    • +
    • The calculate method is the core function, taking sizing parameters and context and returning the calculated position size. It's how you get the actual sizing amount.
    • +
    +

    This service helps manage how your trading strategies determine the size of positions. It acts as a central hub, directing sizing calculations to the correct sizing implementation based on a name you provide.

    +

    To improve performance, it remembers previously used sizing implementations, avoiding redundant setup.

    +

    Think of it as a smart router for sizing requests, ensuring the right method is used for each strategy and caching results to speed things up.

    +

    It allows for flexible sizing methods, supporting techniques like fixed percentages, Kelly Criterion, and ATR-based sizing.

    +

    The service relies on configuration schemas and logging services to function effectively.

    +

    When a strategy doesn't have specific sizing configuration, an empty string is used as the sizing name.

    +

    This component provides a flexible way to manage and store session data during live trading. Think of it as a central place to hold information that changes as your trading strategy runs, like order history or account balances.

    +

    It’s designed to be easily swapped out with different storage methods – you can use a file-based system for persistence, an in-memory solution for speed, or even a dummy adapter to just discard data. The default is to store data in files, meaning your progress will be saved even if the application restarts.

    +

    You can quickly change how the session data is stored using methods like useLocal, usePersist, and useDummy. There's also a way to plug in your own custom storage solution using useSessionAdapter if you have specific needs. The system automatically handles caching these session instances to avoid unnecessary creation, but you can clear this cache with clear if the working directory changes. Retrieving and updating session data is done through the getData and setData functions, respectively, allowing you to access and modify the live trading context.

    +

    The SessionBacktestAdapter helps manage and store data during backtesting runs, allowing for flexibility in how that data is handled. It acts as a bridge, or adapter, between your backtest code and different storage solutions.

    +

    Initially, it uses an in-memory storage – meaning all data exists only in the computer’s memory, and is lost when the program ends – but you can easily switch to other storage methods.

    +

    You can choose to persist your data to files on your hard drive for later retrieval, use a dummy adapter that simply throws away any changes, or even create your own custom adapter.

    +

    The adapter cleverly remembers these configurations, avoiding unnecessary re-initialization.

    +

    To get data from a backtest run, you can use getData, specifying the asset, context (strategy, exchange, frame), and the timestamp. Similarly, setData lets you update values during a backtest.

    +

    If the underlying file system or working directory changes, clear provides a way to refresh the adapter's internal state to ensure data is properly loaded.

    +

    The SessionAdapter acts as a central hub for handling data within your trading sessions, whether you're running a backtest or a live trading environment.

    +

    It intelligently directs data retrieval and storage requests to the appropriate system – either the backtest-specific storage or the live trading storage – based on whether you're in backtest mode.

    +

    You can use getData to retrieve existing session values, specifying the symbol, context details (like strategy and exchange names), a backtest flag to indicate the environment, and a timestamp.

    +

    Similarly, setData lets you update those session values, again routing the update to the correct storage depending on the backtest flag and providing the necessary context and timestamp information. Essentially, it simplifies working with session data by abstracting away the differences between backtesting and live trading.

    +

    The ScheduleUtils class helps you keep track of and report on scheduled trading signals. Think of it as a central place to monitor how signals are being processed and identify potential bottlenecks.

    +

    It lets you gather data about signals waiting to be executed, signals that were cancelled, and calculate metrics like cancellation rates and average wait times.

    +

    This class also provides a way to generate clear, readable markdown reports summarizing all these events for a specific trading strategy and symbol.

    +

    You can easily get statistical data for a particular strategy, create reports with customizable columns, or even save those reports directly to a file on your system. It’s designed to be simple to use, providing a single, convenient point of access for all these functions.

    +

    The ScheduleReportService helps you keep track of how your scheduled signals are performing by recording their lifecycle events. It listens for signals and logs key moments like when a signal is scheduled, when it starts, and when it's canceled. This service calculates how long it takes from the initial scheduling to when the signal actually executes or is canceled, giving you insight into potential delays.

    +

    The service uses a logger to provide debugging information and relies on a "tick" processor for handling signal events.

    +

    You can subscribe to the service to receive these signal events; the subscription is designed to prevent you from accidentally subscribing multiple times. When you're done, you can unsubscribe to stop receiving events.

    +

    The ScheduleMarkdownService helps you track and understand scheduled trading signals by automatically generating reports. It monitors scheduled and cancelled signal events, keeping a record of each one for every strategy you're using.

    +

    These records are then compiled into easy-to-read markdown tables, providing a detailed history of signal activity. The service also calculates useful statistics like cancellation rates and average wait times to give you deeper insights into your trading strategies.

    +

    You can easily generate and save these reports to disk, organizing them by strategy for quick access. The system uses a unique storage area for each combination of symbol, strategy, exchange, frame, and backtest to ensure data isolation.

    +

    You have the option to subscribe to signal events, unsubscribe, clear existing data, retrieve statistics, or generate a report – all of which provide different levels of insight into your scheduled signal performance. You can also customize which columns are displayed in the reports.

    +

    This service helps you keep track of and verify your risk management configurations. It acts as a central place to register different risk profiles, making sure they exist before you try to use them in your trading strategies. To improve speed, it remembers the results of previous validations, so you don't have to repeat checks unnecessarily.

    +

    You can use it to register new risk profiles, validate whether a specific profile exists, and get a full list of all profiles you've registered. Essentially, it provides a way to organize and double-check your risk management setup. It stores all registered risk profiles, validates whether a risk profile exists, and caches results for efficiency.

    +

    This class offers tools for examining and reporting on risk rejections within your trading system. Think of it as a way to easily analyze why trades were rejected, helping you fine-tune your strategies and improve overall risk management.

    +

    It collects data about rejections – things like the symbol involved, the strategy used, the position size, and the reason for rejection.

    +

    You can use it to get statistical summaries of these rejections, which will give you a high-level view of problem areas.

    +

    It can also generate detailed markdown reports that list each rejection event with key information, allowing you to dig into specifics. Finally, you can save these reports directly to files for later review or sharing. The reports are organized by symbol and strategy, so you can focus on particular areas of concern.

    +

    The RiskSchemaService helps you organize and manage your risk schemas, acting like a central hub for defining and accessing them. It uses a special system for storing schemas in a type-safe way, ensuring consistency and reducing errors.

    +

    You add new risk profiles using the addRisk() method (referred to as register in the code), and you can later retrieve them using their names with the get() method.

    +

    Before a new risk schema is added, it's checked with validateShallow() to make sure it has all the necessary parts and is structured correctly.

    +

    If a risk schema already exists, you can update parts of it using the override() method – this allows you to make changes without completely redefining the entire schema. The loggerService property gives access to logging and context information for debugging and monitoring.

    +

    This service, RiskReportService, keeps a record of when risk checks reject trading signals. Think of it as a logbook for those situations.

    +

    It actively listens for these rejections, capturing the reason why a signal was rejected and the details of the signal itself.

    +

    This information is then stored in a database, allowing you to analyze trends, understand the reasons for rejections, and perform audits.

    +

    To get it working, you subscribe to the rejection events, and when you're done, you unsubscribe to stop listening. This helps prevent accidental duplicate subscriptions. The service uses a logger to display debugging messages.

    +

    This service helps you create and store reports about rejected trades due to risk management rules. It listens for events indicating a trade was rejected and organizes them.

    +

    It keeps track of rejections for each symbol and trading strategy you're using. Then, it generates easy-to-read markdown reports that detail the rejection information.

    +

    You'll also get summary statistics, like the total number of rejections and how they're distributed across different symbols and strategies. These reports are saved as files on your computer.

    +

    You can subscribe to receive these rejection events, and the service makes it simple to get statistical data, generate reports, and save them to disk. The service also provides a way to clear out the stored data when it's no longer needed, either all at once or for a specific trading setup.

    +

    RiskGlobalService is a central component that handles risk management within the trading framework. It acts as a gatekeeper, ensuring that trading signals comply with established risk limits before they are executed.

    +

    It utilizes a connection service for risk limit validation and incorporates several services for different aspects of validation, including exchange, frame, and overall risk assessment.

    +

    The validate method helps ensure the risk configuration is correct and avoids unnecessary checks by remembering previous validations.

    +

    The core functions include checkSignal, which simply verifies if a trade is allowed based on risk rules, and checkSignalAndReserve, a more robust version that guarantees concurrency safety when validating and reserving resources. This prevents multiple strategies from simultaneously exceeding limits.

    +

    To complete a trade, addSignal registers the signal with the risk management system, while removeSignal cleans up when a trade is closed. Finally, clear provides a way to wipe out the risk data, either completely or for a specific risk configuration.

    +

    This service acts as a central hub for managing risk checks within your trading system. It intelligently directs requests to the correct risk management component based on the specific risk configuration you've defined.

    +

    Think of it as a router that makes sure the right risk rules are applied to each trading decision. It also remembers which risk rules it's used before, improving performance by avoiding repeated calculations.

    +

    Here’s a breakdown of what it does:

    +
      +
    • Routes Risk Checks: It determines which risk implementation to use based on a risk name, exchange, frame, and backtest mode.
    • +
    • Memoizes Risk Instances: It keeps a record of frequently used risk configurations, so it doesn't have to recreate them every time you need them. This speeds things up considerably.
    • +
    • Provides Methods for Key Actions: It provides functions for checking if a signal is valid, reserving resources for a signal, adding a new signal, removing a closed signal, and clearing cached risk configurations.
    • +
    • Concurrency Safe: The checkSignalAndReserve method is designed to handle situations where multiple processes might be checking a signal at the same time, ensuring data integrity.
    • +
    +

    The service relies on other components, like a risk schema service and time meta service, to function correctly, receiving them through dependency injection.

    +

    This framework provides a flexible way to store and manage data generated during trading simulations and live trading. It uses an adapter pattern, allowing you to easily swap out different storage methods without changing the core logic. The system intelligently keeps track of storage instances, ensuring only one instance of each type is used throughout the application's lifetime, which helps with efficiency.

    +

    The ReportFactory lets you define how reports are created, defaulting to a JSONL storage method. getReportStorage keeps a record of these created instances.

    +

    You can use writeData to write data to the chosen storage, and the system will automatically set up the storage the first time it's used.

    +

    You have control over the storage method using useReportAdapter to specify a different creation method or to switch to a dummy adapter which just discards the data – useful for testing. useJsonl reverts to the standard JSONL method, and clear will remove any cached storage instances, which is helpful when the working directory changes.

    +

    ReportUtils helps you control which parts of the backtest-kit framework generate detailed logs. You can turn on logging for specific areas like backtesting, live trading, or performance analysis.

    +

    It provides a way to selectively start or stop these logs, creating JSONL files that record events in real-time with helpful information. Think of it as a central switchboard for your data collection.

    +

    When you enable logging for a service, it starts listening for events and writing them to files. Be sure to use the provided unsubscribe function when you're done, because this prevents memory issues.

    +

    Disabling a service, on the other hand, immediately halts the logging process for that area without needing a separate unsubscribe step.

    +

    The ReportBase class is designed to efficiently log trading events to files in a standardized JSONL format. It’s particularly useful for keeping track of events during backtesting and for later analysis.

    +

    Each report type gets its own file, and data is written as individual lines, each representing a single event with associated metadata like the trading symbol, strategy, exchange, timeframe, and signal identifier. The system is built to handle large volumes of data with backpressure and includes safeguards to prevent write operations from hanging indefinitely.

    +

    It automatically creates the necessary directories and handles errors gracefully. The waitForInit method ensures the file and stream are properly set up, and the write method is how you actually log the events. You can safely call waitForInit multiple times without issues.

    +

    The ReportAdapter is designed to help you collect and manage data during backtesting, making it easy to switch between different ways of storing that information. Think of it as a central point for handling report data, allowing you to plug in different storage solutions as needed.

    +

    It uses a clever system to avoid creating unnecessary storage instances, remembering which type of storage you're using. By default, it saves data in JSONL format, but you can easily change this if you need to.

    +

    You can even temporarily disable data storage with a "dummy" adapter for testing purposes, ensuring no data is actually written. If your project's working directory changes, clearing the adapter's cache becomes important to ensure it's using the correct storage location.

    +

    This utility class, ReflectUtils, provides a central place to get key performance metrics for your trading positions during backtests or live trading. Think of it as a reporting hub, giving you access to things like unrealized profit/loss (both percentage and dollar amounts), peak profit levels, and drawdown information.

    +

    It's designed to simplify retrieving this data, ensuring consistency and including validation for various aspects like strategy and exchange. It's a singleton, meaning you'll use the same instance throughout your application.

    Here's a breakdown of what it offers:

      -
    • Easy Live Trading Execution: The run method is your primary way to kick off live trading, handling the complexities of connecting to the exchange and processing ticks. It’s designed to be persistent, meaning it will attempt to recover if the process crashes.
    • -
    • Background Operation: If you just want to run live trading for side effects (like sending notifications or saving data), the background method lets you do so without processing or displaying the individual ticks.
    • -
    • Signal Management: Several methods let you peek at what signals the strategy is currently working with, like getPendingSignal (the active signal) or getScheduledSignal (the signal waiting to be triggered). You can also check if signals are missing with hasNoPendingSignal and hasNoScheduledSignal.
    • -
    • Position Insights: Get detailed information about your current open position, including the percentage held (getTotalPercentClosed), cost basis (getTotalCostClosed), and profit/loss calculations (getPositionPnlCost, getPositionPnlPercent). You can also see the history of price entries (getPositionEntries) and partial closes (getPositionPartials).
    • -
    • Control and Adjustment: You can adjust the strategy's behavior with stop (to pause trading), commitCancelScheduled (to cancel a scheduled signal), and commitClosePending (to close the current position).
    • -
    • Trailing Stop/Take Profit: Fine-tune your positions with trailing stop-loss and take-profit orders using methods like commitTrailingStop and commitTrailingTake, ensuring your gains are protected and profits are maximized.
    • -
    • Data & Reporting: Access real-time data about the running strategy with getStrategyStatus, and generate comprehensive reports with getReport and dump. getData provides a way to gather statistics.
    • -
    -

    In essence, LiveUtils gives you the necessary tools to run, monitor, and manage your live trading strategies in a robust and reliable manner.

    -

    LiveReportService helps you track what your trading strategy is doing in real-time by recording every signal event—like when it's waiting, opening a position, actively trading, or closing a position.

    -

    It works by listening for these events and saving all the details to a database, so you can monitor and analyze your strategy’s performance as it’s happening.

    -

    You can think of it as a real-time data logger specifically for your trading strategy.

    -

    To get started, you’ll use the subscribe function to connect it to your signal events. This ensures you don't accidentally subscribe more than once. When you’re finished, unsubscribe cleanly stops the data logging.

    -

    The service also uses a logger for any helpful debugging information.

    -

    The LiveMarkdownService helps you automatically generate and save reports about your live trading activity. It keeps track of all the important events – like when a strategy is idle, when a trade is opened or closed, and everything in between – for each strategy you're running.

    -

    It turns this data into easy-to-read markdown tables, providing insights into your trading performance, like win rates and average profit/loss. These reports are then saved to your computer in a structured way, making it simple to review your trading history.

    -

    You can subscribe to receive live updates as trades happen, and the service safely handles unsubscribing when you no longer need those updates. It allows you to retrieve specific data or full reports for individual strategies, and even clear the recorded data when needed. The service organizes data by symbol, strategy, exchange, frame, and whether it’s a backtest, ensuring that everything is neatly separated.

    -

    The LiveLogicPublicService is designed to manage and orchestrate live trading, making it easier to work with. It builds upon the LiveLogicPrivateService and includes automatic context management, so you don't have to constantly pass around information about the strategy and exchange being used.

    -

    It acts as an infinite stream of trading results (signals to open, close, or cancel positions).

    -

    This service is robust, designed to handle crashes and recover from previous states saved on disk. Real-time progression is achieved by using the current time to track events.

    -

    The run method is the core of the service, initiating live trading for a specific symbol. It automatically injects the necessary context, streamlining the process of getting candles, signals, and executing other trading-related actions.

    -

    This service manages live trading operations, constantly monitoring and reacting to market data. It operates as an ongoing process, checking for new trading signals at regular intervals.

    -

    The core function, run, acts like an endless stream of trading activity, providing real-time updates on trades that have been opened or closed – it skips over trades that are currently active.

    -

    Because this is a continuous process, the system is designed to handle unexpected crashes; it recovers its state from saved data, ensuring trading can resume seamlessly. This approach also uses memory efficiently by streaming results rather than storing everything at once.

    -

    This service, LiveCommandService, acts as a central point for live trading operations. It simplifies accessing and managing the underlying live trading logic.

    -

    Think of it as a helper that makes it easy to inject dependencies needed for live trading.

    -

    It uses several validation services - for strategies, exchanges, schemas, risk, and actions - to ensure everything is set up correctly before trading begins. The validation process is optimized to prevent unnecessary repeated checks.

    -

    The core function, run, handles the actual live trading process for a specific trading symbol. It keeps things running even if errors occur and provides results as an ongoing stream of information about how the strategy is performing (whether it's opened, closed, or cancelled).

    -

    IntervalUtils helps you control how often functions are executed within a specific time interval, preventing them from running too frequently. It offers two ways to manage this: a simple in-memory approach and a more robust, file-based persistent method.

    -

    The fn function lets you wrap regular functions to ensure they only run once per interval. If a function returns null, it will wait for the next interval before attempting to run again. Each unique function gets its own separate management, so modifications to one don't affect others.

    -

    For asynchronous functions, the file function provides similar control but saves the "fired" state to a file. This means the function will still only fire once per interval even if your application restarts. Each unique function also gets its own persistent instance here too.

    -

    You can clean up unused functions with dispose to free up memory, or completely reset the system with clear when necessary, like when the working directory changes. The resetCounter helps ensure new files are created with the correct starting index if the working directory changes. It essentially acts as a cleanup to avoid conflicts between strategy runs.

    -

    This class helps you understand and analyze the highest profits achieved during trading. It acts as a central place to gather and present information about those peak performance moments.

    -

    Think of it as a tool for reviewing how well your strategies have performed – specifically, when they've made the most money.

    -

    You can use this class to:

    -
      -
    • Get detailed statistics about the highest profit events for a specific trading pair (like BTC/USD) and strategy.
    • -
    • Generate reports that summarize all the highest profit occurrences in a readable markdown format.
    • -
    • Save those reports directly to a file so you can share them or keep a record of your results.
    • -
    -

    It's designed to work with data collected by other parts of the backtest-kit system, providing a focused view on the moments of greatest success.

    -

    This service is designed to track and record the highest profit moments during a backtest. It monitors a specific data stream, highestProfitSubject, and whenever a new record of highest profit is detected, it writes that information to a JSONL database for later analysis.

    -

    The service utilizes a ReportWriter to handle the actual persistence of the data.

    -

    Each record includes details like the timestamp, symbol, strategy name, exchange, frame, and backtest information, along with signal-specific data such as signal ID, position, current price, and take profit/stop-loss levels. Importantly, signal-level details come directly from the signal data itself.

    -

    To begin recording these high-profit events, you need to use the subscribe method. This only runs the subscription once, preventing multiple subscriptions. The subscribe method returns a function which you’ll call to stop the recording. If you need to stop recording, call the unsubscribe method.

    -

    This service helps you create reports detailing the highest profit achieved for a specific trading setup. It listens for data about profitable trades and organizes that information.

    -

    You can subscribe to receive these profit events, but the system ensures you only subscribe once to avoid unnecessary actions. Unsubscribing completely clears all the collected data.

    -

    Each time a new profit event comes in, the service processes it and stores it.

    -

    You can then request data, generate a formatted report, or even save the report directly to a file. The filename for saved reports includes details like the symbol, strategy, exchange, and whether it was a backtest.

    -

    Finally, there's a way to clear the stored data, either for a specific trading setup or all of them at once, giving you a fresh start.

    -

    HeatUtils helps you easily visualize and analyze the performance of your trading strategies using heatmaps. It gathers key statistics like total profit, Sharpe ratio, maximum drawdown, and trade counts for each symbol used by a strategy.

    -

    It's designed to be straightforward to use, aggregating data automatically from all completed trades for a specific strategy across an exchange and timeframe.

    -

    You can retrieve the raw data, generate a formatted markdown report, or save the report directly to a file on your computer. The report will present your results in a table sorted by profitability, offering a clear overview of how your strategy performed across different assets. The utility provides logging for tracing operations, and it’s set up as a single, readily accessible instance.

    -

    HeatReportService helps you track and analyze your trading performance by recording every time a signal closes. It's designed to gather data about closed signals across all your investments to give you a portfolio-wide view.

    -

    The service listens for these closing signals and saves key information, like profit and loss (PNL), to a database for later analysis.

    -

    Here's a quick rundown of how it works:

    -
      -
    • It connects to a central system that broadcasts signal events.
    • -
    • It only focuses on signals that have actually closed – it ignores other types of events.
    • -
    • The data it collects is written to a file that can be used to generate a heatmap visualization.
    • -
    -

    To get started, you'll subscribe to the signal events. This setup prevents accidental duplicate subscriptions, and it gives you a way to stop listening later using the unsubscribe function. If you’ve already unsubscribed, attempting to do so again won’t have any effect.

    -

    This service helps you visualize and analyze your trading performance using heatmaps. It listens for trading signals and organizes them, giving you a clear picture of how your strategies are doing.

    -

    You can get detailed statistics for each individual symbol, like total profit, Sharpe Ratio, and maximum drawdown, as well as aggregated portfolio-level metrics across all your strategies.

    -

    It creates reports in a user-friendly markdown format, allowing for easy sharing and analysis. The system is designed to handle tricky situations gracefully, avoiding errors caused by unusual data.

    -

    The service keeps track of data efficiently, storing it separately for different exchanges, timeframes, and backtest modes. You can subscribe to receive updates, and unsubscribe when you no longer need them. It allows clearing of stored data to reset the heatmap for a specific exchange/timeframe/mode or globally. This ensures that new data is tracked from a clean slate.

    -

    This service helps you keep track of and verify your trading timeframes, also known as "frames." Think of it as a central authority for your timeframe configurations.

    -

    You can use it to register new timeframes with specific settings, ensuring they're properly defined.

    -

    Before you start using a timeframe in your backtesting, you can ask this service to check if it exists, preventing errors and ensuring everything runs smoothly. It remembers its checks, so validation happens quickly.

    -

    Finally, if you just need a quick overview of all the timeframes you've set up, you can ask it to list them all. It's designed to be efficient and reliable for managing your timeframe configurations.

    -

    The FrameSchemaService helps you keep track of your frame schemas in a structured and reliable way. It’s designed to store these schemas safely and consistently using a specialized registry.

    -

    You add new frame schemas using the register method and can retrieve them later by their name using get. If a schema already exists, you can update parts of it using the override method.

    -

    Before a schema is added, a quick check happens (validateShallow) to ensure the essential properties are in place and have the right format, making sure everything is set up correctly from the start. The service also leverages logging services for better insights into what's happening.

    -

    FrameCoreService is a central component that handles the creation and management of timeframes for your backtesting processes. It relies on other services to connect to data sources and validate the resulting data. Think of it as the engine that provides the chronological sequence of data points your trading strategies will be tested against.

    -

    It generates arrays of dates representing the time periods for each backtest run. Specifically, you can ask it to create a timeframe array for a particular trading symbol and timeframe name. This service is a critical internal part of the backtest framework.

    -

    The FrameConnectionService acts as a central hub for managing and accessing different trading frames within the backtest environment. It intelligently directs requests to the correct frame implementation based on the current method context.

    -

    To optimize performance, it keeps a record of frequently used frames, so it doesn't have to recreate them every time.

    -

    This service also handles the timeframe used for backtesting, allowing you to define the start and end dates and the interval (e.g., daily, hourly) for your historical data.

    -

    When in live mode, no specific frame is active, and the frameName will be an empty string.

    -

    Here's a breakdown of its core components:

    -
      -
    • It relies on the loggerService for logging, frameSchemaService for frame definitions, and methodContextService to understand the current frame in use.
    • -
    • The getFrame function is its primary way of providing frames, efficiently retrieving or creating them based on the provided frame name.
    • -
    • The getTimeframe function allows you to determine the date range for testing, limiting the backtest to a specific period and interval.
    • -
    -

    The ExchangeValidationService helps you keep track of and confirm the settings for your trading exchanges. Think of it as a central place to register your exchanges and double-check they’re set up correctly before you start trading. It’s designed to be efficient – once an exchange is validated, the result is stored so you don't have to repeat the check unnecessarily.

    -

    You can use addExchange to add a new exchange, validate to make sure an exchange exists before using it, and list to see all the exchanges you've registered. The service also uses a 'loggerService' and an internal 'exchangeMap' to manage and store this information.

    -

    ExchangeUtils provides a set of helpful functions to interact with different exchanges within the backtest-kit framework. Think of it as a toolbox simplifying common exchange-related tasks.

    -

    It's designed as a single, always-available tool, ensuring consistency across your backtesting environment.

    -

    Need historical price data? The getCandles function retrieves it, automatically calculating the date range based on the interval and how much data you need. Similarly, getAveragePrice helps you determine the VWAP based on recent trading activity.

    -

    You can also get the most recent closing price with getClosePrice or retrieve the complete order book with getOrderBook.

    -

    Formatting trades is often tricky due to varying exchange rules; formatQuantity and formatPrice handle this for you, ensuring your orders are correctly structured.

    -

    Finally, getAggregatedTrades pulls trade history, and getRawCandles offers even more control over retrieving raw candle data with precise date ranges.

    -

    The ExchangeSchemaService helps keep track of information about different exchanges, ensuring everything is consistent and correct.

    -

    It uses a special system to store these exchange details in a type-safe way.

    -

    You can add new exchanges using the addExchange() function (represented here as register) and then find them again later by their name using the get() function.

    -

    Before adding a new exchange, the service will quickly check that it has all the necessary information using validateShallow.

    -

    If you need to update an existing exchange, you can use override to only change specific parts of its details.

    -

    This service also has internal components for logging and managing different contexts, but those are typically handled automatically.

    -

    The ExchangeCoreService acts as a central hub for interacting with exchanges, ensuring that key information like the symbol, time, and backtest settings are always factored into the process. It combines the capabilities of connection and execution services to streamline operations.

    -

    This service handles tasks like fetching historical and future candles, calculating average prices, and retrieving order book data. It also offers utilities for formatting prices and quantities, adapting to the specific context of the operation.

    -

    Validation of exchange configurations is also a core function, performed efficiently through memoization to avoid repeated checks. Essentially, it provides a standardized and context-aware way to access exchange data within the trading framework.

    -

    The ExchangeConnectionService acts as a central hub for interacting with different cryptocurrency exchanges within the backtest-kit framework. It intelligently routes requests to the correct exchange implementation based on the currently configured exchange name. To optimize performance, it keeps a cache of these exchange connections, reusing them whenever possible.

    -

    It provides a consistent interface (IExchange) for accessing exchange data and functionalities like retrieving historical candles (getCandles, getNextCandles), fetching the average price (getAveragePrice), obtaining the order book (getOrderBook), and getting aggregated trades (getAggregatedTrades). It handles nuances like formatting prices and quantities (formatPrice, formatQuantity) to align with each exchange’s specific rules. The service leverages several other services for logging, execution context, and exchange schema, ensuring a controlled and informed operation. You can access the specific exchange instance using getExchange, which also benefits from memoization.

    -

    The DumpAdapter provides a way to save data during your backtesting process, acting as a central point for how that data is stored. It has a default method of saving to markdown files, but you can easily change where the data goes.

    -

    Think of it as a manager that handles the actual saving process, making sure the right data ends up in the right place.

    -

    You’ll need to “activate” the adapter using enable() before you start saving anything, and “deactivate” it with disable() when you’re done. Calling enable() multiple times won't cause problems, it just returns the same subscription handle.

    -

    The adapter has several functions to save different types of data, including full conversation histories (dumpAgentAnswer), individual records (dumpRecord), tables (dumpTable), raw text (dumpText), error messages (dumpError), and JSON objects (dumpJson).

    -

    You can switch the storage method using functions like useMarkdown (the default), useMemory, or useDummy (which throws away the data). For more advanced control, useDumpAdapter lets you provide your own custom storage implementation.

    -

    If you need to change the base path (where files are saved), use clear() to refresh the adapter's internal cache.

    -

    This utility class, CronUtils, helps manage periodic tasks within backtesting environments, especially when running multiple tests in parallel. It ensures that even when multiple tests try to fire a task at the same time, only one actually runs, preventing conflicts.

    -

    Think of it like a traffic controller for scheduled events. When several tests need to perform something at a specific time, CronUtils makes sure only one gets through, and the others wait.

    -

    Here’s a breakdown of its key components:

    -
      -
    • Registration: You register tasks with names and intervals.
    • -
    • Single Execution: Even when multiple tests try to run the same task at the same time, only one will execute, keeping things synchronized.
    • -
    • Synchronization: It uses promises to coordinate execution across parallel tests.
    • -
    • Watermarking: It ensures that if a scheduled event is missed due to a jump in virtual time, it's caught on the next tick.
    • -
    • Cleanup: You can clear out fired-once marks to allow tasks to run again, or completely reset the entire system if needed.
    • -
    • Lifecycle Integration: It easily integrates with the backtesting engine's lifecycle to automatically schedule tasks.
    • -
    -

    Essentially, CronUtils simplifies managing and synchronizing periodic tasks in parallel backtests, preventing conflicts and ensuring accurate results.

    -

    The ConstantUtils class provides a set of predefined percentages designed to manage take-profit and stop-loss levels based on the Kelly Criterion with an exponential decay approach. These constants, like TP_LEVEL1, TP_LEVEL2, TP_LEVEL3, SL_LEVEL1, and SL_LEVEL2, are calculated as percentages of the total distance to your final take-profit or stop-loss target. For example, TP_LEVEL1 at 30% means you'll trigger a partial take-profit when the price reaches 30% of the way to your ultimate profit target. This allows for a gradual exit from a trade, locking in some profits while still allowing for potential further gains, and similarly helps to manage risk with early stop-loss warnings. Essentially, these values help to optimize risk management and profit taking in a trading strategy.

    -

    The ConfigValidationService is designed to make sure your trading configurations are mathematically sound and capable of making a profit. It checks a wide range of settings, from percentage-based values like slippage and fees to time-based parameters like timeouts.

    -

    Specifically, it makes sure your take profit distance is large enough to account for costs like slippage and fees, preventing unprofitable trades. It also ensures that percentage values are positive, time and count values are positive whole numbers, and relationships between minimum and maximum values are correct. Finally, it validates settings related to how candles are processed.

    -

    This service's validate function is the core of the process; it examines all of these parameters to catch potential errors before your backtest begins.

    -

    The ColumnValidationService helps ensure your column configurations are set up correctly and consistently. It checks that each column definition includes all the essential pieces of information: a unique key, a descriptive label, a formatting function, and a visibility function to control how it's displayed.

    -

    It verifies these configurations are actually strings and functions as expected, and that the unique keys don't overlap within your column groupings. This service essentially acts as a safeguard, preventing errors and inconsistencies in your column setups before they cause problems.

    -

    The validate method performs this entire validation process across all your column configurations.

    -

    The ClientSizing component handles how much of your capital gets allocated to each trade. It uses different methods, like fixed percentages, Kelly Criterion, or Average True Range (ATR), to determine the right size for a position.

    -

    You can also set limits to ensure your positions don't become too large, either as a maximum dollar amount or as a percentage of your total capital. ClientSizing offers flexibility by letting you provide custom validation checks and logging throughout the sizing process. Essentially, it's the engine that figures out the best position size for your strategy to execute.

    -

    The calculate method is the core of this component; it takes input parameters and returns the calculated position size.

    -

    ClientRisk helps manage risk across your trading strategies, ensuring they don't exceed defined limits. It acts as a central control point, preventing signals that would violate those limits, like exceeding the maximum number of concurrent positions or failing custom validations. Multiple strategies can share the same ClientRisk instance, enabling a holistic view of portfolio risk.

    -

    It tracks active positions – essentially, what’s currently open in your portfolio – and uses this information to evaluate new trading signals. The checkSignal method is the core of this process; it evaluates whether a new signal is permissible based on the configured risk parameters. checkSignalAndReserve is a special, thread-safe version of checkSignal that not only performs the check but also temporarily "reserves" a spot in the active position tracker, preventing other strategies from accidentally exceeding the limits between the check and the actual trade execution.

    -

    The addSignal method is used to register when a trade is actually opened, and removeSignal cleans up when a trade closes. These methods work with a key identifying the strategy, exchange, and symbol of the position. It handles persistence of position data, though this is skipped in backtesting mode. It’s vital to remember that after a successful checkSignalAndReserve, you must either addSignal (to finalize the position) or removeSignal (if the position is cancelled) to avoid accumulating stale data.

    -

    The ClientFrame is a key component that creates the timelines used for backtesting trades. It efficiently generates arrays of timestamps representing the backtest period, ensuring the process isn't repeated unnecessarily with its caching feature.

    -

    You can customize the spacing between these timestamps, choosing intervals from one minute to one day.

    -

    The framework also allows for callbacks, which are useful for validating the generated timeframe data or for logging important events during its creation.

    -

    Essentially, ClientFrame works behind the scenes, feeding the historical data to the backtesting engine. The getTimeframe function is the main way to access this functionality, generating and caching those crucial timeline arrays for a given trading symbol.

    -

    This class, ClientExchange, acts as a bridge to get data from an exchange, designed to be efficient and safe for backtesting. It handles fetching historical and future candle data, which is crucial for analyzing past performance and simulating trades. You can retrieve past candles going backwards from a specific point in time, or look ahead to get data needed for signal durations in backtesting scenarios.

    -

    It also provides convenient methods for calculating things like the VWAP (volume-weighted average price), which is a common indicator used in trading. The class formats prices and quantities appropriately for different trading symbols, ensuring compatibility with exchange requirements.

    -

    Beyond basic candle data, you can get the current order book and aggregated trades, crucial for understanding market depth and order flow. The system carefully prevents "look-ahead bias," meaning it only uses data available at a given point in time, which is vital for accurate backtesting. The whole class is built to be memory efficient by using prototype functions.

    -

    The ClientAction component is a central piece for running your custom action handlers within the backtest-kit framework. Think of it as a manager that sets up, routes, and cleans up after your action handlers – these are the pieces of code that handle things like logging, sending notifications, managing your state (like with Redux), or collecting analytics.

    -

    It works by initializing an instance of your handler, and then directing different types of events to specific methods on that handler. There are separate methods for dealing with events coming from live trading, backtesting, and specific situations like when a breakeven or partial profit target is reached.

    -

    Importantly, ClientAction makes sure that initialization and cleanup only happen once, even if multiple events are triggered. It also provides a direct channel for gated position adjustments using limit orders, with a special note that errors in that process will be passed up for handling elsewhere.

    -

    CacheUtils provides a straightforward way to cache function results, especially useful when dealing with time-sensitive data like financial markets. It's like having a memory for your functions, so they don't have to repeat calculations unnecessarily.

    -

    The fn method lets you wrap regular functions, so their results are cached based on specific time intervals (like hourly, daily, etc.). This is ideal for calculations that should only update when new data becomes available.

    -

    For asynchronous functions (like those fetching data from a database or external API), the file method provides persistent caching, saving data to disk. This is extremely helpful for complex calculations that take a while to run; the results are stored in files within a directory structure that helps keep things organized. Each unique function gets its own, independent cache.

    -

    If you need to completely clear out the cached results for a specific function, you can use dispose. The clear function removes all cached data, which is handy if the environment or working directory changes. Finally, resetCounter helps keep file names consistent when you are working across different iterations of a strategy.

    -

    Essentially, CacheUtils helps you optimize performance by avoiding redundant calculations, storing data efficiently, and managing cached results easily.

    -

    This BrokerBase class is designed to help you connect your trading strategies to real exchanges. Think of it as a foundation for creating adapters that talk to specific brokers or exchanges. It provides a default structure and handles the basic logging of events, so you don't have to worry about setting that up from scratch.

    -

    You can extend this class to implement a custom adapter. It’s like building a specialized connector for placing orders, managing stop-loss and take-profit levels, tracking your position, and sending trade notifications.

    -

    Here’s how it works:

    -
      -
    1. Initialization: The waitForInit() method lets you perform any setup needed before the trading begins, such as logging into your exchange account.
    2. -
    3. Event Handling: As your strategy runs, the onSignalOpenCommit, onSignalCloseCommit, and other on...Commit methods are triggered. These are your opportunities to interact with the exchange – placing orders, closing positions, adjusting stops, and recording trades.
    4. -
    5. Default Behavior: Each of these commit methods has a default implementation that simply logs the event. You can customize these methods to perform the actual actions on your exchange.
    6. -
    7. Lifecycle: The broker doesn’t require explicit cleanup; any teardown can be done in the waitForInit method or handled externally.
    8. -
    -

    Essentially, BrokerBase gives you a convenient and organized way to plug your trading strategy into the real world.

    -

    The BrokerAdapter acts as a gatekeeper for any actions that modify your trading system's state, ensuring everything happens safely and in the right order. It’s particularly important when connecting to a live broker, but it also plays a role even in backtesting.

    -

    Think of it as a safety net: if anything goes wrong during a trade execution, the BrokerAdapter prevents the system from entering an inconsistent state.

    -

    Here's a breakdown of what it does:

    +
  • Profit & Loss Metrics: Easily access unrealized P&L, highest profit levels (price, timestamp, percentage, cost), and the potential for breakeven at those peaks.
  • +
  • Drawdown Analysis: Track the duration of active positions, waiting times, and the time elapsed since peak profit or worst drawdown. You can also get the price and timestamp associated with those extreme points.
  • +
  • Distance Metrics: Calculate the P&L distance (both percentage and cost) between the current price and the highest profit or deepest drawdown points, which gives insight into risk exposure.
  • +
  • Time-Based Metrics: Get the number of minutes the position has been active, waiting, or in drawdown.
  • +
  • Backtest Mode: The backtest parameter allows you to analyze historical performance accurately.
  • + +

    Essentially, ReflectUtils helps you understand the performance characteristics of your trading strategies in a detailed and structured way.

    +

    RecentLiveAdapter helps you manage and access recent trading signals, offering flexibility in how those signals are stored. Think of it as a central hub for accessing the most recent signals for a specific trading strategy.

    +

    It allows you to easily switch between different storage methods—either storing signals persistently on your disk or keeping them only in memory for a quicker, but less durable, solution. This is accomplished through adapters, making it simple to change the underlying storage without modifying the core logic of your trading system.

    +

    You can customize which storage method is used through a simple configuration process. It remembers the initial storage implementation and only recreates it when necessary, like when the directory the strategies are located in changes.

    +

    The adapter handles requests to retrieve the most recent signal, calculate the time since that signal was created, and react to active ping events, forwarding these actions to the chosen storage backend. If you want to keep things simple, it comes with default options for persistent or memory-based storage.

    +

    This component acts as a bridge for managing recent trading signals, allowing you to choose where that data is stored – either in memory or persistently on disk. It uses a flexible design, letting you easily swap out the storage mechanism without changing the rest of your code.

    +

    You can easily switch between an in-memory storage solution and a persistent one, which is useful for different testing and production scenarios.

    +

    Think of it as a central point to get recent signal information, like the most recent signal for a specific trading strategy. It provides helpful functions to retrieve that signal or calculate how long ago it was created.

    +

    The useRecentAdapter method lets you directly specify which storage implementation to use. It also has handy shortcuts like usePersist and useMemory to quickly switch storage types. Clearing the cached instance ensures a fresh start, especially when your working directory changes.

    +

    The RecentAdapter is your central hub for managing recent trading signals, both during backtesting and in live trading. It automatically updates its signal storage by listening for incoming data, ensuring you always have the most up-to-date information.

    +

    To avoid accidentally creating duplicate subscriptions, it uses a "single shot" system to subscribe only once.

    +

    You can easily access the latest signal for a specific symbol and trading context using getLatestSignal, which prioritizes backtest data and includes a safeguard to prevent looking into the future.

    +

    Need to know how long ago the last signal was generated? getMinutesSinceLatestSignalCreated calculates the elapsed time, again considering backtest data first and providing a look-ahead protection.

    +

    When you're finished, disable gracefully unsubscribes the adapter, and you can call it safely as many times as needed. You control when the adapter is active through the enable property, which guarantees a one-time subscription.

    +

    PriceMetaService helps track current market prices for trading strategies. It's designed to provide these prices even when you're not actively executing a trade.

    +

    Think of it as a memory of recent prices, organized by symbol, strategy, exchange, frame, and whether it’s a backtest.

    +

    This service keeps track of prices and updates them as new data comes in from the strategy. If a price isn't immediately available, it will wait a short time to see if one arrives.

    +

    You can clear these stored prices if you want to make sure you're starting with fresh data, especially when starting a new backtest or live trading session.

    +

    If you're running a trade, it uses a different method to get the live exchange price instead of relying on the cached value. It’s registered as a single, central service and updated automatically after each strategy tick.

    +

    This class helps you determine how much of an asset to trade, based on different sizing strategies. It provides several pre-built methods, each with its own formula for calculating the appropriate position size.

    +

    You’ll find options for fixed percentage risk, the Kelly Criterion (which aims to maximize growth rate), and an ATR-based method (using Average True Range to account for volatility).

    +

    Each method performs checks to ensure the information you provide aligns with the sizing technique being used. Essentially, it’s designed to simplify and validate position sizing calculations, making it easier to apply consistent risk management.

    +

    The Position class provides helpful tools for figuring out where to place your take profit and stop loss orders when trading. It automatically adjusts the direction of these orders depending on whether you're going long (buying) or short (selling).

    +

    The class offers two main calculation methods:

    +
      +
    • moonbag: This strategy sets a take profit level at a fixed percentage above (for long positions) or below (for short positions) your entry price.
    • +
    • bracket: This allows for more precise control, letting you define your own custom percentages for both the take profit and stop loss levels.
    • +
    +

    These methods take information about your position (long or short), the current price, and the desired percentages as input, and return an object with the calculated take profit and stop loss prices.

    +

    This class helps manage how your trading strategies remember their state between runs, particularly when you're backtesting or running live. It's designed to handle things like pending orders or actions that haven't fully completed.

    +

    Think of it as a way to safely store and retrieve a snapshot of your strategy's important data.

    +

    The system uses a clever memoization technique, meaning it only creates and manages one storage instance for each unique combination of symbol, strategy, and exchange – this helps improve performance.

    +

    You can customize how the data is stored and retrieved by swapping out the default storage mechanism. There's a default file-based option, a dummy option for testing (where nothing actually gets saved), and the ability to provide your own custom storage solution.

    +

    If you're using ClientStrategy for live trading, this utility automatically takes care of persisting certain internal data. It also provides ways to clear the stored data, which is useful if your working directory changes during a strategy run.

    +

    This class provides a way to reliably save and load the state of your trading strategy. It's designed to work with the backtest-kit framework and ensures that your strategy’s data persists even if there are unexpected interruptions.

    +

    It essentially acts as a wrapper around a file-based storage system, guaranteeing that writes are done safely and atomically. Think of it as a secure container for your strategy's data.

    +

    The class is initialized with the trading symbol, strategy name, and exchange name to clearly identify the data it’s managing. It uses a specific key ("strategy") for storing this data, keeping things organized.

    +

    The waitForInit method is used to set up the underlying storage. To retrieve your strategy's saved state, use readStrategyData. To save the current state, use writeStrategyData, which can also be used to clear the saved state by passing null.

    +

    This class helps manage how your trading signals are saved and loaded persistently, ensuring your data survives restarts and changes. It acts as a central point for handling storage, making it easy to switch between different storage methods.

    +

    The system keeps track of storage instances, creating one for each mode like "backtest" or "live," and it's designed to work reliably even if things crash.

    +

    You can easily customize how data is stored by providing your own storage adapter, or you can use the built-in JSON-based storage or a dummy adapter for testing. This utility automatically handles writing and reading signals, and each signal is stored as its own file, identified by its unique ID. If the current working directory changes during backtesting, it's a good practice to clear the cached storage instances.

    +

    This class provides a way to persistently store trading signals to files on your computer, making your backtesting data safe and recoverable. It's designed to work well with backtesting scenarios, which is reflected in its constructor.

    +

    Each signal you store will be saved as its own JSON file, identified by a unique ID. When you read the data back, the system will look through all the files to find them.

    +

    To ensure your data remains safe even if there are unexpected issues, it uses a technique called atomic writes, which helps prevent data corruption. You'll need to initialize the storage to get started.

    +

    You can read all stored signals at once, and when you want to save changes, they're written back out to the individual signal files.

    +

    This class helps manage and save the state of your trading strategies, ensuring data isn't lost even if things go wrong. It acts like a helper for safely storing and retrieving information related to specific signals and buckets.

    +

    It remembers which state storage instances it has created, so it doesn't make unnecessary copies. You can also customize how it stores data, whether using a file system or another method entirely.

    +

    The waitForInit function lets you control when the storage is initially set up, which can be useful for managing initial setup. Reading and writing data is also handled automatically, and it sets up the necessary storage the first time it's needed.

    +

    You can even temporarily switch to a "dummy" mode where all operations are ignored for testing purposes. To clean things up, you can clear the stored data or explicitly release storage for individual signals. Lastly, you can change the kind of storage that’s used, allowing you to plug in your own methods of persistence.

    +

    This class provides a way to save and load trading state information persistently, usually to a file. It's designed to be a straightforward way to store data like indicator values or order history.

    +

    Think of it as a container specifically for a particular trading signal, identified by its signalId, and a related "bucket" or named storage area (bucketName). It automatically handles writing data to a file in a safe, all-or-nothing manner.

    +

    You don't need to worry about managing the file cleanup itself; that's taken care of by other parts of the system.

    +

    Here's a breakdown of what you can do with it:

    +
      +
    • You can initialize the storage.
    • +
    • You can retrieve previously saved state data.
    • +
    • You can save new or updated state data.
    • +
    • The dispose function simply lets the framework manage caching aspects.
    • +
    +

    This utility class helps manage how signal data is saved and retrieved, ensuring it's reliable even if things go wrong. It keeps track of signal information separately for each strategy, symbol, and exchange you’re using.

    +

    The system uses a special "adapter" to decide how the signal data is actually stored – you can customize this adapter if you need a different storage method. The data is written and read in a way that prevents conflicts, and designed to handle unexpected crashes, making sure your signal state remains consistent.

    +

    You can tell it which type of storage to use – a custom adapter, a file-based solution, or even a dummy version for testing. The system automatically creates and manages these storage instances as needed. If the program's working directory changes, clearing the cache ensures data consistency.

    +

    This class, PersistSignalInstance, is designed to reliably save and retrieve signal data for your trading strategies. It's a handy tool for keeping track of signals across sessions, even if your program crashes.

    +

    It uses a file to store the signal data, ensuring that writes are handled safely and completely. Think of it as a safe place to store your signal information, linked to a specific trading symbol, strategy, and exchange.

    +

    The class takes the trading symbol, strategy name, and exchange name during setup to identify where to store the signal data. It internally manages a file-based storage system and makes sure the initialization happens correctly.

    +

    You can use readSignalData to retrieve a signal's information, and writeSignalData to save updated signal data, or clear the existing signal.

    +

    This utility class helps manage how session data is saved and loaded, ensuring a consistent and reliable experience. It acts as a central hub for handling session persistence, remembering information related to your trading strategies.

    +

    It intelligently caches session storage instances, creating them only when needed and reusing them for the same strategy, exchange, and data frame combination. This caching avoids unnecessary file operations and improves performance.

    +

    You have the flexibility to customize how sessions are persisted, choosing between different storage methods like using a file-based system, a dummy implementation for testing, or providing your own custom adapter.

    +

    The class also includes functions to initialize session storage, read and write data, and clear the cache. You can even trigger cleanup processes for specific sessions. It is designed to be crash-safe, ensuring that your session data remains secure.

    +

    This class provides a way to save and load session data for your trading strategies, using files to store the information. It's designed to work with a specific strategy and exchange, identifying each session by a unique frame name.

    +

    Think of it as a safe keeper for your session's important details.

    +

    The class automatically handles writing data to a file and reading it back, ensuring that the data is stored reliably. It's meant to be used in conjunction with PersistSessionUtils for overall resource management.

    +

    You don't need to worry about cleaning up resources directly; PersistSessionUtils takes care of that.

    +

    Essentially, this class simplifies the process of persisting your session data.

    +

    This class, PersistScheduleUtils, helps manage how scheduled trading signals are saved and loaded. It ensures each strategy's signals are stored independently and reliably.

    +

    It uses a clever system to create storage instances for signals based on the trading symbol, strategy, and exchange, avoiding unnecessary duplication.

    +

    You can customize how these signals are stored by providing your own storage solutions, or choose from pre-built options like a file-based system or a dummy for testing.

    +

    The readScheduleData and writeScheduleData methods handle fetching and saving signals, automatically setting up the storage if it doesn't already exist.

    +

    If you need to change how signals are persisted, the usePersistScheduleAdapter method allows you to plug in a different storage mechanism, and clear will refresh the storage system if needed, like when the working directory changes. It also provides a quick switch to use a default file-based storage or a dummy, no-op storage for testing.

    +

    This class helps store and retrieve schedule data, like signals, for a specific trading strategy on a particular exchange. Think of it as a way to save the state of your automated trading plan so it doesn't get lost if something goes wrong.

    +

    It uses a file to keep the data safe and ensures that writes happen reliably, even if there are interruptions. Each set of data is uniquely identified by a combination of the symbol (like 'AAPL'), strategy name, and exchange name.

    +

    The waitForInit method sets up the initial storage. readScheduleData fetches the data associated with a specific schedule, and writeScheduleData is used to save or clear that data. It essentially provides a simple way to persist data related to scheduled signals.

    +

    This class helps manage and store information about active trading positions, making sure the data is handled consistently and safely. It's specifically designed to work with ClientRisk for real-time trading, ensuring that position data persists even if there are unexpected interruptions.

    +

    It uses a clever system to create storage instances for each risk profile, avoiding unnecessary repetition. You can even customize how this storage works by providing your own “adapter” – a special constructor – to control the persistence mechanism.

    +

    The readPositionData function retrieves existing position data, while writePositionData saves new or updated data. It initializes storage the first time you use those functions.

    +

    To help with flexibility, you can easily switch between different persistence methods, such as using a default file-based system or a dummy system for testing. If things change in your environment, the clear function lets you refresh the storage system and make sure everything is working correctly.

    +

    This class, PersistRiskInstance, helps manage and save your trading positions to a file, ensuring data safety even if things go wrong. It's designed to work specifically within a defined trading context, using a consistent way to identify where the position data is stored. Think of it as a reliable record-keeper for your trading activities.

    +

    It automatically handles saving your position data in a way that minimizes the risk of data loss or corruption, even if the application crashes unexpectedly.

    +

    Here's a breakdown of how it works:

      -
    • Connects to Your Broker: You tell the BrokerAdapter which broker to use through useBrokerAdapter. It then handles the communication with that broker.
    • -
    • Manages Trade Events: It automatically sends "signal open" and "signal close" notifications to your broker, keeping it informed about your trading activity.
    • -
    • Intercepts Key Actions: Before the core trading logic makes changes (like setting partial profits or trailing stops), the BrokerAdapter steps in. This is a chance to make sure everything is valid. If anything fails at this stage, the core system remains untouched.
    • -
    • Backtesting Considerations: During backtesting, these actions are skipped to focus solely on the historical data and simulation.
    • -
    • Easy Activation/Deactivation: You can turn the broker interaction on (enable) or off (disable) as needed. There's also a clear function to ensure a fresh start when things change (like your working directory).
    • -
    -

    Essentially, the BrokerAdapter provides a reliable way to manage interactions with your broker and safeguards your trading system.

    -

    This class offers tools for analyzing and reporting on breakeven events in your trading backtests. Think of it as a way to get a clear picture of how often your strategies hit breakeven points and what those events look like.

    -

    It gathers information about breakeven events, which include details like the trading symbol, strategy used, signal ID, position type, entry and current prices, and whether it was a backtest or live trade.

    -

    You can use it to get statistical summaries of breakeven events, create detailed markdown reports that table all relevant information about these events, or directly save those reports to files.

    -

    The reports include tables showing the details of each breakeven event, along with useful statistics at the bottom. The reports are structured with columns such as symbol, strategy name, signal ID, and position type, along with prices and timestamps.

    -

    The class handles creating the necessary directory structure to store the report files and names them in a predictable format using the symbol and strategy name.

    -

    The BreakevenReportService helps you track when your trading strategies reach a breakeven point. It essentially listens for these "breakeven" moments and records them in a database.

    -

    Think of it as a diligent observer that captures every time a signal becomes profitable.

    -

    It uses a logger to keep you informed and ensures that you don't accidentally subscribe multiple times, which could lead to duplicate entries.

    -

    To start using it, you’ll need to subscribe to the breakeven signal, and when you're done tracking, you can unsubscribe. The subscribe method returns a function that you can call to unsubscribe.

    -

    The BreakevenMarkdownService helps you track and report on breakeven events that occur during trading. It keeps track of these events for each symbol and strategy you're using, organizing them so you can understand what’s happening.

    -

    You can think of it as a reporter that listens for "breakeven" signals and compiles them into easy-to-read markdown reports. These reports include detailed event information and overall statistics.

    -

    The service stores these reports on your computer, neatly organized into folders, making it simple to review your trading activity.

    -

    You can tell it to create these reports for specific symbols and strategies, or clear out all of the accumulated data when you need to start fresh. It’s designed to keep its data separate for each symbol, strategy, exchange, frame, and backtest combination, so you get focused insights.

    -

    This service acts as a central hub for managing and tracking breakeven points within the trading system. Think of it as a go-between, ensuring all breakeven-related activities are logged and handled consistently.

    -

    It's designed to be injected into the core trading strategy, streamlining how strategies interact with the underlying connection layer.

    -

    The service relies on other services—validation and schema services—to make sure everything is set up correctly before any actions are taken.

    -

    The validate function checks that the strategy and associated configurations are valid, and it remembers those checks to avoid repeating them unnecessarily.

    -

    The check function determines if a breakeven trigger should happen, logs the action, and then passes the request along. Similarly, clear handles closing a breakeven position, logging it, and delegating the task.

    -

    The BreakevenConnectionService manages tracking breakeven points for trading signals. It's designed to create and manage individual tracking instances, ensuring efficiency and preventing unnecessary object creation.

    -

    Essentially, it acts as a central hub for breakeven calculations, keeping track of these calculations for each trading signal.

    -

    Here's how it works:

    -
      -
    • It remembers previously created breakeven trackers (memoization), so it doesn’t recreate them every time.
    • -
    • It receives information about the trading signal and setup, allowing it to configure each tracker properly.
    • -
    • It handles the actual checks and clear operations through dedicated trackers, and cleans up when signals are no longer needed.
    • -
    • It works in coordination with other services to provide a complete trading strategy framework.
    • -
    -

    This utility class helps streamline backtesting operations, providing easier access to core functions and logging. It acts as a central point for managing backtest instances, ensuring each symbol-strategy pairing gets its own isolated environment.

    -

    You can run backtests using the run method, which processes data and provides results asynchronously. For background runs that don't require immediate results, use background. There are also methods to retrieve specific signal information like pending or scheduled signals (getPendingSignal, getScheduledSignal), and details about the current position (getTotalPercentClosed, getPositionEffectivePrice, getPositionPnlPercent, getPositionLevels).

    -

    The class offers functions to check for signal absence (hasNoPendingSignal, hasNoScheduledSignal), and to determine breakeven (getBreakeven). You can also access position-specific data like entry prices (getPositionEntries), partial close events (getPositionPartials), and estimated durations (getPositionEstimateMinutes). Several functions help analyze position performance and potential for profit or loss.

    -

    Finally, the stop method allows you to halt a backtest, while commit... methods let you manipulate signals and positions during the process. commitCreateSignal allows inserting custom signals. list displays the current status of all backtest instances.

    -

    This service helps you keep a detailed record of what’s happening during your backtests. It listens for events related to your trading signals – when they're inactive, being set up, actively trading, and when they're finished.

    -

    Essentially, it’s capturing a snapshot of each signal’s journey, storing all the details in a database so you can analyze them later to understand what worked well and what didn't.

    -

    You can think of it as a logging system specifically designed for backtesting, and it avoids accidentally recording the same events multiple times. To start using it, you'll subscribe to the signal events; this returns a function you can call to stop listening. If you're already subscribed and call unsubscribe, it simply stops the service from recording further events.

    -

    The BacktestMarkdownService is designed to automatically create and save detailed reports about your trading backtests. It listens for updates as your strategies run, carefully recording information about each signal that closes.

    -

    This service keeps track of closed signals for each strategy, neatly organized using a storage system that prevents data from different combinations of symbols, strategies, exchanges, and frames from interfering with each other. It then transforms this data into easy-to-read markdown tables.

    -

    You can use it to generate reports that summarize the performance of your strategies, and it saves these reports directly to your backtest logs.

    -

    The service offers a way to clear out this accumulated data when it’s no longer needed, and it provides functions for getting specific data or reports, or even saving them to a particular file path. To use it effectively, you'll need to connect it to your backtest environment, using the provided subscribe and unsubscribe methods.

    -

    The BacktestLogicPublicService helps run backtests in a structured way, handling details like the trading strategy, exchange, and the specific timeframe being tested. It simplifies things by automatically passing this information to the functions used during the backtest, so you don't have to manually include it every time.

    -

    It uses a logger to track events and manage time-related information.

    -

    The service also relies on other services to handle connections to exchanges and define the structure of the data being used in the backtest.

    -

    The run method is the core function to start a backtest. You provide the symbol you want to backtest, and it will give you a stream of results as the backtest progresses, showing the signals generated and the trades executed. The context you provide—strategy, exchange, and timeframe—is automatically applied to every step of the backtest process.

    -

    The BacktestLogicPrivateService manages the complex process of running a backtest for trading strategies. It works by first obtaining the relevant timeframes from a frame service. Then, for each timeframe, it processes incoming data and decides whether to execute trading actions.

    -

    When a trading signal arises, the service fetches the necessary historical data (candles) and executes the backtest logic to simulate the strategy's actions. It intelligently skips ahead in time until the signal is closed, efficiently utilizing resources.

    -

    The service delivers results incrementally using an asynchronous generator, meaning it streams the outcomes (like opened, closed, or cancelled signals) without first storing everything in memory—this is great for large backtests. You can also stop the backtest early by interrupting the generator.

    -

    Internally, it relies on several core services: StrategyCoreService, ExchangeCoreService, FrameCoreService, ActionCoreService, TimeMetaService, PriceMetaService, and a logger service for tracking what’s happening. The run method is the key entry point, and it takes a symbol (like a stock ticker) to specify which asset to backtest.

    -

    This service acts as a central point for accessing backtesting capabilities within the framework. It's designed to be easily integrated into other parts of your application.

    -

    It bundles together several internal services, like those handling logging, strategy validation, and exchange validation, to ensure a smooth and consistent backtesting experience.

    -

    The validate function helps you ensure your strategy and its associated risk settings are correctly configured before you run a backtest. It intelligently remembers past validations to save time.

    -

    The core function, run, performs the actual backtest, taking a symbol and some contextual information like the strategy, exchange, and frame names. It delivers the results step by step.

    -

    The ActionValidationService helps you keep track of your action handlers – those pieces of code that respond to specific events in your trading system. Think of it as a central manager ensuring your handlers are correctly registered and available when needed.

    -

    It provides a straightforward way to register new handlers using addAction, letting you define what actions your system can respond to and how. Before running anything that relies on an action handler, you can use validate to confirm it’s actually registered, preventing errors.

    -

    To make things efficient, the service remembers previous validation results – a technique called memoization – so it doesn’t have to re-check the same handlers repeatedly. If you need a complete overview of what’s registered, list provides a listing of all your configured action schemas. It also has properties for internal usage like loggerService and _actionMap.

    -

    The ActionSchemaService is in charge of keeping track of and managing the blueprints for actions within your trading system. It ensures that actions are set up correctly and safely, using type safety to prevent errors.

    -

    Think of it as a central place where you define what actions your system can perform, what methods those actions use, and how they're validated.

    +
  • The constructor takes the risk and exchange names to identify the context.
  • +
  • waitForInit sets up the underlying storage so that the data can be stored reliably.
  • +
  • readPositionData retrieves the saved positions data at a specific time.
  • +
  • writePositionData saves your current position data, making sure it's stored safely.
  • + +

    Essentially, it provides a straightforward and dependable way to persist and retrieve your risk and position information.

    +

    This class, PersistRecentUtils, helps manage how recent trading signals are stored and retrieved. It's designed to be reliable, even if the system crashes, and remembers signals based on specific criteria like the trading symbol, strategy name, exchange, and timeframe.

    +

    It uses a clever system to create and share storage instances—meaning it doesn't have to repeatedly create and destroy them, making it more efficient. You can even plug in your own custom ways of storing signals.

    +

    Here’s a breakdown of what you can do:

    +
      +
    • Choose how to store signals: Easily switch between different storage methods, like using files, a dummy adapter (for testing), or a custom adapter you create.
    • +
    • Forget and start fresh: Clear out the existing storage if you need to, for example, when running multiple strategies.
    • +
    • Read recent signals: Get the latest signal that was recorded for a specific trading setup.
    • +
    • Save recent signals: Record a new signal for a specific trading setup.
    • +
    • Key Generation: Automatically builds a unique identifier for each signal, including details like timeframe and whether you're in backtest or live mode.
    • +
    +

    It’s a foundational component used by other parts of the trading framework to keep track of recent signals.

    +

    This component, PersistRecentInstance, is designed to reliably save and retrieve the most recent trading signal data for a specific symbol, strategy, and exchange. It essentially provides a way to keep track of the last known signal.

    +

    It works by storing this data in a file, using the symbol as a unique identifier. The location of this file is also influenced by whether the simulation is a backtest or live trading session, and optionally by a frame name.

    +

    You can think of it as a system that automatically remembers the most recent signal for each trading setup you define.

    +

    Here's a breakdown of what it does:

    +
      +
    • It initializes its internal storage mechanism.
    • +
    • It reads the latest signal data that’s been saved.
    • +
    • It saves a new signal to the storage, associating it with the symbol.
    • +
    +

    The class constructor sets up the parameters defining the trading context (symbol, strategy, exchange, frame, and backtest mode). You'll specify those when you create an instance of this component to ensure data is saved to the correct location and with the correct context. The internal _storage property handles the actual file storage.

    +

    This class, PersistPartialUtils, helps manage and store partial profit and loss information for your trading strategies, particularly when dealing with live trading. It's designed to ensure this data is saved reliably, even if there are unexpected interruptions.

    +

    It keeps track of these partial data points, organizing them by the trading symbol, the name of your strategy, and a unique identifier for each signal.

    +

    The system uses a clever trick – it only creates and loads these data storage instances when it absolutely needs them. You can also customize how this data is stored using different adapters; for example, you could use a simple file system, a database, or even a dummy adapter for testing.

    +

    If your trading environment changes, like when you change directories, you can manually clear the stored data. The class also provides shortcuts for using a standard file-based storage or a dummy (no-op) adapter for testing purposes.

    +

    This component helps you save and retrieve temporary data related to your trading strategies, ensuring that even if things go wrong, you don’t lose progress. Think of it as a safe place to store incomplete information while your strategy is running.

    +

    It uses a file on your computer to store this data, automatically handling the saving process securely. Each instance is tied to a specific trading symbol, strategy name, and exchange to keep your data organized.

    +

    The constructor sets up these identifiers.

    +

    The waitForInit method prepares the storage space. The readPartialData method retrieves a saved piece of data based on a unique signal identifier. Finally, writePartialData allows you to store new partial data, again using that unique identifier to pinpoint where the data goes. This helps ensure your data is saved reliably and consistently.

    +

    This class helps manage how notification data is saved and retrieved, especially for backtesting and live trading environments. It acts as a central point for handling notification persistence, making sure that notifications are reliably stored and accessible.

    +

    It uses a clever system of memoization, meaning it creates and reuses notification storage instances to improve efficiency. You can even customize how notifications are stored by providing your own storage constructors.

    +

    The getNotificationStorage property provides these storage instances, and the readNotificationData and writeNotificationData methods handle loading and saving notification information. Each notification is stored as its own file, which improves organization and reliability.

    +

    If you need to change how notifications are persisted, the usePersistNotificationAdapter, useJson, and useDummy methods let you easily switch between different storage options, including a dummy option for testing. Clearing the cache with the clear method is useful when the working directory changes, like between strategy executions, so the system uses the correct file paths.

    +

    This class helps manage and save notification data to files, ensuring they are persistent even if your application restarts. It's designed to be reliable, using atomic writes to prevent data corruption.

    +

    Each notification is stored as its own JSON file, making it easy to access and manage individual notifications.

    +

    The waitForInit method prepares the storage space, while readNotificationData retrieves all saved notifications. You can use writeNotificationData to save new notifications or update existing ones, knowing that each notification's ID will be used to identify and store it. It is configured to be used in backtest scenarios.

    +

    This utility class helps manage how memory data is saved and retrieved, especially when your application needs to recover from crashes or unexpected events. It ensures that each storage area for your data is created and handled efficiently, based on a unique combination of identifiers.

    +

    The class uses a clever system to reuse storage instances, making sure you don't create unnecessary files and slow things down. You can also customize how the storage works by providing your own creation functions.

    +

    It provides methods for reading, writing, and deleting memory entries, and checks to see if data exists before attempting to use it. Importantly, it includes a way to clear the system’s internal cache when needed, like when your application's working directory changes. There's also a function to clean up individual storage areas when they are no longer needed.

    +

    You can easily swap out the default storage behavior with alternatives – either a file-based system or a dummy version that doesn't actually save anything (useful for testing). Finally, it allows you to iterate through existing data to build indexes or perform other tasks.

    +

    This class, PersistMemoryInstance, handles saving and retrieving memory data to a file. It’s a reliable way to store information persistently, like settings or cached results.

    +

    It manages this storage by writing data to JSON files, ensuring that changes are saved correctly.

    +

    The class provides methods to read, write, and delete memory entries, offering a straightforward interface for data management. Deleted entries aren't physically removed but are marked as "removed," allowing you to easily filter them out when listing data.

    +

    It also includes a method to initialize the underlying storage.

    +

    Finally, the dispose method doesn’t actually do anything on its own because the management of related caches is handled elsewhere.

    +

    This utility class helps manage cached data from external APIs, specifically designed for persistent storage. It keeps track of cached data in a structured way, organizing it by a combination of timestamp and symbol.

    +

    The class allows you to customize how the data is stored using different adapter options, ensuring the data is written and read reliably. It handles situations where the data needs to be initialized for the first time, ensuring the process is smooth.

    +

    You can also remove data entries, which marks them for removal rather than permanently deleting them. The system remembers which adapter you’re using, and offers convenient options to switch back to a file-based adapter or a dummy adapter that doesn't actually store anything. Finally, it's important to clear the internal cache when the working directory changes to maintain accuracy.

    +

    This class helps you store and retrieve trading data persistently, like performance metrics or historical results. It acts as a bridge, managing the actual storage and ensuring operations happen reliably.

    +

    It uses files to hold your data, organized within a designated "bucket". This allows you to easily separate different types of data.

    +

    When you need to retrieve data, it looks for entries, and if a measure has been "soft-deleted" (marked as removed), it won't be returned.

    +

    If you want to remove data, it doesn't actually erase the file; instead, it adds a flag to indicate it's removed.

    +

    To get a list of all existing measures, it filters out any that have been soft-deleted.

    +

    The class also handles the initial setup of the storage, making sure everything's ready before you start working with it.

    +

    This class helps manage how log entries are saved and retrieved. It acts as a central point for accessing a log instance, which can be customized with different storage methods.

    +

    The system uses a cached version of the log instance to avoid repeatedly creating it. You can easily swap out the way the logs are stored, for example, to use a file-based system, a JSON-based system, or even a dummy system that doesn't actually save anything.

    +

    To get the log data, you can either read all existing entries or write new entries, with the writes being append-only to prevent duplicates. It's designed to handle situations where the application might crash and ensures the log state remains consistent. If the working directory changes between strategy runs, you’ll need to clear the cached log instance.

    +

    This class provides a way to save and load trading logs to files, ensuring your history is preserved. It's like having a digital notebook for your trades.

    +

    Each trade or event gets its own separate file, making it easy to manage and review. The system only adds new entries, it won't overwrite anything already saved.

    +

    To use it, you'll need to make sure the storage is initialized before reading or writing. The readLogData method pulls all the log entries from the files. When you add new data, writeLogData safely adds entries to the storage, preventing any accidental data loss.

    +

    This component manages how your backtest kit keeps track of which intervals have already fired. It essentially acts as a persistence layer, storing a record for each interval that has run. These records are saved in a directory called ./dump/data/interval/, and their presence indicates the interval has already been processed.

    +

    You can customize how these records are stored and managed by providing your own constructors for the persistence instances. There’s also a handy clear function to reset this tracking when your working directory changes.

    +

    The readIntervalData function retrieves these records, while writeIntervalData creates them, and removeIntervalData marks them as deleted. The listIntervalData method allows you to iterate through all recorded intervals for a specific bucket. For testing or when you don't need actual persistence, you can switch to a dummy implementation where all operations are ignored.

    +

    This class provides a way to save and retrieve data related to specific time intervals, like when a certain event happened. It's designed to work with files, so the data persists even if your program closes.

    +

    It handles writing data to files in a reliable way, even if things go wrong during the process. When you want to remove data, it doesn’t actually delete the file; instead, it marks the data as "removed," so you can always bring it back if needed. This allows intervals to be retried after a 'deletion'.

    +

    The bucket property identifies the storage location for this data. The underlying file storage is managed by _storage.

    +

    You can initialize the storage with waitForInit. readIntervalData lets you fetch the data associated with a particular interval key; if the data is missing or marked as removed, it will return nothing. writeIntervalData stores the data. removeIntervalData essentially hides the data by marking it as removed. Finally, listIntervalData gives you a way to see all the existing interval keys, but it only shows the ones that haven't been marked for removal.

    +

    This class, PersistCandleUtils, helps manage how your historical candle data (like open, high, low, close prices) is stored and retrieved. It acts as a cache, saving data as individual JSON files organized by exchange, symbol, time interval, and timestamp.

    +

    The class intelligently checks if the cached data is complete and up-to-date before using it, automatically refreshing when needed. It ensures data consistency through atomic operations.

    +

    You can customize how the cached data is stored, choosing from different implementations such as a standard file-based approach, a custom adapter, or even a dummy implementation for testing. The getCandlesStorage property is a way to control the creation of these storage instances.

    +

    Functions like readCandlesData and writeCandlesData handle reading and saving data to the cache, creating the storage instance if it doesn't exist yet. If you're changing the directory where your strategy runs, be sure to clear the cache to make sure it re-initializes properly.

    +

    This class provides a way to persistently store and retrieve candle data, acting as a bridge between your trading logic and a file-based storage system. It’s designed to keep track of candles for a specific trading symbol, interval (like 1 minute or 1 hour), and exchange.

    +

    Each candle’s data is saved as a separate JSON file, making it easy to manage and access individual candles. If a candle's timestamp isn’t found, it signals a cache miss, prompting the system to fetch the data again.

    +

    The writing process is careful – it will ignore any candles that are still incomplete (meaning they haven't closed yet) or files that already exist to prevent data corruption. If a candle’s data is found to be invalid, it issues a warning and treats it as a cache miss to ensure you’re always working with reliable information.

    +

    You can use waitForInit to ensure the storage system is ready before you start reading or writing data. The readCandlesData method lets you retrieve a range of candles, and writeCandlesData handles the storage of new candle information.

    +

    This class helps manage and save breakeven data – the point at which a trade becomes profitable – for your trading strategies. It handles the behind-the-scenes work of storing and retrieving this data, so you don't have to.

    +

    Think of it as a central hub that keeps track of breakeven states for each symbol (like BTCUSDT) and strategy you're using. It automatically saves data to files organized by symbol and strategy, making it easy to load them later.

    +

    The system uses a clever technique to ensure it's efficient. It only creates a storage instance for each unique combination of symbol, strategy, and exchange once, and reuses it afterward. You can even customize how the data is stored, either by using the default file-based system or switching to a "dummy" mode for testing. If you need to change how data persistence works, you can register custom components to handle the job.

    +

    If your working directory changes during a strategy run, you'll need to clear the cached storage.

    +

    This class provides a reliable way to save and retrieve breakeven data, a crucial element for backtesting trading strategies. It acts as a bridge, wrapping a file-based storage system to ensure your data is preserved even if something unexpected happens.

    +

    Think of it as a safe keeper for your breakeven calculations. It identifies each data point by a unique signal ID, essentially acting like a digital filing cabinet for this information.

    +

    It's designed to work within a specific trading context, using the symbol, strategy name, and exchange name to organize its storage.

    Here's a breakdown of what it does:

      -
    • Registration: It lets you register new action types, making sure they’re correctly structured and that the methods used within them are approved.
    • -
    • Validation: It checks that your action setups are complete and follow the rules before they're actually used. It verifies that any public methods used in the action's code are allowed.
    • -
    • Modification: You can update existing action schemas without having to completely redefine them. This is helpful for making small changes.
    • -
    • Retrieval: It provides a way to fetch the details of an action when you need it.
    • -
    -

    The service relies on a logger to help debug and monitor its operation. It uses a registry to store and manage the action schemas in a secure and organized way.

    -

    The ActionProxy acts as a safety net when your custom trading strategies interact with the backtest framework. Think of it as a protective layer around your code. It takes your action handlers—the code that reacts to events like a new signal or a profit level—and ensures that any errors within those handlers don't crash the entire backtesting process.

    -

    Instead of letting errors halt the simulation, ActionProxy catches them, logs them, and allows the backtest to continue. This is crucial for robust testing and debugging.

    +
  • It initializes the storage mechanism, preparing it for use.
  • +
  • It can fetch existing breakeven data based on a signal ID and a timestamp.
  • +
  • It saves new or updated breakeven data, again using a signal ID and timestamp for organization.
  • +
  • It safeguards your data with atomic writes, which means changes are saved completely or not at all, preventing data corruption.
  • + +

    This class provides a foundation for storing and retrieving data to files, ensuring the process is reliable and safe. It's designed to handle situations where file corruption might occur, automatically cleaning up any issues.

    +

    The class manages where your data files are stored and organizes them based on a given name. It handles creating the storage directory if it doesn't already exist and also validates the integrity of existing files during initialization.

    +

    You can use it to read data back from storage, check if data exists, and write data securely using a special method that prevents data loss even if something goes wrong during the writing process. Finally, it offers a way to iterate through all the entity IDs (unique identifiers for your data) stored, sorted alphabetically.

    +

    This service is designed to monitor and record how long different parts of your trading strategy take to run. It acts like a detective, tracking down bottlenecks and areas where your strategy might be slow.

    +

    It listens for performance-related events, capturing details like how long each step takes and associated information. This data is then saved so you can analyze it later to improve your strategy's speed and efficiency.

    +

    You can tell it to start listening for these events, and it will automatically stop when you need it to, preventing it from interfering with other parts of your system. If you try to subscribe more than once, it makes sure only one subscription is active. Similarly, you can explicitly tell it to stop listening.

    +

    This service helps you keep track of how your trading strategies are performing. It listens for performance updates, organizes them by strategy, and calculates key statistics like average, minimum, and maximum values.

    +

    It automatically creates reports in a readable markdown format, which it saves to a designated folder, making it easy to analyze bottlenecks and understand what's impacting your strategy's performance.

    +

    You can subscribe to receive these performance events, and unsubscribe when you no longer need them. There are also methods to retrieve specific performance data, generate reports on demand, and even clear out all the accumulated data when you want to start fresh. The framework handles the details of organizing data for each unique combination of symbol, strategy, exchange, frame, and whether it’s a backtest.

    +

    The Performance class helps you understand how your trading strategies are performing. It provides tools to analyze metrics and create reports that pinpoint areas for improvement.

    +

    You can retrieve aggregated performance statistics for a specific symbol and strategy, giving you a breakdown of key metrics like duration, average time, and volatility.

    +

    It also generates markdown reports that visually summarize your strategy’s performance, highlighting potential bottlenecks and areas where operations take the most time.

    +

    Finally, you can save these reports directly to your hard drive for later review, with the option to specify a custom file path. This allows for easy tracking and comparison of different strategies over time.

    +

    This class provides helpful tools for examining partial profit and loss data, which is useful for understanding how your strategies are performing. It acts as a central point to access and visualize these events, allowing you to track metrics and generate reports.

    +

    You can use it to retrieve aggregated statistics like total profit/loss counts for specific symbols and strategies. It can also generate nicely formatted markdown reports, creating tables that show details of each profit/loss event, including the action, symbol, signal ID, position, level, price, timestamp, and whether it was a backtest or live trade.

    +

    Finally, this class simplifies the process of saving these reports to a file; it automatically creates the necessary directories and names the file with a clear and descriptive format, such as "BTCUSDT_my-strategy.md."

    +

    The PartialReportService helps you keep track of smaller, partial exits from your trades. It focuses on recording those moments when you take some profit or cut a loss before a position is fully closed.

    +

    This service listens for signals indicating these partial exits, both when things are going well (profit) and when they aren't (loss). It gathers details like the price and level at which these partial closures occurred.

    +

    The information is then saved persistently, allowing you to analyze your trading behavior regarding partial exits.

    +

    You can control whether the service is active by subscribing and unsubscribing – it prevents accidental multiple subscriptions. To stop it, use the unsubscribe function returned when you initially subscribe. If the service hasn't been subscribed, unsubscribing simply does nothing.

    +

    The tickProfit and tickLoss properties handle the processing of partial profit and loss events respectively. A logger service is also used for debugging output.

    +

    The PartialMarkdownService helps you create and store detailed reports about your trading profits and losses. It listens for events indicating profit or loss, organizes them by symbol and trading strategy, and then compiles them into easy-to-read markdown tables.

    +

    You can subscribe to receive these profit and loss signals, and the service will automatically accumulate the data. It also provides overall statistics like the total number of profit and loss events. The service then saves these reports to files, making it simple to review your trading performance over time.

    +

    You can request specific data, generate reports, or clear all accumulated data. The storage for each report is isolated, ensuring that data from different symbols and strategies doesn’t get mixed up. This makes it a useful tool for tracking and analyzing your trading results.

    +

    This service manages and tracks partial profits and losses, acting as a central hub for these operations. It’s designed to be injected into your trading strategies, providing a clean way to handle partials and ensuring consistent logging.

    +

    Think of it as a middleman; it receives requests related to profits, losses, and clearing partials, logs those actions globally, and then passes them on to the underlying connection service.

    +

    It includes several validation services to check the integrity of your strategies, risks, exchanges, frames, and actions. This helps catch potential configuration issues early on.

    +

    The validate function is a smart shortcut, remembering previous validation results to avoid unnecessary checks. The profit, loss, and clear functions are the main ways you’ll interact with this service, each responsible for handling a specific state change and relaying that information further down the pipeline.

    +

    The PartialConnectionService manages the tracking of partial profits and losses for trading signals. It acts as a central hub, creating and maintaining records for each signal, ensuring that profit and loss information is handled consistently.

    +

    Think of it as a smart cache for signal-specific data. It keeps track of each signal's profit and loss history, creating a new record only once and reusing it whenever that signal is encountered.

    +

    The service allows you to easily record when a signal reaches a profit or loss milestone, and to reset the record when a signal is closed out. It works closely with other parts of the system, automatically cleaning up old data to prevent memory issues. When signals are no longer needed, their records are automatically removed, keeping things tidy.

    +

    This component helps manage and send notifications during a backtest or live trading session. It's designed to be flexible, letting you easily swap out how notifications are handled – whether it's to memory, a file, or even nowhere at all (for testing purposes).

    +

    You can think of it as a central hub for all notifications related to your trading strategy, like signal events, profit/loss updates, errors, and more.

    +

    The system uses a factory pattern, so you can choose different notification methods. The default keeps notifications in memory. You can also switch to persistent storage (saving them to disk) or a dummy adapter (which discards them, ideal for testing).

    +

    Key features include:

    +
      +
    • Flexibility: Easily change how notifications are sent.
    • +
    • Convenience methods: Simple shortcuts to switch between different notification adapters like usePersist, useMemory, and useDummy.
    • +
    • Memoization: The notification utility instance is created once and reused, improving performance. clear() can be called to force a refresh when the underlying environment changes.
    • +
    • Comprehensive handling: Methods exist to manage various events like signals, profits, losses, errors, and synchronization.
    • +
    • Data Retrieval: You can retrieve all stored notifications with the getData method.
    • +
    • Cleanup: The dispose function allows you to clear all stored notifications when you're done.
    • +
    +

    This service helps manage and send out notifications related to trading signals. It's a behind-the-scenes helper used within the system to keep everything running smoothly.

    +

    It validates different aspects of your trading setup – strategy, exchange, frame, risk and action schemas – to make sure everything is set up correctly. This validation is smart; it only runs once for each combination of strategy, exchange, and frame, saving processing time.

    +

    The main function you'll interact with is commitSignalNotify. This is what triggers the notifications you receive about trading signals, combining validation with the actual signal emission. It makes sure that the notification is accurate, properly formatted, and sent out to the right places. Think of it as the final step in confirming and broadcasting a signal event.

    +

    This component lets you manage notifications during backtesting, offering flexibility in how those notifications are handled. It's designed to be adaptable, allowing you to easily swap out different notification methods without changing the core backtesting logic.

    +

    You can choose from several pre-built notification methods: an in-memory storage (the default), a persistent storage option that saves notifications to disk, and a dummy option that essentially ignores notifications entirely.

    +

    The system uses a factory pattern, meaning you can even create your own custom notification handlers if needed. The getInstance property is a smart shortcut – it builds the notification handler once and then reuses it, making things efficient.

    +

    The various handle... methods (like handleSignal, handlePartialProfit, handleRisk, etc.) all act as messengers, passing data to whichever notification method you've currently selected. There are also methods for retrieving all notifications (getData) and clearing them (dispose).

    +

    Finally, the use... methods provide a convenient way to switch between notification methods quickly – useDummy, useMemory, and usePersist. The clear method is crucial if your working directory changes during backtesting, ensuring a fresh notification handler is used.

    +

    The NotificationAdapter is designed to handle all your notification management needs, both during backtesting and when you're live. It keeps track of notifications, automatically updating as new signals arrive.

    +

    You can easily access both backtest and live notifications through a single interface. To prevent unexpected issues, it uses a "singleshot" system, ensuring that you only subscribe to notifications once.

    +

    You can enable and disable notification storage, and the dispose method offers a clean way to clear out all stored notifications when you're finished with a backtest or a live trading session. The getData method lets you retrieve all of your notifications, specifying whether you need backtest or live data.

    +

    This component, MemoryLiveAdapter, provides a flexible way to manage trading memory, allowing you to choose different storage methods depending on your needs. Think of it as a central hub for storing and retrieving data related to your trading strategies.

    +

    You can easily switch between several storage options: a default file-system based storage that saves data persistently, a purely in-memory option for fast but temporary storage, a dummy adapter that simply ignores data, or even create your own custom storage solution.

    +

    The adapter keeps track of stored data using memoization, meaning it efficiently reuses instances to avoid unnecessary overhead. You can clear this cache when needed, particularly when your working directory changes.

    +

    It offers core functions for writing, reading, searching, listing, and removing memory entries, along with a method to discard data associated with specific signals. The search functionality utilizes a powerful text-scoring algorithm (BM25) to find relevant data quickly.

    +

    This adapter provides a flexible way to manage memory storage for your backtests. Think of it as a central point for how your backtest stores and retrieves data. It offers different storage options—like keeping everything in memory, persisting data to files, or even just discarding data—allowing you to tailor the adapter to your specific backtest needs.

    +

    You can easily switch between these storage methods using simple commands like useLocal, usePersist, or useDummy. The adapter automatically handles caching memory instances to improve performance, but you can clear this cache manually if needed, for example, when the working directory changes.

    +

    The adapter includes methods to write, search, list, remove, and read data, all structured around a signal ID and bucket name. It also offers a way to bring in your own custom memory storage implementations, providing maximum control over the backtesting process. Finally, it provides a way to dispose of memoized instances for a specific signal, which is useful when a signal is cancelled or closed.

    +

    The MemoryAdapter is the central component for managing memory storage within the backtest and live trading environments. It intelligently directs memory-related operations, like writing, searching, listing, removing, and reading data, to either the backtest or live memory systems based on configuration.

    +

    To keep things clean, it automatically handles subscription and unsubscription to signal lifecycle events, ensuring that stale data doesn’t linger and resources are properly released. You can explicitly enable or disable this memory management functionality, and it’s designed to prevent duplicate subscriptions to avoid unexpected behavior.

    +

    Think of it as a smart router that makes sure your memory operations go to the right place and handles cleanup for you.

    +

    This class offers tools to understand and analyze maximum drawdown, a crucial metric for assessing risk in trading. Think of it as a way to get detailed reports and statistics about how much your strategies have lost at their worst points.

    +

    It doesn't create new instances; instead, you interact with a single, readily available instance to access its functions.

    +

    You can request specific data, like overall drawdown statistics, for a particular trading symbol and strategy, optionally specifying whether it's a backtest scenario.

    +

    It can also create formatted markdown reports summarizing all drawdown events for a given symbol and strategy combination, letting you see a chronological view of potential losses. You can even have these reports automatically saved to a file. Finally, it provides an option to customize which data columns are included in the report.

    +

    The MaxDrawdownReportService is designed to track and record maximum drawdown events during a trading backtest. It actively monitors for these drawdown events and saves detailed information about them.

    +

    This service keeps a log of each drawdown event, capturing key data points like the timestamp, symbol, strategy name, exchange, frame, and backtest identifier. It also includes specifics about the signal that triggered the drawdown, such as its ID, position, current price, and the effective take profit and stop loss levels.

    +

    To get it working, you'll need to subscribe to the maxDrawdownSubject to start receiving and logging those drawdown records. To stop the service, simply unsubscribe, which cleanly disconnects it from the subject. It's designed to prevent accidental double-subscriptions, so it’s efficient and reliable.

    +

    This service is designed to collect and present information about maximum drawdowns, a key risk metric in trading. It listens for drawdown events and organizes them by symbol, strategy, exchange, and timeframe.

    +

    You can subscribe to receive these drawdown events, and unsubscribe when you no longer need them. The service provides methods to retrieve the raw data, generate a formatted markdown report, and save that report to a file.

    +

    To clear the collected data, you can either clear everything at once or selectively remove data associated with a specific symbol, strategy, exchange, and timeframe combination. This is useful for resetting the service or focusing on particular trading scenarios.

    +

    The MarkdownWriterAdapter helps manage how trading reports are saved, offering flexibility in where and how they're stored. It uses a pattern that allows you to easily swap out different storage methods, like writing each report to its own file, combining them into a single JSONL file, or even disabling report generation entirely. The system remembers which storage method is active, so you don’t have to reconfigure it.

    +

    You can change the default way reports are saved, or choose to store them as individual files, in a single log file, or not at all. The adapter intelligently creates the necessary storage when you first write a report.

    +

    If you need to change your working directory during testing, it’s a good idea to clear the adapter's memory to ensure fresh storage is created using the new path.

    +

    MarkdownUtils helps you control how different parts of the trading framework generate markdown reports. It lets you turn on and off report generation for things like backtests, live trading, and performance analysis.

    +

    You can selectively enable or disable reports for specific areas. When you enable reports, the system starts gathering data and producing reports, and it’s really important to remember to turn off those reports when you're done to avoid problems.

    +

    The clear function is useful if you want to reset the data used for a report without stopping the report generation itself. This allows you to start a new report from scratch without disabling the underlying functionality.

    +

    This adapter lets you generate each report as its own individual markdown file, which is great for keeping your reports organized and easy to browse. It automatically creates the necessary directories to hold these files.

    +

    Think of it as the standard way to create reports when you want a clean, human-readable directory structure.

    +

    The adapter doesn't require any special setup or initial steps—it just writes the content directly to the specified file. You control where these files go using the options.path and options.file settings.

    +

    Essentially, it's designed for straightforward report generation and manual review.

    +

    This framework component provides a way to generate markdown reports in a structured, append-only JSONL file. It’s designed to help you centralize and easily process your trading backtest reports using standard JSONL tools.

    +

    Each report type (like trade details or account history) gets its own file, neatly organized within a directory. The system handles creating this directory for you and ensures that writing to the file is reliable, even if it takes a while.

    +

    You don’t have to worry about constantly checking if the file can accept more data; it handles that automatically with backpressure. There’s also a safety net to prevent operations from hanging indefinitely.

    +

    The reports are structured with useful metadata like the trading symbol, strategy name, exchange, frame, and signal ID, so you can easily filter and search through them later.

    +

    Initializing the adapter is straightforward and safe to do multiple times, and the dump method is how you add your markdown content to the JSONL file, along with that valuable metadata.

    +

    The MarkdownAdapter helps you manage how your markdown files are stored, offering flexibility and efficiency. It lets you easily switch between different storage methods without changing your core code.

    +

    You can choose to store each markdown file as a separate .md file using the standard folder-based approach, or combine them into a single .jsonl file.

    +

    For testing or quick experiments, a dummy adapter is available that simply ignores any data you try to write. The adapter remembers which storage method you’ve chosen, so you don’t have to keep specifying it. It also creates storage instances only when they're needed for the first time, saving resources.

    +

    The LookupUtils class acts like a central record keeper for ongoing backtests and live trading sessions. It keeps track of each activity, like a backtest run or a live trade execution, adding a note when it starts and removing it when it finishes.

    +

    This system helps manage resources, particularly when dealing with parallel processing. It makes sure that the system doesn't waste effort by checking if yielding to another process is even necessary.

    +

    You don’t create instances of this class directly – it’s provided as a singleton called Lookup.

    +

    Here's what it offers:

    +
      +
    • It maintains a map of active activities.
    • +
    • You can add an activity to the map using addActivity. If you try to add the same activity again, it simply updates the existing entry.
    • +
    • When an activity is complete, removeActivity cleans up its record. It's important to use this, even if errors occur, to avoid lingering entries.
    • +
    • listActivity gives you a snapshot of all the activities currently in progress.
    • +
    +

    The LoggerService helps you keep your trading logs organized and informative. It's designed to add extra details to your log messages automatically, so you don't have to remember to include things like the trading strategy being used, the exchange, or the execution context.

    +

    You can plug in your own custom logger if you want, or the system will fall back to a basic "no-op" logger if you don't set one.

    +

    The service provides methods for different logging levels - general messages, debug information, warnings, etc. - all of which include that automatic context. It relies on two services to manage the context information it appends: methodContextService and executionContextService. You can also change the default logger using the setLogger function.

    +

    The LogAdapter provides a flexible way to manage your trading strategy's logging. Think of it as a central hub for how your logs are stored and displayed – you can easily change where they go without altering the rest of your code. It starts with an in-memory log, which is fine for quick testing, but you can swap it out to save logs to a file for later analysis or even disable logging entirely for performance.

    +

    You can choose how to store your logs by using functions like usePersist for disk storage, useMemory for the default in-memory option, or useDummy to essentially turn logging off. useJsonl lets you write logs in a standard JSONL format to a file.

    +

    The clear() function is useful when your working directory changes between tests, ensuring the log adapter re-initializes with the updated directory. The log, debug, info, warn methods let you record different types of events within your trading strategy. You can even define your own custom log adapter if you need something specialized.

    +

    LiveUtils provides tools to manage live trading operations, simplifying the process and adding resilience. It’s designed to run continuously, recovering from crashes and providing real-time data.

    +

    You can start live trading for a specific symbol and strategy using the run function, which creates an ongoing stream of results. Alternatively, background lets you run trading without directly receiving those results, ideal for tasks like persistence.

    +

    To get the current pending or scheduled signal for a trade, use getPendingSignal or getScheduledSignal. You can also check if signals exist with hasNoPendingSignal and hasNoScheduledSignal.

    +

    Several functions provide insights into the current position, such as getTotalPercentClosed, getTotalCostClosed, and getPositionInvestedCost. You can also get the effective entry price (getPositionEffectivePrice), and duration estimates (getPositionEstimateMinutes, getPositionCountdownMinutes).

    +

    There are also methods for price-related checks like getBreakeven, and calculating Position performance metrics like getPositionPnlCost, getPositionDrawdownMinutes.

    +

    LiveUtils also includes functions for managing the trading process: stop to pause trading, commitCancelScheduled and commitClosePending to manually handle signals, and commitAverageBuy to manage DCA entries. Data reporting and diagnostic options are provided through methods like getReport and dump. The list function provides a summary of all active trading instances.

    +

    This service helps you keep a record of what's happening with your live trading strategy. It listens for events related to your signals – when they're inactive, when trades are opened, when they're active, and when they're closed.

    +

    All of these events, along with detailed information about them, are logged and saved to a database. This allows you to monitor your live trading in real-time and analyze its performance.

    +

    You can think of it as a constantly running observer that captures every important signal event and saves it for later review. The subscribe method allows you to start this recording process and provides a way to stop it with unsubscribe. The service uses a mechanism to prevent accidental duplicate subscriptions, ensuring accuracy.

    +

    This service helps you automatically generate and save reports about your live trading activity. It constantly monitors what's happening in your strategies, recording details about events like when a strategy is idle, when a trade is opened or closed, and even the performance of each strategy.

    +

    The service creates easy-to-read markdown tables that summarize these events, also calculating key trading statistics like win rate and average profit/loss. These reports are automatically saved as files, making it simple to track your progress and analyze your strategies.

    +

    You can subscribe to receive these live updates, and later unsubscribe when you no longer need them. There are also functions to get specific data, generate reports for particular strategies or clear all accumulated data. The reports are organized by symbol, strategy name, exchange, frame, and whether it's a backtest or live trade, ensuring everything is neatly categorized.

    +

    LiveLogicPublicService helps manage live trading by automatically handling things like knowing which strategy and exchange are being used. It simplifies things so you don’t have to constantly pass those details around.

    +

    This service continuously runs and provides a stream of trading results—signals to open or close positions, or notifications of cancelled orders—that essentially never stops.

    +

    If something goes wrong and the process crashes, the system can recover the previous state and continue where it left off.

    +

    Key parts:

    +
      +
    • It uses a logger for tracking activity and an exchange connection service to talk to the exchange.
    • +
    • The run method is the main way to start the live trading process, specifying the trading symbol and context.
    • +
    • It’s designed for continuous operation and includes crash recovery features.
    • +
    +

    This service manages the ongoing process of live trading, working as the central coordinator. It continuously monitors the market, checking for new trading signals.

    +

    The core functionality involves an unending loop, regularly creating a timestamp to ensure accurate data. It then evaluates the current signals and, crucially, only sends back the results when a trade is actually opened or closed – avoiding unnecessary updates.

    +

    To optimize performance, it uses an asynchronous generator to stream results efficiently, meaning it doesn't hold a large volume of data in memory. If the trading process encounters a crash, it automatically recovers and picks up where it left off. This service provides a real-time view of trading activity for a specific symbol and runs indefinitely.

    +

    The LiveCommandService acts as a central point for interacting with the live trading components of the backtest-kit framework. It's designed to be easily integrated into your application through dependency injection.

    +

    Essentially, it provides a straightforward way to access and utilize the live trading functionality.

    +

    Here's a breakdown of its key parts:

    +
      +
    • It relies on several internal services – a logger, a public live logic service, and services for validating strategies, exchanges, schemas, risks, and actions.
    • +
    • The validate function helps ensure your strategies and risk configurations are correct, and it remembers previous validations to speed things up.
    • +
    • The run function is the heart of live trading – it starts and manages the live trading process for a specific symbol. This function will continually generate trading results and automatically attempt to recover from any crashes to keep your trading running smoothly.
    • +
    +

    IntervalUtils helps you control when functions are executed, ensuring they only run once within a specific time interval. It provides two ways to manage this: one keeps track of the firing in memory, while the other uses files to remember the state, allowing it to persist even if the application restarts.

    +

    The fn method wraps your function to make sure it doesn't run more than once per interval. If your function returns null, it'll wait and try again later. It smartly creates a separate tracking instance for each unique function you wrap.

    +

    Similarly, the file method does the same but uses file storage. This means the "fired" state of your function is saved, so it won't re-run unnecessarily after a restart. Like fn, it creates a unique persistent instance per function.

    +

    You can clean up old tracking instances with dispose and clear. dispose lets you remove a specific function's tracking, forcing it to create a new instance on the next call. clear wipes out all tracking, which is helpful when the working directory changes during strategy runs. Lastly, resetCounter resets the file-based instance numbering to avoid conflicts when the base path updates.

    +

    This class helps you analyze and report on the highest profits achieved during trading simulations or live trading. It acts as a central place to gather information about the most profitable trades.

    +

    You can think of it as a tool to create reports and summaries of your best-performing strategies.

    +

    It provides a few key functions:

    +
      +
    • getData lets you pull specific statistical information about the highest profits recorded for a particular trading symbol and strategy.
    • +
    • getReport allows you to create a formatted markdown report detailing all the highest profit events for a given symbol and strategy.
    • +
    • dump takes that report and saves it directly to a file, so you can easily share or archive it.
    • +
    +

    These functions work with data collected from “highestProfitSubject” events, offering insights into your most successful trading scenarios.

    +

    This service is responsible for tracking and recording your most profitable trading moments. It keeps an eye on a stream of data called highestProfitSubject and whenever a new high-profit record is achieved, it writes that information to a database for later analysis.

    +

    The service uses a loggerService and tick to manage the data and interaction.

    +

    Each recorded event includes details like the timestamp, the symbol traded, the strategy used, the exchange, the timeframe, and information related to the signal that generated the profit - including price levels, position size, and stop-loss/take-profit orders.

    +

    To start saving this data, you need to "subscribe" to the highestProfitSubject. Because you only want to subscribe once, it uses a system to prevent multiple subscriptions; subsequent calls to subscribe will return the same function to stop the process.

    +

    You can stop the recording process by calling unsubscribe, which disconnects the service from the highestProfitSubject.

    +

    This service is designed to gather and present data about the highest profit achieved during trading, creating easily readable reports. It listens for incoming data about profitable trades, organizing them based on the symbol, strategy, exchange, and time frame.

    +

    You can subscribe to receive these updates, although it will only subscribe once to prevent duplicate subscriptions. Unsubscribing completely clears all accumulated data and stops the service from receiving any further updates.

    +

    The tick method processes individual trade events, directing them to the appropriate storage location. The getData method allows you to retrieve statistics for a specific trading context, showing a summary of the recorded events. getReport generates a formatted markdown report showing the most recent profitable trades. The dump method creates these reports and saves them as markdown files with a specific naming convention, indicating whether it's a backtest or live trading scenario.

    +

    Finally, clear allows you to reset the data, either for a specific combination of symbol, strategy, exchange and frame, or for all recorded data. This is useful for starting fresh or removing existing records.

    +

    HeatUtils offers helpful tools for creating and managing portfolio heatmaps, making it easier to understand your trading strategy's performance. It essentially gathers and summarizes key statistics for each symbol used by a specific strategy.

    +

    You can request the raw data for a strategy's portfolio heatmap, including metrics like total profit, Sharpe ratio, and drawdown. Alternatively, it can generate a nicely formatted markdown report – a table that displays these same statistics for each symbol, sorted by profitability.

    +

    Finally, this data can be easily saved to a file, creating a report you can share or review later, with the file name automatically created based on the strategy’s name. It acts as a single point of access, handling the underlying data gathering and formatting for you.

    +

    HeatReportService helps you track and analyze your trading activity by recording when signals close and how much profit or loss resulted. It listens for these closing events and saves them in a database, allowing you to create heatmaps to visualize your portfolio's performance.

    +

    It's designed to be easy to use - it automatically subscribes to signal events and only logs information about closed signals, so you don't have to worry about filtering.

    +

    You can subscribe to the service to start receiving these events, and an unsubscribe function is provided to stop the process when it’s no longer needed. Importantly, it prevents accidentally subscribing multiple times, which could lead to duplicated data.

    +

    This service builds and presents a heatmap of your trading activity, providing a clear visual summary of how your strategies are performing. It listens for signals about trades – specifically when they're closed – and gathers data on a per-symbol and portfolio level.

    +

    Think of it as a dashboard that lets you quickly see which strategies and symbols are doing well and which need attention.

    +

    You can subscribe to receive these signals, and the service automatically handles the storage and aggregation of data. It keeps things organized by exchange, timeframe, and whether you're in backtest or live mode.

    +

    The service offers several ways to interact with the data:

    +
      +
    • Get Data: Retrieve the aggregated statistics for a specific exchange, timeframe, and backtest mode.
    • +
    • Generate Reports: Create a formatted markdown report for a strategy, exchange, timeframe, and backtest mode, presenting the data in a table.
    • +
    • Dump to File: Save the heatmap report directly to a file on your system.
    • +
    • Clear Data: Reset the data for a specific exchange/timeframe/mode, or clear everything entirely, giving you a fresh start.
    • +
    +

    The system is designed to handle mathematical calculations carefully, avoiding errors that could arise from unusual data (like infinity or "not a number"). It also remembers which storage buckets it’s using, improving performance and preventing unnecessary data duplication. Unsubscribing from the signal emitter cleans up the resources.

    +

    The FrameValidationService helps you keep track of and verify your trading timeframe configurations. Think of it as a central control panel for your frames.

    +

    It allows you to register new timeframes using addFrame, ensuring they're properly defined.

    +

    Before you start using a timeframe, the validate function checks if it’s registered, preventing errors.

    +

    For efficiency, it remembers the results of validations so it doesn't have to repeat checks.

    +

    If you need to see all the timeframes you've set up, the list function provides a convenient way to view them. It’s like getting a complete inventory of your configured timeframes.

    +

    The FrameSchemaService helps keep track of all your frame schemas in a structured and reliable way. Think of it like a central directory for these schema definitions.

    +

    It uses a special system to store these schemas safely and with type checking.

    +

    You add new schemas using the register method and find them later using the get method – simply provide the name you assigned when you registered it.

    +

    If you need to update an existing schema, you can use override to provide only the changes you want to make, rather than replacing the whole thing.

    +

    Before adding a schema, the system checks it over using validateShallow to make sure it has all the necessary parts and they are of the expected types – ensuring consistency.

    +

    FrameCoreService manages how your trading data is organized into timeframes. Think of it as a central coordinator that fetches and prepares the data your backtesting engine needs. It relies on other services to handle connections and data validation, ensuring that the timeframes used for your tests are accurate and consistent. The core function is getTimeframe, which allows you to request a specific timeframe (like daily or weekly data) for a given asset, providing a date array to use in your backtesting loop. It's a foundational piece that keeps everything synchronized and ready for analysis.

    +

    The FrameConnectionService acts as a central hub for managing and accessing different trading frames. It automatically directs requests to the correct frame implementation based on the current context.

    +

    To improve efficiency, it caches frequently used frame instances, so they don't need to be recreated repeatedly.

    +

    This service also handles backtesting timeframes, allowing you to define a specific start and end date for your analysis.

    +

    When in live mode, no frame is active, indicated by an empty frame name.

    +

    The service relies on other services like the logger service, frame schema service, and method context service to function correctly.

    +

    You can use the getFrame method to obtain a frame instance, and getTimeframe to retrieve the timeframe boundaries for a specific symbol.

    +

    The ExchangeValidationService helps you keep track of your configured exchanges and make sure they're actually valid before you try to use them. It essentially acts as a central registry for your exchanges, storing details about each one.

    +

    You can use it to register new exchanges using addExchange, allowing the service to manage them.

    +

    The validate function checks if an exchange actually exists, preventing potential errors later on. This helps ensure stability.

    +

    The service also remembers previous validation results to speed things up—this is known as memoization.

    +

    Finally, list allows you to see all the exchanges currently registered with the service.

    +

    ExchangeUtils offers helpful tools for interacting with different cryptocurrency exchanges. It's designed as a single, readily available resource to simplify common tasks.

    +

    It provides a way to retrieve historical candle data, automatically figuring out the correct date range based on the desired interval and the number of candles you need. You can also use it to calculate the VWAP (volume-weighted average price) from recent trade data.

    +

    Need the latest closing price for a specific trading pair? ExchangeUtils provides a simple function for that.

    +

    It also handles the complexities of formatting trade quantities and prices to match the rules of each exchange.

    +

    Want to see the order book? ExchangeUtils can get that for you. It also lets you retrieve aggregated trade data, allowing you to analyze trading activity. Finally, it can pull raw candle data with custom start and end dates for maximum flexibility.

    +

    The ExchangeSchemaService helps keep track of information about different cryptocurrency exchanges, ensuring everything is structured correctly. It uses a special storage system to manage these exchange details in a type-safe way.

    +

    You can add new exchanges using the addExchange function, and retrieve them later by their name using the get function.

    +

    Before adding an exchange, the validateShallow function checks to make sure it has all the necessary information in the expected format.

    +

    If you need to update an existing exchange, the override function lets you make partial changes.

    +

    The service relies on logging to track its activity and uses a registry to store the exchange schemas.

    +

    ExchangeCoreService acts as a central hub for handling interactions with an exchange, providing a consistent way to access data and execute operations. It seamlessly combines connection management with contextual information like the trading symbol, timestamp, and whether the operation is part of a backtest. This service is crucial for both backtesting historical strategies and executing live trades.

    +

    It offers methods for retrieving various types of data, including historical and future candles (for backtesting), VWAP (volume-weighted average price), order book information, and aggregated trade data. All these methods incorporate execution context, ensuring that data is retrieved with the correct parameters.

    +

    The service includes validation capabilities to make sure exchange configurations are sound, and it formats prices and quantities appropriately for display or further processing. It uses memoization for validation, improving efficiency by avoiding repeated checks on the same exchanges. Ultimately, ExchangeCoreService abstracts the complexities of exchange interactions, simplifying data retrieval and trade execution within the trading framework.

    +

    The ExchangeConnectionService acts as a central hub for interacting with different cryptocurrency exchanges. It intelligently routes requests for data, like candles or order book information, to the correct exchange implementation based on the currently selected exchange. To improve performance, it caches these exchange connections, so it doesn't need to re-establish them repeatedly.

    +

    This service provides a unified way to retrieve various data points: historical candles, the next batch of candles based on the current timestamp, the average price (calculated differently for backtesting and live trading), the closing price of a recent candle, formatted prices and quantities (ensuring they adhere to exchange-specific rules), order book data, and aggregated trade data. It also handles retrieving raw candles, allowing for custom date ranges and limits. The ExchangeConnectionService relies on other services like logging, execution context, and exchange schema to function properly.

    +

    The DumpAdapter helps you save information about your trading tests in various formats. Think of it as a middleman that takes data and puts it where you need it, whether that's a Markdown file, in memory, or nowhere at all (for testing purposes).

    +

    It manages how data is stored based on which "backend" you choose. By default, it creates a Markdown file for each dump, organized by signal ID, bucket name, and dump ID.

    +

    You can easily change how data is saved. For example, you can switch to using memory for faster access or a dummy backend to completely ignore the data during development.

    +

    Before you start dumping data, you need to activate the adapter, and you can deactivate it later. The adapter keeps track of instances and clears them when signals are cancelled to avoid accumulating stale data.

    +

    You can use it to save everything from full message histories and simple records to tables, raw text, JSON objects, and even errors.

    +

    If you need even more control, you can inject your own custom data-saving implementation. There's also a clear function to refresh the adapter’s internal caches when things like the working directory change.

    +

    Okay, here's a breakdown of the CronUtils class in backtest-kit, explained in plain language.

    +

    It's a tool for scheduling tasks to run at specific times during backtesting, especially useful when you need to coordinate actions across multiple simultaneous backtest runs. Think of it as a way to trigger something reliably when a certain time interval passes, even if you’re running many backtests at once.

    +

    The key is that it prevents multiple backtests from trying to run the same task at exactly the same time. It ensures that only one handler runs for a given time slot, even when many backtests hit that same time.

    +

    Here's a look at the important parts:

    +
      +
    • Registration: You "register" your tasks (called "entries") with this class. Each task specifies the interval at which it should run.
    • +
    • Coordination: When the scheduled time arrives, the class ensures that only one instance of the task runs, even if several backtests hit that time simultaneously. This prevents conflicts and ensures correct behavior.
    • +
    • Persistence: It handles situations where backtests might skip time intervals – it will catch up and run the task when the next interval arrives.
    • +
    • Memory Management: The class has internal mechanisms to clean up old task configurations, preventing memory leaks and ensuring that tasks are re-armed correctly.
    • +
    • Lifecycle Integration: It can automatically subscribe to engine events so that tasks run without needing manual configuration.
    • +
    • Resetting: You can clear all scheduled tasks and reset the system to a clean state.
    • +
    +

    Essentially, it's a reliable, synchronized scheduler specifically designed for backtesting environments.

    +

    The ConstantUtils class provides a set of predefined percentages used for setting take-profit and stop-loss levels, designed around the Kelly Criterion and exponential risk decay. These constants help manage risk and capture profits progressively as a trade moves towards its ultimate target.

    +

    Think of these values as checkpoints along your profit or loss journey.

    +

    For example, TP_LEVEL1 at 30% means a partial profit is taken when the price reaches that point, while SL_LEVEL1 at 40% serves as an early warning to adjust your exposure. Each level offers a chance to lock in some gains or reduce potential losses before the trade reaches its full target. It's a system designed to balance letting profits run with protecting your capital.

    +

    The ConfigValidationService is designed to double-check your trading setup to make sure it's mathematically sound and capable of making a profit. It meticulously examines your global configuration parameters, like slippage, fees, and profit margins, ensuring they’re set up correctly.

    +

    Specifically, it makes sure your take-profit distance is large enough to cover all potential trading costs – slippage and fees – so you actually make money when a trade hits that target. It also verifies that relationships between parameters, like minimum and maximum values, are logically consistent.

    +

    Finally, the service verifies that time-related settings and candle parameters have sensible values, such as positive integers for timeouts and appropriate thresholds for candle data requests. It’s like having a built-in safety net to catch potential errors in your configuration.

    +

    The ColumnValidationService helps ensure your column configurations are set up correctly. It checks your column definitions to make sure they meet the requirements for the ColumnModel interface.

    +

    It verifies several things, including:

    +
      +
    • Each column has all the necessary information: a key, a label, a format, and a visibility setting.
    • +
    • The key and label properties are actual text strings and aren't empty.
    • +
    • The format and visibility settings are functions that can be executed.
    • +
    • Each key is unique within the column set, avoiding conflicts.
    • +
    +

    The validate method runs these checks against your column configurations and highlights any problems it finds.

    +

    This component helps you determine how much of an asset to trade based on various strategies. Think of it as a tool for calculating your position sizes.

    +

    It offers different methods for calculating sizes, such as a fixed percentage, Kelly Criterion, or using Average True Range (ATR). You can also set limits on the minimum or maximum position size and restrict the percentage of your capital that’s used for any single trade.

    +

    The system is flexible; it allows you to add custom logic through callbacks for validation or to keep a record of sizing decisions. Ultimately, this component feeds sizing information to the strategy execution process, so your trades are sized appropriately.

    +

    The calculate method is the core function, taking parameters and returning the calculated position size, which is a promise.

    +

    ClientRisk helps manage risk across your trading strategies, acting like a safety net to prevent unintended consequences. It's designed to make sure your strategies don't exceed pre-defined limits, such as the maximum number of simultaneous trades. Think of it as a central control point that all your strategies check in with before placing orders.

    +

    This system isn’t isolated; multiple strategies can share the same ClientRisk instance, allowing for a holistic view of risk across your entire portfolio. It’s used internally by the trading execution process to validate signals before a trade is actually made.

    +

    The ClientRisk is configured with specific parameters that define those risk limits. It keeps track of active positions, combining data from all strategies to get a complete picture. It also offers the ability to create custom validation rules, giving you fine-grained control over risk management.

    +

    To prevent race conditions and errors, there's a special "reservation" process. checkSignalAndReserve ensures that a trade is only confirmed if a spot is available, preventing scenarios where multiple strategies simultaneously attempt to open positions beyond the allowed limits. It's crucial to either complete the trade (with addSignal) or cancel the signal (with removeSignal) after this check.

    +

    Finally, when a trade does happen, addSignal registers the new position, while removeSignal cleans up when a trade closes.

    +

    The ClientFrame is the engine that creates the timelines for your backtesting. It generates arrays of timestamps, essentially defining the sequence of moments your trading strategies will be tested against. To prevent unnecessary work, it remembers previously calculated timelines and reuses them.

    +

    You can adjust how far apart these timestamps are, from as frequent as one minute to as broad as one day.

    +

    The ClientFrame also lets you hook into the process, allowing you to verify the generated timelines or record information about them. It's a core component, used internally by the system to step through historical data.

    +

    The getTimeframe property is your main way to get these timelines; it takes a symbol (like a stock ticker) and returns a promise that resolves to the array of dates and times. The singleshot caching ensures it only calculates the timeframe once.

    +

    The ClientExchange class is your go-to for getting data from an exchange, designed to be efficient and reliable within the backtest-kit framework. It provides ways to retrieve historical and future candle data, calculate VWAP (volume-weighted average price), and format price/quantity information according to exchange-specific rules.

    +

    You can easily grab past candles using getCandles, or look ahead to get future candles with getNextCandles – essential for backtesting strategies. getAveragePrice calculates the VWAP based on recent, short-term candles.

    +

    Need the latest closing price? getClosePrice delivers that. formatQuantity and formatPrice ensure the data is presented in the right way for the exchange.

    +

    The getRawCandles method is very flexible, letting you pull candles from specific start and end dates or using the current time as a reference. It strictly avoids look-ahead bias. Finally, getOrderBook retrieves the current order book, and getAggregatedTrades gives you historical trade data.

    +

    The ClientAction class is a central piece for integrating custom logic into your trading strategy. It handles the communication and lifecycle of your action handlers, which can manage things like logging, notifications, analytics, and managing external state (like Redux).

    +

    Essentially, it provides a structured way for your code to react to various trading events, such as signals, breakeven adjustments, profit/loss milestones, and scheduled tasks.

    +

    Here's a breakdown of what it does:

    +
      +
    • Initialization: It creates and manages an instance of your action handler, ensuring it's set up properly and only initialized once.
    • +
    • Event Routing: It listens for different types of events (live trading, backtesting, etc.) and dispatches them to the appropriate methods within your action handler. These events include signal generation, partial profit/loss triggers, and scheduled checks.
    • +
    • Lifecycle Management: It provides a way to safely clean up resources and subscriptions when the action handler is no longer needed.
    • +
    • Customization: You can define custom logic through event handling, allowing you to tailor the behavior of your strategy and integrate with external systems.
    • +
    +

    The signalLive, signalBacktest, and related methods offer targeted event handling, while scheduleEvent and pendingEvent handle manual event wiring and advanced lifecycle management. Methods like signalSync and orderCheck are critical gateways for specific order execution flows.

    +

    CacheUtils is a helper class designed to make caching function results simpler, especially when dealing with trading strategies that need to repeat calculations within specific timeframes. It acts as a central point for managing these caches, making sure they are invalidated when necessary.

    +

    The fn method lets you wrap regular functions, automatically storing their results based on a timeframe you define. Think of it as a way to avoid recomputing the same data repeatedly during a backtest.

    +

    For asynchronous functions, the file method provides persistent caching, storing the results in files. This is excellent for caching heavy calculations and reusing them across different backtest runs. The file names include the function name, interval, and a unique index, helping to keep things organized.

    +

    If you need to explicitly clean up a function's cache, the dispose method lets you do just that, forcing a fresh calculation next time the function is called.

    +

    The clear and resetCounter methods are helpful for situations where your base directory changes between strategy iterations, ensuring that your caches are rebuilt from scratch. This prevents issues from cached data in unexpected locations.

    +

    The BrokerBase class is designed to help you create custom adapters that connect your trading strategies to different exchanges. Think of it as a foundation for connecting your code to real-world trading platforms. It handles many of the common tasks like placing orders, managing stop-loss and take-profit levels, and keeping track of your positions.

    +

    You don’t need to implement everything yourself – the class has built-in defaults for most functions, so you only need to override the ones you want to customize. It also automatically logs important events to help with debugging and monitoring.

    +

    The process of using this class involves a few key steps: first, you initialize the connection to the exchange in the waitForInit() method. Then, as your strategy runs, various “commit” methods are called for events like opening positions (onSignalOpenCommit), closing positions (onSignalCloseCommit), and adjusting stop-loss levels. These methods provide points where you can interact with the exchange and record the transactions. Specifically, onSignalActivePing allows you to mirror data from the exchange into your own systems and onOrderCheck enables you to proactively manage orders. The whole system is designed to be as safe as possible with exception-based gate mechanisms that prevent unexpected errors from disrupting your trades.

    +

    The BrokerAdapter acts as a middleman between your trading strategy and the actual broker. It ensures that actions like opening or closing positions are handled correctly and provides a controlled way to interact with the broker, especially crucial for things like partial profits or trailing stops.

    +

    Essentially, it’s a safety net. If anything goes wrong during these actions, it prevents unwanted changes to your trading data, keeping your state consistent.

    +

    During backtesting, these interactions are skipped to speed up the process, focusing solely on the simulated results.

    +

    Here’s a breakdown of its key features:

    +
      +
    • Broker Integration: It connects your trading system to a real broker.
    • +
    • Controlled Actions: All trading commands (like opening, closing, adjusting stops) go through it, allowing for checks and safeguards before they reach the broker.
    • +
    • Transaction Safety: If any of these commands fail, it prevents any changes to the system's internal state.
    • +
    • Backtesting Mode: During backtests, it acts as a silent observer to speed up the process.
    • +
    • Automatic Events: Handles certain events like signal openings and closings automatically.
    • +
    • Commit Methods: It exposes various “commit” methods (like commitSignalOpen, commitPartialProfit) that are used to trigger broker actions.
    • +
    • Configuration: You register your broker adapter using useBrokerAdapter before enabling the connection.
    • +
    • Enabling/Disabling: You turn the broker interaction on or off using enable and disable. enable sets up the automatic event handling.
    • +
    • Clearing: The clear method resets the cached broker connection, useful when your trading environment changes.
    • +
    +

    This class provides tools to analyze and report on breakeven events, helping you understand your trading strategies’ performance. It gathers data about when breakeven points are hit, including details like the symbol traded, the strategy used, the entry price, and the current price.

    +

    You can retrieve statistical summaries of these events, giving you an overview of how often breakevens are being triggered. It can also generate detailed markdown reports presenting each breakeven event in a tabular format. These reports include all relevant information and a summary of the statistics.

    +

    Finally, you can easily save these reports to files, named in a consistent way (like "BTCUSDT_my-strategy.md"), for later review and analysis, even creating the necessary folders to store them. The class manages the underlying data storage and formatting, letting you focus on interpreting the results.

    +

    The BreakevenReportService is designed to keep track of when your trading signals reach their breakeven point. It’s like a dedicated record-keeper for these significant moments in your backtesting process.

    +

    It listens for these "breakeven" events and stores them, along with all the details about the signal that triggered them, in a database. This allows you to analyze how often signals achieve breakeven and understand their performance.

    +

    To use it, you’ll subscribe to the breakeven signal emitter, and it will automatically log the events as they happen. Make sure to unsubscribe when you're finished to stop the logging, and you don’t have to worry about accidentally subscribing multiple times – it handles that for you. The service uses a logger to provide helpful debugging information as well.

    +

    The BreakevenMarkdownService helps you track and report on breakeven events in your trading system. It automatically gathers data about when strategies hit breakeven points, organizing it by symbol and strategy.

    +

    The service compiles these events into nicely formatted markdown reports, providing both detailed information and overall statistics like the total number of breakeven events. These reports are saved to disk, making it easy to analyze your trading performance.

    +

    You can subscribe to receive breakeven events in real time, and the service handles the subscription process to prevent accidental duplicates. The tickBreakeven method is where the processing of each event happens.

    +

    It provides methods for getting statistics, generating reports, and saving those reports to your file system. You can also clear the accumulated data if you need to start fresh or remove specific data related to a certain symbol, strategy, exchange, frame, and backtest.

    +

    The BreakevenGlobalService acts as a central hub for tracking breakeven points within the trading system. It's designed to be easily integrated, receiving necessary services through dependency injection. Think of it as a gatekeeper that logs all breakeven-related actions before passing them on to the actual connection service for handling.

    +

    It simplifies how different parts of the system interact with breakeven functionality by providing a single injection point for strategies.

    +

    The service includes various validation tools to ensure strategies, risks, exchanges, frames, and actions are all set up correctly. It even remembers previous validation checks to avoid unnecessary repetition.

    +

    The core functions allow you to check if a breakeven trigger should happen and to clear the breakeven state when a signal closes. These functions always log the activity before directing the actual work to the connection service.

    +

    The BreakevenConnectionService helps keep track of breakeven points for your trading signals. It's designed to manage and create these tracking objects efficiently, avoiding unnecessary duplication.

    +

    Essentially, it creates a dedicated tracking instance for each unique signal you're monitoring, remembering these instances to avoid recreating them.

    +

    The service allows you to easily check if a breakeven condition has been met and clear the tracking data when a signal closes, while ensuring everything is properly cleaned up and avoids memory issues. It works closely with other services like the action core and time management components within your trading system.

    +

    This class provides tools to simplify backtesting in your trading framework. Think of it as a helper for running simulations and getting insights into your strategies.

    +

    It offers shortcuts for running backtests, both synchronously and in the background, and gives you ways to retrieve specific information about a position's performance, like pending signals, total costs, and potential profits. You can also retrieve data like breakeven points and the average entry price.

    +

    Key features include:

    +
      +
    • Easy backtest execution: Simplifies starting and running backtests with logging.
    • +
    • Background execution: Runs backtests without interrupting your main process.
    • +
    • Position details: Access information like pending signals, cost basis, and potential P&L, which help you understand how a strategy is performing.
    • +
    • Signal management: Functions to cancel or activate scheduled signals.
    • +
    • Reporting: Generate reports and save them to disk to analyze results.
    • +
    • Commit functions: Allow you to programmatically influence the backtest process, adding signals, or adjusting stop losses.
    • +
    +

    Essentially, this class is your go-to resource for efficiently running and analyzing backtests within the trading framework.

    +

    The BacktestReportService is designed to keep a detailed record of what's happening during your backtests. It essentially acts as a reporter, meticulously tracking the lifecycle of each trading signal – from when it’s initially idle to when it's opened, active, and finally closed.

    +

    This service connects to a central signal emitter to receive updates on these signal events. Every tick, including all its relevant details, is logged and saved to a SQLite database, providing you with a wealth of information for later analysis and debugging.

    +

    You can think of it as an observer pattern with logging capabilities. The subscribe function lets the service listen for signal events, but it makes sure only one listener is active at a time. When you want the service to stop listening, use unsubscribe to gracefully disconnect and prevent any further logging. The tick property handles the processing and logging of the events themselves, while loggerService handles debugging.

    +

    The BacktestMarkdownService helps you create and save detailed reports about your backtesting results. It automatically keeps track of closed trades for each strategy you're testing.

    +

    As your strategies run, this service listens for tick events and records information about each closed signal. It organizes this data into separate storage areas for each symbol, strategy, exchange, frame, and backtest run, keeping everything nicely isolated.

    +

    You can then request these reports, which are generated as markdown tables filled with details about your signals. These reports are saved as files to your logs/backtest directory.

    +

    The service also allows you to clear out all the accumulated data or just data for a specific combination of symbol, strategy, and settings, allowing you to refresh your results. Finally, you can subscribe to receive these tick events or unsubscribe when you no longer need them.

    +

    The BacktestLogicPublicService helps you run backtests in a straightforward way, handling a lot of the behind-the-scenes setup for you. It essentially simplifies the process by automatically managing important information like the strategy name, exchange, and frame used during the backtest.

    +

    Think of it as a wrapper around a more complex internal service. This wrapper takes care of making sure your trading strategy has the right context without you needing to constantly pass it around in every function call.

    +

    Here’s what you can do with it:

    +
      +
    • Initialization: It’s created without any specific arguments.
    • +
    • Logging: It includes tools for logging and managing the execution context.
    • +
    • Core Functionality: run() This method is the heart of the backtest. You give it a symbol (the asset you're trading) and it streams the results of the backtest, one step at a time. It takes care of injecting the necessary context into the strategy functions automatically, so you don't have to worry about it.
    • +
    • Dependencies: It relies on other services like TimeMetaService, FrameSchemaService, and ExchangeConnectionService to manage time, data structure, and exchange connections.
    • +
    +

    The BacktestLogicPrivateService manages the entire backtesting process, working asynchronously to handle large datasets efficiently. It first retrieves the necessary timeframes and then processes each timeframe one by one. When a trading signal is generated, it fetches the required historical data and executes the backtest logic.

    +

    The service then intelligently skips ahead to the timeframe when the signal closes, minimizing unnecessary computations. Importantly, the backtest results are streamed directly as they become available, rather than being stored in a large array, which helps conserve memory. You can also halt the backtest prematurely by stopping the generator.

    +

    The service relies on several core services like the StrategyCoreService, ExchangeCoreService, FrameCoreService, and others to handle specific tasks related to strategy execution, data retrieval, and time management. To operate it needs a symbol to backtest.

    +

    This service acts as a central hub for performing backtests within the framework. It provides a straightforward way to access and utilize backtesting capabilities, primarily designed to be used when setting up dependencies within your application.

    +

    It bundles together several other services responsible for tasks like logging, validating strategy configurations, and ensuring risks are appropriately managed.

    +

    You can use the validate function to confirm your strategy setup and risk parameters are correct – it remembers previous validations to speed things up.

    +

    The core function is run, which executes the backtest process itself, providing a stream of results representing how the strategy performed with specific context details, like the strategy, exchange, and frame being used.

    +

    The ActionValidationService helps you keep track of and double-check your action handlers – those pieces of code that actually do something when a trade happens. Think of it as a central place to register all your action handlers, making sure they're available before you try to use them.

    +

    It efficiently manages a list of these handlers, and it's smart about remembering its validation results to avoid repetitive checks.

    +

    Here's what it can do:

    +
      +
    • Register new handlers: You can add action schemas (definitions of your handlers) using addAction.
    • +
    • Verify existence: validate confirms an action handler exists before you attempt to run it.
    • +
    • View the registry: list lets you see all the action handlers you’ve registered.
    • +
    +

    The service also keeps a record of which handlers are available and performs validation, remembering the results to speed up future checks. It uses a loggerService for logging and internally uses a map called _actionMap for managing the registered action schemas.

    +

    The ActionSchemaService is like a central librarian for your trading actions, keeping track of all the rules and definitions. It ensures your actions are well-defined and work correctly.

    +

    It uses a special system to store action definitions in a way that prevents errors related to incorrect data types.

    +

    The service also checks that your action handlers only use approved methods, helping to avoid unexpected behavior. It allows private methods to be used internally.

    +

    You can register new action schemas, making sure they are properly structured and validated.

    +

    It also allows you to update existing action schemas without having to create them from scratch again.

    +

    Finally, you can retrieve existing action schemas whenever you need them.

    +

    The ActionProxy acts like a safety net when using custom actions in your trading strategy. It's designed to prevent errors in your custom code from crashing the entire backtest or live trading system. Think of it as a wrapper that catches any mistakes your code might make, logs them, and allows the rest of the system to keep running.

    +

    It's built to handle a wide range of events – initialization, signal generation (in different modes like backtest or live), breakeven and profit/loss targets, scheduled events, and even when dealing with risk management. The system is designed so you don't have to worry about your custom actions breaking everything if something goes wrong.

    +

    You don’t create ActionProxy instances directly; instead, they are created using the fromInstance method. This method takes your custom action code and wraps it, ensuring that all the important methods are protected by error handling. If a method isn’t implemented in your custom code, the ActionProxy handles it gracefully by returning null, ensuring no unexpected behavior. Every time a signal is generated, the ActionProxy catches and logs any errors that might occur, and gracefully continues executing.

    +

    The ActionCoreService is the central hub for managing actions within your trading strategies. It's responsible for coordinating the execution of actions defined within strategy schemas.

    +

    Essentially, it takes the list of actions specified in a strategy's configuration and makes sure they get executed at the right time, in the right order, and with the correct data.

    Here's a breakdown of what it does:

      -
    • Error Handling: It wraps almost every method of your action handlers in error-catching code. This means even if your code has a bug, the backtest won't abruptly stop.
    • -
    • Handles Different Events: It handles signal events (for live, backtest, and general modes), breakeven events, partial profit/loss events, scheduled pings, risk rejections, and cleanup processes (dispose).
    • -
    • Factory Pattern: You don't create ActionProxy instances directly; you use the fromInstance method, which is the correct way to wrap your action handlers.
    • -
    • signalSync Exception: Note that signalSync isn’t wrapped in error handling. Exceptions here are intentional, as they're meant to be caught by a specific system function related to limit order synchronization.
    • -
    -

    In essence, ActionProxy is a vital component ensuring that your strategies can be tested and refined without bringing down the whole backtest.

    -

    The ActionCoreService acts as a central coordinator for handling actions within your trading strategies. It essentially manages how actions are triggered and executed, ensuring they run in the correct order and that all necessary validations are performed.

    -

    Think of it as a traffic controller for your strategy's actions. It fetches the list of actions needed from the strategy's blueprint, verifies that everything is configured correctly (like making sure the strategy name, exchange, and frame are valid), and then sends those actions to the appropriate handlers.

    -

    Here's a breakdown of its key functions:

    -
      -
    • Initialization: initFn sets up the action handlers, preparing them for use.
    • -
    • Signal Routing: Methods like signal, signalLive, signalBacktest, and others (breakeven, partial profit, ping events, risk rejection) all route different kinds of events to the strategy's actions. Each one retrieves the action list and sequentially invokes the corresponding handler for each action.
    • -
    • Validation: validate checks that all parts of your strategy setup are correct to prevent errors during execution. It caches the results to avoid repeated checks.
    • -
    • Synchronization: signalSync ensures all actions agree on position changes, acting as a gatekeeper.
    • -
    • Cleanup: dispose cleans up all the action handlers after the strategy is finished running.
    • -
    • Data Clearing: clear allows you to remove action-related data, either for a specific action or globally.
    • -
    -

    Essentially, the ActionCoreService keeps everything running smoothly and in the right order when your trading strategy is in motion.

    -

    This service acts as a central hub for directing different actions within your trading strategies. It’s designed to route specific events (like signals, breakeven adjustments, or ping requests) to the correct action handler, ensuring the right logic is executed for each situation.

    -

    The service uses a clever caching system – memoization – to avoid repeatedly creating action handlers, which significantly boosts performance. The cache is keyed by the action name, strategy, exchange and frame, meaning actions are isolated per strategy and frame.

    -

    You provide the name of the action, and the service finds or creates the appropriate handler, making it a flexible and efficient way to manage actions in your backtesting and live trading environments. It also includes methods for initializing, disposing, and clearing cached action instances. It allows handling different event types, like regular signals and backtest-specific signals.

    -

    This class, ActionBase, provides a foundation for building custom actions within the backtest-kit trading framework. It's designed to simplify adding logic for things like sending notifications, logging data, or triggering custom actions based on strategy events.

    -

    Think of it as a starting point—you extend this class to create specialized handlers. It takes care of common tasks, like logging events, so you can focus on your unique logic.

    -

    Here’s how it works:

    -
      -
    1. -

      Construction: You're given the strategy name, frame name, action name, and whether you're in backtest mode.

      -
    2. -
    3. -

      init(): Use this method to set up your action, like connecting to a database or initializing an API. It's called once at the beginning.

      -
    4. -
    5. -

      Event Handlers: The class provides methods like signal(), signalLive(), signalBacktest(), breakevenAvailable(), etc. Each of these is called when a specific event occurs within the strategy. You override the ones you need to react to. For example, signalLive() is only called when the strategy is live.

      -
    6. -
    7. -

      dispose(): This method runs when the strategy finishes, allowing you to clean up resources, such as closing connections.

      -
    8. -
    -

    Essentially, ActionBase handles the boilerplate, so you can concentrate on defining the specific actions your strategy should take in response to different trading events. It simplifies creating custom logic for all aspects of your strategy’s behavior.

    +
  • Action Management: It retrieves and processes action lists defined within strategy schemas.
  • +
  • Validation: It verifies the strategy’s configuration, including names, exchanges, frames, and any associated risks or actions. It caches these validations to prevent unnecessary repeats.
  • +
  • Event Dispatch: It handles various events, like market signals, breakeven conditions, partial profit or loss adjustments, scheduled pings, and lifecycle events (opening/closing signals). Each event triggers the corresponding action handler on the registered actions.
  • +
  • Lifecycle Management: It offers functions to initialize, dispose of, and clear actions related to a strategy.
  • +
  • Synchronization: Some events like signalSync and orderCheck require agreement from all actions before proceeding, crucial for coordinated trading.
  • + +

    Think of it as a traffic controller ensuring all actions related to a specific trading strategy are handled efficiently and consistently.

    +

    The ActionConnectionService is responsible for directing different types of events – like signals, breakeven notifications, or scheduled tasks – to the correct action handler within your trading strategies. It's designed to be efficient by remembering (memoizing) which action handlers are needed for specific strategies and frames, so it doesn't have to recreate them every time.

    +

    When an event comes in, the service looks up the corresponding action handler based on its name, the strategy it belongs to, the exchange it's operating on, and the current frame. If the handler hasn't been created yet, it creates it and loads any necessary persistent data. Subsequent events with the same parameters will quickly use the already created handler.

    +

    It offers various methods for handling different events, including signal updates, profit/loss adjustments, scheduled tasks, and lifecycle events. Each method takes an event, indicates whether the process is in backtest mode, and provides context about the specific action and strategy involved. Finally, you can clear the remembered handlers if they are no longer needed, freeing up resources.

    +

    This framework provides a base class, ActionBase, to help you create custom actions within your trading strategies. Think of it as a starting point for handling various events and triggering specific responses, whether you're backtesting or live trading.

    +

    It simplifies the process by providing default logging for all events, and automatically passing essential information like strategy and frame names. You can extend ActionBase to manage things like state updates, send notifications (like to Discord or email), track metrics, and integrate custom logic.

    +

    The lifecycle involves initialization (init), event handling (signal, breakevenAvailable, etc.), and cleanup (dispose). Events like signalLive are for live trading only, while signalBacktest handles events specifically during backtesting. You can customize how each of these events are processed to tailor your strategy’s behavior. The dispose function is important for releasing resources when your strategy is finished.

    +

    The framework handles the technical details of delivering events to your custom actions, allowing you to focus on the strategy's logic. It's designed to be extensible, meaning you can add your own functionality without having to implement the entire interface from scratch.

    diff --git a/documents/private_functions.html b/documents/private_functions.html index c6247318425e208fef0458366429e3dd27c7824e..d4f135b9c45183b162bc76ec078274f55db95762 100644 --- a/documents/private_functions.html +++ b/documents/private_functions.html @@ -122,421 +122,436 @@
  • createAwaiter from functools-kit for async coordination
  • Background execution with Backtest.background() and event-driven completion detection
  • -

    backtest-kit functions

    This function lets you store data in a specific memory location, like writing to a labeled container. Think of it as saving a piece of information for later use within your trading strategy. It automatically figures out if you're running a test or a live trading session.

    -

    You’ll provide a name for the container (bucketName), a unique identifier for the memory location (memoryId), the data you want to save (value), and a brief description of what's being stored. The data you store can be any type of object.

    -

    This function handles the underlying details of managing signals, so you don’t have to worry about that. It's a convenient way to persist data within your strategy’s execution environment.

    -

    This function helps speed up backtesting by pre-loading historical candle data and storing it for quick access. It essentially downloads all the candles for a specific timeframe, from a starting date to an ending date, and saves them so they don't need to be re-downloaded during a backtest. This can significantly reduce the overall backtesting time.

    -

    You provide a set of parameters that define the starting and ending dates, as well as the candle interval you want to download and cache. This lets you focus on your trading strategies without the delay of constantly fetching the same data.

    -

    This function ensures that all necessary components are initialized before you begin trading, whether it's a backtest or a live trading session. It waits for the registries responsible for validating exchanges, trading strategies, and historical data frames to be fully populated.

    -

    During backtesting, it makes sure everything – exchanges, strategies, and historical data – is set up. For live trading, it only confirms that the exchange and strategy registries are ready, as historical data isn't needed.

    -

    It checks these registries every second, waiting for a maximum of a certain time. If everything isn't ready within that time, the function finishes without an error, and it's your responsibility to handle any resulting issues (like missing strategy configurations) later on. You can use this to prevent trading from starting before everything is properly loaded.

    -

    The isBacktest parameter lets you specify whether a frame schema is also needed, which is only relevant for backtesting scenarios.

    -

    This function helps ensure everything is set up correctly before you run a backtest or optimization. It checks that all the entities you’re using – like exchanges, strategies, and sizing methods – actually exist in the system.

    -

    You can tell it to validate specific entity types, or if you leave it blank, it will check everything.

    -

    Think of it as a safety net to prevent errors caused by missing or misconfigured entities, and the results are saved to make it faster next time. It's a good idea to run this validation before kicking off any tests.

    -

    This function lets you pause a trading strategy's signal generation.

    -

    It effectively halts the strategy from creating any new trades.

    -

    Any existing, open trades will still finish up as usual.

    -

    The system gracefully stops the backtest or live trading session at a suitable point, like when it's idle or a trade is closed.

    -

    You simply provide the trading pair symbol (like BTC-USDT) to specify which strategy you're pausing.

    -

    This function provides a way to safely end a backtest run. It signals to all parts of the testing framework that it's time to wrap up and clean up any resources. Think of it as a polite exit – it lets everything know to prepare for the program to finish without any hiccups, especially when the testing is being stopped unexpectedly. This is useful for handling things like signals that tell the program to stop.

    -

    This function helps you manage and update information related to a specific trading signal. It's particularly useful when you're building strategies that track metrics over time, like how long a trade is open or its maximum gain.

    -

    It works by updating a piece of data associated with the currently active signal. Think of it like saving a specific detail about a trade.

    -

    The function handles the details of knowing whether you're in a backtesting environment or a live trading situation.

    -

    If there's no active signal, it will let you know with a warning. This function aims to support advanced strategies that collect information across multiple trades to optimize outcomes, targeting specific drawdown and profit goals.

    -

    The setSessionData function lets you store information that lasts between candles during a backtest or live trading run. Think of it as a way to keep track of things like intermediate calculations or LLM inference results that you need to remember even if your process restarts. You specify which trading pair (symbol) the data belongs to, and then provide the value you want to store, or pass null to remove the data. It automatically knows whether it's running in a backtest or live environment.

    -

    You can now control where and how the backtest-kit framework's internal logging appears. This function lets you plug in your own logging system, like sending logs to a file, a database, or a specialized monitoring tool. The framework will automatically add helpful details to each log message, such as the trading strategy being used, the exchange involved, and the specific asset being traded – making it easier to track down issues and understand what's happening during backtesting. Just provide an object that implements the ILogger interface, and the framework will handle the rest.

    -

    This function lets you adjust how the backtest-kit framework operates by changing its global settings. Think of it as tweaking the underlying machinery. You can provide a new set of configuration values – not all at once, just the ones you want to change – and this function will update the framework accordingly. There's a special _unsafe flag; only use this if you're running tests and need to bypass some safety checks – it's generally best to avoid it otherwise.

    -

    This function lets you customize the columns that appear in your backtest reports, like when you generate markdown reports. Think of it as tweaking what information you see in those reports – you can change the order, names, or even which data points are displayed. You provide a set of new column definitions, and the framework will apply them to your reports. It's designed to be flexible, allowing you to override the default settings.

    -

    For most use cases, the framework checks your new column definitions to make sure they're valid. However, in some specialized testing scenarios, you might need to bypass this validation—there's an option to do so, but use it with caution.

    -

    The searchMemory function helps you find relevant data stored in your memory system based on a search query. It uses a powerful technique called BM25 to rank the results, ensuring the most pertinent entries are returned first.

    -

    The function intelligently figures out which signal to search for and whether you're running a backtest or a live trading environment, so you don’t have to specify those details.

    -

    You provide a bucket name (where the data is stored) and your search query, and it returns an array of results. Each result includes a unique ID, a score indicating how well it matches the query, and the actual data content itself.

    -

    This function lets you run code as if it were part of a backtest or live trading environment, but without actually running a full backtest. It's designed for testing and development.

    -

    Think of it as creating a temporary, simplified version of your trading system.

    -

    You can customize the settings to mimic different scenarios – exchange, strategy, timeframe, even whether it’s a backtest or a live environment. If you don’t provide any settings, it defaults to a basic live-mode setup.

    -

    The run parameter takes a function that you want to execute inside this mock environment, allowing you to safely test context-dependent code.

    -

    This function lets you delete a specific memory entry associated with a signal. Think of it as cleaning up old data related to a particular trading signal. It handles the complexities of knowing whether you're in a testing environment or a live trading scenario, taking care of resolving any pending signals automatically.

    -

    Here's what you need to provide:

    +

    backtest-kit functions

    The writeMemory function lets you store data within a specific memory space, associating it with the current signal being processed. Think of it as writing information to a labeled container that's linked to a particular trading event. It handles the details of which signal is active and whether you're running a test or a live trade, so you don't have to worry about that. You provide a bucket name, a unique memory ID, the value you want to store (which can be any object), and a descriptive label to identify what’s being saved. This function simplifies keeping track of data relevant to a particular signal.

    +

    This function helps prepare your backtesting environment by downloading and storing historical candlestick data. Think of it as pre-loading the data you'll need for your backtests, making the process faster and smoother. It fetches all the candles for a specified time period, from a starting date (from) to an ending date (to), and saves them for later use. You provide it with a set of parameters to define the date range and other settings for this data retrieval and caching process.

    +

    This function ensures everything is set up correctly before you start trading, whether it's a backtest or a live session. It waits patiently, checking the system's registries – those are like lists of necessary components – until they’re all filled with the right information.

    +

    For backtesting, it makes sure the registries for exchange data, historical frames, and trading strategies are ready. If you're running a live session, it only needs to confirm the exchange and strategy registries are in place.

    +

    Think of it as a safety check to prevent errors later on. It pauses execution for a limited time, around a minute, while waiting for these registries to become available. If it doesn’t get confirmation in that time, it moves on and lets you handle any potential errors that arise when you try to start the trading process. The isBacktest option lets you specify if you need frame data to be validated.

    +

    This function helps you double-check that everything is set up correctly before you start running tests. It makes sure all the different pieces of your trading system – like exchanges, strategies, and risk management rules – are properly registered and exist.

    +

    You can tell it to validate specific parts of your system, or if you leave it blank, it will check everything.

    +

    Think of it as a safety net to prevent errors during backtesting or optimization by ensuring everything is in its place. It also remembers past validation checks to work faster.

    +

    This function lets you pause a trading strategy from creating any new trade signals.

    +

    It essentially puts a hold on the strategy's actions, preventing it from opening new positions. Any existing signals that are already active will finish their process normally.

    +

    Whether you're running a backtest or a live trading session, the system will gracefully halt the strategy at a convenient moment – either when it’s idle or after a signal has completed. To stop a strategy, you just need to provide the trading symbol (like BTCUSDT).

    +

    This function allows you to safely stop the backtesting process. It sends a signal that lets everything involved – like data handlers or strategy components – know it's time to clean up and prepare to exit. Think of it as a polite way to tell the system to wrap things up before it closes. This is useful when you need to stop the backtest unexpectedly, like when pressing Ctrl+C.

    +

    This function lets you update a value associated with a specific trading signal. It's designed to be used when you're building strategies that need to track metrics on a per-trade basis, particularly those driven by language models.

    +

    The function automatically handles things like determining whether you're in backtest or live mode, and resolving the current trading signal. If there isn’t a signal currently active, it will notify you.

    +

    Think of it as a way to store information tied to a particular trade, like how long it was open or how much it gained, and it works best when you’re building complex strategies that require detailed tracking of trade performance. It helps keep track of metrics across many trades.

    +

    The setSessionData function lets you store information related to a specific trading setup—like a particular symbol, strategy, exchange, and timeframe—so it’s remembered between candles during a backtest or even if your program restarts in live trading mode. This is great for holding onto things like calculated indicator values or the results of complex computations that you don't want to recalculate every time. You can clear any previously stored data by passing null as the value. The function intelligently adapts to whether it’s running in a backtest or live environment.

    +

    It takes two arguments: the symbol of the trading pair you’re working with and the value you want to store. The value can be any object, or you can clear the data entirely by passing null.

    +

    You can now control how backtest-kit reports its activity by providing a custom logger. This lets you direct log messages – like information about strategies, exchanges, or symbols – to your preferred logging system. The framework automatically adds helpful context to each log message, like the strategy's name or the exchange being used. To use your own logger, simply provide an object that fulfills the ILogger interface.

    +

    This function lets you adjust the overall settings for the backtest-kit framework. You can use it to change things like data fetching or how strategies are executed. It accepts a configuration object where you can specify the properties you want to modify; you don't need to provide the whole configuration, just the parts you want to change. There's also an "unsafe" option which is mainly for testing environments and bypasses some of the standard checks – use it with caution.

    +

    This function lets you customize the columns that appear in your backtest reports, particularly when they are exported as markdown. Think of it as tailoring the report to show exactly the data you need. You can change or add to the default column settings, and the system will check to make sure your changes are valid. If you’re doing some advanced testing and need to bypass these validations, there’s a special option to do so.

    +

    The searchMemory function helps you find relevant information stored in your memory system. It’s designed to quickly locate entries that match a specific query, using a sophisticated scoring system to prioritize the most relevant results.

    +

    Think of it like a smart search engine for your trading data – you give it a query and it finds memory entries that best match.

    +

    It works by searching through data stored in a "bucket" (identified by bucketName) and using a query string to find matching content.

    +

    The function returns a list of memory entries, each including a unique ID (memoryId), a relevance score (score), and the content itself (content).

    +

    It's also smart about how it operates; it knows whether it's running a backtest or a live trading scenario and can automatically resolve pending or scheduled signals.

    +

    This function lets you execute code as if it were running within a backtest-kit environment, but without actually needing a full backtest to run. It’s especially handy for testing and scripting scenarios where you need to use context-aware services like determining the current timeframe.

    +

    You can customize the simulated environment by providing parameters like the exchange name, strategy name, symbol, or whether it should behave like a live or backtest mode. If you don't provide any of these, it will use default placeholder values to create a basic live-mode setup. The "when" parameter defaults to the current minute, aligning with a one-minute interval.

    +

    This function helps you clean up data related to your trading strategies. Specifically, it removes a record of a past memory entry, essentially forgetting something that was previously considered. It's designed to work seamlessly whether you're testing your strategy in a simulated environment or running it live. The function takes information about which memory entry to delete – identifying it by a bucket name and a unique memory ID – and handles the rest, adjusting based on the environment it’s operating in.

    +

    The readMemory function lets you retrieve data that's been stored in a specific memory location, associating it with the current trading signal. Think of it like looking up a saved value tied to a particular moment in your trading strategy. It handles the complexities of figuring out which signal is currently active and whether you're running a backtest or live trading session, so you don't have to worry about those details. To use it, you provide the name of the memory bucket and the unique ID of the memory item you want to read. The function will then return the stored data, which must match a predefined TypeScript type.

    +

    This function lets you tweak an existing "walker" – think of it as a setup for comparing different trading strategies. It allows you to modify specific parts of a walker’s configuration without affecting everything else. You give it a partial configuration, and it returns a complete walker configuration with your changes applied. It's helpful when you want to experiment with slight variations in how your strategies are tested.

    +

    This function lets you modify an existing trading strategy within the backtest-kit framework. Think of it as tweaking a strategy you've already set up, rather than creating a new one from scratch. You provide a portion of the strategy's configuration – only the parts you want to change – and this function updates the original strategy, leaving everything else untouched. It's a way to make adjustments and refinements without needing to redefine the entire strategy.

    +

    This function lets you adjust how your trading positions are sized without completely replacing the original settings. Think of it like fine-tuning an existing sizing plan. You provide a partial configuration – just the settings you want to change – and this function merges those changes with the existing sizing schema. This is useful if you need to tweak things like risk percentages or order sizes based on market conditions or other factors without rewriting the whole sizing plan from scratch. The original sizing schema remains largely untouched, with only the values you specify being modified.

    +

    This function lets you tweak an existing risk management setup within the backtest-kit. Think of it as making targeted adjustments – you provide a set of new settings, and only those specific settings get updated in the existing risk configuration. It’s useful when you need to fine-tune aspects of your risk management without having to redefine the whole thing from scratch. You're essentially providing a set of changes to apply to an already defined risk profile.

    +

    This function lets you tweak how data is structured for a specific timeframe during backtesting. Think of it as a way to make small adjustments to an existing timeframe's settings – you're not creating a brand new timeframe, just modifying one that's already defined. You provide a partial configuration, and only those parts you specify will be changed, while everything else remains as it was previously set up. This is useful for fine-tuning how your backtest handles data for different time intervals.

    +

    This function lets you modify an already set up data source for an exchange within the backtest-kit system. Think of it as a way to tweak the details of how your exchange data is handled.

    +

    You can't completely replace the existing exchange data, only specific parts you define. Any settings you don't provide will stay as they were originally configured.

    +

    It takes a piece of exchange configuration data as input, and it returns a promise that resolves to the updated exchange schema.

    +

    This function lets you tweak existing action handlers within the backtest-kit framework without completely replacing them. Think of it as a targeted update – you can change specific parts of a handler’s configuration.

    +

    It's handy when you need to adjust how events are handled, maybe to test different logic in development versus production, or to swap out different implementations of a handler. You only need to provide the changes you want to make; everything else stays the same. This avoids the need to re-register the entire action handler, making changes quicker and easier.

    +

    This function lets you keep track of how your backtest is progressing. It will notify you whenever a strategy finishes running during the backtest process.

    +

    These updates happen one after another, ensuring events are processed in the order they come in, even if your processing involves asynchronous operations.

    +

    Think of it as a way to get a stream of notifications as your backtest completes each strategy, allowing you to display progress or perform other actions.

    +

    To stop listening for these progress events, the function returns a cleanup function that you can call.

    +

    listenWalkerOnce lets you react to specific events happening during a backtest, but only once. It’s like setting up a temporary listener that waits for a particular condition to be met. You provide a filter to define what events you're interested in, and a function to run when that event occurs. Once the event is processed, the listener automatically disappears, ensuring you don’t keep reacting to the same thing repeatedly.

    +

    It's helpful when you need to perform an action based on a single, distinct event in the backtest process.

    +

    The first argument, filterFn, defines which events should trigger your reaction. The second argument, fn, is what actually gets executed when a matching event is found. The function returned by listenWalkerOnce can be used to unsubscribe manually if needed, though it’s designed to unsubscribe itself.

    +

    This function lets you get notified when a backtest run finishes. It's useful for knowing when all your strategies have been tested. When you subscribe, the function you provide will be called once the testing is complete.

    +

    Even if your callback function takes some time to run (like if it's doing something asynchronously), the events will be handled one after another in the order they arrived. To keep things organized and avoid conflicts, it queues up the execution of your function.

    +

    You can unsubscribe from these notifications at any time by returning the function it provides.

    +

    The listenWalker function lets you keep track of what's happening as your backtest runs. It's like setting up an observer that gets notified after each strategy finishes executing within the backtest.

    +

    You provide a function that will be called with information about the completed strategy.

    +

    Importantly, this function will be executed one at a time, even if your callback itself takes some time to complete, ensuring the process stays orderly. This provides a reliable way to monitor and react to the progress of your backtesting process.

    +

    This function lets you keep an eye on any problems that pop up during the risk validation process, specifically when signals are being checked.

    +

    It's like setting up an alert system: whenever a validation check fails, this alert will trigger and your provided function will be called.

    +

    The errors you receive will include details about what went wrong.

    +

    Importantly, these alerts are handled in the order they occur, and they are processed one at a time to avoid things getting messy with multiple simultaneous alerts. You provide a function that will be executed when an error is detected. This function will receive the error object as a parameter.

    +

    This function lets you set up a listener that will only react to a signal once, and only when it meets a specific condition you define. Think of it as a temporary guardrail for your trading logic. If your callback function involves asynchronous operations like promises, backtest-kit will pause everything else until that operation finishes, ensuring your synchronization is accurate. This is particularly helpful when coordinating with external systems that need to be in sync with your trading actions. Once triggered, the listener is automatically removed, so you don’t have to worry about cleaning it up.

    +

    This function lets you listen for events related to signal synchronization, like when a trade signal is about to be opened or closed. It's designed to help you coordinate with other systems that might need to be involved in the trading process.

    +

    If you provide a function that returns a promise, the trading system will pause and wait for that promise to finish before proceeding with the trade – this ensures everything is in sync. The warned parameter is currently not used. It's a handy tool for keeping your trading operations coordinated and reliable.

    +

    This function lets you react to specific changes happening within your trading strategies, but only once. You tell it what kind of change you're interested in using a filter, and then provide a function that should run when that specific change occurs. Once that change happens, it automatically stops listening, so you don’t have to worry about managing the subscription yourself. It's a simple way to wait for something to happen with your strategies and then take action.

    +

    The filter helps you pinpoint the exact event you're looking for. The callback function then handles that event, performing whatever action you need.

    +

    This function lets you keep an eye on what's happening with your trading strategy's management actions. It's like setting up a listener that gets notified whenever something like a scheduled signal is cancelled, a pending order is closed, or adjustments are made to stop-loss or take-profit levels.

    +

    The notifications you receive include things like partial profit or loss closures, trailing stop adjustments, and when the stop-loss moves to break-even.

    +

    Importantly, the callback you provide will be executed one at a time, even if it takes some time to run, which helps prevent conflicts and keeps things organized. You can unsubscribe from these events when you no longer need them by calling the function it returns.

    +

    This function lets you react to specific trading signals just once. You provide a filter – a test to see if a signal is what you’re looking for – and a function to execute when that signal appears. Once the signal matching your filter arrives, the function runs and automatically stops listening, making it ideal for situations where you need to respond to a signal and then move on. It's a handy way to handle one-off events in your trading strategy.

    +

    This function lets you set up a temporary listener for signal events. You provide a rule (the filterFn) to decide which events you're interested in. Once an event matches your rule, a provided function (fn) will run exactly once to handle that event. After that single execution, the listener automatically stops, so you don't have to manage subscriptions manually. It's perfect for reacting to a signal just once and then forgetting about it.

    +

    This function lets you listen for notifications whenever a trading strategy sends out a signal note about an active trade. Think of it as a way to be informed about specific events happening within your strategy's execution.

    +

    It works by queuing up these notifications so they're processed one at a time, even if your notification handling code takes some time to complete. This prevents things from getting messy or out of order.

    +

    To use it, you provide a function that will be called each time a new signal notification is available, and this function receives information about the signal event. When you're done listening, you can unsubscribe using the function returned by listenSignalNotify.

    +

    The listenSignalLiveOnce function lets you temporarily hook into live trading signals from your backtest, but only for a single event. Think of it as setting up a temporary alert that fires just once when a specific condition is met during a live simulation. It's useful for quickly inspecting data or triggering a one-time action without needing to manage subscriptions manually. You provide a filter – a way to pick which signals you’re interested in – and a function that will be executed only the first time that signal passes through. After that, the subscription is automatically removed, so you don’t need to worry about cleaning up. It works specifically with signals coming from Live.run().

    +

    This function lets you tap into a live trading simulation, receiving updates as they happen. It's designed to process these updates one at a time, ensuring events are handled in the correct order. You provide a function that will be called with each new event, allowing you to react to the trading signals as they arrive from a live run. Keep in mind that these signals are exclusive to executions started by Live.run(). The function you provide returns a function that can be called to unsubscribe from these live signals.

    +

    This function lets you react to a specific event happening within the backtest, but only once. It's like setting up a temporary listener that automatically goes away after it hears what you're looking for. You tell it what kind of event you're interested in using a filter, and then provide a function that will run when that event occurs. After the function runs once, the listener is removed, so you don’t have to worry about cleaning it up. It’s handy if you need to wait for a particular trade to open or close and then do something specific.

    +

    This function lets you keep an eye on what’s happening with your trading signals, both when they’re first created and when they’re finished. You’ll receive notifications whenever a signal is opened, like when a new trade is triggered or you manually activate one, and also when it closes, whether it's due to a profit target, a stop-loss, or just time running out.

    +

    Importantly, these events are delivered to you in the order they happen, even if your response to them takes some time. To use it, you simply provide a function that will be called with details about each signal event. When you're done listening, the function returns another function that you can use to unsubscribe.

    +

    This function lets you set up a listener that only reacts to specific signals coming from a backtest run. Think of it as setting up a temporary alert – it will only fire once when a signal matches your criteria.

    +

    You tell it what kind of signals you're interested in using a filter function.

    +

    Then, you provide a callback function that will execute with that matching signal.

    +

    Once the callback runs, the listener automatically stops, preventing further executions. It's a clean and simple way to react to a single, specific event during a backtest.

    +

    This function lets you set up a listener to receive updates as a backtest is running. Think of it as plugging into a stream of information about what's happening during the simulation.

    +

    The information you get will be in the form of IStrategyTickResult objects, which contain details about each step of the backtest.

    +

    Importantly, the events are processed one at a time, ensuring a predictable order. You’ll only receive signals that come directly from a running backtest.

    +

    The function returns another function that you can call to unsubscribe from the signal listener when you're done.

    +

    The listenSignal function lets you be notified whenever your trading strategy has a significant change in its state, such as opening a position, closing a position, or transitioning to an active state. It's designed to handle these events, called "ticks," in a reliable way, ensuring they are processed one at a time even if your handling code takes some time to complete. Essentially, you provide a function that will receive these updates, and this function automatically manages the order of processing to avoid any unexpected issues. This allows you to react to your strategy's changes in a controlled and predictable manner.

    +

    This function helps you react to specific ping events, but only once. Think of it as setting up a temporary listener that waits for a particular condition to be met, then runs your code, and then automatically stops listening. You provide a filter to define what kind of ping events you’re interested in, and a function to execute when that event is detected. Once the event happens, the listener disappears. This is ideal for situations where you only need to react once to a specific event.

    +

    This function lets you listen for regular "ping" signals that are sent while a scheduled trading signal is being monitored and prepared for activation. Think of it as a heartbeat signal confirming the system is still working while waiting.

    +

    You provide a function that will be called every minute with information about the ping event.

    +

    This allows you to track the progress of a scheduled signal and build custom checks or monitoring logic related to that process.

    +

    The function returns an unsubscribe function, which you can use to stop receiving these ping signals when you no longer need them.

    +

    This function lets you react to a specific scheduled event just once and then stop listening. You provide a filter to identify the event you're interested in, and a function to run when that event occurs. It's perfect when you need to wait for something like a specific trade to be created or cancelled, and then you don’t need to keep monitoring. The function handles automatically unsubscribing, so you don't have to worry about cleaning up your listener.

    +

    This function lets you keep an eye on what's happening with your scheduled trading signals. You’ll get notified when a signal is initially created and when it's cancelled before it actually starts running—for example, if it times out or doesn't meet a price condition or a user cancels it.

    +

    It's important to know that you won’t see notifications about when a signal starts running; those are handled by a different function. The callback you provide will be called with information about the event, and it will run in order.

    +

    The function returns a function that you can use to unsubscribe from these events later.

    +

    The listenRiskOnce function helps you react to specific risk rejection events just once and then automatically stop listening. It takes a filter function that determines which events you're interested in, and a callback function that runs when a matching event occurs. This is handy when you need to wait for a particular risk condition to be met and then take action, after which you don't need to keep monitoring. The function returns an unsubscribe function that you can call if you need to stop listening manually before the single execution.

    +

    This function lets you be notified whenever a trading signal is blocked because it doesn't meet your risk criteria.

    +

    Think of it as a safety net – you'll only hear about it when something goes wrong and a trade is prevented.

    +

    The events are delivered one at a time, ensuring your reaction to the risk event is handled in a controlled manner, even if your response involves asynchronous operations. It’s designed to avoid unnecessary notifications when trades are approved. You provide a function that will be called with details about the rejected trade.

    +

    This function lets you keep an eye on how your trading strategy performs. It sends you updates as your strategy runs, tracking things like how long different parts take to complete. Think of it as a performance monitor – you can use this information to find slow spots and optimize your strategy. The updates are delivered one at a time, even if the information you receive requires some extra processing. This ensures that the updates are handled in a controlled way. To use it, you provide a function that will be called with performance event data. When you're done, the function returns another function to unsubscribe.

    +

    This function lets you set up a listener that reacts to specific profit levels being reached during a backtest. You provide a filter to define exactly which profit conditions you’re interested in. Once that condition is met, the provided function is executed just once, and then the listener automatically stops listening. It's a simple way to trigger actions or record information when a certain profit milestone is hit.

    +

    This function lets you be notified whenever your trading strategy hits certain profit milestones, like reaching 10%, 20%, or 30% profit. It's designed to handle these notifications one at a time, even if the process of handling the notification takes some time. You provide a function that will be called with information about the profit milestone reached. This ensures things are processed in the correct order and avoids potential conflicts.

    +

    This function allows you to monitor for specific partial loss events within your trading strategy and react to them just once. It’s like setting up a temporary alert – when an event that matches your criteria occurs, your provided function will be executed, and then the alert automatically disappears. You define what constitutes a “matching” event using a filter function, and the callback function handles the event data. This is helpful if you only need to respond to a particular loss scenario once.

    +

    This function lets you keep track of how much your trading strategy has lost during a backtest. It will notify you whenever a specific loss level is reached, like 10%, 20%, or 30% of the initial capital.

    +

    The events are delivered one after another, and your callback function will be executed in order, even if it takes some time to run. To prevent issues from running things at the same time, the system ensures that your callback is processed sequentially.

    +

    You provide a function as input, and that function will be called each time a new loss level is hit, giving you information about the loss amount. The function you provide will return a function to unsubscribe from these events.

    +

    This function helps you react to specific maximum drawdown events, but only once. It lets you define a condition – a filter – that determines when you want to be notified. Once that condition is met, a provided function runs to handle the event, and then the function automatically stops listening. It’s great for situations where you need to respond to a particular drawdown situation just one time.

    +

    You provide a filter function to check each drawdown event and a callback function that will be executed when the event matches the filter. The callback is triggered once and then the subscription is ended.

    +

    This function lets you keep an eye on when your backtest reaches new drawdown lows. It's like setting up an alert that triggers whenever the worst point in your trading history changes.

    +

    The events are handled one at a time, even if your alert function takes some time to process.

    +

    You can use this to monitor how much your trading strategy has lost from its peak and adjust your risk management accordingly. To use it, you provide a function that will be called whenever a new drawdown level is detected. The function will receive an event object containing details about the drawdown. When you are done, the function returns another function that you can call to unsubscribe from the events.

    +

    This function lets you react to events indicating periods of inactivity within your application. It listens for "idle ping" events and applies a filter to decide which events trigger an action. Once a matching event is found, it executes a provided function just once, then stops listening. This is useful for actions that need to occur only when inactivity is detected and only once. You specify a filter to determine which idle ping events should be acted upon, and a function to run when a suitable event occurs. When the function returns, the subscription is automatically cancelled.

    +

    This function lets you listen for moments when your backtest system isn't actively processing any trading signals.

    +

    Essentially, it triggers a notification when everything is quiet and the system is idle.

    +

    You provide a function that will be called each time this idle state occurs.

    +

    This allows you to perform tasks like logging or housekeeping during periods of inactivity.

    +

    The function returns an unsubscribe function so you can stop listening when you no longer need to.

    +

    This function lets you set up a temporary listener that reacts to events indicating the highest profit achieved. You provide a filter to specify which events you're interested in, and a function to execute when that event occurs. Once the event happens, the listener automatically stops itself, so you don’t have to worry about managing subscriptions. It's perfect for situations where you need to react to a particular profit milestone just once and then move on.

    +

    The filter function determines which events trigger the callback. The callback function handles the event data when the filter matches.

    +

    This function lets you monitor when a trading strategy reaches a new peak in profitability. It's like setting up an alert that triggers whenever the strategy's profit gets higher than it ever has before.

    +

    The alerts are handled one at a time, even if your alert logic takes some time to complete – this prevents things from getting messy. You provide a function that gets called whenever a new highest profit is achieved, allowing you to track these milestones and potentially adjust your trading strategy on the fly. It’s helpful for keeping tabs on how well your strategy is performing and responding to significant profit jumps.

    +

    The listenExit function lets you register a callback that will be triggered when the backtest or other background processes encounter a fatal, unrecoverable error – the kind of error that stops the whole process. Think of it as an error notification for situations where recovery isn't possible. These errors are handled one after another, even if your callback function needs time to process the error, ensuring a consistent order of events. It’s designed to reliably alert you to these critical issues.

    +

    This function lets you set up a listener that gets notified whenever a recoverable error occurs during your trading strategy's execution. Think of it as a safety net—if something goes wrong, like a failed API call, the strategy doesn't just crash.

    +

    Instead, this listener gets triggered, allowing you to handle the error and keep things running smoothly.

    +

    The errors are handled one at a time, in the order they happen, even if your handling function takes some time to complete. It makes sure things stay predictable and avoids unexpected problems. To stop listening for these errors, the function returns another function that you can call to unsubscribe.

    +

    This function lets you react to when a background task finishes, but only once.

    +

    It allows you to specify a condition – a filter – so you only receive notification when a specific type of task completes.

    +

    When the task finishes and matches your filter, a provided function will execute just one time, and then automatically stop listening. This is helpful for things like confirming a particular step in a sequence has finished without needing to manage subscriptions yourself.

    +

    This function lets you monitor when background tasks within a trading strategy's "walker" component finish processing. It's designed to handle events that signal the completion of these background tasks, ensuring they are processed one at a time, even if your callback function takes some time to execute. Essentially, you provide a function that gets called when a background task is done, and this function returns another function you can use to unsubscribe from these completion notifications. This helps maintain order and prevent unexpected behavior when dealing with asynchronous operations.

    +

    This function lets you react to when a background task finishes running within your backtest.

    +

    It’s a way to listen for completion signals specifically from Live.background().

    +

    You provide a filter – a way to specify which completion events you're interested in – and a function that will be called just once when a matching event occurs. After that single execution, the listener automatically stops listening, preventing unwanted repeated callbacks.

    +

    This function lets you be notified when background tasks initiated through Live.background() finish running. It ensures events are handled one at a time, even if your notification code takes some time to process. Think of it as a way to get a sequential update on the status of those ongoing background operations. You provide a function that will be called whenever a background task is done, and this function returns another function to unsubscribe from those updates.

    +

    This function lets you react to when a background backtest finishes, but only once. You provide a filter to specify which backtest completions you're interested in, and then a function that will run when a matching backtest is done. After that function runs, it automatically stops listening, so you won't get any more notifications about that particular backtest. It's useful when you need to perform a single action after a specific background backtest completes.

    +

    This function lets you be notified when a background backtest finishes running.

    +

    It's useful for triggering actions after a backtest is complete, like updating a UI or saving results.

    +

    The events are delivered in the order they happen, and the code handles asynchronous callbacks gracefully to avoid any problems with multiple things running at once. You provide a function that will be called when a backtest is done, and this function returns another function you can use to unsubscribe from the events later.

    +

    This function lets you set up a listener that reacts to breakeven protection events, but only once. You define a filter to specify which events you're interested in, and then provide a callback function that will be executed when a matching event occurs. After that one execution, the listener automatically stops listening – perfect for situations where you only need to respond to a single instance of a condition being met. It's a convenient way to handle specific breakeven events and then forget about them.

    +

    You give it a function that determines if an event is what you want, and then another function that will run when the right event happens. The listening stops after the callback is run.

    +

    This function lets you monitor when a trade's stop-loss automatically adjusts to the original entry price, a process known as breakeven protection. It’s designed to notify you when this happens, essentially signaling that the trade has made enough profit to cover its costs.

    +

    The events are handled in the order they occur, even if your callback function takes some time to complete. To ensure smooth processing, it uses a queuing mechanism to prevent multiple callbacks from running at once.

    +

    You simply provide a function as input—this function will be called whenever a breakeven event happens, giving you the details of the trade that reached this point. The function you provide will return a function that you can call to stop listening to these events.

    +

    This function lets you react to specific events that happen right before a backtest begins, but only once. You provide a filter to specify which events you're interested in, and then a callback function that will run just one time when a matching event occurs. After that single execution, the function automatically stops listening, keeping your backtest clean and efficient. It's a handy way to perform setup tasks or adjustments just before a backtest kicks off.

    +

    This function lets you hook into the moment right before a trading strategy begins running for a specific asset. You can provide a function that gets called just before each new trading session starts. This function will be executed one after another, ensuring that they run in the order they were received, even if your function involves asynchronous operations. It prevents multiple functions from running at the same time, which can help keep things predictable.

    +

    This function lets you monitor the progress of your backtest as it runs. It's particularly useful for longer backtests where you want to see updates and status changes. You provide a function that will be called whenever a progress event occurs during the background execution of the backtest. Importantly, these events are handled one at a time, even if your callback function takes some time to complete, ensuring that updates are processed in the order they're received. The function returns another function that you can use to unsubscribe from these progress updates when you no longer need them.

    +

    This function lets you react to events that happen after a trading simulation or backtest finishes, but only once. You tell it which events to look for using a filter – essentially, a test to see if the event is relevant to you. Once an event matches your filter, the provided callback function runs, handling that single event, and then the subscription is automatically cancelled. This is a convenient way to perform actions like logging specific results or cleaning up resources without needing to manage subscriptions manually.

    +

    This function lets you tap into what happens after a trading strategy has finished running for a specific asset. Think of it as getting a notification once the engine is completely done with a particular symbol's backtest. Importantly, any code you put inside your notification function will run one at a time, in the order they were received, which is helpful if you need to process things carefully. It’s a way to react to the completion of a backtest run for a specific asset. You provide a function that will be called when that event occurs.

    +

    This function lets you watch for specific active ping events and react to them just once. You provide a filter to define which events you're interested in, and a callback function that will be executed when a matching event occurs. Once the callback runs, the subscription stops automatically, so you don't have to worry about cleaning up. It's perfect for situations where you need to trigger an action only when a particular active ping condition arises.

    +

    This function lets you keep an eye on active trading signals. It listens for events that happen every minute, giving you insights into the status of your signals. Think of it as a way to track what's happening with your trading strategies in real-time.

    +

    The function will call a callback you provide whenever a new active ping event occurs. Importantly, these events are processed one at a time, even if your callback takes some time to complete, so you won't have issues with things happening out of order or overlapping.

    +

    To use it, you simply provide a function that will be executed when a new ping event is detected. This allows for building logic that reacts to changes in the status of active signals. The function returns another function that you can call to stop listening to these events.

    +

    This function gives you a complete list of all the "walkers" that are currently set up in your backtest-kit environment. Think of walkers as specialized tools for analyzing and processing data during a backtest.

    +

    It's a handy way to see exactly what's happening behind the scenes, allowing you to understand how your data is being handled or to create interfaces that dynamically display the available analysis tools. You can use it to inspect the configuration or create visual representations of your trading strategies.

    +

    This function gives you a way to see all the different trading strategies that are currently set up and ready to be used within the backtest-kit framework. Think of it as a directory listing all the available strategies. It’s especially helpful if you're trying to understand what strategies are available, build tools that need to know about them, or just double-check everything is configured correctly. The result is a list of strategy definitions that you can use within your application.

    +

    This function lets you see all the different sizing strategies you've set up for your backtest. It's like getting a complete inventory of how you're determining position sizes. You can use this to double-check your configuration, create helpful documentation, or even build tools that automatically display sizing options. The function returns a list of sizing schemas, each representing a specific sizing strategy.

    +

    This function helps you see all the risk configurations currently loaded into the backtest-kit framework. It essentially provides a complete list of the risk profiles you’ve set up. This is great for checking what's active, generating documentation, or creating user interfaces that need to display these configurations. The function returns a promise that resolves to an array of risk schemas.

    +

    This function helps you see all the stored data related to your trading signal.

    +

    Think of it as a way to peek inside the framework’s memory to see what's been saved.

    +

    It automatically figures out which signal you're working with and whether you're in a testing or live trading environment.

    +

    You provide a name for the data bucket to look in, and it returns a list of all the entries, including their unique IDs and the data they contain. It's useful for debugging or understanding how data is being managed within the backtest kit.

    +

    This function allows you to see a complete catalog of the data structures, or "frames," that your backtesting system is using. Think of it as a way to peek behind the curtain and understand what kinds of information is being processed during a backtest. It provides a list of all the schemas that were previously added using addFrame(), which is invaluable for troubleshooting, generating documentation, or creating interfaces that adapt to different backtesting setups. You'll get a collection of frame schema definitions that you can then examine.

    +

    This function gives you a look at all the exchanges that your backtest-kit setup knows about. It returns a list of information describing each exchange, allowing you to inspect them. You can use this when you're troubleshooting, when you want to create helpful guides, or when you need to build interfaces that adapt to different exchanges. Essentially, it’s a way to see what exchanges are plugged into your backtesting system.

    +

    This function simply tells you whether the system is currently in a state where it can execute trades.

    +

    It verifies that both the execution and method contexts are active.

    +

    You'll need this to be true before using functions that interact with the exchange, like fetching historical data (candles), calculating prices, or formatting values. Think of it as a quick check to make sure everything is set up correctly for trading actions.

    +

    This function helps you check if a trading signal is currently scheduled for a specific asset, like "BTCUSDT". It tells you definitively whether there's no signal waiting to be triggered. Think of it as the opposite of a function that checks for a scheduled signal - you can use this to make sure your signal-generating logic only runs when it's supposed to. It smartly figures out whether you're in a backtesting environment or live trading, so you don't need to worry about that detail.

    +

    You provide the symbol of the asset you're interested in, and it returns a true or false value.

    +

    This function, hasNoPendingSignal, helps you determine if a trading signal is currently waiting to be executed for a specific trading pair, like BTC-USD. It returns true if there isn't a signal waiting, meaning it's safe to potentially generate a new one. Think of it as the opposite of hasPendingSignal. This makes it useful for controlling when your system creates new trading signals, making sure you don't accidentally create conflicting orders. The function smartly figures out whether it's running in a backtesting environment or a live trading environment.

    +

    It takes the trading pair symbol as input, for example, 'BTC-USD'.

    +

    The getWalkerSchema function helps you find the details of a specific trading strategy, or "walker," registered within the backtest-kit system. Think of it as looking up the blueprint for a particular trading approach. You provide the name of the walker you're interested in, and the function returns a structured description of that walker, outlining its configuration and how it operates. This is useful for understanding how different trading strategies are set up and what their intended behavior is.

    +

    This function, getTotalPercentClosed, tells you what portion of your position for a specific trading pair is still open. Think of it as a percentage – 100% means you haven't closed anything yet, and 0% means the entire position has been closed.

    +

    It's particularly helpful if you've been adding to your position over time through dollar-cost averaging (DCA) because it accurately reflects the percentage even with those multiple entries and partial closes.

    +

    You don't need to specify whether you're in backtest mode or live trading; the function figures that out on its own. You just need to provide the symbol of the trading pair you're interested in, like "BTCUSDT".

    +

    getTotalCostClosed helps you figure out how much money you’ve invested in a specific trading pair, like BTC/USD. It tells you the total cost basis of any currently open positions, considering things like dollar-cost averaging (DCA) from multiple purchase points and partial sales. The framework intelligently determines whether it’s running a backtest or a live trading scenario.

    +

    You just need to provide the symbol of the trading pair you’re interested in, and it will return the total cost in dollars.

    +

    The getTimestamp function provides a way to retrieve the current timestamp within your trading strategy. It's a handy tool for ensuring your actions happen at the right time, whether you're running a backtest or live trading. During a backtest, it will return the timestamp associated with the specific historical timeframe being analyzed. When running live, it gives you the current, real-time timestamp.

    +

    This function retrieves the symbol you're currently trading, like 'BTCUSDT' or 'ETHUSD'. It's a simple way to find out which asset the backtest is focused on. The function returns a promise that resolves to a string containing the symbol.

    +

    This function lets you peek into the current state of your trading strategy during a backtest or live trading session. It gives you a snapshot of what's happening behind the scenes, including signals that are waiting to be processed, actions that haven't been finalized, and the ID of the signal currently being handled. Think of it as a way to check on the strategy's progress without interfering with its execution. You provide the symbol of the trading pair (like BTCUSDT) to see the status specifically for that instrument. It figures out if it’s running a backtest or a live trading session automatically.

    +

    This function helps you find the blueprint for a specific trading strategy. It takes the strategy's unique name as input and returns a detailed description of that strategy, including what data it needs and how it's structured. Think of it like looking up the instructions for building a particular strategy. You'll need to know the exact name of the strategy you're interested in to use this function.

    +

    This function lets you access pre-defined strategies for determining how much of your capital to use for each trade. It essentially finds a specific sizing method based on a name you provide. Think of it like looking up a particular recipe for trade size – you give it the recipe's name, and it returns the detailed instructions. You need to know the exact name of the sizing strategy you're looking for to use this function.

    +

    The getSignalState function helps retrieve a specific value associated with the active trading signal. It figures out which signal is active based on the environment it's running in.

    +

    If there isn't an active signal, it will let you know and use the default starting value you provide.

    +

    This function is particularly useful for more complex trading strategies, like those using AI, where you need to track data about each trade (like how long it's open or its maximum gain) over time. The examples given demonstrate how it can be used to manage risk and identify opportunities for exiting trades.

    +

    The function takes the trading symbol and a configuration object as inputs. The configuration object contains the name of the data bucket and the initial value to use if no active signal is found.

    +

    This function lets you retrieve data that’s associated with a specific trading symbol and persists across candles during a backtest or live trading session. Think of it as a way to store information that you want to keep handy throughout a run, even if the process restarts. It’s excellent for caching calculations, remembering the state of indicators, or holding onto data needed for decision-making across multiple candles.

    +

    The function takes the trading symbol as input and returns the session data, or null if no data exists for that symbol. It cleverly figures out whether you're in a backtest or live mode without you having to tell it.

    +

    This function helps you find out what scheduled signals are currently running for a particular trading pair. Think of it as checking if a pre-planned signal is active right now.

    +

    It will return information about that signal if one is found, and if nothing is scheduled, it will simply return null, indicating no signal is active.

    +

    It cleverly figures out if you're in a backtesting simulation or live trading environment without you needing to tell it.

    +

    You just need to provide the symbol of the trading pair you’re interested in, like 'BTCUSDT'.

    +

    This function gives you important details about how your backtest or trading system is currently running. It pulls together information like which asset you're trading, the exchange you're connected to, the timeframe you're using, and the specific strategy that’s active. Essentially, it tells you the context of the current execution, whether you're in a historical backtest or a live trading session. You can use this to adapt your code based on the environment.

    +

    This function lets you fetch a pre-defined structure for managing risk, identified by a specific name. Think of it as looking up a template to ensure consistency when evaluating risk factors in your trading strategies. You provide the name of the risk you're interested in, and it returns the associated schema that describes its details. This helps standardize how risk is calculated and reported within the backtest-kit framework.

    +

    The getRawCandles function allows you to retrieve historical candlestick data for a specific trading pair and timeframe. You can easily control how many candles you want and the date range you're interested in.

    +

    It's designed to be reliable, ensuring that your backtests aren't skewed by looking into the future.

    +

    Here's how you can use the function:

      -
    • bucketName: The name of the bucket where the memory is stored.
    • -
    • memoryId: The unique identifier of the memory entry you want to remove.
    • +
    • You can provide a start date, end date, and the number of candles to retrieve.
    • +
    • You can just give a start date and end date and the system will automatically determine the number of candles within that period.
    • +
    • Or, you could specify an end date and a number of candles, and the function calculates the starting date.
    • +
    • Even just specifying the number of candles will work, using a default starting point.
    -

    Essentially, it provides a straightforward way to remove unwanted memory associated with a signal, simplifying memory management within the backtest-kit framework.

    -

    The readMemory function lets you retrieve stored data from a memory location, associating that data with the current trading signal. It handles figuring out whether you're in a backtesting environment or live trading, and knows which signal it's currently working with, so you don't have to worry about those details. To use it, you provide the name of the memory "bucket" and a unique identifier for the specific memory item you want to read. The function will return the data as an object of a defined type.

    -

    This function lets you tweak a trading strategy's walker configuration—think of it as adjusting how the strategy explores different scenarios for comparison. It doesn’t replace the whole walker setup; instead, you provide only the changes you want to make, and the rest of the existing configuration stays put. This is really handy when you want to test a specific change to a strategy's walker without having to redefine everything from scratch. You supply a partial walker configuration, and the function returns the updated, complete walker schema.

    -

    This function lets you modify a strategy's configuration after it's already been set up. Think of it as tweaking a strategy’s settings without completely replacing it.

    -

    You provide a new set of configuration details – just the parts you want to change – and the function updates the existing strategy, leaving everything else untouched.

    -

    It's useful for making adjustments to strategies during development or for applying conditional configurations.

    -

    The strategySchema argument accepts only a partial configuration object.

    -

    This function lets you tweak an existing position sizing strategy without completely replacing it. Think of it as fine-tuning—you can adjust specific settings within a sizing schema.

    -

    You provide a new configuration, but only the values you specify will be changed; the rest of the original sizing configuration stays the same. This is useful when you want to make small adjustments to your sizing rules based on market conditions or new data. It takes a sizing schema object as input, which will override parts of the previous schema.

    -

    This function lets you tweak existing risk management settings within the backtest-kit framework. Think of it as a way to fine-tune a previously set-up risk profile, rather than starting from scratch. You provide a piece of the risk configuration – like a new maximum drawdown percentage – and only that specific part gets updated. Everything else stays as it was originally defined, keeping the rest of your risk controls intact. It’s a simple way to adapt your risk management without rewriting the entire thing.

    -

    This function lets you modify a timeframe configuration that's already being used for backtesting. Think of it as tweaking an existing timeframe setup – you can change specific parts of it, like the data intervals or other settings. It only updates the information you provide; everything else about the timeframe stays the same. This is helpful if you need to adjust a timeframe after it’s already been set up. You provide a partial configuration object, and it returns the updated timeframe schema.

    -

    This function lets you modify an existing exchange's configuration. Think of it as a way to tweak a data source without rebuilding it entirely. You provide a partial configuration – just the settings you want to change – and the function updates the existing exchange, leaving everything else untouched. It’s useful for making adjustments to your data sources after they’ve already been set up.

    -

    This function lets you tweak an action handler's settings without completely replacing it. Think of it as a targeted update – you can change specific parts of how an action is handled, like its callback or some configuration, while leaving the rest untouched. This is really handy when you need to adjust things on the fly, like changing logic for testing or different environments, or modifying how actions behave without needing to rewrite the whole strategy. You just provide the parts you want to change, and the function takes care of the rest.

    -

    This function lets you track the progress of your backtest as each strategy finishes running. It provides a way to get notified after each strategy's execution is complete. The notifications arrive in the order they happen, and importantly, it handles asynchronous callbacks safely to avoid any conflicts or unexpected behavior. You provide a function that will be called with information about each completed strategy. The function you provide will also return a function to unsubscribe from these updates.

    -

    listenWalkerOnce lets you react to specific events as they happen during a backtest, but only once. You provide a filter – a way to identify the events you're interested in – and a callback function that will run when a matching event occurs. After that single execution, it automatically stops listening, making it perfect for situations where you need to wait for something specific to happen and then react. This helps keep your code clean and efficient by avoiding unnecessary ongoing subscriptions.

    -

    This function lets you be notified when the backtest process finishes running all your trading strategies. It's like setting up a listener that gets triggered when the backtest is done. Importantly, the notifications happen one after another, even if the notification itself involves some asynchronous work. This helps prevent issues that can arise from running things at the same time. To use it, provide a function that will be called when the backtest completes, and the function returns another function to unsubscribe from these notifications later.

    -

    The listenWalker function lets you keep track of what's happening as your backtesting strategies run. It's like setting up an observer that gets notified after each strategy finishes within a Walker.run() process.

    -

    Importantly, it handles these notifications in order and makes sure your callback function runs one at a time, even if it's doing something complex like an asynchronous operation. This helps prevent any unexpected issues caused by running things simultaneously. You provide a function (fn) that gets called for each event, receiving details about the strategy's progress. To stop listening, the function returns another function which you can call to unsubscribe.

    -

    The listenValidation function lets you keep an eye on potential problems in your risk validation processes. It's a way to be notified when those validation checks fail, specifically when they throw errors during signal processing. Think of it as a safety net – it allows you to debug and monitor these failures without interrupting the main flow of your backtesting. The errors you receive will be delivered one at a time, in the order they occurred, ensuring you can analyze them methodically, even if your error handling involves asynchronous operations.

    -

    This function lets you listen for specific signal synchronization events, but only once. It's great when you need to make sure something happens just one time in response to a signal, like when coordinating with another system. The function will execute your provided callback once an event matches the filter you set, and it will wait for the callback to finish if it's a promise. Think of it as a one-time alert for a particular type of signal event. You can also control whether a warning message is displayed. When the function is done, you can stop listening by calling the function it returns.

    -

    This function lets you react to synchronization events within the backtest-kit framework. It’s designed for situations where you need to coordinate with external systems or processes.

    -

    Think of it as a way to get notified when a trade signal is about to be acted upon – like when a signal is pending to be opened or closed. If the function you provide includes asynchronous operations (like promises), the backtest will pause and wait for those to finish before proceeding with the trade. This is a powerful tool for ensuring everything is in sync before executing trades.

    -

    You provide a callback function that gets executed whenever a synchronization event happens, and this function will return a function to unsubscribe from the event.

    -

    This function lets you react to specific changes happening within your trading strategies, but only once. Think of it as setting up a temporary alert for a certain condition. You provide a rule (the filterFn) that describes what kind of event you're interested in, and a function (fn) that gets executed the moment that event occurs. After that single execution, the alert is automatically turned off. It’s great for things like confirming a strategy has loaded or a specific trade has been placed and then you can proceed with other actions.

    -

    This function lets you keep an eye on what's happening with your trading strategies. It’s like setting up a notification system that tells you when things like scheduled orders get cancelled, positions are closed, or stop-loss and take-profit levels are adjusted.

    -

    The notifications happen one at a time, even if your notification handler takes a while to process them, ensuring nothing gets missed or overlaps. You provide a function that will be called whenever one of these strategy events occurs, and this function will be used to handle these events.

    -

    You can unsubscribe from these notifications whenever you need to stop listening.

    -

    This function lets you react to a specific trading signal just once. You provide a condition – a filter – that determines which signals you're interested in. When a signal meets that condition, a callback function you define runs, and then the subscription automatically stops. It's perfect for scenarios where you need to react to a particular event and then move on.

    -

    Essentially, you're setting up a temporary listener that fires only once for the right signal.

    -

    The filterFn is the rule that decides whether a signal is the one you want. The fn is the action that gets performed when a matching signal arrives.

    -

    This function lets you quickly react to specific trading signals and then automatically stop listening. You tell it what kind of signals you're interested in by providing a filter – a function that checks if a signal matches your criteria. When a matching signal arrives, your provided callback function runs just once, and then the subscription is turned off. It’s a convenient way to handle a single, important signal without managing ongoing subscriptions.

    -

    This function lets you listen for notifications when a trading strategy sends out information about a trade. Specifically, it picks up on events triggered when a strategy uses commitSignalInfo() to share notes related to an active position. The system ensures these notifications are handled one at a time, even if the notification process itself takes some time, making sure everything stays orderly. You provide a function that will be called whenever a notification is available, and this function will receive details about the signal information. You can unsubscribe from these notifications when you no longer need them.

    -

    The listenSignalLiveOnce function lets you temporarily tap into live trading signals, but only to catch one specific event. Think of it as setting up a brief alert that triggers a function just once when a certain condition is met during a live trading simulation. It's perfect for quickly reacting to a specific signal without needing to manage ongoing subscriptions. The function takes a filter to decide which events you’re interested in and a callback function that will execute when a matching event appears. After the callback runs, the subscription is automatically removed, so you don't have to worry about cleaning up.

    -

    This function lets you set up a way to receive real-time updates as trades happen during a live backtest.

    -

    It's designed to handle these updates one at a time, ensuring they're processed in the order they arrive.

    -

    You provide a function that will be called whenever a new signal event occurs, and this function will receive information about the event.

    -

    Keep in mind that you'll only get these events if you’re running a backtest in "live" mode.

    -

    The function returns another function that you can call to stop the subscription.

    -

    This function lets you temporarily "listen" for specific events during a backtest run. It's designed for situations where you only need to react to something happening once.

    -

    You provide a filter – a test to determine which events you're interested in – and a function to execute when a matching event occurs.

    -

    Once that one event is processed, the listener automatically stops listening, ensuring you don’t get bombarded with unnecessary data later on. Essentially, it's a quick and clean way to grab a single piece of information during a backtest.

    -

    It takes two arguments: a filter function that checks incoming events and a callback function that runs when the filter matches an event. The filter helps you narrow down the events you want to observe, and the callback is what actually does something with the matching data. The function returns an unsubscribe function, so you can manually stop the listener if needed.

    -

    This function lets you tap into the stream of data generated during a backtest. It's like setting up a listener that gets notified whenever a signal event happens.

    -

    You provide a function that will be called for each event, and the backtest framework handles the rest, ensuring these events are processed one after another.

    -

    Keep in mind, you'll only receive these signals if you're running a backtest with Backtest.run(). The listener is a way to react to what's happening inside the backtest as it unfolds.

    -

    This function lets you listen for updates from your trading strategies – think of it as keeping an ear to the ground for what’s happening with your trades. Whenever a strategy changes state, like when a trade is opened, active, or closed, this function will call a function you provide.

    -

    It's designed to handle these updates in order, preventing things from getting out of sync if your callback function does some work asynchronously. Essentially, it makes sure that your code reacts to each trading event one at a time, in the correct sequence.

    -

    You provide a function that will be executed with the details of each event. This allows you to react to different stages of the trading lifecycle.

    -

    The listenSchedulePingOnce function helps you react to specific ping events, but only once. Think of it as setting up a temporary listener. It takes a filter to identify the events you're interested in and a function to run when that event occurs. Once the event is found and the function is executed, the listener automatically disappears, so you don't need to worry about cleaning up. It's great for situations where you need to respond to a particular condition only one time.

    -

    The filterFn lets you precisely define which events should trigger your callback.

    -

    The fn is the action that happens when a matching event is detected.

    -

    The listenSchedulePing function lets you keep an eye on scheduled signals as they're waiting to become active. It sends out a "ping" every minute while a signal is in this waiting period.

    -

    Think of it as a heartbeat – it lets you know the signal is still there and being monitored. You provide a function that gets called each time this ping happens, so you can build custom checks or logging around the signal's lifecycle.

    -

    Essentially, it’s a way to be notified about the ongoing monitoring of scheduled signals. The function you provide will receive an event object with details about the ping. When you’re done listening for these pings, you can call the function returned by listenSchedulePing to unsubscribe.

    -

    The listenRiskOnce function lets you set up a temporary listener for risk rejection events. It's like saying, "Hey, I only care about these specific risk events, and I just need to react to the first one that fits." Once the condition you define (using filterFn) is met, the provided function (fn) will run, and the listener automatically stops listening. This is great for situations where you're waiting for a particular risk rejection to happen and then want to take action, but don't want to keep listening afterward.

    -

    It takes two parts: a filter to identify the relevant events and a function to run when that event is detected. The function returns another function that can be called to remove the listener.

    -

    This function lets you react to situations where a trading signal is blocked because it violates your defined risk rules.

    -

    Think of it as a notification system specifically for when something goes wrong with your risk checks.

    -

    You provide a function that will be called whenever a signal is rejected due to a risk failure. This function receives information about the rejected signal. Importantly, you'll only get these notifications for rejected signals – you won't be notified when a signal is approved. The framework makes sure your callback function is executed one at a time, in the order the events occur, even if your function takes some time to complete.

    -

    This function lets you keep an eye on how your trading strategies are performing in terms of speed and efficiency. It’s like setting up a listener that gets notified whenever operations happen during a backtest.

    -

    You provide a function that will be called with information about each operation's timing.

    -

    The system ensures these notifications are processed one at a time, even if your provided function takes some time to complete, preventing any overlapping or unexpected behavior. This makes it great for spotting slow parts of your code and optimizing them.

    -

    This function lets you set up a listener that reacts to specific partial profit levels being reached during a backtest. Think of it as a one-time alert for a particular profit condition. You provide a filter – a rule to identify the events you're interested in – and a function to execute when that rule is met. Once the condition is met, the listener automatically stops, so you won't receive any further notifications.

    -

    It's great for situations where you need to react to a specific profit milestone only once, like triggering a particular action or recording data.

    -

    The filter function determines which events trigger the callback. The callback function is then executed with the details of that matching event.

    -

    This function lets you track progress towards profit milestones during a backtest.

    -

    You provide a function that will be called whenever a profit level is reached, like 10%, 20%, or 30% gain.

    -

    Importantly, these events are handled one at a time, even if your function takes some time to complete, ensuring things don't get out of order.

    -

    The subscription can be cancelled by returning the function provided as a parameter.

    -

    This function lets you set up a one-time alert based on changes to your partial loss level. It's like saying, "Hey, I only care about this specific situation happening once."

    -

    You provide a filter—a rule that defines when you want to be notified—and a function that will run when that rule is met.

    -

    The function then monitors for changes and executes your function just one time when the filter condition becomes true, then automatically stops listening. This is great for reacting to a specific, unusual loss event.

    -

    This function lets you monitor your trading strategy's loss levels, like when it hits 10%, 20%, or 30% loss milestones. It sends you notifications whenever these loss levels are reached. Importantly, these notifications are handled one at a time to ensure things run smoothly, even if your notification processing takes some time. You provide a function that will be called each time a loss level is triggered, and this function receives information about the specific loss event. The function you provide will return a function that when called will unsubscribe you from the events.

    -

    This function lets you react to specific max drawdown events and then automatically stop listening. Think of it as setting up a one-time alert for when a certain drawdown condition is met. You tell it what conditions to look for (using filterFn), and it will call your function (fn) just once when that condition is found. After that, it stops listening, so you don't get further notifications.

    -

    It's great for things like pausing a trade when a drawdown reaches a critical level, or triggering a report based on a particular drawdown value.

    -

    The filterFn determines which events trigger the callback. -The fn is the function that will be executed when a matching event is detected, and it handles the details of the event data.

    -

    This function lets you keep an eye on the maximum drawdown of your trading strategies. It will notify you whenever a new peak drawdown is reached, letting you react to changes in risk exposure. The events are handled one at a time, even if your reaction involves some processing, ensuring things happen in the right order. This is helpful if you want to adjust your risk management based on how much your strategy is losing. You provide a function that gets called whenever a drawdown event occurs.

    -

    listenIdlePingOnce lets you set up a listener that reacts to idle ping events, but only once a specific condition is met. You provide a function (filterFn) that determines which idle ping events are relevant to you, and then you specify a callback function (fn) that will be executed when a matching event occurs. Once that matching event has been processed, the listener automatically stops, ensuring it doesn’t trigger again. This is handy for things like initiating a specific action only after the system has been idle for a defined period. It returns a function that unsubscribes the listener.

    -

    This function lets you listen for moments when the backtest kit isn't actively processing any trading signals. Think of it as getting a notification when things are quiet.

    -

    It’s useful if you want to perform maintenance tasks or run checks when the system isn't busy executing trades.

    -

    You provide a function that will be called with information about the idle ping event whenever this quiet period occurs. The function you provide handles the IdlePingContract data. To stop listening, the function returns a cleanup function that you can call.

    -

    This function lets you set up a temporary listener that reacts to specific profitable trades.

    -

    You provide a rule (the filterFn) to define what kind of profitable trade you’re interested in. Then, you give it a function (fn) that will be executed only once when a trade matches your rule.

    -

    After that one execution, the listener automatically stops listening, so it's great for reacting to a particular event and then forgetting about it. Think of it as a quick, one-time alert for a specific trading scenario.

    -

    This function lets you monitor when a trading strategy achieves a new peak profit. It's like setting up a notification system that alerts you whenever the strategy's profit reaches a higher point.

    -

    The events are handled in the order they occur, and the callback function you provide will be executed one at a time, even if it takes some time to complete.

    -

    Think of it as a way to track those important profit milestones and potentially adjust your strategy based on how well it’s performing. You give it a function that will be called whenever a new highest profit is reached. The function you provide will be called with details about that event.

    -

    The listenExit function lets you monitor for and respond to serious errors that abruptly halt processes like background tasks in live trading, backtesting, or data walking. These aren't the minor hiccups your code might recover from – they're critical failures that shut everything down.

    -

    You provide a function as input, and listenExit will call that function whenever a fatal error occurs.

    -

    Importantly, errors are handled one at a time, in the order they happen, even if your error handling function involves asynchronous operations. This ensures a controlled and sequential response to those critical events. The registration returns an unsubscribe function that you can use to stop listening to exit events.

    -

    The listenError function helps you handle errors that happen during your trading strategy's execution but aren't critical enough to stop everything. Think of it as a way to catch and deal with hiccups – maybe an API call fails, but you still want your strategy to keep running.

    -

    It essentially sets up a listener that will notify you whenever one of these recoverable errors occurs.

    -

    The errors will be handled one at a time, in the order they happen, even if the error handling itself takes some time to complete. This makes sure things stay organized and prevents problems caused by trying to process errors all at once.

    -

    To use it, you provide a function (fn) that will be called with the details of each error. The function itself returns a way to stop listening for errors.

    -

    This function lets you react to when a background task within your backtest completes, but only once. You provide a filter to specify which completed tasks you're interested in, and a function that will run when a matching task finishes. Once that function has executed, the listener is automatically removed, ensuring it doesn't trigger again. Think of it as a single, targeted alert for a specific background process.

    -

    This function lets you listen for when background tasks using the Walker framework finish running. It's like setting up a notification system to be alerted when a process is done.

    -

    When a background task completes, it will trigger the function you provide. Importantly, even if your function takes some time to run (like doing something asynchronous), the next completion notification won't be sent until yours is finished – ensuring events are handled one at a time in the order they arrive. This helps maintain order and prevents unexpected behavior if your callback involves asynchronous operations.

    -

    This function lets you react to when background tasks finish running in your backtest.

    -

    It allows you to specify a condition (using filterFn) to determine which completion events you're interested in.

    -

    Once a matching event occurs, a provided callback function (fn) will be executed exactly once, and then the subscription automatically stops. This is great for tasks that you only need to handle once upon completion.

    -

    This function lets you listen for when background tasks, started with Live.background(), finish running. It’s designed for situations where you need to know when a process is truly complete, especially if that process involves asynchronous operations.

    -

    You provide a function (fn) that will be called when a task is done.

    -

    The events are handled one after another to ensure a predictable order, and the framework makes sure your callback function runs without interference from other processes. Think of it as a way to reliably react to the completion of background tasks in a controlled sequence.

    -

    This function lets you react to when a background backtest finishes, but only once. You provide a filter to determine which backtest completions you’re interested in, and then a function that will be executed when a matching backtest is done. Importantly, it automatically stops listening after that single execution, so you don’t need to worry about cleaning up. It’s handy for things like updating a UI with final results or triggering a follow-up action.

    -

    This function lets you get notified when a background backtest finishes running. It’s useful if you need to perform actions after a backtest completes, like updating a user interface or saving results.

    -

    The function provides a way to subscribe to events triggered when a backtest finishes. These events are handled one at a time, even if your notification code takes a while to execute. This ensures that everything runs in the correct order. You provide a function that will be called when a backtest is done, and the function returns another function that you can call to stop listening for these completion events.

    -

    This function lets you set up a temporary listener for breakeven protection events. You provide a filter to specify exactly which events you're interested in. Once an event matching your filter arrives, the provided callback function will be executed just once, and then the listener will automatically stop listening. It's perfect for situations where you need to react to a specific breakeven condition and then move on.

    -

    You essentially tell it "Hey, watch for events like this, and when you see one, do this one time, then stop watching."

    -

    The first argument is the filter - a function that decides if an event is relevant. The second argument is the function that runs when a matching event is found.

    -

    This function allows you to be notified when a trade's stop-loss automatically moves to the original entry price, a feature designed to protect profits. It's essentially telling you that the trade has made enough money to cover its initial costs, so the risk is now at the original purchase price.

    -

    The notifications are delivered one at a time, even if your callback function takes some time to execute, ensuring that nothing gets missed.

    -

    To use it, you provide a function that will be called whenever a breakeven event occurs, and this function returns another function that can be used to unsubscribe from the event.

    -

    This function lets you react to specific events that happen right before a backtest begins. You provide a filter – a way to identify the exact events you're interested in – and a function to execute when that event occurs. Critically, it's designed to only run your function once and then automatically stops listening, keeping things clean and efficient. Think of it as setting up a single, one-time alert for a particular condition at the start of a trading simulation.

    -

    This function lets you hook into the moment right before a trading strategy begins for a specific asset. Think of it as a heads-up signal.

    -

    It provides a way to execute code sequentially, even if that code involves asynchronous operations.

    -

    The fn you provide will be called with details about the upcoming strategy run, ensuring events are handled one after the other to avoid any clashes. You can unsubscribe from these signals at any time by returning the value that is returned from the listenBeforeStart function.

    -

    This function lets you keep an eye on how your backtest is running. It sets up a listener that receives updates as the backtest progresses.

    -

    Think of it as getting occasional snapshots of the backtest's status.

    -

    The updates are delivered in the order they happen, and even if your callback function takes some time to process each update, the updates are handled one after another to avoid any confusion.

    -

    You provide a function that gets called whenever a progress event occurs, and this function will be given information about the event. When you are done, the function returns another function you can use to unsubscribe from the listener.

    -

    This function lets you react to specific events that happen after a trading simulation finishes, but only once. You provide a filter to specify exactly which events you're interested in, and then a callback function that will be executed just the first time a matching event occurs. After that single execution, the subscription is automatically cancelled, so you don't have to worry about cleaning up. It's a convenient way to perform a one-off action based on the final state of your backtest.

    -

    This function lets you tap into what happens after a trading strategy finishes running for a specific asset.

    -

    Think of it as a notification system—you provide a function, and it gets called whenever a strategy concludes.

    -

    Crucially, these notifications are handled in a safe and orderly way; even if your function does something complex (like making an API call), it won't interfere with the next notification until it's fully completed.

    -

    This ensures that events are processed one after another, in the order they arrived, preventing any unexpected clashes or race conditions.

    -

    This function lets you watch for specific active ping events and run a piece of code just once when you find one that matches. Think of it as setting up a temporary listener – it listens until it sees what you're looking for, then it stops listening and runs your code. It’s handy for waiting for a particular condition to be met with these active ping events.

    -

    You provide a filter function to define what events you're interested in, and a function to execute when a matching event is detected. The listener automatically unsubscribes after the callback has been executed once, ensuring you don't continue processing the same event.

    -

    This function allows you to monitor active signals within the backtest environment. It listens for events, which are sent out every minute, providing updates on the lifecycle of active signals.

    -

    Think of it as a way to keep an eye on what's happening with your trading signals.

    -

    Importantly, these events are handled one at a time in the order they're received, and even if your callback function takes some time to process, it won't interfere with the processing of subsequent events. You provide a function that gets called whenever a new active ping event occurs, allowing you to react to changes in signal status.

    -

    This function allows you to see all the different trading strategies or "walkers" that have been set up within the backtest-kit system. It gathers a list of these walkers, providing information about each one. Think of it as a way to peek behind the curtain and understand the different approaches being tested. This is especially helpful when you're trying to figure out what's happening, creating documentation, or building a user interface that needs to display these strategy configurations.

    -

    This function helps you see a complete inventory of all the trading strategies you've set up within the backtest-kit framework. It's like getting a directory listing of all your strategies, returning a list of their descriptions. This is handy if you're trying to understand what strategies are available, building a user interface to manage them, or just checking everything is configured correctly.

    -

    This function lets you see all the sizing strategies that have been set up in your backtesting environment. Think of it as a way to check what rules are in place for determining how much of an asset to trade. It provides a simple list of these configurations, which is handy for understanding your setup, troubleshooting, or even creating tools that automatically display your sizing rules. It's a convenient way to examine the sizing logic being used during backtesting.

    -

    This function lets you see all the risk schemas currently set up in your backtest. Think of it as a way to peek under the hood and get a list of all the risk configurations you've defined. It's handy if you’re troubleshooting, want to understand your setup, or want to build an interface that dynamically displays these risks. The function returns a promise that resolves to an array of risk schema objects.

    -

    This function lets you retrieve a list of all stored memory entries associated with the current signal. Think of it as looking through a history of data points relevant to your trading strategy.

    -

    It simplifies the process by automatically figuring out which signal you're working with and whether you're in a backtesting or live trading environment, based on the surrounding context.

    -

    You provide a simple configuration object, specifying the bucket name where the memory is stored.

    -

    The function returns a promise that resolves to an array. Each item in the array represents a memory entry, including a unique identifier and the content itself.

    -

    This function helps you see all the different "frames" or data structures that your backtest setup uses. It essentially gives you a complete inventory of the data formats defined within your trading system. Think of it as a way to peek under the hood and understand what kind of information is being processed during your backtests. It’s particularly helpful if you're trying to debug or build tools that need to interact with these data structures.

    -

    This function lets you see a complete inventory of all the exchanges your backtest-kit setup recognizes. Think of it as a way to check which data sources are available for trading simulations. It returns a list, so you can easily loop through them or display them. This is really handy for troubleshooting, creating guides, or building interfaces that automatically adapt to the exchanges you're using.

    -

    This function simply tells you if the environment is ready for trading operations.

    -

    It checks if both the execution and method contexts are active.

    -

    If it returns true, you're good to go and can use functions like getting candle data, calculating averages, formatting prices or quantities, and accessing dates and modes. Basically, it's a quick check to ensure everything is set up properly before performing actions related to trading.

    -

    This function helps you check if a trading signal is currently scheduled for a specific asset, like "BTCUSDT".

    -

    It returns true if no scheduled signal exists for that asset, which is helpful to ensure you’re not accidentally generating signals when they aren’t needed.

    -

    Think of it as the opposite of hasScheduledSignal; it’s a safety check to make sure your signal creation process only runs when appropriate.

    -

    The function handles whether you're in a backtesting or live trading environment automatically.

    -

    You simply provide the trading pair's symbol as input to get the result.

    -

    This function, hasNoPendingSignal, helps you check if there’s currently a pending trading signal for a specific asset, like "BTCUSDT". It returns true if there isn’t a signal waiting, meaning you're clear to potentially generate a new one. Think of it as the opposite of hasPendingSignal; it's a useful way to make sure your signal generation logic only runs when appropriate. The function automatically figures out whether it's running in a backtesting or live trading environment, so you don't need to worry about that. You simply provide the symbol of the asset you’re interested in, and it handles the rest.

    -

    The getWalkerSchema function helps you find information about a specific trading strategy, or "walker," within your backtest setup. Think of it as looking up the blueprint for a particular trading method. You give it the name of the walker you're interested in, and it returns a detailed schema describing how that walker operates, including the data it uses and the calculations it performs. This allows you to understand and potentially modify or analyze the behavior of your trading strategies.

    -

    This function lets you check how much of a trading position is still open. It tells you the percentage of the original position size that hasn't been closed out – so a value of 100 means you still hold the entire position, while 0 means it's completely closed.

    -

    It's smart about how it calculates this, even if you’ve added to the position with dollar-cost averaging (DCA) and closed it in smaller chunks along the way.

    -

    You just need to provide the symbol of the trading pair you’re interested in, like 'BTCUSDT'.

    -

    It will automatically figure out if it's running in a backtesting simulation or in a live trading environment.

    -

    This function helps you figure out how much money you've invested in a particular trading pair, like BTC/USD. It’s especially useful if you’ve been adding to your position over time through dollar-cost averaging (DCA) and have also been closing parts of it. The function calculates the total cost basis in dollars, considering those partial closes and the varying prices at which you entered the trade. It works whether you're running a backtest or a live trading simulation, because it automatically understands the environment it's in. You simply provide the trading pair symbol, such as "BTC/USD," and it will return the total cost.

    -

    This function, getTimestamp, gives you the current time, but it behaves differently depending on whether you're running a backtest or live trading. When testing past performance (backtest mode), it provides the timestamp for the specific point in time you're analyzing. If you’re trading in real-time, it delivers the present, live timestamp. Essentially, it's a way to know what time it is relative to your trading activity.

    -

    This function retrieves the symbol you're currently trading, like "BTCUSDT" or "ETHUSD." It's a simple way to know what asset your backtest or trading strategy is focused on. The function returns a promise that resolves to the symbol as a string, so you'll need to use await or .then() to get the actual value.

    -

    This function lets you peek into the current state of your trading strategy as it's running in a backtest or live environment. Think of it as a snapshot of what's happening behind the scenes – queued actions, pending signals, and flags related to user interactions. It provides details for a specific trading pair, like "BTC-USDT". You don't need to worry about whether you're in a backtest or not; the function figures that out for you.

    -

    The getStrategySchema function lets you fetch details about a specific trading strategy that's been set up within the backtest-kit framework. Think of it as looking up the blueprint for a strategy. You provide the strategy's unique name, and the function returns a structured description outlining how that strategy operates, including its inputs, outputs, and other relevant configuration information. This helps you understand and potentially modify or debug strategies programmatically.

    -

    This function helps you find the specific rules for how much of an asset to trade based on a name you give it. Think of it like looking up a recipe; you provide the recipe name (the sizing name), and the function returns the detailed instructions (the sizing schema). It’s used to access the configuration for determining position sizes in your trading strategies. You use a unique identifier to pinpoint the sizing schema you need.

    -

    This function helps you retrieve a specific data value associated with an active trading signal. It automatically figures out whether you're in a backtest or live trading environment.

    -

    If a signal is currently active, it fetches the data; otherwise, it gives you back a default starting value and logs a message to let you know.

    -

    Think of it as a way to keep track of metrics, like how long a trade is open or how much it has gained, as you're executing trades – especially useful for strategies that adjust based on those metrics.

    -

    The function takes the trading symbol as input and a configuration object containing the bucket name and an initial value for the data you're tracking.

    -

    This function lets you retrieve data that's specifically saved for a trading strategy's run. Think of it as a way to store information that needs to be remembered between each candle processed, or even if the process restarts. It's helpful for keeping track of things like complex calculations, caching results, or any state that needs to be maintained throughout a trading session. The function automatically knows whether it's running a backtest or in live trading mode. You just need to provide the symbol of the trading pair you're interested in.

    -

    This function lets you fetch the currently planned or "scheduled" trading signal for a specific asset, like BTC-USD.

    -

    Think of it as checking what the system has already decided to do based on a pre-defined schedule.

    -

    If there's no signal scheduled, the function will tell you by returning nothing.

    -

    It figures out whether it’s running a practice test (backtest) or live trading automatically.

    -

    You just need to provide the trading symbol you're interested in.

    -

    This function gives you a snapshot of how your trading system is currently running. It reveals important details like which asset you’re analyzing, the exchange being used, the timeframe of your charts, and the strategy you've implemented. It also tells you whether you're in a historical simulation (backtest) or a live trading session. Think of it as a quick way to understand the context of your current run.

    -

    This function lets you fetch details about a specific risk metric that's already been defined in your backtesting setup. Think of it as looking up the blueprint for how a certain risk is calculated and tracked. You provide the name or identifier of the risk you’re interested in, and it returns a structured object describing that risk – things like what data it uses and how it’s calculated. It's useful when you need to understand or programmatically work with the details of a registered risk.

    -

    The getRawCandles function helps you retrieve historical price data, also known as candles, for a specific trading pair and timeframe. You can control how much data you get by specifying a limit on the number of candles, or by defining a start and end date for the data you want.

    -

    It’s designed to make sure your analysis is fair and doesn't accidentally peek into the future.

    -

    Here's how you can use the parameters:

    +

    The function handles date validation to make sure you’re not asking for data beyond available history.

    +

    Parameters:

      -
    • You can specify both a start date, end date, and the number of candles.
    • -
    • If you only provide a start and end date, it will automatically figure out how many candles are needed to cover that range.
    • -
    • If you just want a certain number of candles from a specific point in the past, you can simply set the number of candles you want.
    • -
    • If you only provide a number of candles, it will fetch data backwards from the current time.
    • +
    • symbol: The trading pair you're interested in (like "BTCUSDT").
    • +
    • interval: The timeframe for the candles (options include "1m", "3m", "5m", "15m", "30m", "1h", "2h", "4h", "6h", and "8h").
    • +
    • limit: The number of candles you want to retrieve (optional).
    • +
    • sDate: The starting date in milliseconds (optional).
    • +
    • eDate: The ending date in milliseconds (optional).
    -

    The function takes the symbol (like "BTCUSDT"), the interval (like "1m" for one-minute candles), and optionally a limit, start date, and end date. The result is an array of candle data.

    -

    This function helps you find out how long a trading signal has been waiting to be put into action. It tells you the wait time in minutes for a specific trading pair, like BTC/USDT.

    -

    If there's no signal currently waiting, it will return null, meaning there’s nothing waiting right now.

    -

    You just need to provide the symbol of the trading pair you're interested in.

    -

    This function helps you quickly check the unrealized profit or loss as a percentage for a trade you're currently holding. It takes into account things like how much you've already sold, your average entry price (DCA), potential price slippage, and any fees you might have paid.

    -

    If you don't have any active trades, it will return null.

    -

    It figures out whether you’re running a backtest or a live trading session and fetches the current price automatically, making it super convenient to use. To use it, simply provide the symbol of the trading pair you're interested in, like "BTCUSDT".

    -

    This function helps you understand how much money you've potentially gained or lost on a trade that’s still open. It calculates the unrealized profit and loss in dollars based on the current market price.

    -

    The calculation considers factors like how much you've invested, any partial trades you've made, cost of slippage and fees.

    -

    If there are no open trades, it will return null. The function automatically knows whether it's running in a backtesting or live trading environment and gets the current price for you.

    -

    You just need to provide the trading pair symbol, like "BTCUSDT".

    -

    This function lets you check the history of partial profit or loss closures for a specific trading pair. It provides a look at how much of your position has been closed out partially, at what price, and the cost basis at the time of each partial.

    -

    If you haven't started a backtest or haven't executed any partial closures, it will return either a null value or an empty array respectively. The output gives you details like the type of closure (profit or loss), the percentage closed, the price used for the closure, the cost basis, and the number of DCA entries at the time. You pass in the trading pair symbol to see the partials associated with that symbol.

    -

    This function helps you avoid accidentally closing a position partially more than once at roughly the same price. It checks if the current market price is close enough to a previously executed partial close order.

    -

    Essentially, it's a safety net to prevent unwanted duplicate actions.

    -

    The function looks at the prices of any existing partial close orders and calculates a tolerance range based on percentages you define (or default percentages if you don't). If the current price falls within that range, it means a partial close is already in progress nearby.

    -

    You provide the trading symbol and the current price to be checked, and optionally customize the tolerance zone. The function returns true if a partial overlap exists and false otherwise, which is useful for coordinating actions within your trading system.

    -

    This function helps you find out when a specific trading position experienced its biggest loss. It looks back at the entire history of that position – from when it was opened until now – and identifies the exact timestamp marking the lowest point in its value.

    -

    Essentially, it tells you when the position suffered the most drawdown.

    -

    If no trading signals are currently active for that symbol, the function will return null.

    -

    To use it, you simply need to provide the symbol of the trading pair you're interested in, like 'BTCUSDT'. The function will then return a timestamp representing the maximum drawdown point for that position.

    -

    This function helps you understand the most significant loss a specific trade has experienced. It calculates the lowest price the trade reached during its active period, essentially showing you the biggest drawdown.

    -

    If there's no open trade associated with the provided symbol, the function will return null, indicating there's nothing to analyze. You provide the symbol of the trading pair (like BTCUSDT) as input to see its maximum drawdown.

    -

    This function helps you understand the performance of a specific trading position. It calculates the maximum drawdown of the profit and loss percentage for that position, essentially telling you the lowest point the position reached in terms of profitability. The value returned represents the percentage of profit lost at the time of the largest drawdown. If no trading signals are active for that symbol, the function will return null, meaning it can't assess the drawdown. You simply provide the symbol of the trading pair you want to analyze.

    -

    This function helps you understand the financial impact of a trading position. It calculates the total cost in terms of profit and loss (expressed in the quote currency, like USD or EUR) that occurred at the point when the position hit its lowest value. Think of it as revealing how much you've lost at the absolute worst moment for that particular trade. If there's no open trade, it won’t give you a value but rather a null response. You provide the trading pair symbol – like "BTC-USD" – to specify which position you're interested in.

    -

    This function tells you how much time has passed since a trade experienced its biggest loss. It’s a way to measure how long ago things went wrong for a particular trade.

    -

    The time is measured in minutes. If the drawdown happened just now, the value will be close to zero.

    -

    If there's no ongoing trade, the function won't return a value. You need to provide the symbol of the trading pair you're interested in.

    -

    getPositionLevels lets you see the prices at which your initial buy and any subsequent average buy orders were placed for a particular trading pair. It's how you track the prices involved in a dollar-cost averaging (DCA) strategy.

    -

    If there's no open trade, it will return null. If you only made one buy, you'll get an array with just the original entry price. Otherwise, it provides a list of all the prices at which you've bought, starting with the original price and including any prices added through commitAverageBuy. You just need to provide the trading pair symbol to see these prices.

    -

    This function helps you track how many times you've adjusted a trade using dollar-cost averaging (DCA) for a specific trading pair.

    -

    It tells you the number of DCA entries made for the current open trade – a value of 1 means it’s the original purchase, and each subsequent DCA increases that number. If there isn't an active trade, the function will return null. The function intelligently determines whether it's running in a backtest or a live trading environment. You only need to provide the symbol of the trading pair you're interested in.

    -

    This function helps you figure out how much money is tied up in a particular trade. It calculates the total cost basis, which includes all the entry costs associated with a signal.

    -

    Essentially, it adds up the costs from each time you bought into the trade. If there's no signal currently in progress, it will return null. The function intelligently determines whether it's running in a backtest or live trading environment.

    -

    You provide the trading symbol (like BTC-USDT) as input to see the cost basis for that specific trade.

    -

    This function helps you find the exact moment when a specific trade (or "position") made the most profit. It looks at a trading pair, like "BTCUSDT," and tells you the timestamp—essentially, the date and time—when the price was at its highest point for that trade.

    -

    If there's no active signal for that trading pair, it won't be able to provide a timestamp and will return null. Think of it as a way to pinpoint the peak profitability of a past trade. The input needed is just the symbol of the trading pair you're interested in.

    -

    This function helps you find the best price your position has achieved while moving in a profitable direction.

    -

    It essentially remembers the highest price for a long position or the lowest price for a short position, since the position was opened.

    -

    The function takes the trading symbol (like "BTCUSDT") as input and returns a number representing that best price. It's always available when a position is active, giving you a snapshot of its performance so far.

    -

    This function helps you understand how long a trading position has been operating below its best-ever profit level. It tells you the number of minutes that have passed since the price reached its highest point for that particular trading pair. Think of it as a measure of how far a position has fallen from its peak—a longer number means it’s been a while since it hit that high. If there's no trading signal for the symbol, the function will return null. You provide the trading pair symbol, like "BTCUSDT", to get the information.

    -

    This function helps you understand how far your trading position has moved from its most profitable point. It calculates the difference between the highest profit percentage achieved and the current profit percentage.

    -

    Essentially, it shows you how much headroom you had before, and how far you are from that peak.

    -

    If there are no active trading signals, this function won't be able to provide a result. You need to specify the trading pair, like 'BTC/USDT', to get the calculation.

    -

    This function helps you understand how far your trading position is from its potential peak profit. It calculates the difference between the highest profit achieved so far and the current profit, ensuring the result is never negative. If no trading signals are pending for a specific symbol, the function will return null. You provide the trading pair symbol, like 'BTC-USD', to get this information.

    -

    This function helps you understand if a trade could have reached a breakeven point at its peak profit. It checks for a specific trading pair, like BTCUSDT, and determines if the highest price achieved during the trade allowed for a breakeven scenario. If there's no active trade signal for that pair, the function will tell you that. Essentially, it's a tool to analyze past trades and see if they had the potential for a clean break-even at their best performance.

    -

    This function helps you understand how well a particular trade performed. It looks at a specific trading pair, like BTC-USDT, and tells you the highest percentage profit it ever reached while the trade was open. Think of it as finding the peak of a trade’s performance.

    -

    If there's no active trade data available for that symbol, the function will return null, indicating no information can be provided. Essentially, it’s a way to pinpoint the most profitable moment of a trade's history.

    -

    This function lets you find out the highest profit and loss cost incurred during a trading position's lifetime, specifically at the moment the most profitable price was achieved. It’s a way to understand the peak financial risk associated with that position.

    -

    The function takes the trading symbol as input, such as 'BTC-USDT'.

    -

    It returns a numerical value representing that highest PnL cost. If there's no existing signal for that position, the function will return null.

    -

    This function helps you understand how much your trading position has recovered from its biggest loss. It calculates the difference between your current profit percentage and the lowest point your profit reached during that period.

    -

    Essentially, it shows you how far your position has climbed back from its most significant dip in profitability.

    -

    The function requires you to specify the trading symbol, like "BTC/USDT". It returns a percentage value representing this drawdown recovery. If there’s no existing trading signal for that symbol, the function won't return a value.

    -

    This function helps you understand how far your trading position is from its lowest point in terms of profit and loss. It calculates the difference between your current profit/loss and the lowest profit/loss you've experienced during the backtest. Essentially, it tells you how much "cushion" you have against potential further losses. If there isn't a currently active trading signal for a particular symbol, the function won't return a value. You just need to specify the trading pair symbol you're interested in.

    -

    getPositionEstimateMinutes helps you check how long a trade is expected to last. It looks at the initial estimate set for a pending trade, essentially telling you the maximum number of minutes it's expected to stay open before it automatically closes due to time expiration.

    -

    If there isn't a trade waiting to be executed, it will return null.

    -

    You provide the trading pair symbol to identify the specific trade you're interested in.

    -

    The getPositionEntryOverlap function helps you avoid accidentally placing multiple DCA orders at roughly the same price. It checks if the current market price is close to any of your existing DCA entry levels, considering a small tolerance zone around each level.

    -

    Think of it as a safety check – it prevents you from accidentally stacking up DCA orders when the price fluctuates slightly.

    -

    The function returns true if the price falls within a defined range around any existing DCA level and false if there are no levels to check against. You can configure the size of this range with the ladder parameter to fine-tune the sensitivity of the check.

    -

    getPositionEntries lets you peek at the prices and costs of your DCA entries for a specific trading pair. It gives you a list detailing each time you added to your position – whether it was the initial buy or a later DCA commit. If you don't have an active trading signal, it'll return nothing. If you only made one purchase, you'll get a list containing just that one entry. Each entry in the list includes the price at which you bought and the total dollar amount spent at that price.

    -

    This function helps you figure out the average price at which you've accumulated a position, taking into account any previous buys or DCA (Dollar-Cost Averaging) strategies. It essentially calculates a weighted average based on how much you spent and the prices at which you bought.

    -

    If you've partially closed your position at different prices, this function considers those partial closures and blends them with any subsequent DCA entries to give you a comprehensive view of your average entry price.

    -

    If you haven't made any DCA entries, the function simply returns the initial opening price. It will also tell you there’s no data if there's no active trade in progress. The framework automatically determines whether it's running a backtest or in live trading mode.

    -

    You just need to provide the symbol of the trading pair (like BTCUSDT) to get the effective price.

    -

    getPositionDrawdownMinutes tells you how much time has passed since your current trading position reached its highest profit. Think of it as a measure of how far your profits have fallen from their peak. If your position just started making money, this value will be zero. As prices move and your profits decrease, this number will increase, reflecting the length of the pullback. If there's no active trade happening, it won't be able to provide a value and will return null. You need to specify the trading pair, like "BTCUSDT", to get this information.

    -

    getPositionCountdownMinutes tells you how much time is left before a trading position expires. It calculates this by looking at when the position was first flagged for potential expiration and comparing it to an estimated expiration time.

    -

    The result is always a positive number of minutes, or zero if the estimated expiration has already passed.

    -

    If there’s no indication of a pending expiration for a particular trading pair, the function will return null. You need to provide the trading pair symbol as input.

    -

    The getPositionActiveMinutes function lets you check how long a particular trading position has been open. It returns the number of minutes the position has been active.

    -

    If there’s no signal currently pending for that symbol, the function will return null.

    -

    You just need to provide the trading pair symbol – like "BTCUSDT" – to use this function.

    -

    This function lets you check if your trading strategy currently has a pending order waiting to be filled.

    -

    It returns information about that pending order, like the price and quantity.

    -

    If there isn't a pending order active, it will tell you by returning nothing.

    -

    You don’t need to worry about whether you're running a test backtest or a live trade – the function figures it out automatically.

    -

    To use it, you simply provide the trading pair symbol, like "BTCUSDT".

    -

    This function retrieves the order book information for a specific trading pair, like BTCUSDT. It pulls this data from the exchange you've configured within the backtest-kit framework.

    -

    The function takes the trading symbol as input, and you can optionally specify the desired depth of the order book. If you don’t specify a depth, it will use a default value.

    -

    The function is designed to work with the existing timing of your backtest or live trading environment, so the exchange knows when the request is being made. The exchange then uses this timing information as appropriate for either a backtest or a live trading scenario.

    -

    This function lets you grab a batch of future candles for a specific trading pair and time interval. It’s designed to get candles that come after the current time frame you're working with, leveraging the exchange's specific way of fetching them. You'll need to provide the symbol, like "BTCUSDT," the candle interval (options include things like "1m" for one-minute candles or "4h" for four-hour candles), and how many candles you want to retrieve. The function returns a promise that resolves to an array of candle data.

    -

    This function tells you whether the backtest-kit is currently running a simulation (backtest mode) or a live trading session. It's a simple way to check the context of your code and adjust behavior accordingly. It returns a promise that resolves to either "backtest" or "live", making it easy to use in your functions.

    -

    This function helps you figure out how much time has passed since the last trading signal was generated for a specific asset, like "BTC-USDT". It measures this time in whole minutes.

    -

    It doesn't matter whether that signal is still active or has already been closed; it simply checks the timestamp of the most recent signal. This is handy for things like making sure you wait a certain amount of time before placing a new trade after a stop-loss.

    -

    First, it looks for this information in your backtest data, and if it can't find it there, it checks your live trading data. If there’s no signal history at all, it returns null. The function automatically knows whether you're in backtest mode or live trading mode.

    -

    You just need to provide the symbol of the asset you're interested in, for example, "BTC-USDT".

    -

    This function helps you understand the risk profile of a trading strategy. It calculates the maximum drawdown – essentially, the biggest drop from a peak profit to a low point – expressed as a percentage of the peak profit.

    -

    You provide the trading symbol (like BTC/USD) as input, and the function returns that percentage.

    -

    If the strategy hasn’t generated any trading signals yet, the function will return null. This metric can be useful for comparing the riskiness of different strategies.

    -

    This function helps you understand the potential risk in a trading strategy by calculating the maximum drawdown distance based on profit and loss. It essentially measures the difference between the highest profit you've seen and the lowest point where you were in the red.

    -

    Think of it as a way to see how far you might fall from your best performance.

    -

    The result represents the largest amount your account would have lost from its peak profit. This value is returned as a number. It won't return anything if there are no trading signals available.

    -

    You provide the trading pair symbol (like 'BTC-USD') to specify which strategy you’re analyzing.

    -

    This function lets you retrieve the most recent trading signal generated by your strategy, whether it’s still active or has already closed. It’s handy for things like implementing cooldown periods – for instance, preventing a new trade immediately after a stop-loss event. The function checks both your historical backtest data and, if you’re running live, your live trading data to find the most recent signal. If no signal exists for the specified trading pair, it will return null. It automatically figures out if it’s running in a backtest or a live environment.

    -

    You provide the trading symbol, like 'BTCUSDT', to specify which asset's signal you want.

    -

    The getFrameSchema function lets you look up the blueprint for a specific frame within your backtest. Think of it as finding the detailed instructions for how a particular component of your trading simulation should work. You provide the name of the frame you're interested in, and it returns a description outlining its properties and expected behavior. This is helpful when you need to understand or dynamically work with the structure of your backtest frames.

    -

    This function lets you fetch the details of a specific cryptocurrency exchange that backtest-kit knows about. Think of it as looking up the blueprint for how that exchange operates. You provide the name of the exchange you’re interested in, and it returns a structured description of its data format and capabilities. This is useful for understanding the expected data and tailoring your trading strategies accordingly. The exchange name must be a valid identifier recognized by the framework.

    -

    This function gives you a set of default settings for the backtest-kit framework. Think of it as a starting point for your configurations. It provides a collection of numbers and boolean values that control various aspects of the backtesting process, like how often data is fetched, limits on the number of signals generated, and whether certain features are enabled. Exploring this default configuration is a great way to understand all the available options before you customize them for your specific trading strategy.

    -

    This function provides you with a set of predefined column configurations used for generating markdown reports. Think of it as a template for how your report's columns are structured. It gives you the default layout for various data types like strategy results, heatmap rows, live ticks, partial fills, breakeven events, performance metrics, risk events, scheduled events, strategy events, synchronization events, highest profit events, maximum drawdown events, walker P&L data, and overall strategy results. You can use this to understand the available column options and their initial setups, which is helpful when customizing your reports.

    -

    This function, getDate(), helps you retrieve the current date within your trading simulations or live trading environment. When you're running a backtest, it gives you the date associated with the specific timeframe being analyzed. If you’re running in a live trading scenario, it provides the current, real-time date. Essentially, it's a simple way to know what date your calculations and decisions are based on.

    -

    This function gives you a snapshot of the current environment where your trading logic is running. Think of it as a way to peek behind the curtain and see what's happening during a trade execution. It provides a context object that holds information crucial for understanding the current method's behavior and available resources. It's useful when you need to access data or settings related to the ongoing process.

    -

    This function lets you peek at the system’s settings. It gives you a snapshot of all the global configuration values, like how often things are checked, limits on data requests, and various controls for generating reports and managing signals. The important thing is that it provides a copy of these settings, so you can look at them without changing the actual system configuration.

    -

    This function gives you access to the configuration of columns used for generating reports. Think of it as a snapshot of what data is being displayed in your backtest results.

    -

    It provides different sets of columns for various aspects of your backtest, like closed trades, heatmaps, live data, and performance metrics.

    -

    Essentially, you can peek at how the columns are set up to understand the report's structure and the data it presents. The returned configuration is a copy, so changes won't affect the actual backtest-kit setup.

    -

    This function helps you fetch the closing price of the most recent candle for a specific trading pair and timeframe. Think of it as a way to quickly get the latest market price for a particular asset, like Bitcoin against USDT, at a defined interval such as every minute or every hour. You provide the symbol of the trading pair (e.g., BTCUSDT) and the candle interval (like 1m, 5m, 1h), and it returns that closing price. It's useful for making quick decisions based on the latest price action.

    -

    This function helps you retrieve historical price data, also known as candles, for a specific trading pair. You tell it which symbol you’re interested in, like "BTCUSDT" for Bitcoin against USDT, and the time interval for the candles, such as "1h" for one-hour candles. Finally, you specify how many candles you want to pull back in time. It uses the underlying exchange's tools to get this data for you.

    -

    This function helps determine if a trade has become profitable enough to cover the costs involved in the transaction. It looks at the current price of a trading pair and compares it to a threshold that accounts for slippage and trading fees. Essentially, it's checking if the price has moved in a favorable direction to the point where any losses from the trade have been recovered. The function automatically knows whether it's running in a backtesting environment or a live trading situation. You provide the symbol of the trading pair and the current price to see if the breakeven point has been surpassed.

    -

    This function helps you find out the dates and times included in a backtest for a specific trading pair, like BTCUSDT. It returns a list of dates that represent the period being analyzed. Essentially, it tells you the start and end points of the backtest data for that particular asset. You provide the symbol of the trading pair, and the function gives you back a list of dates.

    -

    This function helps you figure out the average price of a trading pair, like BTCUSDT.

    -

    It uses a method called VWAP, which takes into account both the price and the trading volume. Basically, it looks at the last few minutes of trading activity to give you a sense of the overall average.

    -

    If there’s no trading volume for a particular period, it will just calculate the average of the closing prices instead.

    +

    This function lets you check how long a signal has been waiting to be activated for a specific trading pair. It will give you a number representing the waiting time in minutes.

    +

    If no signal is currently scheduled for that particular trading pair, the function will return null.

    +

    You provide the symbol of the trading pair (like "BTC-USDT") as input to get the waiting time.

    +

    This function helps you understand how profitable your current open trades are. It calculates the unrealized profit or loss as a percentage, considering factors like partial trade closures, multiple entries (like with dollar-cost averaging), slippage, and trading fees.

    +

    If there aren't any open trades currently being managed, it will return null.

    +

    It simplifies the process by automatically determining whether the backtest is running in a simulation or a live environment, and it fetches the latest market price for accurate calculations. You just need to provide the trading pair symbol like "BTCUSDT."

    +

    This function helps you understand how much profit or loss you're currently holding on a trade. It calculates the unrealized profit or loss in dollars for a trade that's still open, using the current market price.

    +

    The calculation takes into account things like how much you invested, any partial closes you've made, how you entered the trade (like dollar-cost averaging), potential slippage and trading fees. If there’s no ongoing trade, the function will return null.

    +

    You don’t need to worry about whether you’re in a testing or live trading environment or retrieving the latest price; it handles those automatically. You simply provide the symbol of the trading pair you're interested in.

    +

    This function helps you track how your trades are being partially closed out. It gives you a list of each time a portion of your position was closed for either profit or loss, providing details about the price at which it happened and the accumulated cost basis at that point.

    +

    If no trade is currently in progress, the function will return null. If partial closes have occurred, you’ll get an empty array.

    +

    For each partial close, you’ll see the type (profit or loss), the percentage of the position closed, the current price used for the execution, the cost basis at the time, and how many DCA entries were included. The function requires the symbol of the trading pair you’re interested in.

    +

    This function helps you avoid accidentally closing out a portion of your position multiple times at roughly the same price. It checks if the current market price is close to a price where you’ve already started a partial closing process.

    +

    Think of it as a safety check to prevent unwanted repeats.

    +

    It looks at previously executed partial closing orders and sees if the current price falls within a certain acceptable range around those prices – a range determined by configurable percentages. If the current price is within that range, it means a partial close is already in progress, and the function returns true. If there are no past partial closes or the current price is too far from them, it returns false, indicating it's safe to proceed with a potential partial close. You can adjust the sensitivity of this check by providing a ladder parameter that controls how wide the acceptable price range is.

    +

    This function helps you find out when a specific trading position experienced its biggest loss. It looks back at the entire history of that position, identifies the point where the price dipped the lowest, and then tells you the exact timestamp of that event.

    +

    If there isn't an active trade open for the given symbol, it will return null, meaning no drawdown timestamp can be determined.

    +

    You'll need to provide the symbol of the trading pair (like BTC-USDT) to get the timestamp.

    +

    This function helps you understand the most significant loss a specific trading position has experienced. It looks at the historical price data for a given symbol and finds the lowest point the price reached while the position was active.

    +

    Essentially, it's like finding the 'bottom' of a price decline for a particular trade.

    +

    If there’s no existing trading signal for that symbol, the function will return null.

    +

    You provide the symbol of the trading pair (like BTC-USDT) to get this drawdown information for that specific position.

    +

    This function helps you understand the performance of a specific trading position. It calculates the maximum drawdown in percentage terms based on the profit and loss (PnL) of that position. Essentially, it tells you the biggest percentage loss the position experienced from its highest point.

    +

    If there's no active signal for the specified trading pair, the function will return null, indicating that data isn't available. You simply provide the symbol of the trading pair you're interested in to get this drawdown information.

    +

    This function helps you understand the maximum drawdown experienced by a specific trading position. It calculates the financial cost, expressed in the quote currency, incurred when the position hit its lowest point. Essentially, it tells you how much money you would have lost at the worst possible time for that position.

    +

    If there's no active trading signal for the position, the function will return null.

    +

    To use it, you'll need to provide the symbol of the trading pair you're interested in, like "BTC-USDT."

    +

    This function tells you how much time has passed since your position experienced its lowest point, or maximum drawdown. It essentially measures the duration of the biggest loss you've had so far for a specific trading pair. The number represents minutes, and it will be zero if the lowest point just happened. If there's no open position for the given symbol, it won't return a value. You provide the symbol, like "BTCUSDT," to get the drawdown time for that particular trade.

    +

    getPositionLevels lets you see the prices at which your initial buy and any subsequent DCA buys were made for a particular trading pair. Think of it as a way to track your DCA entries.

    +

    If there's no active trade signal, it will tell you with a null return.

    +

    If you only made one initial buy, it will return an array containing just that original price.

    +

    Otherwise, you'll get an array listing the original entry price, followed by all the prices where you added more buys using commitAverageBuy. This lets you review the progression of your DCA strategy.

    +

    getPositionInvestedCount helps you track how many times a position has been adjusted through dollar-cost averaging (DCA).

    +

    It tells you the number of DCA entries made for a specific trading pair. A value of 1 indicates the initial trade; higher numbers mean subsequent DCA buys.

    +

    If there’s no active trade to track, the function returns null.

    +

    The function automatically determines whether it's running in a backtest or live environment.

    +

    You simply provide the trading pair symbol to get this information.

    +

    This function helps you figure out how much money you've invested in a particular trading pair, like BTC/USD. It calculates the total cost based on all the average buy orders that have been placed.

    +

    If no orders are pending, it will return null.

    +

    The function intelligently knows whether it's running in a backtest or live trading environment. You just need to provide the symbol of the trading pair you’re interested in.

    +

    This function helps you find out exactly when a specific trade (identified by its symbol) made the most money during its active period.

    +

    It returns a timestamp, which is like a precise date and time, marking that peak profit moment.

    +

    If there's no trade history or signals associated with the given symbol, it will return null, indicating no profit information is available. You'll need to provide the trading symbol, such as "BTCUSDT", to get the timestamp.

    +

    This function helps you find the highest price your position has reached while being profitable. It essentially remembers the best price achieved in a favorable direction since the position began.

    +

    For long positions, it tracks the highest price above the initial entry price. For short positions, it tracks the lowest price below the entry price.

    +

    It provides this information for a specific trading symbol.

    +

    You'll always get a value (like the entry price itself) as long as the position is active; otherwise, it will return null, indicating no signal is pending.

    +

    This function tells you how long ago your current trading position reached its highest profit.

    +

    It essentially measures the time passed since the position's peak performance.

    +

    Think of it as a way to see how far your position has fallen from its best point.

    +

    The value will be zero if you're checking it at the precise moment the peak profit was achieved.

    +

    You'll get a null value back if there are no active signals for the specified trading pair.

    +

    The input is the symbol of the trading pair you're interested in, like "BTCUSDT".

    +

    This function helps you understand how far your trading position has moved from its best possible profit. It calculates the difference between the highest profit percentage achieved so far and the current profit percentage, but it only considers the positive difference – meaning it won’t show a negative value even if the current profit is lower than the peak. If there's no trading activity yet, the function won't return anything. You provide the trading pair symbol (like 'BTCUSDT') to get the information specific to that pair.

    +

    This function helps you understand how far your current trading position is from its best possible profit. It calculates the difference between the peak profit you could have achieved and what you've made so far.

    +

    Think of it as a measure of how much room you still have to gain.

    +

    The function takes the trading symbol (like "BTC-USDT") as input.

    +

    It will return a number representing this distance in profit and loss (PnL) cost, or it will return nothing if there’s no active trade signal.

    +

    This function helps determine if a trade could have reached a breakeven point at its peak profit. It checks if, mathematically, the highest profit achieved during a trade was still achievable without losses.

    +

    If there are no open trades or signals, the function will let you know by returning null.

    +

    To use it, you’ll need to provide the trading pair symbol you’re interested in, like 'BTCUSDT'.

    +

    This function helps you understand how well a specific trading position performed. It tells you the highest percentage profit achieved during the entire time the position was open.

    +

    Think of it as finding the peak of a hill – it shows the moment when the position was most profitable.

    +

    To use it, you need to provide the trading symbol, like "BTC-USDT".

    +

    If there's no record of a profitable price for that position, the function will return null.

    +

    This function lets you find the highest profit-and-loss cost that occurred while a trading position was active. Specifically, it looks at the moment the best (most profitable) price was achieved for a given trading pair.

    +

    If there isn't a signal pending for that position, the function will return null.

    +

    You provide the symbol of the trading pair (like BTC-USD) to identify the position you're interested in. The function returns a number representing that highest PnL cost, expressed in the currency of the quote asset.

    +

    This function helps you understand how risky a specific trading position has been. It calculates the largest percentage drop in profit a position experienced from its peak to its lowest point.

    +

    Think of it as measuring the "depth" of the worst loss a trade has seen.

    +

    The result is expressed as a percentage – a higher number means a greater potential for loss.

    +

    If there's no active trading signal for the specified trading pair, the function won’t be able to provide a value and will return null.

    +

    You need to provide the trading pair symbol, like "BTCUSDT", to check the drawdown of that particular position.

    +

    This function helps you understand how far your position is from its lowest point during a drawdown, expressed as a profit and loss (PnL) cost. It calculates the difference between your current PnL and the lowest PnL your position has seen, ensuring the result is never negative (since a drawdown can't increase your profit). Essentially, it’s a measure of how much room your position has to recover from a previous loss. If there’s no active trading signal for the specified symbol, the function won’t return a value. You need to provide the trading pair symbol (like "BTC-USDT") to retrieve this data.

    +

    This function helps you understand how long a trading position is expected to last. It looks at the current pending signal and tells you the estimated duration in minutes. Think of it as checking the planned lifespan of a trade.

    +

    If there’s no active signal currently, it won't be able to provide an estimate and will return null.

    +

    You provide the trading symbol, like "BTCUSDT," to see the estimated time for that specific pair.

    +

    getPositionEntryOverlap helps avoid accidentally entering multiple DCA positions at roughly the same price.

    +

    It checks if the current price is close enough to one of your existing DCA entry levels – essentially, it sees if you’re already within a tolerance zone around a previous price.

    +

    The function returns true if the current price falls within a specified range around any of your existing DCA levels, which helps to prevent unwanted overlapping entries. If no DCA entries exist, it will return false.

    +

    You can customize how close is "too close" using the ladder parameter, letting you adjust the tolerance zone. The ladder parameter dictates how much price fluctuation is acceptable before a new DCA entry is allowed.

    +

    getPositionEntries lets you peek at the history of how a trade was built up. It gives you a list of the prices and costs for each part of a position, whether it was the initial purchase or a later DCA (Dollar Cost Averaging) step. If there's no ongoing trade being built, the function will tell you that. If a trade is in progress but no DCA has happened yet, you’ll see a list containing only the opening price and cost. To see this information, you simply provide the symbol of the trading pair, like "BTC/USDT."

    +

    This function helps you determine the average entry price for a trade you're currently setting up. It calculates a weighted average, taking into account any previous trades and how much you’ve spent.

    +

    It figures this out using a special method that accounts for the cost of each purchase.

    +

    If you've closed parts of your position before, it calculates the price carefully, combining the prices from those partial closures with any later additions to your position. If you haven't used DCA, it's simply the opening price of the trade.

    +

    If no trade is currently being prepared, the function will let you know by returning a null value. It cleverly adapts to whether you're running a backtest or a live trade.

    +

    You only need to provide the symbol of the trading pair (like BTCUSDT) as input.

    +

    This function helps you understand how long a trade has been losing ground since its most profitable point. It tells you the number of minutes that have passed since the price peaked for that specific trading pair.

    +

    Think of it as a measure of how far a trade has fallen from its best performance.

    +

    The value will be zero right when the peak profit is achieved, and it steadily increases as the price moves lower.

    +

    If there's no active trade happening for the specified symbol, the function will return nothing. You need to provide the symbol of the trading pair you are interested in.

    +

    getPositionCountdownMinutes calculates how much time is left before a trading position expires. It looks at when the position was initially flagged as pending and compares that to an estimated expiration time.

    +

    The function will return the remaining time in minutes, but it won't ever show a negative number – if the estimated time has already passed, it returns zero. If a pending signal isn’t found for the specified trading pair, the function will return null.

    +

    You provide the symbol of the trading pair (like "BTCUSDT") to get the countdown for that specific position.

    +

    getPositionActiveMinutes helps you understand how long a particular trade has been running. It tells you the number of minutes a position has been open, giving you a sense of its duration. If there's no active signal for that trade, it will return null, indicating that it can't calculate the active time. You provide the trading pair symbol, like "BTCUSDT," and it gives you back the time in minutes.

    +

    This function lets you check if your trading strategy currently has a pending order based on a signal.

    +

    It essentially tells you if a signal is waiting to be executed.

    +

    If there’s no pending signal for a particular trading pair (like BTC/USDT), it will return nothing.

    +

    The function automatically figures out whether it's running a backtest or a live trade, so you don't need to worry about specifying that.

    You just need to provide the symbol of the trading pair you’re interested in.

    -

    This function retrieves a list of aggregated trades for a specific trading pair, like BTCUSDT. -It pulls this data directly from the exchange you've configured.

    -

    You can request all trades within a defined time window or specify a maximum number of trades to retrieve. If you don't set a limit, it will fetch trades from the past hour. If you do provide a limit, it will collect enough trades to meet that requirement.

    -

    This function helps you find the blueprint for a specific action within your trading strategy. Think of it like looking up the definition of a command – you give it the action's name, and it returns the details outlining what that action should do. It's essential for understanding and validating the actions your backtest kit is performing. The actionName is a unique identifier that tells the function exactly which action schema to retrieve.

    -

    This function helps you display the right amount of a traded asset, like Bitcoin or Ethereum, by automatically applying the rules of the exchange you're using. It takes the trading pair symbol (e.g., BTCUSDT) and the raw quantity as input. The function then figures out how many decimal places are needed based on that specific trading pair and returns a formatted string representing the quantity. This ensures that the displayed value matches what the exchange expects, preventing potential order issues.

    -

    This function helps you display prices correctly for different trading pairs. It takes a symbol, like "BTCUSDT," and the raw price value. It then uses the exchange’s specific rules to format the price, ensuring the right number of decimal places are shown, which is important for accurate representation. Essentially, it handles the details of how different exchanges display prices so you don't have to.

    -

    The dumpText function lets you save raw text data, like logs or analysis results, associated with a specific signal. Think of it as a way to record important information related to a trading decision. It automatically handles things like figuring out which signal it belongs to and whether you're in a backtesting or live trading environment, making it easy to use in different situations. You provide a description, a unique identifier (dumpId), the text itself, and the name of the bucket where it should be stored.

    -

    This function lets you display data as a structured table within the backtest or live trading environment. It takes an array of objects, essentially a collection of rows, and presents them in an organized table format. The table's column headers are automatically determined based on all the different keys found across all the objects in your data. You provide the function with details like the bucket name, a unique ID for the dump, the actual data (the array of objects), and a description to help identify the table. It's designed to work seamlessly, handling signal resolution and mode detection automatically.

    -

    The dumpRecord function helps you save a snapshot of data related to a specific trading signal. Think of it as a way to preserve important information from your backtests or live trading sessions. It takes a record of key-value pairs and associates it with a bucket and ID, along with a description to help you understand what the record represents. The function intelligently figures out whether it's running a backtest or live trading based on its environment and handles signals automatically.

    -

    The dumpJson function helps you record detailed information about your trading decisions. Think of it as a way to save a snapshot of data—like the state of your indicators or the reasoning behind a trade—in a structured JSON format. It's designed to be linked to specific trading signals, making it easy to understand the context of that data later. This function automatically figures out whether you're running a backtest or a live trade, so you don't have to worry about configuring it differently.

    -

    It takes a single object as input that contains the bucket name, a unique dump ID, the JSON data you want to save, and a descriptive message. The function then saves this JSON data, associating it with the correct trading signal. This lets you reconstruct what was happening at a particular moment in your trading history.

    -

    This function lets you record details about an error that occurred during a backtest or live trading session. Think of it as a way to create a log entry specifically tied to a particular trading signal.

    -

    It automatically figures out whether you're in a backtest or live environment and will also handle resolving any pending or scheduled signals that might be relevant to the error. You provide information like the bucket name, a unique dump ID, the error description itself, and a more general description of the problem. This helps with debugging and understanding what went wrong.

    -

    This function helps you save the complete conversation history with the AI agent, linking it to a specific trading signal.

    -

    Think of it as archiving a detailed record of the agent's reasoning for a particular trade.

    -

    It automatically figures out whether you're in a backtesting or live trading environment and resolves the relevant signal for you, simplifying the process of saving this data.

    -

    You provide the function with a name for the data bucket, a unique ID for the dump, the messages exchanged with the agent, and a brief description.

    -

    This function helps you manage the state of signals within your trading strategies. It gives you two handy functions, getState and setState, that let you access and update the signal's information.

    -

    The great thing is you don't need to manually specify the signal ID – it figures it out automatically based on where your strategy is running (backtest or live).

    -

    This is particularly useful if you're building advanced strategies, like those driven by large language models, that need to track details about each trade, such as how long it's been open or its highest gain. The function is designed to work well with strategies that need to gather information over time and potentially exit trades based on those metrics.

    -

    This function lets you manually set the take-profit price for a trade. It’s handy when you want to lock in a profit at a specific price level, regardless of how the price has moved since the trade was opened.

    -

    The function cleverly figures out whether you're backtesting or trading live and automatically gets the current price to calculate the adjusted take-profit. You only need to specify the symbol and the desired take-profit price.

    -

    This function lets you fine-tune the trailing take-profit for an open pending order. Think of it as gently nudging your take-profit level based on market movement.

    -

    It’s important to understand it always calculates adjustments based on the original take-profit you set, not the current, potentially trailing, one. This helps avoid small errors from adding up over time.

    -

    If you want to make your take-profit more conservative (closer to the entry price), use a negative percentage shift. A positive percentage shift will move it further away, making it more aggressive.

    -

    The function will only actually change the take-profit if the new level is more conservative than the current one. For long positions, it will only lower the take-profit. For short positions, it will only raise it.

    -

    It smartly figures out whether it's running in backtest mode or live trading mode based on where it's being used.

    -

    You'll need to provide the symbol (like 'BTCUSDT'), the percentage adjustment you want to make, and the current market price.

    -

    This function lets you change the trailing stop-loss price to a specific value. It simplifies setting a stop-loss by handling the calculations needed to adjust it based on the original stop-loss distance. The system figures out whether it's running a backtest or a live trading scenario and automatically gets the current price to make the calculation. You just need to provide the symbol you're trading and the new stop-loss price you want to set.

    -

    The commitTrailingStop function helps fine-tune your trailing stop-loss orders. Think of it as a way to dynamically adjust how far your stop-loss is from your entry price.

    -

    It's really important to understand that this function always bases its calculations on the original stop-loss distance you set initially – not on any adjustments made by previous trailing stop calculations. This prevents small errors from building up over time.

    -

    The percentShift parameter controls how much to adjust the stop-loss, with negative values bringing it closer to your entry price and positive values moving it further away. It also has a smart "absorption" feature: it only makes changes if the new stop-loss is actually better for protecting your profits. For long positions, it will only loosen the stop-loss, and for short positions, it will only tighten it.

    -

    Finally, the function intelligently knows whether it's running in a backtest or live trading environment.

    -

    You'll need to provide the trading pair's symbol, the percentage adjustment you want to apply, and the current market price.

    -

    This function lets you send out informational messages related to your trading strategy. Think of it as a way to add notes to your backtest or live trading process – it won't change your positions, but it will help you understand what's happening. You can use it to log important decisions, send alerts, or track events within a trade.

    -

    The function handles a lot of the setup for you; it knows whether you're running a backtest or live, and it automatically includes details like the strategy name, exchange, and the current price of the asset.

    -

    You simply provide the symbol you're trading and any extra information you want to include in the notification.

    -

    The commitPartialProfitCost function lets you automatically close a portion of your trading position when you've made a specific dollar amount in profit. It simplifies the process by taking a dollar amount you want to realize in profit and converting that to the appropriate percentage of your original position cost.

    -

    Essentially, it's a shortcut for partially closing a trade when you've reached a desired profit level, ensuring the price is moving in a favorable direction toward your take profit target. It handles the details of figuring out the percentage and automatically adjusts based on whether you're running a backtest or a live trade and retrieves the current price for you.

    -

    You provide the symbol of the trading pair and the dollar amount you want to close, like closing $150 worth of your position.

    -

    The commitPartialProfit function lets you automatically close a portion of your open trade when the price is moving in a profitable direction, essentially moving you closer to your target profit. You specify the symbol of the trading pair and the percentage of your position you want to close, like 25% or 50%. This function is designed to work seamlessly whether you’re backtesting strategies or running live trades because it adapts to the execution environment. It’s a handy tool for locking in some profits as your trade progresses.

    -

    This function lets you partially close a trade to limit losses, by specifying a dollar amount. It’s a shortcut that figures out the percentage of your position to close based on that dollar value. Essentially, it helps move your trade closer to your stop-loss order.

    -

    The function handles the details of determining if the price is trending in the loss direction and retrieving the current price, so you don’t have to worry about those. You just need to tell it which trading pair you're working with and how much in dollars you want to reduce the position size. It works seamlessly whether you’re running a backtest or a live trade.

    -

    This function lets you close a portion of an open trade when the price is heading towards your stop-loss level. It's designed to help manage risk by automatically reducing your exposure on a trade that’s moving against you. You specify the symbol of the trading pair and the percentage of the position you want to close. The system handles whether it's running a backtest or a live trade for you.

    -

    This function lets you feed custom trading signals into your backtest or live trading environment. Think of it as a way to inject your own logic or external data directly into the trading process, bypassing the usual signal retrieval methods.

    -

    The signals are processed in the next tick. If you don't provide a specific price target (priceOpen), the signal is executed right away at the current price. If you do provide a price target, the signal will execute as soon as that price is reached, or it will be scheduled to wait for it.

    -

    Before the signal is processed, it goes through a validation check. And to keep things stable, it prevents you from sending multiple signals at once – only one signal or deferred action can be active at a time.

    -

    The function automatically adapts to whether it's running a backtest or a live trading session.

    -

    You provide the trading symbol and a data object representing your signal.

    -

    This function allows you to cancel a pending order without interrupting your trading strategy. Think of it as a way to clear a signal you've previously set but don't want to execute right now.

    -

    It won't impact any other signals or the overall operation of your strategy, and it won't prevent the strategy from creating new signals. The function intelligently adapts to whether you’re in a backtesting or live trading environment.

    -

    You can optionally provide details like an ID and a note to document the reason for cancelling the pending order.

    -

    This function lets you cancel a scheduled trading signal without disrupting your strategy’s overall operation. Think of it as hitting the pause button on a signal that's waiting to be triggered – it clears the signal that's been set but allows your strategy to keep running and generating new signals. It's useful if you want to change your mind about a planned action. Importantly, this doesn't affect any currently active signals or stop your strategy from working; it simply removes the scheduled one. The framework automatically determines whether it's running a backtest or live trading session. You can optionally include details like an ID and note in the cancellation.

    -

    This function helps manage your trades by automatically adjusting your stop-loss order. It essentially aims to protect your profits by moving the stop-loss to your entry price once the trade has moved favorably enough to cover potential fees and a small amount of slippage.

    -

    It handles the complexity of determining when to trigger this adjustment—it calculates the threshold based on pre-defined percentages for slippage and fees—and it automatically figures out whether you're in a backtesting or live trading environment. You don’t need to worry about getting the current price either; the function fetches that for you.

    -

    Just provide the symbol of the trading pair, and it takes care of the rest, potentially reducing your risk and securing some gains.

    -

    The commitAverageBuy function lets you add a new buy order to your trading strategy's history, useful for dollar-cost averaging (DCA). It essentially records a purchase at the current market price, helping to build a record of how your position was accumulated.

    -

    The function also calculates and updates a running average of the entry prices, and it notifies the system that a new average buy has occurred.

    -

    It handles whether you're running a backtest or a live trade automatically and uses a built-in method to find the current price. You just need to specify the trading pair symbol for the trade. Optionally, you can provide a cost parameter.

    -

    This function lets you trigger a scheduled order to execute before the price actually hits the target price you initially set. It’s useful when you want to proactively manage your trades.

    -

    Essentially, you’re setting a "go" signal for the strategy. The strategy will then act on that signal during the next price update.

    -

    You need to specify the trading symbol for the order, and you can optionally include extra information like an ID or a note to help you track the trade. The framework figures out whether it's running a backtest or a live trading session automatically.

    -

    The checkCandles function is a quick way to see if your historical market data (candles) are already stored and ready to be used. It efficiently verifies if the data exists without having to load everything, which saves time and resources. Think of it as a preliminary check before starting a backtest – it makes sure the data you need is there. It relies on the persistence adapter to handle the actual checking process.

    -

    This function helps make sure your historical price data (candles) is available where it needs to be, usually in a persistent storage location. It's designed to check if the data already exists, and if not, it automatically fetches and validates the missing data. Think of it as a way to proactively prepare your trading system with the data it needs without you having to manually download everything. The function downloads missing data, and then double-checks the data is correct. It’s like having a backup plan for your historical price information.

    -

    It takes information about which asset (symbol), timeframe (interval), data start and end dates (from, to), the exchange providing the data (exchangeName), and functions to track progress (onCheckStart, onWarmStart) as input.

    -

    This function lets you register a new "walker" – essentially a set of instructions – that will help compare how different trading strategies perform against each other. Think of it as setting up a system to run multiple backtests simultaneously, using the same data, and then evaluating them based on a chosen performance measure. You provide a configuration object, detailing how this comparison process will work, and the function takes care of registering it within the backtest-kit framework.

    -

    This function lets you tell the backtest-kit about a new trading strategy you've created. Think of it as registering your strategy so the system knows how to use it. When you register a strategy this way, the framework will automatically check it for common issues like making sure your price data is valid and your take profit/stop loss logic works correctly. It also helps prevent the system from getting overwhelmed with signals and ensures that your strategy's information is safely stored even if there are unexpected problems during live trading.

    -

    You provide the strategy's configuration details – a strategy schema – when you call this function.

    -

    This function lets you tell the backtest-kit how to determine the size of your trades. It’s all about defining rules for how much capital to allocate to each trade based on factors like risk tolerance and market volatility. You provide a sizing schema, which acts as a blueprint outlining the specific sizing method, risk parameters, and any limitations on position sizes. Essentially, it’s a key component for managing risk and ensuring your trading strategy aligns with your overall investment goals.

    -

    This function lets you tell the backtest-kit framework about your risk management rules. Think of it as setting up guardrails for your trading.

    -

    You'll define things like how many trades you can have running at once and even create custom checks to make sure your portfolio stays healthy – maybe checking for correlations between different assets.

    -

    The system keeps track of all your open positions across all your strategies, so it can apply those rules consistently. Multiple strategies use the same risk rules, which helps analyze how they interact and keep everything in check.

    -

    This function lets you tell the backtest-kit about a new timeframe generator it can use. Think of it as registering a way to slice up your historical data into specific time periods for testing. You provide a configuration object that outlines how these timeframes should be created – specifying the overall test period, the interval (like daily, hourly), and a function that will handle the actual generation of these timeframes. Essentially, you're giving the backtest-kit another tool to analyze your data.

    -

    The configuration object you provide has details about the start and end dates for your backtest, the interval of your timeframes, and a function that's called to actually generate the timeframes themselves.

    -

    This function lets you tell the backtest-kit framework about a new data source for an exchange. Think of it as registering where the framework should look to get historical price data, understand the specific formatting of prices and quantities for that exchange, and calculate things like VWAP (volume-weighted average price). You'll provide a configuration object that defines these details for the exchange you want to use. This is a crucial step to enable backtesting with data from a specific exchange.

    -

    This function lets you register a special "action" that will be triggered during your backtest or live trading. Think of actions as automated responses to specific events happening in your strategy, like when a trade hits a profit target or a stop-loss.

    -

    They’re really useful for a bunch of things: keeping track of your trading activity, sending yourself alerts (like to Discord or Telegram), connecting to external systems, or even running custom logic based on what’s happening in your strategy.

    -

    Each time your strategy executes, a new action gets created, and it gets all the important details about what’s happening - signals, profit/loss, and more. You provide a configuration object (actionSchema) to tell the framework exactly what kind of action you want.

    -
    +

    This function lets you retrieve the order book for a specific trading pair, like BTCUSDT.

    +

    It pulls data from the connected exchange.

    +

    You can optionally specify the depth, which controls how many levels of bids and asks you receive. If you don’t provide a depth, it uses a default value.

    +

    The function considers the current time when fetching the order book, which is important whether you're testing past trades or live trading. The exchange itself decides how to use this timing information.

    +

    This function helps you grab a set of future candles for a specific trading pair and time interval. Think of it as requesting a batch of candles that come after the point in time the backtest is currently at. It utilizes the underlying exchange's mechanism to get those candles, ensuring you're getting data that aligns with how the exchange would have provided it. You just need to specify the symbol (like BTCUSDT), the candle interval (like 1 minute, 1 hour, etc.), and how many candles you want to retrieve.

    +

    This function tells you whether the backtest-kit framework is currently running a historical simulation (backtest) or a live, real-time trading session. It returns a simple indicator: either "backtest" or "live". You can use this to adjust your code's behavior depending on the environment it's operating in.

    +

    This function helps you figure out how much time has passed since the last trading signal was generated for a specific asset, like BTC-USD. It gives you the number of minutes that have gone by, rounding down to the nearest whole minute.

    +

    It doesn't matter if the previous signal is still active or already closed - it just looks at the very last one that was recorded. This is handy for things like making sure you wait a certain amount of time before placing another trade after a stop-loss order.

    +

    The function first checks your historical backtesting data and then checks your live data to find that signal. If no signals have ever been created for that asset, it returns null. It automatically knows whether it's running in backtest mode or live mode.

    +

    You just need to tell it which asset you're interested in, using its symbol.

    +

    This function helps you understand the riskiness of a trading strategy by calculating the maximum drawdown. It looks at the highest profit achieved and the lowest point of loss (drawdown) for a specific trading pair, like 'BTC-USDT'. The result is a percentage representing the difference between those two points, but it will always be zero or positive. If there's no trading activity for that symbol, it won’t provide a result.

    +

    This function helps you understand the potential risk of a trading strategy by calculating the maximum drawdown distance based on profit and loss. It looks at the difference between the highest profit achieved and the lowest point of loss, but only considers the positive difference – essentially, the largest potential loss from a peak. The result represents the cost distance.

    +

    To use it, you simply provide the trading symbol (like "BTC/USD") and it will return a number.

    +

    If there's no trading activity or signals for the specified symbol, it won't return a value.

    +

    This function helps you retrieve the most recent trading signal – whether it's still pending or has already closed – for a specific trading pair. It doesn’t differentiate between active and closed signals, simply providing the one that was recorded most recently. This can be helpful for things like cooldown periods; for example, you might want to prevent opening a new trade for a certain amount of time after a stop-loss is triggered. The function looks for signals first in the backtest data and then in live data, and will return nothing if no signals exist. It figures out whether you’re in backtest or live mode automatically. You provide the trading pair's symbol as input.

    +

    The getFrameSchema function helps you find the blueprint, or schema, for a specific frame within your backtest. Think of it like looking up the definition of a particular component in your trading system. You give it the name of the frame you're interested in, and it returns detailed information about what that frame contains and how it operates. This is useful when you need to understand or programmatically interact with the structure of a frame.

    +

    This function helps you find information about a specific cryptocurrency exchange that your backtesting system understands. It’s like looking up the details of how to connect to and retrieve data from a particular exchange. You give it the name of the exchange, and it returns a set of rules and data structures defining how that exchange works. This is useful for ensuring your backtesting strategy is compatible with the exchange data you're using.

    +

    This function provides a set of pre-defined settings for the backtest-kit framework. Think of it as a template to get you started—it shows you all the adjustable options and what they're set to by default. It's a great way to understand the different levers you can pull to customize your backtesting process. This default configuration covers things like how often data is fetched, limits on signal generation, and settings for reports and notifications.

    +

    This function provides the standard set of columns used when generating reports. Think of it as a template for how your reports will look. It gives you a peek at all the different types of data—like strategy performance, risk metrics, or scheduled events—that can be displayed as columns. You can inspect this configuration to understand the available options and how they are pre-defined before customizing them for your specific reporting needs.

    +

    This function retrieves the current date, and its behavior changes depending on whether you're running a backtest or in live trading mode. When backtesting, it provides the date associated with the timeframe you're analyzing. If you’re live, it returns the actual, current date. Essentially, it gives you the date relevant to the context of your trading.

    +

    This function gives you access to the current method's environment. Think of it as a way to peek under the hood and see what's happening during a particular step in your trading strategy's execution. It returns an object filled with details about the method, allowing you to customize behavior or access relevant data.

    +

    This function lets you peek at the system’s core settings. It returns a snapshot of all the configuration values, like how often tasks run, limits on data processing, and flags controlling various features. Importantly, it provides a copy of these settings, so you can look at them without accidentally changing the actual running configuration. Think of it as a read-only window into how the backtest kit is set up.

    +

    This function gives you a peek at how your backtest data will be displayed in the report. It provides details about the columns used for different aspects like closed trades, heatmaps, live data, partial fills, breakeven points, performance metrics, risk management, scheduling, strategy events, synchronization, profit tracking, maximum drawdown, walker pnl data, and overall strategy results. Think of it as a read-only snapshot of the column definitions—you can look, but don't change them directly.

    +

    This function helps you quickly retrieve the closing price from the most recent candle available for a specific trading pair and timeframe. You provide the symbol, like "BTCUSDT" for Bitcoin against USDT, and the candle interval, such as "1m" for one-minute candles or "4h" for four-hour candles. It returns a promise that resolves to the closing price of that last completed candle, giving you a snapshot of the recent market behavior.

    +

    This function allows you to retrieve historical candlestick data for a specific trading pair. You provide the symbol, like "BTCUSDT", the desired timeframe for the candles (options include 1 minute, 3 minutes, 15 minutes, and several longer intervals), and the number of candles you want to retrieve. It essentially asks the underlying exchange to provide this data, pulling it backwards from the present time. It's a convenient way to access past price action for analysis or backtesting purposes.

    +

    This function helps you determine if a trade has become profitable enough to cover the initial costs. It calculates a threshold based on slippage and trading fees, and then checks if the current price has exceeded that threshold. You provide the trading pair symbol and the current market price, and the function tells you whether the trade has reached its breakeven point, meaning it's profitable enough to cover the costs of getting into the trade. This function adjusts automatically based on whether you're running a backtest or a live trading environment.

    +

    This function helps you find out the dates and times that your backtest covers for a specific trading pair, like BTCUSDT. It essentially tells you the time period being analyzed. You provide the symbol of the trading pair you're interested in, and it returns an array of dates representing the backtest timeframe for that pair. This is useful for understanding the scope of your backtesting results.

    +

    This function helps you figure out the average price of a trading pair, like BTCUSDT. It uses a method called VWAP, which takes into account both the price and the trading volume. Specifically, it looks at the last five minutes of trading data to determine this average. If there's no trading volume reported, it will just use the average of the closing prices instead. You give it the symbol of the trading pair you're interested in, and it returns a number representing the average price.

    +

    This function retrieves historical trade data for a specific trading pair, like BTCUSDT. It pulls this data directly from the exchange you're using.

    +

    You can request all trades within a set timeframe, or specify a limit to only get the most recent trades. The function ensures you get the requested number of trades by potentially retrieving multiple pages of data. This is useful for analyzing past market activity.

    +

    This function helps you find the blueprint for a specific action within your trading strategy. Think of it as looking up the definition of what a particular action, like "buy" or "sell", should do. You provide the name of the action you're interested in, and it returns a detailed description of that action, outlining what parameters it expects and what kind of data it uses. It's useful for validating your actions or understanding how they’re structured.

    +

    This function helps you display the correct amount of a cryptocurrency or asset when placing orders. It automatically adjusts the number of decimal places based on the specific trading pair, ensuring that your orders comply with exchange requirements. You provide the trading pair symbol, like "BTCUSDT", and the raw quantity value, and it returns a formatted string representing that amount. This ensures accurate order placement and avoids potential rejection due to incorrect formatting.

    +

    This function helps you display prices correctly for different trading pairs. It takes the symbol, like "BTCUSDT", and the actual price value as input. Then, it automatically adjusts the number of decimal places based on the rules of the specific exchange you're using, ensuring your prices look accurate and consistent. Basically, it handles the formatting details so you don’t have to.

    +

    The dumpText function lets you output raw text data, associating it with a specific signal within your backtest or live trading environment. Think of it as a way to record observations or data points related to a particular trading signal. It handles the complexities of knowing which signal is active and whether you're in a backtesting scenario, so you don't have to worry about that.

    +

    The function takes an object containing the bucket name, a unique identifier for the data, the actual text content, and a description to explain the data. It then promises to complete the dumping process without returning any value.

    +

    This function helps you display data in a nicely formatted table. It takes an array of objects (like data from a trading simulation) and turns it into a readable table. The table will be linked to the specific trading signal that was running when it was created.

    +

    It intelligently figures out whether you're running a backtest or a live trading session, and handles the details of setting up the signal automatically. The column headers will be determined by examining all the keys present in your data, ensuring everything is displayed clearly. You provide the data, and this function does the presentation work for you.

    +

    This function lets you save a piece of data, which you might think of as a single observation or event, into a specific storage location. It’s designed to work with the backtest-kit system and automatically adjusts based on whether you're running a test or a live trading session.

    +

    The data you provide is structured as a simple collection of key-value pairs.

    +

    It takes a description to help you understand what the data represents. +The function handles the details of which signal to associate with this data, automatically choosing the appropriate one based on the system’s current state.

    +

    This function helps you save complex data structures, like those generated during backtesting, as neatly formatted JSON. It's like taking a snapshot of your data and storing it in a structured way. The dumpJson function automatically knows whether it's running a backtest or live trading, and handles the signal (a communication channel) for you, so you don't have to worry about those details. You provide a name for your data ("dumpId"), a bucket to store it in ("bucketName"), the actual data you want to save (in the "json" field), and a brief description. It takes care of the technicalities of writing this data out.

    +

    This function lets you record detailed error information, associating it with a specific data bucket and a unique identifier. Think of it as a way to permanently log error details alongside your trading activity. It automatically figures out whether you're running a backtest or a live trading session and handles the signal context, simplifying the error reporting process. You provide the function with information about the error, including a description and its location, and it takes care of the rest.

    +

    This function helps you save detailed records of conversations with the AI agent during a trading simulation or live trading. It takes all the messages exchanged with the agent, along with a description, and stores them together, linked to a specific trading signal.

    +

    Essentially, it’s a way to create a complete audit trail of the agent’s reasoning and actions. The function takes care of figuring out which signal is currently active and automatically adapts to whether you're running a test or a real-time trading session. You just provide the information about the messages and a short description of what’s happening.

    +

    This function helps you manage the state of a trading signal in a simple and organized way. It creates two functions: one to get the current state and another to update it.

    +

    You don’t have to worry about specifying a signal ID because it automatically figures out whether you're in backtesting or live trading mode.

    +

    It’s especially useful for strategies that track details on each trade, like how long a trade lasts or its maximum profit—perfect for complex strategies using large language models.

    +

    Think of it as a way to keep track of important data points for your trades, making it easier to analyze and refine your strategy.

    +

    This function lets you change the take-profit price for a trade to a specific price level. It's helpful if you want to set a fixed target for your profits.

    +

    Essentially, it adjusts the trailing take-profit to match the price you provide.

    +

    It simplifies the process by automatically figuring out if you're in a backtest or a live trading environment and also gets the current market price for you.

    +

    You'll need to give it the trading pair symbol and the new, desired take-profit price. It returns a promise that resolves to a boolean indicating whether the operation was successful.

    +

    This function helps you fine-tune your take-profit orders by adjusting the distance from the original take-profit level. It's designed to keep your trading strategy responsive while avoiding compounding errors that can happen with repeated adjustments.

    +

    Think of it as a way to nudge your take-profit order closer to or further from your entry price, always based on where you initially set that take-profit.

    +

    It’s important to understand that the adjustments are made relative to the original take-profit distance, not the current trailing take-profit, ensuring accuracy over time.

    +

    The function only makes changes that make your take-profit more conservative—meaning it will only move it closer to your entry point. For long positions, it brings the TP down, and for short positions, it raises the TP. The percentShift value determines the size of this adjustment.

    +

    It automatically knows whether it’s running in a backtest or a live trading environment. You just provide the symbol, the percentage adjustment you want to make, and the current price.

    +

    This function lets you change the trailing stop-loss price to a specific value. It handles the technical details of calculating how much the percentage shift needs to adjust, making it easier to manage.

    +

    It figures out whether you're running a backtest or a live trade automatically.

    +

    It also gets the current price to make the calculation accurate.

    +

    You provide the trading symbol and the new stop-loss price you want to set. The function will then return a boolean indicating whether the update was successful.

    +

    This function helps fine-tune your trailing stop-loss orders. It lets you adjust how far away your stop-loss is from your entry price, expressed as a percentage.

    +

    It's especially important to remember that it always bases its calculations on the initial stop-loss distance you set, not any adjustments that might have already been made. This keeps things accurate and avoids compounding errors.

    +

    The function prioritizes protecting your profits. If you try to loosen your stop-loss too much, or move it in a direction that doesn't provide better protection, it won't make the change. For long positions, the stop-loss can only move upward (away from your entry). For short positions, it can only move downward (towards your entry).

    +

    It figures out whether you're in a backtesting environment or live trading mode automatically.

    +

    To use it, you’ll need the trading pair symbol, the percentage change you want to make to the initial stop-loss, and the current market price.

    +

    This function lets you send out informational messages related to your trading strategy. Think of it as a way to add notes or alerts during a backtest or live trade – it won't change your positions, but it will give you extra details about what's happening. It automatically includes information like the trading pair, the strategy name, the exchange, and the current price, simplifying the notification process. You can also add custom details to your notification using the payload parameter to tailor the message to your specific needs.

    +

    The commitPartialProfitCost function lets you close a portion of your trading position when you’ve made a profit, based on a specific dollar amount. It simplifies the process by automatically calculating the percentage of your initial investment that needs to be closed to achieve that dollar amount.

    +

    Essentially, it’s a shortcut for closing off some of your position, moving towards your target profit.

    +

    The function will automatically determine if it's running in a backtesting or live environment and gets the current price to make calculations.

    +

    You just need to specify the trading symbol and the dollar amount you want to close.

    +

    This function lets you automatically close a portion of your trading position when the price moves favorably, essentially moving you closer to your target profit. It’s designed to take profit on a percentage of your open position.

    +

    The function handles whether you're running a backtest or a live trade automatically, so you don’t need to worry about configuring that.

    +

    You'll need to provide the symbol of the trading pair (like BTCUSDT) and the percentage of your position you want to close – for example, 50% would close half of your active position. Keep in mind that the price must be moving in the direction of your take profit for this function to execute.

    +

    This function lets you partially close a position to limit losses, specifying the dollar amount you want to reduce the position by. It's essentially a shortcut – you tell it how much in dollars you want to close, and it figures out the corresponding percentage of your position.

    +

    The system works best when the price is trending in the direction of your stop-loss order.

    +

    It handles the technical details for you, like determining whether it’s running in a backtest or live environment and fetching the current price. You just provide the symbol and the dollar amount you want to use for the partial close.

    +

    The commitPartialLoss function lets you automatically close a portion of your open position when the price is heading towards your stop-loss level. It’s designed to help manage losses by closing a specified percentage of your position, like 25% or 50%, without needing to manually intervene. The function handles whether it's running in a backtesting environment or a live trading account, making it adaptable to different scenarios. To use it, you provide the symbol of the trading pair (like BTC/USDT) and the percentage of the position you want to close.

    +

    This function tells the backtest kit that a take-profit order for an existing position has been filled on the exchange. It's used to handle situations where the actual order execution happens outside of the VWAP-based take-profit checks performed by the framework. Think of it as a way to reconcile what the strategy thought would happen with what actually happened in the market.

    +

    The function essentially confirms a close, marking it as a take-profit event and reporting it on the next tick. If there's no open position waiting for a take-profit, this function does nothing. The framework automatically knows if it's running a backtest or live, so you don't need to specify that.

    +

    You can also add an optional note or ID to the commit payload to provide more context around the trade.

    +

    This function lets you tell the backtest framework that a stop-loss order for a position has been triggered on the exchange. It’s used when the actual order gets filled, perhaps because of a price hitting a high or low, bypassing the usual VWAP-based stop-loss checks.

    +

    Think of it as confirming that the exchange has taken action on the stop-loss, and the position will be closed.

    +

    The framework handles whether it's a backtest or live trading session automatically. If there's no pending signal, this function does nothing. You can also include extra information, like an ID and a note, when calling it to help with tracking and analysis.

    +

    This function lets you feed custom signals into your backtest or live trading environment, bypassing the usual signal retrieval process. You provide a data object (called a Signal DTO) that contains the details of your signal – think of it as giving the system a direct order.

    +

    It's smart about how it handles these signals: if you include a target price, it’ll try to execute the trade immediately if that price is already hit; otherwise, it'll wait for the price to reach that level. If you don’t specify a price, the signal is processed right away.

    +

    Important: It makes sure only one signal or deferred action is being processed at a time, and the data you provide gets checked for validity. It figures out whether it's running a backtest or live trading automatically. You'll need to provide the trading pair symbol and the signal data object.

    +

    This function lets you clear a pending trading signal without interrupting your strategy's operation. Think of it as acknowledging a signal that was previously set but not yet acted upon. It doesn't halt the strategy or prevent it from generating new signals, nor does it set any stop flags. The function intelligently recognizes whether it's running in a backtest or live environment. You can optionally include details like an ID and note with the cancellation.

    +

    This function lets you cancel a previously scheduled signal, essentially removing it from the queue. Think of it as hitting the brakes on a plan without stopping the whole process. It's useful if you've scheduled something but then changed your mind, and you want to keep the strategy running smoothly. Importantly, it doesn't interrupt any signals already in action and won't prevent the strategy from creating new signals. It automatically knows whether it's running in backtest or live mode.

    +

    You tell it which symbol the scheduled signal belongs to, and you can optionally add some extra information like an ID or a note to the cancellation.

    +

    This function helps you automatically manage your stop-loss orders.

    +

    It moves your stop-loss to the entry price, essentially eliminating risk, once the price has moved favorably enough to cover trading fees and a small buffer.

    +

    Think of it as a way to lock in profits when things are going well – it will happen without you needing to manually adjust anything.

    +

    The function handles things like determining whether it's running in a backtest or live trading environment and getting the current price for you. You only need to tell it which trading pair (symbol) to apply this to.

    +

    The commitAverageBuy function lets you add a new purchase to your dollar-cost averaging (DCA) strategy. It essentially records a purchase at the current market price, keeping a record of all your purchases to calculate an average price.

    +

    This function automatically figures out if it's running in a backtest or a live trading environment, and it grabs the latest price for you. It keeps track of the average purchase price and notifies the system that a new average buy has occurred. You just need to tell it the symbol you're trading, and optionally provide a cost.

    +

    This function lets you trigger a scheduled trading signal to execute before the price actually reaches the predetermined entry price.

    +

    Essentially, it's a way to proactively activate a strategy based on a scheduled signal.

    +

    The function handles whether you're in a backtesting environment or live trading without you needing to specify.

    +

    You provide the symbol (like "BTCUSDT") and can optionally include a note or identifier for tracking purposes within the commit payload. Think of it as a way to manually "kick off" a signal, and the system will handle the rest.

    +

    The checkCandles function is a quick way to see if your historical price data (candles) are already stored and ready to be used. It's designed to be efficient – instead of loading all the data, it only checks for the specific candles you expect. If even one candle is missing or out of sync, the whole check fails, letting you know you need to load or refresh the data. This function relies on a “persist adapter” to handle the actual data storage and retrieval.

    +

    The cacheCandles function helps make sure your trading data is readily available. It fetches candlestick data for a specific trading symbol, time period, and exchange.

    +

    It works in two steps: first, it verifies if the data already exists; if not, it downloads the missing pieces and re-checks. This ensures you have the necessary historical data for backtesting or other analyses.

    +

    You'll need to provide details like the symbol you're interested in (e.g., BTC/USDT), the data interval (e.g., 1 hour), the start and end dates for the data you need, the exchange it's from, and optional callbacks to monitor progress.

    +

    This function lets you register a walker, which is essentially a way to run multiple trading strategies against the same historical data and then compare how well they performed. Think of it as setting up a system to evaluate different approaches simultaneously. You provide a configuration object that defines how the walker should operate, including the specific metric used to assess the strategies. This enables systematic comparison and optimization of your trading strategies.

    +

    This function lets you tell the backtest-kit about a new trading strategy you've created. Think of it as registering your strategy so the system knows how to use it.

    +

    When you add a strategy, the framework automatically checks that it's set up correctly, like making sure your price data and stop-loss/take-profit rules make sense. It also helps prevent the strategy from sending too many signals too quickly, and if something goes wrong while you're trading live, it can make sure your strategy’s settings are preserved.

    +

    You provide the strategy's configuration details, which is a structured object defining how the strategy works.

    +

    This function lets you tell the backtest-kit how to determine the size of your trades.

    +

    Think of it as setting up the rules for how much money you’ll risk on each trade.

    +

    You provide a configuration object that specifies things like whether you want to use a fixed percentage of your capital, a Kelly Criterion approach, or something based on Average True Range.

    +

    It also allows you to set limits on how much you can risk per trade and define custom logic for calculating position sizes. The framework then uses this information during the backtest to simulate realistic trade sizing.

    +

    This function lets you define how your trading system manages risk. It's a way to set limits, like the maximum number of positions you can have open at once, and to create custom checks for more complex risk scenarios, such as analyzing portfolio metrics or correlations.

    +

    Think of it as registering a set of rules to keep your trading safe.

    +

    Importantly, multiple trading strategies can share the same risk management setup, so you can analyze how they interact and impact each other. The system keeps track of all open positions, allowing your custom risk checks to access that information.

    +

    This function lets you tell the backtest-kit what kind of timeframes you want to use when running your simulations. Think of it as registering a new way to slice up your historical data into trading periods.

    +

    You provide a configuration object that describes the timeframe's start and end dates, the interval (like daily, weekly, or monthly), and a function that will be called to generate those timeframes. This enables the backtest kit to understand your specific needs for timeframe generation. It’s essential to register these schemas before you begin a backtest.

    +

    This function lets you tell the backtest-kit framework about a new exchange you want to use for your trading simulations. Think of it as registering a data source – it tells the system where to find historical price data and how to interpret it.

    +

    The exchange you register should be able to provide historical candlestick data, handle formatting of prices and trade sizes, and calculate the VWAP (Volume Weighted Average Price) based on recent trades.

    +

    You'll need to create a configuration object that describes your exchange, and then pass it to this function to officially add it to the system.

    +

    This function lets you register a new action handler within the backtest-kit framework. Think of actions as a way to react to events happening during your backtest, like a signal being generated or a trade reaching a profit target. They're really useful for connecting your backtest to external systems - for example, sending notifications to a Discord channel when a trade is opened, logging detailed performance data, or even integrating with a state management library like Redux. Each action gets triggered alongside specific events during the backtest, giving it access to important information like the trade signals and profit/loss updates. You define the action's configuration using an object and pass it to this function to register it.

    +

    Function commitCreateStopLoss

    • Reports that the pending position's stop-loss order was actually filled on the exchange +(e.g. by candle high/low), forcing a close that bypasses the VWAP-based SL check.

      +

      The exchange and the strategy are parallel states: the framework evaluates TP/SL against VWAP, +but the real order may fill on high/low. The close is deferred and emitted with closeReason +"stop_loss" on the next tick. No-op if no pending signal exists.

      +

      Automatically detects backtest/live mode from execution context.

      +

      Parameters

      • symbol: string

        Trading pair symbol

        +
      • Optionalpayload: Partial<CommitPayload>

        Optional commit payload with id and note

        +

      Returns Promise<void>

      Promise that resolves when the stop-loss fill is queued

      +
      import { commitCreateStopLoss } from "backtest-kit";

      // Report SL fill confirmed on the exchange
      await commitCreateStopLoss("BTCUSDT", { id: "sl-fill-001" }); +
      + +
    + + + + + + + + + diff --git a/functions/types.commitCreateTakeProfit.html b/functions/types.commitCreateTakeProfit.html new file mode 100644 index 0000000000000000000000000000000000000000..5c4d2fa4028048eedbb5b257c57a891a7b532e70 --- /dev/null +++ b/functions/types.commitCreateTakeProfit.html @@ -0,0 +1,37 @@ +commitCreateTakeProfit | backtest-kit

    Function commitCreateTakeProfit

    • Reports that the pending position's take-profit order was actually filled on the exchange +(e.g. by candle high/low), forcing a close that bypasses the VWAP-based TP check.

      +

      The exchange and the strategy are parallel states: the framework evaluates TP/SL against VWAP, +but the real order may fill on high/low. The close is deferred and emitted with closeReason +"take_profit" on the next tick. No-op if no pending signal exists.

      +

      Automatically detects backtest/live mode from execution context.

      +

      Parameters

      • symbol: string

        Trading pair symbol

        +
      • Optionalpayload: Partial<CommitPayload>

        Optional commit payload with id and note

        +

      Returns Promise<void>

      Promise that resolves when the take-profit fill is queued

      +
      import { commitCreateTakeProfit } from "backtest-kit";

      // Report TP fill confirmed on the exchange
      await commitCreateTakeProfit("BTCUSDT", { id: "tp-fill-001" }); +
      + +
    + + + + + + + + + diff --git a/functions/types.commitPartialLoss.html b/functions/types.commitPartialLoss.html index b63f48a0ff1ab23ed4cc7a5d78e8d896d91c5f75..157ab3806890e355b7770d07e1ae9a0eb5f2a382 100644 --- a/functions/types.commitPartialLoss.html +++ b/functions/types.commitPartialLoss.html @@ -13,7 +13,7 @@ Price must be moving toward stop loss (in loss direction).

    import { partialLoss } from "backtest-kit";

    // Close 40% of LONG position at loss
    const success = await partialLoss("BTCUSDT", 40);
    if (success) {
    console.log('Partial loss executed');
    }
    -
    +

    Function listenScheduleEvent

    • Subscribes to scheduled signal lifecycle events (creation and cancellation) with queued async processing.

      +

      Emitted when a scheduled signal is created (action "scheduled") or cancelled before activation +(action "cancelled" with reason "timeout" / "price_reject" / "user"), in both live and backtest.

      +

      IMPORTANT: The scheduled -> active transition (activation) is NOT reported here. Activation +produces an "opened" event on the regular signal emitters (listenSignal) instead.

      +

      Events are processed sequentially in order received, even if callback is async.

      +

      Parameters

      Returns () => void

      Unsubscribe function to stop listening

      +
      import { listenScheduleEvent } from "./function/event";

      const unsubscribe = listenScheduleEvent((event) => {
      if (event.action === "scheduled") {
      console.log(`Scheduled ${event.symbol} @ ${event.data.priceOpen}`);
      } else {
      console.log(`Cancelled ${event.symbol} (reason: ${event.reason})`);
      }
      });

      // Later: stop listening
      unsubscribe(); +
      + +
    + + + + + + + + + diff --git a/functions/types.listenScheduleEventOnce.html b/functions/types.listenScheduleEventOnce.html new file mode 100644 index 0000000000000000000000000000000000000000..d2c4d54109dd9ada9e0a36b4cc5a2d1029f40ce0 --- /dev/null +++ b/functions/types.listenScheduleEventOnce.html @@ -0,0 +1,35 @@ +listenScheduleEventOnce | backtest-kit

    Function listenScheduleEventOnce

    • Subscribes to filtered scheduled lifecycle events with one-time execution.

      +

      Listens for events matching the filter predicate, then executes callback once +and automatically unsubscribes. Useful for waiting for a specific scheduled creation +or cancellation.

      +

      Parameters

      • filterFn: (event: ScheduleEventContract) => boolean

        Predicate to filter which events trigger the callback

        +
      • fn: (event: ScheduleEventContract) => void

        Callback function to handle the filtered event (called only once)

        +

      Returns () => void

      Unsubscribe function to cancel the listener before it fires

      +
      import { listenScheduleEventOnce } from "./function/event";

      // Wait for the first cancellation on BTCUSDT
      listenScheduleEventOnce(
      (event) => event.symbol === "BTCUSDT" && event.action === "cancelled",
      (event) => console.log("BTCUSDT scheduled cancelled:", event.reason)
      ); +
      + +
    + + + + + + + + + diff --git a/functions/types.listenSchedulePing.html b/functions/types.listenSchedulePing.html index 5608380738d01ae08bd5d6aa64884a827cbc9eb9..2e9a3919a8a4d560aa8c844a76cf4414768edacf 100644 --- a/functions/types.listenSchedulePing.html +++ b/functions/types.listenSchedulePing.html @@ -6,7 +6,7 @@ Allows tracking of scheduled signal lifecycle and custom monitoring logic.

    import { listenPing } from "./function/event";

    const unsubscribe = listenPing((event) => {
    console.log(`Ping for ${event.symbol} at ${new Date(event.timestamp).toISOString()}`);
    console.log(`Strategy: ${event.strategyName}, Exchange: ${event.exchangeName}`);
    console.log(`Mode: ${event.backtest ? "Backtest" : "Live"}`);
    });

    // Later: stop listening
    unsubscribe();
    -
    +

    Function listenSignalEvent

    • Subscribes to pending signal lifecycle events (open and close) with queued async processing.

      +

      Emitted when a pending position is opened (action "opened": new signal / immediate / scheduled +or user activation) or closed (action "closed" with closeReason "take_profit" / "stop_loss" / +"time_expired" / "closed"), in both live and backtest.

      +

      Events are processed sequentially in order received, even if callback is async.

      +

      Parameters

      Returns () => void

      Unsubscribe function to stop listening

      +
      import { listenSignalEvent } from "./function/event";

      const unsubscribe = listenSignalEvent((event) => {
      if (event.action === "opened") {
      console.log(`Opened ${event.symbol} @ ${event.data.priceOpen}`);
      } else {
      console.log(`Closed ${event.symbol} (reason: ${event.closeReason})`);
      }
      });

      // Later: stop listening
      unsubscribe(); +
      + +
    + + + + + + + + + diff --git a/functions/types.listenSignalEventOnce.html b/functions/types.listenSignalEventOnce.html new file mode 100644 index 0000000000000000000000000000000000000000..0d00bd156e2ff30593b67b3860f67e7ab95f5921 --- /dev/null +++ b/functions/types.listenSignalEventOnce.html @@ -0,0 +1,34 @@ +listenSignalEventOnce | backtest-kit

    Function listenSignalEventOnce

    • Subscribes to filtered pending lifecycle events with one-time execution.

      +

      Listens for events matching the filter predicate, then executes callback once +and automatically unsubscribes. Useful for waiting for a specific open or close.

      +

      Parameters

      • filterFn: (event: SignalEventContract) => boolean

        Predicate to filter which events trigger the callback

        +
      • fn: (event: SignalEventContract) => void

        Callback function to handle the filtered event (called only once)

        +

      Returns () => void

      Unsubscribe function to cancel the listener before it fires

      +
      import { listenSignalEventOnce } from "./function/event";

      // Wait for the first close on BTCUSDT
      listenSignalEventOnce(
      (event) => event.symbol === "BTCUSDT" && event.action === "closed",
      (event) => console.log("BTCUSDT closed:", event.closeReason)
      ); +
      + +
    + + + + + + + + + diff --git a/functions/types.listenSignalLive.html b/functions/types.listenSignalLive.html index b4645417805d960cf7beb504447ff36f7ebe8d56..41102d801a45595ae2a05721d295bb4306eeef72 100644 --- a/functions/types.listenSignalLive.html +++ b/functions/types.listenSignalLive.html @@ -6,7 +6,7 @@ Events are processed sequentially in order received.

    import { listenSignalLive } from "./function/event";

    const unsubscribe = listenSignalLive((event) => {
    if (event.action === "closed") {
    console.log("Live signal closed:", event.pnl.pnlPercentage);
    }
    });
    -
    +

    Function shutdown

    • Gracefully shuts down the backtest execution by emitting a shutdown event. This allows all components that subscribe to the shutdownEmitter to perform necessary cleanup before the process exits. The shutdown method is typically called in response to a termination signal (e.g., SIGINT) to ensure a clean exit.

      -

      Returns void

    +

    Returns void

    Function toPlainString

    Converts markdown content to plain text with minimal formatting

    • Parameters

      • content: string

        Markdown string to convert

      Returns string

      Plain text representation

      -
    +

    Function waitForCandle

    Waits for the next candle interval to start and returns the timestamp of the new candle.

    • Parameters

      • interval: CandleInterval

        The candle interval (e.g., "1m", "1h") to wait for.

      Returns Promise<number>

      A promise that resolves with the timestamp (in milliseconds) of the next candle start.

      -
    +

    Function warmCandles

    • Pre-caches candles for a date range into persist storage. Downloads all candles matching the interval from from to to.

      Parameters

      • params: IWarmCandlesParams

        Cache parameters

        -

      Returns Promise<void>

    +

    Returns Promise<void>

    +backtest-kit

    Interface ActivateScheduledCommit

    Activate scheduled signal event.

    -
    interface ActivateScheduledCommit {
        action: "activate-scheduled";
        activateId?: string;
        backtest: boolean;
        currentPrice: number;
        exchangeName: string;
        frameName: string;
        maxDrawdown: IStrategyPnL;
        note?: string;
        originalPriceOpen: number;
        originalPriceStopLoss: number;
        originalPriceTakeProfit: number;
        peakProfit: IStrategyPnL;
        pendingAt: number;
        pnl: IStrategyPnL;
        position: "long" | "short";
        priceOpen: number;
        priceStopLoss: number;
        priceTakeProfit: number;
        scheduledAt: number;
        signal: IPublicSignalRow;
        signalId: string;
        strategyName: string;
        symbol: string;
        timestamp: number;
        totalEntries: number;
        totalPartials: number;
    }

    Hierarchy

    • SignalCommitBase
      • ActivateScheduledCommit

    Properties

    interface ActivateScheduledCommit {
        action: "activate-scheduled";
        activateId?: string;
        backtest: boolean;
        currentPrice: number;
        exchangeName: string;
        frameName: string;
        maxDrawdown: IStrategyPnL;
        note?: string;
        originalPriceOpen: number;
        originalPriceStopLoss: number;
        originalPriceTakeProfit: number;
        peakProfit: IStrategyPnL;
        pendingAt: number;
        pnl: IStrategyPnL;
        position: "long" | "short";
        priceOpen: number;
        priceStopLoss: number;
        priceTakeProfit: number;
        scheduledAt: number;
        signal: IPublicSignalRow;
        signalId: string;
        strategyName: string;
        symbol: string;
        timestamp: number;
        totalEntries: number;
        totalPartials: number;
    }

    Hierarchy

    • SignalCommitBase
      • ActivateScheduledCommit

    Properties

    action: "activate-scheduled"

    Discriminator for activate-scheduled action

    -
    activateId?: string

    Optional identifier for the activation reason (user-provided)

    -
    backtest: boolean

    Whether this event is from backtest mode (true) or live mode (false)

    -
    currentPrice: number

    Current market price at time of activation

    -
    exchangeName: string

    Exchange name where signal was executed

    -
    frameName: string

    Timeframe name (used in backtest mode, empty string in live mode)

    -
    maxDrawdown: IStrategyPnL

    Maximum drawdown experienced during the life of this position up to the moment this public signal was created

    -
    note?: string

    Optional human-readable description of signal reason

    -
    originalPriceOpen: number

    Original entry price at signal creation (unchanged by DCA averaging).

    -
    originalPriceStopLoss: number

    Original stop loss price before any trailing adjustments

    -
    originalPriceTakeProfit: number

    Original take profit price before any trailing adjustments

    -
    peakProfit: IStrategyPnL

    Peak profit achieved during the life of this position up to the moment this public signal was created

    -
    pendingAt: number

    Position activation timestamp in milliseconds (set during this activation)

    -

    Total PNL of the closed position (including all entries and partials)

    -
    position: "long" | "short"

    Trade direction: "long" (buy) or "short" (sell)

    -
    priceOpen: number

    Entry price for the position

    -
    priceStopLoss: number

    Effective stop loss price

    -
    priceTakeProfit: number

    Effective take profit price

    -
    scheduledAt: number

    Signal creation timestamp in milliseconds

    -

    Signal data at the moment of this event (snapshot of IPublicSignalRow)

    -
    signalId: string

    Unique signal identifier (UUID v4)

    -
    strategyName: string

    Strategy name that generated this signal

    -
    symbol: string

    Trading pair symbol (e.g., "BTCUSDT")

    -
    timestamp: number

    Timestamp from execution context (tick's when or backtest candle timestamp)

    -
    totalEntries: number

    Total number of DCA entries at the time of this event (_entry.length). +

    activateId?: string

    Optional identifier for the activation reason (user-provided)

    +
    backtest: boolean

    Whether this event is from backtest mode (true) or live mode (false)

    +
    currentPrice: number

    Current market price at time of activation

    +
    exchangeName: string

    Exchange name where signal was executed

    +
    frameName: string

    Timeframe name (used in backtest mode, empty string in live mode)

    +
    maxDrawdown: IStrategyPnL

    Maximum drawdown experienced during the life of this position up to the moment this public signal was created

    +
    note?: string

    Optional human-readable description of signal reason

    +
    originalPriceOpen: number

    Original entry price at signal creation (unchanged by DCA averaging).

    +
    originalPriceStopLoss: number

    Original stop loss price before any trailing adjustments

    +
    originalPriceTakeProfit: number

    Original take profit price before any trailing adjustments

    +
    peakProfit: IStrategyPnL

    Peak profit achieved during the life of this position up to the moment this public signal was created

    +
    pendingAt: number

    Position activation timestamp in milliseconds (set during this activation)

    +

    Total PNL of the closed position (including all entries and partials)

    +
    position: "long" | "short"

    Trade direction: "long" (buy) or "short" (sell)

    +
    priceOpen: number

    Entry price for the position

    +
    priceStopLoss: number

    Effective stop loss price

    +
    priceTakeProfit: number

    Effective take profit price

    +
    scheduledAt: number

    Signal creation timestamp in milliseconds

    +

    Signal data at the moment of this event (snapshot of IPublicSignalRow)

    +
    signalId: string

    Unique signal identifier (UUID v4)

    +
    strategyName: string

    Strategy name that generated this signal

    +
    symbol: string

    Trading pair symbol (e.g., "BTCUSDT")

    +
    timestamp: number

    Timestamp from execution context (tick's when or backtest candle timestamp)

    +
    totalEntries: number

    Total number of DCA entries at the time of this event (_entry.length). 1 = no averaging done (only initial entry). 2+ = averaged positions.

    -
    totalPartials: number

    Total number of partial closes executed at the time of this event (_partial.length). +

    totalPartials: number

    Total number of partial closes executed at the time of this event (_partial.length). 0 = no partial closes done. 1+ = partial closes executed.

    -
    +

    Interface ActivateScheduledCommitNotification

    Activate scheduled commit notification. Emitted when a scheduled signal is activated by user (without waiting for priceOpen).

    -
    interface ActivateScheduledCommitNotification {
        activateId?: string;
        backtest: boolean;
        createdAt: number;
        currentPrice: number;
        exchangeName: string;
        id: string;
        maxDrawdown: IStrategyPnL;
        maxDrawdownCost: number;
        maxDrawdownEntries: number;
        maxDrawdownPercentage: number;
        maxDrawdownPriceClose: number;
        maxDrawdownPriceOpen: number;
        note?: string;
        originalPriceOpen: number;
        originalPriceStopLoss: number;
        originalPriceTakeProfit: number;
        peakProfit: IStrategyPnL;
        peakProfitCost: number;
        peakProfitEntries: number;
        peakProfitPercentage: number;
        peakProfitPriceClose: number;
        peakProfitPriceOpen: number;
        pendingAt: number;
        pnl: IStrategyPnL;
        pnlCost: number;
        pnlEntries: number;
        pnlPercentage: number;
        pnlPriceClose: number;
        pnlPriceOpen: number;
        position: "long" | "short";
        priceOpen: number;
        priceStopLoss: number;
        priceTakeProfit: number;
        scheduledAt: number;
        signalId: string;
        strategyName: string;
        symbol: string;
        timestamp: number;
        totalEntries: number;
        totalPartials: number;
        type: "activate_scheduled.commit";
    }

    Properties

    interface ActivateScheduledCommitNotification {
        activateId?: string;
        backtest: boolean;
        createdAt: number;
        currentPrice: number;
        exchangeName: string;
        id: string;
        maxDrawdown: IStrategyPnL;
        maxDrawdownCost: number;
        maxDrawdownEntries: number;
        maxDrawdownPercentage: number;
        maxDrawdownPriceClose: number;
        maxDrawdownPriceOpen: number;
        note?: string;
        originalPriceOpen: number;
        originalPriceStopLoss: number;
        originalPriceTakeProfit: number;
        peakProfit: IStrategyPnL;
        peakProfitCost: number;
        peakProfitEntries: number;
        peakProfitPercentage: number;
        peakProfitPriceClose: number;
        peakProfitPriceOpen: number;
        pendingAt: number;
        pnl: IStrategyPnL;
        pnlCost: number;
        pnlEntries: number;
        pnlPercentage: number;
        pnlPriceClose: number;
        pnlPriceOpen: number;
        position: "long" | "short";
        priceOpen: number;
        priceStopLoss: number;
        priceTakeProfit: number;
        scheduledAt: number;
        signalId: string;
        strategyName: string;
        symbol: string;
        timestamp: number;
        totalEntries: number;
        totalPartials: number;
        type: "activate_scheduled.commit";
    }

    Properties

    activateId? backtest createdAt currentPrice @@ -42,47 +42,47 @@ Emitted when a scheduled signal is activated by user (without waiting for priceO totalPartials type

    Properties

    activateId?: string

    Optional activation identifier (provided when user calls activateScheduled())

    -
    backtest: boolean

    Whether this notification is from backtest mode (true) or live mode (false)

    -
    createdAt: number

    Unix timestamp in milliseconds when the notification was created

    -
    currentPrice: number

    Current market price when activation was executed

    -
    exchangeName: string

    Exchange name where signal was executed

    -
    id: string

    Unique notification identifier

    -
    maxDrawdown: IStrategyPnL

    Maximum drawdown experienced during the life of this position up to the moment this public signal was created

    -
    maxDrawdownCost: number

    Absolute profit/loss in USD at the moment the position reached its maximum drawdown during the life of this position

    -
    maxDrawdownEntries: number

    Number of entries executed at the moment the position reached its maximum drawdown during the life of this position

    -
    maxDrawdownPercentage: number

    Profit/loss as percentage at the moment the position reached its maximum drawdown during the life of this position

    -
    maxDrawdownPriceClose: number

    Exit price for PNL calculation at the moment of max drawdown

    -
    maxDrawdownPriceOpen: number

    Maximum drawdown price reached in loss direction during the life of this position

    -
    note?: string

    Optional human-readable description of signal reason

    -
    originalPriceOpen: number

    Original entry price at signal creation (unchanged by DCA averaging)

    -
    originalPriceStopLoss: number

    Original stop loss price before any trailing adjustments

    -
    originalPriceTakeProfit: number

    Original take profit price before any trailing adjustments

    -
    peakProfit: IStrategyPnL

    Peak profit achieved during the life of this position up to the moment this public signal was created

    -
    peakProfitCost: number

    Absolute profit/loss in USD at the moment the position reached its peak profit during the life of this position

    -
    peakProfitEntries: number

    Number of entries executed at the moment the position reached its peak profit during the life of this position

    -
    peakProfitPercentage: number

    Profit/loss as percentage at the moment the position reached its peak profit during the life of this position

    -
    peakProfitPriceClose: number

    Exit price for PNL calculation at the moment of peak profit

    -
    peakProfitPriceOpen: number

    Peak price reached in profit direction during the life of this position

    -
    pendingAt: number

    Pending timestamp in milliseconds (when position became pending/active at priceOpen)

    -

    Total PNL of the closed position (including all entries and partials)

    -
    pnlCost: number

    Absolute profit/loss in USD

    -
    pnlEntries: number

    Total invested capital in USD

    -
    pnlPercentage: number

    Profit/loss as percentage (e.g., 1.5 for +1.5%, -2.3 for -2.3%)

    -
    pnlPriceClose: number

    Exit price from PNL calculation (adjusted with slippage and fees)

    -
    pnlPriceOpen: number

    Entry price from PNL calculation (effective price adjusted with slippage and fees)

    -
    position: "long" | "short"

    Trade direction: "long" (buy) or "short" (sell)

    -
    priceOpen: number

    Entry price for the position

    -
    priceStopLoss: number

    Effective stop loss price

    -
    priceTakeProfit: number

    Effective take profit price

    -
    scheduledAt: number

    Signal creation timestamp in milliseconds (when signal was first created/scheduled)

    -
    signalId: string

    Unique signal identifier (UUID v4)

    -
    strategyName: string

    Strategy name that generated this signal

    -
    symbol: string

    Trading pair symbol (e.g., "BTCUSDT")

    -
    timestamp: number

    Unix timestamp in milliseconds when activation was committed

    -
    totalEntries: number

    Total number of DCA entries (_entry.length). 1 = no averaging.

    -
    totalPartials: number

    Total number of partial closes executed (_partial.length). 0 = no partial closes done.

    -
    type: "activate_scheduled.commit"

    Discriminator for type-safe union

    -
    +
    backtest: boolean

    Whether this notification is from backtest mode (true) or live mode (false)

    +
    createdAt: number

    Unix timestamp in milliseconds when the notification was created

    +
    currentPrice: number

    Current market price when activation was executed

    +
    exchangeName: string

    Exchange name where signal was executed

    +
    id: string

    Unique notification identifier

    +
    maxDrawdown: IStrategyPnL

    Maximum drawdown experienced during the life of this position up to the moment this public signal was created

    +
    maxDrawdownCost: number

    Absolute profit/loss in USD at the moment the position reached its maximum drawdown during the life of this position

    +
    maxDrawdownEntries: number

    Number of entries executed at the moment the position reached its maximum drawdown during the life of this position

    +
    maxDrawdownPercentage: number

    Profit/loss as percentage at the moment the position reached its maximum drawdown during the life of this position

    +
    maxDrawdownPriceClose: number

    Exit price for PNL calculation at the moment of max drawdown

    +
    maxDrawdownPriceOpen: number

    Maximum drawdown price reached in loss direction during the life of this position

    +
    note?: string

    Optional human-readable description of signal reason

    +
    originalPriceOpen: number

    Original entry price at signal creation (unchanged by DCA averaging)

    +
    originalPriceStopLoss: number

    Original stop loss price before any trailing adjustments

    +
    originalPriceTakeProfit: number

    Original take profit price before any trailing adjustments

    +
    peakProfit: IStrategyPnL

    Peak profit achieved during the life of this position up to the moment this public signal was created

    +
    peakProfitCost: number

    Absolute profit/loss in USD at the moment the position reached its peak profit during the life of this position

    +
    peakProfitEntries: number

    Number of entries executed at the moment the position reached its peak profit during the life of this position

    +
    peakProfitPercentage: number

    Profit/loss as percentage at the moment the position reached its peak profit during the life of this position

    +
    peakProfitPriceClose: number

    Exit price for PNL calculation at the moment of peak profit

    +
    peakProfitPriceOpen: number

    Peak price reached in profit direction during the life of this position

    +
    pendingAt: number

    Pending timestamp in milliseconds (when position became pending/active at priceOpen)

    +

    Total PNL of the closed position (including all entries and partials)

    +
    pnlCost: number

    Absolute profit/loss in USD

    +
    pnlEntries: number

    Total invested capital in USD

    +
    pnlPercentage: number

    Profit/loss as percentage (e.g., 1.5 for +1.5%, -2.3 for -2.3%)

    +
    pnlPriceClose: number

    Exit price from PNL calculation (adjusted with slippage and fees)

    +
    pnlPriceOpen: number

    Entry price from PNL calculation (effective price adjusted with slippage and fees)

    +
    position: "long" | "short"

    Trade direction: "long" (buy) or "short" (sell)

    +
    priceOpen: number

    Entry price for the position

    +
    priceStopLoss: number

    Effective stop loss price

    +
    priceTakeProfit: number

    Effective take profit price

    +
    scheduledAt: number

    Signal creation timestamp in milliseconds (when signal was first created/scheduled)

    +
    signalId: string

    Unique signal identifier (UUID v4)

    +
    strategyName: string

    Strategy name that generated this signal

    +
    symbol: string

    Trading pair symbol (e.g., "BTCUSDT")

    +
    timestamp: number

    Unix timestamp in milliseconds when activation was committed

    +
    totalEntries: number

    Total number of DCA entries (_entry.length). 1 = no averaging.

    +
    totalPartials: number

    Total number of partial closes executed (_partial.length). 0 = no partial closes done.

    +
    type: "activate_scheduled.commit"

    Discriminator for type-safe union

    +

    Interface AverageBuyCommit

    Average-buy (DCA) event. Emitted when a new averaging entry is added to an open position.

    -
    interface AverageBuyCommit {
        action: "average-buy";
        backtest: boolean;
        cost: number;
        currentPrice: number;
        effectivePriceOpen: number;
        exchangeName: string;
        frameName: string;
        maxDrawdown: IStrategyPnL;
        note?: string;
        originalPriceOpen: number;
        originalPriceStopLoss: number;
        originalPriceTakeProfit: number;
        peakProfit: IStrategyPnL;
        pendingAt: number;
        pnl: IStrategyPnL;
        position: "long" | "short";
        priceOpen: number;
        priceStopLoss: number;
        priceTakeProfit: number;
        scheduledAt: number;
        signal: IPublicSignalRow;
        signalId: string;
        strategyName: string;
        symbol: string;
        timestamp: number;
        totalEntries: number;
        totalPartials: number;
    }

    Hierarchy

    • SignalCommitBase
      • AverageBuyCommit

    Properties

    interface AverageBuyCommit {
        action: "average-buy";
        backtest: boolean;
        cost: number;
        currentPrice: number;
        effectivePriceOpen: number;
        exchangeName: string;
        frameName: string;
        maxDrawdown: IStrategyPnL;
        note?: string;
        originalPriceOpen: number;
        originalPriceStopLoss: number;
        originalPriceTakeProfit: number;
        peakProfit: IStrategyPnL;
        pendingAt: number;
        pnl: IStrategyPnL;
        position: "long" | "short";
        priceOpen: number;
        priceStopLoss: number;
        priceTakeProfit: number;
        scheduledAt: number;
        signal: IPublicSignalRow;
        signalId: string;
        strategyName: string;
        symbol: string;
        timestamp: number;
        totalEntries: number;
        totalPartials: number;
    }

    Hierarchy

    • SignalCommitBase
      • AverageBuyCommit

    Properties

    action backtest cost currentPrice @@ -28,35 +28,35 @@ Emitted when a new averaging entry is added to an open position.

    totalEntries totalPartials

    Properties

    action: "average-buy"

    Discriminator for average-buy action

    -
    backtest: boolean

    Whether this event is from backtest mode (true) or live mode (false)

    -
    cost: number

    Cost of this averaging entry in USD

    -
    currentPrice: number

    Price at which the new averaging entry was executed

    -
    effectivePriceOpen: number

    Effective (averaged) entry price after this addition

    -
    exchangeName: string

    Exchange name where signal was executed

    -
    frameName: string

    Timeframe name (used in backtest mode, empty string in live mode)

    -
    maxDrawdown: IStrategyPnL

    Maximum drawdown experienced during the life of this position up to the moment this public signal was created

    -
    note?: string

    Optional human-readable description of signal reason

    -
    originalPriceOpen: number

    Original entry price at signal creation (unchanged by DCA averaging).

    -
    originalPriceStopLoss: number

    Original stop loss price before any trailing adjustments

    -
    originalPriceTakeProfit: number

    Original take profit price before any trailing adjustments

    -
    peakProfit: IStrategyPnL

    Peak profit achieved during the life of this position up to the moment this public signal was created

    -
    pendingAt: number

    Position activation timestamp in milliseconds (when price reached priceOpen)

    -

    Unrealized PNL at the moment of average-buy (calculated after new entry added)

    -
    position: "long" | "short"

    Trade direction: "long" (buy) or "short" (sell)

    -
    priceOpen: number

    Original entry price (signal.priceOpen, unchanged by averaging)

    -
    priceStopLoss: number

    Effective stop loss price (may differ from original after trailing)

    -
    priceTakeProfit: number

    Effective take profit price (may differ from original after trailing)

    -
    scheduledAt: number

    Signal creation timestamp in milliseconds

    -

    Signal data at the moment of this event (snapshot of IPublicSignalRow)

    -
    signalId: string

    Unique signal identifier (UUID v4)

    -
    strategyName: string

    Strategy name that generated this signal

    -
    symbol: string

    Trading pair symbol (e.g., "BTCUSDT")

    -
    timestamp: number

    Timestamp from execution context (tick's when or backtest candle timestamp)

    -
    totalEntries: number

    Total number of DCA entries at the time of this event (_entry.length). +

    backtest: boolean

    Whether this event is from backtest mode (true) or live mode (false)

    +
    cost: number

    Cost of this averaging entry in USD

    +
    currentPrice: number

    Price at which the new averaging entry was executed

    +
    effectivePriceOpen: number

    Effective (averaged) entry price after this addition

    +
    exchangeName: string

    Exchange name where signal was executed

    +
    frameName: string

    Timeframe name (used in backtest mode, empty string in live mode)

    +
    maxDrawdown: IStrategyPnL

    Maximum drawdown experienced during the life of this position up to the moment this public signal was created

    +
    note?: string

    Optional human-readable description of signal reason

    +
    originalPriceOpen: number

    Original entry price at signal creation (unchanged by DCA averaging).

    +
    originalPriceStopLoss: number

    Original stop loss price before any trailing adjustments

    +
    originalPriceTakeProfit: number

    Original take profit price before any trailing adjustments

    +
    peakProfit: IStrategyPnL

    Peak profit achieved during the life of this position up to the moment this public signal was created

    +
    pendingAt: number

    Position activation timestamp in milliseconds (when price reached priceOpen)

    +

    Unrealized PNL at the moment of average-buy (calculated after new entry added)

    +
    position: "long" | "short"

    Trade direction: "long" (buy) or "short" (sell)

    +
    priceOpen: number

    Original entry price (signal.priceOpen, unchanged by averaging)

    +
    priceStopLoss: number

    Effective stop loss price (may differ from original after trailing)

    +
    priceTakeProfit: number

    Effective take profit price (may differ from original after trailing)

    +
    scheduledAt: number

    Signal creation timestamp in milliseconds

    +

    Signal data at the moment of this event (snapshot of IPublicSignalRow)

    +
    signalId: string

    Unique signal identifier (UUID v4)

    +
    strategyName: string

    Strategy name that generated this signal

    +
    symbol: string

    Trading pair symbol (e.g., "BTCUSDT")

    +
    timestamp: number

    Timestamp from execution context (tick's when or backtest candle timestamp)

    +
    totalEntries: number

    Total number of DCA entries at the time of this event (_entry.length). 1 = no averaging done (only initial entry). 2+ = averaged positions.

    -
    totalPartials: number

    Total number of partial closes executed at the time of this event (_partial.length). +

    totalPartials: number

    Total number of partial closes executed at the time of this event (_partial.length). 0 = no partial closes done. 1+ = partial closes executed.

    -
    +

    Interface AverageBuyCommitNotification

    Average-buy (DCA) commit notification. Emitted when a new averaging entry is added to an open position.

    -
    interface AverageBuyCommitNotification {
        backtest: boolean;
        cost: number;
        createdAt: number;
        currentPrice: number;
        effectivePriceOpen: number;
        exchangeName: string;
        id: string;
        maxDrawdown: IStrategyPnL;
        maxDrawdownCost: number;
        maxDrawdownEntries: number;
        maxDrawdownPercentage: number;
        maxDrawdownPriceClose: number;
        maxDrawdownPriceOpen: number;
        note?: string;
        originalPriceOpen: number;
        originalPriceStopLoss: number;
        originalPriceTakeProfit: number;
        peakProfit: IStrategyPnL;
        peakProfitCost: number;
        peakProfitEntries: number;
        peakProfitPercentage: number;
        peakProfitPriceClose: number;
        peakProfitPriceOpen: number;
        pendingAt: number;
        pnl: IStrategyPnL;
        pnlCost: number;
        pnlEntries: number;
        pnlPercentage: number;
        pnlPriceClose: number;
        pnlPriceOpen: number;
        position: "long" | "short";
        priceOpen: number;
        priceStopLoss: number;
        priceTakeProfit: number;
        scheduledAt: number;
        signalId: string;
        strategyName: string;
        symbol: string;
        timestamp: number;
        totalEntries: number;
        totalPartials: number;
        type: "average_buy.commit";
    }

    Properties

    interface AverageBuyCommitNotification {
        backtest: boolean;
        cost: number;
        createdAt: number;
        currentPrice: number;
        effectivePriceOpen: number;
        exchangeName: string;
        id: string;
        maxDrawdown: IStrategyPnL;
        maxDrawdownCost: number;
        maxDrawdownEntries: number;
        maxDrawdownPercentage: number;
        maxDrawdownPriceClose: number;
        maxDrawdownPriceOpen: number;
        note?: string;
        originalPriceOpen: number;
        originalPriceStopLoss: number;
        originalPriceTakeProfit: number;
        peakProfit: IStrategyPnL;
        peakProfitCost: number;
        peakProfitEntries: number;
        peakProfitPercentage: number;
        peakProfitPriceClose: number;
        peakProfitPriceOpen: number;
        pendingAt: number;
        pnl: IStrategyPnL;
        pnlCost: number;
        pnlEntries: number;
        pnlPercentage: number;
        pnlPriceClose: number;
        pnlPriceOpen: number;
        position: "long" | "short";
        priceOpen: number;
        priceStopLoss: number;
        priceTakeProfit: number;
        scheduledAt: number;
        signalId: string;
        strategyName: string;
        symbol: string;
        timestamp: number;
        totalEntries: number;
        totalPartials: number;
        type: "average_buy.commit";
    }

    Properties

    backtest cost createdAt currentPrice @@ -43,48 +43,48 @@ Emitted when a new averaging entry is added to an open position.

    totalPartials type

    Properties

    backtest: boolean

    Whether this notification is from backtest mode (true) or live mode (false)

    -
    cost: number

    Cost of this averaging entry in USD

    -
    createdAt: number

    Unix timestamp in milliseconds when the notification was created

    -
    currentPrice: number

    Price at which the new averaging entry was executed

    -
    effectivePriceOpen: number

    Averaged (effective) entry price after this addition

    -
    exchangeName: string

    Exchange name where signal was executed

    -
    id: string

    Unique notification identifier

    -
    maxDrawdown: IStrategyPnL

    Maximum drawdown experienced during the life of this position up to the moment this public signal was created

    -
    maxDrawdownCost: number

    Absolute profit/loss in USD at the moment the position reached its maximum drawdown during the life of this position

    -
    maxDrawdownEntries: number

    Number of entries executed at the moment the position reached its maximum drawdown during the life of this position

    -
    maxDrawdownPercentage: number

    Profit/loss as percentage at the moment the position reached its maximum drawdown during the life of this position

    -
    maxDrawdownPriceClose: number

    Exit price for PNL calculation at the moment of max drawdown

    -
    maxDrawdownPriceOpen: number

    Maximum drawdown price reached in loss direction during the life of this position

    -
    note?: string

    Optional human-readable description of signal reason

    -
    originalPriceOpen: number

    Original entry price at signal creation (unchanged by DCA averaging)

    -
    originalPriceStopLoss: number

    Original stop loss price before any trailing adjustments

    -
    originalPriceTakeProfit: number

    Original take profit price before any trailing adjustments

    -
    peakProfit: IStrategyPnL

    Peak profit achieved during the life of this position up to the moment this public signal was created

    -
    peakProfitCost: number

    Absolute profit/loss in USD at the moment the position reached its peak profit during the life of this position

    -
    peakProfitEntries: number

    Number of entries executed at the moment the position reached its peak profit during the life of this position

    -
    peakProfitPercentage: number

    Profit/loss as percentage at the moment the position reached its peak profit during the life of this position

    -
    peakProfitPriceClose: number

    Exit price for PNL calculation at the moment of peak profit

    -
    peakProfitPriceOpen: number

    Peak price reached in profit direction during the life of this position

    -
    pendingAt: number

    Pending timestamp in milliseconds (when position became pending/active at priceOpen)

    -

    Total PNL of the closed position (including all entries and partials)

    -
    pnlCost: number

    Absolute profit/loss in USD

    -
    pnlEntries: number

    Total invested capital in USD

    -
    pnlPercentage: number

    Profit/loss as percentage (e.g., 1.5 for +1.5%, -2.3 for -2.3%)

    -
    pnlPriceClose: number

    Exit price from PNL calculation (adjusted with slippage and fees)

    -
    pnlPriceOpen: number

    Entry price from PNL calculation (effective price adjusted with slippage and fees)

    -
    position: "long" | "short"

    Trade direction: "long" (buy) or "short" (sell)

    -
    priceOpen: number

    Original entry price (unchanged by averaging)

    -
    priceStopLoss: number

    Effective stop loss price (with trailing if set)

    -
    priceTakeProfit: number

    Effective take profit price (with trailing if set)

    -
    scheduledAt: number

    Signal creation timestamp in milliseconds (when signal was first created/scheduled)

    -
    signalId: string

    Unique signal identifier (UUID v4)

    -
    strategyName: string

    Strategy name that generated this signal

    -
    symbol: string

    Trading pair symbol (e.g., "BTCUSDT")

    -
    timestamp: number

    Unix timestamp in milliseconds when the averaging entry was executed

    -
    totalEntries: number

    Total number of DCA entries after this addition

    -
    totalPartials: number

    Total number of partial closes executed (_partial.length). 0 = no partial closes done.

    -
    type: "average_buy.commit"

    Discriminator for type-safe union

    -
    +
    cost: number

    Cost of this averaging entry in USD

    +
    createdAt: number

    Unix timestamp in milliseconds when the notification was created

    +
    currentPrice: number

    Price at which the new averaging entry was executed

    +
    effectivePriceOpen: number

    Averaged (effective) entry price after this addition

    +
    exchangeName: string

    Exchange name where signal was executed

    +
    id: string

    Unique notification identifier

    +
    maxDrawdown: IStrategyPnL

    Maximum drawdown experienced during the life of this position up to the moment this public signal was created

    +
    maxDrawdownCost: number

    Absolute profit/loss in USD at the moment the position reached its maximum drawdown during the life of this position

    +
    maxDrawdownEntries: number

    Number of entries executed at the moment the position reached its maximum drawdown during the life of this position

    +
    maxDrawdownPercentage: number

    Profit/loss as percentage at the moment the position reached its maximum drawdown during the life of this position

    +
    maxDrawdownPriceClose: number

    Exit price for PNL calculation at the moment of max drawdown

    +
    maxDrawdownPriceOpen: number

    Maximum drawdown price reached in loss direction during the life of this position

    +
    note?: string

    Optional human-readable description of signal reason

    +
    originalPriceOpen: number

    Original entry price at signal creation (unchanged by DCA averaging)

    +
    originalPriceStopLoss: number

    Original stop loss price before any trailing adjustments

    +
    originalPriceTakeProfit: number

    Original take profit price before any trailing adjustments

    +
    peakProfit: IStrategyPnL

    Peak profit achieved during the life of this position up to the moment this public signal was created

    +
    peakProfitCost: number

    Absolute profit/loss in USD at the moment the position reached its peak profit during the life of this position

    +
    peakProfitEntries: number

    Number of entries executed at the moment the position reached its peak profit during the life of this position

    +
    peakProfitPercentage: number

    Profit/loss as percentage at the moment the position reached its peak profit during the life of this position

    +
    peakProfitPriceClose: number

    Exit price for PNL calculation at the moment of peak profit

    +
    peakProfitPriceOpen: number

    Peak price reached in profit direction during the life of this position

    +
    pendingAt: number

    Pending timestamp in milliseconds (when position became pending/active at priceOpen)

    +

    Total PNL of the closed position (including all entries and partials)

    +
    pnlCost: number

    Absolute profit/loss in USD

    +
    pnlEntries: number

    Total invested capital in USD

    +
    pnlPercentage: number

    Profit/loss as percentage (e.g., 1.5 for +1.5%, -2.3 for -2.3%)

    +
    pnlPriceClose: number

    Exit price from PNL calculation (adjusted with slippage and fees)

    +
    pnlPriceOpen: number

    Entry price from PNL calculation (effective price adjusted with slippage and fees)

    +
    position: "long" | "short"

    Trade direction: "long" (buy) or "short" (sell)

    +
    priceOpen: number

    Original entry price (unchanged by averaging)

    +
    priceStopLoss: number

    Effective stop loss price (with trailing if set)

    +
    priceTakeProfit: number

    Effective take profit price (with trailing if set)

    +
    scheduledAt: number

    Signal creation timestamp in milliseconds (when signal was first created/scheduled)

    +
    signalId: string

    Unique signal identifier (UUID v4)

    +
    strategyName: string

    Strategy name that generated this signal

    +
    symbol: string

    Trading pair symbol (e.g., "BTCUSDT")

    +
    timestamp: number

    Unix timestamp in milliseconds when the averaging entry was executed

    +
    totalEntries: number

    Total number of DCA entries after this addition

    +
    totalPartials: number

    Total number of partial closes executed (_partial.length). 0 = no partial closes done.

    +
    type: "average_buy.commit"

    Discriminator for type-safe union

    +

    Interface BreakevenAvailableNotification

    Breakeven available notification. Emitted when signal's stop-loss can be moved to breakeven (entry price).

    -
    interface BreakevenAvailableNotification {
        backtest: boolean;
        createdAt: number;
        currentPrice: number;
        exchangeName: string;
        id: string;
        maxDrawdown: IStrategyPnL;
        maxDrawdownCost: number;
        maxDrawdownEntries: number;
        maxDrawdownPercentage: number;
        maxDrawdownPriceClose: number;
        maxDrawdownPriceOpen: number;
        note?: string;
        originalPriceOpen: number;
        originalPriceStopLoss: number;
        originalPriceTakeProfit: number;
        peakProfit: IStrategyPnL;
        peakProfitCost: number;
        peakProfitEntries: number;
        peakProfitPercentage: number;
        peakProfitPriceClose: number;
        peakProfitPriceOpen: number;
        pendingAt: number;
        pnl: IStrategyPnL;
        pnlCost: number;
        pnlEntries: number;
        pnlPercentage: number;
        pnlPriceClose: number;
        pnlPriceOpen: number;
        position: "long" | "short";
        priceOpen: number;
        priceStopLoss: number;
        priceTakeProfit: number;
        scheduledAt: number;
        signalId: string;
        strategyName: string;
        symbol: string;
        timestamp: number;
        totalEntries: number;
        totalPartials: number;
        type: "breakeven.available";
    }

    Properties

    interface BreakevenAvailableNotification {
        backtest: boolean;
        createdAt: number;
        currentPrice: number;
        exchangeName: string;
        id: string;
        maxDrawdown: IStrategyPnL;
        maxDrawdownCost: number;
        maxDrawdownEntries: number;
        maxDrawdownPercentage: number;
        maxDrawdownPriceClose: number;
        maxDrawdownPriceOpen: number;
        note?: string;
        originalPriceOpen: number;
        originalPriceStopLoss: number;
        originalPriceTakeProfit: number;
        peakProfit: IStrategyPnL;
        peakProfitCost: number;
        peakProfitEntries: number;
        peakProfitPercentage: number;
        peakProfitPriceClose: number;
        peakProfitPriceOpen: number;
        pendingAt: number;
        pnl: IStrategyPnL;
        pnlCost: number;
        pnlEntries: number;
        pnlPercentage: number;
        pnlPriceClose: number;
        pnlPriceOpen: number;
        position: "long" | "short";
        priceOpen: number;
        priceStopLoss: number;
        priceTakeProfit: number;
        scheduledAt: number;
        signalId: string;
        strategyName: string;
        symbol: string;
        timestamp: number;
        totalEntries: number;
        totalPartials: number;
        type: "breakeven.available";
    }

    Properties

    backtest createdAt currentPrice exchangeName @@ -41,46 +41,46 @@ Emitted when signal's stop-loss can be moved to breakeven (entry price).

    totalPartials type

    Properties

    backtest: boolean

    Whether this notification is from backtest mode (true) or live mode (false)

    -
    createdAt: number

    Unix timestamp in milliseconds when the notification was created

    -
    currentPrice: number

    Current market price when breakeven became available

    -
    exchangeName: string

    Exchange name where signal was executed

    -
    id: string

    Unique notification identifier

    -
    maxDrawdown: IStrategyPnL

    Maximum drawdown experienced during the life of this position up to the moment this public signal was created

    -
    maxDrawdownCost: number

    Absolute profit/loss in USD at the moment the position reached its maximum drawdown during the life of this position

    -
    maxDrawdownEntries: number

    Number of entries executed at the moment the position reached its maximum drawdown during the life of this position

    -
    maxDrawdownPercentage: number

    Profit/loss as percentage at the moment the position reached its maximum drawdown during the life of this position

    -
    maxDrawdownPriceClose: number

    Exit price for PNL calculation at the moment of max drawdown

    -
    maxDrawdownPriceOpen: number

    Maximum drawdown price reached in loss direction during the life of this position

    -
    note?: string

    Optional human-readable description of signal reason

    -
    originalPriceOpen: number

    Original entry price at signal creation (unchanged by DCA averaging)

    -
    originalPriceStopLoss: number

    Original stop loss price before any trailing adjustments

    -
    originalPriceTakeProfit: number

    Original take profit price before any trailing adjustments

    -
    peakProfit: IStrategyPnL

    Peak profit achieved during the life of this position up to the moment this public signal was created

    -
    peakProfitCost: number

    Absolute profit/loss in USD at the moment the position reached its peak profit during the life of this position

    -
    peakProfitEntries: number

    Number of entries executed at the moment the position reached its peak profit during the life of this position

    -
    peakProfitPercentage: number

    Profit/loss as percentage at the moment the position reached its peak profit during the life of this position

    -
    peakProfitPriceClose: number

    Exit price for PNL calculation at the moment of peak profit

    -
    peakProfitPriceOpen: number

    Peak price reached in profit direction during the life of this position

    -
    pendingAt: number

    Pending timestamp in milliseconds (when position became pending/active at priceOpen)

    -

    Total PNL of the closed position (including all entries and partials)

    -
    pnlCost: number

    Absolute profit/loss in USD

    -
    pnlEntries: number

    Total invested capital in USD

    -
    pnlPercentage: number

    Profit/loss as percentage (e.g., 1.5 for +1.5%, -2.3 for -2.3%)

    -
    pnlPriceClose: number

    Exit price from PNL calculation (adjusted with slippage and fees)

    -
    pnlPriceOpen: number

    Entry price from PNL calculation (effective price adjusted with slippage and fees)

    -
    position: "long" | "short"

    Trade direction: "long" (buy) or "short" (sell)

    -
    priceOpen: number

    Entry price for the position (breakeven level)

    -
    priceStopLoss: number

    Effective stop loss price (with trailing if set)

    -
    priceTakeProfit: number

    Effective take profit price (with trailing if set)

    -
    scheduledAt: number

    Signal creation timestamp in milliseconds (when signal was first created/scheduled)

    -
    signalId: string

    Unique signal identifier (UUID v4)

    -
    strategyName: string

    Strategy name that generated this signal

    -
    symbol: string

    Trading pair symbol (e.g., "BTCUSDT")

    -
    timestamp: number

    Unix timestamp in milliseconds when breakeven became available

    -
    totalEntries: number

    Total number of DCA entries (_entry.length). 1 = no averaging.

    -
    totalPartials: number

    Total number of partial closes executed (_partial.length). 0 = no partial closes done.

    -
    type: "breakeven.available"

    Discriminator for type-safe union

    -
    +
    createdAt: number

    Unix timestamp in milliseconds when the notification was created

    +
    currentPrice: number

    Current market price when breakeven became available

    +
    exchangeName: string

    Exchange name where signal was executed

    +
    id: string

    Unique notification identifier

    +
    maxDrawdown: IStrategyPnL

    Maximum drawdown experienced during the life of this position up to the moment this public signal was created

    +
    maxDrawdownCost: number

    Absolute profit/loss in USD at the moment the position reached its maximum drawdown during the life of this position

    +
    maxDrawdownEntries: number

    Number of entries executed at the moment the position reached its maximum drawdown during the life of this position

    +
    maxDrawdownPercentage: number

    Profit/loss as percentage at the moment the position reached its maximum drawdown during the life of this position

    +
    maxDrawdownPriceClose: number

    Exit price for PNL calculation at the moment of max drawdown

    +
    maxDrawdownPriceOpen: number

    Maximum drawdown price reached in loss direction during the life of this position

    +
    note?: string

    Optional human-readable description of signal reason

    +
    originalPriceOpen: number

    Original entry price at signal creation (unchanged by DCA averaging)

    +
    originalPriceStopLoss: number

    Original stop loss price before any trailing adjustments

    +
    originalPriceTakeProfit: number

    Original take profit price before any trailing adjustments

    +
    peakProfit: IStrategyPnL

    Peak profit achieved during the life of this position up to the moment this public signal was created

    +
    peakProfitCost: number

    Absolute profit/loss in USD at the moment the position reached its peak profit during the life of this position

    +
    peakProfitEntries: number

    Number of entries executed at the moment the position reached its peak profit during the life of this position

    +
    peakProfitPercentage: number

    Profit/loss as percentage at the moment the position reached its peak profit during the life of this position

    +
    peakProfitPriceClose: number

    Exit price for PNL calculation at the moment of peak profit

    +
    peakProfitPriceOpen: number

    Peak price reached in profit direction during the life of this position

    +
    pendingAt: number

    Pending timestamp in milliseconds (when position became pending/active at priceOpen)

    +

    Total PNL of the closed position (including all entries and partials)

    +
    pnlCost: number

    Absolute profit/loss in USD

    +
    pnlEntries: number

    Total invested capital in USD

    +
    pnlPercentage: number

    Profit/loss as percentage (e.g., 1.5 for +1.5%, -2.3 for -2.3%)

    +
    pnlPriceClose: number

    Exit price from PNL calculation (adjusted with slippage and fees)

    +
    pnlPriceOpen: number

    Entry price from PNL calculation (effective price adjusted with slippage and fees)

    +
    position: "long" | "short"

    Trade direction: "long" (buy) or "short" (sell)

    +
    priceOpen: number

    Entry price for the position (breakeven level)

    +
    priceStopLoss: number

    Effective stop loss price (with trailing if set)

    +
    priceTakeProfit: number

    Effective take profit price (with trailing if set)

    +
    scheduledAt: number

    Signal creation timestamp in milliseconds (when signal was first created/scheduled)

    +
    signalId: string

    Unique signal identifier (UUID v4)

    +
    strategyName: string

    Strategy name that generated this signal

    +
    symbol: string

    Trading pair symbol (e.g., "BTCUSDT")

    +
    timestamp: number

    Unix timestamp in milliseconds when breakeven became available

    +
    totalEntries: number

    Total number of DCA entries (_entry.length). 1 = no averaging.

    +
    totalPartials: number

    Total number of partial closes executed (_partial.length). 0 = no partial closes done.

    +
    type: "breakeven.available"

    Discriminator for type-safe union

    +

    Interface BreakevenCommit

    Breakeven event.

    -
    interface BreakevenCommit {
        action: "breakeven";
        backtest: boolean;
        currentPrice: number;
        exchangeName: string;
        frameName: string;
        maxDrawdown: IStrategyPnL;
        note?: string;
        originalPriceOpen: number;
        originalPriceStopLoss: number;
        originalPriceTakeProfit: number;
        peakProfit: IStrategyPnL;
        pendingAt: number;
        pnl: IStrategyPnL;
        position: "long" | "short";
        priceOpen: number;
        priceStopLoss: number;
        priceTakeProfit: number;
        scheduledAt: number;
        signal: IPublicSignalRow;
        signalId: string;
        strategyName: string;
        symbol: string;
        timestamp: number;
        totalEntries: number;
        totalPartials: number;
    }

    Hierarchy

    • SignalCommitBase
      • BreakevenCommit

    Properties

    interface BreakevenCommit {
        action: "breakeven";
        backtest: boolean;
        currentPrice: number;
        exchangeName: string;
        frameName: string;
        maxDrawdown: IStrategyPnL;
        note?: string;
        originalPriceOpen: number;
        originalPriceStopLoss: number;
        originalPriceTakeProfit: number;
        peakProfit: IStrategyPnL;
        pendingAt: number;
        pnl: IStrategyPnL;
        position: "long" | "short";
        priceOpen: number;
        priceStopLoss: number;
        priceTakeProfit: number;
        scheduledAt: number;
        signal: IPublicSignalRow;
        signalId: string;
        strategyName: string;
        symbol: string;
        timestamp: number;
        totalEntries: number;
        totalPartials: number;
    }

    Hierarchy

    • SignalCommitBase
      • BreakevenCommit

    Properties

    action: "breakeven"

    Discriminator for breakeven action

    -
    backtest: boolean

    Whether this event is from backtest mode (true) or live mode (false)

    -
    currentPrice: number

    Current market price at time of breakeven adjustment

    -
    exchangeName: string

    Exchange name where signal was executed

    -
    frameName: string

    Timeframe name (used in backtest mode, empty string in live mode)

    -
    maxDrawdown: IStrategyPnL

    Maximum drawdown experienced during the life of this position up to the moment this public signal was created

    -
    note?: string

    Optional human-readable description of signal reason

    -
    originalPriceOpen: number

    Original entry price at signal creation (unchanged by DCA averaging).

    -
    originalPriceStopLoss: number

    Original stop loss price before any trailing adjustments

    -
    originalPriceTakeProfit: number

    Original take profit price before any trailing adjustments

    -
    peakProfit: IStrategyPnL

    Peak profit achieved during the life of this position up to the moment this public signal was created

    -
    pendingAt: number

    Position activation timestamp in milliseconds (when price reached priceOpen)

    -

    Total PNL of the closed position (including all entries and partials)

    -
    position: "long" | "short"

    Trade direction: "long" (buy) or "short" (sell)

    -
    priceOpen: number

    Entry price for the position

    -
    priceStopLoss: number

    Effective stop loss price (set to priceOpen by breakeven action)

    -
    priceTakeProfit: number

    Effective take profit price (may differ from original after trailing)

    -
    scheduledAt: number

    Signal creation timestamp in milliseconds

    -

    Signal data at the moment of this event (snapshot of IPublicSignalRow)

    -
    signalId: string

    Unique signal identifier (UUID v4)

    -
    strategyName: string

    Strategy name that generated this signal

    -
    symbol: string

    Trading pair symbol (e.g., "BTCUSDT")

    -
    timestamp: number

    Timestamp from execution context (tick's when or backtest candle timestamp)

    -
    totalEntries: number

    Total number of DCA entries at the time of this event (_entry.length). +

    backtest: boolean

    Whether this event is from backtest mode (true) or live mode (false)

    +
    currentPrice: number

    Current market price at time of breakeven adjustment

    +
    exchangeName: string

    Exchange name where signal was executed

    +
    frameName: string

    Timeframe name (used in backtest mode, empty string in live mode)

    +
    maxDrawdown: IStrategyPnL

    Maximum drawdown experienced during the life of this position up to the moment this public signal was created

    +
    note?: string

    Optional human-readable description of signal reason

    +
    originalPriceOpen: number

    Original entry price at signal creation (unchanged by DCA averaging).

    +
    originalPriceStopLoss: number

    Original stop loss price before any trailing adjustments

    +
    originalPriceTakeProfit: number

    Original take profit price before any trailing adjustments

    +
    peakProfit: IStrategyPnL

    Peak profit achieved during the life of this position up to the moment this public signal was created

    +
    pendingAt: number

    Position activation timestamp in milliseconds (when price reached priceOpen)

    +

    Total PNL of the closed position (including all entries and partials)

    +
    position: "long" | "short"

    Trade direction: "long" (buy) or "short" (sell)

    +
    priceOpen: number

    Entry price for the position

    +
    priceStopLoss: number

    Effective stop loss price (set to priceOpen by breakeven action)

    +
    priceTakeProfit: number

    Effective take profit price (may differ from original after trailing)

    +
    scheduledAt: number

    Signal creation timestamp in milliseconds

    +

    Signal data at the moment of this event (snapshot of IPublicSignalRow)

    +
    signalId: string

    Unique signal identifier (UUID v4)

    +
    strategyName: string

    Strategy name that generated this signal

    +
    symbol: string

    Trading pair symbol (e.g., "BTCUSDT")

    +
    timestamp: number

    Timestamp from execution context (tick's when or backtest candle timestamp)

    +
    totalEntries: number

    Total number of DCA entries at the time of this event (_entry.length). 1 = no averaging done (only initial entry). 2+ = averaged positions.

    -
    totalPartials: number

    Total number of partial closes executed at the time of this event (_partial.length). +

    totalPartials: number

    Total number of partial closes executed at the time of this event (_partial.length). 0 = no partial closes done. 1+ = partial closes executed.

    -
    +

    Interface BreakevenCommitNotification

    Breakeven commit notification. Emitted when breakeven action is executed.

    -
    interface BreakevenCommitNotification {
        backtest: boolean;
        createdAt: number;
        currentPrice: number;
        exchangeName: string;
        id: string;
        maxDrawdown: IStrategyPnL;
        maxDrawdownCost: number;
        maxDrawdownEntries: number;
        maxDrawdownPercentage: number;
        maxDrawdownPriceClose: number;
        maxDrawdownPriceOpen: number;
        note?: string;
        originalPriceOpen: number;
        originalPriceStopLoss: number;
        originalPriceTakeProfit: number;
        peakProfit: IStrategyPnL;
        peakProfitCost: number;
        peakProfitEntries: number;
        peakProfitPercentage: number;
        peakProfitPriceClose: number;
        peakProfitPriceOpen: number;
        pendingAt: number;
        pnl: IStrategyPnL;
        pnlCost: number;
        pnlEntries: number;
        pnlPercentage: number;
        pnlPriceClose: number;
        pnlPriceOpen: number;
        position: "long" | "short";
        priceOpen: number;
        priceStopLoss: number;
        priceTakeProfit: number;
        scheduledAt: number;
        signalId: string;
        strategyName: string;
        symbol: string;
        timestamp: number;
        totalEntries: number;
        totalPartials: number;
        type: "breakeven.commit";
    }

    Properties

    interface BreakevenCommitNotification {
        backtest: boolean;
        createdAt: number;
        currentPrice: number;
        exchangeName: string;
        id: string;
        maxDrawdown: IStrategyPnL;
        maxDrawdownCost: number;
        maxDrawdownEntries: number;
        maxDrawdownPercentage: number;
        maxDrawdownPriceClose: number;
        maxDrawdownPriceOpen: number;
        note?: string;
        originalPriceOpen: number;
        originalPriceStopLoss: number;
        originalPriceTakeProfit: number;
        peakProfit: IStrategyPnL;
        peakProfitCost: number;
        peakProfitEntries: number;
        peakProfitPercentage: number;
        peakProfitPriceClose: number;
        peakProfitPriceOpen: number;
        pendingAt: number;
        pnl: IStrategyPnL;
        pnlCost: number;
        pnlEntries: number;
        pnlPercentage: number;
        pnlPriceClose: number;
        pnlPriceOpen: number;
        position: "long" | "short";
        priceOpen: number;
        priceStopLoss: number;
        priceTakeProfit: number;
        scheduledAt: number;
        signalId: string;
        strategyName: string;
        symbol: string;
        timestamp: number;
        totalEntries: number;
        totalPartials: number;
        type: "breakeven.commit";
    }

    Properties

    backtest createdAt currentPrice exchangeName @@ -41,46 +41,46 @@ Emitted when breakeven action is executed.

    totalPartials type

    Properties

    backtest: boolean

    Whether this notification is from backtest mode (true) or live mode (false)

    -
    createdAt: number

    Unix timestamp in milliseconds when the notification was created

    -
    currentPrice: number

    Current market price when breakeven was executed

    -
    exchangeName: string

    Exchange name where signal was executed

    -
    id: string

    Unique notification identifier

    -
    maxDrawdown: IStrategyPnL

    Maximum drawdown experienced during the life of this position up to the moment this public signal was created

    -
    maxDrawdownCost: number

    Absolute profit/loss in USD at the moment the position reached its maximum drawdown during the life of this position

    -
    maxDrawdownEntries: number

    Number of entries executed at the moment the position reached its maximum drawdown during the life of this position

    -
    maxDrawdownPercentage: number

    Profit/loss as percentage at the moment the position reached its maximum drawdown during the life of this position

    -
    maxDrawdownPriceClose: number

    Exit price for PNL calculation at the moment of max drawdown

    -
    maxDrawdownPriceOpen: number

    Maximum drawdown price reached in loss direction during the life of this position

    -
    note?: string

    Optional human-readable description of signal reason

    -
    originalPriceOpen: number

    Original entry price at signal creation (unchanged by DCA averaging)

    -
    originalPriceStopLoss: number

    Original stop loss price before any trailing adjustments

    -
    originalPriceTakeProfit: number

    Original take profit price before any trailing adjustments

    -
    peakProfit: IStrategyPnL

    Peak profit achieved during the life of this position up to the moment this public signal was created

    -
    peakProfitCost: number

    Absolute profit/loss in USD at the moment the position reached its peak profit during the life of this position

    -
    peakProfitEntries: number

    Number of entries executed at the moment the position reached its peak profit during the life of this position

    -
    peakProfitPercentage: number

    Profit/loss as percentage at the moment the position reached its peak profit during the life of this position

    -
    peakProfitPriceClose: number

    Exit price for PNL calculation at the moment of peak profit

    -
    peakProfitPriceOpen: number

    Peak price reached in profit direction during the life of this position

    -
    pendingAt: number

    Pending timestamp in milliseconds (when position became pending/active at priceOpen)

    -

    Total PNL of the closed position (including all entries and partials)

    -
    pnlCost: number

    Absolute profit/loss in USD

    -
    pnlEntries: number

    Total invested capital in USD

    -
    pnlPercentage: number

    Profit/loss as percentage (e.g., 1.5 for +1.5%, -2.3 for -2.3%)

    -
    pnlPriceClose: number

    Exit price from PNL calculation (adjusted with slippage and fees)

    -
    pnlPriceOpen: number

    Entry price from PNL calculation (effective price adjusted with slippage and fees)

    -
    position: "long" | "short"

    Trade direction: "long" (buy) or "short" (sell)

    -
    priceOpen: number

    Entry price for the position

    -
    priceStopLoss: number

    Effective stop loss price (with trailing if set, after breakeven this equals priceOpen)

    -
    priceTakeProfit: number

    Effective take profit price (with trailing if set)

    -
    scheduledAt: number

    Signal creation timestamp in milliseconds (when signal was first created/scheduled)

    -
    signalId: string

    Unique signal identifier (UUID v4)

    -
    strategyName: string

    Strategy name that generated this signal

    -
    symbol: string

    Trading pair symbol (e.g., "BTCUSDT")

    -
    timestamp: number

    Unix timestamp in milliseconds when breakeven was committed

    -
    totalEntries: number

    Total number of DCA entries (_entry.length). 1 = no averaging.

    -
    totalPartials: number

    Total number of partial closes executed (_partial.length). 0 = no partial closes done.

    -
    type: "breakeven.commit"

    Discriminator for type-safe union

    -
    +
    createdAt: number

    Unix timestamp in milliseconds when the notification was created

    +
    currentPrice: number

    Current market price when breakeven was executed

    +
    exchangeName: string

    Exchange name where signal was executed

    +
    id: string

    Unique notification identifier

    +
    maxDrawdown: IStrategyPnL

    Maximum drawdown experienced during the life of this position up to the moment this public signal was created

    +
    maxDrawdownCost: number

    Absolute profit/loss in USD at the moment the position reached its maximum drawdown during the life of this position

    +
    maxDrawdownEntries: number

    Number of entries executed at the moment the position reached its maximum drawdown during the life of this position

    +
    maxDrawdownPercentage: number

    Profit/loss as percentage at the moment the position reached its maximum drawdown during the life of this position

    +
    maxDrawdownPriceClose: number

    Exit price for PNL calculation at the moment of max drawdown

    +
    maxDrawdownPriceOpen: number

    Maximum drawdown price reached in loss direction during the life of this position

    +
    note?: string

    Optional human-readable description of signal reason

    +
    originalPriceOpen: number

    Original entry price at signal creation (unchanged by DCA averaging)

    +
    originalPriceStopLoss: number

    Original stop loss price before any trailing adjustments

    +
    originalPriceTakeProfit: number

    Original take profit price before any trailing adjustments

    +
    peakProfit: IStrategyPnL

    Peak profit achieved during the life of this position up to the moment this public signal was created

    +
    peakProfitCost: number

    Absolute profit/loss in USD at the moment the position reached its peak profit during the life of this position

    +
    peakProfitEntries: number

    Number of entries executed at the moment the position reached its peak profit during the life of this position

    +
    peakProfitPercentage: number

    Profit/loss as percentage at the moment the position reached its peak profit during the life of this position

    +
    peakProfitPriceClose: number

    Exit price for PNL calculation at the moment of peak profit

    +
    peakProfitPriceOpen: number

    Peak price reached in profit direction during the life of this position

    +
    pendingAt: number

    Pending timestamp in milliseconds (when position became pending/active at priceOpen)

    +

    Total PNL of the closed position (including all entries and partials)

    +
    pnlCost: number

    Absolute profit/loss in USD

    +
    pnlEntries: number

    Total invested capital in USD

    +
    pnlPercentage: number

    Profit/loss as percentage (e.g., 1.5 for +1.5%, -2.3 for -2.3%)

    +
    pnlPriceClose: number

    Exit price from PNL calculation (adjusted with slippage and fees)

    +
    pnlPriceOpen: number

    Entry price from PNL calculation (effective price adjusted with slippage and fees)

    +
    position: "long" | "short"

    Trade direction: "long" (buy) or "short" (sell)

    +
    priceOpen: number

    Entry price for the position

    +
    priceStopLoss: number

    Effective stop loss price (with trailing if set, after breakeven this equals priceOpen)

    +
    priceTakeProfit: number

    Effective take profit price (with trailing if set)

    +
    scheduledAt: number

    Signal creation timestamp in milliseconds (when signal was first created/scheduled)

    +
    signalId: string

    Unique signal identifier (UUID v4)

    +
    strategyName: string

    Strategy name that generated this signal

    +
    symbol: string

    Trading pair symbol (e.g., "BTCUSDT")

    +
    timestamp: number

    Unix timestamp in milliseconds when breakeven was committed

    +
    totalEntries: number

    Total number of DCA entries (_entry.length). 1 = no averaging.

    +
    totalPartials: number

    Total number of partial closes executed (_partial.length). 0 = no partial closes done.

    +
    type: "breakeven.commit"

    Discriminator for type-safe union

    +

    Interface BreakevenEvent

    Unified breakeven event data for report generation. Contains all information about when signals reached breakeven.

    -
    interface BreakevenEvent {
        backtest: boolean;
        currentPrice: number;
        note?: string;
        originalPriceOpen?: number;
        originalPriceStopLoss?: number;
        originalPriceTakeProfit?: number;
        partialExecuted?: number;
        pendingAt?: number;
        pnl?: IStrategyPnL;
        position: string;
        priceOpen: number;
        priceStopLoss?: number;
        priceTakeProfit?: number;
        scheduledAt?: number;
        signalId: string;
        strategyName: string;
        symbol: string;
        timestamp: number;
        totalEntries?: number;
        totalPartials?: number;
    }

    Properties

    interface BreakevenEvent {
        backtest: boolean;
        currentPrice: number;
        note?: string;
        originalPriceOpen?: number;
        originalPriceStopLoss?: number;
        originalPriceTakeProfit?: number;
        partialExecuted?: number;
        pendingAt?: number;
        pnl?: IStrategyPnL;
        position: string;
        priceOpen: number;
        priceStopLoss?: number;
        priceTakeProfit?: number;
        scheduledAt?: number;
        signalId: string;
        strategyName: string;
        symbol: string;
        timestamp: number;
        totalEntries?: number;
        totalPartials?: number;
    }

    Properties

    backtest currentPrice note? originalPriceOpen? @@ -21,26 +21,26 @@ Contains all information about when signals reached breakeven.

    totalEntries? totalPartials?

    Properties

    backtest: boolean

    True if backtest mode, false if live mode

    -
    currentPrice: number

    Current market price when breakeven was reached

    -
    note?: string

    Human-readable description of signal reason

    -
    originalPriceOpen?: number

    Original entry price before DCA averaging (present when averageBuy was applied)

    -
    originalPriceStopLoss?: number

    Original stop loss price set at signal creation

    -
    originalPriceTakeProfit?: number

    Original take profit price set at signal creation

    -
    partialExecuted?: number

    Total executed percentage from partial closes

    -
    pendingAt?: number

    Timestamp when position became active (ms)

    -

    Unrealized PNL at the moment breakeven was reached

    -
    position: string

    Position type

    -
    priceOpen: number

    Entry price (breakeven level)

    -
    priceStopLoss?: number

    Stop loss exit price

    -
    priceTakeProfit?: number

    Take profit target price

    -
    scheduledAt?: number

    Timestamp when signal was created/scheduled (ms)

    -
    signalId: string

    Signal ID

    -
    strategyName: string

    Strategy name

    -
    symbol: string

    Trading pair symbol

    -
    timestamp: number

    Event timestamp in milliseconds

    -
    totalEntries?: number

    Total number of DCA entries (present when averageBuy was applied)

    -
    totalPartials?: number

    Total number of partial closes executed (_partial.length)

    -
    +
    currentPrice: number

    Current market price when breakeven was reached

    +
    note?: string

    Human-readable description of signal reason

    +
    originalPriceOpen?: number

    Original entry price before DCA averaging (present when averageBuy was applied)

    +
    originalPriceStopLoss?: number

    Original stop loss price set at signal creation

    +
    originalPriceTakeProfit?: number

    Original take profit price set at signal creation

    +
    partialExecuted?: number

    Total executed percentage from partial closes

    +
    pendingAt?: number

    Timestamp when position became active (ms)

    +

    Unrealized PNL at the moment breakeven was reached

    +
    position: string

    Position type

    +
    priceOpen: number

    Entry price (breakeven level)

    +
    priceStopLoss?: number

    Stop loss exit price

    +
    priceTakeProfit?: number

    Take profit target price

    +
    scheduledAt?: number

    Timestamp when signal was created/scheduled (ms)

    +
    signalId: string

    Signal ID

    +
    strategyName: string

    Strategy name

    +
    symbol: string

    Trading pair symbol

    +
    timestamp: number

    Event timestamp in milliseconds

    +
    totalEntries?: number

    Total number of DCA entries (present when averageBuy was applied)

    +
    totalPartials?: number

    Total number of partial closes executed (_partial.length)

    +

    Interface CancelScheduledCommit

    Cancel scheduled signal event.

    -
    interface CancelScheduledCommit {
        action: "cancel-scheduled";
        backtest: boolean;
        cancelId?: string;
        exchangeName: string;
        frameName: string;
        maxDrawdown: IStrategyPnL;
        note?: string;
        originalPriceOpen: number;
        peakProfit: IStrategyPnL;
        pnl: IStrategyPnL;
        signal: IPublicSignalRow;
        signalId: string;
        strategyName: string;
        symbol: string;
        timestamp: number;
        totalEntries: number;
        totalPartials: number;
    }

    Hierarchy

    • SignalCommitBase
      • CancelScheduledCommit

    Properties

    interface CancelScheduledCommit {
        action: "cancel-scheduled";
        backtest: boolean;
        cancelId?: string;
        exchangeName: string;
        frameName: string;
        maxDrawdown: IStrategyPnL;
        note?: string;
        originalPriceOpen: number;
        peakProfit: IStrategyPnL;
        pnl: IStrategyPnL;
        signal: IPublicSignalRow;
        signalId: string;
        strategyName: string;
        symbol: string;
        timestamp: number;
        totalEntries: number;
        totalPartials: number;
    }

    Hierarchy

    • SignalCommitBase
      • CancelScheduledCommit

    Properties

    action: "cancel-scheduled"

    Discriminator for cancel-scheduled action

    -
    backtest: boolean

    Whether this event is from backtest mode (true) or live mode (false)

    -
    cancelId?: string

    Optional identifier for the cancellation reason (user-provided)

    -
    exchangeName: string

    Exchange name where signal was executed

    -
    frameName: string

    Timeframe name (used in backtest mode, empty string in live mode)

    -
    maxDrawdown: IStrategyPnL

    Maximum drawdown experienced during the life of this position up to the moment this public signal was created

    -
    note?: string

    Optional human-readable description of signal reason

    -
    originalPriceOpen: number

    Original entry price at signal creation (unchanged by DCA averaging).

    -
    peakProfit: IStrategyPnL

    Peak profit achieved during the life of this position up to the moment this public signal was created

    -

    Total PNL of the closed position (including all entries and partials)

    -

    Signal data at the moment of this event (snapshot of IPublicSignalRow)

    -
    signalId: string

    Unique signal identifier (UUID v4)

    -
    strategyName: string

    Strategy name that generated this signal

    -
    symbol: string

    Trading pair symbol (e.g., "BTCUSDT")

    -
    timestamp: number

    Timestamp from execution context (tick's when or backtest candle timestamp)

    -
    totalEntries: number

    Total number of DCA entries at the time of this event (_entry.length). +

    backtest: boolean

    Whether this event is from backtest mode (true) or live mode (false)

    +
    cancelId?: string

    Optional identifier for the cancellation reason (user-provided)

    +
    exchangeName: string

    Exchange name where signal was executed

    +
    frameName: string

    Timeframe name (used in backtest mode, empty string in live mode)

    +
    maxDrawdown: IStrategyPnL

    Maximum drawdown experienced during the life of this position up to the moment this public signal was created

    +
    note?: string

    Optional human-readable description of signal reason

    +
    originalPriceOpen: number

    Original entry price at signal creation (unchanged by DCA averaging).

    +
    peakProfit: IStrategyPnL

    Peak profit achieved during the life of this position up to the moment this public signal was created

    +

    Total PNL of the closed position (including all entries and partials)

    +

    Signal data at the moment of this event (snapshot of IPublicSignalRow)

    +
    signalId: string

    Unique signal identifier (UUID v4)

    +
    strategyName: string

    Strategy name that generated this signal

    +
    symbol: string

    Trading pair symbol (e.g., "BTCUSDT")

    +
    timestamp: number

    Timestamp from execution context (tick's when or backtest candle timestamp)

    +
    totalEntries: number

    Total number of DCA entries at the time of this event (_entry.length). 1 = no averaging done (only initial entry). 2+ = averaged positions.

    -
    totalPartials: number

    Total number of partial closes executed at the time of this event (_partial.length). +

    totalPartials: number

    Total number of partial closes executed at the time of this event (_partial.length). 0 = no partial closes done. 1+ = partial closes executed.

    -
    +

    Interface CancelScheduledCommitNotification

    Cancel scheduled commit notification. Emitted when a scheduled signal is cancelled before activation.

    -
    interface CancelScheduledCommitNotification {
        backtest: boolean;
        cancelId?: string;
        createdAt: number;
        exchangeName: string;
        id: string;
        maxDrawdown: IStrategyPnL;
        maxDrawdownCost: number;
        maxDrawdownEntries: number;
        maxDrawdownPercentage: number;
        maxDrawdownPriceClose: number;
        maxDrawdownPriceOpen: number;
        note?: string;
        originalPriceOpen: number;
        peakProfit: IStrategyPnL;
        peakProfitCost: number;
        peakProfitEntries: number;
        peakProfitPercentage: number;
        peakProfitPriceClose: number;
        peakProfitPriceOpen: number;
        pnl: IStrategyPnL;
        pnlCost: number;
        pnlEntries: number;
        pnlPercentage: number;
        pnlPriceClose: number;
        pnlPriceOpen: number;
        signalId: string;
        strategyName: string;
        symbol: string;
        timestamp: number;
        totalEntries: number;
        totalPartials: number;
        type: "cancel_scheduled.commit";
    }

    Properties

    interface CancelScheduledCommitNotification {
        backtest: boolean;
        cancelId?: string;
        createdAt: number;
        exchangeName: string;
        id: string;
        maxDrawdown: IStrategyPnL;
        maxDrawdownCost: number;
        maxDrawdownEntries: number;
        maxDrawdownPercentage: number;
        maxDrawdownPriceClose: number;
        maxDrawdownPriceOpen: number;
        note?: string;
        originalPriceOpen: number;
        peakProfit: IStrategyPnL;
        peakProfitCost: number;
        peakProfitEntries: number;
        peakProfitPercentage: number;
        peakProfitPriceClose: number;
        peakProfitPriceOpen: number;
        pnl: IStrategyPnL;
        pnlCost: number;
        pnlEntries: number;
        pnlPercentage: number;
        pnlPriceClose: number;
        pnlPriceOpen: number;
        signalId: string;
        strategyName: string;
        symbol: string;
        timestamp: number;
        totalEntries: number;
        totalPartials: number;
        type: "cancel_scheduled.commit";
    }

    Properties

    backtest cancelId? createdAt exchangeName @@ -33,38 +33,38 @@ Emitted when a scheduled signal is cancelled before activation.

    totalPartials type

    Properties

    backtest: boolean

    Whether this notification is from backtest mode (true) or live mode (false)

    -
    cancelId?: string

    Optional identifier for the cancellation reason (user-provided)

    -
    createdAt: number

    Unix timestamp in milliseconds when the notification was created

    -
    exchangeName: string

    Exchange name where signal was executed

    -
    id: string

    Unique notification identifier

    -
    maxDrawdown: IStrategyPnL

    Maximum drawdown experienced during the life of this position up to the moment this public signal was created

    -
    maxDrawdownCost: number

    Absolute profit/loss in USD at the moment the position reached its maximum drawdown during the life of this position

    -
    maxDrawdownEntries: number

    Number of entries executed at the moment the position reached its maximum drawdown during the life of this position

    -
    maxDrawdownPercentage: number

    Profit/loss as percentage at the moment the position reached its maximum drawdown during the life of this position

    -
    maxDrawdownPriceClose: number

    Exit price for PNL calculation at the moment of max drawdown

    -
    maxDrawdownPriceOpen: number

    Maximum drawdown price reached in loss direction during the life of this position

    -
    note?: string

    Optional human-readable description of signal reason

    -
    originalPriceOpen: number

    Original entry price at signal creation (unchanged by DCA averaging)

    -
    peakProfit: IStrategyPnL

    Peak profit achieved during the life of this position up to the moment this public signal was created

    -
    peakProfitCost: number

    Absolute profit/loss in USD at the moment the position reached its peak profit during the life of this position

    -
    peakProfitEntries: number

    Number of entries executed at the moment the position reached its peak profit during the life of this position

    -
    peakProfitPercentage: number

    Profit/loss as percentage at the moment the position reached its peak profit during the life of this position

    -
    peakProfitPriceClose: number

    Exit price for PNL calculation at the moment of peak profit

    -
    peakProfitPriceOpen: number

    Peak price reached in profit direction during the life of this position

    -

    Total PNL of the closed position (including all entries and partials)

    -
    pnlCost: number

    Absolute profit/loss in USD

    -
    pnlEntries: number

    Total invested capital in USD

    -
    pnlPercentage: number

    Profit/loss as percentage (e.g., 1.5 for +1.5%, -2.3 for -2.3%)

    -
    pnlPriceClose: number

    Exit price from PNL calculation (adjusted with slippage and fees)

    -
    pnlPriceOpen: number

    Entry price from PNL calculation (effective price adjusted with slippage and fees)

    -
    signalId: string

    Unique signal identifier (UUID v4)

    -
    strategyName: string

    Strategy name that generated this signal

    -
    symbol: string

    Trading pair symbol (e.g., "BTCUSDT")

    -
    timestamp: number

    Unix timestamp in milliseconds when cancellation was committed

    -
    totalEntries: number

    Total number of DCA entries (_entry.length). 1 = no averaging.

    -
    totalPartials: number

    Total number of partial closes executed (_partial.length). 0 = no partial closes done.

    -
    type: "cancel_scheduled.commit"

    Discriminator for type-safe union

    -
    +
    cancelId?: string

    Optional identifier for the cancellation reason (user-provided)

    +
    createdAt: number

    Unix timestamp in milliseconds when the notification was created

    +
    exchangeName: string

    Exchange name where signal was executed

    +
    id: string

    Unique notification identifier

    +
    maxDrawdown: IStrategyPnL

    Maximum drawdown experienced during the life of this position up to the moment this public signal was created

    +
    maxDrawdownCost: number

    Absolute profit/loss in USD at the moment the position reached its maximum drawdown during the life of this position

    +
    maxDrawdownEntries: number

    Number of entries executed at the moment the position reached its maximum drawdown during the life of this position

    +
    maxDrawdownPercentage: number

    Profit/loss as percentage at the moment the position reached its maximum drawdown during the life of this position

    +
    maxDrawdownPriceClose: number

    Exit price for PNL calculation at the moment of max drawdown

    +
    maxDrawdownPriceOpen: number

    Maximum drawdown price reached in loss direction during the life of this position

    +
    note?: string

    Optional human-readable description of signal reason

    +
    originalPriceOpen: number

    Original entry price at signal creation (unchanged by DCA averaging)

    +
    peakProfit: IStrategyPnL

    Peak profit achieved during the life of this position up to the moment this public signal was created

    +
    peakProfitCost: number

    Absolute profit/loss in USD at the moment the position reached its peak profit during the life of this position

    +
    peakProfitEntries: number

    Number of entries executed at the moment the position reached its peak profit during the life of this position

    +
    peakProfitPercentage: number

    Profit/loss as percentage at the moment the position reached its peak profit during the life of this position

    +
    peakProfitPriceClose: number

    Exit price for PNL calculation at the moment of peak profit

    +
    peakProfitPriceOpen: number

    Peak price reached in profit direction during the life of this position

    +

    Total PNL of the closed position (including all entries and partials)

    +
    pnlCost: number

    Absolute profit/loss in USD

    +
    pnlEntries: number

    Total invested capital in USD

    +
    pnlPercentage: number

    Profit/loss as percentage (e.g., 1.5 for +1.5%, -2.3 for -2.3%)

    +
    pnlPriceClose: number

    Exit price from PNL calculation (adjusted with slippage and fees)

    +
    pnlPriceOpen: number

    Entry price from PNL calculation (effective price adjusted with slippage and fees)

    +
    signalId: string

    Unique signal identifier (UUID v4)

    +
    strategyName: string

    Strategy name that generated this signal

    +
    symbol: string

    Trading pair symbol (e.g., "BTCUSDT")

    +
    timestamp: number

    Unix timestamp in milliseconds when cancellation was committed

    +
    totalEntries: number

    Total number of DCA entries (_entry.length). 1 = no averaging.

    +
    totalPartials: number

    Total number of partial closes executed (_partial.length). 0 = no partial closes done.

    +
    type: "cancel_scheduled.commit"

    Discriminator for type-safe union

    +

    Interface ClosePendingCommit

    Close pending signal event.

    -
    interface ClosePendingCommit {
        action: "close-pending";
        backtest: boolean;
        closeId?: string;
        exchangeName: string;
        frameName: string;
        maxDrawdown: IStrategyPnL;
        note?: string;
        originalPriceOpen: number;
        peakProfit: IStrategyPnL;
        pnl: IStrategyPnL;
        signal: IPublicSignalRow;
        signalId: string;
        strategyName: string;
        symbol: string;
        timestamp: number;
        totalEntries: number;
        totalPartials: number;
    }

    Hierarchy

    • SignalCommitBase
      • ClosePendingCommit

    Properties

    interface ClosePendingCommit {
        action: "close-pending";
        backtest: boolean;
        closeId?: string;
        exchangeName: string;
        frameName: string;
        maxDrawdown: IStrategyPnL;
        note?: string;
        originalPriceOpen: number;
        peakProfit: IStrategyPnL;
        pnl: IStrategyPnL;
        signal: IPublicSignalRow;
        signalId: string;
        strategyName: string;
        symbol: string;
        timestamp: number;
        totalEntries: number;
        totalPartials: number;
    }

    Hierarchy

    • SignalCommitBase
      • ClosePendingCommit

    Properties

    action: "close-pending"

    Discriminator for close-pending action

    -
    backtest: boolean

    Whether this event is from backtest mode (true) or live mode (false)

    -
    closeId?: string

    Optional identifier for the close reason (user-provided)

    -
    exchangeName: string

    Exchange name where signal was executed

    -
    frameName: string

    Timeframe name (used in backtest mode, empty string in live mode)

    -
    maxDrawdown: IStrategyPnL

    Maximum drawdown experienced during the life of this position up to the moment this public signal was created

    -
    note?: string

    Optional human-readable description of signal reason

    -
    originalPriceOpen: number

    Original entry price at signal creation (unchanged by DCA averaging).

    -
    peakProfit: IStrategyPnL

    Peak profit achieved during the life of this position up to the moment this public signal was created

    -

    Total PNL of the closed position (including all entries and partials)

    -

    Signal data at the moment of this event (snapshot of IPublicSignalRow)

    -
    signalId: string

    Unique signal identifier (UUID v4)

    -
    strategyName: string

    Strategy name that generated this signal

    -
    symbol: string

    Trading pair symbol (e.g., "BTCUSDT")

    -
    timestamp: number

    Timestamp from execution context (tick's when or backtest candle timestamp)

    -
    totalEntries: number

    Total number of DCA entries at the time of this event (_entry.length). +

    backtest: boolean

    Whether this event is from backtest mode (true) or live mode (false)

    +
    closeId?: string

    Optional identifier for the close reason (user-provided)

    +
    exchangeName: string

    Exchange name where signal was executed

    +
    frameName: string

    Timeframe name (used in backtest mode, empty string in live mode)

    +
    maxDrawdown: IStrategyPnL

    Maximum drawdown experienced during the life of this position up to the moment this public signal was created

    +
    note?: string

    Optional human-readable description of signal reason

    +
    originalPriceOpen: number

    Original entry price at signal creation (unchanged by DCA averaging).

    +
    peakProfit: IStrategyPnL

    Peak profit achieved during the life of this position up to the moment this public signal was created

    +

    Total PNL of the closed position (including all entries and partials)

    +

    Signal data at the moment of this event (snapshot of IPublicSignalRow)

    +
    signalId: string

    Unique signal identifier (UUID v4)

    +
    strategyName: string

    Strategy name that generated this signal

    +
    symbol: string

    Trading pair symbol (e.g., "BTCUSDT")

    +
    timestamp: number

    Timestamp from execution context (tick's when or backtest candle timestamp)

    +
    totalEntries: number

    Total number of DCA entries at the time of this event (_entry.length). 1 = no averaging done (only initial entry). 2+ = averaged positions.

    -
    totalPartials: number

    Total number of partial closes executed at the time of this event (_partial.length). +

    totalPartials: number

    Total number of partial closes executed at the time of this event (_partial.length). 0 = no partial closes done. 1+ = partial closes executed.

    -
    +

    Interface ClosePendingCommitNotification

    Close pending commit notification. Emitted when a pending signal is closed before position activation.

    -
    interface ClosePendingCommitNotification {
        backtest: boolean;
        closeId?: string;
        createdAt: number;
        exchangeName: string;
        id: string;
        maxDrawdown: IStrategyPnL;
        maxDrawdownCost: number;
        maxDrawdownEntries: number;
        maxDrawdownPercentage: number;
        maxDrawdownPriceClose: number;
        maxDrawdownPriceOpen: number;
        note?: string;
        originalPriceOpen: number;
        peakProfit: IStrategyPnL;
        peakProfitCost: number;
        peakProfitEntries: number;
        peakProfitPercentage: number;
        peakProfitPriceClose: number;
        peakProfitPriceOpen: number;
        pnl: IStrategyPnL;
        pnlCost: number;
        pnlEntries: number;
        pnlPercentage: number;
        pnlPriceClose: number;
        pnlPriceOpen: number;
        signalId: string;
        strategyName: string;
        symbol: string;
        timestamp: number;
        totalEntries: number;
        totalPartials: number;
        type: "close_pending.commit";
    }

    Properties

    interface ClosePendingCommitNotification {
        backtest: boolean;
        closeId?: string;
        createdAt: number;
        exchangeName: string;
        id: string;
        maxDrawdown: IStrategyPnL;
        maxDrawdownCost: number;
        maxDrawdownEntries: number;
        maxDrawdownPercentage: number;
        maxDrawdownPriceClose: number;
        maxDrawdownPriceOpen: number;
        note?: string;
        originalPriceOpen: number;
        peakProfit: IStrategyPnL;
        peakProfitCost: number;
        peakProfitEntries: number;
        peakProfitPercentage: number;
        peakProfitPriceClose: number;
        peakProfitPriceOpen: number;
        pnl: IStrategyPnL;
        pnlCost: number;
        pnlEntries: number;
        pnlPercentage: number;
        pnlPriceClose: number;
        pnlPriceOpen: number;
        signalId: string;
        strategyName: string;
        symbol: string;
        timestamp: number;
        totalEntries: number;
        totalPartials: number;
        type: "close_pending.commit";
    }

    Properties

    backtest closeId? createdAt exchangeName @@ -33,38 +33,38 @@ Emitted when a pending signal is closed before position activation.

    totalPartials type

    Properties

    backtest: boolean

    Whether this notification is from backtest mode (true) or live mode (false)

    -
    closeId?: string

    Optional identifier for the close reason (user-provided)

    -
    createdAt: number

    Unix timestamp in milliseconds when the notification was created

    -
    exchangeName: string

    Exchange name where signal was executed

    -
    id: string

    Unique notification identifier

    -
    maxDrawdown: IStrategyPnL

    Maximum drawdown experienced during the life of this position up to the moment this public signal was created

    -
    maxDrawdownCost: number

    Absolute profit/loss in USD at the moment the position reached its maximum drawdown during the life of this position

    -
    maxDrawdownEntries: number

    Number of entries executed at the moment the position reached its maximum drawdown during the life of this position

    -
    maxDrawdownPercentage: number

    Profit/loss as percentage at the moment the position reached its maximum drawdown during the life of this position

    -
    maxDrawdownPriceClose: number

    Exit price for PNL calculation at the moment of max drawdown

    -
    maxDrawdownPriceOpen: number

    Maximum drawdown price reached in loss direction during the life of this position

    -
    note?: string

    Optional human-readable description of signal reason

    -
    originalPriceOpen: number

    Original entry price at signal creation (unchanged by DCA averaging)

    -
    peakProfit: IStrategyPnL

    Peak profit achieved during the life of this position up to the moment this public signal was created

    -
    peakProfitCost: number

    Absolute profit/loss in USD at the moment the position reached its peak profit during the life of this position

    -
    peakProfitEntries: number

    Number of entries executed at the moment the position reached its peak profit during the life of this position

    -
    peakProfitPercentage: number

    Profit/loss as percentage at the moment the position reached its peak profit during the life of this position

    -
    peakProfitPriceClose: number

    Exit price for PNL calculation at the moment of peak profit

    -
    peakProfitPriceOpen: number

    Peak price reached in profit direction during the life of this position

    -

    Total PNL of the closed position (including all entries and partials)

    -
    pnlCost: number

    Absolute profit/loss in USD

    -
    pnlEntries: number

    Total invested capital in USD

    -
    pnlPercentage: number

    Profit/loss as percentage (e.g., 1.5 for +1.5%, -2.3 for -2.3%)

    -
    pnlPriceClose: number

    Exit price from PNL calculation (adjusted with slippage and fees)

    -
    pnlPriceOpen: number

    Entry price from PNL calculation (effective price adjusted with slippage and fees)

    -
    signalId: string

    Unique signal identifier (UUID v4)

    -
    strategyName: string

    Strategy name that generated this signal

    -
    symbol: string

    Trading pair symbol (e.g., "BTCUSDT")

    -
    timestamp: number

    Unix timestamp in milliseconds when close was committed

    -
    totalEntries: number

    Total number of DCA entries (_entry.length). 1 = no averaging.

    -
    totalPartials: number

    Total number of partial closes executed (_partial.length). 0 = no partial closes done.

    -
    type: "close_pending.commit"

    Discriminator for type-safe union

    -
    +
    closeId?: string

    Optional identifier for the close reason (user-provided)

    +
    createdAt: number

    Unix timestamp in milliseconds when the notification was created

    +
    exchangeName: string

    Exchange name where signal was executed

    +
    id: string

    Unique notification identifier

    +
    maxDrawdown: IStrategyPnL

    Maximum drawdown experienced during the life of this position up to the moment this public signal was created

    +
    maxDrawdownCost: number

    Absolute profit/loss in USD at the moment the position reached its maximum drawdown during the life of this position

    +
    maxDrawdownEntries: number

    Number of entries executed at the moment the position reached its maximum drawdown during the life of this position

    +
    maxDrawdownPercentage: number

    Profit/loss as percentage at the moment the position reached its maximum drawdown during the life of this position

    +
    maxDrawdownPriceClose: number

    Exit price for PNL calculation at the moment of max drawdown

    +
    maxDrawdownPriceOpen: number

    Maximum drawdown price reached in loss direction during the life of this position

    +
    note?: string

    Optional human-readable description of signal reason

    +
    originalPriceOpen: number

    Original entry price at signal creation (unchanged by DCA averaging)

    +
    peakProfit: IStrategyPnL

    Peak profit achieved during the life of this position up to the moment this public signal was created

    +
    peakProfitCost: number

    Absolute profit/loss in USD at the moment the position reached its peak profit during the life of this position

    +
    peakProfitEntries: number

    Number of entries executed at the moment the position reached its peak profit during the life of this position

    +
    peakProfitPercentage: number

    Profit/loss as percentage at the moment the position reached its peak profit during the life of this position

    +
    peakProfitPriceClose: number

    Exit price for PNL calculation at the moment of peak profit

    +
    peakProfitPriceOpen: number

    Peak price reached in profit direction during the life of this position

    +

    Total PNL of the closed position (including all entries and partials)

    +
    pnlCost: number

    Absolute profit/loss in USD

    +
    pnlEntries: number

    Total invested capital in USD

    +
    pnlPercentage: number

    Profit/loss as percentage (e.g., 1.5 for +1.5%, -2.3 for -2.3%)

    +
    pnlPriceClose: number

    Exit price from PNL calculation (adjusted with slippage and fees)

    +
    pnlPriceOpen: number

    Entry price from PNL calculation (effective price adjusted with slippage and fees)

    +
    signalId: string

    Unique signal identifier (UUID v4)

    +
    strategyName: string

    Strategy name that generated this signal

    +
    symbol: string

    Trading pair symbol (e.g., "BTCUSDT")

    +
    timestamp: number

    Unix timestamp in milliseconds when close was committed

    +
    totalEntries: number

    Total number of DCA entries (_entry.length). 1 = no averaging.

    +
    totalPartials: number

    Total number of partial closes executed (_partial.length). 0 = no partial closes done.

    +
    type: "close_pending.commit"

    Discriminator for type-safe union

    +

    Interface CriticalErrorNotification

    Critical error notification. Emitted for fatal errors requiring process termination.

    -
    interface CriticalErrorNotification {
        backtest: boolean;
        error: object;
        id: string;
        message: string;
        type: "error.critical";
    }

    Properties

    interface CriticalErrorNotification {
        backtest: boolean;
        error: object;
        id: string;
        message: string;
        type: "error.critical";
    }

    Properties

    backtest: boolean

    Always false for error notifications (errors are from live context)

    -
    error: object

    Serialized error object with stack trace and metadata

    -
    id: string

    Unique notification identifier

    -
    message: string

    Human-readable error message

    -
    type: "error.critical"

    Discriminator for type-safe union

    -
    +
    error: object

    Serialized error object with stack trace and metadata

    +
    id: string

    Unique notification identifier

    +
    message: string

    Human-readable error message

    +
    type: "error.critical"

    Discriminator for type-safe union

    +

    Interface CronEntry

    Configuration for a registered cron entry.

    -
    interface CronEntry {
        handler: CronCallback;
        interval?: CandleInterval;
        name: string;
        symbols?: string[];
    }

    Properties

    interface CronEntry {
        handler: CronCallback;
        interval?: CandleInterval;
        name: string;
        symbols?: string[];
    }

    Properties

    handler: CronCallback

    Handler invoked on the first parallel tick to reach a new boundary.

    -
    interval?: CandleInterval

    Candle interval at whose boundaries the handler fires. +

    interval?: CandleInterval

    Candle interval at whose boundaries the handler fires. Same scale as CandleInterval used by Interval and Cache: "1m" | "5m" | "1h" | "1d" etc.

    If omitted, the entry switches to fire-once mode: the handler is invoked on the very first matching tick (no boundary check) and never again. If the handler throws, the entry is not marked as fired and will retry on the next tick.

    -
    name: string

    Unique name of the entry. Used as the dedup key on register (re-registering +

    name: string

    Unique name of the entry. Used as the dedup key on register (re-registering the same name replaces the previous entry) and as part of the singleshot coordination key.

    Must be non-empty and must not contain :: is reserved as the slot-key segment separator and would otherwise create ambiguity between global and fan-out fire-once keys.

    -
    symbols?: string[]

    Symbol whitelist that doubles as the fan-out switch.

    +
    symbols?: string[]

    Symbol whitelist that doubles as the fan-out switch.

    • Empty/undefined → global singleshot: across all parallel backtests the handler runs once per boundary. The first symbol to reach the @@ -30,7 +30,7 @@ boundary.
    • The same rule applies in fire-once mode: global → handler runs once total; fan-out → once per whitelisted symbol.

      Each symbol must not contain : (same reason as CronEntry.name).

      -
    +

    Interface HeatmapStatisticsModel

    Portfolio heatmap statistics structure. Contains aggregated data for all symbols in the portfolio.

    -
    interface HeatmapStatisticsModel {
        portfolioAnnualizedSharpeRatio: number;
        portfolioAvgConsecutiveLossPnl: number;
        portfolioAvgConsecutiveWinPnl: number;
        portfolioAvgDuration: number;
        portfolioAvgFallPnl: number;
        portfolioAvgLossDuration: number;
        portfolioAvgPeakPnl: number;
        portfolioAvgWinDuration: number;
        portfolioCalmarRatio: number;
        portfolioCertaintyRatio: number;
        portfolioExpectancy: number;
        portfolioExpectedYearlyReturns: number;
        portfolioMaxDrawdownPnl: number;
        portfolioMedianPnl: number;
        portfolioPeakProfitPnl: number;
        portfolioRecoveryFactor: number;
        portfolioSharpeRatio: number;
        portfolioSortinoRatio: number;
        portfolioStdDev: number;
        portfolioTotalPnl: number;
        portfolioTotalTrades: number;
        portfolioTradesPerYear: number;
        symbols: IHeatmapRow[];
        totalSymbols: number;
    }

    Properties

    interface HeatmapStatisticsModel {
        portfolioAnnualizedSharpeRatio: number;
        portfolioAvgConsecutiveLossPnl: number;
        portfolioAvgConsecutiveWinPnl: number;
        portfolioAvgDuration: number;
        portfolioAvgFallPnl: number;
        portfolioAvgLossDuration: number;
        portfolioAvgPeakPnl: number;
        portfolioAvgWinDuration: number;
        portfolioCalmarRatio: number;
        portfolioCertaintyRatio: number;
        portfolioExpectancy: number;
        portfolioExpectedYearlyReturns: number;
        portfolioMaxDrawdownPnl: number;
        portfolioMedianPnl: number;
        portfolioPeakProfitPnl: number;
        portfolioRecoveryFactor: number;
        portfolioSharpeRatio: number;
        portfolioSortinoRatio: number;
        portfolioStdDev: number;
        portfolioTotalPnl: number;
        portfolioTotalTrades: number;
        portfolioTradesPerYear: number;
        symbols: IHeatmapRow[];
        totalSymbols: number;
    }

    Properties

    Properties

    portfolioAnnualizedSharpeRatio: number

    Pooled Annualized Sharpe Ratio (portfolioSharpeRatio × √portfolioTradesPerYear). Higher is better.

    -
    portfolioAvgConsecutiveLossPnl: number

    Trade-count-weighted mean of per-symbol avgConsecutiveLossPnl. Null if no symbol has a loss streak.

    -
    portfolioAvgConsecutiveWinPnl: number

    Trade-count-weighted mean of per-symbol avgConsecutiveWinPnl. Null if no symbol has a win streak.

    -
    portfolioAvgDuration: number

    Pooled average trade duration in minutes across all trades of all symbols.

    -
    portfolioAvgFallPnl: number

    Trade-count-weighted average fall PNL across all symbols. Closer to 0 is better.

    -
    portfolioAvgLossDuration: number

    Pooled average duration in minutes of losing trades.

    -
    portfolioAvgPeakPnl: number

    Trade-count-weighted average peak PNL across all symbols. Higher is better.

    -
    portfolioAvgWinDuration: number

    Pooled average duration in minutes of winning trades.

    -
    portfolioCalmarRatio: number

    Pooled Calmar Ratio: pooled compound annual / equity drawdown. Capped at ±MAX_CALMAR_RATIO.

    -
    portfolioCertaintyRatio: number

    Pooled Certainty Ratio (pooledAvgWin / |pooledAvgLoss|). Higher is better.

    -
    portfolioExpectancy: number

    Pooled Expectancy: winProbavgWin + lossProbavgLoss (per-trade expected %).

    -
    portfolioExpectedYearlyReturns: number

    Pooled expected yearly returns (geometric annualization of pooled equity, capped at ±MAX_EXPECTED_YEARLY_RETURNS).

    -
    portfolioMaxDrawdownPnl: number

    Minimum fall PNL across all trades of all symbols (worst worst-case). Closer to 0 is better.

    -
    portfolioMedianPnl: number

    Pooled median pnlPercentage across all trades of all symbols.

    -
    portfolioPeakProfitPnl: number

    Maximum peak PNL across all trades of all symbols (best best-case). Higher is better.

    -
    portfolioRecoveryFactor: number

    Pooled Recovery Factor: (equityFinal-1)*100 / equityMaxDrawdown. Capped at ±MAX_CALMAR_RATIO.

    -
    portfolioSharpeRatio: number

    Portfolio-wide Sharpe Ratio

    -
    portfolioSortinoRatio: number

    Pooled Sortino Ratio over all trades. Same canonical formula as per-symbol.

    -
    portfolioStdDev: number

    Pooled sample standard deviation of returns across all symbols.

    -
    portfolioTotalPnl: number

    Portfolio-wide total PNL

    -
    portfolioTotalTrades: number

    Portfolio-wide total trades

    -
    portfolioTradesPerYear: number

    Pooled observed trade frequency extrapolated to one year.

    -
    symbols: IHeatmapRow[]

    Array of symbol statistics

    -
    totalSymbols: number

    Total number of symbols tracked

    -
    +
    portfolioAvgConsecutiveLossPnl: number

    Trade-count-weighted mean of per-symbol avgConsecutiveLossPnl. Null if no symbol has a loss streak.

    +
    portfolioAvgConsecutiveWinPnl: number

    Trade-count-weighted mean of per-symbol avgConsecutiveWinPnl. Null if no symbol has a win streak.

    +
    portfolioAvgDuration: number

    Pooled average trade duration in minutes across all trades of all symbols.

    +
    portfolioAvgFallPnl: number

    Trade-count-weighted average fall PNL across all symbols. Closer to 0 is better.

    +
    portfolioAvgLossDuration: number

    Pooled average duration in minutes of losing trades.

    +
    portfolioAvgPeakPnl: number

    Trade-count-weighted average peak PNL across all symbols. Higher is better.

    +
    portfolioAvgWinDuration: number

    Pooled average duration in minutes of winning trades.

    +
    portfolioCalmarRatio: number

    Pooled Calmar Ratio: pooled compound annual / equity drawdown. Capped at ±MAX_CALMAR_RATIO.

    +
    portfolioCertaintyRatio: number

    Pooled Certainty Ratio (pooledAvgWin / |pooledAvgLoss|). Higher is better.

    +
    portfolioExpectancy: number

    Pooled Expectancy: winProbavgWin + lossProbavgLoss (per-trade expected %).

    +
    portfolioExpectedYearlyReturns: number

    Pooled expected yearly returns (geometric annualization of pooled equity, capped at ±MAX_EXPECTED_YEARLY_RETURNS).

    +
    portfolioMaxDrawdownPnl: number

    Minimum fall PNL across all trades of all symbols (worst worst-case). Closer to 0 is better.

    +
    portfolioMedianPnl: number

    Pooled median pnlPercentage across all trades of all symbols.

    +
    portfolioPeakProfitPnl: number

    Maximum peak PNL across all trades of all symbols (best best-case). Higher is better.

    +
    portfolioRecoveryFactor: number

    Pooled Recovery Factor: (equityFinal-1)*100 / equityMaxDrawdown. Capped at ±MAX_CALMAR_RATIO.

    +
    portfolioSharpeRatio: number

    Portfolio-wide Sharpe Ratio

    +
    portfolioSortinoRatio: number

    Pooled Sortino Ratio over all trades. Same canonical formula as per-symbol.

    +
    portfolioStdDev: number

    Pooled sample standard deviation of returns across all symbols.

    +
    portfolioTotalPnl: number

    Portfolio-wide total PNL

    +
    portfolioTotalTrades: number

    Portfolio-wide total trades

    +
    portfolioTradesPerYear: number

    Pooled observed trade frequency extrapolated to one year.

    +
    symbols: IHeatmapRow[]

    Array of symbol statistics

    +
    totalSymbols: number

    Total number of symbols tracked

    +

    Interface HighestProfitEvent

    Single highest profit event recorded for a position.

    -
    interface HighestProfitEvent {
        backtest: boolean;
        currentPrice: number;
        maxDrawdown: IStrategyPnL;
        peakProfit: IStrategyPnL;
        pnl: IStrategyPnL;
        position: "long" | "short";
        priceOpen: number;
        priceStopLoss: number;
        priceTakeProfit: number;
        signalId: string;
        strategyName: string;
        symbol: string;
        timestamp: number;
    }

    Properties

    interface HighestProfitEvent {
        backtest: boolean;
        currentPrice: number;
        maxDrawdown: IStrategyPnL;
        peakProfit: IStrategyPnL;
        pnl: IStrategyPnL;
        position: "long" | "short";
        priceOpen: number;
        priceStopLoss: number;
        priceTakeProfit: number;
        signalId: string;
        strategyName: string;
        symbol: string;
        timestamp: number;
    }

    Properties

    backtest: boolean

    Whether the event occurred in backtest mode

    -
    currentPrice: number

    Record price reached in the profit direction

    -
    maxDrawdown: IStrategyPnL

    Maximum drawdown experienced during the life of this position up to the moment this public signal was created

    -
    peakProfit: IStrategyPnL

    Peak profit achieved during the life of this position up to the moment this public signal was created

    -

    Total PNL of the closed position (including all entries and partials)

    -
    position: "long" | "short"

    Position direction

    -
    priceOpen: number

    Effective entry price at the time of the update

    -
    priceStopLoss: number

    Stop loss price

    -
    priceTakeProfit: number

    Take profit price

    -
    signalId: string

    Signal unique identifier

    -
    strategyName: string

    Strategy name

    -
    symbol: string

    Trading pair symbol

    -
    timestamp: number

    Unix timestamp in milliseconds when the record was set

    -
    +
    currentPrice: number

    Record price reached in the profit direction

    +
    maxDrawdown: IStrategyPnL

    Maximum drawdown experienced during the life of this position up to the moment this public signal was created

    +
    peakProfit: IStrategyPnL

    Peak profit achieved during the life of this position up to the moment this public signal was created

    +

    Total PNL of the closed position (including all entries and partials)

    +
    position: "long" | "short"

    Position direction

    +
    priceOpen: number

    Effective entry price at the time of the update

    +
    priceStopLoss: number

    Stop loss price

    +
    priceTakeProfit: number

    Take profit price

    +
    signalId: string

    Signal unique identifier

    +
    strategyName: string

    Strategy name

    +
    symbol: string

    Trading pair symbol

    +
    timestamp: number

    Unix timestamp in milliseconds when the record was set

    +

    Interface HighestProfitStatisticsModel

    Aggregated statistics model for highest profit events.

    -
    interface HighestProfitStatisticsModel {
        eventList: HighestProfitEvent[];
        totalEvents: number;
    }

    Properties

    interface HighestProfitStatisticsModel {
        eventList: HighestProfitEvent[];
        totalEvents: number;
    }

    Properties

    eventList: HighestProfitEvent[]

    Full list of recorded events (newest first)

    -
    totalEvents: number

    Total number of recorded events

    -
    +
    totalEvents: number

    Total number of recorded events

    +

    Interface IActivateScheduledCommitRow

    Queued activate scheduled commit.

    -
    interface IActivateScheduledCommitRow {
        action: "activate-scheduled";
        activateId?: string;
        backtest: boolean;
        signalId: string;
        symbol: string;
    }

    Hierarchy

    • ICommitRowBase
      • IActivateScheduledCommitRow

    Properties

    interface IActivateScheduledCommitRow {
        action: "activate-scheduled";
        activateId?: string;
        backtest: boolean;
        signalId: string;
        symbol: string;
    }

    Hierarchy

    • ICommitRowBase
      • IActivateScheduledCommitRow

    Properties

    action: "activate-scheduled"

    Discriminator

    -
    activateId?: string

    Activation ID (optional, for user-initiated activations)

    -
    backtest: boolean

    Whether running in backtest mode

    -
    signalId: string

    Signal ID being activated

    -
    symbol: string

    Trading pair symbol

    -
    +
    activateId?: string

    Activation ID (optional, for user-initiated activations)

    +
    backtest: boolean

    Whether running in backtest mode

    +
    signalId: string

    Signal ID being activated

    +
    symbol: string

    Trading pair symbol

    +

    Interface IAggregatedTradeData

    Aggregated trade data point. Represents a single trade that has occurred, used for detailed analysis and backtesting. Includes price, quantity, timestamp, and whether the buyer is the market maker (which can indicate trade direction).

    -
    interface IAggregatedTradeData {
        id: string;
        isBuyerMaker: boolean;
        price: number;
        qty: number;
        timestamp: number;
    }

    Properties

    id +
    interface IAggregatedTradeData {
        id: string;
        isBuyerMaker: boolean;
        price: number;
        qty: number;
        timestamp: number;
    }

    Properties

    id: string

    Unique identifier for the aggregated trade

    -
    isBuyerMaker: boolean

    Whether the buyer is the market maker (true if buyer is maker, false if seller is maker)

    -
    price: number

    Price at which the trade occurred

    -
    qty: number

    Quantity traded

    -
    timestamp: number

    Unix timestamp in milliseconds when the trade occurred

    -
    +
    isBuyerMaker: boolean

    Whether the buyer is the market maker (true if buyer is maker, false if seller is maker)

    +
    price: number

    Price at which the trade occurred

    +
    qty: number

    Quantity traded

    +
    timestamp: number

    Unix timestamp in milliseconds when the trade occurred

    +

    Interface IBidData

    Single bid or ask in order book.

    -
    interface IBidData {
        price: string;
        quantity: string;
    }

    Properties

    interface IBidData {
        price: string;
        quantity: string;
    }

    Properties

    Properties

    price: string

    Price level as string

    -
    quantity: string

    Quantity at this price level as string

    -
    +
    quantity: string

    Quantity at this price level as string

    +

    Interface IBreakevenCommitRow

    Queued breakeven commit.

    -
    interface IBreakevenCommitRow {
        action: "breakeven";
        backtest: boolean;
        currentPrice: number;
        symbol: string;
    }

    Hierarchy

    • ICommitRowBase
      • IBreakevenCommitRow

    Properties

    interface IBreakevenCommitRow {
        action: "breakeven";
        backtest: boolean;
        currentPrice: number;
        symbol: string;
    }

    Hierarchy

    • ICommitRowBase
      • IBreakevenCommitRow

    Properties

    action: "breakeven"

    Discriminator

    -
    backtest: boolean

    Whether running in backtest mode

    -
    currentPrice: number

    Price at which breakeven was set

    -
    symbol: string

    Trading pair symbol

    -
    +
    backtest: boolean

    Whether running in backtest mode

    +
    currentPrice: number

    Price at which breakeven was set

    +
    symbol: string

    Trading pair symbol

    +

    Interface ICandleData

    Single OHLCV candle data point. Used for VWAP calculation and backtesting.

    -
    interface ICandleData {
        close: number;
        high: number;
        low: number;
        open: number;
        timestamp: number;
        volume: number;
    }

    Properties

    interface ICandleData {
        close: number;
        high: number;
        low: number;
        open: number;
        timestamp: number;
        volume: number;
    }

    Properties

    close: number

    Closing price at candle end

    -
    high: number

    Highest price during candle period

    -
    low: number

    Lowest price during candle period

    -
    open: number

    Opening price at candle start

    -
    timestamp: number

    Unix timestamp in milliseconds when candle opened

    -
    volume: number

    Trading volume during candle period

    -
    +
    high: number

    Highest price during candle period

    +
    low: number

    Lowest price during candle period

    +
    open: number

    Opening price at candle start

    +
    timestamp: number

    Unix timestamp in milliseconds when candle opened

    +
    volume: number

    Trading volume during candle period

    +

    Interface IDumpContext

    Context required to identify a dump entry. Passed only through DumpAdapter - instances receive signalId, bucketName, and backtest via constructor.

    -
    interface IDumpContext {
        backtest: boolean;
        bucketName: string;
        description: string;
        dumpId: string;
        signalId: string;
    }

    Properties

    interface IDumpContext {
        backtest: boolean;
        bucketName: string;
        description: string;
        dumpId: string;
        signalId: string;
    }

    Properties

    backtest: boolean

    Flag indicating if the context is backtest or live; routed to Memory.writeMemory

    -
    bucketName: string

    Bucket name - groups dumps by strategy or agent name

    -
    description: string

    Human-readable label describing the dump contents; included in the BM25 index for Memory search and rendered in Markdown output

    -
    dumpId: string

    Unique identifier for this dump entry

    -
    signalId: string

    Signal identifier - scopes the dump to a specific trade

    -
    +
    bucketName: string

    Bucket name - groups dumps by strategy or agent name

    +
    description: string

    Human-readable label describing the dump contents; included in the BM25 index for Memory search and rendered in Markdown output

    +
    dumpId: string

    Unique identifier for this dump entry

    +
    signalId: string

    Signal identifier - scopes the dump to a specific trade

    +

    Interface IDumpInstance

    Interface for dump instance implementations. Instances are scoped to (signalId, bucketName) via constructor. Methods receive only the payload and dumpId.

    -
    interface IDumpInstance {
        dispose(): void;
        dumpAgentAnswer(
            messages: MessageModel<MessageRole>[],
            dumpId: string,
            description: string,
        ): Promise<void>;
        dumpError(
            content: string,
            dumpId: string,
            description: string,
        ): Promise<void>;
        dumpJson(json: object, dumpId: string, description: string): Promise<void>;
        dumpRecord(
            record: Record<string, unknown>,
            dumpId: string,
            description: string,
        ): Promise<void>;
        dumpTable(
            rows: Record<string, unknown>[],
            dumpId: string,
            description: string,
        ): Promise<void>;
        dumpText(
            content: string,
            dumpId: string,
            description: string,
        ): Promise<void>;
    }

    Methods

    interface IDumpInstance {
        dispose(): void;
        dumpAgentAnswer(
            messages: MessageModel<MessageRole>[],
            dumpId: string,
            description: string,
        ): Promise<void>;
        dumpError(
            content: string,
            dumpId: string,
            description: string,
        ): Promise<void>;
        dumpJson(json: object, dumpId: string, description: string): Promise<void>;
        dumpRecord(
            record: Record<string, unknown>,
            dumpId: string,
            description: string,
        ): Promise<void>;
        dumpTable(
            rows: Record<string, unknown>[],
            dumpId: string,
            description: string,
        ): Promise<void>;
        dumpText(
            content: string,
            dumpId: string,
            description: string,
        ): Promise<void>;
    }

    Methods

    dispose dumpAgentAnswer dumpError dumpJson @@ -9,33 +9,33 @@ Methods receive only the payload and dumpId.

    dumpTable dumpText

    Methods

    • Releases any resources held by this instance.

      -

      Returns void

    • Persist the full message history of one agent invocation.

      +

      Returns void

    • Persist the full message history of one agent invocation.

      Parameters

      • messages: MessageModel<MessageRole>[]

        Full chat history (system, user, assistant, tool)

      • dumpId: string

        Unique identifier for this dump entry

      • description: string

        Human-readable label describing the agent invocation context; included in the BM25 index for Memory search

        -

      Returns Promise<void>

    • Persist an error description.

      +

    Returns Promise<void>

    • Persist an error description.

      Parameters

      • content: string

        Error message or description to dump

      • dumpId: string

        Unique identifier for this dump entry

      • description: string

        Human-readable label describing the error context; included in the BM25 index for Memory search

        -

      Returns Promise<void>

    • Persist an arbitrary nested object as a fenced JSON block.

      +

    Returns Promise<void>

    • Persist an arbitrary nested object as a fenced JSON block.

      Parameters

      • json: object

        Arbitrary object to serialize with JSON.stringify

      • dumpId: string

        Unique identifier for this dump entry

      • description: string

        Human-readable label describing the object contents; included in the BM25 index for Memory search

      Returns Promise<void>

      Prefer dumpRecord - flat key-value structure maps naturally to markdown tables and SQL storage

      -
    • Persist a flat key-value record.

      +
    • Persist a flat key-value record.

      Parameters

      • record: Record<string, unknown>

        Arbitrary flat object to dump

      • dumpId: string

        Unique identifier for this dump entry

      • description: string

        Human-readable label describing the record contents; included in the BM25 index for Memory search

        -

      Returns Promise<void>

    • Persist an array of objects as a table. +

    Returns Promise<void>

    • Persist an array of objects as a table. Column headers are derived from the union of all keys across all rows.

      Parameters

      • rows: Record<string, unknown>[]

        Array of arbitrary objects to dump

      • dumpId: string

        Unique identifier for this dump entry

      • description: string

        Human-readable label describing the table contents; included in the BM25 index for Memory search

        -

      Returns Promise<void>

    • Persist a raw text or markdown string.

      +

    Returns Promise<void>

    • Persist a raw text or markdown string.

      Parameters

      • content: string

        Arbitrary text content to dump

      • dumpId: string

        Unique identifier for this dump entry

      • description: string

        Human-readable label describing the content; included in the BM25 index for Memory search

        -

      Returns Promise<void>

    +

    Returns Promise<void>

    Interface IExchangeSchema

    Exchange schema registered via addExchange(). Defines candle data source and formatting logic.

    -
    interface IExchangeSchema {
        callbacks?: Partial<IExchangeCallbacks>;
        exchangeName: string;
        formatPrice?: (
            symbol: string,
            price: number,
            backtest: boolean,
        ) => Promise<string>;
        formatQuantity?: (
            symbol: string,
            quantity: number,
            backtest: boolean,
        ) => Promise<string>;
        getAggregatedTrades?: (
            symbol: string,
            from: Date,
            to: Date,
            backtest: boolean,
        ) => Promise<IAggregatedTradeData[]>;
        getCandles: (
            symbol: string,
            interval: CandleInterval,
            since: Date,
            limit: number,
            backtest: boolean,
        ) => Promise<IPublicCandleData[]>;
        getOrderBook?: (
            symbol: string,
            depth: number,
            from: Date,
            to: Date,
            backtest: boolean,
        ) => Promise<IOrderBookData>;
        note?: string;
    }

    Properties

    interface IExchangeSchema {
        callbacks?: Partial<IExchangeCallbacks>;
        exchangeName: string;
        formatPrice?: (
            symbol: string,
            price: number,
            backtest: boolean,
        ) => Promise<string>;
        formatQuantity?: (
            symbol: string,
            quantity: number,
            backtest: boolean,
        ) => Promise<string>;
        getAggregatedTrades?: (
            symbol: string,
            from: Date,
            to: Date,
            backtest: boolean,
        ) => Promise<IAggregatedTradeData[]>;
        getCandles: (
            symbol: string,
            interval: CandleInterval,
            since: Date,
            limit: number,
            backtest: boolean,
        ) => Promise<IPublicCandleData[]>;
        getOrderBook?: (
            symbol: string,
            depth: number,
            from: Date,
            to: Date,
            backtest: boolean,
        ) => Promise<IOrderBookData>;
        note?: string;
    }

    Properties

    callbacks? exchangeName formatPrice? formatQuantity? @@ -9,20 +9,20 @@ Defines candle data source and formatting logic.

    getOrderBook? note?

    Properties

    callbacks?: Partial<IExchangeCallbacks>

    Optional lifecycle event callbacks (onCandleData)

    -
    exchangeName: string

    Unique exchange identifier for registration

    -
    formatPrice?: (
        symbol: string,
        price: number,
        backtest: boolean,
    ) => Promise<string>

    Format price according to exchange precision rules.

    +
    exchangeName: string

    Unique exchange identifier for registration

    +
    formatPrice?: (
        symbol: string,
        price: number,
        backtest: boolean,
    ) => Promise<string>

    Format price according to exchange precision rules.

    Optional. If not provided, defaults to Bitcoin precision on Binance (2 decimal places).

    Type declaration

      • (symbol: string, price: number, backtest: boolean): Promise<string>
      • Parameters

        • symbol: string

          Trading pair symbol

        • price: number

          Raw price value

        • backtest: boolean

          Whether running in backtest mode

        Returns Promise<string>

        Promise resolving to formatted price string

        -
    formatQuantity?: (
        symbol: string,
        quantity: number,
        backtest: boolean,
    ) => Promise<string>

    Format quantity according to exchange precision rules.

    +
    formatQuantity?: (
        symbol: string,
        quantity: number,
        backtest: boolean,
    ) => Promise<string>

    Format quantity according to exchange precision rules.

    Optional. If not provided, defaults to Bitcoin precision on Binance (8 decimal places).

    Type declaration

      • (symbol: string, quantity: number, backtest: boolean): Promise<string>
      • Parameters

        • symbol: string

          Trading pair symbol

        • quantity: number

          Raw quantity value

        • backtest: boolean

          Whether running in backtest mode

        Returns Promise<string>

        Promise resolving to formatted quantity string

        -
    getAggregatedTrades?: (
        symbol: string,
        from: Date,
        to: Date,
        backtest: boolean,
    ) => Promise<IAggregatedTradeData[]>

    Fetch aggregated trades for a trading pair. +

    getAggregatedTrades?: (
        symbol: string,
        from: Date,
        to: Date,
        backtest: boolean,
    ) => Promise<IAggregatedTradeData[]>

    Fetch aggregated trades for a trading pair. Optional. If not provided, throws an error when called.

    Type declaration

      • (
            symbol: string,
            from: Date,
            to: Date,
            backtest: boolean,
        ): Promise<IAggregatedTradeData[]>
      • Parameters

        • symbol: string

          Trading pair symbol (e.g., "BTCUSDT")

        • from: Date

          Start of time range (used in backtest for historical data, can be ignored in live)

          @@ -32,14 +32,14 @@ Optional. If not provided, throws an error when called.

    // Backtest implementation: returns historical aggregated trades for the time range
    const backtestAggregatedTrades = async (symbol: string, from: Date, to: Date, backtest: boolean) => {
    if (backtest) {
    return await database.getAggregatedTrades(symbol, from, to);
    }
    return await exchange.fetchAggregatedTrades(symbol);
    };

    // Live implementation: ignores from/to when not in backtest mode
    const liveAggregatedTrades = async (symbol: string, _from: Date, _to: Date, backtest: boolean) => {
    return await exchange.fetchAggregatedTrades(symbol);
    };
    -
    getCandles: (
        symbol: string,
        interval: CandleInterval,
        since: Date,
        limit: number,
        backtest: boolean,
    ) => Promise<IPublicCandleData[]>

    Fetch candles from data source (API or database).

    +
    getCandles: (
        symbol: string,
        interval: CandleInterval,
        since: Date,
        limit: number,
        backtest: boolean,
    ) => Promise<IPublicCandleData[]>

    Fetch candles from data source (API or database).

    Type declaration

      • (
            symbol: string,
            interval: CandleInterval,
            since: Date,
            limit: number,
            backtest: boolean,
        ): Promise<IPublicCandleData[]>
      • Parameters

        • symbol: string

          Trading pair symbol (e.g., "BTCUSDT")

        • interval: CandleInterval

          Candle time interval (e.g., "1m", "1h")

        • since: Date

          Start date for candle fetching

        • limit: number

          Maximum number of candles to fetch

        • backtest: boolean

          Whether running in backtest mode

        Returns Promise<IPublicCandleData[]>

        Promise resolving to array of OHLCV candle data

        -
    getOrderBook?: (
        symbol: string,
        depth: number,
        from: Date,
        to: Date,
        backtest: boolean,
    ) => Promise<IOrderBookData>

    Fetch order book for a trading pair.

    +
    getOrderBook?: (
        symbol: string,
        depth: number,
        from: Date,
        to: Date,
        backtest: boolean,
    ) => Promise<IOrderBookData>

    Fetch order book for a trading pair.

    Optional. If not provided, throws an error when called.

    Type declaration

      • (
            symbol: string,
            depth: number,
            from: Date,
            to: Date,
            backtest: boolean,
        ): Promise<IOrderBookData>
      • Parameters

        • symbol: string

          Trading pair symbol (e.g., "BTCUSDT")

        • depth: number

          Maximum depth levels for both bids and asks (default: CC_ORDER_BOOK_MAX_DEPTH_LEVELS)

          @@ -50,8 +50,8 @@ Optional. If not provided, throws an error when called.

    // Backtest implementation: returns historical order book for the time range
    const backtestOrderBook = async (symbol: string, depth: number, from: Date, to: Date, backtest: boolean) => {
    if (backtest) {
    return await database.getOrderBookSnapshot(symbol, depth, from, to);
    }
    return await exchange.fetchOrderBook(symbol, depth);
    };

    // Live implementation: ignores from/to when not in backtest mode
    const liveOrderBook = async (symbol: string, depth: number, _from: Date, _to: Date, backtest: boolean) => {
    return await exchange.fetchOrderBook(symbol, depth);
    };
    -
    note?: string

    Optional developer note for documentation

    -
    +
    note?: string

    Optional developer note for documentation

    +

    Interface IHeatmapRow

    Portfolio heatmap statistics for a single symbol. Aggregated metrics across all strategies for one trading pair.

    -
    interface IHeatmapRow {
        annualizedSharpeRatio: number;
        avgConsecutiveLossPnl: number;
        avgConsecutiveWinPnl: number;
        avgDuration: number;
        avgFallPnl: number;
        avgLoss: number;
        avgLossDuration: number;
        avgPeakPnl: number;
        avgPnl: number;
        avgWin: number;
        avgWinDuration: number;
        buyerPressure: number;
        buyerStrength: number;
        calmarRatio: number;
        certaintyRatio: number;
        expectancy: number;
        expectedYearlyReturns: number;
        lossCount: number;
        maxDrawdown: number;
        maxDrawdownPnl: number;
        maxLossStreak: number;
        maxWinStreak: number;
        medianPnl: number;
        medianStepSize: number;
        peakProfitPnl: number;
        pressureImbalance: number;
        profitFactor: number;
        recoveryFactor: number;
        sellerPressure: number;
        sellerStrength: number;
        sharpeRatio: number;
        sortinoRatio: number;
        stdDev: number;
        symbol: string;
        totalPnl: number;
        totalTrades: number;
        tradesPerYear: number;
        trend: "bullish" | "bearish" | "sideways" | "neutral";
        trendConfidence: number;
        trendStrength: number;
        winCount: number;
        winRate: number;
    }

    Properties

    interface IHeatmapRow {
        annualizedSharpeRatio: number;
        avgConsecutiveLossPnl: number;
        avgConsecutiveWinPnl: number;
        avgDuration: number;
        avgFallPnl: number;
        avgLoss: number;
        avgLossDuration: number;
        avgPeakPnl: number;
        avgPnl: number;
        avgWin: number;
        avgWinDuration: number;
        buyerPressure: number;
        buyerStrength: number;
        calmarRatio: number;
        certaintyRatio: number;
        expectancy: number;
        expectedYearlyReturns: number;
        lossCount: number;
        maxDrawdown: number;
        maxDrawdownPnl: number;
        maxLossStreak: number;
        maxWinStreak: number;
        medianPnl: number;
        medianStepSize: number;
        peakProfitPnl: number;
        pressureImbalance: number;
        profitFactor: number;
        recoveryFactor: number;
        sellerPressure: number;
        sellerStrength: number;
        sharpeRatio: number;
        sortinoRatio: number;
        stdDev: number;
        symbol: string;
        totalPnl: number;
        totalTrades: number;
        tradesPerYear: number;
        trend: "bullish" | "bearish" | "sideways" | "neutral";
        trendConfidence: number;
        trendStrength: number;
        winCount: number;
        winRate: number;
    }

    Properties

    annualizedSharpeRatio avgConsecutiveLossPnl avgConsecutiveWinPnl avgDuration @@ -43,48 +43,48 @@ Aggregated metrics across all strategies for one trading pair.

    winCount winRate

    Properties

    annualizedSharpeRatio: number

    Annualized Sharpe Ratio (sharpeRatio × √tradesPerYear). Higher is better.

    -
    avgConsecutiveLossPnl: number

    Average sum of pnlPercentage across consecutive losing streaks. Null if no loss streak. Closer to 0 is better.

    -
    avgConsecutiveWinPnl: number

    Average sum of pnlPercentage across consecutive winning streaks. Null if no win streak.

    -
    avgDuration: number

    Average trade duration in minutes ((closeTimestamp - pendingAt) / 60_000).

    -
    avgFallPnl: number

    Average fall PNL percentage across all trades (_fall.pnlPercentage). Closer to 0 is better.

    -
    avgLoss: number

    Average loss percentage on losing trades

    -
    avgLossDuration: number

    Average duration in minutes of losing trades.

    -
    avgPeakPnl: number

    Average peak PNL percentage across all trades (_peak.pnlPercentage). Higher is better.

    -
    avgPnl: number

    Average PNL per trade

    -
    avgWin: number

    Average profit percentage on winning trades

    -
    avgWinDuration: number

    Average duration in minutes of winning trades.

    -
    buyerPressure: number

    Fraction of up-moves among decisive close-to-close moves. 0..1. Higher = buyers more frequent.

    -
    buyerStrength: number

    Share of upward absolute movement in total close-to-close movement. 0..1.

    -
    calmarRatio: number

    Calmar Ratio (totalPnl / maxDrawdown). Higher is better.

    -
    certaintyRatio: number

    Certainty Ratio (avgWin / |avgLoss|). Higher is better.

    -
    expectancy: number

    Expectancy: (winRate * avgWin) - (lossRate * avgLoss)

    -
    expectedYearlyReturns: number

    Expected yearly returns (geometric, capped at ±MAX_EXPECTED_YEARLY_RETURNS). Higher is better.

    -
    lossCount: number

    Number of losing trades

    -
    maxDrawdown: number

    Maximum drawdown percentage (largest peak-to-trough decline)

    -
    maxDrawdownPnl: number

    Minimum fall PNL percentage observed across all trades (worst worst-case). Closer to 0 is better.

    -
    maxLossStreak: number

    Maximum consecutive losing trades

    -
    maxWinStreak: number

    Maximum consecutive winning trades

    -
    medianPnl: number

    Median pnlPercentage — robust to outliers; reveals distribution skew when paired with avgPnl.

    -
    medianStepSize: number

    Median |close[i] - close[i-1]| / close[i-1] across trade closes, in %. Robust to outliers.

    -
    peakProfitPnl: number

    Maximum peak PNL percentage observed across all trades (best best-case). Higher is better.

    -
    pressureImbalance: number

    buyerStrength - sellerStrength ∈ [-1, 1]. Positive = bullish bias on magnitude.

    -
    profitFactor: number

    Profit factor: sum of wins / sum of losses

    -
    recoveryFactor: number

    Recovery Factor (totalPnl / maxDrawdown). Higher is better.

    -
    sellerPressure: number

    Fraction of down-moves among decisive moves. 0..1. Equals 1 - buyerPressure.

    -
    sellerStrength: number

    Share of downward absolute movement in total close-to-close movement. 0..1.

    -
    sharpeRatio: number

    Risk-adjusted return per trade (Sharpe Ratio = avgPnl / stdDev)

    -
    sortinoRatio: number

    Sortino Ratio (avgPnl / downside deviation — RMS of losing trades only). Higher is better.

    -
    stdDev: number

    Standard deviation of PNL

    -
    symbol: string

    Trading pair symbol (e.g., "BTCUSDT")

    -
    totalPnl: number

    Total profit/loss percentage across all closed trades

    -
    totalTrades: number

    Total number of closed trades

    -
    tradesPerYear: number

    Observed trade frequency extrapolated to one year (signals × 365 / calendarSpanDays).

    -
    trend: "bullish" | "bearish" | "sideways" | "neutral"

    Bivariate trend classification (slope × R²).

    -
    trendConfidence: number

    R² of the log-price regression, in [0, 1].

    -
    trendStrength: number

    Log-price regression slope, in %/day.

    -
    winCount: number

    Number of winning trades

    -
    winRate: number

    Win rate percentage

    -
    +
    avgConsecutiveLossPnl: number

    Average sum of pnlPercentage across consecutive losing streaks. Null if no loss streak. Closer to 0 is better.

    +
    avgConsecutiveWinPnl: number

    Average sum of pnlPercentage across consecutive winning streaks. Null if no win streak.

    +
    avgDuration: number

    Average trade duration in minutes ((closeTimestamp - pendingAt) / 60_000).

    +
    avgFallPnl: number

    Average fall PNL percentage across all trades (_fall.pnlPercentage). Closer to 0 is better.

    +
    avgLoss: number

    Average loss percentage on losing trades

    +
    avgLossDuration: number

    Average duration in minutes of losing trades.

    +
    avgPeakPnl: number

    Average peak PNL percentage across all trades (_peak.pnlPercentage). Higher is better.

    +
    avgPnl: number

    Average PNL per trade

    +
    avgWin: number

    Average profit percentage on winning trades

    +
    avgWinDuration: number

    Average duration in minutes of winning trades.

    +
    buyerPressure: number

    Fraction of up-moves among decisive close-to-close moves. 0..1. Higher = buyers more frequent.

    +
    buyerStrength: number

    Share of upward absolute movement in total close-to-close movement. 0..1.

    +
    calmarRatio: number

    Calmar Ratio (totalPnl / maxDrawdown). Higher is better.

    +
    certaintyRatio: number

    Certainty Ratio (avgWin / |avgLoss|). Higher is better.

    +
    expectancy: number

    Expectancy: (winRate * avgWin) - (lossRate * avgLoss)

    +
    expectedYearlyReturns: number

    Expected yearly returns (geometric, capped at ±MAX_EXPECTED_YEARLY_RETURNS). Higher is better.

    +
    lossCount: number

    Number of losing trades

    +
    maxDrawdown: number

    Maximum drawdown percentage (largest peak-to-trough decline)

    +
    maxDrawdownPnl: number

    Minimum fall PNL percentage observed across all trades (worst worst-case). Closer to 0 is better.

    +
    maxLossStreak: number

    Maximum consecutive losing trades

    +
    maxWinStreak: number

    Maximum consecutive winning trades

    +
    medianPnl: number

    Median pnlPercentage — robust to outliers; reveals distribution skew when paired with avgPnl.

    +
    medianStepSize: number

    Median |close[i] - close[i-1]| / close[i-1] across trade closes, in %. Robust to outliers.

    +
    peakProfitPnl: number

    Maximum peak PNL percentage observed across all trades (best best-case). Higher is better.

    +
    pressureImbalance: number

    buyerStrength - sellerStrength ∈ [-1, 1]. Positive = bullish bias on magnitude.

    +
    profitFactor: number

    Profit factor: sum of wins / sum of losses

    +
    recoveryFactor: number

    Recovery Factor (totalPnl / maxDrawdown). Higher is better.

    +
    sellerPressure: number

    Fraction of down-moves among decisive moves. 0..1. Equals 1 - buyerPressure.

    +
    sellerStrength: number

    Share of downward absolute movement in total close-to-close movement. 0..1.

    +
    sharpeRatio: number

    Risk-adjusted return per trade (Sharpe Ratio = avgPnl / stdDev)

    +
    sortinoRatio: number

    Sortino Ratio (avgPnl / downside deviation — RMS of losing trades only). Higher is better.

    +
    stdDev: number

    Standard deviation of PNL

    +
    symbol: string

    Trading pair symbol (e.g., "BTCUSDT")

    +
    totalPnl: number

    Total profit/loss percentage across all closed trades

    +
    totalTrades: number

    Total number of closed trades

    +
    tradesPerYear: number

    Observed trade frequency extrapolated to one year (signals × 365 / calendarSpanDays).

    +
    trend: "bullish" | "bearish" | "sideways" | "neutral"

    Bivariate trend classification (slope × R²).

    +
    trendConfidence: number

    R² of the log-price regression, in [0, 1].

    +
    trendStrength: number

    Log-price regression slope, in %/day.

    +
    winCount: number

    Number of winning trades

    +
    winRate: number

    Win rate percentage

    +

    Interface ILog

    Extended logger interface with log history access.

    -
    interface ILog {
        debug(topic: string, ...args: any[]): void;
        getList(): Promise<ILogEntry[]>;
        info(topic: string, ...args: any[]): void;
        log(topic: string, ...args: any[]): void;
        warn(topic: string, ...args: any[]): void;
    }

    Hierarchy (View Summary)

    Methods

    interface ILog {
        debug(topic: string, ...args: any[]): void;
        getList(): Promise<ILogEntry[]>;
        info(topic: string, ...args: any[]): void;
        log(topic: string, ...args: any[]): void;
        warn(topic: string, ...args: any[]): void;
    }

    Hierarchy (View Summary)

    Methods

    • Logs a debug-level message. Employed for detailed diagnostic information, such as intermediate states during agent tool calls, swarm navigation changes, or embedding creation processes, typically enabled in development or troubleshooting scenarios.

      -

      Parameters

      • topic: string
      • ...args: any[]

      Returns void

    • Logs an info-level message. +

    • Logs an info-level message. Used to record informational updates, such as successful completions, policy validations, or history commits, providing a high-level overview of system activity without excessive detail.

      -

      Parameters

      • topic: string
      • ...args: any[]

      Returns void

    • Logs a general-purpose message. +

      Parameters

      • topic: string
      • ...args: any[]

      Returns void

    • Logs a general-purpose message. Used throughout the swarm system to record significant events or state changes, such as agent execution, session connections, or storage updates.

      -

      Parameters

      • topic: string
      • ...args: any[]

      Returns void

    • Logs a warning-level message. +

      Parameters

      • topic: string
      • ...args: any[]

      Returns void

    • Logs a warning-level message. Used to record potentially problematic situations that don't prevent execution but may require attention, such as missing data, unexpected conditions, or deprecated usage.

      -

      Parameters

      • topic: string
      • ...args: any[]

      Returns void

    +

    Parameters

    • topic: string
    • ...args: any[]

    Returns void

    Interface ILogEntry

    Single log entry stored in the log history.

    -
    interface ILogEntry {
        args: unknown[];
        createdAt: string;
        executionContext: IExecutionContext;
        id: string;
        methodContext: IMethodContext;
        priority: number;
        timestamp: number;
        topic: string;
        type: "log" | "debug" | "info" | "warn";
    }

    Properties

    interface ILogEntry {
        args: unknown[];
        createdAt: string;
        executionContext: IExecutionContext;
        id: string;
        methodContext: IMethodContext;
        priority: number;
        timestamp: number;
        topic: string;
        type: "log" | "debug" | "info" | "warn";
    }

    Properties

    Properties

    args: unknown[]

    Additional arguments passed to the log call

    -
    createdAt: string

    Date taken from backtest context to improve user experience

    -
    executionContext: IExecutionContext

    Optional execution context associated with the log entry, providing additional details about the execution environment or state when the log was recorded

    -
    id: string

    Unique entry identifier generated via randomString

    -
    methodContext: IMethodContext

    Optional method context associated with the log entry, providing additional details about the execution environment or state when the log was recorded

    -
    priority: number

    Current Unix timestamp in milliseconds for storage rotate

    -
    timestamp: number

    Unix timestamp in milliseconds taken from backtest context to improve user experience

    -
    topic: string

    Log topic / method name

    -
    type: "log" | "debug" | "info" | "warn"

    Log level

    -
    +
    createdAt: string

    Date taken from backtest context to improve user experience

    +
    executionContext: IExecutionContext

    Optional execution context associated with the log entry, providing additional details about the execution environment or state when the log was recorded

    +
    id: string

    Unique entry identifier generated via randomString

    +
    methodContext: IMethodContext

    Optional method context associated with the log entry, providing additional details about the execution environment or state when the log was recorded

    +
    priority: number

    Current Unix timestamp in milliseconds for storage rotate

    +
    timestamp: number

    Unix timestamp in milliseconds taken from backtest context to improve user experience

    +
    topic: string

    Log topic / method name

    +
    type: "log" | "debug" | "info" | "warn"

    Log level

    +

    Interface ILogger

    Interface representing a logging mechanism for the swarm system. Provides methods to record messages at different severity levels, used across components like agents, sessions, states, storage, swarms, history, embeddings, completions, and policies. Logs are utilized to track lifecycle events (e.g., initialization, disposal), operational details (e.g., tool calls, message emissions), validation outcomes (e.g., policy checks), and errors (e.g., persistence failures), aiding in debugging, monitoring, and auditing.

    -
    interface ILogger {
        debug(topic: string, ...args: any[]): void;
        info(topic: string, ...args: any[]): void;
        log(topic: string, ...args: any[]): void;
        warn(topic: string, ...args: any[]): void;
    }

    Hierarchy (View Summary)

    Methods

    interface ILogger {
        debug(topic: string, ...args: any[]): void;
        info(topic: string, ...args: any[]): void;
        log(topic: string, ...args: any[]): void;
        warn(topic: string, ...args: any[]): void;
    }

    Hierarchy (View Summary)

    Methods

    Methods

    • Logs a debug-level message. Employed for detailed diagnostic information, such as intermediate states during agent tool calls, swarm navigation changes, or embedding creation processes, typically enabled in development or troubleshooting scenarios.

      -

      Parameters

      • topic: string
      • ...args: any[]

      Returns void

    • Logs an info-level message. +

      Parameters

      • topic: string
      • ...args: any[]

      Returns void

    • Logs an info-level message. Used to record informational updates, such as successful completions, policy validations, or history commits, providing a high-level overview of system activity without excessive detail.

      -

      Parameters

      • topic: string
      • ...args: any[]

      Returns void

    • Logs a general-purpose message. +

      Parameters

      • topic: string
      • ...args: any[]

      Returns void

    • Logs a general-purpose message. Used throughout the swarm system to record significant events or state changes, such as agent execution, session connections, or storage updates.

      -

      Parameters

      • topic: string
      • ...args: any[]

      Returns void

    • Logs a warning-level message. +

      Parameters

      • topic: string
      • ...args: any[]

      Returns void

    • Logs a warning-level message. Used to record potentially problematic situations that don't prevent execution but may require attention, such as missing data, unexpected conditions, or deprecated usage.

      -

      Parameters

      • topic: string
      • ...args: any[]

      Returns void

    +

    Parameters

    • topic: string
    • ...args: any[]

    Returns void

    Interface IMarkdownDumpOptions

    Options for markdown dump operations. Contains path information and metadata for filtering.

    -
    interface IMarkdownDumpOptions {
        exchangeName: string;
        file: string;
        frameName: string;
        path: string;
        signalId: string;
        strategyName: string;
        symbol: string;
    }

    Properties

    interface IMarkdownDumpOptions {
        exchangeName: string;
        file: string;
        frameName: string;
        path: string;
        signalId: string;
        strategyName: string;
        symbol: string;
    }

    Properties

    exchangeName file frameName path @@ -8,13 +8,13 @@ Contains path information and metadata for filtering.

    strategyName symbol

    Properties

    exchangeName: string

    Exchange name

    -
    file: string

    File name including extension

    -
    frameName: string

    Frame name (timeframe identifier)

    -
    path: string

    Directory path relative to process.cwd()

    -
    signalId: string

    Signal unique identifier

    -
    strategyName: string

    Strategy name

    -
    symbol: string

    Trading pair symbol (e.g., "BTCUSDT")

    -
    +
    file: string

    File name including extension

    +
    frameName: string

    Frame name (timeframe identifier)

    +
    path: string

    Directory path relative to process.cwd()

    +
    signalId: string

    Signal unique identifier

    +
    strategyName: string

    Strategy name

    +
    symbol: string

    Trading pair symbol (e.g., "BTCUSDT")

    +

    Interface IMemoryInstance

    Interface for memory instance implementations. Defines the contract for local, persist, and dummy backends.

    -
    interface IMemoryInstance {
        dispose(): void;
        listMemory<T extends object = object>(
            when: Date,
        ): Promise<{ content: T; memoryId: string }[]>;
        readMemory<T extends object = object>(
            memoryId: string,
            when: Date,
        ): Promise<T>;
        removeMemory(memoryId: string, when: Date): Promise<void>;
        searchMemory<T extends object = object>(
            query: string,
            when: Date,
            settings?: SearchSettings,
        ): Promise<{ content: T; memoryId: string; score: number }[]>;
        waitForInit(initial: boolean): Promise<void>;
        writeMemory<T extends object = object>(
            memoryId: string,
            value: T,
            description: string,
            when: Date,
        ): Promise<void>;
    }

    Methods

    interface IMemoryInstance {
        dispose(): void;
        listMemory<T extends object = object>(
            when: Date,
        ): Promise<{ content: T; memoryId: string }[]>;
        readMemory<T extends object = object>(
            memoryId: string,
            when: Date,
        ): Promise<T>;
        removeMemory(memoryId: string, when: Date): Promise<void>;
        searchMemory<T extends object = object>(
            query: string,
            when: Date,
            settings?: SearchSettings,
        ): Promise<{ content: T; memoryId: string; score: number }[]>;
        waitForInit(initial: boolean): Promise<void>;
        writeMemory<T extends object = object>(
            memoryId: string,
            value: T,
            description: string,
            when: Date,
        ): Promise<void>;
    }

    Methods

    dispose listMemory readMemory removeMemory @@ -8,32 +8,32 @@ Defines the contract for local, persist, and dummy backends.

    waitForInit writeMemory

    Methods

    • Releases any resources held by this instance.

      -

      Returns void

    • List all entries in memory. +

      Returns void

    • List all entries in memory. Filters out entries whose when is greater than the requested when.

      Type Parameters

      • T extends object = object

      Parameters

      • when: Date

        Logical timestamp at which the read is happening (look-ahead guard)

      Returns Promise<{ content: T; memoryId: string }[]>

      Array of all stored entries

      -
    • Read a single entry from memory. +

    • Read a single entry from memory. Behaves as not-found if the stored when is greater than the requested when.

      Type Parameters

      • T extends object = object

      Parameters

      • memoryId: string

        Unique entry identifier

      • when: Date

        Logical timestamp at which the read is happening (look-ahead guard)

      Returns Promise<T>

      Entry value

      Error if entry not found (or shadowed by look-ahead)

      -
    • Remove an entry from memory.

      +
    • Remove an entry from memory.

      Parameters

      • memoryId: string

        Unique entry identifier

      • when: Date

        Logical timestamp (kept for API consistency; removal is by UUID)

        -

      Returns Promise<void>

    • Search memory using BM25 full-text scoring. +

    Returns Promise<void>

    • Search memory using BM25 full-text scoring. Filters out entries whose when is greater than the requested when.

      Type Parameters

      • T extends object = object

      Parameters

      • query: string

        Search query string

      • when: Date

        Logical timestamp at which the read is happening (look-ahead guard)

      • Optionalsettings: SearchSettings

      Returns Promise<{ content: T; memoryId: string; score: number }[]>

      Array of matching entries with scores

      -
    • Initialize the memory instance.

      +
    • Initialize the memory instance.

      Parameters

      • initial: boolean

        Whether this is the first initialization

        -

      Returns Promise<void>

    • Write a value to memory.

      +

    Returns Promise<void>

    • Write a value to memory.

      Type Parameters

      • T extends object = object

      Parameters

      • memoryId: string

        Unique entry identifier

      • value: T

        Value to store

      • description: string

        Optional BM25 index string; defaults to JSON.stringify(value)

      • when: Date

        Logical timestamp this entry belongs to (look-ahead guard)

        -

      Returns Promise<void>

    +

    Returns Promise<void>

    Interface INotificationUtils

    Base interface for notification adapters. All notification adapters must implement this interface.

    -
    interface INotificationUtils {
        dispose(): Promise<void>;
        getData(): Promise<NotificationModel[]>;
        handleBreakeven(data: BreakevenContract): Promise<void>;
        handleCriticalError(error: Error): Promise<void>;
        handleError(error: Error): Promise<void>;
        handlePartialLoss(data: PartialLossContract): Promise<void>;
        handlePartialProfit(data: PartialProfitContract): Promise<void>;
        handleRisk(data: RiskContract): Promise<void>;
        handleSignal(data: IStrategyTickResult): Promise<void>;
        handleSignalNotify(data: SignalInfoContract): Promise<void>;
        handleStrategyCommit(data: StrategyCommitContract): Promise<void>;
        handleSync(data: SignalSyncContract): Promise<void>;
        handleValidationError(error: Error): Promise<void>;
    }

    Methods

    interface INotificationUtils {
        dispose(): Promise<void>;
        getData(): Promise<NotificationModel[]>;
        handleBreakeven(data: BreakevenContract): Promise<void>;
        handleCriticalError(error: Error): Promise<void>;
        handleError(error: Error): Promise<void>;
        handlePartialLoss(data: PartialLossContract): Promise<void>;
        handlePartialProfit(data: PartialProfitContract): Promise<void>;
        handleRisk(data: RiskContract): Promise<void>;
        handleSignal(data: IStrategyTickResult): Promise<void>;
        handleSignalNotify(data: SignalInfoContract): Promise<void>;
        handleStrategyCommit(data: StrategyCommitContract): Promise<void>;
        handleSync(data: SignalSyncContract): Promise<void>;
        handleValidationError(error: Error): Promise<void>;
    }

    Methods

    dispose getData handleBreakeven handleCriticalError @@ -14,29 +14,29 @@ All notification adapters must implement this interface.

    handleSync handleValidationError

    Methods

    • Clears all stored notifications.

      -

      Returns Promise<void>

    • Handles critical error event.

      +

    Returns Promise<void>

    • Handles critical error event.

      Parameters

      • error: Error

        The error object

        -

      Returns Promise<void>

    • Handles error event.

      +

    Returns Promise<void>

    • Handles error event.

      Parameters

      • error: Error

        The error object

        -

      Returns Promise<void>

    • Handles partial loss availability event.

      +

    Returns Promise<void>

    • Handles partial profit availability event.

      +

    Returns Promise<void>

    • Handles risk rejection event.

      +

    Returns Promise<void>

    • Handles signal events (opened, closed, scheduled, cancelled).

      +

    Returns Promise<void>

    • Handles strategy commit events (partial-profit, breakeven, trailing, etc.).

      +

    Returns Promise<void>

    • Handles signal sync event (signal-open, signal-close).

      +

    Returns Promise<void>

    • Handles validation error event.

      +

    Returns Promise<void>

    • Handles validation error event.

      Parameters

      • error: Error

        The error object

        -

      Returns Promise<void>

    +

    Returns Promise<void>

    Interface IOrderBookData

    Order book data containing bids and asks.

    -
    interface IOrderBookData {
        asks: IBidData[];
        bids: IBidData[];
        symbol: string;
    }

    Properties

    interface IOrderBookData {
        asks: IBidData[];
        bids: IBidData[];
        symbol: string;
    }

    Properties

    Properties

    asks: IBidData[]

    Array of ask orders (sell orders)

    -
    bids: IBidData[]

    Array of bid orders (buy orders)

    -
    symbol: string

    Trading pair symbol

    -
    +
    bids: IBidData[]

    Array of bid orders (buy orders)

    +
    symbol: string

    Trading pair symbol

    +

    Interface IPartialLossCommitRow

    Queued partial loss commit.

    -
    interface IPartialLossCommitRow {
        action: "partial-loss";
        backtest: boolean;
        currentPrice: number;
        percentToClose: number;
        symbol: string;
    }

    Hierarchy

    • ICommitRowBase
      • IPartialLossCommitRow

    Properties

    interface IPartialLossCommitRow {
        action: "partial-loss";
        backtest: boolean;
        currentPrice: number;
        percentToClose: number;
        symbol: string;
    }

    Hierarchy

    • ICommitRowBase
      • IPartialLossCommitRow

    Properties

    action: "partial-loss"

    Discriminator

    -
    backtest: boolean

    Whether running in backtest mode

    -
    currentPrice: number

    Price at which partial was executed

    -
    percentToClose: number

    Percentage of position closed

    -
    symbol: string

    Trading pair symbol

    -
    +
    backtest: boolean

    Whether running in backtest mode

    +
    currentPrice: number

    Price at which partial was executed

    +
    percentToClose: number

    Percentage of position closed

    +
    symbol: string

    Trading pair symbol

    +

    Interface IPartialProfitCommitRow

    Queued partial profit commit.

    -
    interface IPartialProfitCommitRow {
        action: "partial-profit";
        backtest: boolean;
        currentPrice: number;
        percentToClose: number;
        symbol: string;
    }

    Hierarchy

    • ICommitRowBase
      • IPartialProfitCommitRow

    Properties

    interface IPartialProfitCommitRow {
        action: "partial-profit";
        backtest: boolean;
        currentPrice: number;
        percentToClose: number;
        symbol: string;
    }

    Hierarchy

    • ICommitRowBase
      • IPartialProfitCommitRow

    Properties

    action: "partial-profit"

    Discriminator

    -
    backtest: boolean

    Whether running in backtest mode

    -
    currentPrice: number

    Price at which partial was executed

    -
    percentToClose: number

    Percentage of position closed

    -
    symbol: string

    Trading pair symbol

    -
    +
    backtest: boolean

    Whether running in backtest mode

    +
    currentPrice: number

    Price at which partial was executed

    +
    percentToClose: number

    Percentage of position closed

    +
    symbol: string

    Trading pair symbol

    +

    Interface IPositionSizeATRParams

    Public API parameters for ATR-based sizing (without method field).

    -
    interface IPositionSizeATRParams {
        accountBalance: number;
        atr: number;
        priceOpen: number;
        symbol: string;
    }

    Hierarchy

    • ISizingCalculateParamsBase
      • IPositionSizeATRParams

    Properties

    interface IPositionSizeATRParams {
        accountBalance: number;
        atr: number;
        priceOpen: number;
        symbol: string;
    }

    Hierarchy

    • ISizingCalculateParamsBase
      • IPositionSizeATRParams

    Properties

    accountBalance: number

    Current account balance

    -
    atr: number

    Current ATR value

    -
    priceOpen: number

    Planned entry price

    -
    symbol: string

    Trading pair symbol (e.g., "BTCUSDT")

    -
    +
    atr: number

    Current ATR value

    +
    priceOpen: number

    Planned entry price

    +
    symbol: string

    Trading pair symbol (e.g., "BTCUSDT")

    +

    Interface IPositionSizeFixedPercentageParams

    Public API parameters for fixed percentage sizing (without method field).

    -
    interface IPositionSizeFixedPercentageParams {
        accountBalance: number;
        priceOpen: number;
        priceStopLoss: number;
        symbol: string;
    }

    Hierarchy

    • ISizingCalculateParamsBase
      • IPositionSizeFixedPercentageParams

    Properties

    interface IPositionSizeFixedPercentageParams {
        accountBalance: number;
        priceOpen: number;
        priceStopLoss: number;
        symbol: string;
    }

    Hierarchy

    • ISizingCalculateParamsBase
      • IPositionSizeFixedPercentageParams

    Properties

    accountBalance: number

    Current account balance

    -
    priceOpen: number

    Planned entry price

    -
    priceStopLoss: number

    Stop-loss price

    -
    symbol: string

    Trading pair symbol (e.g., "BTCUSDT")

    -
    +
    priceOpen: number

    Planned entry price

    +
    priceStopLoss: number

    Stop-loss price

    +
    symbol: string

    Trading pair symbol (e.g., "BTCUSDT")

    +

    Interface IPositionSizeKellyParams

    Public API parameters for Kelly Criterion sizing (without method field).

    -
    interface IPositionSizeKellyParams {
        accountBalance: number;
        priceOpen: number;
        symbol: string;
        winLossRatio: number;
        winRate: number;
    }

    Hierarchy

    • ISizingCalculateParamsBase
      • IPositionSizeKellyParams

    Properties

    interface IPositionSizeKellyParams {
        accountBalance: number;
        priceOpen: number;
        symbol: string;
        winLossRatio: number;
        winRate: number;
    }

    Hierarchy

    • ISizingCalculateParamsBase
      • IPositionSizeKellyParams

    Properties

    accountBalance: number

    Current account balance

    -
    priceOpen: number

    Planned entry price

    -
    symbol: string

    Trading pair symbol (e.g., "BTCUSDT")

    -
    winLossRatio: number

    Average win/loss ratio

    -
    winRate: number

    Win rate (0-1)

    -
    +
    priceOpen: number

    Planned entry price

    +
    symbol: string

    Trading pair symbol (e.g., "BTCUSDT")

    +
    winLossRatio: number

    Average win/loss ratio

    +
    winRate: number

    Win rate (0-1)

    +

    Interface IPublicCandleData

    interface IPublicCandleData {
        close: number;
        high: number;
        low: number;
        open: number;
        timestamp: number;
        volume: number;
    }

    Properties

    close +IPublicCandleData | backtest-kit

    Interface IPublicCandleData

    interface IPublicCandleData {
        close: number;
        high: number;
        low: number;
        open: number;
        timestamp: number;
        volume: number;
    }

    Properties

    close: number

    Closing price at candle end

    -
    high: number

    Highest price during candle period

    -
    low: number

    Lowest price during candle period

    -
    open: number

    Opening price at candle start

    -
    timestamp: number

    Unix timestamp in milliseconds when candle opened

    -
    volume: number

    Trading volume during candle period

    -
    +
    high: number

    Highest price during candle period

    +
    low: number

    Lowest price during candle period

    +
    open: number

    Opening price at candle start

    +
    timestamp: number

    Unix timestamp in milliseconds when candle opened

    +
    volume: number

    Trading volume during candle period

    +

    Interface IRecentUtils

    Base interface for recent signal storage adapters.

    -
    interface IRecentUtils {
        getLatestSignal(
            symbol: string,
            strategyName: string,
            exchangeName: string,
            frameName: string,
            backtest: boolean,
            when: Date,
        ): Promise<IPublicSignalRow>;
        getMinutesSinceLatestSignalCreated(
            timestamp: number,
            symbol: string,
            strategyName: string,
            exchangeName: string,
            frameName: string,
            backtest: boolean,
        ): Promise<number>;
        handleActivePing(event: ActivePingContract): Promise<void>;
    }

    Methods

    interface IRecentUtils {
        getLatestSignal(
            symbol: string,
            strategyName: string,
            exchangeName: string,
            frameName: string,
            backtest: boolean,
            when: Date,
        ): Promise<IPublicSignalRow>;
        getMinutesSinceLatestSignalCreated(
            timestamp: number,
            symbol: string,
            strategyName: string,
            exchangeName: string,
            frameName: string,
            backtest: boolean,
        ): Promise<number>;
        handleActivePing(event: ActivePingContract): Promise<void>;
    }

    Methods

    • Retrieves the latest active signal for the given context. @@ -12,7 +12,7 @@ Returns null if the stored signal's timestamp is greater than the r

    • backtest: boolean

      Flag indicating if the context is backtest or live

    • when: Date

      Logical timestamp at which the read is happening (look-ahead guard)

    Returns Promise<IPublicSignalRow>

    The latest signal or null if not found / shadowed by look-ahead

    -
    • Returns the number of minutes elapsed since the latest signal's timestamp. +

    • Returns the number of minutes elapsed since the latest signal's timestamp. timestamp doubles as the look-ahead cutoff — a signal whose timestamp exceeds the requested one is treated as not yet visible.

      Parameters

      • timestamp: number

        Current timestamp in milliseconds (also serves as look-ahead cutoff)

        @@ -22,9 +22,9 @@ exceeds the requested one is treated as not yet visible.

      • frameName: string

        Frame identifier

      • backtest: boolean

        Flag indicating if the context is backtest or live

      Returns Promise<number>

      Minutes since the latest signal, or null if no signal found / shadowed by look-ahead

      -
    +

    Returns Promise<void>

    Interface IReportDumpOptions

    Options for report data writes. Contains metadata for event filtering and search.

    -
    interface IReportDumpOptions {
        exchangeName: string;
        frameName: string;
        signalId: string;
        strategyName: string;
        symbol: string;
        walkerName: string;
    }

    Properties

    interface IReportDumpOptions {
        exchangeName: string;
        frameName: string;
        signalId: string;
        strategyName: string;
        symbol: string;
        walkerName: string;
    }

    Properties

    exchangeName: string

    Exchange name

    -
    frameName: string

    Frame name (timeframe identifier)

    -
    signalId: string

    Signal unique identifier

    -
    strategyName: string

    Strategy name

    -
    symbol: string

    Trading pair symbol (e.g., "BTCUSDT")

    -
    walkerName: string

    Walker optimization name

    -
    +
    frameName: string

    Frame name (timeframe identifier)

    +
    signalId: string

    Signal unique identifier

    +
    strategyName: string

    Strategy name

    +
    symbol: string

    Trading pair symbol (e.g., "BTCUSDT")

    +
    walkerName: string

    Walker optimization name

    +

    Interface IRiskActivePosition

    Active position tracked by ClientRisk for cross-strategy analysis.

    -
    interface IRiskActivePosition {
        exchangeName: string;
        frameName: string;
        minuteEstimatedTime: number;
        openTimestamp: number;
        position: "long" | "short";
        priceOpen: number;
        priceStopLoss: number;
        priceTakeProfit: number;
        strategyName: string;
        symbol: string;
    }

    Properties

    interface IRiskActivePosition {
        exchangeName: string;
        frameName: string;
        minuteEstimatedTime: number;
        openTimestamp: number;
        position: "long" | "short";
        priceOpen: number;
        priceStopLoss: number;
        priceTakeProfit: number;
        strategyName: string;
        symbol: string;
    }

    Properties

    exchangeName: string

    Exchange name

    -
    frameName: string

    Frame name

    -
    minuteEstimatedTime: number

    Estimated time in minutes

    -
    openTimestamp: number

    Timestamp when the position was opened

    -
    position: "long" | "short"

    Position direction ("long" or "short")

    -
    priceOpen: number

    Entry price

    -
    priceStopLoss: number

    Stop loss price

    -
    priceTakeProfit: number

    Take profit price

    -
    strategyName: string

    Strategy name owning the position

    -
    symbol: string

    Trading pair symbol (e.g., "BTCUSDT")

    -
    +
    frameName: string

    Frame name

    +
    minuteEstimatedTime: number

    Estimated time in minutes

    +
    openTimestamp: number

    Timestamp when the position was opened

    +
    position: "long" | "short"

    Position direction ("long" or "short")

    +
    priceOpen: number

    Entry price

    +
    priceStopLoss: number

    Stop loss price

    +
    priceTakeProfit: number

    Take profit price

    +
    strategyName: string

    Strategy name owning the position

    +
    symbol: string

    Trading pair symbol (e.g., "BTCUSDT")

    +

    Interface IRiskCheckArgs

    Risk check arguments for evaluating whether to allow opening a new position. Called BEFORE signal creation to validate if conditions allow new signals. Contains only passthrough arguments from ClientStrategy context.

    -
    interface IRiskCheckArgs {
        currentPrice: number;
        currentSignal: IPublicSignalRow;
        exchangeName: string;
        frameName: string;
        riskName: string;
        strategyName: string;
        symbol: string;
        timestamp: number;
    }

    Hierarchy (View Summary)

    Properties

    interface IRiskCheckArgs {
        currentPrice: number;
        currentSignal: IPublicSignalRow;
        exchangeName: string;
        frameName: string;
        riskName: string;
        strategyName: string;
        symbol: string;
        timestamp: number;
    }

    Hierarchy (View Summary)

    Properties

    currentPrice currentSignal exchangeName frameName @@ -10,14 +10,14 @@ Contains only passthrough arguments from ClientStrategy context.

    symbol timestamp

    Properties

    currentPrice: number

    Current VWAP price

    -
    currentSignal: IPublicSignalRow

    Pending signal to apply

    -
    exchangeName: string

    Exchange name

    -
    frameName: string

    Frame name

    -
    riskName: string

    Risk name

    -
    strategyName: string

    Strategy name requesting to open a position

    -
    symbol: string

    Trading pair symbol (e.g., "BTCUSDT")

    -
    timestamp: number

    Current timestamp

    -
    +
    currentSignal: IPublicSignalRow

    Pending signal to apply

    +
    exchangeName: string

    Exchange name

    +
    frameName: string

    Frame name

    +
    riskName: string

    Risk name

    +
    strategyName: string

    Strategy name requesting to open a position

    +
    symbol: string

    Trading pair symbol (e.g., "BTCUSDT")

    +
    timestamp: number

    Current timestamp

    +

    Interface IRiskSchema

    Risk schema registered via addRisk(). Defines portfolio-level risk controls via custom validations.

    -
    interface IRiskSchema {
        callbacks?: Partial<IRiskCallbacks>;
        note?: string;
        riskName: string;
        validations: (IRiskValidationFn | IRiskValidation)[];
    }

    Properties

    interface IRiskSchema {
        callbacks?: Partial<IRiskCallbacks>;
        note?: string;
        riskName: string;
        validations: (IRiskValidationFn | IRiskValidation)[];
    }

    Properties

    callbacks?: Partial<IRiskCallbacks>

    Optional lifecycle event callbacks (onRejected, onAllowed)

    -
    note?: string

    Optional developer note for documentation

    -
    riskName: string

    Unique risk profile identifier

    -

    Custom validations array for risk logic

    -
    +
    note?: string

    Optional developer note for documentation

    +
    riskName: string

    Unique risk profile identifier

    +

    Custom validations array for risk logic

    +

    Interface IRiskSignalRow

    Risk signal row for internal risk management. Extends ISignalDto to include priceOpen, originalPriceStopLoss and originalPriceTakeProfit. Used in risk validation to access entry price and original SL/TP.

    -
    interface IRiskSignalRow {
        _entry?: { cost: number; price: number; timestamp: number }[];
        _fall: { price: number; timestamp: number } & IStrategyPnL;
        _isScheduled: boolean;
        _partial?: {
            costBasisAtClose: number;
            currentPrice: number;
            entryCountAtClose: number;
            percent: number;
            timestamp: number;
            type: "profit" | "loss";
        }[];
        _peak: { price: number; timestamp: number } & IStrategyPnL;
        _trailingPriceStopLoss?: number;
        _trailingPriceTakeProfit?: number;
        cost: number;
        exchangeName: string;
        frameName: string;
        id: string;
        maxDrawdown: IStrategyPnL;
        minuteEstimatedTime: number;
        note?: string;
        originalPriceOpen: number;
        originalPriceStopLoss: number;
        originalPriceTakeProfit: number;
        partialExecuted: number;
        peakProfit: IStrategyPnL;
        pendingAt: number;
        pnl: IStrategyPnL;
        position: "long" | "short";
        priceOpen: number;
        priceStopLoss: number;
        priceTakeProfit: number;
        scheduledAt: number;
        strategyName: string;
        symbol: string;
        timestamp: number;
        totalEntries: number;
        totalPartials: number;
    }

    Hierarchy (View Summary)

    Properties

    interface IRiskSignalRow {
        _entry?: { cost: number; price: number; timestamp: number }[];
        _fall: { price: number; timestamp: number } & IStrategyPnL;
        _isScheduled: boolean;
        _partial?: {
            costBasisAtClose: number;
            currentPrice: number;
            entryCountAtClose: number;
            percent: number;
            timestamp: number;
            type: "profit" | "loss";
        }[];
        _peak: { price: number; timestamp: number } & IStrategyPnL;
        _trailingPriceStopLoss?: number;
        _trailingPriceTakeProfit?: number;
        cost: number;
        exchangeName: string;
        frameName: string;
        id: string;
        maxDrawdown: IStrategyPnL;
        minuteEstimatedTime: number;
        note?: string;
        originalPriceOpen: number;
        originalPriceStopLoss: number;
        originalPriceTakeProfit: number;
        partialExecuted: number;
        peakProfit: IStrategyPnL;
        pendingAt: number;
        pnl: IStrategyPnL;
        position: "long" | "short";
        priceOpen: number;
        priceStopLoss: number;
        priceTakeProfit: number;
        scheduledAt: number;
        strategyName: string;
        symbol: string;
        timestamp: number;
        totalEntries: number;
        totalPartials: number;
    }

    Hierarchy (View Summary)

    Properties

    _entry? _fall _isScheduled _partial? @@ -40,15 +40,15 @@ Original priceOpen is preserved unchanged for identity/audit purposes.

    Type declaration

    • cost: number

      Cost of this entry in USD (e.g. 100 for $100 position)

    • price: number

      Price at which this entry was executed

    • timestamp: number

      Unix timestamp in milliseconds when this entry was executed

      -
    _fall: { price: number; timestamp: number } & IStrategyPnL

    Worst price seen in loss direction during the life of this position. +

    _fall: { price: number; timestamp: number } & IStrategyPnL

    Worst price seen in loss direction during the life of this position. Initialized at position open with priceOpen/pendingAt (pnl = 0). Updated on every tick/candle when price moves toward SL (currentDistance < 0).

    • For LONG: minimum VWAP price seen below effective entry
    • For SHORT: maximum VWAP price seen above effective entry
    -
    _isScheduled: boolean

    Internal runtime marker for scheduled signals

    -
    _partial?: {
        costBasisAtClose: number;
        currentPrice: number;
        entryCountAtClose: number;
        percent: number;
        timestamp: number;
        type: "profit" | "loss";
    }[]

    History of partial closes for PNL calculation. +

    _isScheduled: boolean

    Internal runtime marker for scheduled signals

    +
    _partial?: {
        costBasisAtClose: number;
        currentPrice: number;
        entryCountAtClose: number;
        percent: number;
        timestamp: number;
        type: "profit" | "loss";
    }[]

    History of partial closes for PNL calculation. Each entry contains type (profit/loss), percent closed, and price. Used to calculate weighted PNL: Σ(percent_i × pnl_i) for each partial + (remaining% × final_pnl)

    Computed values (derived from this array):

    @@ -67,14 +67,14 @@ Used to slice _entry to only entries that existed at this partial.

  • percent: number

    Percentage of position closed (0-100)

  • timestamp: number

    Unix timestamp in milliseconds when this partial close was executed

  • type: "profit" | "loss"

    Type of partial close: profit (moving toward TP) or loss (moving toward SL)

    -
  • _peak: { price: number; timestamp: number } & IStrategyPnL

    Best price seen in profit direction during the life of this position. +

    _peak: { price: number; timestamp: number } & IStrategyPnL

    Best price seen in profit direction during the life of this position. Initialized at position open with priceOpen/pendingAt. Updated on every tick/candle when price moves toward TP (currentDistance > 0).

    • For LONG: maximum VWAP price seen above effective entry
    • For SHORT: minimum VWAP price seen below effective entry
    -
    _trailingPriceStopLoss?: number

    Trailing stop-loss price that overrides priceStopLoss when set. +

    _trailingPriceStopLoss?: number

    Trailing stop-loss price that overrides priceStopLoss when set. Updated by trailing() method based on position type and percentage distance.

    • For LONG: moves upward as price moves toward TP (never moves down)
    • @@ -82,7 +82,7 @@ Updated by trailing() method based on position type and percentage distance.

      When _trailingPriceStopLoss is set, it replaces priceStopLoss for TP/SL checks. Original priceStopLoss is preserved in persistence but ignored during execution.
    -
    _trailingPriceTakeProfit?: number

    Trailing take-profit price that overrides priceTakeProfit when set. +

    _trailingPriceTakeProfit?: number

    Trailing take-profit price that overrides priceTakeProfit when set. Created and managed by trailingTake() method for dynamic TP adjustment. Allows moving TP further from or closer to current price based on strategy. Updated by trailingTake() method based on position type and percentage distance.

    @@ -92,41 +92,41 @@ Updated by trailingTake() method based on position type and percentage distance. When _trailingPriceTakeProfit is set, it replaces priceTakeProfit for TP/SL checks. Original priceTakeProfit is preserved in persistence but ignored during execution. -
    cost: number

    Cost of the initial position entry in USD (first entry, not DCA). +

    cost: number

    Cost of the initial position entry in USD (first entry, not DCA). Inherited from ISignalRow. Explicitly surfaced here for consumer visibility.

    -
    exchangeName: string

    Unique exchange identifier for execution

    -
    frameName: string

    Unique frame identifier for execution (empty string for live mode)

    -
    id: string

    Unique signal identifier (UUID v4 auto-generated)

    -
    maxDrawdown: IStrategyPnL

    Maximum drawdown experienced during the life of this position up to the moment this public signal was created. +

    exchangeName: string

    Unique exchange identifier for execution

    +
    frameName: string

    Unique frame identifier for execution (empty string for live mode)

    +
    id: string

    Unique signal identifier (UUID v4 auto-generated)

    +
    maxDrawdown: IStrategyPnL

    Maximum drawdown experienced during the life of this position up to the moment this public signal was created. Calculated using the worst unfavorable price reached (for long: min price below entry, for short: max price above entry) and the original entry price.

    -
    minuteEstimatedTime: number

    Expected duration in minutes before time_expired (required in row, defaults applied in ClientStrategy)

    -
    note?: string

    Human-readable description of signal reason

    -
    originalPriceOpen: number

    Original entry price set at signal creation (unchanged by averaging). +

    minuteEstimatedTime: number

    Expected duration in minutes before time_expired (required in row, defaults applied in ClientStrategy)

    +
    note?: string

    Human-readable description of signal reason

    +
    originalPriceOpen: number

    Original entry price set at signal creation (unchanged by averaging). Mirrors signal.priceOpen which is preserved for identity/audit purposes.

    -
    originalPriceStopLoss: number

    Original stop-loss price set at signal creation.

    -
    originalPriceTakeProfit: number

    Original take-profit price set at signal creation.

    -
    partialExecuted: number

    Total executed percentage from partial closes. +

    originalPriceStopLoss: number

    Original stop-loss price set at signal creation.

    +
    originalPriceTakeProfit: number

    Original take-profit price set at signal creation.

    +
    partialExecuted: number

    Total executed percentage from partial closes. Sum of all percent values from _partial array (both profit and loss types). Represents the total portion of the position that has been closed through partial executions. Range: 0-100. Value of 0 means no partial closes, 100 means position fully closed through partials.

    -
    peakProfit: IStrategyPnL

    Peak profit achieved during the life of this position up to the moment this public signal was created. +

    peakProfit: IStrategyPnL

    Peak profit achieved during the life of this position up to the moment this public signal was created. Calculated using the highest favorable price reached (for long: max price above entry, for short: min price below entry) and the original entry price.

    -
    pendingAt: number

    Pending timestamp in milliseconds (when position became pending/active at priceOpen)

    -

    Unrealized PNL at the time this public signal was created. +

    pendingAt: number

    Pending timestamp in milliseconds (when position became pending/active at priceOpen)

    +

    Unrealized PNL at the time this public signal was created. Calculated using toProfitLossDto with the currentPrice at the moment of emission.

    -
    position: "long" | "short"

    Trade direction: "long" (buy) or "short" (sell)

    -
    priceOpen: number

    Entry price for the position.

    -
    priceStopLoss: number

    Stop loss exit price (must be < priceOpen for long, > priceOpen for short)

    -
    priceTakeProfit: number

    Take profit target price (must be > priceOpen for long, < priceOpen for short)

    -
    scheduledAt: number

    Signal creation timestamp in milliseconds (when signal was first created/scheduled)

    -
    strategyName: string

    Unique strategy identifier for execution

    -
    symbol: string

    Trading pair symbol (e.g., "BTCUSDT")

    -
    timestamp: number

    Unix timestamp in milliseconds when this signal was created/scheduled in backtest context or when getSignal was called in live context (before validation)

    -
    totalEntries: number

    Total number of entries in the DCA _entry history (_entry.length). +

    position: "long" | "short"

    Trade direction: "long" (buy) or "short" (sell)

    +
    priceOpen: number

    Entry price for the position.

    +
    priceStopLoss: number

    Stop loss exit price (must be < priceOpen for long, > priceOpen for short)

    +
    priceTakeProfit: number

    Take profit target price (must be > priceOpen for long, < priceOpen for short)

    +
    scheduledAt: number

    Signal creation timestamp in milliseconds (when signal was first created/scheduled)

    +
    strategyName: string

    Unique strategy identifier for execution

    +
    symbol: string

    Trading pair symbol (e.g., "BTCUSDT")

    +
    timestamp: number

    Unix timestamp in milliseconds when this signal was created/scheduled in backtest context or when getSignal was called in live context (before validation)

    +
    totalEntries: number

    Total number of entries in the DCA _entry history (_entry.length). 1 = no averaging done (only initial entry). 2+ = averaged positions.

    -
    totalPartials: number

    Total number of partial closes executed (_partial.length). +

    totalPartials: number

    Total number of partial closes executed (_partial.length). 0 = no partial closes done. 1+ = partial closes executed.

    -
    +

    Interface IRiskValidation

    Risk validation configuration. Defines validation logic with optional documentation.

    -
    interface IRiskValidation {
        note?: string;
        validate: IRiskValidationFn;
    }

    Properties

    interface IRiskValidation {
        note?: string;
        validate: IRiskValidationFn;
    }

    Properties

    Properties

    note?: string

    Optional description for documentation purposes. Aids in understanding the purpose or behavior of the validation.

    -

    The validation function to apply to the risk check parameters.

    -
    +

    The validation function to apply to the risk check parameters.

    +

    Interface IRiskValidationFn

    Risk validation function type. Returns null/void if validation passes, IRiskRejectionResult if validation fails. Can also throw error which will be caught and converted to IRiskRejectionResult.

    -
    +

    Interface IRiskValidationPayload

    Payload passed to risk validation functions. Extends IRiskCheckArgs with portfolio state data.

    -
    interface IRiskValidationPayload {
        activePositionCount: number;
        activePositions: IRiskActivePosition[];
        currentPrice: number;
        currentSignal: IRiskSignalRow;
        exchangeName: string;
        frameName: string;
        riskName: string;
        strategyName: string;
        symbol: string;
        timestamp: number;
    }

    Hierarchy (View Summary)

    Properties

    interface IRiskValidationPayload {
        activePositionCount: number;
        activePositions: IRiskActivePosition[];
        currentPrice: number;
        currentSignal: IRiskSignalRow;
        exchangeName: string;
        frameName: string;
        riskName: string;
        strategyName: string;
        symbol: string;
        timestamp: number;
    }

    Hierarchy (View Summary)

    Properties

    activePositionCount activePositions currentPrice currentSignal @@ -11,16 +11,16 @@ Extends IRiskCheckArgs with portfolio state data.

    symbol timestamp

    Properties

    activePositionCount: number

    Number of currently active positions across all strategies

    -
    activePositions: IRiskActivePosition[]

    List of currently active positions across all strategies

    -
    currentPrice: number

    Current VWAP price

    -
    currentSignal: IRiskSignalRow

    Current signal being validated (IRiskSignalRow is calculated internally so priceOpen always exist)

    -
    exchangeName: string

    Exchange name

    -
    frameName: string

    Frame name

    -
    riskName: string

    Risk name

    -
    strategyName: string

    Strategy name requesting to open a position

    -
    symbol: string

    Trading pair symbol (e.g., "BTCUSDT")

    -
    timestamp: number

    Current timestamp

    -
    +
    activePositions: IRiskActivePosition[]

    List of currently active positions across all strategies

    +
    currentPrice: number

    Current VWAP price

    +
    currentSignal: IRiskSignalRow

    Current signal being validated (IRiskSignalRow is calculated internally so priceOpen always exist)

    +
    exchangeName: string

    Exchange name

    +
    frameName: string

    Frame name

    +
    riskName: string

    Risk name

    +
    strategyName: string

    Strategy name requesting to open a position

    +
    symbol: string

    Trading pair symbol (e.g., "BTCUSDT")

    +
    timestamp: number

    Current timestamp

    +

    Interface IRuntimeInfo<Data>

    Interface for runtime information returned by the RuntimeMetaService. This includes the symbol being traded, the time range of the backtest, any additional info defined by the strategy, and contextual information about the exchange, strategy, and frame being used.

    -
    interface IRuntimeInfo<Data extends RuntimeData = RuntimeData> {
        backtest: boolean;
        context: { exchangeName: string; frameName: string; strategyName: string };
        currentPrice: number;
        info: Data;
        range: IRuntimeRange;
        symbol: string;
        when: Date;
    }

    Type Parameters

    Properties

    interface IRuntimeInfo<Data extends RuntimeData = RuntimeData> {
        backtest: boolean;
        context: { exchangeName: string; frameName: string; strategyName: string };
        currentPrice: number;
        info: Data;
        range: IRuntimeRange;
        symbol: string;
        when: Date;
    }

    Type Parameters

    Properties

    backtest context currentPrice info @@ -9,13 +9,13 @@ and contextual information about the exchange, strategy, and frame being used.symbol when

    Properties

    backtest: boolean

    Whether the strategy is running in backtest mode

    -
    context: { exchangeName: string; frameName: string; strategyName: string }

    Contextual information about the current execution environment

    -
    currentPrice: number

    Current market price for the symbol at the time of execution

    -
    info: Data

    Additional runtime information defined by the strategy, can be used for custom monitoring or reporting

    -

    Time range for the backtest, null if running in live mode

    -
    symbol: string

    Trading pair symbol (e.g., "BTCUSDT")

    -
    when: Date

    Timestamp of the current candle or tick

    -
    +
    context: { exchangeName: string; frameName: string; strategyName: string }

    Contextual information about the current execution environment

    +
    currentPrice: number

    Current market price for the symbol at the time of execution

    +
    info: Data

    Additional runtime information defined by the strategy, can be used for custom monitoring or reporting

    +

    Time range for the backtest, null if running in live mode

    +
    symbol: string

    Trading pair symbol (e.g., "BTCUSDT")

    +
    when: Date

    Timestamp of the current candle or tick

    +

    Interface IRuntimeRange

    Interface for runtime information and range used in backtesting and strategy execution. The interface defines the time range for the backtest while executing a strategy in backtest mode

    -
    interface IRuntimeRange {
        from: Date;
        to: Date;
    }

    Properties

    interface IRuntimeRange {
        from: Date;
        to: Date;
    }

    Properties

    Properties

    from: Date

    Start date of the runtime range

    -
    to: Date

    End date of the runtime range

    -
    +
    to: Date

    End date of the runtime range

    +

    Interface IScheduledSignalCancelRow

    Scheduled signal row with cancellation ID. Extends IScheduledSignalRow to include optional cancelId for user-initiated cancellations.

    -
    interface IScheduledSignalCancelRow {
        _entry?: { cost: number; price: number; timestamp: number }[];
        _fall: { price: number; timestamp: number } & IStrategyPnL;
        _isScheduled: boolean;
        _partial?: {
            costBasisAtClose: number;
            currentPrice: number;
            entryCountAtClose: number;
            percent: number;
            timestamp: number;
            type: "profit" | "loss";
        }[];
        _peak: { price: number; timestamp: number } & IStrategyPnL;
        _trailingPriceStopLoss?: number;
        _trailingPriceTakeProfit?: number;
        cancelId?: string;
        cancelNote?: string;
        cost: number;
        exchangeName: string;
        frameName: string;
        id: string;
        minuteEstimatedTime: number;
        note?: string;
        pendingAt: number;
        position: "long" | "short";
        priceOpen: number;
        priceStopLoss: number;
        priceTakeProfit: number;
        scheduledAt: number;
        strategyName: string;
        symbol: string;
        timestamp: number;
    }

    Hierarchy (View Summary)

    Properties

    interface IScheduledSignalCancelRow {
        _entry?: { cost: number; price: number; timestamp: number }[];
        _fall: { price: number; timestamp: number } & IStrategyPnL;
        _isScheduled: boolean;
        _partial?: {
            costBasisAtClose: number;
            currentPrice: number;
            entryCountAtClose: number;
            percent: number;
            timestamp: number;
            type: "profit" | "loss";
        }[];
        _peak: { price: number; timestamp: number } & IStrategyPnL;
        _trailingPriceStopLoss?: number;
        _trailingPriceTakeProfit?: number;
        cancelId?: string;
        cancelNote?: string;
        cost: number;
        exchangeName: string;
        frameName: string;
        id: string;
        minuteEstimatedTime: number;
        note?: string;
        pendingAt: number;
        position: "long" | "short";
        priceOpen: number;
        priceStopLoss: number;
        priceTakeProfit: number;
        scheduledAt: number;
        strategyName: string;
        symbol: string;
        timestamp: number;
    }

    Hierarchy (View Summary)

    Properties

    _entry? _fall _isScheduled _partial? @@ -32,15 +32,15 @@ Original priceOpen is preserved unchanged for identity/audit purposes.

    Type declaration

    • cost: number

      Cost of this entry in USD (e.g. 100 for $100 position)

    • price: number

      Price at which this entry was executed

    • timestamp: number

      Unix timestamp in milliseconds when this entry was executed

      -
    _fall: { price: number; timestamp: number } & IStrategyPnL

    Worst price seen in loss direction during the life of this position. +

    _fall: { price: number; timestamp: number } & IStrategyPnL

    Worst price seen in loss direction during the life of this position. Initialized at position open with priceOpen/pendingAt (pnl = 0). Updated on every tick/candle when price moves toward SL (currentDistance < 0).

    • For LONG: minimum VWAP price seen below effective entry
    • For SHORT: maximum VWAP price seen above effective entry
    -
    _isScheduled: boolean

    Internal runtime marker for scheduled signals

    -
    _partial?: {
        costBasisAtClose: number;
        currentPrice: number;
        entryCountAtClose: number;
        percent: number;
        timestamp: number;
        type: "profit" | "loss";
    }[]

    History of partial closes for PNL calculation. +

    _isScheduled: boolean

    Internal runtime marker for scheduled signals

    +
    _partial?: {
        costBasisAtClose: number;
        currentPrice: number;
        entryCountAtClose: number;
        percent: number;
        timestamp: number;
        type: "profit" | "loss";
    }[]

    History of partial closes for PNL calculation. Each entry contains type (profit/loss), percent closed, and price. Used to calculate weighted PNL: Σ(percent_i × pnl_i) for each partial + (remaining% × final_pnl)

    Computed values (derived from this array):

    @@ -59,14 +59,14 @@ Used to slice _entry to only entries that existed at this partial.

  • percent: number

    Percentage of position closed (0-100)

  • timestamp: number

    Unix timestamp in milliseconds when this partial close was executed

  • type: "profit" | "loss"

    Type of partial close: profit (moving toward TP) or loss (moving toward SL)

    -
  • _peak: { price: number; timestamp: number } & IStrategyPnL

    Best price seen in profit direction during the life of this position. +

    _peak: { price: number; timestamp: number } & IStrategyPnL

    Best price seen in profit direction during the life of this position. Initialized at position open with priceOpen/pendingAt. Updated on every tick/candle when price moves toward TP (currentDistance > 0).

    • For LONG: maximum VWAP price seen above effective entry
    • For SHORT: minimum VWAP price seen below effective entry
    -
    _trailingPriceStopLoss?: number

    Trailing stop-loss price that overrides priceStopLoss when set. +

    _trailingPriceStopLoss?: number

    Trailing stop-loss price that overrides priceStopLoss when set. Updated by trailing() method based on position type and percentage distance.

    • For LONG: moves upward as price moves toward TP (never moves down)
    • @@ -74,7 +74,7 @@ Updated by trailing() method based on position type and percentage distance.

      When _trailingPriceStopLoss is set, it replaces priceStopLoss for TP/SL checks. Original priceStopLoss is preserved in persistence but ignored during execution.
    -
    _trailingPriceTakeProfit?: number

    Trailing take-profit price that overrides priceTakeProfit when set. +

    _trailingPriceTakeProfit?: number

    Trailing take-profit price that overrides priceTakeProfit when set. Created and managed by trailingTake() method for dynamic TP adjustment. Allows moving TP further from or closer to current price based on strategy. Updated by trailingTake() method based on position type and percentage distance.

    @@ -84,24 +84,24 @@ Updated by trailingTake() method based on position type and percentage distance. When _trailingPriceTakeProfit is set, it replaces priceTakeProfit for TP/SL checks. Original priceTakeProfit is preserved in persistence but ignored during execution. -
    cancelId?: string

    Cancellation ID (only for user-initiated cancellations)

    -
    cancelNote?: string

    Note from user payload (only for user-initiated cancellations)

    -
    cost: number

    Cost of this entry in USD (e.g. 100 for $100 position)

    -
    exchangeName: string

    Unique exchange identifier for execution

    -
    frameName: string

    Unique frame identifier for execution (empty string for live mode)

    -
    id: string

    Unique signal identifier (UUID v4 auto-generated)

    -
    minuteEstimatedTime: number

    Expected duration in minutes before time_expired (required in row, defaults applied in ClientStrategy)

    -
    note?: string

    Human-readable description of signal reason

    -
    pendingAt: number

    Pending timestamp in milliseconds (when position became pending/active at priceOpen)

    -
    position: "long" | "short"

    Trade direction: "long" (buy) or "short" (sell)

    -
    priceOpen: number

    Entry price for the position

    -
    priceStopLoss: number

    Stop loss exit price (must be < priceOpen for long, > priceOpen for short)

    -
    priceTakeProfit: number

    Take profit target price (must be > priceOpen for long, < priceOpen for short)

    -
    scheduledAt: number

    Signal creation timestamp in milliseconds (when signal was first created/scheduled)

    -
    strategyName: string

    Unique strategy identifier for execution

    -
    symbol: string

    Trading pair symbol (e.g., "BTCUSDT")

    -
    timestamp: number

    Unix timestamp in milliseconds when this signal was created/scheduled in backtest context or when getSignal was called in live context (before validation)

    -
    +
    cancelId?: string

    Cancellation ID (only for user-initiated cancellations)

    +
    cancelNote?: string

    Note from user payload (only for user-initiated cancellations)

    +
    cost: number

    Cost of this entry in USD (e.g. 100 for $100 position)

    +
    exchangeName: string

    Unique exchange identifier for execution

    +
    frameName: string

    Unique frame identifier for execution (empty string for live mode)

    +
    id: string

    Unique signal identifier (UUID v4 auto-generated)

    +
    minuteEstimatedTime: number

    Expected duration in minutes before time_expired (required in row, defaults applied in ClientStrategy)

    +
    note?: string

    Human-readable description of signal reason

    +
    pendingAt: number

    Pending timestamp in milliseconds (when position became pending/active at priceOpen)

    +
    position: "long" | "short"

    Trade direction: "long" (buy) or "short" (sell)

    +
    priceOpen: number

    Entry price for the position

    +
    priceStopLoss: number

    Stop loss exit price (must be < priceOpen for long, > priceOpen for short)

    +
    priceTakeProfit: number

    Take profit target price (must be > priceOpen for long, < priceOpen for short)

    +
    scheduledAt: number

    Signal creation timestamp in milliseconds (when signal was first created/scheduled)

    +
    strategyName: string

    Unique strategy identifier for execution

    +
    symbol: string

    Trading pair symbol (e.g., "BTCUSDT")

    +
    timestamp: number

    Unix timestamp in milliseconds when this signal was created/scheduled in backtest context or when getSignal was called in live context (before validation)

    +

    Interface ISignalDto

    Signal data transfer object returned by getSignal. Will be validated and augmented with auto-generated id.

    -
    interface ISignalDto {
        cost?: number;
        id?: string;
        minuteEstimatedTime?: number;
        note?: string;
        position: "long" | "short";
        priceOpen?: number;
        priceStopLoss: number;
        priceTakeProfit: number;
        symbol?: string;
    }

    Hierarchy (View Summary)

    Properties

    interface ISignalDto {
        cost?: number;
        id?: string;
        minuteEstimatedTime?: number;
        note?: string;
        position: "long" | "short";
        priceOpen?: number;
        priceStopLoss: number;
        priceTakeProfit: number;
        symbol?: string;
    }

    Hierarchy (View Summary)

    Properties

    cost? id? minuteEstimatedTime? note? @@ -10,17 +10,17 @@ Will be validated and augmented with auto-generated id.

    priceTakeProfit symbol?

    Properties

    cost?: number

    Cost of this entry in USD. Default: GLOBAL_CONFIG.CC_POSITION_ENTRY_COST

    -
    id?: string

    Optional signal ID (auto-generated if not provided)

    -
    minuteEstimatedTime?: number

    Expected duration in minutes before time_expired. +

    id?: string

    Optional signal ID (auto-generated if not provided)

    +
    minuteEstimatedTime?: number

    Expected duration in minutes before time_expired. Use Infinity for no timeout — position stays open until TP/SL or explicit closePending(). Default: GLOBAL_CONFIG.CC_MAX_SIGNAL_LIFETIME_MINUTES

    -
    note?: string

    Human-readable description of signal reason

    -
    position: "long" | "short"

    Trade direction: "long" (buy) or "short" (sell)

    -
    priceOpen?: number

    Entry price for the position

    -
    priceStopLoss: number

    Stop loss exit price (must be < priceOpen for long, > priceOpen for short)

    -
    priceTakeProfit: number

    Take profit target price (must be > priceOpen for long, < priceOpen for short)

    -
    symbol?: string

    Symbol of a ticker on exchange

    -
    +
    note?: string

    Human-readable description of signal reason

    +
    position: "long" | "short"

    Trade direction: "long" (buy) or "short" (sell)

    +
    priceOpen?: number

    Entry price for the position

    +
    priceStopLoss: number

    Stop loss exit price (must be < priceOpen for long, > priceOpen for short)

    +
    priceTakeProfit: number

    Take profit target price (must be > priceOpen for long, < priceOpen for short)

    +
    symbol?: string

    Symbol of a ticker on exchange

    +

    Interface ISignalIntervalDto

    Signal dto for IntervalUtils.fn which allows returning multiple signals in one getSignal call. This will pause the next signal untill interval elapses

    -
    interface ISignalIntervalDto {
        cost?: number;
        id: string;
        minuteEstimatedTime?: number;
        note?: string;
        position: "long" | "short";
        priceOpen?: number;
        priceStopLoss: number;
        priceTakeProfit: number;
        symbol?: string;
    }

    Hierarchy (View Summary)

    Properties

    interface ISignalIntervalDto {
        cost?: number;
        id: string;
        minuteEstimatedTime?: number;
        note?: string;
        position: "long" | "short";
        priceOpen?: number;
        priceStopLoss: number;
        priceTakeProfit: number;
        symbol?: string;
    }

    Hierarchy (View Summary)

    Properties

    cost? id minuteEstimatedTime? note? @@ -10,17 +10,17 @@ This will pause the next signal untill interval elapses

    priceTakeProfit symbol?

    Properties

    cost?: number

    Cost of this entry in USD. Default: GLOBAL_CONFIG.CC_POSITION_ENTRY_COST

    -
    id: string

    Unique signal identifier (UUID v4 auto-generated)

    -
    minuteEstimatedTime?: number

    Expected duration in minutes before time_expired. +

    id: string

    Unique signal identifier (UUID v4 auto-generated)

    +
    minuteEstimatedTime?: number

    Expected duration in minutes before time_expired. Use Infinity for no timeout — position stays open until TP/SL or explicit closePending(). Default: GLOBAL_CONFIG.CC_MAX_SIGNAL_LIFETIME_MINUTES

    -
    note?: string

    Human-readable description of signal reason

    -
    position: "long" | "short"

    Trade direction: "long" (buy) or "short" (sell)

    -
    priceOpen?: number

    Entry price for the position

    -
    priceStopLoss: number

    Stop loss exit price (must be < priceOpen for long, > priceOpen for short)

    -
    priceTakeProfit: number

    Take profit target price (must be > priceOpen for long, < priceOpen for short)

    -
    symbol?: string

    Symbol of a ticker on exchange

    -
    +
    note?: string

    Human-readable description of signal reason

    +
    position: "long" | "short"

    Trade direction: "long" (buy) or "short" (sell)

    +
    priceOpen?: number

    Entry price for the position

    +
    priceStopLoss: number

    Stop loss exit price (must be < priceOpen for long, > priceOpen for short)

    +
    priceTakeProfit: number

    Take profit target price (must be > priceOpen for long, < priceOpen for short)

    +
    symbol?: string

    Symbol of a ticker on exchange

    +

    Interface ISignalRow

    Complete signal with auto-generated id. Used throughout the system after validation.

    -
    interface ISignalRow {
        _entry?: { cost: number; price: number; timestamp: number }[];
        _fall: { price: number; timestamp: number } & IStrategyPnL;
        _isScheduled: boolean;
        _partial?: {
            costBasisAtClose: number;
            currentPrice: number;
            entryCountAtClose: number;
            percent: number;
            timestamp: number;
            type: "profit" | "loss";
        }[];
        _peak: { price: number; timestamp: number } & IStrategyPnL;
        _trailingPriceStopLoss?: number;
        _trailingPriceTakeProfit?: number;
        cost: number;
        exchangeName: string;
        frameName: string;
        id: string;
        minuteEstimatedTime: number;
        note?: string;
        pendingAt: number;
        position: "long" | "short";
        priceOpen: number;
        priceStopLoss: number;
        priceTakeProfit: number;
        scheduledAt: number;
        strategyName: string;
        symbol: string;
        timestamp: number;
    }

    Hierarchy (View Summary)

    Properties

    interface ISignalRow {
        _entry?: { cost: number; price: number; timestamp: number }[];
        _fall: { price: number; timestamp: number } & IStrategyPnL;
        _isScheduled: boolean;
        _partial?: {
            costBasisAtClose: number;
            currentPrice: number;
            entryCountAtClose: number;
            percent: number;
            timestamp: number;
            type: "profit" | "loss";
        }[];
        _peak: { price: number; timestamp: number } & IStrategyPnL;
        _trailingPriceStopLoss?: number;
        _trailingPriceTakeProfit?: number;
        cost: number;
        exchangeName: string;
        frameName: string;
        id: string;
        minuteEstimatedTime: number;
        note?: string;
        pendingAt: number;
        position: "long" | "short";
        priceOpen: number;
        priceStopLoss: number;
        priceTakeProfit: number;
        scheduledAt: number;
        strategyName: string;
        symbol: string;
        timestamp: number;
    }

    Hierarchy (View Summary)

    Properties

    _entry? _fall _isScheduled _partial? @@ -30,15 +30,15 @@ Original priceOpen is preserved unchanged for identity/audit purposes.

    Type declaration

    • cost: number

      Cost of this entry in USD (e.g. 100 for $100 position)

    • price: number

      Price at which this entry was executed

    • timestamp: number

      Unix timestamp in milliseconds when this entry was executed

      -
    _fall: { price: number; timestamp: number } & IStrategyPnL

    Worst price seen in loss direction during the life of this position. +

    _fall: { price: number; timestamp: number } & IStrategyPnL

    Worst price seen in loss direction during the life of this position. Initialized at position open with priceOpen/pendingAt (pnl = 0). Updated on every tick/candle when price moves toward SL (currentDistance < 0).

    • For LONG: minimum VWAP price seen below effective entry
    • For SHORT: maximum VWAP price seen above effective entry
    -
    _isScheduled: boolean

    Internal runtime marker for scheduled signals

    -
    _partial?: {
        costBasisAtClose: number;
        currentPrice: number;
        entryCountAtClose: number;
        percent: number;
        timestamp: number;
        type: "profit" | "loss";
    }[]

    History of partial closes for PNL calculation. +

    _isScheduled: boolean

    Internal runtime marker for scheduled signals

    +
    _partial?: {
        costBasisAtClose: number;
        currentPrice: number;
        entryCountAtClose: number;
        percent: number;
        timestamp: number;
        type: "profit" | "loss";
    }[]

    History of partial closes for PNL calculation. Each entry contains type (profit/loss), percent closed, and price. Used to calculate weighted PNL: Σ(percent_i × pnl_i) for each partial + (remaining% × final_pnl)

    Computed values (derived from this array):

    @@ -57,14 +57,14 @@ Used to slice _entry to only entries that existed at this partial.

  • percent: number

    Percentage of position closed (0-100)

  • timestamp: number

    Unix timestamp in milliseconds when this partial close was executed

  • type: "profit" | "loss"

    Type of partial close: profit (moving toward TP) or loss (moving toward SL)

    -
  • _peak: { price: number; timestamp: number } & IStrategyPnL

    Best price seen in profit direction during the life of this position. +

    _peak: { price: number; timestamp: number } & IStrategyPnL

    Best price seen in profit direction during the life of this position. Initialized at position open with priceOpen/pendingAt. Updated on every tick/candle when price moves toward TP (currentDistance > 0).

    • For LONG: maximum VWAP price seen above effective entry
    • For SHORT: minimum VWAP price seen below effective entry
    -
    _trailingPriceStopLoss?: number

    Trailing stop-loss price that overrides priceStopLoss when set. +

    _trailingPriceStopLoss?: number

    Trailing stop-loss price that overrides priceStopLoss when set. Updated by trailing() method based on position type and percentage distance.

    • For LONG: moves upward as price moves toward TP (never moves down)
    • @@ -72,7 +72,7 @@ Updated by trailing() method based on position type and percentage distance.

      When _trailingPriceStopLoss is set, it replaces priceStopLoss for TP/SL checks. Original priceStopLoss is preserved in persistence but ignored during execution.
    -
    _trailingPriceTakeProfit?: number

    Trailing take-profit price that overrides priceTakeProfit when set. +

    _trailingPriceTakeProfit?: number

    Trailing take-profit price that overrides priceTakeProfit when set. Created and managed by trailingTake() method for dynamic TP adjustment. Allows moving TP further from or closer to current price based on strategy. Updated by trailingTake() method based on position type and percentage distance.

    @@ -82,22 +82,22 @@ Updated by trailingTake() method based on position type and percentage distance. When _trailingPriceTakeProfit is set, it replaces priceTakeProfit for TP/SL checks. Original priceTakeProfit is preserved in persistence but ignored during execution. -
    cost: number

    Cost of this entry in USD (e.g. 100 for $100 position)

    -
    exchangeName: string

    Unique exchange identifier for execution

    -
    frameName: string

    Unique frame identifier for execution (empty string for live mode)

    -
    id: string

    Unique signal identifier (UUID v4 auto-generated)

    -
    minuteEstimatedTime: number

    Expected duration in minutes before time_expired (required in row, defaults applied in ClientStrategy)

    -
    note?: string

    Human-readable description of signal reason

    -
    pendingAt: number

    Pending timestamp in milliseconds (when position became pending/active at priceOpen)

    -
    position: "long" | "short"

    Trade direction: "long" (buy) or "short" (sell)

    -
    priceOpen: number

    Entry price for the position

    -
    priceStopLoss: number

    Stop loss exit price (must be < priceOpen for long, > priceOpen for short)

    -
    priceTakeProfit: number

    Take profit target price (must be > priceOpen for long, < priceOpen for short)

    -
    scheduledAt: number

    Signal creation timestamp in milliseconds (when signal was first created/scheduled)

    -
    strategyName: string

    Unique strategy identifier for execution

    -
    symbol: string

    Trading pair symbol (e.g., "BTCUSDT")

    -
    timestamp: number

    Unix timestamp in milliseconds when this signal was created/scheduled in backtest context or when getSignal was called in live context (before validation)

    -
    +
    cost: number

    Cost of this entry in USD (e.g. 100 for $100 position)

    +
    exchangeName: string

    Unique exchange identifier for execution

    +
    frameName: string

    Unique frame identifier for execution (empty string for live mode)

    +
    id: string

    Unique signal identifier (UUID v4 auto-generated)

    +
    minuteEstimatedTime: number

    Expected duration in minutes before time_expired (required in row, defaults applied in ClientStrategy)

    +
    note?: string

    Human-readable description of signal reason

    +
    pendingAt: number

    Pending timestamp in milliseconds (when position became pending/active at priceOpen)

    +
    position: "long" | "short"

    Trade direction: "long" (buy) or "short" (sell)

    +
    priceOpen: number

    Entry price for the position

    +
    priceStopLoss: number

    Stop loss exit price (must be < priceOpen for long, > priceOpen for short)

    +
    priceTakeProfit: number

    Take profit target price (must be > priceOpen for long, < priceOpen for short)

    +
    scheduledAt: number

    Signal creation timestamp in milliseconds (when signal was first created/scheduled)

    +
    strategyName: string

    Unique strategy identifier for execution

    +
    symbol: string

    Trading pair symbol (e.g., "BTCUSDT")

    +
    timestamp: number

    Unix timestamp in milliseconds when this signal was created/scheduled in backtest context or when getSignal was called in live context (before validation)

    +

    Interface ISizingCalculateParamsATR

    Parameters for ATR-based sizing calculation.

    -
    interface ISizingCalculateParamsATR {
        accountBalance: number;
        atr: number;
        method: "atr-based";
        priceOpen: number;
        symbol: string;
    }

    Hierarchy

    • ISizingCalculateParamsBase
      • ISizingCalculateParamsATR

    Properties

    interface ISizingCalculateParamsATR {
        accountBalance: number;
        atr: number;
        method: "atr-based";
        priceOpen: number;
        symbol: string;
    }

    Hierarchy

    • ISizingCalculateParamsBase
      • ISizingCalculateParamsATR

    Properties

    accountBalance: number

    Current account balance

    -
    atr: number

    Current ATR value

    -
    method: "atr-based"
    priceOpen: number

    Planned entry price

    -
    symbol: string

    Trading pair symbol (e.g., "BTCUSDT")

    -
    +
    atr: number

    Current ATR value

    +
    method: "atr-based"
    priceOpen: number

    Planned entry price

    +
    symbol: string

    Trading pair symbol (e.g., "BTCUSDT")

    +

    Interface ISizingCalculateParamsFixedPercentage

    Parameters for fixed percentage sizing calculation.

    -
    interface ISizingCalculateParamsFixedPercentage {
        accountBalance: number;
        method: "fixed-percentage";
        priceOpen: number;
        priceStopLoss: number;
        symbol: string;
    }

    Hierarchy

    • ISizingCalculateParamsBase
      • ISizingCalculateParamsFixedPercentage

    Properties

    interface ISizingCalculateParamsFixedPercentage {
        accountBalance: number;
        method: "fixed-percentage";
        priceOpen: number;
        priceStopLoss: number;
        symbol: string;
    }

    Hierarchy

    • ISizingCalculateParamsBase
      • ISizingCalculateParamsFixedPercentage

    Properties

    accountBalance: number

    Current account balance

    -
    method: "fixed-percentage"
    priceOpen: number

    Planned entry price

    -
    priceStopLoss: number

    Stop-loss price

    -
    symbol: string

    Trading pair symbol (e.g., "BTCUSDT")

    -
    +
    method: "fixed-percentage"
    priceOpen: number

    Planned entry price

    +
    priceStopLoss: number

    Stop-loss price

    +
    symbol: string

    Trading pair symbol (e.g., "BTCUSDT")

    +

    Interface ISizingCalculateParamsKelly

    Parameters for Kelly Criterion sizing calculation.

    -
    interface ISizingCalculateParamsKelly {
        accountBalance: number;
        method: "kelly-criterion";
        priceOpen: number;
        symbol: string;
        winLossRatio: number;
        winRate: number;
    }

    Hierarchy

    • ISizingCalculateParamsBase
      • ISizingCalculateParamsKelly

    Properties

    interface ISizingCalculateParamsKelly {
        accountBalance: number;
        method: "kelly-criterion";
        priceOpen: number;
        symbol: string;
        winLossRatio: number;
        winRate: number;
    }

    Hierarchy

    • ISizingCalculateParamsBase
      • ISizingCalculateParamsKelly

    Properties

    accountBalance: number

    Current account balance

    -
    method: "kelly-criterion"
    priceOpen: number

    Planned entry price

    -
    symbol: string

    Trading pair symbol (e.g., "BTCUSDT")

    -
    winLossRatio: number

    Average win/loss ratio

    -
    winRate: number

    Win rate (0-1)

    -
    +
    method: "kelly-criterion"
    priceOpen: number

    Planned entry price

    +
    symbol: string

    Trading pair symbol (e.g., "BTCUSDT")

    +
    winLossRatio: number

    Average win/loss ratio

    +
    winRate: number

    Win rate (0-1)

    +

    Interface ISizingParamsATR

    ATR-based sizing parameters for ClientSizing constructor.

    -
    interface ISizingParamsATR {
        atrMultiplier?: number;
        callbacks?: Partial<ISizingCallbacks>;
        logger: ILogger;
        maxPositionPercentage?: number;
        maxPositionSize?: number;
        method: "atr-based";
        minPositionSize?: number;
        note?: string;
        riskPercentage: number;
        sizingName: string;
    }

    Hierarchy (View Summary)

    Properties

    interface ISizingParamsATR {
        atrMultiplier?: number;
        callbacks?: Partial<ISizingCallbacks>;
        logger: ILogger;
        maxPositionPercentage?: number;
        maxPositionSize?: number;
        method: "atr-based";
        minPositionSize?: number;
        note?: string;
        riskPercentage: number;
        sizingName: string;
    }

    Hierarchy (View Summary)

    Properties

    atrMultiplier?: number

    ATR multiplier for stop distance calculation

    -
    callbacks?: Partial<ISizingCallbacks>

    Optional lifecycle callbacks

    -
    logger: ILogger

    Logger service for debug output

    -
    maxPositionPercentage?: number

    Maximum position size as % of account (0-100)

    -
    maxPositionSize?: number

    Maximum position size (absolute value)

    -
    method: "atr-based"
    minPositionSize?: number

    Minimum position size (absolute value)

    -
    note?: string

    Optional developer note for documentation

    -
    riskPercentage: number

    Risk percentage per trade (0-100)

    -
    sizingName: string

    Unique identifier for this sizing configuration

    -
    +
    callbacks?: Partial<ISizingCallbacks>

    Optional lifecycle callbacks

    +
    logger: ILogger

    Logger service for debug output

    +
    maxPositionPercentage?: number

    Maximum position size as % of account (0-100)

    +
    maxPositionSize?: number

    Maximum position size (absolute value)

    +
    method: "atr-based"
    minPositionSize?: number

    Minimum position size (absolute value)

    +
    note?: string

    Optional developer note for documentation

    +
    riskPercentage: number

    Risk percentage per trade (0-100)

    +
    sizingName: string

    Unique identifier for this sizing configuration

    +

    Interface ISizingParamsFixedPercentage

    Fixed percentage sizing parameters for ClientSizing constructor.

    -
    interface ISizingParamsFixedPercentage {
        callbacks?: Partial<ISizingCallbacks>;
        logger: ILogger;
        maxPositionPercentage?: number;
        maxPositionSize?: number;
        method: "fixed-percentage";
        minPositionSize?: number;
        note?: string;
        riskPercentage: number;
        sizingName: string;
    }

    Hierarchy (View Summary)

    Properties

    interface ISizingParamsFixedPercentage {
        callbacks?: Partial<ISizingCallbacks>;
        logger: ILogger;
        maxPositionPercentage?: number;
        maxPositionSize?: number;
        method: "fixed-percentage";
        minPositionSize?: number;
        note?: string;
        riskPercentage: number;
        sizingName: string;
    }

    Hierarchy (View Summary)

    Properties

    callbacks?: Partial<ISizingCallbacks>

    Optional lifecycle callbacks

    -
    logger: ILogger

    Logger service for debug output

    -
    maxPositionPercentage?: number

    Maximum position size as % of account (0-100)

    -
    maxPositionSize?: number

    Maximum position size (absolute value)

    -
    method: "fixed-percentage"
    minPositionSize?: number

    Minimum position size (absolute value)

    -
    note?: string

    Optional developer note for documentation

    -
    riskPercentage: number

    Risk percentage per trade (0-100)

    -
    sizingName: string

    Unique identifier for this sizing configuration

    -
    +
    logger: ILogger

    Logger service for debug output

    +
    maxPositionPercentage?: number

    Maximum position size as % of account (0-100)

    +
    maxPositionSize?: number

    Maximum position size (absolute value)

    +
    method: "fixed-percentage"
    minPositionSize?: number

    Minimum position size (absolute value)

    +
    note?: string

    Optional developer note for documentation

    +
    riskPercentage: number

    Risk percentage per trade (0-100)

    +
    sizingName: string

    Unique identifier for this sizing configuration

    +

    Interface ISizingParamsKelly

    Kelly Criterion sizing parameters for ClientSizing constructor.

    -
    interface ISizingParamsKelly {
        callbacks?: Partial<ISizingCallbacks>;
        kellyMultiplier?: number;
        logger: ILogger;
        maxPositionPercentage?: number;
        maxPositionSize?: number;
        method: "kelly-criterion";
        minPositionSize?: number;
        note?: string;
        sizingName: string;
    }

    Hierarchy (View Summary)

    Properties

    interface ISizingParamsKelly {
        callbacks?: Partial<ISizingCallbacks>;
        kellyMultiplier?: number;
        logger: ILogger;
        maxPositionPercentage?: number;
        maxPositionSize?: number;
        method: "kelly-criterion";
        minPositionSize?: number;
        note?: string;
        sizingName: string;
    }

    Hierarchy (View Summary)

    Properties

    callbacks?: Partial<ISizingCallbacks>

    Optional lifecycle callbacks

    -
    kellyMultiplier?: number

    Kelly Criterion multiplier (0-1, default 0.25 for quarter Kelly)

    -
    logger: ILogger

    Logger service for debug output

    -
    maxPositionPercentage?: number

    Maximum position size as % of account (0-100)

    -
    maxPositionSize?: number

    Maximum position size (absolute value)

    -
    method: "kelly-criterion"
    minPositionSize?: number

    Minimum position size (absolute value)

    -
    note?: string

    Optional developer note for documentation

    -
    sizingName: string

    Unique identifier for this sizing configuration

    -
    +
    kellyMultiplier?: number

    Kelly Criterion multiplier (0-1, default 0.25 for quarter Kelly)

    +
    logger: ILogger

    Logger service for debug output

    +
    maxPositionPercentage?: number

    Maximum position size as % of account (0-100)

    +
    maxPositionSize?: number

    Maximum position size (absolute value)

    +
    method: "kelly-criterion"
    minPositionSize?: number

    Minimum position size (absolute value)

    +
    note?: string

    Optional developer note for documentation

    +
    sizingName: string

    Unique identifier for this sizing configuration

    +

    Interface IStorageUtils

    Base interface for storage adapters. All storage adapters must implement this interface.

    -
    interface IStorageUtils {
        findById(id: string): Promise<IStorageSignalRow>;
        handleActivePing(event: ActivePingContract): Promise<void>;
        handleCancelled(tick: IStrategyTickResultCancelled): Promise<void>;
        handleClosed(tick: IStrategyTickResultClosed): Promise<void>;
        handleOpened(tick: IStrategyTickResultOpened): Promise<void>;
        handleScheduled(tick: IStrategyTickResultScheduled): Promise<void>;
        handleSchedulePing(event: SchedulePingContract): Promise<void>;
        list(): Promise<IStorageSignalRow[]>;
    }

    Methods

    interface IStorageUtils {
        findById(id: string): Promise<IStorageSignalRow>;
        handleActivePing(event: ActivePingContract): Promise<void>;
        handleCancelled(tick: IStrategyTickResultCancelled): Promise<void>;
        handleClosed(tick: IStrategyTickResultClosed): Promise<void>;
        handleOpened(tick: IStrategyTickResultOpened): Promise<void>;
        handleScheduled(tick: IStrategyTickResultScheduled): Promise<void>;
        handleSchedulePing(event: SchedulePingContract): Promise<void>;
        list(): Promise<IStorageSignalRow[]>;
    }

    Methods

    findById handleActivePing handleCancelled handleClosed @@ -11,23 +11,23 @@ All storage adapters must implement this interface.

    Methods

    • Handles active ping event for opened signals. Updates updatedAt for the signal if it is currently opened.

      Parameters

      Returns Promise<void>

    Returns Promise<void>

    Returns Promise<void>

    Returns Promise<void>

    Returns Promise<void>

    • Handles schedule ping event for scheduled signals. +

    Returns Promise<void>

    • Handles schedule ping event for scheduled signals. Updates updatedAt for the signal if it is currently scheduled.

      Parameters

      Returns Promise<void>

    Returns Promise<void>

    +

    Interface IStrategyPnL

    Profit and loss calculation result. Includes adjusted prices with fees (0.1%) and slippage (0.1%).

    -
    interface IStrategyPnL {
        pnlCost: number;
        pnlEntries: number;
        pnlPercentage: number;
        priceClose: number;
        priceOpen: number;
    }

    Properties

    interface IStrategyPnL {
        pnlCost: number;
        pnlEntries: number;
        pnlPercentage: number;
        priceClose: number;
        priceOpen: number;
    }

    Properties

    pnlCost: number

    Absolute profit/loss in USD: pnlPercentage / 100 * pnlEntries

    -
    pnlEntries: number

    Total invested capital in USD: sum of all entry costs

    -
    pnlPercentage: number

    Profit/loss as percentage (e.g., 1.5 for +1.5%, -2.3 for -2.3%)

    -
    priceClose: number

    Exit price adjusted with slippage and fees

    -
    priceOpen: number

    Entry price adjusted with slippage and fees

    -
    +
    pnlEntries: number

    Total invested capital in USD: sum of all entry costs

    +
    pnlPercentage: number

    Profit/loss as percentage (e.g., 1.5 for +1.5%, -2.3 for -2.3%)

    +
    priceClose: number

    Exit price adjusted with slippage and fees

    +
    priceOpen: number

    Entry price adjusted with slippage and fees

    +

    Interface IStrategyResult

    Strategy result entry for comparison table. Contains strategy name, full statistics, and metric value for ranking.

    -
    interface IStrategyResult {
        firstEventTime: number;
        lastEventTime: number;
        metricValue: number;
        stats: BacktestStatisticsModel;
        strategyName: string;
    }

    Properties

    interface IStrategyResult {
        firstEventTime: number;
        lastEventTime: number;
        metricValue: number;
        stats: BacktestStatisticsModel;
        strategyName: string;
    }

    Properties

    firstEventTime: number

    Timestamp of the first signal event (pendingAt of earliest signal), null if no signals

    -
    lastEventTime: number

    Timestamp of the last signal event (closeTimestamp of latest signal), null if no signals

    -
    metricValue: number

    Value of the optimization metric (null if invalid)

    -

    Complete backtest statistics for this strategy

    -
    strategyName: string

    Strategy name

    -
    +
    lastEventTime: number

    Timestamp of the last signal event (closeTimestamp of latest signal), null if no signals

    +
    metricValue: number

    Value of the optimization metric (null if invalid)

    +

    Complete backtest statistics for this strategy

    +
    strategyName: string

    Strategy name

    +

    Interface IStrategySchema

    Strategy schema registered via addStrategy(). Defines signal generation logic and configuration.

    -
    interface IStrategySchema {
        actions?: string[];
        callbacks?: Partial<IStrategyCallbacks>;
        getSignal?: (
            symbol: string,
            when: Date,
            currentPrice: number,
        ) => Promise<ISignalDto>;
        info?: RuntimeData;
        interval?: SignalInterval;
        note?: string;
        riskList?: string[];
        riskName?: string;
        strategyName: string;
    }

    Properties

    interface IStrategySchema {
        actions?: string[];
        callbacks?: Partial<IStrategyCallbacks>;
        getSignal?: (
            symbol: string,
            when: Date,
            currentPrice: number,
        ) => Promise<ISignalDto>;
        info?: RuntimeData;
        interval?: SignalInterval;
        note?: string;
        riskList?: string[];
        riskName?: string;
        strategyName: string;
    }

    Properties

    actions? callbacks? getSignal? info? @@ -10,18 +10,18 @@ Defines signal generation logic and configuration.

    riskName? strategyName

    Properties

    actions?: string[]

    Optional list of action identifiers to attach to this strategy

    -
    callbacks?: Partial<IStrategyCallbacks>

    Optional lifecycle event callbacks (onOpen, onClose)

    -
    getSignal?: (
        symbol: string,
        when: Date,
        currentPrice: number,
    ) => Promise<ISignalDto>

    Signal generation function (returns null if no signal, validated DTO if signal). +

    callbacks?: Partial<IStrategyCallbacks>

    Optional lifecycle event callbacks (onOpen, onClose)

    +
    getSignal?: (
        symbol: string,
        when: Date,
        currentPrice: number,
    ) => Promise<ISignalDto>

    Signal generation function (returns null if no signal, validated DTO if signal). If priceOpen is provided - becomes scheduled signal waiting for price to reach entry point. If priceOpen is omitted - opens immediately at current price.

    -

    Optional runtime for custom monitoring, reporting or external logic

    -
    interval?: SignalInterval

    Minimum interval between getSignal calls (throttling)

    +

    Optional runtime for custom monitoring, reporting or external logic

    +
    interval?: SignalInterval

    Minimum interval between getSignal calls (throttling)

    Default: 1m

    -
    note?: string

    Optional developer note for documentation

    -
    riskList?: string[]

    Optional several risk profile list for risk management (if multiple required)

    -
    riskName?: string

    Optional risk profile identifier for risk management

    -
    strategyName: string

    Unique strategy identifier for registration

    -
    +
    note?: string

    Optional developer note for documentation

    +
    riskList?: string[]

    Optional several risk profile list for risk management (if multiple required)

    +
    riskName?: string

    Optional risk profile identifier for risk management

    +
    strategyName: string

    Unique strategy identifier for registration

    +

    Interface IStrategyTickResultActive

    Tick result: signal is being monitored. Waiting for TP/SL or time expiration.

    -
    interface IStrategyTickResultActive {
        _backtestLastTimestamp: number;
        action: "active";
        backtest: boolean;
        createdAt: number;
        currentPrice: number;
        exchangeName: string;
        frameName: string;
        percentSl: number;
        percentTp: number;
        pnl: IStrategyPnL;
        signal: IPublicSignalRow;
        strategyName: string;
        symbol: string;
    }

    Properties

    interface IStrategyTickResultActive {
        _backtestLastTimestamp: number;
        action: "active";
        backtest: boolean;
        createdAt: number;
        currentPrice: number;
        exchangeName: string;
        frameName: string;
        percentSl: number;
        percentTp: number;
        pnl: IStrategyPnL;
        signal: IPublicSignalRow;
        strategyName: string;
        symbol: string;
    }

    Properties

    _backtestLastTimestamp action backtest createdAt @@ -14,19 +14,19 @@ Waiting for TP/SL or time expiration.

    strategyName symbol

    Properties

    _backtestLastTimestamp: number

    Unix timestamp in milliseconds of the last processed candle. Used by BacktestLogicPrivateService to advance chunkStart for the next chunk request.

    -
    action: "active"

    Discriminator for type-safe union

    -
    backtest: boolean

    Whether this event is from backtest mode (true) or live mode (false)

    -
    createdAt: number

    Unix timestamp in milliseconds when this tick result was created (from candle timestamp in backtest or execution context when in live)

    -
    currentPrice: number

    Current VWAP price for monitoring

    -
    exchangeName: string

    Exchange name for tracking

    -
    frameName: string

    Time frame name for tracking (e.g., "1m", "5m")

    -
    percentSl: number

    Percentage progress towards stop loss (0-100%, 0 if moving towards TP)

    -
    percentTp: number

    Percentage progress towards take profit (0-100%, 0 if moving towards SL)

    -

    Unrealized PNL for active position with fees, slippage, and partial closes

    -

    Currently monitored signal

    -
    strategyName: string

    Strategy name for tracking

    -
    symbol: string

    Trading pair symbol (e.g., "BTCUSDT")

    -
    +
    action: "active"

    Discriminator for type-safe union

    +
    backtest: boolean

    Whether this event is from backtest mode (true) or live mode (false)

    +
    createdAt: number

    Unix timestamp in milliseconds when this tick result was created (from candle timestamp in backtest or execution context when in live)

    +
    currentPrice: number

    Current VWAP price for monitoring

    +
    exchangeName: string

    Exchange name for tracking

    +
    frameName: string

    Time frame name for tracking (e.g., "1m", "5m")

    +
    percentSl: number

    Percentage progress towards stop loss (0-100%, 0 if moving towards TP)

    +
    percentTp: number

    Percentage progress towards take profit (0-100%, 0 if moving towards SL)

    +

    Unrealized PNL for active position with fees, slippage, and partial closes

    +

    Currently monitored signal

    +
    strategyName: string

    Strategy name for tracking

    +
    symbol: string

    Trading pair symbol (e.g., "BTCUSDT")

    +

    Interface IStrategyTickResultCancelled

    Tick result: scheduled signal cancelled without opening position. Occurs when scheduled signal doesn't activate or hits stop loss before entry.

    -
    interface IStrategyTickResultCancelled {
        action: "cancelled";
        backtest: boolean;
        cancelId?: string;
        closeTimestamp: number;
        createdAt: number;
        currentPrice: number;
        exchangeName: string;
        frameName: string;
        reason: StrategyCancelReason;
        signal: IPublicSignalRow;
        strategyName: string;
        symbol: string;
    }

    Properties

    interface IStrategyTickResultCancelled {
        action: "cancelled";
        backtest: boolean;
        cancelId?: string;
        closeTimestamp: number;
        createdAt: number;
        currentPrice: number;
        exchangeName: string;
        frameName: string;
        reason: StrategyCancelReason;
        signal: IPublicSignalRow;
        strategyName: string;
        symbol: string;
    }

    Properties

    action backtest cancelId? closeTimestamp @@ -13,18 +13,18 @@ Occurs when scheduled signal doesn't activate or hits stop loss before entry.

    strategyName symbol

    Properties

    action: "cancelled"

    Discriminator for type-safe union

    -
    backtest: boolean

    Whether this event is from backtest mode (true) or live mode (false)

    -
    cancelId?: string

    Optional cancellation ID (provided when user calls Backtest.cancel() or Live.cancel())

    -
    closeTimestamp: number

    Unix timestamp in milliseconds when signal cancelled

    -
    createdAt: number

    Unix timestamp in milliseconds when this tick result was created (from candle timestamp in backtest or execution context when in live)

    -
    currentPrice: number

    Final VWAP price at cancellation

    -
    exchangeName: string

    Exchange name for tracking

    -
    frameName: string

    Time frame name for tracking (e.g., "1m", "5m")

    -

    Reason for cancellation

    -

    Cancelled scheduled signal

    -
    strategyName: string

    Strategy name for tracking

    -
    symbol: string

    Trading pair symbol (e.g., "BTCUSDT")

    -
    +
    backtest: boolean

    Whether this event is from backtest mode (true) or live mode (false)

    +
    cancelId?: string

    Optional cancellation ID (provided when user calls Backtest.cancel() or Live.cancel())

    +
    closeTimestamp: number

    Unix timestamp in milliseconds when signal cancelled

    +
    createdAt: number

    Unix timestamp in milliseconds when this tick result was created (from candle timestamp in backtest or execution context when in live)

    +
    currentPrice: number

    Final VWAP price at cancellation

    +
    exchangeName: string

    Exchange name for tracking

    +
    frameName: string

    Time frame name for tracking (e.g., "1m", "5m")

    +

    Reason for cancellation

    +

    Cancelled scheduled signal

    +
    strategyName: string

    Strategy name for tracking

    +
    symbol: string

    Trading pair symbol (e.g., "BTCUSDT")

    +

    Interface IStrategyTickResultClosed

    Tick result: signal closed with PNL. Final state with close reason and profit/loss calculation.

    -
    interface IStrategyTickResultClosed {
        action: "closed";
        backtest: boolean;
        closeId?: string;
        closeReason: StrategyCloseReason;
        closeTimestamp: number;
        createdAt: number;
        currentPrice: number;
        exchangeName: string;
        frameName: string;
        pnl: IStrategyPnL;
        signal: IPublicSignalRow;
        strategyName: string;
        symbol: string;
    }

    Properties

    interface IStrategyTickResultClosed {
        action: "closed";
        backtest: boolean;
        closeId?: string;
        closeReason: StrategyCloseReason;
        closeTimestamp: number;
        createdAt: number;
        currentPrice: number;
        exchangeName: string;
        frameName: string;
        pnl: IStrategyPnL;
        signal: IPublicSignalRow;
        strategyName: string;
        symbol: string;
    }

    Properties

    action backtest closeId? closeReason @@ -14,19 +14,19 @@ Final state with close reason and profit/loss calculation.

    strategyName symbol

    Properties

    action: "closed"

    Discriminator for type-safe union

    -
    backtest: boolean

    Whether this event is from backtest mode (true) or live mode (false)

    -
    closeId?: string

    Close ID (only for user-initiated closes with reason "closed")

    -
    closeReason: StrategyCloseReason

    Why signal closed (time_expired | take_profit | stop_loss | closed)

    -
    closeTimestamp: number

    Unix timestamp in milliseconds when signal closed

    -
    createdAt: number

    Unix timestamp in milliseconds when this tick result was created (from candle timestamp in backtest or execution context when in live)

    -
    currentPrice: number

    Final VWAP price at close

    -
    exchangeName: string

    Exchange name for tracking

    -
    frameName: string

    Time frame name for tracking (e.g., "1m", "5m")

    -

    Profit/loss calculation with fees and slippage

    -

    Completed signal with original parameters

    -
    strategyName: string

    Strategy name for tracking

    -
    symbol: string

    Trading pair symbol (e.g., "BTCUSDT")

    -
    +
    backtest: boolean

    Whether this event is from backtest mode (true) or live mode (false)

    +
    closeId?: string

    Close ID (only for user-initiated closes with reason "closed")

    +
    closeReason: StrategyCloseReason

    Why signal closed (time_expired | take_profit | stop_loss | closed)

    +
    closeTimestamp: number

    Unix timestamp in milliseconds when signal closed

    +
    createdAt: number

    Unix timestamp in milliseconds when this tick result was created (from candle timestamp in backtest or execution context when in live)

    +
    currentPrice: number

    Final VWAP price at close

    +
    exchangeName: string

    Exchange name for tracking

    +
    frameName: string

    Time frame name for tracking (e.g., "1m", "5m")

    +

    Profit/loss calculation with fees and slippage

    +

    Completed signal with original parameters

    +
    strategyName: string

    Strategy name for tracking

    +
    symbol: string

    Trading pair symbol (e.g., "BTCUSDT")

    +

    Interface IStrategyTickResultIdle

    Tick result: no active signal, idle state.

    -
    interface IStrategyTickResultIdle {
        action: "idle";
        backtest: boolean;
        createdAt: number;
        currentPrice: number;
        exchangeName: string;
        frameName: string;
        signal: null;
        strategyName: string;
        symbol: string;
    }

    Properties

    interface IStrategyTickResultIdle {
        action: "idle";
        backtest: boolean;
        createdAt: number;
        currentPrice: number;
        exchangeName: string;
        frameName: string;
        signal: null;
        strategyName: string;
        symbol: string;
    }

    Properties

    action: "idle"

    Discriminator for type-safe union

    -
    backtest: boolean

    Whether this event is from backtest mode (true) or live mode (false)

    -
    createdAt: number

    Unix timestamp in milliseconds when this tick result was created (from candle timestamp in backtest or execution context when in live)

    -
    currentPrice: number

    Current VWAP price during idle state

    -
    exchangeName: string

    Exchange name for tracking idle events

    -
    frameName: string

    Time frame name for tracking (e.g., "1m", "5m")

    -
    signal: null

    No signal in idle state

    -
    strategyName: string

    Strategy name for tracking idle events

    -
    symbol: string

    Trading pair symbol (e.g., "BTCUSDT")

    -
    +
    backtest: boolean

    Whether this event is from backtest mode (true) or live mode (false)

    +
    createdAt: number

    Unix timestamp in milliseconds when this tick result was created (from candle timestamp in backtest or execution context when in live)

    +
    currentPrice: number

    Current VWAP price during idle state

    +
    exchangeName: string

    Exchange name for tracking idle events

    +
    frameName: string

    Time frame name for tracking (e.g., "1m", "5m")

    +
    signal: null

    No signal in idle state

    +
    strategyName: string

    Strategy name for tracking idle events

    +
    symbol: string

    Trading pair symbol (e.g., "BTCUSDT")

    +

    Interface IStrategyTickResultOpened

    Tick result: new signal just created. Triggered after getSignal validation and persistence.

    -
    interface IStrategyTickResultOpened {
        action: "opened";
        backtest: boolean;
        createdAt: number;
        currentPrice: number;
        exchangeName: string;
        frameName: string;
        signal: IPublicSignalRow;
        strategyName: string;
        symbol: string;
    }

    Properties

    interface IStrategyTickResultOpened {
        action: "opened";
        backtest: boolean;
        createdAt: number;
        currentPrice: number;
        exchangeName: string;
        frameName: string;
        signal: IPublicSignalRow;
        strategyName: string;
        symbol: string;
    }

    Properties

    action backtest createdAt currentPrice @@ -10,15 +10,15 @@ Triggered after getSignal validation and persistence.

    strategyName symbol

    Properties

    action: "opened"

    Discriminator for type-safe union

    -
    backtest: boolean

    Whether this event is from backtest mode (true) or live mode (false)

    -
    createdAt: number

    Unix timestamp in milliseconds when this tick result was created (from candle timestamp in backtest or execution context when in live)

    -
    currentPrice: number

    Current VWAP price at signal open

    -
    exchangeName: string

    Exchange name for tracking

    -
    frameName: string

    Time frame name for tracking (e.g., "1m", "5m")

    -

    Newly created and validated signal with generated ID

    -
    strategyName: string

    Strategy name for tracking

    -
    symbol: string

    Trading pair symbol (e.g., "BTCUSDT")

    -
    +
    backtest: boolean

    Whether this event is from backtest mode (true) or live mode (false)

    +
    createdAt: number

    Unix timestamp in milliseconds when this tick result was created (from candle timestamp in backtest or execution context when in live)

    +
    currentPrice: number

    Current VWAP price at signal open

    +
    exchangeName: string

    Exchange name for tracking

    +
    frameName: string

    Time frame name for tracking (e.g., "1m", "5m")

    +

    Newly created and validated signal with generated ID

    +
    strategyName: string

    Strategy name for tracking

    +
    symbol: string

    Trading pair symbol (e.g., "BTCUSDT")

    +

    Interface IStrategyTickResultScheduled

    Tick result: scheduled signal created, waiting for price to reach entry point. Triggered when getSignal returns signal with priceOpen specified.

    -
    interface IStrategyTickResultScheduled {
        action: "scheduled";
        backtest: boolean;
        createdAt: number;
        currentPrice: number;
        exchangeName: string;
        frameName: string;
        signal: IPublicSignalRow;
        strategyName: string;
        symbol: string;
    }

    Properties

    interface IStrategyTickResultScheduled {
        action: "scheduled";
        backtest: boolean;
        createdAt: number;
        currentPrice: number;
        exchangeName: string;
        frameName: string;
        signal: IPublicSignalRow;
        strategyName: string;
        symbol: string;
    }

    Properties

    action backtest createdAt currentPrice @@ -10,15 +10,15 @@ Triggered when getSignal returns signal with priceOpen specified.

    strategyName symbol

    Properties

    action: "scheduled"

    Discriminator for type-safe union

    -
    backtest: boolean

    Whether this event is from backtest mode (true) or live mode (false)

    -
    createdAt: number

    Unix timestamp in milliseconds when this tick result was created (from candle timestamp in backtest or execution context when in live)

    -
    currentPrice: number

    Current VWAP price when scheduled signal created

    -
    exchangeName: string

    Exchange name for tracking

    -
    frameName: string

    Time frame name for tracking (e.g., "1m", "5m")

    -

    Scheduled signal waiting for activation

    -
    strategyName: string

    Strategy name for tracking

    -
    symbol: string

    Trading pair symbol (e.g., "BTCUSDT")

    -
    +
    backtest: boolean

    Whether this event is from backtest mode (true) or live mode (false)

    +
    createdAt: number

    Unix timestamp in milliseconds when this tick result was created (from candle timestamp in backtest or execution context when in live)

    +
    currentPrice: number

    Current VWAP price when scheduled signal created

    +
    exchangeName: string

    Exchange name for tracking

    +
    frameName: string

    Time frame name for tracking (e.g., "1m", "5m")

    +

    Scheduled signal waiting for activation

    +
    strategyName: string

    Strategy name for tracking

    +
    symbol: string

    Trading pair symbol (e.g., "BTCUSDT")

    +

    Interface IStrategyTickResultWaiting

    Tick result: scheduled signal is waiting for price to reach entry point. This is returned on subsequent ticks while monitoring a scheduled signal. Different from "scheduled" which is only returned once when signal is first created.

    -
    interface IStrategyTickResultWaiting {
        action: "waiting";
        backtest: boolean;
        createdAt: number;
        currentPrice: number;
        exchangeName: string;
        frameName: string;
        percentSl: number;
        percentTp: number;
        pnl: IStrategyPnL;
        signal: IPublicSignalRow;
        strategyName: string;
        symbol: string;
    }

    Properties

    interface IStrategyTickResultWaiting {
        action: "waiting";
        backtest: boolean;
        createdAt: number;
        currentPrice: number;
        exchangeName: string;
        frameName: string;
        percentSl: number;
        percentTp: number;
        pnl: IStrategyPnL;
        signal: IPublicSignalRow;
        strategyName: string;
        symbol: string;
    }

    Properties

    action backtest createdAt currentPrice @@ -14,18 +14,18 @@ Different from "scheduled" which is only returned once when signal is strategyName symbol

    Properties

    action: "waiting"

    Discriminator for type-safe union

    -
    backtest: boolean

    Whether this event is from backtest mode (true) or live mode (false)

    -
    createdAt: number

    Unix timestamp in milliseconds when this tick result was created (from candle timestamp in backtest or execution context when in live)

    -
    currentPrice: number

    Current VWAP price for monitoring

    -
    exchangeName: string

    Exchange name for tracking

    -
    frameName: string

    Time frame name for tracking (e.g., "1m", "5m")

    -
    percentSl: number

    Percentage progress towards stop loss (always 0 for waiting scheduled signals)

    -
    percentTp: number

    Percentage progress towards take profit (always 0 for waiting scheduled signals)

    -

    Unrealized PNL for scheduled position (theoretical, not yet activated)

    -

    Scheduled signal waiting for activation

    -
    strategyName: string

    Strategy name for tracking

    -
    symbol: string

    Trading pair symbol (e.g., "BTCUSDT")

    -
    +
    backtest: boolean

    Whether this event is from backtest mode (true) or live mode (false)

    +
    createdAt: number

    Unix timestamp in milliseconds when this tick result was created (from candle timestamp in backtest or execution context when in live)

    +
    currentPrice: number

    Current VWAP price for monitoring

    +
    exchangeName: string

    Exchange name for tracking

    +
    frameName: string

    Time frame name for tracking (e.g., "1m", "5m")

    +
    percentSl: number

    Percentage progress towards stop loss (always 0 for waiting scheduled signals)

    +
    percentTp: number

    Percentage progress towards take profit (always 0 for waiting scheduled signals)

    +

    Unrealized PNL for scheduled position (theoretical, not yet activated)

    +

    Scheduled signal waiting for activation

    +
    strategyName: string

    Strategy name for tracking

    +
    symbol: string

    Trading pair symbol (e.g., "BTCUSDT")

    +

    Interface ITrailingStopCommitRow

    Queued trailing stop commit.

    -
    interface ITrailingStopCommitRow {
        action: "trailing-stop";
        backtest: boolean;
        currentPrice: number;
        percentShift: number;
        symbol: string;
    }

    Hierarchy

    • ICommitRowBase
      • ITrailingStopCommitRow

    Properties

    interface ITrailingStopCommitRow {
        action: "trailing-stop";
        backtest: boolean;
        currentPrice: number;
        percentShift: number;
        symbol: string;
    }

    Hierarchy

    • ICommitRowBase
      • ITrailingStopCommitRow

    Properties

    action: "trailing-stop"

    Discriminator

    -
    backtest: boolean

    Whether running in backtest mode

    -
    currentPrice: number

    Price at which trailing was set

    -
    percentShift: number

    Percentage shift applied

    -
    symbol: string

    Trading pair symbol

    -
    +
    backtest: boolean

    Whether running in backtest mode

    +
    currentPrice: number

    Price at which trailing was set

    +
    percentShift: number

    Percentage shift applied

    +
    symbol: string

    Trading pair symbol

    +

    Interface ITrailingTakeCommitRow

    Queued trailing take commit.

    -
    interface ITrailingTakeCommitRow {
        action: "trailing-take";
        backtest: boolean;
        currentPrice: number;
        percentShift: number;
        symbol: string;
    }

    Hierarchy

    • ICommitRowBase
      • ITrailingTakeCommitRow

    Properties

    interface ITrailingTakeCommitRow {
        action: "trailing-take";
        backtest: boolean;
        currentPrice: number;
        percentShift: number;
        symbol: string;
    }

    Hierarchy

    • ICommitRowBase
      • ITrailingTakeCommitRow

    Properties

    action: "trailing-take"

    Discriminator

    -
    backtest: boolean

    Whether running in backtest mode

    -
    currentPrice: number

    Price at which trailing was set

    -
    percentShift: number

    Percentage shift applied

    -
    symbol: string

    Trading pair symbol

    -
    +
    backtest: boolean

    Whether running in backtest mode

    +
    currentPrice: number

    Price at which trailing was set

    +
    percentShift: number

    Percentage shift applied

    +
    symbol: string

    Trading pair symbol

    +

    Interface IWalkerResults

    Complete walker results after comparing all strategies.

    -
    interface IWalkerResults {
        bestMetric: number;
        bestStats: BacktestStatisticsModel;
        bestStrategy: string;
        exchangeName: string;
        frameName: string;
        metric: WalkerMetric;
        symbol: string;
        totalStrategies: number;
        walkerName: string;
    }

    Hierarchy (View Summary)

    Properties

    interface IWalkerResults {
        bestMetric: number;
        bestStats: BacktestStatisticsModel;
        bestStrategy: string;
        exchangeName: string;
        frameName: string;
        metric: WalkerMetric;
        symbol: string;
        totalStrategies: number;
        walkerName: string;
    }

    Hierarchy (View Summary)

    Properties

    bestMetric: number

    bestMetric - Best metric value achieved

    -

    bestStats - Best strategy statistics

    -
    bestStrategy: string

    bestStrategy - Best performing strategy name

    -
    exchangeName: string

    Exchange used

    -
    frameName: string

    Frame used

    -
    metric: WalkerMetric

    metric - Metric used for optimization

    -
    symbol: string

    Symbol tested

    -
    totalStrategies: number

    totalStrategies - Total number of strategies tested

    -
    walkerName: string

    Walker name

    -
    +

    bestStats - Best strategy statistics

    +
    bestStrategy: string

    bestStrategy - Best performing strategy name

    +
    exchangeName: string

    Exchange used

    +
    frameName: string

    Frame used

    +
    metric: WalkerMetric

    metric - Metric used for optimization

    +
    symbol: string

    Symbol tested

    +
    totalStrategies: number

    totalStrategies - Total number of strategies tested

    +
    walkerName: string

    Walker name

    +

    Interface IWalkerSchema

    Walker schema registered via addWalker(). Defines A/B testing configuration for multiple strategies.

    -
    interface IWalkerSchema {
        callbacks?: Partial<IWalkerCallbacks>;
        exchangeName: string;
        frameName: string;
        metric?: WalkerMetric;
        note?: string;
        strategies: string[];
        walkerName: string;
    }

    Properties

    interface IWalkerSchema {
        callbacks?: Partial<IWalkerCallbacks>;
        exchangeName: string;
        frameName: string;
        metric?: WalkerMetric;
        note?: string;
        strategies: string[];
        walkerName: string;
    }

    Properties

    callbacks? exchangeName frameName metric? @@ -8,13 +8,13 @@ Defines A/B testing configuration for multiple strategies.

    strategies walkerName

    Properties

    callbacks?: Partial<IWalkerCallbacks>

    Optional lifecycle event callbacks

    -
    exchangeName: string

    Exchange to use for backtesting all strategies

    -
    frameName: string

    Timeframe generator to use for backtesting all strategies

    -
    metric?: WalkerMetric

    Metric to optimize (default: "sharpeRatio")

    -
    note?: string

    Optional developer note for documentation

    -
    strategies: string[]

    List of strategy names to compare (must be registered via addStrategy)

    -
    walkerName: string

    Unique walker identifier for registration

    -
    +
    exchangeName: string

    Exchange to use for backtesting all strategies

    +
    frameName: string

    Timeframe generator to use for backtesting all strategies

    +
    metric?: WalkerMetric

    Metric to optimize (default: "sharpeRatio")

    +
    note?: string

    Optional developer note for documentation

    +
    strategies: string[]

    List of strategy names to compare (must be registered via addStrategy)

    +
    walkerName: string

    Unique walker identifier for registration

    +

    Interface IWalkerStrategyResult

    Result for a single strategy in the comparison.

    -
    interface IWalkerStrategyResult {
        metric: number;
        rank: number;
        stats: BacktestStatisticsModel;
        strategyName: string;
    }

    Properties

    interface IWalkerStrategyResult {
        metric: number;
        rank: number;
        stats: BacktestStatisticsModel;
        strategyName: string;
    }

    Properties

    metric: number

    Metric value used for comparison (null if invalid)

    -
    rank: number

    Rank position (1 = best, 2 = second best, etc.)

    -

    Backtest statistics for this strategy

    -
    strategyName: string

    Strategy name

    -
    +
    rank: number

    Rank position (1 = best, 2 = second best, etc.)

    +

    Backtest statistics for this strategy

    +
    strategyName: string

    Strategy name

    +

    Interface InfoErrorNotification

    Error notification. Emitted for recoverable errors in background tasks.

    -
    interface InfoErrorNotification {
        backtest: boolean;
        error: object;
        id: string;
        message: string;
        type: "error.info";
    }

    Properties

    interface InfoErrorNotification {
        backtest: boolean;
        error: object;
        id: string;
        message: string;
        type: "error.info";
    }

    Properties

    backtest: boolean

    Always false for error notifications (errors are from live context)

    -
    error: object

    Serialized error object with stack trace and metadata

    -
    id: string

    Unique notification identifier

    -
    message: string

    Human-readable error message

    -
    type: "error.info"

    Discriminator for type-safe union

    -
    +
    error: object

    Serialized error object with stack trace and metadata

    +
    id: string

    Unique notification identifier

    +
    message: string

    Human-readable error message

    +
    type: "error.info"

    Discriminator for type-safe union

    +

    Interface MaxDrawdownEvent

    Single max drawdown event recorded for a position.

    -
    interface MaxDrawdownEvent {
        backtest: boolean;
        currentPrice: number;
        maxDrawdown: IStrategyPnL;
        peakProfit: IStrategyPnL;
        pnl: IStrategyPnL;
        position: "long" | "short";
        priceOpen: number;
        priceStopLoss: number;
        priceTakeProfit: number;
        signalId: string;
        strategyName: string;
        symbol: string;
        timestamp: number;
    }

    Properties

    interface MaxDrawdownEvent {
        backtest: boolean;
        currentPrice: number;
        maxDrawdown: IStrategyPnL;
        peakProfit: IStrategyPnL;
        pnl: IStrategyPnL;
        position: "long" | "short";
        priceOpen: number;
        priceStopLoss: number;
        priceTakeProfit: number;
        signalId: string;
        strategyName: string;
        symbol: string;
        timestamp: number;
    }

    Properties

    backtest: boolean

    Whether the event occurred in backtest mode

    -
    currentPrice: number

    Record price reached in the loss direction

    -
    maxDrawdown: IStrategyPnL

    Maximum drawdown experienced during the life of this position up to the moment this public signal was created

    -
    peakProfit: IStrategyPnL

    Peak profit achieved during the life of this position up to the moment this public signal was created

    -

    Total PNL of the closed position (including all entries and partials)

    -
    position: "long" | "short"

    Position direction

    -
    priceOpen: number

    Effective entry price at the time of the update

    -
    priceStopLoss: number

    Stop loss price

    -
    priceTakeProfit: number

    Take profit price

    -
    signalId: string

    Signal unique identifier

    -
    strategyName: string

    Strategy name

    -
    symbol: string

    Trading pair symbol

    -
    timestamp: number

    Unix timestamp in milliseconds when the record was set

    -
    +
    currentPrice: number

    Record price reached in the loss direction

    +
    maxDrawdown: IStrategyPnL

    Maximum drawdown experienced during the life of this position up to the moment this public signal was created

    +
    peakProfit: IStrategyPnL

    Peak profit achieved during the life of this position up to the moment this public signal was created

    +

    Total PNL of the closed position (including all entries and partials)

    +
    position: "long" | "short"

    Position direction

    +
    priceOpen: number

    Effective entry price at the time of the update

    +
    priceStopLoss: number

    Stop loss price

    +
    priceTakeProfit: number

    Take profit price

    +
    signalId: string

    Signal unique identifier

    +
    strategyName: string

    Strategy name

    +
    symbol: string

    Trading pair symbol

    +
    timestamp: number

    Unix timestamp in milliseconds when the record was set

    +

    Interface MaxDrawdownStatisticsModel

    Aggregated statistics model for max drawdown events.

    -
    interface MaxDrawdownStatisticsModel {
        eventList: MaxDrawdownEvent[];
        totalEvents: number;
    }

    Properties

    interface MaxDrawdownStatisticsModel {
        eventList: MaxDrawdownEvent[];
        totalEvents: number;
    }

    Properties

    eventList: MaxDrawdownEvent[]

    Full list of recorded events (newest first)

    -
    totalEvents: number

    Total number of recorded events

    -
    +
    totalEvents: number

    Total number of recorded events

    +

    Interface MessageModel<Role>

    A single message in an LLM chat history. Covers all roles: system instructions, user input, assistant responses, and tool results.

    -
    interface MessageModel<Role extends MessageRole = MessageRole> {
        content: string;
        images?: string[] | Blob[] | Uint8Array<ArrayBufferLike>[];
        reasoning_content?: string;
        role: Role;
        tool_call_id?: string;
        tool_calls?: MessageToolCall[];
    }

    Type Parameters

    Properties

    interface MessageModel<Role extends MessageRole = MessageRole> {
        content: string;
        images?: string[] | Blob[] | Uint8Array<ArrayBufferLike>[];
        reasoning_content?: string;
        role: Role;
        tool_call_id?: string;
        tool_calls?: MessageToolCall[];
    }

    Type Parameters

    Properties

    content: string

    Text content of the message. Empty string for assistant messages that only contain tool_calls.

    -
    images?: string[] | Blob[] | Uint8Array<ArrayBufferLike>[]

    Images attached to the message. Supported as Blob, raw bytes, or base64 strings.

    -
    reasoning_content?: string

    Chain-of-thought / reasoning exposed by some providers (e.g. DeepSeek).

    -
    role: Role

    Sender role — determines how the message is interpreted by the model.

    -
    tool_call_id?: string

    ID of the tool call this message is responding to. Present only on tool messages.

    -
    tool_calls?: MessageToolCall[]

    Tool calls emitted by the assistant. Present only on assistant messages.

    -
    +
    images?: string[] | Blob[] | Uint8Array<ArrayBufferLike>[]

    Images attached to the message. Supported as Blob, raw bytes, or base64 strings.

    +
    reasoning_content?: string

    Chain-of-thought / reasoning exposed by some providers (e.g. DeepSeek).

    +
    role: Role

    Sender role — determines how the message is interpreted by the model.

    +
    tool_call_id?: string

    ID of the tool call this message is responding to. Present only on tool messages.

    +
    tool_calls?: MessageToolCall[]

    Tool calls emitted by the assistant. Present only on assistant messages.

    +

    Interface MetricStats

    Aggregated statistics for a specific metric type.

    -
    interface MetricStats {
        avgDuration: number;
        avgWaitTime: number;
        count: number;
        maxDuration: number;
        maxWaitTime: number;
        median: number;
        metricType: PerformanceMetricType;
        minDuration: number;
        minWaitTime: number;
        p95: number;
        p99: number;
        stdDev: number;
        totalDuration: number;
    }

    Properties

    interface MetricStats {
        avgDuration: number;
        avgWaitTime: number;
        count: number;
        maxDuration: number;
        maxWaitTime: number;
        median: number;
        metricType: PerformanceMetricType;
        minDuration: number;
        minWaitTime: number;
        p95: number;
        p99: number;
        stdDev: number;
        totalDuration: number;
    }

    Properties

    avgDuration: number

    Average duration (ms)

    -
    avgWaitTime: number

    Average wait time between events (ms)

    -
    count: number

    Number of recorded samples

    -
    maxDuration: number

    Maximum duration (ms)

    -
    maxWaitTime: number

    Maximum wait time between events (ms)

    -
    median: number

    Median duration (ms)

    -

    Type of metric

    -
    minDuration: number

    Minimum duration (ms)

    -
    minWaitTime: number

    Minimum wait time between events (ms)

    -
    p95: number

    95th percentile duration (ms)

    -
    p99: number

    99th percentile duration (ms)

    -
    stdDev: number

    Standard deviation of duration (ms)

    -
    totalDuration: number

    Total duration across all samples (ms)

    -
    +
    avgWaitTime: number

    Average wait time between events (ms)

    +
    count: number

    Number of recorded samples

    +
    maxDuration: number

    Maximum duration (ms)

    +
    maxWaitTime: number

    Maximum wait time between events (ms)

    +
    median: number

    Median duration (ms)

    +

    Type of metric

    +
    minDuration: number

    Minimum duration (ms)

    +
    minWaitTime: number

    Minimum wait time between events (ms)

    +
    p95: number

    95th percentile duration (ms)

    +
    p99: number

    99th percentile duration (ms)

    +
    stdDev: number

    Standard deviation of duration (ms)

    +
    totalDuration: number

    Total duration across all samples (ms)

    +

    Interface PartialEvent

    Unified partial profit/loss event data for report generation. Contains all information about profit and loss level milestones.

    -
    interface PartialEvent {
        action: "profit" | "loss";
        backtest: boolean;
        currentPrice: number;
        level: PartialLevel;
        note?: string;
        originalPriceOpen?: number;
        originalPriceStopLoss?: number;
        originalPriceTakeProfit?: number;
        partialExecuted?: number;
        pendingAt?: number;
        pnl?: IStrategyPnL;
        position: string;
        priceOpen?: number;
        priceStopLoss?: number;
        priceTakeProfit?: number;
        scheduledAt?: number;
        signalId: string;
        strategyName: string;
        symbol: string;
        timestamp: number;
        totalEntries?: number;
        totalPartials?: number;
    }

    Properties

    interface PartialEvent {
        action: "profit" | "loss";
        backtest: boolean;
        currentPrice: number;
        level: PartialLevel;
        note?: string;
        originalPriceOpen?: number;
        originalPriceStopLoss?: number;
        originalPriceTakeProfit?: number;
        partialExecuted?: number;
        pendingAt?: number;
        pnl?: IStrategyPnL;
        position: string;
        priceOpen?: number;
        priceStopLoss?: number;
        priceTakeProfit?: number;
        scheduledAt?: number;
        signalId: string;
        strategyName: string;
        symbol: string;
        timestamp: number;
        totalEntries?: number;
        totalPartials?: number;
    }

    Properties

    action backtest currentPrice level @@ -23,28 +23,28 @@ Contains all information about profit and loss level milestones.

    totalEntries? totalPartials?

    Properties

    action: "profit" | "loss"

    Event action type (profit or loss)

    -
    backtest: boolean

    True if backtest mode, false if live mode

    -
    currentPrice: number

    Current market price

    -
    level: PartialLevel

    Profit/loss level reached (10, 20, 30, etc)

    -
    note?: string

    Human-readable description of signal reason

    -
    originalPriceOpen?: number

    Original entry price before DCA averaging (present when averageBuy was applied)

    -
    originalPriceStopLoss?: number

    Original stop loss price set at signal creation

    -
    originalPriceTakeProfit?: number

    Original take profit price set at signal creation

    -
    partialExecuted?: number

    Total executed percentage from partial closes

    -
    pendingAt?: number

    Timestamp when position became active (ms)

    -

    Unrealized PNL at the moment this level was reached

    -
    position: string

    Position type

    -
    priceOpen?: number

    Entry price for the position

    -
    priceStopLoss?: number

    Stop loss exit price

    -
    priceTakeProfit?: number

    Take profit target price

    -
    scheduledAt?: number

    Timestamp when signal was created/scheduled (ms)

    -
    signalId: string

    Signal ID

    -
    strategyName: string

    Strategy name

    -
    symbol: string

    Trading pair symbol

    -
    timestamp: number

    Event timestamp in milliseconds

    -
    totalEntries?: number

    Total number of DCA entries (present when averageBuy was applied)

    -
    totalPartials?: number

    Total number of partial closes executed (_partial.length)

    -
    +
    backtest: boolean

    True if backtest mode, false if live mode

    +
    currentPrice: number

    Current market price

    +
    level: PartialLevel

    Profit/loss level reached (10, 20, 30, etc)

    +
    note?: string

    Human-readable description of signal reason

    +
    originalPriceOpen?: number

    Original entry price before DCA averaging (present when averageBuy was applied)

    +
    originalPriceStopLoss?: number

    Original stop loss price set at signal creation

    +
    originalPriceTakeProfit?: number

    Original take profit price set at signal creation

    +
    partialExecuted?: number

    Total executed percentage from partial closes

    +
    pendingAt?: number

    Timestamp when position became active (ms)

    +

    Unrealized PNL at the moment this level was reached

    +
    position: string

    Position type

    +
    priceOpen?: number

    Entry price for the position

    +
    priceStopLoss?: number

    Stop loss exit price

    +
    priceTakeProfit?: number

    Take profit target price

    +
    scheduledAt?: number

    Timestamp when signal was created/scheduled (ms)

    +
    signalId: string

    Signal ID

    +
    strategyName: string

    Strategy name

    +
    symbol: string

    Trading pair symbol

    +
    timestamp: number

    Event timestamp in milliseconds

    +
    totalEntries?: number

    Total number of DCA entries (present when averageBuy was applied)

    +
    totalPartials?: number

    Total number of partial closes executed (_partial.length)

    +

    Interface PartialLossAvailableNotification

    Partial loss notification. Emitted when signal reaches loss level milestone (-10%, -20%, etc).

    -
    interface PartialLossAvailableNotification {
        backtest: boolean;
        createdAt: number;
        currentPrice: number;
        exchangeName: string;
        id: string;
        level: PartialLevel;
        maxDrawdown: IStrategyPnL;
        maxDrawdownCost: number;
        maxDrawdownEntries: number;
        maxDrawdownPercentage: number;
        maxDrawdownPriceClose: number;
        maxDrawdownPriceOpen: number;
        note?: string;
        originalPriceOpen: number;
        originalPriceStopLoss: number;
        originalPriceTakeProfit: number;
        peakProfit: IStrategyPnL;
        peakProfitCost: number;
        peakProfitEntries: number;
        peakProfitPercentage: number;
        peakProfitPriceClose: number;
        peakProfitPriceOpen: number;
        pendingAt: number;
        pnl: IStrategyPnL;
        pnlCost: number;
        pnlEntries: number;
        pnlPercentage: number;
        pnlPriceClose: number;
        pnlPriceOpen: number;
        position: "long" | "short";
        priceOpen: number;
        priceStopLoss: number;
        priceTakeProfit: number;
        scheduledAt: number;
        signalId: string;
        strategyName: string;
        symbol: string;
        timestamp: number;
        totalEntries: number;
        totalPartials: number;
        type: "partial_loss.available";
    }

    Properties

    interface PartialLossAvailableNotification {
        backtest: boolean;
        createdAt: number;
        currentPrice: number;
        exchangeName: string;
        id: string;
        level: PartialLevel;
        maxDrawdown: IStrategyPnL;
        maxDrawdownCost: number;
        maxDrawdownEntries: number;
        maxDrawdownPercentage: number;
        maxDrawdownPriceClose: number;
        maxDrawdownPriceOpen: number;
        note?: string;
        originalPriceOpen: number;
        originalPriceStopLoss: number;
        originalPriceTakeProfit: number;
        peakProfit: IStrategyPnL;
        peakProfitCost: number;
        peakProfitEntries: number;
        peakProfitPercentage: number;
        peakProfitPriceClose: number;
        peakProfitPriceOpen: number;
        pendingAt: number;
        pnl: IStrategyPnL;
        pnlCost: number;
        pnlEntries: number;
        pnlPercentage: number;
        pnlPriceClose: number;
        pnlPriceOpen: number;
        position: "long" | "short";
        priceOpen: number;
        priceStopLoss: number;
        priceTakeProfit: number;
        scheduledAt: number;
        signalId: string;
        strategyName: string;
        symbol: string;
        timestamp: number;
        totalEntries: number;
        totalPartials: number;
        type: "partial_loss.available";
    }

    Properties

    backtest createdAt currentPrice exchangeName @@ -42,47 +42,47 @@ Emitted when signal reaches loss level milestone (-10%, -20%, etc).

    totalPartials type

    Properties

    backtest: boolean

    Whether this notification is from backtest mode (true) or live mode (false)

    -
    createdAt: number

    Unix timestamp in milliseconds when the notification was created

    -
    currentPrice: number

    Current market price when milestone was reached

    -
    exchangeName: string

    Exchange name where signal was executed

    -
    id: string

    Unique notification identifier

    -
    level: PartialLevel

    Loss level milestone reached (10, 20, 30, etc)

    -
    maxDrawdown: IStrategyPnL

    Maximum drawdown experienced during the life of this position up to the moment this public signal was created

    -
    maxDrawdownCost: number

    Absolute profit/loss in USD at the moment the position reached its maximum drawdown during the life of this position

    -
    maxDrawdownEntries: number

    Number of entries executed at the moment the position reached its maximum drawdown during the life of this position

    -
    maxDrawdownPercentage: number

    Profit/loss as percentage at the moment the position reached its maximum drawdown during the life of this position

    -
    maxDrawdownPriceClose: number

    Exit price for PNL calculation at the moment of max drawdown

    -
    maxDrawdownPriceOpen: number

    Maximum drawdown price reached in loss direction during the life of this position

    -
    note?: string

    Optional human-readable description of signal reason

    -
    originalPriceOpen: number

    Original entry price at signal creation (unchanged by DCA averaging)

    -
    originalPriceStopLoss: number

    Original stop loss price before any trailing adjustments

    -
    originalPriceTakeProfit: number

    Original take profit price before any trailing adjustments

    -
    peakProfit: IStrategyPnL

    Peak profit achieved during the life of this position up to the moment this public signal was created

    -
    peakProfitCost: number

    Absolute profit/loss in USD at the moment the position reached its peak profit during the life of this position

    -
    peakProfitEntries: number

    Number of entries executed at the moment the position reached its peak profit during the life of this position

    -
    peakProfitPercentage: number

    Profit/loss as percentage at the moment the position reached its peak profit during the life of this position

    -
    peakProfitPriceClose: number

    Exit price for PNL calculation at the moment of peak profit

    -
    peakProfitPriceOpen: number

    Peak price reached in profit direction during the life of this position

    -
    pendingAt: number

    Pending timestamp in milliseconds (when position became pending/active at priceOpen)

    -

    Total PNL of the closed position (including all entries and partials)

    -
    pnlCost: number

    Absolute profit/loss in USD

    -
    pnlEntries: number

    Total invested capital in USD

    -
    pnlPercentage: number

    Profit/loss as percentage (e.g., 1.5 for +1.5%, -2.3 for -2.3%)

    -
    pnlPriceClose: number

    Exit price from PNL calculation (adjusted with slippage and fees)

    -
    pnlPriceOpen: number

    Entry price from PNL calculation (effective price adjusted with slippage and fees)

    -
    position: "long" | "short"

    Trade direction: "long" (buy) or "short" (sell)

    -
    priceOpen: number

    Entry price for the position

    -
    priceStopLoss: number

    Effective stop loss price (with trailing if set)

    -
    priceTakeProfit: number

    Effective take profit price (with trailing if set)

    -
    scheduledAt: number

    Signal creation timestamp in milliseconds (when signal was first created/scheduled)

    -
    signalId: string

    Unique signal identifier (UUID v4)

    -
    strategyName: string

    Strategy name that generated this signal

    -
    symbol: string

    Trading pair symbol (e.g., "BTCUSDT")

    -
    timestamp: number

    Unix timestamp in milliseconds when partial loss level was reached

    -
    totalEntries: number

    Total number of DCA entries (_entry.length). 1 = no averaging.

    -
    totalPartials: number

    Total number of partial closes executed (_partial.length). 0 = no partial closes done.

    -
    type: "partial_loss.available"

    Discriminator for type-safe union

    -
    +
    createdAt: number

    Unix timestamp in milliseconds when the notification was created

    +
    currentPrice: number

    Current market price when milestone was reached

    +
    exchangeName: string

    Exchange name where signal was executed

    +
    id: string

    Unique notification identifier

    +
    level: PartialLevel

    Loss level milestone reached (10, 20, 30, etc)

    +
    maxDrawdown: IStrategyPnL

    Maximum drawdown experienced during the life of this position up to the moment this public signal was created

    +
    maxDrawdownCost: number

    Absolute profit/loss in USD at the moment the position reached its maximum drawdown during the life of this position

    +
    maxDrawdownEntries: number

    Number of entries executed at the moment the position reached its maximum drawdown during the life of this position

    +
    maxDrawdownPercentage: number

    Profit/loss as percentage at the moment the position reached its maximum drawdown during the life of this position

    +
    maxDrawdownPriceClose: number

    Exit price for PNL calculation at the moment of max drawdown

    +
    maxDrawdownPriceOpen: number

    Maximum drawdown price reached in loss direction during the life of this position

    +
    note?: string

    Optional human-readable description of signal reason

    +
    originalPriceOpen: number

    Original entry price at signal creation (unchanged by DCA averaging)

    +
    originalPriceStopLoss: number

    Original stop loss price before any trailing adjustments

    +
    originalPriceTakeProfit: number

    Original take profit price before any trailing adjustments

    +
    peakProfit: IStrategyPnL

    Peak profit achieved during the life of this position up to the moment this public signal was created

    +
    peakProfitCost: number

    Absolute profit/loss in USD at the moment the position reached its peak profit during the life of this position

    +
    peakProfitEntries: number

    Number of entries executed at the moment the position reached its peak profit during the life of this position

    +
    peakProfitPercentage: number

    Profit/loss as percentage at the moment the position reached its peak profit during the life of this position

    +
    peakProfitPriceClose: number

    Exit price for PNL calculation at the moment of peak profit

    +
    peakProfitPriceOpen: number

    Peak price reached in profit direction during the life of this position

    +
    pendingAt: number

    Pending timestamp in milliseconds (when position became pending/active at priceOpen)

    +

    Total PNL of the closed position (including all entries and partials)

    +
    pnlCost: number

    Absolute profit/loss in USD

    +
    pnlEntries: number

    Total invested capital in USD

    +
    pnlPercentage: number

    Profit/loss as percentage (e.g., 1.5 for +1.5%, -2.3 for -2.3%)

    +
    pnlPriceClose: number

    Exit price from PNL calculation (adjusted with slippage and fees)

    +
    pnlPriceOpen: number

    Entry price from PNL calculation (effective price adjusted with slippage and fees)

    +
    position: "long" | "short"

    Trade direction: "long" (buy) or "short" (sell)

    +
    priceOpen: number

    Entry price for the position

    +
    priceStopLoss: number

    Effective stop loss price (with trailing if set)

    +
    priceTakeProfit: number

    Effective take profit price (with trailing if set)

    +
    scheduledAt: number

    Signal creation timestamp in milliseconds (when signal was first created/scheduled)

    +
    signalId: string

    Unique signal identifier (UUID v4)

    +
    strategyName: string

    Strategy name that generated this signal

    +
    symbol: string

    Trading pair symbol (e.g., "BTCUSDT")

    +
    timestamp: number

    Unix timestamp in milliseconds when partial loss level was reached

    +
    totalEntries: number

    Total number of DCA entries (_entry.length). 1 = no averaging.

    +
    totalPartials: number

    Total number of partial closes executed (_partial.length). 0 = no partial closes done.

    +
    type: "partial_loss.available"

    Discriminator for type-safe union

    +

    Interface PartialLossCommit

    Partial loss event.

    -
    interface PartialLossCommit {
        action: "partial-loss";
        backtest: boolean;
        currentPrice: number;
        exchangeName: string;
        frameName: string;
        maxDrawdown: IStrategyPnL;
        note?: string;
        originalPriceOpen: number;
        originalPriceStopLoss: number;
        originalPriceTakeProfit: number;
        peakProfit: IStrategyPnL;
        pendingAt: number;
        percentToClose: number;
        pnl: IStrategyPnL;
        position: "long" | "short";
        priceOpen: number;
        priceStopLoss: number;
        priceTakeProfit: number;
        scheduledAt: number;
        signal: IPublicSignalRow;
        signalId: string;
        strategyName: string;
        symbol: string;
        timestamp: number;
        totalEntries: number;
        totalPartials: number;
    }

    Hierarchy

    • SignalCommitBase
      • PartialLossCommit

    Properties

    interface PartialLossCommit {
        action: "partial-loss";
        backtest: boolean;
        currentPrice: number;
        exchangeName: string;
        frameName: string;
        maxDrawdown: IStrategyPnL;
        note?: string;
        originalPriceOpen: number;
        originalPriceStopLoss: number;
        originalPriceTakeProfit: number;
        peakProfit: IStrategyPnL;
        pendingAt: number;
        percentToClose: number;
        pnl: IStrategyPnL;
        position: "long" | "short";
        priceOpen: number;
        priceStopLoss: number;
        priceTakeProfit: number;
        scheduledAt: number;
        signal: IPublicSignalRow;
        signalId: string;
        strategyName: string;
        symbol: string;
        timestamp: number;
        totalEntries: number;
        totalPartials: number;
    }

    Hierarchy

    • SignalCommitBase
      • PartialLossCommit

    Properties

    action: "partial-loss"

    Discriminator for partial-loss action

    -
    backtest: boolean

    Whether this event is from backtest mode (true) or live mode (false)

    -
    currentPrice: number

    Current market price at time of action

    -
    exchangeName: string

    Exchange name where signal was executed

    -
    frameName: string

    Timeframe name (used in backtest mode, empty string in live mode)

    -
    maxDrawdown: IStrategyPnL

    Maximum drawdown experienced during the life of this position up to the moment this public signal was created

    -
    note?: string

    Optional human-readable description of signal reason

    -
    originalPriceOpen: number

    Original entry price at signal creation (unchanged by DCA averaging).

    -
    originalPriceStopLoss: number

    Original stop loss price before any trailing adjustments

    -
    originalPriceTakeProfit: number

    Original take profit price before any trailing adjustments

    -
    peakProfit: IStrategyPnL

    Peak profit achieved during the life of this position up to the moment this public signal was created

    -
    pendingAt: number

    Position activation timestamp in milliseconds (when price reached priceOpen)

    -
    percentToClose: number

    Percentage of position to close (0-100)

    -

    Total PNL of the closed position (including all entries and partials)

    -
    position: "long" | "short"

    Trade direction: "long" (buy) or "short" (sell)

    -
    priceOpen: number

    Entry price for the position

    -
    priceStopLoss: number

    Effective stop loss price (may differ from original after trailing)

    -
    priceTakeProfit: number

    Effective take profit price (may differ from original after trailing)

    -
    scheduledAt: number

    Signal creation timestamp in milliseconds

    -

    Signal data at the moment of this event (snapshot of IPublicSignalRow)

    -
    signalId: string

    Unique signal identifier (UUID v4)

    -
    strategyName: string

    Strategy name that generated this signal

    -
    symbol: string

    Trading pair symbol (e.g., "BTCUSDT")

    -
    timestamp: number

    Timestamp from execution context (tick's when or backtest candle timestamp)

    -
    totalEntries: number

    Total number of DCA entries at the time of this event (_entry.length). +

    backtest: boolean

    Whether this event is from backtest mode (true) or live mode (false)

    +
    currentPrice: number

    Current market price at time of action

    +
    exchangeName: string

    Exchange name where signal was executed

    +
    frameName: string

    Timeframe name (used in backtest mode, empty string in live mode)

    +
    maxDrawdown: IStrategyPnL

    Maximum drawdown experienced during the life of this position up to the moment this public signal was created

    +
    note?: string

    Optional human-readable description of signal reason

    +
    originalPriceOpen: number

    Original entry price at signal creation (unchanged by DCA averaging).

    +
    originalPriceStopLoss: number

    Original stop loss price before any trailing adjustments

    +
    originalPriceTakeProfit: number

    Original take profit price before any trailing adjustments

    +
    peakProfit: IStrategyPnL

    Peak profit achieved during the life of this position up to the moment this public signal was created

    +
    pendingAt: number

    Position activation timestamp in milliseconds (when price reached priceOpen)

    +
    percentToClose: number

    Percentage of position to close (0-100)

    +

    Total PNL of the closed position (including all entries and partials)

    +
    position: "long" | "short"

    Trade direction: "long" (buy) or "short" (sell)

    +
    priceOpen: number

    Entry price for the position

    +
    priceStopLoss: number

    Effective stop loss price (may differ from original after trailing)

    +
    priceTakeProfit: number

    Effective take profit price (may differ from original after trailing)

    +
    scheduledAt: number

    Signal creation timestamp in milliseconds

    +

    Signal data at the moment of this event (snapshot of IPublicSignalRow)

    +
    signalId: string

    Unique signal identifier (UUID v4)

    +
    strategyName: string

    Strategy name that generated this signal

    +
    symbol: string

    Trading pair symbol (e.g., "BTCUSDT")

    +
    timestamp: number

    Timestamp from execution context (tick's when or backtest candle timestamp)

    +
    totalEntries: number

    Total number of DCA entries at the time of this event (_entry.length). 1 = no averaging done (only initial entry). 2+ = averaged positions.

    -
    totalPartials: number

    Total number of partial closes executed at the time of this event (_partial.length). +

    totalPartials: number

    Total number of partial closes executed at the time of this event (_partial.length). 0 = no partial closes done. 1+ = partial closes executed.

    -
    +

    Interface PartialLossCommitNotification

    Partial loss commit notification. Emitted when partial loss action is executed.

    -
    interface PartialLossCommitNotification {
        backtest: boolean;
        createdAt: number;
        currentPrice: number;
        exchangeName: string;
        id: string;
        maxDrawdown: IStrategyPnL;
        maxDrawdownCost: number;
        maxDrawdownEntries: number;
        maxDrawdownPercentage: number;
        maxDrawdownPriceClose: number;
        maxDrawdownPriceOpen: number;
        note?: string;
        originalPriceOpen: number;
        originalPriceStopLoss: number;
        originalPriceTakeProfit: number;
        peakProfit: IStrategyPnL;
        peakProfitCost: number;
        peakProfitEntries: number;
        peakProfitPercentage: number;
        peakProfitPriceClose: number;
        peakProfitPriceOpen: number;
        pendingAt: number;
        percentToClose: number;
        pnl: IStrategyPnL;
        pnlCost: number;
        pnlEntries: number;
        pnlPercentage: number;
        pnlPriceClose: number;
        pnlPriceOpen: number;
        position: "long" | "short";
        priceOpen: number;
        priceStopLoss: number;
        priceTakeProfit: number;
        scheduledAt: number;
        signalId: string;
        strategyName: string;
        symbol: string;
        timestamp: number;
        totalEntries: number;
        totalPartials: number;
        type: "partial_loss.commit";
    }

    Properties

    interface PartialLossCommitNotification {
        backtest: boolean;
        createdAt: number;
        currentPrice: number;
        exchangeName: string;
        id: string;
        maxDrawdown: IStrategyPnL;
        maxDrawdownCost: number;
        maxDrawdownEntries: number;
        maxDrawdownPercentage: number;
        maxDrawdownPriceClose: number;
        maxDrawdownPriceOpen: number;
        note?: string;
        originalPriceOpen: number;
        originalPriceStopLoss: number;
        originalPriceTakeProfit: number;
        peakProfit: IStrategyPnL;
        peakProfitCost: number;
        peakProfitEntries: number;
        peakProfitPercentage: number;
        peakProfitPriceClose: number;
        peakProfitPriceOpen: number;
        pendingAt: number;
        percentToClose: number;
        pnl: IStrategyPnL;
        pnlCost: number;
        pnlEntries: number;
        pnlPercentage: number;
        pnlPriceClose: number;
        pnlPriceOpen: number;
        position: "long" | "short";
        priceOpen: number;
        priceStopLoss: number;
        priceTakeProfit: number;
        scheduledAt: number;
        signalId: string;
        strategyName: string;
        symbol: string;
        timestamp: number;
        totalEntries: number;
        totalPartials: number;
        type: "partial_loss.commit";
    }

    Properties

    backtest createdAt currentPrice exchangeName @@ -42,47 +42,47 @@ Emitted when partial loss action is executed.

    totalPartials type

    Properties

    backtest: boolean

    Whether this notification is from backtest mode (true) or live mode (false)

    -
    createdAt: number

    Unix timestamp in milliseconds when the notification was created

    -
    currentPrice: number

    Current market price when partial was executed

    -
    exchangeName: string

    Exchange name where signal was executed

    -
    id: string

    Unique notification identifier

    -
    maxDrawdown: IStrategyPnL

    Maximum drawdown experienced during the life of this position up to the moment this public signal was created

    -
    maxDrawdownCost: number

    Absolute profit/loss in USD at the moment the position reached its maximum drawdown during the life of this position

    -
    maxDrawdownEntries: number

    Number of entries executed at the moment the position reached its maximum drawdown during the life of this position

    -
    maxDrawdownPercentage: number

    Profit/loss as percentage at the moment the position reached its maximum drawdown during the life of this position

    -
    maxDrawdownPriceClose: number

    Exit price for PNL calculation at the moment of max drawdown

    -
    maxDrawdownPriceOpen: number

    Maximum drawdown price reached in loss direction during the life of this position

    -
    note?: string

    Optional human-readable description of signal reason

    -
    originalPriceOpen: number

    Original entry price at signal creation (unchanged by DCA averaging)

    -
    originalPriceStopLoss: number

    Original stop loss price before any trailing adjustments

    -
    originalPriceTakeProfit: number

    Original take profit price before any trailing adjustments

    -
    peakProfit: IStrategyPnL

    Peak profit achieved during the life of this position up to the moment this public signal was created

    -
    peakProfitCost: number

    Absolute profit/loss in USD at the moment the position reached its peak profit during the life of this position

    -
    peakProfitEntries: number

    Number of entries executed at the moment the position reached its peak profit during the life of this position

    -
    peakProfitPercentage: number

    Profit/loss as percentage at the moment the position reached its peak profit during the life of this position

    -
    peakProfitPriceClose: number

    Exit price for PNL calculation at the moment of peak profit

    -
    peakProfitPriceOpen: number

    Peak price reached in profit direction during the life of this position

    -
    pendingAt: number

    Pending timestamp in milliseconds (when position became pending/active at priceOpen)

    -
    percentToClose: number

    Percentage of position closed (0-100)

    -

    Total PNL of the closed position (including all entries and partials)

    -
    pnlCost: number

    Absolute profit/loss in USD

    -
    pnlEntries: number

    Total invested capital in USD

    -
    pnlPercentage: number

    Profit/loss as percentage (e.g., 1.5 for +1.5%, -2.3 for -2.3%)

    -
    pnlPriceClose: number

    Exit price from PNL calculation (adjusted with slippage and fees)

    -
    pnlPriceOpen: number

    Entry price from PNL calculation (effective price adjusted with slippage and fees)

    -
    position: "long" | "short"

    Trade direction: "long" (buy) or "short" (sell)

    -
    priceOpen: number

    Entry price for the position

    -
    priceStopLoss: number

    Effective stop loss price (with trailing if set)

    -
    priceTakeProfit: number

    Effective take profit price (with trailing if set)

    -
    scheduledAt: number

    Signal creation timestamp in milliseconds (when signal was first created/scheduled)

    -
    signalId: string

    Unique signal identifier (UUID v4)

    -
    strategyName: string

    Strategy name that generated this signal

    -
    symbol: string

    Trading pair symbol (e.g., "BTCUSDT")

    -
    timestamp: number

    Unix timestamp in milliseconds when partial loss was committed

    -
    totalEntries: number

    Total number of DCA entries (_entry.length). 1 = no averaging.

    -
    totalPartials: number

    Total number of partial closes executed (_partial.length). 0 = no partial closes done.

    -
    type: "partial_loss.commit"

    Discriminator for type-safe union

    -
    +
    createdAt: number

    Unix timestamp in milliseconds when the notification was created

    +
    currentPrice: number

    Current market price when partial was executed

    +
    exchangeName: string

    Exchange name where signal was executed

    +
    id: string

    Unique notification identifier

    +
    maxDrawdown: IStrategyPnL

    Maximum drawdown experienced during the life of this position up to the moment this public signal was created

    +
    maxDrawdownCost: number

    Absolute profit/loss in USD at the moment the position reached its maximum drawdown during the life of this position

    +
    maxDrawdownEntries: number

    Number of entries executed at the moment the position reached its maximum drawdown during the life of this position

    +
    maxDrawdownPercentage: number

    Profit/loss as percentage at the moment the position reached its maximum drawdown during the life of this position

    +
    maxDrawdownPriceClose: number

    Exit price for PNL calculation at the moment of max drawdown

    +
    maxDrawdownPriceOpen: number

    Maximum drawdown price reached in loss direction during the life of this position

    +
    note?: string

    Optional human-readable description of signal reason

    +
    originalPriceOpen: number

    Original entry price at signal creation (unchanged by DCA averaging)

    +
    originalPriceStopLoss: number

    Original stop loss price before any trailing adjustments

    +
    originalPriceTakeProfit: number

    Original take profit price before any trailing adjustments

    +
    peakProfit: IStrategyPnL

    Peak profit achieved during the life of this position up to the moment this public signal was created

    +
    peakProfitCost: number

    Absolute profit/loss in USD at the moment the position reached its peak profit during the life of this position

    +
    peakProfitEntries: number

    Number of entries executed at the moment the position reached its peak profit during the life of this position

    +
    peakProfitPercentage: number

    Profit/loss as percentage at the moment the position reached its peak profit during the life of this position

    +
    peakProfitPriceClose: number

    Exit price for PNL calculation at the moment of peak profit

    +
    peakProfitPriceOpen: number

    Peak price reached in profit direction during the life of this position

    +
    pendingAt: number

    Pending timestamp in milliseconds (when position became pending/active at priceOpen)

    +
    percentToClose: number

    Percentage of position closed (0-100)

    +

    Total PNL of the closed position (including all entries and partials)

    +
    pnlCost: number

    Absolute profit/loss in USD

    +
    pnlEntries: number

    Total invested capital in USD

    +
    pnlPercentage: number

    Profit/loss as percentage (e.g., 1.5 for +1.5%, -2.3 for -2.3%)

    +
    pnlPriceClose: number

    Exit price from PNL calculation (adjusted with slippage and fees)

    +
    pnlPriceOpen: number

    Entry price from PNL calculation (effective price adjusted with slippage and fees)

    +
    position: "long" | "short"

    Trade direction: "long" (buy) or "short" (sell)

    +
    priceOpen: number

    Entry price for the position

    +
    priceStopLoss: number

    Effective stop loss price (with trailing if set)

    +
    priceTakeProfit: number

    Effective take profit price (with trailing if set)

    +
    scheduledAt: number

    Signal creation timestamp in milliseconds (when signal was first created/scheduled)

    +
    signalId: string

    Unique signal identifier (UUID v4)

    +
    strategyName: string

    Strategy name that generated this signal

    +
    symbol: string

    Trading pair symbol (e.g., "BTCUSDT")

    +
    timestamp: number

    Unix timestamp in milliseconds when partial loss was committed

    +
    totalEntries: number

    Total number of DCA entries (_entry.length). 1 = no averaging.

    +
    totalPartials: number

    Total number of partial closes executed (_partial.length). 0 = no partial closes done.

    +
    type: "partial_loss.commit"

    Discriminator for type-safe union

    +

    Interface PartialProfitAvailableNotification

    Partial profit notification. Emitted when signal reaches profit level milestone (10%, 20%, etc).

    -
    interface PartialProfitAvailableNotification {
        backtest: boolean;
        createdAt: number;
        currentPrice: number;
        exchangeName: string;
        id: string;
        level: PartialLevel;
        maxDrawdown: IStrategyPnL;
        maxDrawdownCost: number;
        maxDrawdownEntries: number;
        maxDrawdownPercentage: number;
        maxDrawdownPriceClose: number;
        maxDrawdownPriceOpen: number;
        note?: string;
        originalPriceOpen: number;
        originalPriceStopLoss: number;
        originalPriceTakeProfit: number;
        peakProfit: IStrategyPnL;
        peakProfitCost: number;
        peakProfitEntries: number;
        peakProfitPercentage: number;
        peakProfitPriceClose: number;
        peakProfitPriceOpen: number;
        pendingAt: number;
        pnl: IStrategyPnL;
        pnlCost: number;
        pnlEntries: number;
        pnlPercentage: number;
        pnlPriceClose: number;
        pnlPriceOpen: number;
        position: "long" | "short";
        priceOpen: number;
        priceStopLoss: number;
        priceTakeProfit: number;
        scheduledAt: number;
        signalId: string;
        strategyName: string;
        symbol: string;
        timestamp: number;
        totalEntries: number;
        totalPartials: number;
        type: "partial_profit.available";
    }

    Properties

    interface PartialProfitAvailableNotification {
        backtest: boolean;
        createdAt: number;
        currentPrice: number;
        exchangeName: string;
        id: string;
        level: PartialLevel;
        maxDrawdown: IStrategyPnL;
        maxDrawdownCost: number;
        maxDrawdownEntries: number;
        maxDrawdownPercentage: number;
        maxDrawdownPriceClose: number;
        maxDrawdownPriceOpen: number;
        note?: string;
        originalPriceOpen: number;
        originalPriceStopLoss: number;
        originalPriceTakeProfit: number;
        peakProfit: IStrategyPnL;
        peakProfitCost: number;
        peakProfitEntries: number;
        peakProfitPercentage: number;
        peakProfitPriceClose: number;
        peakProfitPriceOpen: number;
        pendingAt: number;
        pnl: IStrategyPnL;
        pnlCost: number;
        pnlEntries: number;
        pnlPercentage: number;
        pnlPriceClose: number;
        pnlPriceOpen: number;
        position: "long" | "short";
        priceOpen: number;
        priceStopLoss: number;
        priceTakeProfit: number;
        scheduledAt: number;
        signalId: string;
        strategyName: string;
        symbol: string;
        timestamp: number;
        totalEntries: number;
        totalPartials: number;
        type: "partial_profit.available";
    }

    Properties

    backtest createdAt currentPrice exchangeName @@ -42,47 +42,47 @@ Emitted when signal reaches profit level milestone (10%, 20%, etc).

    totalPartials type

    Properties

    backtest: boolean

    Whether this notification is from backtest mode (true) or live mode (false)

    -
    createdAt: number

    Unix timestamp in milliseconds when the notification was created

    -
    currentPrice: number

    Current market price when milestone was reached

    -
    exchangeName: string

    Exchange name where signal was executed

    -
    id: string

    Unique notification identifier

    -
    level: PartialLevel

    Profit level milestone reached (10, 20, 30, etc)

    -
    maxDrawdown: IStrategyPnL

    Maximum drawdown experienced during the life of this position up to the moment this public signal was created

    -
    maxDrawdownCost: number

    Absolute profit/loss in USD at the moment the position reached its maximum drawdown during the life of this position

    -
    maxDrawdownEntries: number

    Number of entries executed at the moment the position reached its maximum drawdown during the life of this position

    -
    maxDrawdownPercentage: number

    Profit/loss as percentage at the moment the position reached its maximum drawdown during the life of this position

    -
    maxDrawdownPriceClose: number

    Exit price for PNL calculation at the moment of max drawdown

    -
    maxDrawdownPriceOpen: number

    Maximum drawdown price reached in loss direction during the life of this position

    -
    note?: string

    Optional human-readable description of signal reason

    -
    originalPriceOpen: number

    Original entry price at signal creation (unchanged by DCA averaging)

    -
    originalPriceStopLoss: number

    Original stop loss price before any trailing adjustments

    -
    originalPriceTakeProfit: number

    Original take profit price before any trailing adjustments

    -
    peakProfit: IStrategyPnL

    Peak profit achieved during the life of this position up to the moment this public signal was created

    -
    peakProfitCost: number

    Absolute profit/loss in USD at the moment the position reached its peak profit during the life of this position

    -
    peakProfitEntries: number

    Number of entries executed at the moment the position reached its peak profit during the life of this position

    -
    peakProfitPercentage: number

    Profit/loss as percentage at the moment the position reached its peak profit during the life of this position

    -
    peakProfitPriceClose: number

    Exit price for PNL calculation at the moment of peak profit

    -
    peakProfitPriceOpen: number

    Peak price reached in profit direction during the life of this position

    -
    pendingAt: number

    Pending timestamp in milliseconds (when position became pending/active at priceOpen)

    -

    Total PNL of the closed position (including all entries and partials)

    -
    pnlCost: number

    Absolute profit/loss in USD

    -
    pnlEntries: number

    Total invested capital in USD

    -
    pnlPercentage: number

    Profit/loss as percentage (e.g., 1.5 for +1.5%, -2.3 for -2.3%)

    -
    pnlPriceClose: number

    Exit price from PNL calculation (adjusted with slippage and fees)

    -
    pnlPriceOpen: number

    Entry price from PNL calculation (effective price adjusted with slippage and fees)

    -
    position: "long" | "short"

    Trade direction: "long" (buy) or "short" (sell)

    -
    priceOpen: number

    Entry price for the position

    -
    priceStopLoss: number

    Effective stop loss price (with trailing if set)

    -
    priceTakeProfit: number

    Effective take profit price (with trailing if set)

    -
    scheduledAt: number

    Signal creation timestamp in milliseconds (when signal was first created/scheduled)

    -
    signalId: string

    Unique signal identifier (UUID v4)

    -
    strategyName: string

    Strategy name that generated this signal

    -
    symbol: string

    Trading pair symbol (e.g., "BTCUSDT")

    -
    timestamp: number

    Unix timestamp in milliseconds when partial profit level was reached

    -
    totalEntries: number

    Total number of DCA entries (_entry.length). 1 = no averaging.

    -
    totalPartials: number

    Total number of partial closes executed (_partial.length). 0 = no partial closes done.

    -
    type: "partial_profit.available"

    Discriminator for type-safe union

    -
    +
    createdAt: number

    Unix timestamp in milliseconds when the notification was created

    +
    currentPrice: number

    Current market price when milestone was reached

    +
    exchangeName: string

    Exchange name where signal was executed

    +
    id: string

    Unique notification identifier

    +
    level: PartialLevel

    Profit level milestone reached (10, 20, 30, etc)

    +
    maxDrawdown: IStrategyPnL

    Maximum drawdown experienced during the life of this position up to the moment this public signal was created

    +
    maxDrawdownCost: number

    Absolute profit/loss in USD at the moment the position reached its maximum drawdown during the life of this position

    +
    maxDrawdownEntries: number

    Number of entries executed at the moment the position reached its maximum drawdown during the life of this position

    +
    maxDrawdownPercentage: number

    Profit/loss as percentage at the moment the position reached its maximum drawdown during the life of this position

    +
    maxDrawdownPriceClose: number

    Exit price for PNL calculation at the moment of max drawdown

    +
    maxDrawdownPriceOpen: number

    Maximum drawdown price reached in loss direction during the life of this position

    +
    note?: string

    Optional human-readable description of signal reason

    +
    originalPriceOpen: number

    Original entry price at signal creation (unchanged by DCA averaging)

    +
    originalPriceStopLoss: number

    Original stop loss price before any trailing adjustments

    +
    originalPriceTakeProfit: number

    Original take profit price before any trailing adjustments

    +
    peakProfit: IStrategyPnL

    Peak profit achieved during the life of this position up to the moment this public signal was created

    +
    peakProfitCost: number

    Absolute profit/loss in USD at the moment the position reached its peak profit during the life of this position

    +
    peakProfitEntries: number

    Number of entries executed at the moment the position reached its peak profit during the life of this position

    +
    peakProfitPercentage: number

    Profit/loss as percentage at the moment the position reached its peak profit during the life of this position

    +
    peakProfitPriceClose: number

    Exit price for PNL calculation at the moment of peak profit

    +
    peakProfitPriceOpen: number

    Peak price reached in profit direction during the life of this position

    +
    pendingAt: number

    Pending timestamp in milliseconds (when position became pending/active at priceOpen)

    +

    Total PNL of the closed position (including all entries and partials)

    +
    pnlCost: number

    Absolute profit/loss in USD

    +
    pnlEntries: number

    Total invested capital in USD

    +
    pnlPercentage: number

    Profit/loss as percentage (e.g., 1.5 for +1.5%, -2.3 for -2.3%)

    +
    pnlPriceClose: number

    Exit price from PNL calculation (adjusted with slippage and fees)

    +
    pnlPriceOpen: number

    Entry price from PNL calculation (effective price adjusted with slippage and fees)

    +
    position: "long" | "short"

    Trade direction: "long" (buy) or "short" (sell)

    +
    priceOpen: number

    Entry price for the position

    +
    priceStopLoss: number

    Effective stop loss price (with trailing if set)

    +
    priceTakeProfit: number

    Effective take profit price (with trailing if set)

    +
    scheduledAt: number

    Signal creation timestamp in milliseconds (when signal was first created/scheduled)

    +
    signalId: string

    Unique signal identifier (UUID v4)

    +
    strategyName: string

    Strategy name that generated this signal

    +
    symbol: string

    Trading pair symbol (e.g., "BTCUSDT")

    +
    timestamp: number

    Unix timestamp in milliseconds when partial profit level was reached

    +
    totalEntries: number

    Total number of DCA entries (_entry.length). 1 = no averaging.

    +
    totalPartials: number

    Total number of partial closes executed (_partial.length). 0 = no partial closes done.

    +
    type: "partial_profit.available"

    Discriminator for type-safe union

    +

    Interface PartialProfitCommit

    Partial profit event.

    -
    interface PartialProfitCommit {
        action: "partial-profit";
        backtest: boolean;
        currentPrice: number;
        exchangeName: string;
        frameName: string;
        maxDrawdown: IStrategyPnL;
        note?: string;
        originalPriceOpen: number;
        originalPriceStopLoss: number;
        originalPriceTakeProfit: number;
        peakProfit: IStrategyPnL;
        pendingAt: number;
        percentToClose: number;
        pnl: IStrategyPnL;
        position: "long" | "short";
        priceOpen: number;
        priceStopLoss: number;
        priceTakeProfit: number;
        scheduledAt: number;
        signal: IPublicSignalRow;
        signalId: string;
        strategyName: string;
        symbol: string;
        timestamp: number;
        totalEntries: number;
        totalPartials: number;
    }

    Hierarchy

    • SignalCommitBase
      • PartialProfitCommit

    Properties

    interface PartialProfitCommit {
        action: "partial-profit";
        backtest: boolean;
        currentPrice: number;
        exchangeName: string;
        frameName: string;
        maxDrawdown: IStrategyPnL;
        note?: string;
        originalPriceOpen: number;
        originalPriceStopLoss: number;
        originalPriceTakeProfit: number;
        peakProfit: IStrategyPnL;
        pendingAt: number;
        percentToClose: number;
        pnl: IStrategyPnL;
        position: "long" | "short";
        priceOpen: number;
        priceStopLoss: number;
        priceTakeProfit: number;
        scheduledAt: number;
        signal: IPublicSignalRow;
        signalId: string;
        strategyName: string;
        symbol: string;
        timestamp: number;
        totalEntries: number;
        totalPartials: number;
    }

    Hierarchy

    • SignalCommitBase
      • PartialProfitCommit

    Properties

    action: "partial-profit"

    Discriminator for partial-profit action

    -
    backtest: boolean

    Whether this event is from backtest mode (true) or live mode (false)

    -
    currentPrice: number

    Current market price at time of action

    -
    exchangeName: string

    Exchange name where signal was executed

    -
    frameName: string

    Timeframe name (used in backtest mode, empty string in live mode)

    -
    maxDrawdown: IStrategyPnL

    Maximum drawdown experienced during the life of this position up to the moment this public signal was created

    -
    note?: string

    Optional human-readable description of signal reason

    -
    originalPriceOpen: number

    Original entry price at signal creation (unchanged by DCA averaging).

    -
    originalPriceStopLoss: number

    Original stop loss price before any trailing adjustments

    -
    originalPriceTakeProfit: number

    Original take profit price before any trailing adjustments

    -
    peakProfit: IStrategyPnL

    Peak profit achieved during the life of this position up to the moment this public signal was created

    -
    pendingAt: number

    Position activation timestamp in milliseconds (when price reached priceOpen)

    -
    percentToClose: number

    Percentage of position to close (0-100)

    -

    Total PNL of the closed position (including all entries and partials)

    -
    position: "long" | "short"

    Trade direction: "long" (buy) or "short" (sell)

    -
    priceOpen: number

    Entry price for the position

    -
    priceStopLoss: number

    Effective stop loss price (may differ from original after trailing)

    -
    priceTakeProfit: number

    Effective take profit price (may differ from original after trailing)

    -
    scheduledAt: number

    Signal creation timestamp in milliseconds

    -

    Signal data at the moment of this event (snapshot of IPublicSignalRow)

    -
    signalId: string

    Unique signal identifier (UUID v4)

    -
    strategyName: string

    Strategy name that generated this signal

    -
    symbol: string

    Trading pair symbol (e.g., "BTCUSDT")

    -
    timestamp: number

    Timestamp from execution context (tick's when or backtest candle timestamp)

    -
    totalEntries: number

    Total number of DCA entries at the time of this event (_entry.length). +

    backtest: boolean

    Whether this event is from backtest mode (true) or live mode (false)

    +
    currentPrice: number

    Current market price at time of action

    +
    exchangeName: string

    Exchange name where signal was executed

    +
    frameName: string

    Timeframe name (used in backtest mode, empty string in live mode)

    +
    maxDrawdown: IStrategyPnL

    Maximum drawdown experienced during the life of this position up to the moment this public signal was created

    +
    note?: string

    Optional human-readable description of signal reason

    +
    originalPriceOpen: number

    Original entry price at signal creation (unchanged by DCA averaging).

    +
    originalPriceStopLoss: number

    Original stop loss price before any trailing adjustments

    +
    originalPriceTakeProfit: number

    Original take profit price before any trailing adjustments

    +
    peakProfit: IStrategyPnL

    Peak profit achieved during the life of this position up to the moment this public signal was created

    +
    pendingAt: number

    Position activation timestamp in milliseconds (when price reached priceOpen)

    +
    percentToClose: number

    Percentage of position to close (0-100)

    +

    Total PNL of the closed position (including all entries and partials)

    +
    position: "long" | "short"

    Trade direction: "long" (buy) or "short" (sell)

    +
    priceOpen: number

    Entry price for the position

    +
    priceStopLoss: number

    Effective stop loss price (may differ from original after trailing)

    +
    priceTakeProfit: number

    Effective take profit price (may differ from original after trailing)

    +
    scheduledAt: number

    Signal creation timestamp in milliseconds

    +

    Signal data at the moment of this event (snapshot of IPublicSignalRow)

    +
    signalId: string

    Unique signal identifier (UUID v4)

    +
    strategyName: string

    Strategy name that generated this signal

    +
    symbol: string

    Trading pair symbol (e.g., "BTCUSDT")

    +
    timestamp: number

    Timestamp from execution context (tick's when or backtest candle timestamp)

    +
    totalEntries: number

    Total number of DCA entries at the time of this event (_entry.length). 1 = no averaging done (only initial entry). 2+ = averaged positions.

    -
    totalPartials: number

    Total number of partial closes executed at the time of this event (_partial.length). +

    totalPartials: number

    Total number of partial closes executed at the time of this event (_partial.length). 0 = no partial closes done. 1+ = partial closes executed.

    -
    +

    Interface PartialProfitCommitNotification

    Partial profit commit notification. Emitted when partial profit action is executed.

    -
    interface PartialProfitCommitNotification {
        backtest: boolean;
        createdAt: number;
        currentPrice: number;
        exchangeName: string;
        id: string;
        maxDrawdown: IStrategyPnL;
        maxDrawdownCost: number;
        maxDrawdownEntries: number;
        maxDrawdownPercentage: number;
        maxDrawdownPriceClose: number;
        maxDrawdownPriceOpen: number;
        note?: string;
        originalPriceOpen: number;
        originalPriceStopLoss: number;
        originalPriceTakeProfit: number;
        peakProfit: IStrategyPnL;
        peakProfitCost: number;
        peakProfitEntries: number;
        peakProfitPercentage: number;
        peakProfitPriceClose: number;
        peakProfitPriceOpen: number;
        pendingAt: number;
        percentToClose: number;
        pnl: IStrategyPnL;
        pnlCost: number;
        pnlEntries: number;
        pnlPercentage: number;
        pnlPriceClose: number;
        pnlPriceOpen: number;
        position: "long" | "short";
        priceOpen: number;
        priceStopLoss: number;
        priceTakeProfit: number;
        scheduledAt: number;
        signalId: string;
        strategyName: string;
        symbol: string;
        timestamp: number;
        totalEntries: number;
        totalPartials: number;
        type: "partial_profit.commit";
    }

    Properties

    interface PartialProfitCommitNotification {
        backtest: boolean;
        createdAt: number;
        currentPrice: number;
        exchangeName: string;
        id: string;
        maxDrawdown: IStrategyPnL;
        maxDrawdownCost: number;
        maxDrawdownEntries: number;
        maxDrawdownPercentage: number;
        maxDrawdownPriceClose: number;
        maxDrawdownPriceOpen: number;
        note?: string;
        originalPriceOpen: number;
        originalPriceStopLoss: number;
        originalPriceTakeProfit: number;
        peakProfit: IStrategyPnL;
        peakProfitCost: number;
        peakProfitEntries: number;
        peakProfitPercentage: number;
        peakProfitPriceClose: number;
        peakProfitPriceOpen: number;
        pendingAt: number;
        percentToClose: number;
        pnl: IStrategyPnL;
        pnlCost: number;
        pnlEntries: number;
        pnlPercentage: number;
        pnlPriceClose: number;
        pnlPriceOpen: number;
        position: "long" | "short";
        priceOpen: number;
        priceStopLoss: number;
        priceTakeProfit: number;
        scheduledAt: number;
        signalId: string;
        strategyName: string;
        symbol: string;
        timestamp: number;
        totalEntries: number;
        totalPartials: number;
        type: "partial_profit.commit";
    }

    Properties

    backtest createdAt currentPrice exchangeName @@ -42,47 +42,47 @@ Emitted when partial profit action is executed.

    totalPartials type

    Properties

    backtest: boolean

    Whether this notification is from backtest mode (true) or live mode (false)

    -
    createdAt: number

    Unix timestamp in milliseconds when the notification was created

    -
    currentPrice: number

    Current market price when partial was executed

    -
    exchangeName: string

    Exchange name where signal was executed

    -
    id: string

    Unique notification identifier

    -
    maxDrawdown: IStrategyPnL

    Maximum drawdown experienced during the life of this position up to the moment this public signal was created

    -
    maxDrawdownCost: number

    Absolute profit/loss in USD at the moment the position reached its maximum drawdown during the life of this position

    -
    maxDrawdownEntries: number

    Number of entries executed at the moment the position reached its maximum drawdown during the life of this position

    -
    maxDrawdownPercentage: number

    Profit/loss as percentage at the moment the position reached its maximum drawdown during the life of this position

    -
    maxDrawdownPriceClose: number

    Exit price for PNL calculation at the moment of max drawdown

    -
    maxDrawdownPriceOpen: number

    Maximum drawdown price reached in loss direction during the life of this position

    -
    note?: string

    Optional human-readable description of signal reason

    -
    originalPriceOpen: number

    Original entry price at signal creation (unchanged by DCA averaging)

    -
    originalPriceStopLoss: number

    Original stop loss price before any trailing adjustments

    -
    originalPriceTakeProfit: number

    Original take profit price before any trailing adjustments

    -
    peakProfit: IStrategyPnL

    Peak profit achieved during the life of this position up to the moment this public signal was created

    -
    peakProfitCost: number

    Absolute profit/loss in USD at the moment the position reached its peak profit during the life of this position

    -
    peakProfitEntries: number

    Number of entries executed at the moment the position reached its peak profit during the life of this position

    -
    peakProfitPercentage: number

    Profit/loss as percentage at the moment the position reached its peak profit during the life of this position

    -
    peakProfitPriceClose: number

    Exit price for PNL calculation at the moment of peak profit

    -
    peakProfitPriceOpen: number

    Peak price reached in profit direction during the life of this position

    -
    pendingAt: number

    Pending timestamp in milliseconds (when position became pending/active at priceOpen)

    -
    percentToClose: number

    Percentage of position closed (0-100)

    -

    Total PNL of the closed position (including all entries and partials)

    -
    pnlCost: number

    Absolute profit/loss in USD

    -
    pnlEntries: number

    Total invested capital in USD

    -
    pnlPercentage: number

    Profit/loss as percentage (e.g., 1.5 for +1.5%, -2.3 for -2.3%)

    -
    pnlPriceClose: number

    Exit price from PNL calculation (adjusted with slippage and fees)

    -
    pnlPriceOpen: number

    Entry price from PNL calculation (effective price adjusted with slippage and fees)

    -
    position: "long" | "short"

    Trade direction: "long" (buy) or "short" (sell)

    -
    priceOpen: number

    Entry price for the position

    -
    priceStopLoss: number

    Effective stop loss price (with trailing if set)

    -
    priceTakeProfit: number

    Effective take profit price (with trailing if set)

    -
    scheduledAt: number

    Signal creation timestamp in milliseconds (when signal was first created/scheduled)

    -
    signalId: string

    Unique signal identifier (UUID v4)

    -
    strategyName: string

    Strategy name that generated this signal

    -
    symbol: string

    Trading pair symbol (e.g., "BTCUSDT")

    -
    timestamp: number

    Unix timestamp in milliseconds when partial profit was committed

    -
    totalEntries: number

    Total number of DCA entries (_entry.length). 1 = no averaging.

    -
    totalPartials: number

    Total number of partial closes executed (_partial.length). 0 = no partial closes done.

    -
    type: "partial_profit.commit"

    Discriminator for type-safe union

    -
    +
    createdAt: number

    Unix timestamp in milliseconds when the notification was created

    +
    currentPrice: number

    Current market price when partial was executed

    +
    exchangeName: string

    Exchange name where signal was executed

    +
    id: string

    Unique notification identifier

    +
    maxDrawdown: IStrategyPnL

    Maximum drawdown experienced during the life of this position up to the moment this public signal was created

    +
    maxDrawdownCost: number

    Absolute profit/loss in USD at the moment the position reached its maximum drawdown during the life of this position

    +
    maxDrawdownEntries: number

    Number of entries executed at the moment the position reached its maximum drawdown during the life of this position

    +
    maxDrawdownPercentage: number

    Profit/loss as percentage at the moment the position reached its maximum drawdown during the life of this position

    +
    maxDrawdownPriceClose: number

    Exit price for PNL calculation at the moment of max drawdown

    +
    maxDrawdownPriceOpen: number

    Maximum drawdown price reached in loss direction during the life of this position

    +
    note?: string

    Optional human-readable description of signal reason

    +
    originalPriceOpen: number

    Original entry price at signal creation (unchanged by DCA averaging)

    +
    originalPriceStopLoss: number

    Original stop loss price before any trailing adjustments

    +
    originalPriceTakeProfit: number

    Original take profit price before any trailing adjustments

    +
    peakProfit: IStrategyPnL

    Peak profit achieved during the life of this position up to the moment this public signal was created

    +
    peakProfitCost: number

    Absolute profit/loss in USD at the moment the position reached its peak profit during the life of this position

    +
    peakProfitEntries: number

    Number of entries executed at the moment the position reached its peak profit during the life of this position

    +
    peakProfitPercentage: number

    Profit/loss as percentage at the moment the position reached its peak profit during the life of this position

    +
    peakProfitPriceClose: number

    Exit price for PNL calculation at the moment of peak profit

    +
    peakProfitPriceOpen: number

    Peak price reached in profit direction during the life of this position

    +
    pendingAt: number

    Pending timestamp in milliseconds (when position became pending/active at priceOpen)

    +
    percentToClose: number

    Percentage of position closed (0-100)

    +

    Total PNL of the closed position (including all entries and partials)

    +
    pnlCost: number

    Absolute profit/loss in USD

    +
    pnlEntries: number

    Total invested capital in USD

    +
    pnlPercentage: number

    Profit/loss as percentage (e.g., 1.5 for +1.5%, -2.3 for -2.3%)

    +
    pnlPriceClose: number

    Exit price from PNL calculation (adjusted with slippage and fees)

    +
    pnlPriceOpen: number

    Entry price from PNL calculation (effective price adjusted with slippage and fees)

    +
    position: "long" | "short"

    Trade direction: "long" (buy) or "short" (sell)

    +
    priceOpen: number

    Entry price for the position

    +
    priceStopLoss: number

    Effective stop loss price (with trailing if set)

    +
    priceTakeProfit: number

    Effective take profit price (with trailing if set)

    +
    scheduledAt: number

    Signal creation timestamp in milliseconds (when signal was first created/scheduled)

    +
    signalId: string

    Unique signal identifier (UUID v4)

    +
    strategyName: string

    Strategy name that generated this signal

    +
    symbol: string

    Trading pair symbol (e.g., "BTCUSDT")

    +
    timestamp: number

    Unix timestamp in milliseconds when partial profit was committed

    +
    totalEntries: number

    Total number of DCA entries (_entry.length). 1 = no averaging.

    +
    totalPartials: number

    Total number of partial closes executed (_partial.length). 0 = no partial closes done.

    +
    type: "partial_profit.commit"

    Discriminator for type-safe union

    +

    Interface PerformanceStatisticsModel

    Performance statistics aggregated by strategy.

    -
    interface PerformanceStatisticsModel {
        events: PerformanceContract[];
        metricStats: Record<string, MetricStats>;
        strategyName: string;
        totalDuration: number;
        totalEvents: number;
    }

    Properties

    interface PerformanceStatisticsModel {
        events: PerformanceContract[];
        metricStats: Record<string, MetricStats>;
        strategyName: string;
        totalDuration: number;
        totalEvents: number;
    }

    Properties

    All raw performance events

    -
    metricStats: Record<string, MetricStats>

    Statistics grouped by metric type

    -
    strategyName: string

    Strategy name

    -
    totalDuration: number

    Total execution time across all metrics (ms)

    -
    totalEvents: number

    Total number of performance events recorded

    -
    +
    metricStats: Record<string, MetricStats>

    Statistics grouped by metric type

    +
    strategyName: string

    Strategy name

    +
    totalDuration: number

    Total execution time across all metrics (ms)

    +
    totalEvents: number

    Total number of performance events recorded

    +

    Interface RiskEvent

    Risk rejection event data for report generation. Contains all information about rejected signals due to risk limits.

    -
    interface RiskEvent {
        activePositionCount: number;
        backtest: boolean;
        currentPrice: number;
        currentSignal: IRiskSignalRow;
        exchangeName: string;
        frameName: string;
        rejectionId: string;
        rejectionNote: string;
        strategyName: string;
        symbol: string;
        timestamp: number;
    }

    Properties

    interface RiskEvent {
        activePositionCount: number;
        backtest: boolean;
        currentPrice: number;
        currentSignal: IRiskSignalRow;
        exchangeName: string;
        frameName: string;
        rejectionId: string;
        rejectionNote: string;
        strategyName: string;
        symbol: string;
        timestamp: number;
    }

    Properties

    activePositionCount backtest currentPrice currentSignal @@ -12,17 +12,17 @@ Contains all information about rejected signals due to risk limits.

    symbol timestamp

    Properties

    activePositionCount: number

    Number of active positions at rejection time

    -
    backtest: boolean

    Whether this event is from backtest mode (true) or live mode (false)

    -
    currentPrice: number

    Current market price

    -
    currentSignal: IRiskSignalRow

    Pending signal details

    -
    exchangeName: string

    Exchange name

    -
    frameName: string

    Time frame name

    -
    rejectionId: string

    Unique identifier for this rejection instance (null if validation threw exception without custom ID)

    -
    rejectionNote: string

    Rejection reason from validation note

    -
    strategyName: string

    Strategy name

    -
    symbol: string

    Trading pair symbol

    -
    timestamp: number

    Event timestamp in milliseconds

    -
    +
    backtest: boolean

    Whether this event is from backtest mode (true) or live mode (false)

    +
    currentPrice: number

    Current market price

    +
    currentSignal: IRiskSignalRow

    Pending signal details

    +
    exchangeName: string

    Exchange name

    +
    frameName: string

    Time frame name

    +
    rejectionId: string

    Unique identifier for this rejection instance (null if validation threw exception without custom ID)

    +
    rejectionNote: string

    Rejection reason from validation note

    +
    strategyName: string

    Strategy name

    +
    symbol: string

    Trading pair symbol

    +
    timestamp: number

    Event timestamp in milliseconds

    +

    Interface RiskRejectionNotification

    Risk rejection notification. Emitted when a signal is rejected due to risk management rules.

    -
    interface RiskRejectionNotification {
        activePositionCount: number;
        backtest: boolean;
        createdAt: number;
        currentPrice: number;
        exchangeName: string;
        id: string;
        minuteEstimatedTime: number;
        position: "long" | "short";
        priceOpen: number;
        priceStopLoss: number;
        priceTakeProfit: number;
        rejectionId: string;
        rejectionNote: string;
        signalId: string;
        signalNote?: string;
        strategyName: string;
        symbol: string;
        timestamp: number;
        type: "risk.rejection";
    }

    Properties

    interface RiskRejectionNotification {
        activePositionCount: number;
        backtest: boolean;
        createdAt: number;
        currentPrice: number;
        exchangeName: string;
        id: string;
        minuteEstimatedTime: number;
        position: "long" | "short";
        priceOpen: number;
        priceStopLoss: number;
        priceTakeProfit: number;
        rejectionId: string;
        rejectionNote: string;
        signalId: string;
        signalNote?: string;
        strategyName: string;
        symbol: string;
        timestamp: number;
        type: "risk.rejection";
    }

    Properties

    activePositionCount backtest createdAt currentPrice @@ -20,25 +20,25 @@ Emitted when a signal is rejected due to risk management rules.

    timestamp type

    Properties

    activePositionCount: number

    Number of currently active positions at rejection time

    -
    backtest: boolean

    Whether this notification is from backtest mode (true) or live mode (false)

    -
    createdAt: number

    Unix timestamp in milliseconds when the notification was created

    -
    currentPrice: number

    Current market price when rejection occurred

    -
    exchangeName: string

    Exchange name where signal was rejected

    -
    id: string

    Unique notification identifier

    -
    minuteEstimatedTime: number

    Expected duration in minutes before time_expired

    -
    position: "long" | "short"

    Trade direction: "long" (buy) or "short" (sell)

    -
    priceOpen: number

    Entry price for the position (may be undefined if not provided)

    -
    priceStopLoss: number

    Stop loss exit price

    -
    priceTakeProfit: number

    Take profit target price

    -
    rejectionId: string

    Optional unique rejection identifier for tracking

    -
    rejectionNote: string

    Human-readable reason for rejection

    -
    signalId: string

    Unique signal identifier from pending signal (may be undefined if not provided)

    -
    signalNote?: string

    Optional human-readable description of signal reason

    -
    strategyName: string

    Strategy name that attempted to create signal

    -
    symbol: string

    Trading pair symbol (e.g., "BTCUSDT")

    -
    timestamp: number

    Unix timestamp in milliseconds when signal was rejected

    -
    type: "risk.rejection"

    Discriminator for type-safe union

    -
    +
    backtest: boolean

    Whether this notification is from backtest mode (true) or live mode (false)

    +
    createdAt: number

    Unix timestamp in milliseconds when the notification was created

    +
    currentPrice: number

    Current market price when rejection occurred

    +
    exchangeName: string

    Exchange name where signal was rejected

    +
    id: string

    Unique notification identifier

    +
    minuteEstimatedTime: number

    Expected duration in minutes before time_expired

    +
    position: "long" | "short"

    Trade direction: "long" (buy) or "short" (sell)

    +
    priceOpen: number

    Entry price for the position (may be undefined if not provided)

    +
    priceStopLoss: number

    Stop loss exit price

    +
    priceTakeProfit: number

    Take profit target price

    +
    rejectionId: string

    Optional unique rejection identifier for tracking

    +
    rejectionNote: string

    Human-readable reason for rejection

    +
    signalId: string

    Unique signal identifier from pending signal (may be undefined if not provided)

    +
    signalNote?: string

    Optional human-readable description of signal reason

    +
    strategyName: string

    Strategy name that attempted to create signal

    +
    symbol: string

    Trading pair symbol (e.g., "BTCUSDT")

    +
    timestamp: number

    Unix timestamp in milliseconds when signal was rejected

    +
    type: "risk.rejection"

    Discriminator for type-safe union

    +

    Interface ScheduleEventContract

    Contract for scheduled signal lifecycle events (creation and cancellation).

    +

    Emitted by scheduleEventSubject when a scheduled signal is created (added) or cancelled +during tick()/backtest() processing. Lets consumers track the scheduled phase of a signal +without subscribing to the full signal stream.

    +

    IMPORTANT: The scheduled -> active transition (activation) is intentionally NOT emitted here. +Activation produces an "opened" signal on the regular signal emitters; this contract only +covers a scheduled signal being put in place and being removed before it ever opened.

    +

    Consumers:

    +
      +
    • User callbacks via listenScheduleEvent() / listenScheduleEventOnce()
    • +
    +
    import { listenScheduleEvent } from "backtest-kit";

    listenScheduleEvent((event) => {
    if (event.action === "scheduled") {
    console.log(`Scheduled ${event.symbol} @ ${event.data.priceOpen}`);
    } else {
    console.log(`Cancelled ${event.symbol} (reason: ${event.reason})`);
    }
    }); +
    + +
    interface ScheduleEventContract {
        action: "scheduled" | "cancelled";
        backtest: boolean;
        currentPrice: number;
        data: IPublicSignalRow;
        exchangeName: string;
        frameName: string;
        reason?: StrategyCancelReason;
        strategyName: string;
        symbol: string;
        timestamp: number;
    }

    Properties

    action: "scheduled" | "cancelled"

    Lifecycle action for the scheduled signal.

    +
      +
    • "scheduled": a new scheduled signal was created (waiting for priceOpen activation)
    • +
    • "cancelled": the scheduled signal was removed before activation (timeout / price reject / user)
    • +
    +
    backtest: boolean

    Execution mode flag.

    +
      +
    • true: Event from backtest execution (historical candle data)
    • +
    • false: Event from live trading (real-time tick)
    • +
    +
    currentPrice: number

    Current market price of the symbol at the time of the event.

    +

    Complete scheduled signal row data in public form. +Contains all signal information: id, position, priceOpen, priceTakeProfit, priceStopLoss, etc.

    +
    exchangeName: string

    Exchange name where this scheduled signal lives.

    +
    frameName: string

    Frame name (timeframe / date range) for the run. Empty string in live mode. +Same value as the signal's frameName (data.frameName).

    +

    Cancellation reason. Present only when action === "cancelled":

    +
      +
    • "timeout": CC_SCHEDULE_AWAIT_MINUTES elapsed without reaching priceOpen
    • +
    • "price_reject": price hit stop-loss before activation
    • +
    • "user": cancelled via cancelScheduled()
    • +
    +

    Always undefined when action === "scheduled".

    +
    strategyName: string

    Strategy name that owns this scheduled signal.

    +
    symbol: string

    Trading pair symbol (e.g., "BTCUSDT"). +Identifies which market this event belongs to.

    +
    timestamp: number

    Event timestamp in milliseconds since Unix epoch.

    +

    Timing semantics:

    +
      +
    • Live mode: when.getTime() at the moment of the event
    • +
    • Backtest mode: candle.timestamp of the candle being processed
    • +
    +
    + + + + + + + + + diff --git a/interfaces/types.SchedulePingContract.html b/interfaces/types.SchedulePingContract.html index 2b89e7601d433746a3a9eeda8f983e19c9bc9ad9..103febc0c635f34cfbf45c604a784b1c89f2fc7d 100644 --- a/interfaces/types.SchedulePingContract.html +++ b/interfaces/types.SchedulePingContract.html @@ -10,7 +10,7 @@ Allows users to implement custom cancellation logic via onSchedulePing callback.
    import { listenSchedulePing } from "backtest-kit";

    // Listen to all schedule ping events
    listenSchedulePing((event) => {
    console.log(`[${event.backtest ? "Backtest" : "Live"}] Schedule Ping for ${event.symbol}`);
    console.log(`Strategy: ${event.strategyName}, Exchange: ${event.exchangeName}`);
    console.log(`Signal ID: ${event.data.id}, priceOpen: ${event.data.priceOpen}`);
    console.log(`Timestamp: ${new Date(event.timestamp).toISOString()}`);
    });

    // Wait for specific schedule ping
    listenSchedulePingOnce(
    (event) => event.symbol === "BTCUSDT",
    (event) => console.log("BTCUSDT schedule ping received:", event.timestamp)
    );
    -
    interface SchedulePingContract {
        backtest: boolean;
        currentPrice: number;
        data: IScheduledSignalRow;
        exchangeName: string;
        frameName: string;
        strategyName: string;
        symbol: string;
        timestamp: number;
    }

    Properties

    interface SchedulePingContract {
        backtest: boolean;
        currentPrice: number;
        data: IScheduledSignalRow;
        exchangeName: string;
        frameName: string;
        strategyName: string;
        symbol: string;
        timestamp: number;
    }

    Properties

    backtest currentPrice data exchangeName @@ -23,22 +23,22 @@ Allows users to implement custom cancellation logic via onSchedulePing callback.
  • true: Event from backtest execution (historical candle data)
  • false: Event from live trading (real-time tick)
  • -
    currentPrice: number

    Current market price of the symbol at the time of the ping. +

    currentPrice: number

    Current market price of the symbol at the time of the ping. Useful for users to implement custom monitoring logic based on price conditions. For example, users can choose to cancel the scheduled signal if the price moves too far from priceOpen. Note: This is the current price at the time of the ping, not necessarily the priceOpen of the signal.

    -

    Complete scheduled signal row data. +

    Complete scheduled signal row data. Contains all signal information: id, position, priceOpen, priceTakeProfit, priceStopLoss, etc.

    -
    exchangeName: string

    Exchange name where this scheduled signal is being monitored. +

    exchangeName: string

    Exchange name where this scheduled signal is being monitored. Identifies which exchange this ping event belongs to.

    -
    frameName: string

    Frame name (timeframe / date range) for the run. Empty string in live +

    frameName: string

    Frame name (timeframe / date range) for the run. Empty string in live mode, where frames are not used. Same value as the monitored signal's frameName (data.frameName).

    -
    strategyName: string

    Strategy name that is monitoring this scheduled signal. +

    strategyName: string

    Strategy name that is monitoring this scheduled signal. Identifies which strategy execution this ping event belongs to.

    -
    symbol: string

    Trading pair symbol (e.g., "BTCUSDT"). +

    symbol: string

    Trading pair symbol (e.g., "BTCUSDT"). Identifies which market this ping event belongs to.

    -
    timestamp: number

    Event timestamp in milliseconds since Unix epoch.

    +
    timestamp: number

    Event timestamp in milliseconds since Unix epoch.

    Timing semantics:

    • Live mode: when.getTime() at the moment of ping
    • @@ -47,7 +47,7 @@ Identifies which market this ping event belongs to.

    const eventDate = new Date(event.timestamp);
    console.log(`Ping at: ${eventDate.toISOString()}`);
    -
    +

    Interface ScheduledEvent

    Unified scheduled signal event data for report generation. Contains all information about scheduled, opened and cancelled events.

    -
    interface ScheduledEvent {
        action: "opened" | "scheduled" | "cancelled";
        cancelId?: string;
        cancelReason?: "timeout" | "user" | "price_reject";
        closeTimestamp?: number;
        currentPrice: number;
        duration?: number;
        note?: string;
        originalPriceOpen?: number;
        originalPriceStopLoss?: number;
        originalPriceTakeProfit?: number;
        partialExecuted?: number;
        pendingAt?: number;
        pnl?: IStrategyPnL;
        position: string;
        priceOpen: number;
        priceStopLoss: number;
        priceTakeProfit: number;
        scheduledAt?: number;
        signalId: string;
        symbol: string;
        timestamp: number;
        totalEntries?: number;
        totalPartials?: number;
    }

    Properties

    interface ScheduledEvent {
        action: "scheduled" | "cancelled" | "opened";
        cancelId?: string;
        cancelReason?: "timeout" | "user" | "price_reject";
        closeTimestamp?: number;
        currentPrice: number;
        duration?: number;
        note?: string;
        originalPriceOpen?: number;
        originalPriceStopLoss?: number;
        originalPriceTakeProfit?: number;
        partialExecuted?: number;
        pendingAt?: number;
        pnl?: IStrategyPnL;
        position: string;
        priceOpen: number;
        priceStopLoss: number;
        priceTakeProfit: number;
        scheduledAt?: number;
        signalId: string;
        symbol: string;
        timestamp: number;
        totalEntries?: number;
        totalPartials?: number;
    }

    Properties

    action cancelId? cancelReason? closeTimestamp? @@ -23,30 +23,30 @@ Contains all information about scheduled, opened and cancelled events.

    timestamp totalEntries? totalPartials? -

    Properties

    action: "opened" | "scheduled" | "cancelled"

    Event action type

    -
    cancelId?: string

    Cancellation ID (only for user-initiated cancellations)

    -
    cancelReason?: "timeout" | "user" | "price_reject"

    Cancellation reason (only for cancelled events)

    -
    closeTimestamp?: number

    Close timestamp (only for cancelled)

    -
    currentPrice: number

    Current market price

    -
    duration?: number

    Duration in minutes (only for cancelled/opened)

    -
    note?: string

    Signal note

    -
    originalPriceOpen?: number

    Original entry price before DCA averaging (present when averageBuy was applied)

    -
    originalPriceStopLoss?: number

    Original stop loss price before modifications

    -
    originalPriceTakeProfit?: number

    Original take profit price before modifications

    -
    partialExecuted?: number

    Total executed percentage from partial closes

    -
    pendingAt?: number

    Timestamp when position became active (only for opened events)

    -

    Unrealized PNL at the moment of this event

    -
    position: string

    Position type

    -
    priceOpen: number

    Scheduled entry price

    -
    priceStopLoss: number

    Stop loss price

    -
    priceTakeProfit: number

    Take profit price

    -
    scheduledAt?: number

    Timestamp when signal was created/scheduled (for all events)

    -
    signalId: string

    Signal ID

    -
    symbol: string

    Trading pair symbol

    -
    timestamp: number

    Event timestamp in milliseconds (scheduledAt for scheduled/cancelled events)

    -
    totalEntries?: number

    Total number of DCA entries (present when averageBuy was applied)

    -
    totalPartials?: number

    Total number of partial closes executed (_partial.length)

    -
    +

    Properties

    action: "scheduled" | "cancelled" | "opened"

    Event action type

    +
    cancelId?: string

    Cancellation ID (only for user-initiated cancellations)

    +
    cancelReason?: "timeout" | "user" | "price_reject"

    Cancellation reason (only for cancelled events)

    +
    closeTimestamp?: number

    Close timestamp (only for cancelled)

    +
    currentPrice: number

    Current market price

    +
    duration?: number

    Duration in minutes (only for cancelled/opened)

    +
    note?: string

    Signal note

    +
    originalPriceOpen?: number

    Original entry price before DCA averaging (present when averageBuy was applied)

    +
    originalPriceStopLoss?: number

    Original stop loss price before modifications

    +
    originalPriceTakeProfit?: number

    Original take profit price before modifications

    +
    partialExecuted?: number

    Total executed percentage from partial closes

    +
    pendingAt?: number

    Timestamp when position became active (only for opened events)

    +

    Unrealized PNL at the moment of this event

    +
    position: string

    Position type

    +
    priceOpen: number

    Scheduled entry price

    +
    priceStopLoss: number

    Stop loss price

    +
    priceTakeProfit: number

    Take profit price

    +
    scheduledAt?: number

    Timestamp when signal was created/scheduled (for all events)

    +
    signalId: string

    Signal ID

    +
    symbol: string

    Trading pair symbol

    +
    timestamp: number

    Event timestamp in milliseconds (scheduledAt for scheduled/cancelled events)

    +
    totalEntries?: number

    Total number of DCA entries (present when averageBuy was applied)

    +
    totalPartials?: number

    Total number of partial closes executed (_partial.length)

    +

    Interface SignalCancelledNotification

    Signal cancelled notification. Emitted when a scheduled signal is cancelled before activation.

    -
    interface SignalCancelledNotification {
        backtest: boolean;
        cancelId: string;
        cancelReason: string;
        createdAt: number;
        duration: number;
        exchangeName: string;
        id: string;
        note?: string;
        originalPriceOpen: number;
        originalPriceStopLoss: number;
        originalPriceTakeProfit: number;
        pendingAt: number;
        position: "long" | "short";
        priceOpen: number;
        priceStopLoss: number;
        priceTakeProfit: number;
        scheduledAt: number;
        signalId: string;
        strategyName: string;
        symbol: string;
        timestamp: number;
        totalEntries: number;
        totalPartials: number;
        type: "signal.cancelled";
    }

    Properties

    interface SignalCancelledNotification {
        backtest: boolean;
        cancelId: string;
        cancelReason: string;
        createdAt: number;
        duration: number;
        exchangeName: string;
        id: string;
        note?: string;
        originalPriceOpen: number;
        originalPriceStopLoss: number;
        originalPriceTakeProfit: number;
        pendingAt: number;
        position: "long" | "short";
        priceOpen: number;
        priceStopLoss: number;
        priceTakeProfit: number;
        scheduledAt: number;
        signalId: string;
        strategyName: string;
        symbol: string;
        timestamp: number;
        totalEntries: number;
        totalPartials: number;
        type: "signal.cancelled";
    }

    Properties

    backtest cancelId cancelReason createdAt @@ -25,30 +25,30 @@ Emitted when a scheduled signal is cancelled before activation.

    totalPartials type

    Properties

    backtest: boolean

    Whether this notification is from backtest mode (true) or live mode (false)

    -
    cancelId: string

    Optional cancellation identifier (provided when user calls cancel())

    -
    cancelReason: string

    Why signal was cancelled (timeout | price_reject | user)

    -
    createdAt: number

    Unix timestamp in milliseconds when the tick result was created (from candle timestamp in backtest or execution context when in live)

    -
    duration: number

    Duration in minutes from scheduledAt to cancellation

    -
    exchangeName: string

    Exchange name where signal was scheduled

    -
    id: string

    Unique notification identifier

    -
    note?: string

    Optional human-readable description of signal reason

    -
    originalPriceOpen: number

    Original entry price at signal creation (unchanged by DCA averaging)

    -
    originalPriceStopLoss: number

    Original stop loss price before any trailing adjustments

    -
    originalPriceTakeProfit: number

    Original take profit price before any trailing adjustments

    -
    pendingAt: number

    Pending timestamp in milliseconds (when position became pending/active at priceOpen)

    -
    position: "long" | "short"

    Trade direction: "long" (buy) or "short" (sell)

    -
    priceOpen: number

    Entry price for the position

    -
    priceStopLoss: number

    Stop loss exit price

    -
    priceTakeProfit: number

    Take profit target price

    -
    scheduledAt: number

    Signal creation timestamp in milliseconds (when signal was first created/scheduled)

    -
    signalId: string

    Unique signal identifier (UUID v4)

    -
    strategyName: string

    Strategy name that generated this signal

    -
    symbol: string

    Trading pair symbol (e.g., "BTCUSDT")

    -
    timestamp: number

    Unix timestamp in milliseconds when signal was cancelled (closeTimestamp)

    -
    totalEntries: number

    Total number of DCA entries (_entry.length). 1 = no averaging.

    -
    totalPartials: number

    Total number of partial closes executed (_partial.length). 0 = no partial closes done.

    -
    type: "signal.cancelled"

    Discriminator for type-safe union

    -
    +
    cancelId: string

    Optional cancellation identifier (provided when user calls cancel())

    +
    cancelReason: string

    Why signal was cancelled (timeout | price_reject | user)

    +
    createdAt: number

    Unix timestamp in milliseconds when the tick result was created (from candle timestamp in backtest or execution context when in live)

    +
    duration: number

    Duration in minutes from scheduledAt to cancellation

    +
    exchangeName: string

    Exchange name where signal was scheduled

    +
    id: string

    Unique notification identifier

    +
    note?: string

    Optional human-readable description of signal reason

    +
    originalPriceOpen: number

    Original entry price at signal creation (unchanged by DCA averaging)

    +
    originalPriceStopLoss: number

    Original stop loss price before any trailing adjustments

    +
    originalPriceTakeProfit: number

    Original take profit price before any trailing adjustments

    +
    pendingAt: number

    Pending timestamp in milliseconds (when position became pending/active at priceOpen)

    +
    position: "long" | "short"

    Trade direction: "long" (buy) or "short" (sell)

    +
    priceOpen: number

    Entry price for the position

    +
    priceStopLoss: number

    Stop loss exit price

    +
    priceTakeProfit: number

    Take profit target price

    +
    scheduledAt: number

    Signal creation timestamp in milliseconds (when signal was first created/scheduled)

    +
    signalId: string

    Unique signal identifier (UUID v4)

    +
    strategyName: string

    Strategy name that generated this signal

    +
    symbol: string

    Trading pair symbol (e.g., "BTCUSDT")

    +
    timestamp: number

    Unix timestamp in milliseconds when signal was cancelled (closeTimestamp)

    +
    totalEntries: number

    Total number of DCA entries (_entry.length). 1 = no averaging.

    +
    totalPartials: number

    Total number of partial closes executed (_partial.length). 0 = no partial closes done.

    +
    type: "signal.cancelled"

    Discriminator for type-safe union

    +

    Interface SignalClosedNotification

    Signal closed notification. Emitted when a trading position is closed (TP/SL hit).

    -
    interface SignalClosedNotification {
        backtest: boolean;
        closeReason: string;
        createdAt: number;
        duration: number;
        exchangeName: string;
        id: string;
        maxDrawdown: IStrategyPnL;
        maxDrawdownCost: number;
        maxDrawdownEntries: number;
        maxDrawdownPercentage: number;
        maxDrawdownPriceClose: number;
        maxDrawdownPriceOpen: number;
        note?: string;
        originalPriceOpen: number;
        originalPriceStopLoss: number;
        originalPriceTakeProfit: number;
        peakProfit: IStrategyPnL;
        peakProfitCost: number;
        peakProfitEntries: number;
        peakProfitPercentage: number;
        peakProfitPriceClose: number;
        peakProfitPriceOpen: number;
        pendingAt: number;
        pnl: IStrategyPnL;
        pnlCost: number;
        pnlEntries: number;
        pnlPercentage: number;
        pnlPriceClose: number;
        pnlPriceOpen: number;
        position: "long" | "short";
        priceClose: number;
        priceOpen: number;
        priceStopLoss: number;
        priceTakeProfit: number;
        scheduledAt: number;
        signalId: string;
        strategyName: string;
        symbol: string;
        timestamp: number;
        totalEntries: number;
        totalPartials: number;
        type: "signal.closed";
    }

    Properties

    interface SignalClosedNotification {
        backtest: boolean;
        closeReason: string;
        createdAt: number;
        duration: number;
        exchangeName: string;
        id: string;
        maxDrawdown: IStrategyPnL;
        maxDrawdownCost: number;
        maxDrawdownEntries: number;
        maxDrawdownPercentage: number;
        maxDrawdownPriceClose: number;
        maxDrawdownPriceOpen: number;
        note?: string;
        originalPriceOpen: number;
        originalPriceStopLoss: number;
        originalPriceTakeProfit: number;
        peakProfit: IStrategyPnL;
        peakProfitCost: number;
        peakProfitEntries: number;
        peakProfitPercentage: number;
        peakProfitPriceClose: number;
        peakProfitPriceOpen: number;
        pendingAt: number;
        pnl: IStrategyPnL;
        pnlCost: number;
        pnlEntries: number;
        pnlPercentage: number;
        pnlPriceClose: number;
        pnlPriceOpen: number;
        position: "long" | "short";
        priceClose: number;
        priceOpen: number;
        priceStopLoss: number;
        priceTakeProfit: number;
        scheduledAt: number;
        signalId: string;
        strategyName: string;
        symbol: string;
        timestamp: number;
        totalEntries: number;
        totalPartials: number;
        type: "signal.closed";
    }

    Properties

    backtest closeReason createdAt duration @@ -43,48 +43,48 @@ Emitted when a trading position is closed (TP/SL hit).

    totalPartials type

    Properties

    backtest: boolean

    Whether this notification is from backtest mode (true) or live mode (false)

    -
    closeReason: string

    Why signal closed (time_expired | take_profit | stop_loss | closed)

    -
    createdAt: number

    Unix timestamp in milliseconds when the tick result was created (from candle timestamp in backtest or execution context when in live)

    -
    duration: number

    Duration of position in minutes (from pendingAt to closeTimestamp)

    -
    exchangeName: string

    Exchange name where signal was executed

    -
    id: string

    Unique notification identifier

    -
    maxDrawdown: IStrategyPnL

    Maximum drawdown experienced during the life of this position up to the moment this public signal was created

    -
    maxDrawdownCost: number

    Absolute profit/loss in USD at the moment the position reached its maximum drawdown during the life of this position

    -
    maxDrawdownEntries: number

    Number of entries executed at the moment the position reached its maximum drawdown during the life of this position

    -
    maxDrawdownPercentage: number

    Profit/loss as percentage at the moment the position reached its maximum drawdown during the life of this position

    -
    maxDrawdownPriceClose: number

    Exit price for PNL calculation at the moment of max drawdown

    -
    maxDrawdownPriceOpen: number

    Maximum drawdown price reached in loss direction during the life of this position

    -
    note?: string

    Optional human-readable description of signal reason

    -
    originalPriceOpen: number

    Original entry price at signal creation (unchanged by DCA averaging)

    -
    originalPriceStopLoss: number

    Original stop loss price before any trailing adjustments

    -
    originalPriceTakeProfit: number

    Original take profit price before any trailing adjustments

    -
    peakProfit: IStrategyPnL

    Peak profit achieved during the life of this position up to the moment this public signal was created

    -
    peakProfitCost: number

    Absolute profit/loss in USD at the moment the position reached its peak profit during the life of this position

    -
    peakProfitEntries: number

    Number of entries executed at the moment the position reached its peak profit during the life of this position

    -
    peakProfitPercentage: number

    Profit/loss as percentage at the moment the position reached its peak profit during the life of this position

    -
    peakProfitPriceClose: number

    Exit price for PNL calculation at the moment of peak profit

    -
    peakProfitPriceOpen: number

    Peak price reached in profit direction during the life of this position

    -
    pendingAt: number

    Pending timestamp in milliseconds (when position became pending/active at priceOpen)

    -

    Total PNL of the closed position (including all entries and partials)

    -
    pnlCost: number

    Absolute profit/loss in USD

    -
    pnlEntries: number

    Total invested capital in USD

    -
    pnlPercentage: number

    Profit/loss as percentage (e.g., 1.5 for +1.5%, -2.3 for -2.3%)

    -
    pnlPriceClose: number

    Exit price from PNL calculation (adjusted with slippage and fees)

    -
    pnlPriceOpen: number

    Entry price from PNL calculation (effective price adjusted with slippage and fees)

    -
    position: "long" | "short"

    Trade direction: "long" (buy) or "short" (sell)

    -
    priceClose: number

    Exit price when position was closed

    -
    priceOpen: number

    Entry price for the position

    -
    priceStopLoss: number

    Stop loss exit price

    -
    priceTakeProfit: number

    Take profit target price

    -
    scheduledAt: number

    Signal creation timestamp in milliseconds (when signal was first created/scheduled)

    -
    signalId: string

    Unique signal identifier (UUID v4)

    -
    strategyName: string

    Strategy name that generated this signal

    -
    symbol: string

    Trading pair symbol (e.g., "BTCUSDT")

    -
    timestamp: number

    Unix timestamp in milliseconds when signal was closed (closeTimestamp)

    -
    totalEntries: number

    Total number of DCA entries (_entry.length). 1 = no averaging.

    -
    totalPartials: number

    Total number of partial closes executed (_partial.length). 0 = no partial closes done.

    -
    type: "signal.closed"

    Discriminator for type-safe union

    -
    +
    closeReason: string

    Why signal closed (time_expired | take_profit | stop_loss | closed)

    +
    createdAt: number

    Unix timestamp in milliseconds when the tick result was created (from candle timestamp in backtest or execution context when in live)

    +
    duration: number

    Duration of position in minutes (from pendingAt to closeTimestamp)

    +
    exchangeName: string

    Exchange name where signal was executed

    +
    id: string

    Unique notification identifier

    +
    maxDrawdown: IStrategyPnL

    Maximum drawdown experienced during the life of this position up to the moment this public signal was created

    +
    maxDrawdownCost: number

    Absolute profit/loss in USD at the moment the position reached its maximum drawdown during the life of this position

    +
    maxDrawdownEntries: number

    Number of entries executed at the moment the position reached its maximum drawdown during the life of this position

    +
    maxDrawdownPercentage: number

    Profit/loss as percentage at the moment the position reached its maximum drawdown during the life of this position

    +
    maxDrawdownPriceClose: number

    Exit price for PNL calculation at the moment of max drawdown

    +
    maxDrawdownPriceOpen: number

    Maximum drawdown price reached in loss direction during the life of this position

    +
    note?: string

    Optional human-readable description of signal reason

    +
    originalPriceOpen: number

    Original entry price at signal creation (unchanged by DCA averaging)

    +
    originalPriceStopLoss: number

    Original stop loss price before any trailing adjustments

    +
    originalPriceTakeProfit: number

    Original take profit price before any trailing adjustments

    +
    peakProfit: IStrategyPnL

    Peak profit achieved during the life of this position up to the moment this public signal was created

    +
    peakProfitCost: number

    Absolute profit/loss in USD at the moment the position reached its peak profit during the life of this position

    +
    peakProfitEntries: number

    Number of entries executed at the moment the position reached its peak profit during the life of this position

    +
    peakProfitPercentage: number

    Profit/loss as percentage at the moment the position reached its peak profit during the life of this position

    +
    peakProfitPriceClose: number

    Exit price for PNL calculation at the moment of peak profit

    +
    peakProfitPriceOpen: number

    Peak price reached in profit direction during the life of this position

    +
    pendingAt: number

    Pending timestamp in milliseconds (when position became pending/active at priceOpen)

    +

    Total PNL of the closed position (including all entries and partials)

    +
    pnlCost: number

    Absolute profit/loss in USD

    +
    pnlEntries: number

    Total invested capital in USD

    +
    pnlPercentage: number

    Profit/loss as percentage (e.g., 1.5 for +1.5%, -2.3 for -2.3%)

    +
    pnlPriceClose: number

    Exit price from PNL calculation (adjusted with slippage and fees)

    +
    pnlPriceOpen: number

    Entry price from PNL calculation (effective price adjusted with slippage and fees)

    +
    position: "long" | "short"

    Trade direction: "long" (buy) or "short" (sell)

    +
    priceClose: number

    Exit price when position was closed

    +
    priceOpen: number

    Entry price for the position

    +
    priceStopLoss: number

    Stop loss exit price

    +
    priceTakeProfit: number

    Take profit target price

    +
    scheduledAt: number

    Signal creation timestamp in milliseconds (when signal was first created/scheduled)

    +
    signalId: string

    Unique signal identifier (UUID v4)

    +
    strategyName: string

    Strategy name that generated this signal

    +
    symbol: string

    Trading pair symbol (e.g., "BTCUSDT")

    +
    timestamp: number

    Unix timestamp in milliseconds when signal was closed (closeTimestamp)

    +
    totalEntries: number

    Total number of DCA entries (_entry.length). 1 = no averaging.

    +
    totalPartials: number

    Total number of partial closes executed (_partial.length). 0 = no partial closes done.

    +
    type: "signal.closed"

    Discriminator for type-safe union

    +

    Interface SignalEventContract

    Contract for pending signal lifecycle events (open and close).

    +

    Emitted by signalEventSubject when a pending position is opened (action "opened") or closed +(action "closed") during tick()/backtest() processing. Lets consumers track the active phase +of a signal without subscribing to the full signal stream.

    +

    Covers every way a position opens (new signal, immediate entry, scheduled activation, user +activation) and every way it closes (take_profit / stop_loss / time_expired / user-close / +broker fill / order no longer pending).

    +

    Consumers:

    +
      +
    • User callbacks via listenSignalEvent() / listenSignalEventOnce()
    • +
    +
    import { listenSignalEvent } from "backtest-kit";

    listenSignalEvent((event) => {
    if (event.action === "opened") {
    console.log(`Opened ${event.symbol} @ ${event.data.priceOpen}`);
    } else {
    console.log(`Closed ${event.symbol} (reason: ${event.closeReason})`);
    }
    }); +
    + +
    interface SignalEventContract {
        action: "closed" | "opened";
        backtest: boolean;
        closeReason?: StrategyCloseReason;
        currentPrice: number;
        data: IPublicSignalRow;
        exchangeName: string;
        frameName: string;
        strategyName: string;
        symbol: string;
        timestamp: number;
    }

    Properties

    action: "closed" | "opened"

    Lifecycle action for the pending signal.

    +
      +
    • "opened": a pending position was opened (new signal / immediate / scheduled or user activation)
    • +
    • "closed": the pending position was closed (TP / SL / time_expired / user / broker fill / ping)
    • +
    +
    backtest: boolean

    Execution mode flag.

    +
      +
    • true: Event from backtest execution (historical candle data)
    • +
    • false: Event from live trading (real-time tick)
    • +
    +
    closeReason?: StrategyCloseReason

    Close reason. Present only when action === "closed":

    +
      +
    • "take_profit": effective take-profit level reached
    • +
    • "stop_loss": effective stop-loss level reached
    • +
    • "time_expired": position exceeded minuteEstimatedTime
    • +
    • "closed": closed by user (closePending) or because the order is no longer open on the exchange
    • +
    +

    Always undefined when action === "opened".

    +
    currentPrice: number

    Current market price of the symbol at the time of the event. +For "opened" this is the effective entry (priceOpen); for "closed" the close price.

    +

    Complete pending signal row data in public form. +Contains all signal information: id, position, priceOpen, priceTakeProfit, priceStopLoss, +effective entry / trailing SL/TP, PnL, etc.

    +
    exchangeName: string

    Exchange name where this pending signal lives.

    +
    frameName: string

    Frame name (timeframe / date range) for the run. Empty string in live mode. +Same value as the signal's frameName (data.frameName).

    +
    strategyName: string

    Strategy name that owns this pending signal.

    +
    symbol: string

    Trading pair symbol (e.g., "BTCUSDT"). +Identifies which market this event belongs to.

    +
    timestamp: number

    Event timestamp in milliseconds since Unix epoch.

    +

    Timing semantics:

    +
      +
    • Live mode: when.getTime() at the moment of the event
    • +
    • Backtest mode: candle.timestamp of the candle being processed
    • +
    +
    + + + + + + + + + diff --git a/interfaces/types.SignalInfoContract.html b/interfaces/types.SignalInfoContract.html index ec1452bf17a7212f48d1756ed4a2eccc0d689c0e..e1b5b4c1c2d43b89ee001c9dd295379f85653394 100644 --- a/interfaces/types.SignalInfoContract.html +++ b/interfaces/types.SignalInfoContract.html @@ -9,7 +9,7 @@ Used for custom strategy annotations, debug output, and external notification ro
    import { listenSignalNotify } from "backtest-kit";

    // Listen to all signal info events
    listenSignalNotify((event) => {
    console.log(`[${event.backtest ? "Backtest" : "Live"}] Signal ${event.data.id}: ${event.note}`);
    console.log(`Symbol: ${event.symbol}, Price: ${event.currentPrice}`);
    });

    // Wait for the first info event on BTCUSDT
    listenSignalNotifyOnce(
    (event) => event.symbol === "BTCUSDT",
    (event) => console.log("BTCUSDT info:", event.note)
    );
    -
    interface SignalInfoContract {
        backtest: boolean;
        currentPrice: number;
        data: IPublicSignalRow;
        exchangeName: string;
        frameName: string;
        note: string;
        notificationId?: string;
        strategyName: string;
        symbol: string;
        timestamp: number;
    }

    Properties

    interface SignalInfoContract {
        backtest: boolean;
        currentPrice: number;
        data: IPublicSignalRow;
        exchangeName: string;
        frameName: string;
        note: string;
        notificationId?: string;
        strategyName: string;
        symbol: string;
        timestamp: number;
    }

    Properties

    backtest currentPrice data exchangeName @@ -24,28 +24,28 @@ Used for custom strategy annotations, debug output, and external notification ro
  • true: Event from backtest execution (historical candle data)
  • false: Event from live trading (real-time tick)
  • -
    currentPrice: number

    Current market price at the moment the info event was emitted.

    -

    Complete signal row data with original prices. +

    currentPrice: number

    Current market price at the moment the info event was emitted.

    +

    Complete signal row data with original prices. Contains all signal information including originalPriceStopLoss, originalPriceTakeProfit, and partialExecuted.

    -
    exchangeName: string

    Exchange name where this signal is being executed. +

    exchangeName: string

    Exchange name where this signal is being executed. Identifies which exchange this info event belongs to.

    -
    frameName: string

    Frame name where this signal is being executed. +

    frameName: string

    Frame name where this signal is being executed. Identifies which frame this info event belongs to (empty string for live mode).

    -
    note: string

    User-defined informational note attached to this event. +

    note: string

    User-defined informational note attached to this event. Provided by the strategy when calling commitSignalInfo().

    -
    notificationId?: string

    Optional user-defined identifier for correlating this event with external systems. +

    notificationId?: string

    Optional user-defined identifier for correlating this event with external systems. Provided by the strategy when calling commitSignalInfo().

    -
    strategyName: string

    Strategy name that generated this signal. +

    strategyName: string

    Strategy name that generated this signal. Identifies which strategy execution this info event belongs to.

    -
    symbol: string

    Trading pair symbol (e.g., "BTCUSDT"). +

    symbol: string

    Trading pair symbol (e.g., "BTCUSDT"). Identifies which market this info event belongs to.

    -
    timestamp: number

    Event timestamp in milliseconds since Unix epoch.

    +
    timestamp: number

    Event timestamp in milliseconds since Unix epoch.

    Timing semantics:

    • Live mode: when.getTime() at the moment the info event was emitted
    • Backtest mode: candle.timestamp of the candle that triggered the event
    -
    +

    Interface SignalInfoNotification

    Signal info notification. Emitted when a strategy broadcasts a user-defined informational note for an open position.

    -
    interface SignalInfoNotification {
        backtest: boolean;
        createdAt: number;
        currentPrice: number;
        exchangeName: string;
        id: string;
        maxDrawdown: IStrategyPnL;
        maxDrawdownCost: number;
        maxDrawdownEntries: number;
        maxDrawdownPercentage: number;
        maxDrawdownPriceClose: number;
        maxDrawdownPriceOpen: number;
        note: string;
        notificationId?: string;
        originalPriceOpen: number;
        originalPriceStopLoss: number;
        originalPriceTakeProfit: number;
        peakProfit: IStrategyPnL;
        peakProfitCost: number;
        peakProfitEntries: number;
        peakProfitPercentage: number;
        peakProfitPriceClose: number;
        peakProfitPriceOpen: number;
        pendingAt: number;
        pnl: IStrategyPnL;
        pnlCost: number;
        pnlEntries: number;
        pnlPercentage: number;
        pnlPriceClose: number;
        pnlPriceOpen: number;
        position: "long" | "short";
        priceOpen: number;
        priceStopLoss: number;
        priceTakeProfit: number;
        scheduledAt: number;
        signalId: string;
        strategyName: string;
        symbol: string;
        timestamp: number;
        totalEntries: number;
        totalPartials: number;
        type: "signal.info";
    }

    Properties

    interface SignalInfoNotification {
        backtest: boolean;
        createdAt: number;
        currentPrice: number;
        exchangeName: string;
        id: string;
        maxDrawdown: IStrategyPnL;
        maxDrawdownCost: number;
        maxDrawdownEntries: number;
        maxDrawdownPercentage: number;
        maxDrawdownPriceClose: number;
        maxDrawdownPriceOpen: number;
        note: string;
        notificationId?: string;
        originalPriceOpen: number;
        originalPriceStopLoss: number;
        originalPriceTakeProfit: number;
        peakProfit: IStrategyPnL;
        peakProfitCost: number;
        peakProfitEntries: number;
        peakProfitPercentage: number;
        peakProfitPriceClose: number;
        peakProfitPriceOpen: number;
        pendingAt: number;
        pnl: IStrategyPnL;
        pnlCost: number;
        pnlEntries: number;
        pnlPercentage: number;
        pnlPriceClose: number;
        pnlPriceOpen: number;
        position: "long" | "short";
        priceOpen: number;
        priceStopLoss: number;
        priceTakeProfit: number;
        scheduledAt: number;
        signalId: string;
        strategyName: string;
        symbol: string;
        timestamp: number;
        totalEntries: number;
        totalPartials: number;
        type: "signal.info";
    }

    Properties

    backtest createdAt currentPrice exchangeName @@ -42,47 +42,47 @@ Emitted when a strategy broadcasts a user-defined informational note for an open totalPartials type

    Properties

    backtest: boolean

    Whether this notification is from backtest mode (true) or live mode (false)

    -
    createdAt: number

    Unix timestamp in milliseconds when the notification was created

    -
    currentPrice: number

    Current market price when the info event was emitted

    -
    exchangeName: string

    Exchange name where signal was executed

    -
    id: string

    Unique notification identifier

    -
    maxDrawdown: IStrategyPnL

    Maximum drawdown experienced during the life of this position up to the moment this public signal was created

    -
    maxDrawdownCost: number

    Absolute profit/loss in USD at the moment the position reached its maximum drawdown during the life of this position

    -
    maxDrawdownEntries: number

    Number of entries executed at the moment the position reached its maximum drawdown during the life of this position

    -
    maxDrawdownPercentage: number

    Profit/loss as percentage at the moment the position reached its maximum drawdown during the life of this position

    -
    maxDrawdownPriceClose: number

    Exit price for PNL calculation at the moment of max drawdown

    -
    maxDrawdownPriceOpen: number

    Maximum drawdown price reached in loss direction during the life of this position

    -
    note: string

    User-defined informational note provided by the strategy

    -
    notificationId?: string

    Optional user-defined identifier for correlating this notification with external systems

    -
    originalPriceOpen: number

    Original entry price at signal creation (unchanged by DCA averaging)

    -
    originalPriceStopLoss: number

    Original stop loss price before any trailing adjustments

    -
    originalPriceTakeProfit: number

    Original take profit price before any trailing adjustments

    -
    peakProfit: IStrategyPnL

    Peak profit achieved during the life of this position up to the moment this public signal was created

    -
    peakProfitCost: number

    Absolute profit/loss in USD at the moment the position reached its peak profit during the life of this position

    -
    peakProfitEntries: number

    Number of entries executed at the moment the position reached its peak profit during the life of this position

    -
    peakProfitPercentage: number

    Profit/loss as percentage at the moment the position reached its peak profit during the life of this position

    -
    peakProfitPriceClose: number

    Exit price for PNL calculation at the moment of peak profit

    -
    peakProfitPriceOpen: number

    Peak price reached in profit direction during the life of this position

    -
    pendingAt: number

    Pending timestamp in milliseconds (when position became pending/active at priceOpen)

    -

    Total PNL of the closed position (including all entries and partials)

    -
    pnlCost: number

    Absolute profit/loss in USD

    -
    pnlEntries: number

    Total invested capital in USD

    -
    pnlPercentage: number

    Profit/loss as percentage (e.g., 1.5 for +1.5%, -2.3 for -2.3%)

    -
    pnlPriceClose: number

    Exit price from PNL calculation (adjusted with slippage and fees)

    -
    pnlPriceOpen: number

    Entry price from PNL calculation (effective price adjusted with slippage and fees)

    -
    position: "long" | "short"

    Trade direction: "long" (buy) or "short" (sell)

    -
    priceOpen: number

    Entry price for the position

    -
    priceStopLoss: number

    Effective stop loss price (with trailing if set)

    -
    priceTakeProfit: number

    Effective take profit price (with trailing if set)

    -
    scheduledAt: number

    Signal creation timestamp in milliseconds (when signal was first created/scheduled)

    -
    signalId: string

    Unique signal identifier (UUID v4)

    -
    strategyName: string

    Strategy name that generated this signal

    -
    symbol: string

    Trading pair symbol (e.g., "BTCUSDT")

    -
    timestamp: number

    Unix timestamp in milliseconds when the info event was emitted

    -
    totalEntries: number

    Total number of DCA entries (_entry.length). 1 = no averaging.

    -
    totalPartials: number

    Total number of partial closes executed (_partial.length). 0 = no partial closes done.

    -
    type: "signal.info"

    Discriminator for type-safe union

    -
    +
    createdAt: number

    Unix timestamp in milliseconds when the notification was created

    +
    currentPrice: number

    Current market price when the info event was emitted

    +
    exchangeName: string

    Exchange name where signal was executed

    +
    id: string

    Unique notification identifier

    +
    maxDrawdown: IStrategyPnL

    Maximum drawdown experienced during the life of this position up to the moment this public signal was created

    +
    maxDrawdownCost: number

    Absolute profit/loss in USD at the moment the position reached its maximum drawdown during the life of this position

    +
    maxDrawdownEntries: number

    Number of entries executed at the moment the position reached its maximum drawdown during the life of this position

    +
    maxDrawdownPercentage: number

    Profit/loss as percentage at the moment the position reached its maximum drawdown during the life of this position

    +
    maxDrawdownPriceClose: number

    Exit price for PNL calculation at the moment of max drawdown

    +
    maxDrawdownPriceOpen: number

    Maximum drawdown price reached in loss direction during the life of this position

    +
    note: string

    User-defined informational note provided by the strategy

    +
    notificationId?: string

    Optional user-defined identifier for correlating this notification with external systems

    +
    originalPriceOpen: number

    Original entry price at signal creation (unchanged by DCA averaging)

    +
    originalPriceStopLoss: number

    Original stop loss price before any trailing adjustments

    +
    originalPriceTakeProfit: number

    Original take profit price before any trailing adjustments

    +
    peakProfit: IStrategyPnL

    Peak profit achieved during the life of this position up to the moment this public signal was created

    +
    peakProfitCost: number

    Absolute profit/loss in USD at the moment the position reached its peak profit during the life of this position

    +
    peakProfitEntries: number

    Number of entries executed at the moment the position reached its peak profit during the life of this position

    +
    peakProfitPercentage: number

    Profit/loss as percentage at the moment the position reached its peak profit during the life of this position

    +
    peakProfitPriceClose: number

    Exit price for PNL calculation at the moment of peak profit

    +
    peakProfitPriceOpen: number

    Peak price reached in profit direction during the life of this position

    +
    pendingAt: number

    Pending timestamp in milliseconds (when position became pending/active at priceOpen)

    +

    Total PNL of the closed position (including all entries and partials)

    +
    pnlCost: number

    Absolute profit/loss in USD

    +
    pnlEntries: number

    Total invested capital in USD

    +
    pnlPercentage: number

    Profit/loss as percentage (e.g., 1.5 for +1.5%, -2.3 for -2.3%)

    +
    pnlPriceClose: number

    Exit price from PNL calculation (adjusted with slippage and fees)

    +
    pnlPriceOpen: number

    Entry price from PNL calculation (effective price adjusted with slippage and fees)

    +
    position: "long" | "short"

    Trade direction: "long" (buy) or "short" (sell)

    +
    priceOpen: number

    Entry price for the position

    +
    priceStopLoss: number

    Effective stop loss price (with trailing if set)

    +
    priceTakeProfit: number

    Effective take profit price (with trailing if set)

    +
    scheduledAt: number

    Signal creation timestamp in milliseconds (when signal was first created/scheduled)

    +
    signalId: string

    Unique signal identifier (UUID v4)

    +
    strategyName: string

    Strategy name that generated this signal

    +
    symbol: string

    Trading pair symbol (e.g., "BTCUSDT")

    +
    timestamp: number

    Unix timestamp in milliseconds when the info event was emitted

    +
    totalEntries: number

    Total number of DCA entries (_entry.length). 1 = no averaging.

    +
    totalPartials: number

    Total number of partial closes executed (_partial.length). 0 = no partial closes done.

    +
    type: "signal.info"

    Discriminator for type-safe union

    +

    Interface SignalOpenedNotification

    Signal opened notification. Emitted when a new trading position is opened.

    -
    interface SignalOpenedNotification {
        backtest: boolean;
        cost: number;
        createdAt: number;
        exchangeName: string;
        id: string;
        maxDrawdown: IStrategyPnL;
        maxDrawdownCost: number;
        maxDrawdownEntries: number;
        maxDrawdownPercentage: number;
        maxDrawdownPriceClose: number;
        maxDrawdownPriceOpen: number;
        note?: string;
        originalPriceOpen: number;
        originalPriceStopLoss: number;
        originalPriceTakeProfit: number;
        peakProfit: IStrategyPnL;
        peakProfitCost: number;
        peakProfitEntries: number;
        peakProfitPercentage: number;
        peakProfitPriceClose: number;
        peakProfitPriceOpen: number;
        pendingAt: number;
        pnl: IStrategyPnL;
        pnlCost: number;
        pnlEntries: number;
        pnlPercentage: number;
        pnlPriceClose: number;
        pnlPriceOpen: number;
        position: "long" | "short";
        priceOpen: number;
        priceStopLoss: number;
        priceTakeProfit: number;
        scheduledAt: number;
        signalId: string;
        strategyName: string;
        symbol: string;
        timestamp: number;
        totalEntries: number;
        totalPartials: number;
        type: "signal.opened";
    }

    Properties

    interface SignalOpenedNotification {
        backtest: boolean;
        cost: number;
        createdAt: number;
        exchangeName: string;
        id: string;
        maxDrawdown: IStrategyPnL;
        maxDrawdownCost: number;
        maxDrawdownEntries: number;
        maxDrawdownPercentage: number;
        maxDrawdownPriceClose: number;
        maxDrawdownPriceOpen: number;
        note?: string;
        originalPriceOpen: number;
        originalPriceStopLoss: number;
        originalPriceTakeProfit: number;
        peakProfit: IStrategyPnL;
        peakProfitCost: number;
        peakProfitEntries: number;
        peakProfitPercentage: number;
        peakProfitPriceClose: number;
        peakProfitPriceOpen: number;
        pendingAt: number;
        pnl: IStrategyPnL;
        pnlCost: number;
        pnlEntries: number;
        pnlPercentage: number;
        pnlPriceClose: number;
        pnlPriceOpen: number;
        position: "long" | "short";
        priceOpen: number;
        priceStopLoss: number;
        priceTakeProfit: number;
        scheduledAt: number;
        signalId: string;
        strategyName: string;
        symbol: string;
        timestamp: number;
        totalEntries: number;
        totalPartials: number;
        type: "signal.opened";
    }

    Properties

    backtest cost createdAt exchangeName @@ -41,46 +41,46 @@ Emitted when a new trading position is opened.

    totalPartials type

    Properties

    backtest: boolean

    Whether this notification is from backtest mode (true) or live mode (false)

    -
    cost: number

    Cost of the initial position entry in USD (from signal.cost)

    -
    createdAt: number

    Unix timestamp in milliseconds when the tick result was created (from candle timestamp in backtest or execution context when in live)

    -
    exchangeName: string

    Exchange name where signal was executed

    -
    id: string

    Unique notification identifier

    -
    maxDrawdown: IStrategyPnL

    Maximum drawdown experienced during the life of this position up to the moment this public signal was created

    -
    maxDrawdownCost: number

    Absolute profit/loss in USD at the moment the position reached its maximum drawdown during the life of this position

    -
    maxDrawdownEntries: number

    Number of entries executed at the moment the position reached its maximum drawdown during the life of this position

    -
    maxDrawdownPercentage: number

    Profit/loss as percentage at the moment the position reached its maximum drawdown during the life of this position

    -
    maxDrawdownPriceClose: number

    Exit price for PNL calculation at the moment of max drawdown

    -
    maxDrawdownPriceOpen: number

    Maximum drawdown price reached in loss direction during the life of this position

    -
    note?: string

    Optional human-readable description of signal reason

    -
    originalPriceOpen: number

    Original entry price at signal creation (unchanged by DCA averaging)

    -
    originalPriceStopLoss: number

    Original stop loss price before any trailing adjustments

    -
    originalPriceTakeProfit: number

    Original take profit price before any trailing adjustments

    -
    peakProfit: IStrategyPnL

    Peak profit achieved during the life of this position up to the moment this public signal was created

    -
    peakProfitCost: number

    Absolute profit/loss in USD at the moment the position reached its peak profit during the life of this position

    -
    peakProfitEntries: number

    Number of entries executed at the moment the position reached its peak profit during the life of this position

    -
    peakProfitPercentage: number

    Profit/loss as percentage at the moment the position reached its peak profit during the life of this position

    -
    peakProfitPriceClose: number

    Exit price for PNL calculation at the moment of peak profit

    -
    peakProfitPriceOpen: number

    Peak price reached in profit direction during the life of this position

    -
    pendingAt: number

    Pending timestamp in milliseconds (when position became pending/active at priceOpen)

    -

    Total PNL of the closed position (including all entries and partials)

    -
    pnlCost: number

    Absolute profit/loss in USD

    -
    pnlEntries: number

    Total invested capital in USD

    -
    pnlPercentage: number

    Profit/loss as percentage (e.g., 1.5 for +1.5%, -2.3 for -2.3%)

    -
    pnlPriceClose: number

    Exit price from PNL calculation (adjusted with slippage and fees)

    -
    pnlPriceOpen: number

    Entry price from PNL calculation (effective price adjusted with slippage and fees)

    -
    position: "long" | "short"

    Trade direction: "long" (buy) or "short" (sell)

    -
    priceOpen: number

    Entry price for the position

    -
    priceStopLoss: number

    Stop loss exit price

    -
    priceTakeProfit: number

    Take profit target price

    -
    scheduledAt: number

    Signal creation timestamp in milliseconds (when signal was first created/scheduled)

    -
    signalId: string

    Unique signal identifier (UUID v4)

    -
    strategyName: string

    Strategy name that generated this signal

    -
    symbol: string

    Trading pair symbol (e.g., "BTCUSDT")

    -
    timestamp: number

    Unix timestamp in milliseconds when signal was opened (pendingAt)

    -
    totalEntries: number

    Total number of DCA entries (_entry.length). 1 = no averaging.

    -
    totalPartials: number

    Total number of partial closes executed (_partial.length). 0 = no partial closes done.

    -
    type: "signal.opened"

    Discriminator for type-safe union

    -
    +
    cost: number

    Cost of the initial position entry in USD (from signal.cost)

    +
    createdAt: number

    Unix timestamp in milliseconds when the tick result was created (from candle timestamp in backtest or execution context when in live)

    +
    exchangeName: string

    Exchange name where signal was executed

    +
    id: string

    Unique notification identifier

    +
    maxDrawdown: IStrategyPnL

    Maximum drawdown experienced during the life of this position up to the moment this public signal was created

    +
    maxDrawdownCost: number

    Absolute profit/loss in USD at the moment the position reached its maximum drawdown during the life of this position

    +
    maxDrawdownEntries: number

    Number of entries executed at the moment the position reached its maximum drawdown during the life of this position

    +
    maxDrawdownPercentage: number

    Profit/loss as percentage at the moment the position reached its maximum drawdown during the life of this position

    +
    maxDrawdownPriceClose: number

    Exit price for PNL calculation at the moment of max drawdown

    +
    maxDrawdownPriceOpen: number

    Maximum drawdown price reached in loss direction during the life of this position

    +
    note?: string

    Optional human-readable description of signal reason

    +
    originalPriceOpen: number

    Original entry price at signal creation (unchanged by DCA averaging)

    +
    originalPriceStopLoss: number

    Original stop loss price before any trailing adjustments

    +
    originalPriceTakeProfit: number

    Original take profit price before any trailing adjustments

    +
    peakProfit: IStrategyPnL

    Peak profit achieved during the life of this position up to the moment this public signal was created

    +
    peakProfitCost: number

    Absolute profit/loss in USD at the moment the position reached its peak profit during the life of this position

    +
    peakProfitEntries: number

    Number of entries executed at the moment the position reached its peak profit during the life of this position

    +
    peakProfitPercentage: number

    Profit/loss as percentage at the moment the position reached its peak profit during the life of this position

    +
    peakProfitPriceClose: number

    Exit price for PNL calculation at the moment of peak profit

    +
    peakProfitPriceOpen: number

    Peak price reached in profit direction during the life of this position

    +
    pendingAt: number

    Pending timestamp in milliseconds (when position became pending/active at priceOpen)

    +

    Total PNL of the closed position (including all entries and partials)

    +
    pnlCost: number

    Absolute profit/loss in USD

    +
    pnlEntries: number

    Total invested capital in USD

    +
    pnlPercentage: number

    Profit/loss as percentage (e.g., 1.5 for +1.5%, -2.3 for -2.3%)

    +
    pnlPriceClose: number

    Exit price from PNL calculation (adjusted with slippage and fees)

    +
    pnlPriceOpen: number

    Entry price from PNL calculation (effective price adjusted with slippage and fees)

    +
    position: "long" | "short"

    Trade direction: "long" (buy) or "short" (sell)

    +
    priceOpen: number

    Entry price for the position

    +
    priceStopLoss: number

    Stop loss exit price

    +
    priceTakeProfit: number

    Take profit target price

    +
    scheduledAt: number

    Signal creation timestamp in milliseconds (when signal was first created/scheduled)

    +
    signalId: string

    Unique signal identifier (UUID v4)

    +
    strategyName: string

    Strategy name that generated this signal

    +
    symbol: string

    Trading pair symbol (e.g., "BTCUSDT")

    +
    timestamp: number

    Unix timestamp in milliseconds when signal was opened (pendingAt)

    +
    totalEntries: number

    Total number of DCA entries (_entry.length). 1 = no averaging.

    +
    totalPartials: number

    Total number of partial closes executed (_partial.length). 0 = no partial closes done.

    +
    type: "signal.opened"

    Discriminator for type-safe union

    +

    Interface SignalScheduledNotification

    Scheduled signal notification. Emitted when a signal is scheduled for future execution.

    -
    interface SignalScheduledNotification {
        backtest: boolean;
        cost: number;
        createdAt: number;
        currentPrice: number;
        exchangeName: string;
        id: string;
        maxDrawdown: IStrategyPnL;
        maxDrawdownCost: number;
        maxDrawdownEntries: number;
        maxDrawdownPercentage: number;
        maxDrawdownPriceClose: number;
        maxDrawdownPriceOpen: number;
        note?: string;
        originalPriceOpen: number;
        originalPriceStopLoss: number;
        originalPriceTakeProfit: number;
        peakProfit: IStrategyPnL;
        peakProfitCost: number;
        peakProfitEntries: number;
        peakProfitPercentage: number;
        peakProfitPriceClose: number;
        peakProfitPriceOpen: number;
        pnl: IStrategyPnL;
        pnlCost: number;
        pnlEntries: number;
        pnlPercentage: number;
        pnlPriceClose: number;
        pnlPriceOpen: number;
        position: "long" | "short";
        priceOpen: number;
        priceStopLoss: number;
        priceTakeProfit: number;
        scheduledAt: number;
        signalId: string;
        strategyName: string;
        symbol: string;
        timestamp: number;
        totalEntries: number;
        totalPartials: number;
        type: "signal.scheduled";
    }

    Properties

    interface SignalScheduledNotification {
        backtest: boolean;
        cost: number;
        createdAt: number;
        currentPrice: number;
        exchangeName: string;
        id: string;
        maxDrawdown: IStrategyPnL;
        maxDrawdownCost: number;
        maxDrawdownEntries: number;
        maxDrawdownPercentage: number;
        maxDrawdownPriceClose: number;
        maxDrawdownPriceOpen: number;
        note?: string;
        originalPriceOpen: number;
        originalPriceStopLoss: number;
        originalPriceTakeProfit: number;
        peakProfit: IStrategyPnL;
        peakProfitCost: number;
        peakProfitEntries: number;
        peakProfitPercentage: number;
        peakProfitPriceClose: number;
        peakProfitPriceOpen: number;
        pnl: IStrategyPnL;
        pnlCost: number;
        pnlEntries: number;
        pnlPercentage: number;
        pnlPriceClose: number;
        pnlPriceOpen: number;
        position: "long" | "short";
        priceOpen: number;
        priceStopLoss: number;
        priceTakeProfit: number;
        scheduledAt: number;
        signalId: string;
        strategyName: string;
        symbol: string;
        timestamp: number;
        totalEntries: number;
        totalPartials: number;
        type: "signal.scheduled";
    }

    Properties

    backtest cost createdAt currentPrice @@ -41,46 +41,46 @@ Emitted when a signal is scheduled for future execution.

    totalPartials type

    Properties

    backtest: boolean

    Whether this notification is from backtest mode (true) or live mode (false)

    -
    cost: number

    Cost of the initial position entry in USD (from signal.cost)

    -
    createdAt: number

    Unix timestamp in milliseconds when the tick result was created (from candle timestamp in backtest or execution context when in live)

    -
    currentPrice: number

    Current market price when signal was scheduled

    -
    exchangeName: string

    Exchange name where signal will be executed

    -
    id: string

    Unique notification identifier

    -
    maxDrawdown: IStrategyPnL

    Maximum drawdown experienced during the life of this position up to the moment this public signal was created

    -
    maxDrawdownCost: number

    Absolute profit/loss in USD at the moment the position reached its maximum drawdown during the life of this position

    -
    maxDrawdownEntries: number

    Number of entries executed at the moment the position reached its maximum drawdown during the life of this position

    -
    maxDrawdownPercentage: number

    Profit/loss as percentage at the moment the position reached its maximum drawdown during the life of this position

    -
    maxDrawdownPriceClose: number

    Exit price for PNL calculation at the moment of max drawdown

    -
    maxDrawdownPriceOpen: number

    Maximum drawdown price reached in loss direction during the life of this position

    -
    note?: string

    Optional human-readable description of signal reason

    -
    originalPriceOpen: number

    Original entry price at signal creation (unchanged by DCA averaging)

    -
    originalPriceStopLoss: number

    Original stop loss price before any trailing adjustments

    -
    originalPriceTakeProfit: number

    Original take profit price before any trailing adjustments

    -
    peakProfit: IStrategyPnL

    Peak profit achieved during the life of this position up to the moment this public signal was created

    -
    peakProfitCost: number

    Absolute profit/loss in USD at the moment the position reached its peak profit during the life of this position

    -
    peakProfitEntries: number

    Number of entries executed at the moment the position reached its peak profit during the life of this position

    -
    peakProfitPercentage: number

    Profit/loss as percentage at the moment the position reached its peak profit during the life of this position

    -
    peakProfitPriceClose: number

    Exit price for PNL calculation at the moment of peak profit

    -
    peakProfitPriceOpen: number

    Peak price reached in profit direction during the life of this position

    -

    Total PNL of the closed position (including all entries and partials)

    -
    pnlCost: number

    Absolute profit/loss in USD

    -
    pnlEntries: number

    Total invested capital in USD

    -
    pnlPercentage: number

    Profit/loss as percentage (e.g., 1.5 for +1.5%, -2.3 for -2.3%)

    -
    pnlPriceClose: number

    Exit price from PNL calculation (adjusted with slippage and fees)

    -
    pnlPriceOpen: number

    Entry price from PNL calculation (effective price adjusted with slippage and fees)

    -
    position: "long" | "short"

    Trade direction: "long" (buy) or "short" (sell)

    -
    priceOpen: number

    Target entry price for activation

    -
    priceStopLoss: number

    Stop loss exit price

    -
    priceTakeProfit: number

    Take profit target price

    -
    scheduledAt: number

    Unix timestamp in milliseconds when signal was scheduled

    -
    signalId: string

    Unique signal identifier (UUID v4)

    -
    strategyName: string

    Strategy name that generated this signal

    -
    symbol: string

    Trading pair symbol (e.g., "BTCUSDT")

    -
    timestamp: number

    Unix timestamp in milliseconds when signal was scheduled (scheduledAt)

    -
    totalEntries: number

    Total number of DCA entries (_entry.length). 1 = no averaging.

    -
    totalPartials: number

    Total number of partial closes executed (_partial.length). 0 = no partial closes done.

    -
    type: "signal.scheduled"

    Discriminator for type-safe union

    -
    +
    cost: number

    Cost of the initial position entry in USD (from signal.cost)

    +
    createdAt: number

    Unix timestamp in milliseconds when the tick result was created (from candle timestamp in backtest or execution context when in live)

    +
    currentPrice: number

    Current market price when signal was scheduled

    +
    exchangeName: string

    Exchange name where signal will be executed

    +
    id: string

    Unique notification identifier

    +
    maxDrawdown: IStrategyPnL

    Maximum drawdown experienced during the life of this position up to the moment this public signal was created

    +
    maxDrawdownCost: number

    Absolute profit/loss in USD at the moment the position reached its maximum drawdown during the life of this position

    +
    maxDrawdownEntries: number

    Number of entries executed at the moment the position reached its maximum drawdown during the life of this position

    +
    maxDrawdownPercentage: number

    Profit/loss as percentage at the moment the position reached its maximum drawdown during the life of this position

    +
    maxDrawdownPriceClose: number

    Exit price for PNL calculation at the moment of max drawdown

    +
    maxDrawdownPriceOpen: number

    Maximum drawdown price reached in loss direction during the life of this position

    +
    note?: string

    Optional human-readable description of signal reason

    +
    originalPriceOpen: number

    Original entry price at signal creation (unchanged by DCA averaging)

    +
    originalPriceStopLoss: number

    Original stop loss price before any trailing adjustments

    +
    originalPriceTakeProfit: number

    Original take profit price before any trailing adjustments

    +
    peakProfit: IStrategyPnL

    Peak profit achieved during the life of this position up to the moment this public signal was created

    +
    peakProfitCost: number

    Absolute profit/loss in USD at the moment the position reached its peak profit during the life of this position

    +
    peakProfitEntries: number

    Number of entries executed at the moment the position reached its peak profit during the life of this position

    +
    peakProfitPercentage: number

    Profit/loss as percentage at the moment the position reached its peak profit during the life of this position

    +
    peakProfitPriceClose: number

    Exit price for PNL calculation at the moment of peak profit

    +
    peakProfitPriceOpen: number

    Peak price reached in profit direction during the life of this position

    +

    Total PNL of the closed position (including all entries and partials)

    +
    pnlCost: number

    Absolute profit/loss in USD

    +
    pnlEntries: number

    Total invested capital in USD

    +
    pnlPercentage: number

    Profit/loss as percentage (e.g., 1.5 for +1.5%, -2.3 for -2.3%)

    +
    pnlPriceClose: number

    Exit price from PNL calculation (adjusted with slippage and fees)

    +
    pnlPriceOpen: number

    Entry price from PNL calculation (effective price adjusted with slippage and fees)

    +
    position: "long" | "short"

    Trade direction: "long" (buy) or "short" (sell)

    +
    priceOpen: number

    Target entry price for activation

    +
    priceStopLoss: number

    Stop loss exit price

    +
    priceTakeProfit: number

    Take profit target price

    +
    scheduledAt: number

    Unix timestamp in milliseconds when signal was scheduled

    +
    signalId: string

    Unique signal identifier (UUID v4)

    +
    strategyName: string

    Strategy name that generated this signal

    +
    symbol: string

    Trading pair symbol (e.g., "BTCUSDT")

    +
    timestamp: number

    Unix timestamp in milliseconds when signal was scheduled (scheduledAt)

    +
    totalEntries: number

    Total number of DCA entries (_entry.length). 1 = no averaging.

    +
    totalPartials: number

    Total number of partial closes executed (_partial.length). 0 = no partial closes done.

    +
    type: "signal.scheduled"

    Discriminator for type-safe union

    +

    Interface SignalSyncCloseNotification

    Signal sync close notification. Emitted when an active pending signal is closed (TP/SL hit, time expired, or user-initiated).

    -
    interface SignalSyncCloseNotification {
        backtest: boolean;
        closeReason: string;
        createdAt: number;
        currentPrice: number;
        exchangeName: string;
        id: string;
        maxDrawdown: IStrategyPnL;
        maxDrawdownCost: number;
        maxDrawdownEntries: number;
        maxDrawdownPercentage: number;
        maxDrawdownPriceClose: number;
        maxDrawdownPriceOpen: number;
        note?: string;
        originalPriceOpen: number;
        originalPriceStopLoss: number;
        originalPriceTakeProfit: number;
        peakProfit: IStrategyPnL;
        peakProfitCost: number;
        peakProfitEntries: number;
        peakProfitPercentage: number;
        peakProfitPriceClose: number;
        peakProfitPriceOpen: number;
        pendingAt: number;
        pnl: IStrategyPnL;
        pnlCost: number;
        pnlEntries: number;
        pnlPercentage: number;
        pnlPriceClose: number;
        pnlPriceOpen: number;
        position: "long" | "short";
        priceOpen: number;
        priceStopLoss: number;
        priceTakeProfit: number;
        scheduledAt: number;
        signalId: string;
        strategyName: string;
        symbol: string;
        timestamp: number;
        totalEntries: number;
        totalPartials: number;
        type: "signal_sync.close";
    }

    Properties

    interface SignalSyncCloseNotification {
        backtest: boolean;
        closeReason: string;
        createdAt: number;
        currentPrice: number;
        exchangeName: string;
        id: string;
        maxDrawdown: IStrategyPnL;
        maxDrawdownCost: number;
        maxDrawdownEntries: number;
        maxDrawdownPercentage: number;
        maxDrawdownPriceClose: number;
        maxDrawdownPriceOpen: number;
        note?: string;
        originalPriceOpen: number;
        originalPriceStopLoss: number;
        originalPriceTakeProfit: number;
        peakProfit: IStrategyPnL;
        peakProfitCost: number;
        peakProfitEntries: number;
        peakProfitPercentage: number;
        peakProfitPriceClose: number;
        peakProfitPriceOpen: number;
        pendingAt: number;
        pnl: IStrategyPnL;
        pnlCost: number;
        pnlEntries: number;
        pnlPercentage: number;
        pnlPriceClose: number;
        pnlPriceOpen: number;
        position: "long" | "short";
        priceOpen: number;
        priceStopLoss: number;
        priceTakeProfit: number;
        scheduledAt: number;
        signalId: string;
        strategyName: string;
        symbol: string;
        timestamp: number;
        totalEntries: number;
        totalPartials: number;
        type: "signal_sync.close";
    }

    Properties

    backtest closeReason createdAt currentPrice @@ -42,47 +42,47 @@ Emitted when an active pending signal is closed (TP/SL hit, time expired, or use totalPartials type

    Properties

    backtest: boolean

    Whether this notification is from backtest mode (true) or live mode (false)

    -
    closeReason: string

    Why the signal was closed (take_profit | stop_loss | time_expired | closed)

    -
    createdAt: number

    Unix timestamp in milliseconds when the notification was created

    -
    currentPrice: number

    Current market price at close

    -
    exchangeName: string

    Exchange name where signal was executed

    -
    id: string

    Unique notification identifier

    -
    maxDrawdown: IStrategyPnL

    Maximum drawdown experienced during the life of this position up to the moment this public signal was created

    -
    maxDrawdownCost: number

    Absolute profit/loss in USD at the moment the position reached its maximum drawdown during the life of this position

    -
    maxDrawdownEntries: number

    Number of entries executed at the moment the position reached its maximum drawdown during the life of this position

    -
    maxDrawdownPercentage: number

    Profit/loss as percentage at the moment the position reached its maximum drawdown during the life of this position

    -
    maxDrawdownPriceClose: number

    Exit price for PNL calculation at the moment of max drawdown

    -
    maxDrawdownPriceOpen: number

    Maximum drawdown price reached in loss direction during the life of this position

    -
    note?: string

    Optional human-readable description of signal reason

    -
    originalPriceOpen: number

    Original entry price before any DCA averaging

    -
    originalPriceStopLoss: number

    Original stop loss price before any trailing adjustments

    -
    originalPriceTakeProfit: number

    Original take profit price before any trailing adjustments

    -
    peakProfit: IStrategyPnL

    Peak profit achieved during the life of this position up to the moment this public signal was created

    -
    peakProfitCost: number

    Absolute profit/loss in USD at the moment the position reached its peak profit during the life of this position

    -
    peakProfitEntries: number

    Number of entries executed at the moment the position reached its peak profit during the life of this position

    -
    peakProfitPercentage: number

    Profit/loss as percentage at the moment the position reached its peak profit during the life of this position

    -
    peakProfitPriceClose: number

    Exit price for PNL calculation at the moment of peak profit

    -
    peakProfitPriceOpen: number

    Peak price reached in profit direction during the life of this position

    -
    pendingAt: number

    Position activation timestamp in milliseconds

    -

    Total PNL of the closed position (including all entries and partials)

    -
    pnlCost: number

    Absolute profit/loss in USD

    -
    pnlEntries: number

    Total invested capital in USD

    -
    pnlPercentage: number

    Profit/loss as percentage

    -
    pnlPriceClose: number

    Exit price from PNL calculation

    -
    pnlPriceOpen: number

    Entry price from PNL calculation

    -
    position: "long" | "short"

    Trade direction: "long" (buy) or "short" (sell)

    -
    priceOpen: number

    Effective entry price at close

    -
    priceStopLoss: number

    Effective stop loss price at close

    -
    priceTakeProfit: number

    Effective take profit price at close

    -
    scheduledAt: number

    Signal creation timestamp in milliseconds

    -
    signalId: string

    Unique signal identifier (UUID v4)

    -
    strategyName: string

    Strategy name that generated this signal

    -
    symbol: string

    Trading pair symbol (e.g., "BTCUSDT")

    -
    timestamp: number

    Unix timestamp in milliseconds when signal was closed

    -
    totalEntries: number

    Total number of DCA entries (_entry.length). 1 = no averaging.

    -
    totalPartials: number

    Total number of partial closes executed (_partial.length). 0 = no partial closes done.

    -
    type: "signal_sync.close"

    Discriminator for type-safe union

    -
    +
    closeReason: string

    Why the signal was closed (take_profit | stop_loss | time_expired | closed)

    +
    createdAt: number

    Unix timestamp in milliseconds when the notification was created

    +
    currentPrice: number

    Current market price at close

    +
    exchangeName: string

    Exchange name where signal was executed

    +
    id: string

    Unique notification identifier

    +
    maxDrawdown: IStrategyPnL

    Maximum drawdown experienced during the life of this position up to the moment this public signal was created

    +
    maxDrawdownCost: number

    Absolute profit/loss in USD at the moment the position reached its maximum drawdown during the life of this position

    +
    maxDrawdownEntries: number

    Number of entries executed at the moment the position reached its maximum drawdown during the life of this position

    +
    maxDrawdownPercentage: number

    Profit/loss as percentage at the moment the position reached its maximum drawdown during the life of this position

    +
    maxDrawdownPriceClose: number

    Exit price for PNL calculation at the moment of max drawdown

    +
    maxDrawdownPriceOpen: number

    Maximum drawdown price reached in loss direction during the life of this position

    +
    note?: string

    Optional human-readable description of signal reason

    +
    originalPriceOpen: number

    Original entry price before any DCA averaging

    +
    originalPriceStopLoss: number

    Original stop loss price before any trailing adjustments

    +
    originalPriceTakeProfit: number

    Original take profit price before any trailing adjustments

    +
    peakProfit: IStrategyPnL

    Peak profit achieved during the life of this position up to the moment this public signal was created

    +
    peakProfitCost: number

    Absolute profit/loss in USD at the moment the position reached its peak profit during the life of this position

    +
    peakProfitEntries: number

    Number of entries executed at the moment the position reached its peak profit during the life of this position

    +
    peakProfitPercentage: number

    Profit/loss as percentage at the moment the position reached its peak profit during the life of this position

    +
    peakProfitPriceClose: number

    Exit price for PNL calculation at the moment of peak profit

    +
    peakProfitPriceOpen: number

    Peak price reached in profit direction during the life of this position

    +
    pendingAt: number

    Position activation timestamp in milliseconds

    +

    Total PNL of the closed position (including all entries and partials)

    +
    pnlCost: number

    Absolute profit/loss in USD

    +
    pnlEntries: number

    Total invested capital in USD

    +
    pnlPercentage: number

    Profit/loss as percentage

    +
    pnlPriceClose: number

    Exit price from PNL calculation

    +
    pnlPriceOpen: number

    Entry price from PNL calculation

    +
    position: "long" | "short"

    Trade direction: "long" (buy) or "short" (sell)

    +
    priceOpen: number

    Effective entry price at close

    +
    priceStopLoss: number

    Effective stop loss price at close

    +
    priceTakeProfit: number

    Effective take profit price at close

    +
    scheduledAt: number

    Signal creation timestamp in milliseconds

    +
    signalId: string

    Unique signal identifier (UUID v4)

    +
    strategyName: string

    Strategy name that generated this signal

    +
    symbol: string

    Trading pair symbol (e.g., "BTCUSDT")

    +
    timestamp: number

    Unix timestamp in milliseconds when signal was closed

    +
    totalEntries: number

    Total number of DCA entries (_entry.length). 1 = no averaging.

    +
    totalPartials: number

    Total number of partial closes executed (_partial.length). 0 = no partial closes done.

    +
    type: "signal_sync.close"

    Discriminator for type-safe union

    +

    Interface SignalSyncOpenNotification

    Signal sync open notification. Emitted when a scheduled (limit order) signal is activated and the position is opened.

    -
    interface SignalSyncOpenNotification {
        backtest: boolean;
        cost: number;
        createdAt: number;
        currentPrice: number;
        exchangeName: string;
        id: string;
        maxDrawdown: IStrategyPnL;
        maxDrawdownCost: number;
        maxDrawdownEntries: number;
        maxDrawdownPercentage: number;
        maxDrawdownPriceClose: number;
        maxDrawdownPriceOpen: number;
        note?: string;
        originalPriceOpen: number;
        originalPriceStopLoss: number;
        originalPriceTakeProfit: number;
        peakProfit: IStrategyPnL;
        peakProfitCost: number;
        peakProfitEntries: number;
        peakProfitPercentage: number;
        peakProfitPriceClose: number;
        peakProfitPriceOpen: number;
        pendingAt: number;
        pnl: IStrategyPnL;
        pnlCost: number;
        pnlEntries: number;
        pnlPercentage: number;
        pnlPriceClose: number;
        pnlPriceOpen: number;
        position: "long" | "short";
        priceOpen: number;
        priceStopLoss: number;
        priceTakeProfit: number;
        scheduledAt: number;
        signalId: string;
        strategyName: string;
        symbol: string;
        timestamp: number;
        totalEntries: number;
        totalPartials: number;
        type: "signal_sync.open";
    }

    Properties

    interface SignalSyncOpenNotification {
        backtest: boolean;
        cost: number;
        createdAt: number;
        currentPrice: number;
        exchangeName: string;
        id: string;
        maxDrawdown: IStrategyPnL;
        maxDrawdownCost: number;
        maxDrawdownEntries: number;
        maxDrawdownPercentage: number;
        maxDrawdownPriceClose: number;
        maxDrawdownPriceOpen: number;
        note?: string;
        originalPriceOpen: number;
        originalPriceStopLoss: number;
        originalPriceTakeProfit: number;
        peakProfit: IStrategyPnL;
        peakProfitCost: number;
        peakProfitEntries: number;
        peakProfitPercentage: number;
        peakProfitPriceClose: number;
        peakProfitPriceOpen: number;
        pendingAt: number;
        pnl: IStrategyPnL;
        pnlCost: number;
        pnlEntries: number;
        pnlPercentage: number;
        pnlPriceClose: number;
        pnlPriceOpen: number;
        position: "long" | "short";
        priceOpen: number;
        priceStopLoss: number;
        priceTakeProfit: number;
        scheduledAt: number;
        signalId: string;
        strategyName: string;
        symbol: string;
        timestamp: number;
        totalEntries: number;
        totalPartials: number;
        type: "signal_sync.open";
    }

    Properties

    backtest cost createdAt currentPrice @@ -42,47 +42,47 @@ Emitted when a scheduled (limit order) signal is activated and the position is o totalPartials type

    Properties

    backtest: boolean

    Whether this notification is from backtest mode (true) or live mode (false)

    -
    cost: number

    Cost of the position entry in USD

    -
    createdAt: number

    Unix timestamp in milliseconds when the notification was created

    -
    currentPrice: number

    Current market price at activation

    -
    exchangeName: string

    Exchange name where signal was executed

    -
    id: string

    Unique notification identifier

    -
    maxDrawdown: IStrategyPnL

    Maximum drawdown experienced during the life of this position up to the moment this public signal was created

    -
    maxDrawdownCost: number

    Absolute profit/loss in USD at the moment the position reached its maximum drawdown during the life of this position

    -
    maxDrawdownEntries: number

    Number of entries executed at the moment the position reached its maximum drawdown during the life of this position

    -
    maxDrawdownPercentage: number

    Profit/loss as percentage at the moment the position reached its maximum drawdown during the life of this position

    -
    maxDrawdownPriceClose: number

    Exit price for PNL calculation at the moment of max drawdown

    -
    maxDrawdownPriceOpen: number

    Maximum drawdown price reached in loss direction during the life of this position

    -
    note?: string

    Optional human-readable description of signal reason

    -
    originalPriceOpen: number

    Original entry price before any DCA averaging

    -
    originalPriceStopLoss: number

    Original stop loss price before any trailing adjustments

    -
    originalPriceTakeProfit: number

    Original take profit price before any trailing adjustments

    -
    peakProfit: IStrategyPnL

    Peak profit achieved during the life of this position up to the moment this public signal was created

    -
    peakProfitCost: number

    Absolute profit/loss in USD at the moment the position reached its peak profit during the life of this position

    -
    peakProfitEntries: number

    Number of entries executed at the moment the position reached its peak profit during the life of this position

    -
    peakProfitPercentage: number

    Profit/loss as percentage at the moment the position reached its peak profit during the life of this position

    -
    peakProfitPriceClose: number

    Exit price for PNL calculation at the moment of peak profit

    -
    peakProfitPriceOpen: number

    Peak price reached in profit direction during the life of this position

    -
    pendingAt: number

    Position activation timestamp in milliseconds

    -

    Total PNL of the closed position (including all entries and partials)

    -
    pnlCost: number

    Absolute profit/loss in USD

    -
    pnlEntries: number

    Total invested capital in USD

    -
    pnlPercentage: number

    Profit/loss as percentage

    -
    pnlPriceClose: number

    Exit price from PNL calculation

    -
    pnlPriceOpen: number

    Entry price from PNL calculation

    -
    position: "long" | "short"

    Trade direction: "long" (buy) or "short" (sell)

    -
    priceOpen: number

    Entry price at which the limit order was filled

    -
    priceStopLoss: number

    Effective stop loss price at activation

    -
    priceTakeProfit: number

    Effective take profit price at activation

    -
    scheduledAt: number

    Signal creation timestamp in milliseconds

    -
    signalId: string

    Unique signal identifier (UUID v4)

    -
    strategyName: string

    Strategy name that generated this signal

    -
    symbol: string

    Trading pair symbol (e.g., "BTCUSDT")

    -
    timestamp: number

    Unix timestamp in milliseconds when signal was opened

    -
    totalEntries: number

    Total number of DCA entries (_entry.length). 1 = no averaging.

    -
    totalPartials: number

    Total number of partial closes executed (_partial.length). 0 = no partial closes done.

    -
    type: "signal_sync.open"

    Discriminator for type-safe union

    -
    +
    cost: number

    Cost of the position entry in USD

    +
    createdAt: number

    Unix timestamp in milliseconds when the notification was created

    +
    currentPrice: number

    Current market price at activation

    +
    exchangeName: string

    Exchange name where signal was executed

    +
    id: string

    Unique notification identifier

    +
    maxDrawdown: IStrategyPnL

    Maximum drawdown experienced during the life of this position up to the moment this public signal was created

    +
    maxDrawdownCost: number

    Absolute profit/loss in USD at the moment the position reached its maximum drawdown during the life of this position

    +
    maxDrawdownEntries: number

    Number of entries executed at the moment the position reached its maximum drawdown during the life of this position

    +
    maxDrawdownPercentage: number

    Profit/loss as percentage at the moment the position reached its maximum drawdown during the life of this position

    +
    maxDrawdownPriceClose: number

    Exit price for PNL calculation at the moment of max drawdown

    +
    maxDrawdownPriceOpen: number

    Maximum drawdown price reached in loss direction during the life of this position

    +
    note?: string

    Optional human-readable description of signal reason

    +
    originalPriceOpen: number

    Original entry price before any DCA averaging

    +
    originalPriceStopLoss: number

    Original stop loss price before any trailing adjustments

    +
    originalPriceTakeProfit: number

    Original take profit price before any trailing adjustments

    +
    peakProfit: IStrategyPnL

    Peak profit achieved during the life of this position up to the moment this public signal was created

    +
    peakProfitCost: number

    Absolute profit/loss in USD at the moment the position reached its peak profit during the life of this position

    +
    peakProfitEntries: number

    Number of entries executed at the moment the position reached its peak profit during the life of this position

    +
    peakProfitPercentage: number

    Profit/loss as percentage at the moment the position reached its peak profit during the life of this position

    +
    peakProfitPriceClose: number

    Exit price for PNL calculation at the moment of peak profit

    +
    peakProfitPriceOpen: number

    Peak price reached in profit direction during the life of this position

    +
    pendingAt: number

    Position activation timestamp in milliseconds

    +

    Total PNL of the closed position (including all entries and partials)

    +
    pnlCost: number

    Absolute profit/loss in USD

    +
    pnlEntries: number

    Total invested capital in USD

    +
    pnlPercentage: number

    Profit/loss as percentage

    +
    pnlPriceClose: number

    Exit price from PNL calculation

    +
    pnlPriceOpen: number

    Entry price from PNL calculation

    +
    position: "long" | "short"

    Trade direction: "long" (buy) or "short" (sell)

    +
    priceOpen: number

    Entry price at which the limit order was filled

    +
    priceStopLoss: number

    Effective stop loss price at activation

    +
    priceTakeProfit: number

    Effective take profit price at activation

    +
    scheduledAt: number

    Signal creation timestamp in milliseconds

    +
    signalId: string

    Unique signal identifier (UUID v4)

    +
    strategyName: string

    Strategy name that generated this signal

    +
    symbol: string

    Trading pair symbol (e.g., "BTCUSDT")

    +
    timestamp: number

    Unix timestamp in milliseconds when signal was opened

    +
    totalEntries: number

    Total number of DCA entries (_entry.length). 1 = no averaging.

    +
    totalPartials: number

    Total number of partial closes executed (_partial.length). 0 = no partial closes done.

    +
    type: "signal_sync.open"

    Discriminator for type-safe union

    +

    Interface StrategyEvent

    Unified strategy event data for markdown report generation. Contains all information about strategy management actions.

    -
    interface StrategyEvent {
        action: StrategyActionType;
        activateId?: string;
        backtest: boolean;
        cancelId?: string;
        closeId?: string;
        cost?: number;
        createdAt: string;
        currentPrice?: number;
        effectivePriceOpen?: number;
        exchangeName: string;
        frameName: string;
        note?: string;
        originalPriceOpen?: number;
        originalPriceStopLoss?: number;
        originalPriceTakeProfit?: number;
        pendingAt?: number;
        percentShift?: number;
        percentToClose?: number;
        pnl?: IStrategyPnL;
        position?: "long" | "short";
        priceOpen?: number;
        priceStopLoss?: number;
        priceTakeProfit?: number;
        scheduledAt?: number;
        signalId: string;
        strategyName: string;
        symbol: string;
        timestamp: number;
        totalEntries?: number;
        totalPartials?: number;
    }

    Properties

    interface StrategyEvent {
        action: StrategyActionType;
        activateId?: string;
        backtest: boolean;
        cancelId?: string;
        closeId?: string;
        cost?: number;
        createdAt: string;
        currentPrice?: number;
        effectivePriceOpen?: number;
        exchangeName: string;
        frameName: string;
        note?: string;
        originalPriceOpen?: number;
        originalPriceStopLoss?: number;
        originalPriceTakeProfit?: number;
        pendingAt?: number;
        percentShift?: number;
        percentToClose?: number;
        pnl?: IStrategyPnL;
        position?: "long" | "short";
        priceOpen?: number;
        priceStopLoss?: number;
        priceTakeProfit?: number;
        scheduledAt?: number;
        signalId: string;
        strategyName: string;
        symbol: string;
        timestamp: number;
        totalEntries?: number;
        totalPartials?: number;
    }

    Properties

    action activateId? backtest cancelId? @@ -31,36 +31,36 @@ Contains all information about strategy management actions.

    totalEntries? totalPartials?

    Properties

    Action type

    -
    activateId?: string

    Activate ID for activate-scheduled action

    -
    backtest: boolean

    True if backtest mode, false if live mode

    -
    cancelId?: string

    Cancel ID for cancel-scheduled action

    -
    closeId?: string

    Close ID for close-pending action

    -
    cost?: number

    Cost of this entry in USD (average-buy action only)

    -
    createdAt: string

    ISO timestamp string when action was created

    -
    currentPrice?: number

    Current market price when action was executed

    -
    effectivePriceOpen?: number

    Averaged entry price after DCA addition (average-buy action only)

    -
    exchangeName: string

    Exchange name

    -
    frameName: string

    Frame name (empty for live)

    -
    note?: string

    Optional note from commit payload

    -
    originalPriceOpen?: number

    Original entry price at signal creation (unchanged by DCA averaging)

    -
    originalPriceStopLoss?: number

    Original stop loss price before any trailing adjustments

    -
    originalPriceTakeProfit?: number

    Original take profit price before any trailing adjustments

    -
    pendingAt?: number

    Pending timestamp in milliseconds (when position became pending/active at priceOpen)

    -
    percentShift?: number

    Percent shift for trailing stop/take

    -
    percentToClose?: number

    Percent to close for partial profit/loss

    -

    PNL at the moment of this action

    -
    position?: "long" | "short"

    Trade direction: "long" (buy) or "short" (sell)

    -
    priceOpen?: number

    Entry price for the position

    -
    priceStopLoss?: number

    Effective stop loss price (with trailing if set)

    -
    priceTakeProfit?: number

    Effective take profit price (with trailing if set)

    -
    scheduledAt?: number

    Signal creation timestamp in milliseconds (when signal was first created/scheduled)

    -
    signalId: string

    Signal ID

    -
    strategyName: string

    Strategy name

    -
    symbol: string

    Trading pair symbol

    -
    timestamp: number

    Event timestamp in milliseconds

    -
    totalEntries?: number

    Total number of DCA entries after this addition (average-buy action only)

    -
    totalPartials?: number

    Total number of partial closes executed (_partial.length)

    -
    +
    activateId?: string

    Activate ID for activate-scheduled action

    +
    backtest: boolean

    True if backtest mode, false if live mode

    +
    cancelId?: string

    Cancel ID for cancel-scheduled action

    +
    closeId?: string

    Close ID for close-pending action

    +
    cost?: number

    Cost of this entry in USD (average-buy action only)

    +
    createdAt: string

    ISO timestamp string when action was created

    +
    currentPrice?: number

    Current market price when action was executed

    +
    effectivePriceOpen?: number

    Averaged entry price after DCA addition (average-buy action only)

    +
    exchangeName: string

    Exchange name

    +
    frameName: string

    Frame name (empty for live)

    +
    note?: string

    Optional note from commit payload

    +
    originalPriceOpen?: number

    Original entry price at signal creation (unchanged by DCA averaging)

    +
    originalPriceStopLoss?: number

    Original stop loss price before any trailing adjustments

    +
    originalPriceTakeProfit?: number

    Original take profit price before any trailing adjustments

    +
    pendingAt?: number

    Pending timestamp in milliseconds (when position became pending/active at priceOpen)

    +
    percentShift?: number

    Percent shift for trailing stop/take

    +
    percentToClose?: number

    Percent to close for partial profit/loss

    +

    PNL at the moment of this action

    +
    position?: "long" | "short"

    Trade direction: "long" (buy) or "short" (sell)

    +
    priceOpen?: number

    Entry price for the position

    +
    priceStopLoss?: number

    Effective stop loss price (with trailing if set)

    +
    priceTakeProfit?: number

    Effective take profit price (with trailing if set)

    +
    scheduledAt?: number

    Signal creation timestamp in milliseconds (when signal was first created/scheduled)

    +
    signalId: string

    Signal ID

    +
    strategyName: string

    Strategy name

    +
    symbol: string

    Trading pair symbol

    +
    timestamp: number

    Event timestamp in milliseconds

    +
    totalEntries?: number

    Total number of DCA entries after this addition (average-buy action only)

    +
    totalPartials?: number

    Total number of partial closes executed (_partial.length)

    +

    Interface SyncEvent

    Unified sync event data for markdown report generation. Contains all information about signal lifecycle sync events.

    -
    interface SyncEvent {
        action: SyncActionType;
        backtest: boolean;
        closeReason?: StrategyCloseReason;
        createdAt: string;
        currentPrice: number;
        exchangeName: string;
        frameName: string;
        maxDrawdown: IStrategyPnL;
        originalPriceOpen: number;
        originalPriceStopLoss: number;
        originalPriceTakeProfit: number;
        peakProfit: IStrategyPnL;
        pendingAt: number;
        pnl: IStrategyPnL;
        position: "long" | "short";
        priceOpen: number;
        priceStopLoss: number;
        priceTakeProfit: number;
        scheduledAt: number;
        signalId: string;
        strategyName: string;
        symbol: string;
        timestamp: number;
        totalEntries: number;
        totalPartials: number;
    }

    Properties

    interface SyncEvent {
        action: SyncActionType;
        backtest: boolean;
        closeReason?: StrategyCloseReason;
        createdAt: string;
        currentPrice: number;
        exchangeName: string;
        frameName: string;
        maxDrawdown: IStrategyPnL;
        originalPriceOpen: number;
        originalPriceStopLoss: number;
        originalPriceTakeProfit: number;
        peakProfit: IStrategyPnL;
        pendingAt: number;
        pnl: IStrategyPnL;
        position: "long" | "short";
        priceOpen: number;
        priceStopLoss: number;
        priceTakeProfit: number;
        scheduledAt: number;
        signalId: string;
        strategyName: string;
        symbol: string;
        timestamp: number;
        totalEntries: number;
        totalPartials: number;
    }

    Properties

    action backtest closeReason? createdAt @@ -26,31 +26,31 @@ Contains all information about signal lifecycle sync events.

    totalEntries totalPartials

    Properties

    action: SyncActionType

    Sync action type

    -
    backtest: boolean

    Whether this event is from backtest mode

    -
    closeReason?: StrategyCloseReason

    Why the signal was closed (signal-close only)

    -
    createdAt: string

    ISO timestamp string when event was created

    -
    currentPrice: number

    Market price at the moment of this event

    -
    exchangeName: string

    Exchange name

    -
    frameName: string

    Frame name (empty for live)

    -
    maxDrawdown: IStrategyPnL

    Maximum drawdown experienced during the life of this position up to the moment this public signal was created

    -
    originalPriceOpen: number

    Original entry price before any DCA averaging

    -
    originalPriceStopLoss: number

    Original stop loss price before any trailing adjustments

    -
    originalPriceTakeProfit: number

    Original take profit price before any trailing adjustments

    -
    peakProfit: IStrategyPnL

    Peak profit achieved during the life of this position up to the moment this public signal was created

    -
    pendingAt: number

    Position activation timestamp in milliseconds

    -

    Total PNL of the closed position (including all entries and partials)

    -
    position: "long" | "short"

    Trade direction: "long" (buy) or "short" (sell)

    -
    priceOpen: number

    Entry price at which the limit order was filled

    -
    priceStopLoss: number

    Effective stop loss price

    -
    priceTakeProfit: number

    Effective take profit price

    -
    scheduledAt: number

    Signal creation timestamp in milliseconds

    -
    signalId: string

    Signal unique identifier

    -
    strategyName: string

    Strategy name

    -
    symbol: string

    Trading pair symbol

    -
    timestamp: number

    Event timestamp in milliseconds

    -
    totalEntries: number

    Total number of DCA entries

    -
    totalPartials: number

    Total number of partial closes executed

    -
    +
    backtest: boolean

    Whether this event is from backtest mode

    +
    closeReason?: StrategyCloseReason

    Why the signal was closed (signal-close only)

    +
    createdAt: string

    ISO timestamp string when event was created

    +
    currentPrice: number

    Market price at the moment of this event

    +
    exchangeName: string

    Exchange name

    +
    frameName: string

    Frame name (empty for live)

    +
    maxDrawdown: IStrategyPnL

    Maximum drawdown experienced during the life of this position up to the moment this public signal was created

    +
    originalPriceOpen: number

    Original entry price before any DCA averaging

    +
    originalPriceStopLoss: number

    Original stop loss price before any trailing adjustments

    +
    originalPriceTakeProfit: number

    Original take profit price before any trailing adjustments

    +
    peakProfit: IStrategyPnL

    Peak profit achieved during the life of this position up to the moment this public signal was created

    +
    pendingAt: number

    Position activation timestamp in milliseconds

    +

    Total PNL of the closed position (including all entries and partials)

    +
    position: "long" | "short"

    Trade direction: "long" (buy) or "short" (sell)

    +
    priceOpen: number

    Entry price at which the limit order was filled

    +
    priceStopLoss: number

    Effective stop loss price

    +
    priceTakeProfit: number

    Effective take profit price

    +
    scheduledAt: number

    Signal creation timestamp in milliseconds

    +
    signalId: string

    Signal unique identifier

    +
    strategyName: string

    Strategy name

    +
    symbol: string

    Trading pair symbol

    +
    timestamp: number

    Event timestamp in milliseconds

    +
    totalEntries: number

    Total number of DCA entries

    +
    totalPartials: number

    Total number of partial closes executed

    +

    Interface TickEvent

    Unified tick event data for report generation. Contains all information about a tick event regardless of action type.

    -
    interface TickEvent {
        action:
            | "waiting"
            | "active"
            | "closed"
            | "idle"
            | "opened"
            | "scheduled"
            | "cancelled";
        cancelReason?: string;
        closeReason?: string;
        currentPrice: number;
        duration?: number;
        fallPnl?: number;
        note?: string;
        originalPriceOpen?: number;
        originalPriceStopLoss?: number;
        originalPriceTakeProfit?: number;
        partialExecuted?: number;
        peakPnl?: number;
        pendingAt?: number;
        percentSl?: number;
        percentTp?: number;
        pnl?: number;
        pnlCost?: number;
        pnlEntries?: number;
        position?: string;
        priceOpen?: number;
        priceStopLoss?: number;
        priceTakeProfit?: number;
        scheduledAt?: number;
        signalId?: string;
        symbol?: string;
        timestamp: number;
        totalEntries?: number;
        totalPartials?: number;
    }

    Properties

    interface TickEvent {
        action:
            | "waiting"
            | "active"
            | "closed"
            | "idle"
            | "scheduled"
            | "cancelled"
            | "opened";
        cancelReason?: string;
        closeReason?: string;
        currentPrice: number;
        duration?: number;
        fallPnl?: number;
        note?: string;
        originalPriceOpen?: number;
        originalPriceStopLoss?: number;
        originalPriceTakeProfit?: number;
        partialExecuted?: number;
        peakPnl?: number;
        pendingAt?: number;
        percentSl?: number;
        percentTp?: number;
        pnl?: number;
        pnlCost?: number;
        pnlEntries?: number;
        position?: string;
        priceOpen?: number;
        priceStopLoss?: number;
        priceTakeProfit?: number;
        scheduledAt?: number;
        signalId?: string;
        symbol?: string;
        timestamp: number;
        totalEntries?: number;
        totalPartials?: number;
    }

    Properties

    action cancelReason? closeReason? currentPrice @@ -28,35 +28,35 @@ Contains all information about a tick event regardless of action type.

    timestamp totalEntries? totalPartials? -

    Properties

    action:
        | "waiting"
        | "active"
        | "closed"
        | "idle"
        | "opened"
        | "scheduled"
        | "cancelled"

    Event action type

    -
    cancelReason?: string

    Cancel reason (only for cancelled)

    -
    closeReason?: string

    Close reason (only for closed)

    -
    currentPrice: number

    Current price

    -
    duration?: number

    Duration in minutes (only for closed)

    -
    fallPnl?: number

    Fall PNL percentage at worst price during position (_fall.pnlPercentage, only for closed)

    -
    note?: string

    Signal note (only for scheduled/waiting/opened/active/closed/cancelled)

    -
    originalPriceOpen?: number

    Original entry price at signal creation (unchanged by DCA averaging)

    -
    originalPriceStopLoss?: number

    Original stop loss price before modifications (only for scheduled/waiting/opened/active/closed/cancelled)

    -
    originalPriceTakeProfit?: number

    Original take profit price before modifications (only for scheduled/waiting/opened/active/closed/cancelled)

    -
    partialExecuted?: number

    Total executed percentage from partial closes (only for scheduled/waiting/opened/active/closed/cancelled)

    -
    peakPnl?: number

    Peak PNL percentage at best price during position (_peak.pnlPercentage, only for closed)

    -
    pendingAt?: number

    Timestamp when position became active (only for opened/active/closed)

    -
    percentSl?: number

    Percentage progress towards stop loss (only for active/waiting)

    -
    percentTp?: number

    Percentage progress towards take profit (only for active/waiting)

    -
    pnl?: number

    PNL percentage (for active/waiting: unrealized, for closed: realized)

    -
    pnlCost?: number

    Absolute profit/loss in USD (for active/waiting: unrealized, for closed: realized)

    -
    pnlEntries?: number

    Total invested capital in USD

    -
    position?: string

    Position type (only for scheduled/waiting/opened/active/closed/cancelled)

    -
    priceOpen?: number

    Open price (only for scheduled/waiting/opened/active/closed/cancelled)

    -
    priceStopLoss?: number

    Stop loss price (only for scheduled/waiting/opened/active/closed/cancelled)

    -
    priceTakeProfit?: number

    Take profit price (only for scheduled/waiting/opened/active/closed/cancelled)

    -
    scheduledAt?: number

    Timestamp when signal was created/scheduled (only for scheduled/waiting/opened/active/closed/cancelled)

    -
    signalId?: string

    Signal ID (only for scheduled/waiting/opened/active/closed/cancelled)

    -
    symbol?: string

    Trading pair symbol (only for non-idle events)

    -
    timestamp: number

    Event timestamp in milliseconds (scheduledAt for scheduled events, pendingAt for opened/closed events)

    -
    totalEntries?: number

    Total number of DCA entries (_entry.length). 1 = no averaging.

    -
    totalPartials?: number

    Total number of partial closes executed (_partial.length)

    -
    +

    Properties

    action:
        | "waiting"
        | "active"
        | "closed"
        | "idle"
        | "scheduled"
        | "cancelled"
        | "opened"

    Event action type

    +
    cancelReason?: string

    Cancel reason (only for cancelled)

    +
    closeReason?: string

    Close reason (only for closed)

    +
    currentPrice: number

    Current price

    +
    duration?: number

    Duration in minutes (only for closed)

    +
    fallPnl?: number

    Fall PNL percentage at worst price during position (_fall.pnlPercentage, only for closed)

    +
    note?: string

    Signal note (only for scheduled/waiting/opened/active/closed/cancelled)

    +
    originalPriceOpen?: number

    Original entry price at signal creation (unchanged by DCA averaging)

    +
    originalPriceStopLoss?: number

    Original stop loss price before modifications (only for scheduled/waiting/opened/active/closed/cancelled)

    +
    originalPriceTakeProfit?: number

    Original take profit price before modifications (only for scheduled/waiting/opened/active/closed/cancelled)

    +
    partialExecuted?: number

    Total executed percentage from partial closes (only for scheduled/waiting/opened/active/closed/cancelled)

    +
    peakPnl?: number

    Peak PNL percentage at best price during position (_peak.pnlPercentage, only for closed)

    +
    pendingAt?: number

    Timestamp when position became active (only for opened/active/closed)

    +
    percentSl?: number

    Percentage progress towards stop loss (only for active/waiting)

    +
    percentTp?: number

    Percentage progress towards take profit (only for active/waiting)

    +
    pnl?: number

    PNL percentage (for active/waiting: unrealized, for closed: realized)

    +
    pnlCost?: number

    Absolute profit/loss in USD (for active/waiting: unrealized, for closed: realized)

    +
    pnlEntries?: number

    Total invested capital in USD

    +
    position?: string

    Position type (only for scheduled/waiting/opened/active/closed/cancelled)

    +
    priceOpen?: number

    Open price (only for scheduled/waiting/opened/active/closed/cancelled)

    +
    priceStopLoss?: number

    Stop loss price (only for scheduled/waiting/opened/active/closed/cancelled)

    +
    priceTakeProfit?: number

    Take profit price (only for scheduled/waiting/opened/active/closed/cancelled)

    +
    scheduledAt?: number

    Timestamp when signal was created/scheduled (only for scheduled/waiting/opened/active/closed/cancelled)

    +
    signalId?: string

    Signal ID (only for scheduled/waiting/opened/active/closed/cancelled)

    +
    symbol?: string

    Trading pair symbol (only for non-idle events)

    +
    timestamp: number

    Event timestamp in milliseconds (scheduledAt for scheduled events, pendingAt for opened/closed events)

    +
    totalEntries?: number

    Total number of DCA entries (_entry.length). 1 = no averaging.

    +
    totalPartials?: number

    Total number of partial closes executed (_partial.length)

    +

    Interface TrailingStopCommit

    Trailing stop event.

    -
    interface TrailingStopCommit {
        action: "trailing-stop";
        backtest: boolean;
        currentPrice: number;
        exchangeName: string;
        frameName: string;
        maxDrawdown: IStrategyPnL;
        note?: string;
        originalPriceOpen: number;
        originalPriceStopLoss: number;
        originalPriceTakeProfit: number;
        peakProfit: IStrategyPnL;
        pendingAt: number;
        percentShift: number;
        pnl: IStrategyPnL;
        position: "long" | "short";
        priceOpen: number;
        priceStopLoss: number;
        priceTakeProfit: number;
        scheduledAt: number;
        signal: IPublicSignalRow;
        signalId: string;
        strategyName: string;
        symbol: string;
        timestamp: number;
        totalEntries: number;
        totalPartials: number;
    }

    Hierarchy

    • SignalCommitBase
      • TrailingStopCommit

    Properties

    interface TrailingStopCommit {
        action: "trailing-stop";
        backtest: boolean;
        currentPrice: number;
        exchangeName: string;
        frameName: string;
        maxDrawdown: IStrategyPnL;
        note?: string;
        originalPriceOpen: number;
        originalPriceStopLoss: number;
        originalPriceTakeProfit: number;
        peakProfit: IStrategyPnL;
        pendingAt: number;
        percentShift: number;
        pnl: IStrategyPnL;
        position: "long" | "short";
        priceOpen: number;
        priceStopLoss: number;
        priceTakeProfit: number;
        scheduledAt: number;
        signal: IPublicSignalRow;
        signalId: string;
        strategyName: string;
        symbol: string;
        timestamp: number;
        totalEntries: number;
        totalPartials: number;
    }

    Hierarchy

    • SignalCommitBase
      • TrailingStopCommit

    Properties

    action: "trailing-stop"

    Discriminator for trailing-stop action

    -
    backtest: boolean

    Whether this event is from backtest mode (true) or live mode (false)

    -
    currentPrice: number

    Current market price at time of trailing adjustment

    -
    exchangeName: string

    Exchange name where signal was executed

    -
    frameName: string

    Timeframe name (used in backtest mode, empty string in live mode)

    -
    maxDrawdown: IStrategyPnL

    Maximum drawdown experienced during the life of this position up to the moment this public signal was created

    -
    note?: string

    Optional human-readable description of signal reason

    -
    originalPriceOpen: number

    Original entry price at signal creation (unchanged by DCA averaging).

    -
    originalPriceStopLoss: number

    Original stop loss price before any trailing adjustments

    -
    originalPriceTakeProfit: number

    Original take profit price before any trailing adjustments

    -
    peakProfit: IStrategyPnL

    Peak profit achieved during the life of this position up to the moment this public signal was created

    -
    pendingAt: number

    Position activation timestamp in milliseconds (when price reached priceOpen)

    -
    percentShift: number

    Percentage shift for stop loss adjustment

    -

    Total PNL of the closed position (including all entries and partials)

    -
    position: "long" | "short"

    Trade direction: "long" (buy) or "short" (sell)

    -
    priceOpen: number

    Entry price for the position

    -
    priceStopLoss: number

    Effective stop loss price (updated by this trailing action)

    -
    priceTakeProfit: number

    Effective take profit price (may differ from original after trailing)

    -
    scheduledAt: number

    Signal creation timestamp in milliseconds

    -

    Signal data at the moment of this event (snapshot of IPublicSignalRow)

    -
    signalId: string

    Unique signal identifier (UUID v4)

    -
    strategyName: string

    Strategy name that generated this signal

    -
    symbol: string

    Trading pair symbol (e.g., "BTCUSDT")

    -
    timestamp: number

    Timestamp from execution context (tick's when or backtest candle timestamp)

    -
    totalEntries: number

    Total number of DCA entries at the time of this event (_entry.length). +

    backtest: boolean

    Whether this event is from backtest mode (true) or live mode (false)

    +
    currentPrice: number

    Current market price at time of trailing adjustment

    +
    exchangeName: string

    Exchange name where signal was executed

    +
    frameName: string

    Timeframe name (used in backtest mode, empty string in live mode)

    +
    maxDrawdown: IStrategyPnL

    Maximum drawdown experienced during the life of this position up to the moment this public signal was created

    +
    note?: string

    Optional human-readable description of signal reason

    +
    originalPriceOpen: number

    Original entry price at signal creation (unchanged by DCA averaging).

    +
    originalPriceStopLoss: number

    Original stop loss price before any trailing adjustments

    +
    originalPriceTakeProfit: number

    Original take profit price before any trailing adjustments

    +
    peakProfit: IStrategyPnL

    Peak profit achieved during the life of this position up to the moment this public signal was created

    +
    pendingAt: number

    Position activation timestamp in milliseconds (when price reached priceOpen)

    +
    percentShift: number

    Percentage shift for stop loss adjustment

    +

    Total PNL of the closed position (including all entries and partials)

    +
    position: "long" | "short"

    Trade direction: "long" (buy) or "short" (sell)

    +
    priceOpen: number

    Entry price for the position

    +
    priceStopLoss: number

    Effective stop loss price (updated by this trailing action)

    +
    priceTakeProfit: number

    Effective take profit price (may differ from original after trailing)

    +
    scheduledAt: number

    Signal creation timestamp in milliseconds

    +

    Signal data at the moment of this event (snapshot of IPublicSignalRow)

    +
    signalId: string

    Unique signal identifier (UUID v4)

    +
    strategyName: string

    Strategy name that generated this signal

    +
    symbol: string

    Trading pair symbol (e.g., "BTCUSDT")

    +
    timestamp: number

    Timestamp from execution context (tick's when or backtest candle timestamp)

    +
    totalEntries: number

    Total number of DCA entries at the time of this event (_entry.length). 1 = no averaging done (only initial entry). 2+ = averaged positions.

    -
    totalPartials: number

    Total number of partial closes executed at the time of this event (_partial.length). +

    totalPartials: number

    Total number of partial closes executed at the time of this event (_partial.length). 0 = no partial closes done. 1+ = partial closes executed.

    -
    +

    Interface TrailingStopCommitNotification

    Trailing stop commit notification. Emitted when trailing stop action is executed.

    -
    interface TrailingStopCommitNotification {
        backtest: boolean;
        createdAt: number;
        currentPrice: number;
        exchangeName: string;
        id: string;
        maxDrawdown: IStrategyPnL;
        maxDrawdownCost: number;
        maxDrawdownEntries: number;
        maxDrawdownPercentage: number;
        maxDrawdownPriceClose: number;
        maxDrawdownPriceOpen: number;
        note?: string;
        originalPriceOpen: number;
        originalPriceStopLoss: number;
        originalPriceTakeProfit: number;
        peakProfit: IStrategyPnL;
        peakProfitCost: number;
        peakProfitEntries: number;
        peakProfitPercentage: number;
        peakProfitPriceClose: number;
        peakProfitPriceOpen: number;
        pendingAt: number;
        percentShift: number;
        pnl: IStrategyPnL;
        pnlCost: number;
        pnlEntries: number;
        pnlPercentage: number;
        pnlPriceClose: number;
        pnlPriceOpen: number;
        position: "long" | "short";
        priceOpen: number;
        priceStopLoss: number;
        priceTakeProfit: number;
        scheduledAt: number;
        signalId: string;
        strategyName: string;
        symbol: string;
        timestamp: number;
        totalEntries: number;
        totalPartials: number;
        type: "trailing_stop.commit";
    }

    Properties

    interface TrailingStopCommitNotification {
        backtest: boolean;
        createdAt: number;
        currentPrice: number;
        exchangeName: string;
        id: string;
        maxDrawdown: IStrategyPnL;
        maxDrawdownCost: number;
        maxDrawdownEntries: number;
        maxDrawdownPercentage: number;
        maxDrawdownPriceClose: number;
        maxDrawdownPriceOpen: number;
        note?: string;
        originalPriceOpen: number;
        originalPriceStopLoss: number;
        originalPriceTakeProfit: number;
        peakProfit: IStrategyPnL;
        peakProfitCost: number;
        peakProfitEntries: number;
        peakProfitPercentage: number;
        peakProfitPriceClose: number;
        peakProfitPriceOpen: number;
        pendingAt: number;
        percentShift: number;
        pnl: IStrategyPnL;
        pnlCost: number;
        pnlEntries: number;
        pnlPercentage: number;
        pnlPriceClose: number;
        pnlPriceOpen: number;
        position: "long" | "short";
        priceOpen: number;
        priceStopLoss: number;
        priceTakeProfit: number;
        scheduledAt: number;
        signalId: string;
        strategyName: string;
        symbol: string;
        timestamp: number;
        totalEntries: number;
        totalPartials: number;
        type: "trailing_stop.commit";
    }

    Properties

    backtest createdAt currentPrice exchangeName @@ -42,47 +42,47 @@ Emitted when trailing stop action is executed.

    totalPartials type

    Properties

    backtest: boolean

    Whether this notification is from backtest mode (true) or live mode (false)

    -
    createdAt: number

    Unix timestamp in milliseconds when the notification was created

    -
    currentPrice: number

    Current market price when trailing stop was executed

    -
    exchangeName: string

    Exchange name where signal was executed

    -
    id: string

    Unique notification identifier

    -
    maxDrawdown: IStrategyPnL

    Maximum drawdown experienced during the life of this position up to the moment this public signal was created

    -
    maxDrawdownCost: number

    Absolute profit/loss in USD at the moment the position reached its maximum drawdown during the life of this position

    -
    maxDrawdownEntries: number

    Number of entries executed at the moment the position reached its maximum drawdown during the life of this position

    -
    maxDrawdownPercentage: number

    Profit/loss as percentage at the moment the position reached its maximum drawdown during the life of this position

    -
    maxDrawdownPriceClose: number

    Exit price for PNL calculation at the moment of max drawdown

    -
    maxDrawdownPriceOpen: number

    Maximum drawdown price reached in loss direction during the life of this position

    -
    note?: string

    Optional human-readable description of signal reason

    -
    originalPriceOpen: number

    Original entry price at signal creation (unchanged by DCA averaging)

    -
    originalPriceStopLoss: number

    Original stop loss price before any trailing adjustments

    -
    originalPriceTakeProfit: number

    Original take profit price before any trailing adjustments

    -
    peakProfit: IStrategyPnL

    Peak profit achieved during the life of this position up to the moment this public signal was created

    -
    peakProfitCost: number

    Absolute profit/loss in USD at the moment the position reached its peak profit during the life of this position

    -
    peakProfitEntries: number

    Number of entries executed at the moment the position reached its peak profit during the life of this position

    -
    peakProfitPercentage: number

    Profit/loss as percentage at the moment the position reached its peak profit during the life of this position

    -
    peakProfitPriceClose: number

    Exit price for PNL calculation at the moment of peak profit

    -
    peakProfitPriceOpen: number

    Peak price reached in profit direction during the life of this position

    -
    pendingAt: number

    Pending timestamp in milliseconds (when position became pending/active at priceOpen)

    -
    percentShift: number

    Percentage shift of original SL distance (-100 to 100)

    -

    Total PNL of the closed position (including all entries and partials)

    -
    pnlCost: number

    Absolute profit/loss in USD

    -
    pnlEntries: number

    Total invested capital in USD

    -
    pnlPercentage: number

    Profit/loss as percentage (e.g., 1.5 for +1.5%, -2.3 for -2.3%)

    -
    pnlPriceClose: number

    Exit price from PNL calculation (adjusted with slippage and fees)

    -
    pnlPriceOpen: number

    Entry price from PNL calculation (effective price adjusted with slippage and fees)

    -
    position: "long" | "short"

    Trade direction: "long" (buy) or "short" (sell)

    -
    priceOpen: number

    Entry price for the position

    -
    priceStopLoss: number

    Effective stop loss price after trailing adjustment

    -
    priceTakeProfit: number

    Effective take profit price (with trailing if set)

    -
    scheduledAt: number

    Signal creation timestamp in milliseconds (when signal was first created/scheduled)

    -
    signalId: string

    Unique signal identifier (UUID v4)

    -
    strategyName: string

    Strategy name that generated this signal

    -
    symbol: string

    Trading pair symbol (e.g., "BTCUSDT")

    -
    timestamp: number

    Unix timestamp in milliseconds when trailing stop was committed

    -
    totalEntries: number

    Total number of DCA entries (_entry.length). 1 = no averaging.

    -
    totalPartials: number

    Total number of partial closes executed (_partial.length). 0 = no partial closes done.

    -
    type: "trailing_stop.commit"

    Discriminator for type-safe union

    -
    +
    createdAt: number

    Unix timestamp in milliseconds when the notification was created

    +
    currentPrice: number

    Current market price when trailing stop was executed

    +
    exchangeName: string

    Exchange name where signal was executed

    +
    id: string

    Unique notification identifier

    +
    maxDrawdown: IStrategyPnL

    Maximum drawdown experienced during the life of this position up to the moment this public signal was created

    +
    maxDrawdownCost: number

    Absolute profit/loss in USD at the moment the position reached its maximum drawdown during the life of this position

    +
    maxDrawdownEntries: number

    Number of entries executed at the moment the position reached its maximum drawdown during the life of this position

    +
    maxDrawdownPercentage: number

    Profit/loss as percentage at the moment the position reached its maximum drawdown during the life of this position

    +
    maxDrawdownPriceClose: number

    Exit price for PNL calculation at the moment of max drawdown

    +
    maxDrawdownPriceOpen: number

    Maximum drawdown price reached in loss direction during the life of this position

    +
    note?: string

    Optional human-readable description of signal reason

    +
    originalPriceOpen: number

    Original entry price at signal creation (unchanged by DCA averaging)

    +
    originalPriceStopLoss: number

    Original stop loss price before any trailing adjustments

    +
    originalPriceTakeProfit: number

    Original take profit price before any trailing adjustments

    +
    peakProfit: IStrategyPnL

    Peak profit achieved during the life of this position up to the moment this public signal was created

    +
    peakProfitCost: number

    Absolute profit/loss in USD at the moment the position reached its peak profit during the life of this position

    +
    peakProfitEntries: number

    Number of entries executed at the moment the position reached its peak profit during the life of this position

    +
    peakProfitPercentage: number

    Profit/loss as percentage at the moment the position reached its peak profit during the life of this position

    +
    peakProfitPriceClose: number

    Exit price for PNL calculation at the moment of peak profit

    +
    peakProfitPriceOpen: number

    Peak price reached in profit direction during the life of this position

    +
    pendingAt: number

    Pending timestamp in milliseconds (when position became pending/active at priceOpen)

    +
    percentShift: number

    Percentage shift of original SL distance (-100 to 100)

    +

    Total PNL of the closed position (including all entries and partials)

    +
    pnlCost: number

    Absolute profit/loss in USD

    +
    pnlEntries: number

    Total invested capital in USD

    +
    pnlPercentage: number

    Profit/loss as percentage (e.g., 1.5 for +1.5%, -2.3 for -2.3%)

    +
    pnlPriceClose: number

    Exit price from PNL calculation (adjusted with slippage and fees)

    +
    pnlPriceOpen: number

    Entry price from PNL calculation (effective price adjusted with slippage and fees)

    +
    position: "long" | "short"

    Trade direction: "long" (buy) or "short" (sell)

    +
    priceOpen: number

    Entry price for the position

    +
    priceStopLoss: number

    Effective stop loss price after trailing adjustment

    +
    priceTakeProfit: number

    Effective take profit price (with trailing if set)

    +
    scheduledAt: number

    Signal creation timestamp in milliseconds (when signal was first created/scheduled)

    +
    signalId: string

    Unique signal identifier (UUID v4)

    +
    strategyName: string

    Strategy name that generated this signal

    +
    symbol: string

    Trading pair symbol (e.g., "BTCUSDT")

    +
    timestamp: number

    Unix timestamp in milliseconds when trailing stop was committed

    +
    totalEntries: number

    Total number of DCA entries (_entry.length). 1 = no averaging.

    +
    totalPartials: number

    Total number of partial closes executed (_partial.length). 0 = no partial closes done.

    +
    type: "trailing_stop.commit"

    Discriminator for type-safe union

    +

    Interface TrailingTakeCommit

    Trailing take event.

    -
    interface TrailingTakeCommit {
        action: "trailing-take";
        backtest: boolean;
        currentPrice: number;
        exchangeName: string;
        frameName: string;
        maxDrawdown: IStrategyPnL;
        note?: string;
        originalPriceOpen: number;
        originalPriceStopLoss: number;
        originalPriceTakeProfit: number;
        peakProfit: IStrategyPnL;
        pendingAt: number;
        percentShift: number;
        pnl: IStrategyPnL;
        position: "long" | "short";
        priceOpen: number;
        priceStopLoss: number;
        priceTakeProfit: number;
        scheduledAt: number;
        signal: IPublicSignalRow;
        signalId: string;
        strategyName: string;
        symbol: string;
        timestamp: number;
        totalEntries: number;
        totalPartials: number;
    }

    Hierarchy

    • SignalCommitBase
      • TrailingTakeCommit

    Properties

    interface TrailingTakeCommit {
        action: "trailing-take";
        backtest: boolean;
        currentPrice: number;
        exchangeName: string;
        frameName: string;
        maxDrawdown: IStrategyPnL;
        note?: string;
        originalPriceOpen: number;
        originalPriceStopLoss: number;
        originalPriceTakeProfit: number;
        peakProfit: IStrategyPnL;
        pendingAt: number;
        percentShift: number;
        pnl: IStrategyPnL;
        position: "long" | "short";
        priceOpen: number;
        priceStopLoss: number;
        priceTakeProfit: number;
        scheduledAt: number;
        signal: IPublicSignalRow;
        signalId: string;
        strategyName: string;
        symbol: string;
        timestamp: number;
        totalEntries: number;
        totalPartials: number;
    }

    Hierarchy

    • SignalCommitBase
      • TrailingTakeCommit

    Properties

    action: "trailing-take"

    Discriminator for trailing-take action

    -
    backtest: boolean

    Whether this event is from backtest mode (true) or live mode (false)

    -
    currentPrice: number

    Current market price at time of trailing adjustment

    -
    exchangeName: string

    Exchange name where signal was executed

    -
    frameName: string

    Timeframe name (used in backtest mode, empty string in live mode)

    -
    maxDrawdown: IStrategyPnL

    Maximum drawdown experienced during the life of this position up to the moment this public signal was created

    -
    note?: string

    Optional human-readable description of signal reason

    -
    originalPriceOpen: number

    Original entry price at signal creation (unchanged by DCA averaging).

    -
    originalPriceStopLoss: number

    Original stop loss price before any trailing adjustments

    -
    originalPriceTakeProfit: number

    Original take profit price before any trailing adjustments

    -
    peakProfit: IStrategyPnL

    Peak profit achieved during the life of this position up to the moment this public signal was created

    -
    pendingAt: number

    Position activation timestamp in milliseconds (when price reached priceOpen)

    -
    percentShift: number

    Percentage shift for take profit adjustment

    -

    Total PNL of the closed position (including all entries and partials)

    -
    position: "long" | "short"

    Trade direction: "long" (buy) or "short" (sell)

    -
    priceOpen: number

    Entry price for the position

    -
    priceStopLoss: number

    Effective stop loss price (may differ from original after trailing)

    -
    priceTakeProfit: number

    Effective take profit price (updated by this trailing action)

    -
    scheduledAt: number

    Signal creation timestamp in milliseconds

    -

    Signal data at the moment of this event (snapshot of IPublicSignalRow)

    -
    signalId: string

    Unique signal identifier (UUID v4)

    -
    strategyName: string

    Strategy name that generated this signal

    -
    symbol: string

    Trading pair symbol (e.g., "BTCUSDT")

    -
    timestamp: number

    Timestamp from execution context (tick's when or backtest candle timestamp)

    -
    totalEntries: number

    Total number of DCA entries at the time of this event (_entry.length). +

    backtest: boolean

    Whether this event is from backtest mode (true) or live mode (false)

    +
    currentPrice: number

    Current market price at time of trailing adjustment

    +
    exchangeName: string

    Exchange name where signal was executed

    +
    frameName: string

    Timeframe name (used in backtest mode, empty string in live mode)

    +
    maxDrawdown: IStrategyPnL

    Maximum drawdown experienced during the life of this position up to the moment this public signal was created

    +
    note?: string

    Optional human-readable description of signal reason

    +
    originalPriceOpen: number

    Original entry price at signal creation (unchanged by DCA averaging).

    +
    originalPriceStopLoss: number

    Original stop loss price before any trailing adjustments

    +
    originalPriceTakeProfit: number

    Original take profit price before any trailing adjustments

    +
    peakProfit: IStrategyPnL

    Peak profit achieved during the life of this position up to the moment this public signal was created

    +
    pendingAt: number

    Position activation timestamp in milliseconds (when price reached priceOpen)

    +
    percentShift: number

    Percentage shift for take profit adjustment

    +

    Total PNL of the closed position (including all entries and partials)

    +
    position: "long" | "short"

    Trade direction: "long" (buy) or "short" (sell)

    +
    priceOpen: number

    Entry price for the position

    +
    priceStopLoss: number

    Effective stop loss price (may differ from original after trailing)

    +
    priceTakeProfit: number

    Effective take profit price (updated by this trailing action)

    +
    scheduledAt: number

    Signal creation timestamp in milliseconds

    +

    Signal data at the moment of this event (snapshot of IPublicSignalRow)

    +
    signalId: string

    Unique signal identifier (UUID v4)

    +
    strategyName: string

    Strategy name that generated this signal

    +
    symbol: string

    Trading pair symbol (e.g., "BTCUSDT")

    +
    timestamp: number

    Timestamp from execution context (tick's when or backtest candle timestamp)

    +
    totalEntries: number

    Total number of DCA entries at the time of this event (_entry.length). 1 = no averaging done (only initial entry). 2+ = averaged positions.

    -
    totalPartials: number

    Total number of partial closes executed at the time of this event (_partial.length). +

    totalPartials: number

    Total number of partial closes executed at the time of this event (_partial.length). 0 = no partial closes done. 1+ = partial closes executed.

    -
    +

    Interface TrailingTakeCommitNotification

    Trailing take commit notification. Emitted when trailing take action is executed.

    -
    interface TrailingTakeCommitNotification {
        backtest: boolean;
        createdAt: number;
        currentPrice: number;
        exchangeName: string;
        id: string;
        maxDrawdown: IStrategyPnL;
        maxDrawdownCost: number;
        maxDrawdownEntries: number;
        maxDrawdownPercentage: number;
        maxDrawdownPriceClose: number;
        maxDrawdownPriceOpen: number;
        note?: string;
        originalPriceOpen: number;
        originalPriceStopLoss: number;
        originalPriceTakeProfit: number;
        peakProfit: IStrategyPnL;
        peakProfitCost: number;
        peakProfitEntries: number;
        peakProfitPercentage: number;
        peakProfitPriceClose: number;
        peakProfitPriceOpen: number;
        pendingAt: number;
        percentShift: number;
        pnl: IStrategyPnL;
        pnlCost: number;
        pnlEntries: number;
        pnlPercentage: number;
        pnlPriceClose: number;
        pnlPriceOpen: number;
        position: "long" | "short";
        priceOpen: number;
        priceStopLoss: number;
        priceTakeProfit: number;
        scheduledAt: number;
        signalId: string;
        strategyName: string;
        symbol: string;
        timestamp: number;
        totalEntries: number;
        totalPartials: number;
        type: "trailing_take.commit";
    }

    Properties

    interface TrailingTakeCommitNotification {
        backtest: boolean;
        createdAt: number;
        currentPrice: number;
        exchangeName: string;
        id: string;
        maxDrawdown: IStrategyPnL;
        maxDrawdownCost: number;
        maxDrawdownEntries: number;
        maxDrawdownPercentage: number;
        maxDrawdownPriceClose: number;
        maxDrawdownPriceOpen: number;
        note?: string;
        originalPriceOpen: number;
        originalPriceStopLoss: number;
        originalPriceTakeProfit: number;
        peakProfit: IStrategyPnL;
        peakProfitCost: number;
        peakProfitEntries: number;
        peakProfitPercentage: number;
        peakProfitPriceClose: number;
        peakProfitPriceOpen: number;
        pendingAt: number;
        percentShift: number;
        pnl: IStrategyPnL;
        pnlCost: number;
        pnlEntries: number;
        pnlPercentage: number;
        pnlPriceClose: number;
        pnlPriceOpen: number;
        position: "long" | "short";
        priceOpen: number;
        priceStopLoss: number;
        priceTakeProfit: number;
        scheduledAt: number;
        signalId: string;
        strategyName: string;
        symbol: string;
        timestamp: number;
        totalEntries: number;
        totalPartials: number;
        type: "trailing_take.commit";
    }

    Properties

    backtest createdAt currentPrice exchangeName @@ -42,47 +42,47 @@ Emitted when trailing take action is executed.

    totalPartials type

    Properties

    backtest: boolean

    Whether this notification is from backtest mode (true) or live mode (false)

    -
    createdAt: number

    Unix timestamp in milliseconds when the notification was created

    -
    currentPrice: number

    Current market price when trailing take was executed

    -
    exchangeName: string

    Exchange name where signal was executed

    -
    id: string

    Unique notification identifier

    -
    maxDrawdown: IStrategyPnL

    Maximum drawdown experienced during the life of this position up to the moment this public signal was created

    -
    maxDrawdownCost: number

    Absolute profit/loss in USD at the moment the position reached its maximum drawdown during the life of this position

    -
    maxDrawdownEntries: number

    Number of entries executed at the moment the position reached its maximum drawdown during the life of this position

    -
    maxDrawdownPercentage: number

    Profit/loss as percentage at the moment the position reached its maximum drawdown during the life of this position

    -
    maxDrawdownPriceClose: number

    Exit price for PNL calculation at the moment of max drawdown

    -
    maxDrawdownPriceOpen: number

    Maximum drawdown price reached in loss direction during the life of this position

    -
    note?: string

    Optional human-readable description of signal reason

    -
    originalPriceOpen: number

    Original entry price at signal creation (unchanged by DCA averaging)

    -
    originalPriceStopLoss: number

    Original stop loss price before any trailing adjustments

    -
    originalPriceTakeProfit: number

    Original take profit price before any trailing adjustments

    -
    peakProfit: IStrategyPnL

    Peak profit achieved during the life of this position up to the moment this public signal was created

    -
    peakProfitCost: number

    Absolute profit/loss in USD at the moment the position reached its peak profit during the life of this position

    -
    peakProfitEntries: number

    Number of entries executed at the moment the position reached its peak profit during the life of this position

    -
    peakProfitPercentage: number

    Profit/loss as percentage at the moment the position reached its peak profit during the life of this position

    -
    peakProfitPriceClose: number

    Exit price for PNL calculation at the moment of peak profit

    -
    peakProfitPriceOpen: number

    Peak price reached in profit direction during the life of this position

    -
    pendingAt: number

    Pending timestamp in milliseconds (when position became pending/active at priceOpen)

    -
    percentShift: number

    Percentage shift of original TP distance (-100 to 100)

    -

    Total PNL of the closed position (including all entries and partials)

    -
    pnlCost: number

    Absolute profit/loss in USD

    -
    pnlEntries: number

    Total invested capital in USD

    -
    pnlPercentage: number

    Profit/loss as percentage (e.g., 1.5 for +1.5%, -2.3 for -2.3%)

    -
    pnlPriceClose: number

    Exit price from PNL calculation (adjusted with slippage and fees)

    -
    pnlPriceOpen: number

    Entry price from PNL calculation (effective price adjusted with slippage and fees)

    -
    position: "long" | "short"

    Trade direction: "long" (buy) or "short" (sell)

    -
    priceOpen: number

    Entry price for the position

    -
    priceStopLoss: number

    Effective stop loss price (with trailing if set)

    -
    priceTakeProfit: number

    Effective take profit price after trailing adjustment

    -
    scheduledAt: number

    Signal creation timestamp in milliseconds (when signal was first created/scheduled)

    -
    signalId: string

    Unique signal identifier (UUID v4)

    -
    strategyName: string

    Strategy name that generated this signal

    -
    symbol: string

    Trading pair symbol (e.g., "BTCUSDT")

    -
    timestamp: number

    Unix timestamp in milliseconds when trailing take was committed

    -
    totalEntries: number

    Total number of DCA entries (_entry.length). 1 = no averaging.

    -
    totalPartials: number

    Total number of partial closes executed (_partial.length). 0 = no partial closes done.

    -
    type: "trailing_take.commit"

    Discriminator for type-safe union

    -
    +
    createdAt: number

    Unix timestamp in milliseconds when the notification was created

    +
    currentPrice: number

    Current market price when trailing take was executed

    +
    exchangeName: string

    Exchange name where signal was executed

    +
    id: string

    Unique notification identifier

    +
    maxDrawdown: IStrategyPnL

    Maximum drawdown experienced during the life of this position up to the moment this public signal was created

    +
    maxDrawdownCost: number

    Absolute profit/loss in USD at the moment the position reached its maximum drawdown during the life of this position

    +
    maxDrawdownEntries: number

    Number of entries executed at the moment the position reached its maximum drawdown during the life of this position

    +
    maxDrawdownPercentage: number

    Profit/loss as percentage at the moment the position reached its maximum drawdown during the life of this position

    +
    maxDrawdownPriceClose: number

    Exit price for PNL calculation at the moment of max drawdown

    +
    maxDrawdownPriceOpen: number

    Maximum drawdown price reached in loss direction during the life of this position

    +
    note?: string

    Optional human-readable description of signal reason

    +
    originalPriceOpen: number

    Original entry price at signal creation (unchanged by DCA averaging)

    +
    originalPriceStopLoss: number

    Original stop loss price before any trailing adjustments

    +
    originalPriceTakeProfit: number

    Original take profit price before any trailing adjustments

    +
    peakProfit: IStrategyPnL

    Peak profit achieved during the life of this position up to the moment this public signal was created

    +
    peakProfitCost: number

    Absolute profit/loss in USD at the moment the position reached its peak profit during the life of this position

    +
    peakProfitEntries: number

    Number of entries executed at the moment the position reached its peak profit during the life of this position

    +
    peakProfitPercentage: number

    Profit/loss as percentage at the moment the position reached its peak profit during the life of this position

    +
    peakProfitPriceClose: number

    Exit price for PNL calculation at the moment of peak profit

    +
    peakProfitPriceOpen: number

    Peak price reached in profit direction during the life of this position

    +
    pendingAt: number

    Pending timestamp in milliseconds (when position became pending/active at priceOpen)

    +
    percentShift: number

    Percentage shift of original TP distance (-100 to 100)

    +

    Total PNL of the closed position (including all entries and partials)

    +
    pnlCost: number

    Absolute profit/loss in USD

    +
    pnlEntries: number

    Total invested capital in USD

    +
    pnlPercentage: number

    Profit/loss as percentage (e.g., 1.5 for +1.5%, -2.3 for -2.3%)

    +
    pnlPriceClose: number

    Exit price from PNL calculation (adjusted with slippage and fees)

    +
    pnlPriceOpen: number

    Entry price from PNL calculation (effective price adjusted with slippage and fees)

    +
    position: "long" | "short"

    Trade direction: "long" (buy) or "short" (sell)

    +
    priceOpen: number

    Entry price for the position

    +
    priceStopLoss: number

    Effective stop loss price (with trailing if set)

    +
    priceTakeProfit: number

    Effective take profit price after trailing adjustment

    +
    scheduledAt: number

    Signal creation timestamp in milliseconds (when signal was first created/scheduled)

    +
    signalId: string

    Unique signal identifier (UUID v4)

    +
    strategyName: string

    Strategy name that generated this signal

    +
    symbol: string

    Trading pair symbol (e.g., "BTCUSDT")

    +
    timestamp: number

    Unix timestamp in milliseconds when trailing take was committed

    +
    totalEntries: number

    Total number of DCA entries (_entry.length). 1 = no averaging.

    +
    totalPartials: number

    Total number of partial closes executed (_partial.length). 0 = no partial closes done.

    +
    type: "trailing_take.commit"

    Discriminator for type-safe union

    +

    Interface ValidationErrorNotification

    Validation error notification. Emitted when risk validation functions throw errors.

    -
    interface ValidationErrorNotification {
        backtest: boolean;
        error: object;
        id: string;
        message: string;
        type: "error.validation";
    }

    Properties

    interface ValidationErrorNotification {
        backtest: boolean;
        error: object;
        id: string;
        message: string;
        type: "error.validation";
    }

    Properties

    backtest: boolean

    Always false for error notifications (errors are from live context)

    -
    error: object

    Serialized error object with stack trace and metadata

    -
    id: string

    Unique notification identifier

    -
    message: string

    Human-readable validation error message

    -
    type: "error.validation"

    Discriminator for type-safe union

    -
    +
    error: object

    Serialized error object with stack trace and metadata

    +
    id: string

    Unique notification identifier

    +
    message: string

    Human-readable validation error message

    +
    type: "error.validation"

    Discriminator for type-safe union

    +

    Interface WalkerContract

    Contract for walker progress events during strategy comparison. Emitted each time a strategy completes testing with its current ranking.

    -
    interface WalkerContract {
        bestMetric: number;
        bestStrategy: string;
        exchangeName: string;
        frameName: string;
        metric: WalkerMetric;
        metricValue: number;
        stats: BacktestStatisticsModel;
        strategiesTested: number;
        strategyName: string;
        symbol: string;
        totalStrategies: number;
        walkerName: string;
    }

    Properties

    interface WalkerContract {
        bestMetric: number;
        bestStrategy: string;
        exchangeName: string;
        frameName: string;
        metric: WalkerMetric;
        metricValue: number;
        stats: BacktestStatisticsModel;
        strategiesTested: number;
        strategyName: string;
        symbol: string;
        totalStrategies: number;
        walkerName: string;
    }

    Properties

    bestMetric bestStrategy exchangeName frameName @@ -13,18 +13,18 @@ Emitted each time a strategy completes testing with its current ranking.

    totalStrategies walkerName

    Properties

    bestMetric: number

    Current best metric value across all tested strategies so far

    -
    bestStrategy: string

    Current best strategy name

    -
    exchangeName: string

    Exchange name

    -
    frameName: string

    Frame name

    -
    metric: WalkerMetric

    Metric being optimized

    -
    metricValue: number

    Metric value for this strategy (null if invalid)

    -

    Backtest statistics for this strategy

    -
    strategiesTested: number

    Number of strategies tested so far

    -
    strategyName: string

    Strategy that just completed

    -
    symbol: string

    Symbol being tested

    -
    totalStrategies: number

    Total number of strategies to test

    -
    walkerName: string

    Walker name

    -
    +
    bestStrategy: string

    Current best strategy name

    +
    exchangeName: string

    Exchange name

    +
    frameName: string

    Frame name

    +
    metric: WalkerMetric

    Metric being optimized

    +
    metricValue: number

    Metric value for this strategy (null if invalid)

    +

    Backtest statistics for this strategy

    +
    strategiesTested: number

    Number of strategies tested so far

    +
    strategyName: string

    Strategy that just completed

    +
    symbol: string

    Symbol being tested

    +
    totalStrategies: number

    Total number of strategies to test

    +
    walkerName: string

    Walker name

    +

    Interface WalkerSignalData

    Signal data for PNL table. Represents a single closed signal with essential trading information.

    -
    interface WalkerSignalData {
        closeReason: string;
        closeTime: number;
        openTime: number;
        pnl: number;
        position: string;
        signalId: string;
        strategyName: string;
        symbol: string;
    }

    Properties

    interface WalkerSignalData {
        closeReason: string;
        closeTime: number;
        openTime: number;
        pnl: number;
        position: string;
        signalId: string;
        strategyName: string;
        symbol: string;
    }

    Properties

    closeReason closeTime openTime pnl @@ -9,14 +9,14 @@ Represents a single closed signal with essential trading information.

    strategyName symbol

    Properties

    closeReason: string

    Reason why signal was closed

    -
    closeTime: number

    Timestamp when signal closed

    -
    openTime: number

    Timestamp when signal opened

    -
    pnl: number

    PNL as percentage

    -
    position: string

    Position type (long/short)

    -
    signalId: string

    Unique signal identifier

    -
    strategyName: string

    Strategy that generated this signal

    -
    symbol: string

    Trading pair symbol

    -
    +
    closeTime: number

    Timestamp when signal closed

    +
    openTime: number

    Timestamp when signal opened

    +
    pnl: number

    PNL as percentage

    +
    position: string

    Position type (long/short)

    +
    signalId: string

    Unique signal identifier

    +
    strategyName: string

    Strategy that generated this signal

    +
    symbol: string

    Trading pair symbol

    +

    Interface WalkerStatisticsModel

    Alias for walker statistics result interface. Used for clarity in markdown service context.

    Extends IWalkerResults with additional strategy comparison data.

    -
    interface WalkerStatisticsModel {
        bestMetric: number;
        bestStats: BacktestStatisticsModel;
        bestStrategy: string;
        exchangeName: string;
        frameName: string;
        metric: WalkerMetric;
        strategyResults: IStrategyResult[];
        symbol: string;
        totalStrategies: number;
        walkerName: string;
    }

    Hierarchy (View Summary)

    Properties

    interface WalkerStatisticsModel {
        bestMetric: number;
        bestStats: BacktestStatisticsModel;
        bestStrategy: string;
        exchangeName: string;
        frameName: string;
        metric: WalkerMetric;
        strategyResults: IStrategyResult[];
        symbol: string;
        totalStrategies: number;
        walkerName: string;
    }

    Hierarchy (View Summary)

    Properties

    bestMetric bestStats bestStrategy exchangeName @@ -12,16 +12,16 @@ Used for clarity in markdown service context.

    totalStrategies walkerName

    Properties

    bestMetric: number

    bestMetric - Best metric value achieved

    -

    bestStats - Best strategy statistics

    -
    bestStrategy: string

    bestStrategy - Best performing strategy name

    -
    exchangeName: string

    exchangeName - Exchange used

    -
    frameName: string

    frameName - Frame used

    -
    metric: WalkerMetric

    metric - Metric used for optimization

    -
    strategyResults: IStrategyResult[]

    Array of all strategy results for comparison and analysis

    -
    symbol: string

    symbol - Symbol tested

    -
    totalStrategies: number

    totalStrategies - Total number of strategies tested

    -
    walkerName: string

    walkerName - Walker name

    -
    +

    bestStats - Best strategy statistics

    +
    bestStrategy: string

    bestStrategy - Best performing strategy name

    +
    exchangeName: string

    exchangeName - Exchange used

    +
    frameName: string

    frameName - Frame used

    +
    metric: WalkerMetric

    metric - Metric used for optimization

    +
    strategyResults: IStrategyResult[]

    Array of all strategy results for comparison and analysis

    +
    symbol: string

    symbol - Symbol tested

    +
    totalStrategies: number

    totalStrategies - Total number of strategies tested

    +
    walkerName: string

    walkerName - Walker name

    +

    backtest-kit

    Documents

    LLMs

    Modules

    types

    article

    article/01_look_ahead_bias
    article/02_second_order_chaos
    article/03_claude_trader
    article/04_option_hedging
    article/05_ai_strategy_workflow
    article/06_ai_strategy_blueprint
    article/07_ai_news_trading_signals
    article/08_ai_liquidity_harvesting
    article/09_pinescript_local_markets
    article/10_dca_averaging_strategy

    begin

    begin/01_project_overview
    begin/02_getting_started_configuration
    begin/03_system_architecture_overview
    begin/04_llm_forecast_engine_logic
    begin/05_forecast_pipeline_outline
    begin/06_advisors_news_market_data
    begin/07_news_fetching_caching_fetchnews
    begin/08_ollama_completions
    begin/09_trading_strategy_feb_2026_strategy
    begin/10_signal_generation_sentiment_mapping
    begin/11_position_lifecycle_exit_logic
    begin/12_backtest_module_frame_configuration
    begin/13_february_2026_case_study_performance
    begin/14_backtest_kit_framework
    begin/15_backtesting_execution_reporting
    begin/16_signal_state_machine
    begin/17_live_trading_mode
    begin/18_risk_management
    begin/19_ai_strategy_optimization_walker
    begin/20_exchange_integration_modules
    begin/21_ccxt_exchange_adapter
    begin/22_symbol_configuration
    begin/23_glossary

    cli

    cli/readme

    concept

    concept/01_monorepo_parallel_execution
    concept/02_zero_expectation_escape

    demo/backtest

    demo/backtest/readme

    demo/broker

    demo/broker/readme

    demo/exchange

    demo/exchange/readme

    demo/live

    demo/live/readme

    demo/optimization

    demo/optimization/readme

    demo/pinets

    demo/pinets/readme

    design

    design/01_overview
    design/02_key_features
    design/03_installation_and_setup
    design/04_quick_start_guide
    design/05_core_concepts
    design/06_execution_modes
    design/07_signal_lifecycle_overview
    design/08_component_registration
    design/09_temporal_isolation_and_look-ahead_prevention
    design/10_architecture
    design/11_layer_responsibilities
    design/12_dependency_injection_system
    design/13_context_propagation
    design/14_event_system
    design/15_public_api_reference
    design/16_configuration_functions
    design/17_component_registration_functions
    design/18_backtest_api
    design/19_live_trading_api
    design/20_walker_api
    design/21_persistence_utilities
    design/22_exchange_functions
    design/23_event_listeners
    design/24_component_schemas
    design/25_strategy_schemas
    design/26_exchange_schemas
    design/27_frame_schemas
    design/28_risk_schemas
    design/29_sizing_schemas
    design/30_walker_schemas
    design/31_optimizer_schemas
    design/32_client_implementations
    design/33_clientstrategy
    design/34_clientexchange
    design/35_clientframe
    design/36_clientrisk
    design/37_clientsizing
    design/38_clientpartial
    design/39_clientoptimizer
    design/40_service_layer
    design/41_service_architecture_overview
    design/42_connection_services
    design/43_schema_services
    design/44_validation_services
    design/45_global_services
    design/46_logic_services
    design/47_markdown_services
    design/48_signal_lifecycle
    design/49_signal_states
    design/50_signal_generation_and_validation
    design/51_scheduled_signals
    design/52_signal_persistence
    design/53_pnl_calculation
    design/54_backtesting
    design/55_backtest_execution_flow
    design/56_timeframe_generation
    design/57_fast-forward_simulation
    design/58_live_trading
    design/59_live_execution_flow
    design/60_crash_recovery
    design/61_real-time_monitoring
    design/62_interval_throttling
    design/63_walker_mode
    design/64_walker_execution_flow
    design/65_strategy_comparison
    design/66_walker_reports
    design/67_risk_management
    design/68_risk_profiles
    design/69_risk_validation
    design/70_position_tracking
    design/71_reporting_and_analytics
    design/72_markdown_report_generation
    design/73_performance_metrics
    design/74_statistics_calculation
    design/75_partial_profit_loss_tracking
    design/76_heatmap_analytics
    design/77_configuration
    design/78_global_configuration
    design/79_validation_parameters
    design/80_timing_parameters
    design/81_cross-cutting_concerns
    design/82_logging_system
    design/83_error_handling
    design/84_persistence_layer
    design/85_advanced_topics
    design/86_custom_exchange_integration
    design/87_custom_persistence_backends
    design/88_custom_risk_validations
    design/89_multi-symbol_strategies
    design/90_ai-powered_strategy_optimization
    design/91_optimizer_architecture
    design/92_data_collection_pipeline
    design/93_llm_integration
    design/94_strategy_code_generation
    design/95_training_vs_testing_ranges

    docs

    docs
    docs/class/ActionBase
    docs/class/ActionConnectionService
    docs/class/ActionCoreService
    docs/class/ActionProxy
    docs/class/ActionSchemaService
    docs/class/ActionValidationService
    docs/class/BacktestCommandService
    docs/class/BacktestLogicPrivateService
    docs/class/BacktestLogicPublicService
    docs/class/BacktestMarkdownService
    docs/class/BacktestReportService
    docs/class/BacktestUtils
    docs/class/BreakevenConnectionService
    docs/class/BreakevenGlobalService
    docs/class/BreakevenMarkdownService
    docs/class/BreakevenReportService
    docs/class/BreakevenUtils
    docs/class/BrokerAdapter
    docs/class/BrokerBase
    docs/class/CacheUtils
    docs/class/ClientAction
    docs/class/ClientExchange
    docs/class/ClientFrame
    docs/class/ClientRisk
    docs/class/ClientSizing
    docs/class/ColumnValidationService
    docs/class/ConfigValidationService
    docs/class/ConstantUtils
    docs/class/CronUtils
    docs/class/DumpAdapter
    docs/class/ExchangeConnectionService
    docs/class/ExchangeCoreService
    docs/class/ExchangeSchemaService
    docs/class/ExchangeUtils
    docs/class/ExchangeValidationService
    docs/class/FrameConnectionService
    docs/class/FrameCoreService
    docs/class/FrameSchemaService
    docs/class/FrameValidationService
    docs/class/HeatMarkdownService
    docs/class/HeatReportService
    docs/class/HeatUtils
    docs/class/HighestProfitMarkdownService
    docs/class/HighestProfitReportService
    docs/class/HighestProfitUtils
    docs/class/IntervalUtils
    docs/class/LiveCommandService
    docs/class/LiveLogicPrivateService
    docs/class/LiveLogicPublicService
    docs/class/LiveMarkdownService
    docs/class/LiveReportService
    docs/class/LiveUtils
    docs/class/LogAdapter
    docs/class/LoggerService
    docs/class/LookupUtils
    docs/class/MarkdownAdapter
    docs/class/MarkdownFileBase
    docs/class/MarkdownFolderBase
    docs/class/MarkdownUtils
    docs/class/MarkdownWriterAdapter
    docs/class/MaxDrawdownMarkdownService
    docs/class/MaxDrawdownReportService
    docs/class/MaxDrawdownUtils
    docs/class/MemoryAdapter
    docs/class/MemoryBacktestAdapter
    docs/class/MemoryLiveAdapter
    docs/class/NotificationAdapter
    docs/class/NotificationBacktestAdapter
    docs/class/NotificationHelperService
    docs/class/NotificationLiveAdapter
    docs/class/PartialConnectionService
    docs/class/PartialGlobalService
    docs/class/PartialMarkdownService
    docs/class/PartialReportService
    docs/class/PartialUtils
    docs/class/Performance
    docs/class/PerformanceMarkdownService
    docs/class/PerformanceReportService
    docs/class/PersistBase
    docs/class/PersistBreakevenInstance
    docs/class/PersistBreakevenUtils
    docs/class/PersistCandleInstance
    docs/class/PersistCandleUtils
    docs/class/PersistIntervalInstance
    docs/class/PersistIntervalUtils
    docs/class/PersistLogInstance
    docs/class/PersistLogUtils
    docs/class/PersistMeasureInstance
    docs/class/PersistMeasureUtils
    docs/class/PersistMemoryInstance
    docs/class/PersistMemoryUtils
    docs/class/PersistNotificationInstance
    docs/class/PersistNotificationUtils
    docs/class/PersistPartialInstance
    docs/class/PersistPartialUtils
    docs/class/PersistRecentInstance
    docs/class/PersistRecentUtils
    docs/class/PersistRiskInstance
    docs/class/PersistRiskUtils
    docs/class/PersistScheduleInstance
    docs/class/PersistScheduleUtils
    docs/class/PersistSessionInstance
    docs/class/PersistSessionUtils
    docs/class/PersistSignalInstance
    docs/class/PersistSignalUtils
    docs/class/PersistStateInstance
    docs/class/PersistStateUtils
    docs/class/PersistStorageInstance
    docs/class/PersistStorageUtils
    docs/class/PersistStrategyInstance
    docs/class/PersistStrategyUtils
    docs/class/Position
    docs/class/PositionSizeUtils
    docs/class/PriceMetaService
    docs/class/RecentAdapter
    docs/class/RecentBacktestAdapter
    docs/class/RecentLiveAdapter
    docs/class/ReflectUtils
    docs/class/ReportAdapter
    docs/class/ReportBase
    docs/class/ReportUtils
    docs/class/ReportWriterAdapter
    docs/class/RiskConnectionService
    docs/class/RiskGlobalService
    docs/class/RiskMarkdownService
    docs/class/RiskReportService
    docs/class/RiskSchemaService
    docs/class/RiskUtils
    docs/class/RiskValidationService
    docs/class/ScheduleMarkdownService
    docs/class/ScheduleReportService
    docs/class/ScheduleUtils
    docs/class/SessionAdapter
    docs/class/SessionBacktestAdapter
    docs/class/SessionLiveAdapter
    docs/class/SizingConnectionService
    docs/class/SizingGlobalService
    docs/class/SizingSchemaService
    docs/class/SizingValidationService
    docs/class/StateAdapter
    docs/class/StateBacktestAdapter
    docs/class/StateLiveAdapter
    docs/class/StorageAdapter
    docs/class/StorageBacktestAdapter
    docs/class/StorageLiveAdapter
    docs/class/StrategyConnectionService
    docs/class/StrategyCoreService
    docs/class/StrategyMarkdownService
    docs/class/StrategyReportService
    docs/class/StrategySchemaService
    docs/class/StrategyUtils
    docs/class/StrategyValidationService
    docs/class/SyncMarkdownService
    docs/class/SyncReportService
    docs/class/SyncUtils
    docs/class/SystemUtils
    docs/class/TimeMetaService
    docs/class/WalkerCommandService
    docs/class/WalkerLogicPrivateService
    docs/class/WalkerLogicPublicService
    docs/class/WalkerMarkdownService
    docs/class/WalkerReportService
    docs/class/WalkerSchemaService
    docs/class/WalkerUtils
    docs/class/WalkerValidationService
    docs/function/addActionSchema
    docs/function/addExchangeSchema
    docs/function/addFrameSchema
    docs/function/addRiskSchema
    docs/function/addSizingSchema
    docs/function/addStrategySchema
    docs/function/addWalkerSchema
    docs/function/cacheCandles
    docs/function/checkCandles
    docs/function/commitActivateScheduled
    docs/function/commitAverageBuy
    docs/function/commitBreakeven
    docs/function/commitCancelScheduled
    docs/function/commitClosePending
    docs/function/commitCreateSignal
    docs/function/commitPartialLoss
    docs/function/commitPartialLossCost
    docs/function/commitPartialProfit
    docs/function/commitPartialProfitCost
    docs/function/commitSignalNotify
    docs/function/commitTrailingStop
    docs/function/commitTrailingStopCost
    docs/function/commitTrailingTake
    docs/function/commitTrailingTakeCost
    docs/function/createSignalState
    docs/function/dumpAgentAnswer
    docs/function/dumpError
    docs/function/dumpJson
    docs/function/dumpRecord
    docs/function/dumpTable
    docs/function/dumpText
    docs/function/formatPrice
    docs/function/formatQuantity
    docs/function/getActionSchema
    docs/function/getAggregatedTrades
    docs/function/getAveragePrice
    docs/function/getBacktestTimeframe
    docs/function/getBreakeven
    docs/function/getCandles
    docs/function/getClosePrice
    docs/function/getColumns
    docs/function/getConfig
    docs/function/getContext
    docs/function/getDate
    docs/function/getDefaultColumns
    docs/function/getDefaultConfig
    docs/function/getExchangeSchema
    docs/function/getFrameSchema
    docs/function/getLatestSignal
    docs/function/getMaxDrawdownDistancePnlCost
    docs/function/getMaxDrawdownDistancePnlPercentage
    docs/function/getMinutesSinceLatestSignalCreated
    docs/function/getMode
    docs/function/getNextCandles
    docs/function/getOrderBook
    docs/function/getPendingSignal
    docs/function/getPositionActiveMinutes
    docs/function/getPositionCountdownMinutes
    docs/function/getPositionDrawdownMinutes
    docs/function/getPositionEffectivePrice
    docs/function/getPositionEntries
    docs/function/getPositionEntryOverlap
    docs/function/getPositionEstimateMinutes
    docs/function/getPositionHighestMaxDrawdownPnlCost
    docs/function/getPositionHighestMaxDrawdownPnlPercentage
    docs/function/getPositionHighestPnlCost
    docs/function/getPositionHighestPnlPercentage
    docs/function/getPositionHighestProfitBreakeven
    docs/function/getPositionHighestProfitDistancePnlCost
    docs/function/getPositionHighestProfitDistancePnlPercentage
    docs/function/getPositionHighestProfitMinutes
    docs/function/getPositionHighestProfitPrice
    docs/function/getPositionHighestProfitTimestamp
    docs/function/getPositionInvestedCost
    docs/function/getPositionInvestedCount
    docs/function/getPositionLevels
    docs/function/getPositionMaxDrawdownMinutes
    docs/function/getPositionMaxDrawdownPnlCost
    docs/function/getPositionMaxDrawdownPnlPercentage
    docs/function/getPositionMaxDrawdownPrice
    docs/function/getPositionMaxDrawdownTimestamp
    docs/function/getPositionPartialOverlap
    docs/function/getPositionPartials
    docs/function/getPositionPnlCost
    docs/function/getPositionPnlPercent
    docs/function/getPositionWaitingMinutes
    docs/function/getRawCandles
    docs/function/getRiskSchema
    docs/function/getRuntimeInfo
    docs/function/getScheduledSignal
    docs/function/getSessionData
    docs/function/getSignalState
    docs/function/getSizingSchema
    docs/function/getStrategySchema
    docs/function/getStrategyStatus
    docs/function/getSymbol
    docs/function/getTimestamp
    docs/function/getTotalCostClosed
    docs/function/getTotalPercentClosed
    docs/function/getWalkerSchema
    docs/function/hasNoPendingSignal
    docs/function/hasNoScheduledSignal
    docs/function/hasTradeContext
    docs/function/listenActivePing
    docs/function/listenActivePingOnce
    docs/function/listenAfterEnd
    docs/function/listenAfterEndOnce
    docs/function/listenBacktestProgress
    docs/function/listenBeforeStart
    docs/function/listenBeforeStartOnce
    docs/function/listenBreakevenAvailable
    docs/function/listenBreakevenAvailableOnce
    docs/function/listenDoneBacktest
    docs/function/listenDoneBacktestOnce
    docs/function/listenDoneLive
    docs/function/listenDoneLiveOnce
    docs/function/listenDoneWalker
    docs/function/listenDoneWalkerOnce
    docs/function/listenError
    docs/function/listenExit
    docs/function/listenHighestProfit
    docs/function/listenHighestProfitOnce
    docs/function/listenIdlePing
    docs/function/listenIdlePingOnce
    docs/function/listenMaxDrawdown
    docs/function/listenMaxDrawdownOnce
    docs/function/listenPartialLossAvailable
    docs/function/listenPartialLossAvailableOnce
    docs/function/listenPartialProfitAvailable
    docs/function/listenPartialProfitAvailableOnce
    docs/function/listenPerformance
    docs/function/listenRisk
    docs/function/listenRiskOnce
    docs/function/listenSchedulePing
    docs/function/listenSchedulePingOnce
    docs/function/listenSignal
    docs/function/listenSignalBacktest
    docs/function/listenSignalBacktestOnce
    docs/function/listenSignalLive
    docs/function/listenSignalLiveOnce
    docs/function/listenSignalNotify
    docs/function/listenSignalNotifyOnce
    docs/function/listenSignalOnce
    docs/function/listenStrategyCommit
    docs/function/listenStrategyCommitOnce
    docs/function/listenSync
    docs/function/listenSyncOnce
    docs/function/listenValidation
    docs/function/listenWalker
    docs/function/listenWalkerComplete
    docs/function/listenWalkerOnce
    docs/function/listenWalkerProgress
    docs/function/listExchangeSchema
    docs/function/listFrameSchema
    docs/function/listMemory
    docs/function/listRiskSchema
    docs/function/listSizingSchema
    docs/function/listStrategySchema
    docs/function/listWalkerSchema
    docs/function/overrideActionSchema
    docs/function/overrideExchangeSchema
    docs/function/overrideFrameSchema
    docs/function/overrideRiskSchema
    docs/function/overrideSizingSchema
    docs/function/overrideStrategySchema
    docs/function/overrideWalkerSchema
    docs/function/readMemory
    docs/function/removeMemory
    docs/function/runInMockContext
    docs/function/searchMemory
    docs/function/setColumns
    docs/function/setConfig
    docs/function/setLogger
    docs/function/setSessionData
    docs/function/setSignalState
    docs/function/shutdown
    docs/function/stopStrategy
    docs/function/validate
    docs/function/waitForReady
    docs/function/warmCandles
    docs/function/writeMemory
    docs/interface/ActivateScheduledCommit
    docs/interface/ActivateScheduledCommitNotification
    docs/interface/ActivePingContract
    docs/interface/AfterEndContract
    docs/interface/AverageBuyCommit
    docs/interface/AverageBuyCommitNotification
    docs/interface/BacktestStatisticsModel
    docs/interface/BeforeStartContract
    docs/interface/BreakevenAvailableNotification
    docs/interface/BreakevenCommit
    docs/interface/BreakevenCommitNotification
    docs/interface/BreakevenContract
    docs/interface/BreakevenEvent
    docs/interface/BreakevenStatisticsModel
    docs/interface/CancelScheduledCommit
    docs/interface/CancelScheduledCommitNotification
    docs/interface/ClosePendingCommit
    docs/interface/ClosePendingCommitNotification
    docs/interface/ColumnModel
    docs/interface/CriticalErrorNotification
    docs/interface/CronEntry
    docs/interface/CronHandle
    docs/interface/DoneContract
    docs/interface/HeatmapStatisticsModel
    docs/interface/HighestProfitContract
    docs/interface/HighestProfitEvent
    docs/interface/HighestProfitStatisticsModel
    docs/interface/IAction
    docs/interface/IActionCallbacks
    docs/interface/IActionParams
    docs/interface/IActionSchema
    docs/interface/IActionStrategy
    docs/interface/IActivateScheduledCommitRow
    docs/interface/IActivityEntry
    docs/interface/IAggregatedTradeData
    docs/interface/IAverageBuyCommitRow
    docs/interface/IBidData
    docs/interface/IBreakeven
    docs/interface/IBreakevenCommitRow
    docs/interface/IBreakevenData
    docs/interface/IBroker
    docs/interface/ICacheCandlesParams
    docs/interface/ICandleData
    docs/interface/ICheckCandlesParams
    docs/interface/ICommitRowBase
    docs/interface/IdlePingContract
    docs/interface/IDumpContext
    docs/interface/IDumpInstance
    docs/interface/IEntity
    docs/interface/IExchange
    docs/interface/IExchangeCallbacks
    docs/interface/IExchangeParams
    docs/interface/IExchangeSchema
    docs/interface/IExecutionContext
    docs/interface/IFrame
    docs/interface/IFrameCallbacks
    docs/interface/IFrameParams
    docs/interface/IFrameSchema
    docs/interface/IHeatmapRow
    docs/interface/ILog
    docs/interface/ILogEntry
    docs/interface/ILogger
    docs/interface/IMarkdownDumpOptions
    docs/interface/IMarkdownTarget
    docs/interface/IMemoryInstance
    docs/interface/IMethodContext
    docs/interface/InfoErrorNotification
    docs/interface/INotificationTarget
    docs/interface/INotificationUtils
    docs/interface/IOrderBookData
    docs/interface/IParseArgsParams
    docs/interface/IParseArgsResult
    docs/interface/IPartial
    docs/interface/IPartialData
    docs/interface/IPartialLossCommitRow
    docs/interface/IPartialProfitCommitRow
    docs/interface/IPersistBase
    docs/interface/IPersistBreakevenInstance
    docs/interface/IPersistCandleInstance
    docs/interface/IPersistIntervalInstance
    docs/interface/IPersistLogInstance
    docs/interface/IPersistMeasureInstance
    docs/interface/IPersistMemoryInstance
    docs/interface/IPersistNotificationInstance
    docs/interface/IPersistPartialInstance
    docs/interface/IPersistRecentInstance
    docs/interface/IPersistRiskInstance
    docs/interface/IPersistScheduleInstance
    docs/interface/IPersistSessionInstance
    docs/interface/IPersistSignalInstance
    docs/interface/IPersistStateInstance
    docs/interface/IPersistStorageInstance
    docs/interface/IPersistStrategyInstance
    docs/interface/IPositionOverlapLadder
    docs/interface/IPositionSizeATRParams
    docs/interface/IPositionSizeFixedPercentageParams
    docs/interface/IPositionSizeKellyParams
    docs/interface/IPublicCandleData
    docs/interface/IPublicSignalRow
    docs/interface/IRecentUtils
    docs/interface/IReportDumpOptions
    docs/interface/IReportTarget
    docs/interface/IRisk
    docs/interface/IRiskActivePosition
    docs/interface/IRiskCallbacks
    docs/interface/IRiskCheckArgs
    docs/interface/IRiskCheckOptions
    docs/interface/IRiskParams
    docs/interface/IRiskRejectionResult
    docs/interface/IRiskSchema
    docs/interface/IRiskSignalRow
    docs/interface/IRiskValidation
    docs/interface/IRiskValidationFn
    docs/interface/IRiskValidationPayload
    docs/interface/IRunContext
    docs/interface/IRuntimeInfo
    docs/interface/IRuntimeRange
    docs/interface/IScheduledSignalActivateRow
    docs/interface/IScheduledSignalCancelRow
    docs/interface/IScheduledSignalRow
    docs/interface/ISessionInstance
    docs/interface/ISignalCloseRow
    docs/interface/ISignalDto
    docs/interface/ISignalIntervalDto
    docs/interface/ISignalRow
    docs/interface/ISizing
    docs/interface/ISizingCalculateParamsATR
    docs/interface/ISizingCalculateParamsBase
    docs/interface/ISizingCalculateParamsFixedPercentage
    docs/interface/ISizingCalculateParamsKelly
    docs/interface/ISizingCallbacks
    docs/interface/ISizingParamsATR
    docs/interface/ISizingParamsFixedPercentage
    docs/interface/ISizingParamsKelly
    docs/interface/ISizingSchemaATR
    docs/interface/ISizingSchemaBase
    docs/interface/ISizingSchemaFixedPercentage
    docs/interface/ISizingSchemaKelly
    docs/interface/IStateInstance
    docs/interface/IStateParams
    docs/interface/IStorageSignalRowBase
    docs/interface/IStorageSignalRowCancelled
    docs/interface/IStorageSignalRowClosed
    docs/interface/IStorageSignalRowOpened
    docs/interface/IStorageSignalRowScheduled
    docs/interface/IStorageUtils
    docs/interface/IStrategy
    docs/interface/IStrategyCallbacks
    docs/interface/IStrategyPnL
    docs/interface/IStrategyResult
    docs/interface/IStrategySchema
    docs/interface/IStrategyTickResultActive
    docs/interface/IStrategyTickResultCancelled
    docs/interface/IStrategyTickResultClosed
    docs/interface/IStrategyTickResultIdle
    docs/interface/IStrategyTickResultOpened
    docs/interface/IStrategyTickResultScheduled
    docs/interface/IStrategyTickResultWaiting
    docs/interface/ITrailingStopCommitRow
    docs/interface/ITrailingTakeCommitRow
    docs/interface/IWalkerCallbacks
    docs/interface/IWalkerResults
    docs/interface/IWalkerSchema
    docs/interface/IWalkerStrategyResult
    docs/interface/IWarmCandlesParams
    docs/interface/LiveStatisticsModel
    docs/interface/MaxDrawdownContract
    docs/interface/MaxDrawdownEvent
    docs/interface/MaxDrawdownStatisticsModel
    docs/interface/MessageModel
    docs/interface/MetricStats
    docs/interface/PartialEvent
    docs/interface/PartialLossAvailableNotification
    docs/interface/PartialLossCommit
    docs/interface/PartialLossCommitNotification
    docs/interface/PartialLossContract
    docs/interface/PartialProfitAvailableNotification
    docs/interface/PartialProfitCommit
    docs/interface/PartialProfitCommitNotification
    docs/interface/PartialProfitContract
    docs/interface/PartialStatisticsModel
    docs/interface/PerformanceContract
    docs/interface/PerformanceStatisticsModel
    docs/interface/ProgressBacktestContract
    docs/interface/ProgressWalkerContract
    docs/interface/RiskContract
    docs/interface/RiskEvent
    docs/interface/RiskRejectionNotification
    docs/interface/RiskStatisticsModel
    docs/interface/ScheduledEvent
    docs/interface/SchedulePingContract
    docs/interface/ScheduleStatisticsModel
    docs/interface/Signal
    docs/interface/Signal$1
    docs/interface/Signal$2
    docs/interface/SignalCancelledNotification
    docs/interface/SignalCloseContract
    docs/interface/SignalClosedNotification
    docs/interface/SignalCommitBase
    docs/interface/SignalData$1
    docs/interface/SignalInfoContract
    docs/interface/SignalInfoNotification
    docs/interface/SignalOpenContract
    docs/interface/SignalOpenedNotification
    docs/interface/SignalPingContract
    docs/interface/SignalScheduledNotification
    docs/interface/SignalSyncBase
    docs/interface/SignalSyncCloseNotification
    docs/interface/SignalSyncOpenNotification
    docs/interface/StrategyEvent
    docs/interface/StrategyStatisticsModel
    docs/interface/SyncEvent
    docs/interface/SyncStatisticsModel
    docs/interface/TickEvent
    docs/interface/TrailingStopCommit
    docs/interface/TrailingStopCommitNotification
    docs/interface/TrailingTakeCommit
    docs/interface/TrailingTakeCommitNotification
    docs/interface/ValidateArgs
    docs/interface/ValidationErrorNotification
    docs/interface/WalkerCompleteContract
    docs/interface/WalkerContract
    docs/interface/WalkerStatisticsModel
    docs/interface/WalkerStopContract
    docs/type/ActionName
    docs/type/Args
    docs/type/BreakevenData
    docs/type/BrokerAverageBuyPayload
    docs/type/BrokerBreakevenPayload
    docs/type/BrokerPartialLossPayload
    docs/type/BrokerPartialProfitPayload
    docs/type/BrokerSignalClosePayload
    docs/type/BrokerSignalOpenPayload
    docs/type/BrokerSignalPendingPayload
    docs/type/BrokerTrailingStopPayload
    docs/type/BrokerTrailingTakePayload
    docs/type/BucketName
    docs/type/CacheFileFunction
    docs/type/CacheFileKeyArgs
    docs/type/CandleData
    docs/type/CandleInterval
    docs/type/ColumnConfig
    docs/type/Columns
    docs/type/Columns$1
    docs/type/Columns$2
    docs/type/Columns$3
    docs/type/Columns$4
    docs/type/Columns$5
    docs/type/Columns$6
    docs/type/Columns$7
    docs/type/Columns$8
    docs/type/Columns$9
    docs/type/Columns$a
    docs/type/Columns$b
    docs/type/CommitPayload
    docs/type/CronCallback
    docs/type/Dispatch
    docs/type/Dispatch$1
    docs/type/DropFirst
    docs/type/DropFirst$1
    docs/type/EntityId
    docs/type/Enum
    docs/type/ExchangeName
    docs/type/FrameInterval
    docs/type/FrameName
    docs/type/Function
    docs/type/Function$1
    docs/type/Function$2
    docs/type/GetStateFn
    docs/type/GlobalConfig
    docs/type/IBacktestLogicPrivateService
    docs/type/ICommitRow
    docs/type/ILiveLogicPrivateService
    docs/type/IntervalData
    docs/type/IntervalFileFunction
    docs/type/IntervalFileKeyArgs
    docs/type/IPublicAction
    docs/type/ISizingCalculateParams
    docs/type/ISizingParams
    docs/type/ISizingSchema
    docs/type/IStorageSignalRow
    docs/type/IStrategyBacktestResult
    docs/type/IStrategyTickResult
    docs/type/IWalkerLogicPrivateService
    docs/type/Keys
    docs/type/Keys$1
    docs/type/LogData
    docs/type/MarkdownName
    docs/type/MeasureData
    docs/type/MemoryData
    docs/type/MessageRole
    docs/type/MessageToolCall
    docs/type/NotificationData
    docs/type/NotificationModel
    docs/type/Num
    docs/type/PartialData
    docs/type/PartialLevel
    docs/type/PerformanceMetricType
    docs/type/PnlColumn
    docs/type/RecentData
    docs/type/ReportName
    docs/type/RestoreSnapshot
    docs/type/RiskData
    docs/type/RiskMap
    docs/type/RiskName
    docs/type/RiskRejection
    docs/type/RuntimeData
    docs/type/ScheduleData
    docs/type/SearchSettings
    docs/type/SessionData
    docs/type/SetStateFn
    docs/type/SignalData
    docs/type/SignalInterval
    docs/type/SignalNotificationPayload
    docs/type/SignalStateTuple
    docs/type/SignalSyncContract
    docs/type/SizingName
    docs/type/StateData
    docs/type/StorageData
    docs/type/StorageId
    docs/type/StrategyActionType
    docs/type/StrategyCancelReason
    docs/type/StrategyCloseReason
    docs/type/StrategyColumn
    docs/type/StrategyCommitContract
    docs/type/StrategyData
    docs/type/StrategyName
    docs/type/StrategyStatus
    docs/type/SyncActionType
    docs/type/TAction
    docs/type/TAction$1
    docs/type/TActionCtor
    docs/type/TActionSchema
    docs/type/TBacktestLogicPrivateService
    docs/type/TBacktestLogicPublicService
    docs/type/TBreakeven
    docs/type/TBrokerCtor
    docs/type/TDumpInstanceCtor
    docs/type/TExchange
    docs/type/TExchangeSchema
    docs/type/TExecutionContextService
    docs/type/TFrame
    docs/type/TFrameSchema
    docs/type/TLiveLogicPrivateService
    docs/type/TLiveLogicPublicService
    docs/type/TLogCtor
    docs/type/TMarkdownBase
    docs/type/TMarkdownBaseCtor
    docs/type/TMemoryInstance
    docs/type/TMemoryInstanceCtor
    docs/type/TNotificationUtilsCtor
    docs/type/TPartial
    docs/type/TPersistBase
    docs/type/TPersistBaseCtor
    docs/type/TPersistBreakevenInstanceCtor
    docs/type/TPersistCandleInstanceCtor
    docs/type/TPersistIntervalInstanceCtor
    docs/type/TPersistLogInstanceCtor
    docs/type/TPersistMeasureInstanceCtor
    docs/type/TPersistMemoryInstanceCtor
    docs/type/TPersistNotificationInstanceCtor
    docs/type/TPersistPartialInstanceCtor
    docs/type/TPersistRecentInstanceCtor
    docs/type/TPersistRiskInstanceCtor
    docs/type/TPersistScheduleInstanceCtor
    docs/type/TPersistSessionInstanceCtor
    docs/type/TPersistSignalInstanceCtor
    docs/type/TPersistStateInstanceCtor
    docs/type/TPersistStorageInstanceCtor
    docs/type/TPersistStrategyInstanceCtor
    docs/type/TRecentUtilsCtor
    docs/type/TReportBase
    docs/type/TReportBaseCtor
    docs/type/TRisk
    docs/type/TRisk$1
    docs/type/TRiskSchema
    docs/type/TSessionAdapter
    docs/type/TSessionInstanceCtor
    docs/type/TSizing
    docs/type/TSizing$1
    docs/type/TSizingSchema
    docs/type/TStateAdapter
    docs/type/TStateInstanceCtor
    docs/type/TStorageUtilsCtor
    docs/type/TStrategy
    docs/type/TStrategy$1
    docs/type/TStrategySchema
    docs/type/TWalkerLogicPrivateService
    docs/type/TWalkerLogicPublicService
    docs/type/TWalkerSchema
    docs/type/WalkerMetric
    docs/type/WalkerName

    example

    example/01_getting_started
    example/02_first_backtest
    example/03_understanding_signals
    example/04_live_trading
    example/05_risk_management
    example/06_ai_optimization
    example/07_llm_trading

    packages/front

    packages/front/readme

    packages/graph

    packages/graph/readme

    packages/mongo

    packages/mongo/readme

    packages/ollama

    packages/ollama/readme

    packages/pinets

    packages/pinets/readme

    packages/sidekick

    packages/sidekick/readme

    packages/signals

    packages/signals/readme

    private

    private/classes
    private/functions
    private/interfaces

    strategies

    strategies/apr_2024
    strategies/apr_2026
    strategies/dec_2025
    strategies/feb_2021
    strategies/feb_2026
    strategies/jan_2026
    strategies/mar_2026
    strategies/oct_2021
    strategies/overview
    +backtest-kit

    backtest-kit

    Documents

    docs\data\positional-args-audit
    LLMs

    Modules

    types

    article

    article/01_look_ahead_bias
    article/02_second_order_chaos
    article/03_claude_trader
    article/04_option_hedging
    article/05_ai_strategy_workflow
    article/06_ai_strategy_blueprint
    article/07_ai_news_trading_signals
    article/08_ai_liquidity_harvesting
    article/09_pinescript_local_markets
    article/10_dca_averaging_strategy

    begin

    begin/01_project_overview
    begin/02_getting_started_configuration
    begin/03_system_architecture_overview
    begin/04_llm_forecast_engine_logic
    begin/05_forecast_pipeline_outline
    begin/06_advisors_news_market_data
    begin/07_news_fetching_caching_fetchnews
    begin/08_ollama_completions
    begin/09_trading_strategy_feb_2026_strategy
    begin/10_signal_generation_sentiment_mapping
    begin/11_position_lifecycle_exit_logic
    begin/12_backtest_module_frame_configuration
    begin/13_february_2026_case_study_performance
    begin/14_backtest_kit_framework
    begin/15_backtesting_execution_reporting
    begin/16_signal_state_machine
    begin/17_live_trading_mode
    begin/18_risk_management
    begin/19_ai_strategy_optimization_walker
    begin/20_exchange_integration_modules
    begin/21_ccxt_exchange_adapter
    begin/22_symbol_configuration
    begin/23_glossary

    cli

    cli/readme

    concept

    concept/01_monorepo_parallel_execution
    concept/02_zero_expectation_escape
    concept/03_manual_control_adapter

    data

    data/test-guidelines

    demo/backtest

    demo/backtest/readme

    demo/broker

    demo/broker/readme

    demo/exchange

    demo/exchange/readme

    demo/live

    demo/live/readme

    demo/optimization

    demo/optimization/readme

    demo/pinets

    demo/pinets/readme

    design

    design/01_overview
    design/02_key_features
    design/03_installation_and_setup
    design/04_quick_start_guide
    design/05_core_concepts
    design/06_execution_modes
    design/07_signal_lifecycle_overview
    design/08_component_registration
    design/09_temporal_isolation_and_look-ahead_prevention
    design/10_architecture
    design/11_layer_responsibilities
    design/12_dependency_injection_system
    design/13_context_propagation
    design/14_event_system
    design/15_public_api_reference
    design/16_configuration_functions
    design/17_component_registration_functions
    design/18_backtest_api
    design/19_live_trading_api
    design/20_walker_api
    design/21_persistence_utilities
    design/22_exchange_functions
    design/23_event_listeners
    design/24_component_schemas
    design/25_strategy_schemas
    design/26_exchange_schemas
    design/27_frame_schemas
    design/28_risk_schemas
    design/29_sizing_schemas
    design/30_walker_schemas
    design/31_optimizer_schemas
    design/32_client_implementations
    design/33_clientstrategy
    design/34_clientexchange
    design/35_clientframe
    design/36_clientrisk
    design/37_clientsizing
    design/38_clientpartial
    design/39_clientoptimizer
    design/40_service_layer
    design/41_service_architecture_overview
    design/42_connection_services
    design/43_schema_services
    design/44_validation_services
    design/45_global_services
    design/46_logic_services
    design/47_markdown_services
    design/48_signal_lifecycle
    design/49_signal_states
    design/50_signal_generation_and_validation
    design/51_scheduled_signals
    design/52_signal_persistence
    design/53_pnl_calculation
    design/54_backtesting
    design/55_backtest_execution_flow
    design/56_timeframe_generation
    design/57_fast-forward_simulation
    design/58_live_trading
    design/59_live_execution_flow
    design/60_crash_recovery
    design/61_real-time_monitoring
    design/62_interval_throttling
    design/63_walker_mode
    design/64_walker_execution_flow
    design/65_strategy_comparison
    design/66_walker_reports
    design/67_risk_management
    design/68_risk_profiles
    design/69_risk_validation
    design/70_position_tracking
    design/71_reporting_and_analytics
    design/72_markdown_report_generation
    design/73_performance_metrics
    design/74_statistics_calculation
    design/75_partial_profit_loss_tracking
    design/76_heatmap_analytics
    design/77_configuration
    design/78_global_configuration
    design/79_validation_parameters
    design/80_timing_parameters
    design/81_cross-cutting_concerns
    design/82_logging_system
    design/83_error_handling
    design/84_persistence_layer
    design/85_advanced_topics
    design/86_custom_exchange_integration
    design/87_custom_persistence_backends
    design/88_custom_risk_validations
    design/89_multi-symbol_strategies
    design/90_ai-powered_strategy_optimization
    design/91_optimizer_architecture
    design/92_data_collection_pipeline
    design/93_llm_integration
    design/94_strategy_code_generation
    design/95_training_vs_testing_ranges

    docs

    docs
    docs/class/ActionBase
    docs/class/ActionConnectionService
    docs/class/ActionCoreService
    docs/class/ActionProxy
    docs/class/ActionSchemaService
    docs/class/ActionValidationService
    docs/class/BacktestCommandService
    docs/class/BacktestLogicPrivateService
    docs/class/BacktestLogicPublicService
    docs/class/BacktestMarkdownService
    docs/class/BacktestReportService
    docs/class/BacktestUtils
    docs/class/BreakevenConnectionService
    docs/class/BreakevenGlobalService
    docs/class/BreakevenMarkdownService
    docs/class/BreakevenReportService
    docs/class/BreakevenUtils
    docs/class/BrokerAdapter
    docs/class/BrokerBase
    docs/class/CacheUtils
    docs/class/ClientAction
    docs/class/ClientExchange
    docs/class/ClientFrame
    docs/class/ClientRisk
    docs/class/ClientSizing
    docs/class/ColumnValidationService
    docs/class/ConfigValidationService
    docs/class/ConstantUtils
    docs/class/CronUtils
    docs/class/DumpAdapter
    docs/class/ExchangeConnectionService
    docs/class/ExchangeCoreService
    docs/class/ExchangeSchemaService
    docs/class/ExchangeUtils
    docs/class/ExchangeValidationService
    docs/class/FrameConnectionService
    docs/class/FrameCoreService
    docs/class/FrameSchemaService
    docs/class/FrameValidationService
    docs/class/HeatMarkdownService
    docs/class/HeatReportService
    docs/class/HeatUtils
    docs/class/HighestProfitMarkdownService
    docs/class/HighestProfitReportService
    docs/class/HighestProfitUtils
    docs/class/IntervalUtils
    docs/class/LiveCommandService
    docs/class/LiveLogicPrivateService
    docs/class/LiveLogicPublicService
    docs/class/LiveMarkdownService
    docs/class/LiveReportService
    docs/class/LiveUtils
    docs/class/LogAdapter
    docs/class/LoggerService
    docs/class/LookupUtils
    docs/class/MarkdownAdapter
    docs/class/MarkdownFileBase
    docs/class/MarkdownFolderBase
    docs/class/MarkdownUtils
    docs/class/MarkdownWriterAdapter
    docs/class/MaxDrawdownMarkdownService
    docs/class/MaxDrawdownReportService
    docs/class/MaxDrawdownUtils
    docs/class/MemoryAdapter
    docs/class/MemoryBacktestAdapter
    docs/class/MemoryLiveAdapter
    docs/class/NotificationAdapter
    docs/class/NotificationBacktestAdapter
    docs/class/NotificationHelperService
    docs/class/NotificationLiveAdapter
    docs/class/PartialConnectionService
    docs/class/PartialGlobalService
    docs/class/PartialMarkdownService
    docs/class/PartialReportService
    docs/class/PartialUtils
    docs/class/Performance
    docs/class/PerformanceMarkdownService
    docs/class/PerformanceReportService
    docs/class/PersistBase
    docs/class/PersistBreakevenInstance
    docs/class/PersistBreakevenUtils
    docs/class/PersistCandleInstance
    docs/class/PersistCandleUtils
    docs/class/PersistIntervalInstance
    docs/class/PersistIntervalUtils
    docs/class/PersistLogInstance
    docs/class/PersistLogUtils
    docs/class/PersistMeasureInstance
    docs/class/PersistMeasureUtils
    docs/class/PersistMemoryInstance
    docs/class/PersistMemoryUtils
    docs/class/PersistNotificationInstance
    docs/class/PersistNotificationUtils
    docs/class/PersistPartialInstance
    docs/class/PersistPartialUtils
    docs/class/PersistRecentInstance
    docs/class/PersistRecentUtils
    docs/class/PersistRiskInstance
    docs/class/PersistRiskUtils
    docs/class/PersistScheduleInstance
    docs/class/PersistScheduleUtils
    docs/class/PersistSessionInstance
    docs/class/PersistSessionUtils
    docs/class/PersistSignalInstance
    docs/class/PersistSignalUtils
    docs/class/PersistStateInstance
    docs/class/PersistStateUtils
    docs/class/PersistStorageInstance
    docs/class/PersistStorageUtils
    docs/class/PersistStrategyInstance
    docs/class/PersistStrategyUtils
    docs/class/Position
    docs/class/PositionSizeUtils
    docs/class/PriceMetaService
    docs/class/RecentAdapter
    docs/class/RecentBacktestAdapter
    docs/class/RecentLiveAdapter
    docs/class/ReflectUtils
    docs/class/ReportAdapter
    docs/class/ReportBase
    docs/class/ReportUtils
    docs/class/ReportWriterAdapter
    docs/class/RiskConnectionService
    docs/class/RiskGlobalService
    docs/class/RiskMarkdownService
    docs/class/RiskReportService
    docs/class/RiskSchemaService
    docs/class/RiskUtils
    docs/class/RiskValidationService
    docs/class/ScheduleMarkdownService
    docs/class/ScheduleReportService
    docs/class/ScheduleUtils
    docs/class/SessionAdapter
    docs/class/SessionBacktestAdapter
    docs/class/SessionLiveAdapter
    docs/class/SizingConnectionService
    docs/class/SizingGlobalService
    docs/class/SizingSchemaService
    docs/class/SizingValidationService
    docs/class/StateAdapter
    docs/class/StateBacktestAdapter
    docs/class/StateLiveAdapter
    docs/class/StorageAdapter
    docs/class/StorageBacktestAdapter
    docs/class/StorageLiveAdapter
    docs/class/StrategyConnectionService
    docs/class/StrategyCoreService
    docs/class/StrategyMarkdownService
    docs/class/StrategyReportService
    docs/class/StrategySchemaService
    docs/class/StrategyUtils
    docs/class/StrategyValidationService
    docs/class/SyncMarkdownService
    docs/class/SyncReportService
    docs/class/SyncUtils
    docs/class/SystemUtils
    docs/class/TimeMetaService
    docs/class/WalkerCommandService
    docs/class/WalkerLogicPrivateService
    docs/class/WalkerLogicPublicService
    docs/class/WalkerMarkdownService
    docs/class/WalkerReportService
    docs/class/WalkerSchemaService
    docs/class/WalkerUtils
    docs/class/WalkerValidationService
    docs/function/addActionSchema
    docs/function/addExchangeSchema
    docs/function/addFrameSchema
    docs/function/addRiskSchema
    docs/function/addSizingSchema
    docs/function/addStrategySchema
    docs/function/addWalkerSchema
    docs/function/cacheCandles
    docs/function/checkCandles
    docs/function/commitActivateScheduled
    docs/function/commitAverageBuy
    docs/function/commitBreakeven
    docs/function/commitCancelScheduled
    docs/function/commitClosePending
    docs/function/commitCreateSignal
    docs/function/commitCreateStopLoss
    docs/function/commitCreateTakeProfit
    docs/function/commitPartialLoss
    docs/function/commitPartialLossCost
    docs/function/commitPartialProfit
    docs/function/commitPartialProfitCost
    docs/function/commitSignalNotify
    docs/function/commitTrailingStop
    docs/function/commitTrailingStopCost
    docs/function/commitTrailingTake
    docs/function/commitTrailingTakeCost
    docs/function/createSignalState
    docs/function/dumpAgentAnswer
    docs/function/dumpError
    docs/function/dumpJson
    docs/function/dumpRecord
    docs/function/dumpTable
    docs/function/dumpText
    docs/function/formatPrice
    docs/function/formatQuantity
    docs/function/getActionSchema
    docs/function/getAggregatedTrades
    docs/function/getAveragePrice
    docs/function/getBacktestTimeframe
    docs/function/getBreakeven
    docs/function/getCandles
    docs/function/getClosePrice
    docs/function/getColumns
    docs/function/getConfig
    docs/function/getContext
    docs/function/getDate
    docs/function/getDefaultColumns
    docs/function/getDefaultConfig
    docs/function/getExchangeSchema
    docs/function/getFrameSchema
    docs/function/getLatestSignal
    docs/function/getMaxDrawdownDistancePnlCost
    docs/function/getMaxDrawdownDistancePnlPercentage
    docs/function/getMinutesSinceLatestSignalCreated
    docs/function/getMode
    docs/function/getNextCandles
    docs/function/getOrderBook
    docs/function/getPendingSignal
    docs/function/getPositionActiveMinutes
    docs/function/getPositionCountdownMinutes
    docs/function/getPositionDrawdownMinutes
    docs/function/getPositionEffectivePrice
    docs/function/getPositionEntries
    docs/function/getPositionEntryOverlap
    docs/function/getPositionEstimateMinutes
    docs/function/getPositionHighestMaxDrawdownPnlCost
    docs/function/getPositionHighestMaxDrawdownPnlPercentage
    docs/function/getPositionHighestPnlCost
    docs/function/getPositionHighestPnlPercentage
    docs/function/getPositionHighestProfitBreakeven
    docs/function/getPositionHighestProfitDistancePnlCost
    docs/function/getPositionHighestProfitDistancePnlPercentage
    docs/function/getPositionHighestProfitMinutes
    docs/function/getPositionHighestProfitPrice
    docs/function/getPositionHighestProfitTimestamp
    docs/function/getPositionInvestedCost
    docs/function/getPositionInvestedCount
    docs/function/getPositionLevels
    docs/function/getPositionMaxDrawdownMinutes
    docs/function/getPositionMaxDrawdownPnlCost
    docs/function/getPositionMaxDrawdownPnlPercentage
    docs/function/getPositionMaxDrawdownPrice
    docs/function/getPositionMaxDrawdownTimestamp
    docs/function/getPositionPartialOverlap
    docs/function/getPositionPartials
    docs/function/getPositionPnlCost
    docs/function/getPositionPnlPercent
    docs/function/getPositionWaitingMinutes
    docs/function/getRawCandles
    docs/function/getRiskSchema
    docs/function/getRuntimeInfo
    docs/function/getScheduledSignal
    docs/function/getSessionData
    docs/function/getSignalState
    docs/function/getSizingSchema
    docs/function/getStrategySchema
    docs/function/getStrategyStatus
    docs/function/getSymbol
    docs/function/getTimestamp
    docs/function/getTotalCostClosed
    docs/function/getTotalPercentClosed
    docs/function/getWalkerSchema
    docs/function/hasNoPendingSignal
    docs/function/hasNoScheduledSignal
    docs/function/hasTradeContext
    docs/function/listenActivePing
    docs/function/listenActivePingOnce
    docs/function/listenAfterEnd
    docs/function/listenAfterEndOnce
    docs/function/listenBacktestProgress
    docs/function/listenBeforeStart
    docs/function/listenBeforeStartOnce
    docs/function/listenBreakevenAvailable
    docs/function/listenBreakevenAvailableOnce
    docs/function/listenDoneBacktest
    docs/function/listenDoneBacktestOnce
    docs/function/listenDoneLive
    docs/function/listenDoneLiveOnce
    docs/function/listenDoneWalker
    docs/function/listenDoneWalkerOnce
    docs/function/listenError
    docs/function/listenExit
    docs/function/listenHighestProfit
    docs/function/listenHighestProfitOnce
    docs/function/listenIdlePing
    docs/function/listenIdlePingOnce
    docs/function/listenMaxDrawdown
    docs/function/listenMaxDrawdownOnce
    docs/function/listenPartialLossAvailable
    docs/function/listenPartialLossAvailableOnce
    docs/function/listenPartialProfitAvailable
    docs/function/listenPartialProfitAvailableOnce
    docs/function/listenPerformance
    docs/function/listenRisk
    docs/function/listenRiskOnce
    docs/function/listenScheduleEvent
    docs/function/listenScheduleEventOnce
    docs/function/listenSchedulePing
    docs/function/listenSchedulePingOnce
    docs/function/listenSignal
    docs/function/listenSignalBacktest
    docs/function/listenSignalBacktestOnce
    docs/function/listenSignalEvent
    docs/function/listenSignalEventOnce
    docs/function/listenSignalLive
    docs/function/listenSignalLiveOnce
    docs/function/listenSignalNotify
    docs/function/listenSignalNotifyOnce
    docs/function/listenSignalOnce
    docs/function/listenStrategyCommit
    docs/function/listenStrategyCommitOnce
    docs/function/listenSync
    docs/function/listenSyncOnce
    docs/function/listenValidation
    docs/function/listenWalker
    docs/function/listenWalkerComplete
    docs/function/listenWalkerOnce
    docs/function/listenWalkerProgress
    docs/function/listExchangeSchema
    docs/function/listFrameSchema
    docs/function/listMemory
    docs/function/listRiskSchema
    docs/function/listSizingSchema
    docs/function/listStrategySchema
    docs/function/listWalkerSchema
    docs/function/overrideActionSchema
    docs/function/overrideExchangeSchema
    docs/function/overrideFrameSchema
    docs/function/overrideRiskSchema
    docs/function/overrideSizingSchema
    docs/function/overrideStrategySchema
    docs/function/overrideWalkerSchema
    docs/function/readMemory
    docs/function/removeMemory
    docs/function/runInMockContext
    docs/function/searchMemory
    docs/function/setColumns
    docs/function/setConfig
    docs/function/setLogger
    docs/function/setSessionData
    docs/function/setSignalState
    docs/function/shutdown
    docs/function/stopStrategy
    docs/function/validate
    docs/function/waitForReady
    docs/function/warmCandles
    docs/function/writeMemory
    docs/interface/ActivateScheduledCommit
    docs/interface/ActivateScheduledCommitNotification
    docs/interface/ActivePingContract
    docs/interface/AfterEndContract
    docs/interface/AverageBuyCommit
    docs/interface/AverageBuyCommitNotification
    docs/interface/BacktestStatisticsModel
    docs/interface/BeforeStartContract
    docs/interface/BreakevenAvailableNotification
    docs/interface/BreakevenCommit
    docs/interface/BreakevenCommitNotification
    docs/interface/BreakevenContract
    docs/interface/BreakevenEvent
    docs/interface/BreakevenStatisticsModel
    docs/interface/CancelScheduledCommit
    docs/interface/CancelScheduledCommitNotification
    docs/interface/ClosePendingCommit
    docs/interface/ClosePendingCommitNotification
    docs/interface/ColumnModel
    docs/interface/CriticalErrorNotification
    docs/interface/CronEntry
    docs/interface/CronHandle
    docs/interface/DoneContract
    docs/interface/HeatmapStatisticsModel
    docs/interface/HighestProfitContract
    docs/interface/HighestProfitEvent
    docs/interface/HighestProfitStatisticsModel
    docs/interface/IAction
    docs/interface/IActionCallbacks
    docs/interface/IActionParams
    docs/interface/IActionSchema
    docs/interface/IActionStrategy
    docs/interface/IActivateScheduledCommitRow
    docs/interface/IActivityEntry
    docs/interface/IAggregatedTradeData
    docs/interface/IAverageBuyCommitRow
    docs/interface/IBidData
    docs/interface/IBreakeven
    docs/interface/IBreakevenCommitRow
    docs/interface/IBreakevenData
    docs/interface/IBroker
    docs/interface/ICacheCandlesParams
    docs/interface/ICandleData
    docs/interface/ICheckCandlesParams
    docs/interface/ICommitRowBase
    docs/interface/IdlePingContract
    docs/interface/IDumpContext
    docs/interface/IDumpInstance
    docs/interface/IEntity
    docs/interface/IExchange
    docs/interface/IExchangeCallbacks
    docs/interface/IExchangeParams
    docs/interface/IExchangeSchema
    docs/interface/IExecutionContext
    docs/interface/IFrame
    docs/interface/IFrameCallbacks
    docs/interface/IFrameParams
    docs/interface/IFrameSchema
    docs/interface/IHeatmapRow
    docs/interface/ILog
    docs/interface/ILogEntry
    docs/interface/ILogger
    docs/interface/IMarkdownDumpOptions
    docs/interface/IMarkdownTarget
    docs/interface/IMemoryInstance
    docs/interface/IMethodContext
    docs/interface/InfoErrorNotification
    docs/interface/INotificationTarget
    docs/interface/INotificationUtils
    docs/interface/IOrderBookData
    docs/interface/IParseArgsParams
    docs/interface/IParseArgsResult
    docs/interface/IPartial
    docs/interface/IPartialData
    docs/interface/IPartialLossCommitRow
    docs/interface/IPartialProfitCommitRow
    docs/interface/IPersistBase
    docs/interface/IPersistBreakevenInstance
    docs/interface/IPersistCandleInstance
    docs/interface/IPersistIntervalInstance
    docs/interface/IPersistLogInstance
    docs/interface/IPersistMeasureInstance
    docs/interface/IPersistMemoryInstance
    docs/interface/IPersistNotificationInstance
    docs/interface/IPersistPartialInstance
    docs/interface/IPersistRecentInstance
    docs/interface/IPersistRiskInstance
    docs/interface/IPersistScheduleInstance
    docs/interface/IPersistSessionInstance
    docs/interface/IPersistSignalInstance
    docs/interface/IPersistStateInstance
    docs/interface/IPersistStorageInstance
    docs/interface/IPersistStrategyInstance
    docs/interface/IPositionOverlapLadder
    docs/interface/IPositionSizeATRParams
    docs/interface/IPositionSizeFixedPercentageParams
    docs/interface/IPositionSizeKellyParams
    docs/interface/IPublicCandleData
    docs/interface/IPublicSignalRow
    docs/interface/IRecentUtils
    docs/interface/IReportDumpOptions
    docs/interface/IReportTarget
    docs/interface/IRisk
    docs/interface/IRiskActivePosition
    docs/interface/IRiskCallbacks
    docs/interface/IRiskCheckArgs
    docs/interface/IRiskCheckOptions
    docs/interface/IRiskParams
    docs/interface/IRiskRejectionResult
    docs/interface/IRiskSchema
    docs/interface/IRiskSignalRow
    docs/interface/IRiskValidation
    docs/interface/IRiskValidationFn
    docs/interface/IRiskValidationPayload
    docs/interface/IRunContext
    docs/interface/IRuntimeInfo
    docs/interface/IRuntimeRange
    docs/interface/IScheduledSignalActivateRow
    docs/interface/IScheduledSignalCancelRow
    docs/interface/IScheduledSignalRow
    docs/interface/ISessionInstance
    docs/interface/ISignalCloseRow
    docs/interface/ISignalDto
    docs/interface/ISignalIntervalDto
    docs/interface/ISignalRow
    docs/interface/ISizing
    docs/interface/ISizingCalculateParamsATR
    docs/interface/ISizingCalculateParamsBase
    docs/interface/ISizingCalculateParamsFixedPercentage
    docs/interface/ISizingCalculateParamsKelly
    docs/interface/ISizingCallbacks
    docs/interface/ISizingParamsATR
    docs/interface/ISizingParamsFixedPercentage
    docs/interface/ISizingParamsKelly
    docs/interface/ISizingSchemaATR
    docs/interface/ISizingSchemaBase
    docs/interface/ISizingSchemaFixedPercentage
    docs/interface/ISizingSchemaKelly
    docs/interface/IStateInstance
    docs/interface/IStateParams
    docs/interface/IStorageSignalRowBase
    docs/interface/IStorageSignalRowCancelled
    docs/interface/IStorageSignalRowClosed
    docs/interface/IStorageSignalRowOpened
    docs/interface/IStorageSignalRowScheduled
    docs/interface/IStorageUtils
    docs/interface/IStrategy
    docs/interface/IStrategyCallbacks
    docs/interface/IStrategyPnL
    docs/interface/IStrategyResult
    docs/interface/IStrategySchema
    docs/interface/IStrategyTickResultActive
    docs/interface/IStrategyTickResultCancelled
    docs/interface/IStrategyTickResultClosed
    docs/interface/IStrategyTickResultIdle
    docs/interface/IStrategyTickResultOpened
    docs/interface/IStrategyTickResultScheduled
    docs/interface/IStrategyTickResultWaiting
    docs/interface/ITrailingStopCommitRow
    docs/interface/ITrailingTakeCommitRow
    docs/interface/IWalkerCallbacks
    docs/interface/IWalkerResults
    docs/interface/IWalkerSchema
    docs/interface/IWalkerStrategyResult
    docs/interface/IWarmCandlesParams
    docs/interface/LiveStatisticsModel
    docs/interface/MaxDrawdownContract
    docs/interface/MaxDrawdownEvent
    docs/interface/MaxDrawdownStatisticsModel
    docs/interface/MessageModel
    docs/interface/MetricStats
    docs/interface/PartialEvent
    docs/interface/PartialLossAvailableNotification
    docs/interface/PartialLossCommit
    docs/interface/PartialLossCommitNotification
    docs/interface/PartialLossContract
    docs/interface/PartialProfitAvailableNotification
    docs/interface/PartialProfitCommit
    docs/interface/PartialProfitCommitNotification
    docs/interface/PartialProfitContract
    docs/interface/PartialStatisticsModel
    docs/interface/PerformanceContract
    docs/interface/PerformanceStatisticsModel
    docs/interface/ProgressBacktestContract
    docs/interface/ProgressWalkerContract
    docs/interface/RiskContract
    docs/interface/RiskEvent
    docs/interface/RiskRejectionNotification
    docs/interface/RiskStatisticsModel
    docs/interface/ScheduledEvent
    docs/interface/ScheduleEventContract
    docs/interface/SchedulePingContract
    docs/interface/ScheduleStatisticsModel
    docs/interface/Signal
    docs/interface/Signal$1
    docs/interface/Signal$2
    docs/interface/SignalCancelledNotification
    docs/interface/SignalCloseContract
    docs/interface/SignalClosedNotification
    docs/interface/SignalCommitBase
    docs/interface/SignalData$1
    docs/interface/SignalEventContract
    docs/interface/SignalInfoContract
    docs/interface/SignalInfoNotification
    docs/interface/SignalOpenContract
    docs/interface/SignalOpenedNotification
    docs/interface/SignalPingContract
    docs/interface/SignalScheduledNotification
    docs/interface/SignalSyncBase
    docs/interface/SignalSyncCloseNotification
    docs/interface/SignalSyncOpenNotification
    docs/interface/StrategyEvent
    docs/interface/StrategyStatisticsModel
    docs/interface/SyncEvent
    docs/interface/SyncStatisticsModel
    docs/interface/TickEvent
    docs/interface/TrailingStopCommit
    docs/interface/TrailingStopCommitNotification
    docs/interface/TrailingTakeCommit
    docs/interface/TrailingTakeCommitNotification
    docs/interface/ValidateArgs
    docs/interface/ValidationErrorNotification
    docs/interface/WalkerCompleteContract
    docs/interface/WalkerContract
    docs/interface/WalkerStatisticsModel
    docs/interface/WalkerStopContract
    docs/type/ActionName
    docs/type/Args
    docs/type/BreakevenData
    docs/type/BrokerActivePingPayload
    docs/type/BrokerAverageBuyPayload
    docs/type/BrokerBreakevenPayload
    docs/type/BrokerIdlePingPayload
    docs/type/BrokerPartialLossPayload
    docs/type/BrokerPartialProfitPayload
    docs/type/BrokerPendingClosePayload
    docs/type/BrokerPendingOpenPayload
    docs/type/BrokerScheduleCancelledPayload
    docs/type/BrokerScheduleOpenPayload
    docs/type/BrokerSchedulePingPayload
    docs/type/BrokerSignalClosePayload
    docs/type/BrokerSignalOpenPayload
    docs/type/BrokerSignalPendingPayload
    docs/type/BrokerTrailingStopPayload
    docs/type/BrokerTrailingTakePayload
    docs/type/BucketName
    docs/type/CacheFileFunction
    docs/type/CacheFileKeyArgs
    docs/type/CandleData
    docs/type/CandleInterval
    docs/type/ColumnConfig
    docs/type/Columns
    docs/type/Columns$1
    docs/type/Columns$2
    docs/type/Columns$3
    docs/type/Columns$4
    docs/type/Columns$5
    docs/type/Columns$6
    docs/type/Columns$7
    docs/type/Columns$8
    docs/type/Columns$9
    docs/type/Columns$a
    docs/type/Columns$b
    docs/type/CommitPayload
    docs/type/CronCallback
    docs/type/Dispatch
    docs/type/Dispatch$1
    docs/type/DropFirst
    docs/type/DropFirst$1
    docs/type/EntityId
    docs/type/Enum
    docs/type/ExchangeName
    docs/type/FrameInterval
    docs/type/FrameName
    docs/type/Function
    docs/type/Function$1
    docs/type/Function$2
    docs/type/GetStateFn
    docs/type/GlobalConfig
    docs/type/IBacktestLogicPrivateService
    docs/type/ICommitRow
    docs/type/ILiveLogicPrivateService
    docs/type/IntervalData
    docs/type/IntervalFileFunction
    docs/type/IntervalFileKeyArgs
    docs/type/IPublicAction
    docs/type/ISizingCalculateParams
    docs/type/ISizingParams
    docs/type/ISizingSchema
    docs/type/IStorageSignalRow
    docs/type/IStrategyBacktestResult
    docs/type/IStrategyTickResult
    docs/type/IWalkerLogicPrivateService
    docs/type/Keys
    docs/type/Keys$1
    docs/type/LogData
    docs/type/MarkdownName
    docs/type/MeasureData
    docs/type/MemoryData
    docs/type/MessageRole
    docs/type/MessageToolCall
    docs/type/NotificationData
    docs/type/NotificationModel
    docs/type/Num
    docs/type/PartialData
    docs/type/PartialLevel
    docs/type/PerformanceMetricType
    docs/type/PnlColumn
    docs/type/RecentData
    docs/type/ReportName
    docs/type/RestoreSnapshot
    docs/type/RiskData
    docs/type/RiskMap
    docs/type/RiskName
    docs/type/RiskRejection
    docs/type/RuntimeData
    docs/type/ScheduleData
    docs/type/SearchSettings
    docs/type/SessionData
    docs/type/SetStateFn
    docs/type/SignalData
    docs/type/SignalInterval
    docs/type/SignalNotificationPayload
    docs/type/SignalStateTuple
    docs/type/SignalSyncContract
    docs/type/SizingName
    docs/type/StateData
    docs/type/StorageData
    docs/type/StorageId
    docs/type/StrategyActionType
    docs/type/StrategyCancelReason
    docs/type/StrategyCloseReason
    docs/type/StrategyColumn
    docs/type/StrategyCommitContract
    docs/type/StrategyData
    docs/type/StrategyName
    docs/type/StrategyStatus
    docs/type/SyncActionType
    docs/type/TAction
    docs/type/TAction$1
    docs/type/TActionCtor
    docs/type/TActionSchema
    docs/type/TBacktestLogicPrivateService
    docs/type/TBacktestLogicPublicService
    docs/type/TBreakeven
    docs/type/TBrokerCtor
    docs/type/TDumpInstanceCtor
    docs/type/TExchange
    docs/type/TExchangeSchema
    docs/type/TExecutionContextService
    docs/type/TFrame
    docs/type/TFrameSchema
    docs/type/TLiveLogicPrivateService
    docs/type/TLiveLogicPublicService
    docs/type/TLogCtor
    docs/type/TMarkdownBase
    docs/type/TMarkdownBaseCtor
    docs/type/TMemoryInstance
    docs/type/TMemoryInstanceCtor
    docs/type/TNotificationUtilsCtor
    docs/type/TPartial
    docs/type/TPersistBase
    docs/type/TPersistBaseCtor
    docs/type/TPersistBreakevenInstanceCtor
    docs/type/TPersistCandleInstanceCtor
    docs/type/TPersistIntervalInstanceCtor
    docs/type/TPersistLogInstanceCtor
    docs/type/TPersistMeasureInstanceCtor
    docs/type/TPersistMemoryInstanceCtor
    docs/type/TPersistNotificationInstanceCtor
    docs/type/TPersistPartialInstanceCtor
    docs/type/TPersistRecentInstanceCtor
    docs/type/TPersistRiskInstanceCtor
    docs/type/TPersistScheduleInstanceCtor
    docs/type/TPersistSessionInstanceCtor
    docs/type/TPersistSignalInstanceCtor
    docs/type/TPersistStateInstanceCtor
    docs/type/TPersistStorageInstanceCtor
    docs/type/TPersistStrategyInstanceCtor
    docs/type/TRecentUtilsCtor
    docs/type/TReportBase
    docs/type/TReportBaseCtor
    docs/type/TRisk
    docs/type/TRisk$1
    docs/type/TRiskSchema
    docs/type/TSessionAdapter
    docs/type/TSessionInstanceCtor
    docs/type/TSizing
    docs/type/TSizing$1
    docs/type/TSizingSchema
    docs/type/TStateAdapter
    docs/type/TStateInstanceCtor
    docs/type/TStorageUtilsCtor
    docs/type/TStrategy
    docs/type/TStrategy$1
    docs/type/TStrategySchema
    docs/type/TWalkerLogicPrivateService
    docs/type/TWalkerLogicPublicService
    docs/type/TWalkerSchema
    docs/type/WalkerMetric
    docs/type/WalkerName

    example

    example/01_getting_started
    example/02_first_backtest
    example/03_understanding_signals
    example/04_live_trading
    example/05_risk_management
    example/06_ai_optimization
    example/07_llm_trading

    packages/front

    packages/front/readme

    packages/graph

    packages/graph/readme

    packages/mongo

    packages/mongo/readme

    packages/ollama

    packages/ollama/readme

    packages/pinets

    packages/pinets/readme

    packages/sidekick

    packages/sidekick/readme

    packages/signals

    packages/signals/readme

    private

    private/classes
    private/functions
    private/interfaces

    strategies

    strategies/apr_2024
    strategies/apr_2026
    strategies/dec_2025
    strategies/feb_2021
    strategies/feb_2026
    strategies/jan_2026
    strategies/mar_2026
    strategies/oct_2021
    strategies/overview
    +emitters | backtest-kit

    Module types

    Namespaces

    emitters

    Classes

    ActionBase
    BrokerBase
    MarkdownFileBase
    MarkdownFolderBase
    MemoryBacktestAdapter
    MemoryLiveAdapter
    Performance
    PersistBase
    PersistBreakevenInstance
    PersistCandleInstance
    PersistIntervalInstance
    PersistLogInstance
    PersistMeasureInstance
    PersistMemoryInstance
    PersistNotificationInstance
    PersistPartialInstance
    PersistRecentInstance
    PersistRiskInstance
    PersistScheduleInstance
    PersistSessionInstance
    PersistSignalInstance
    PersistStateInstance
    PersistStorageInstance
    PersistStrategyInstance
    Position
    ReportBase
    StateBacktestAdapter
    StateLiveAdapter

    Interfaces

    ActivateScheduledCommit
    ActivateScheduledCommitNotification
    ActivePingContract
    AfterEndContract
    AverageBuyCommit
    AverageBuyCommitNotification
    BacktestStatisticsModel
    BeforeStartContract
    BreakevenAvailableNotification
    BreakevenCommit
    BreakevenCommitNotification
    BreakevenContract
    BreakevenEvent
    BreakevenStatisticsModel
    CancelScheduledCommit
    CancelScheduledCommitNotification
    ClosePendingCommit
    ClosePendingCommitNotification
    ColumnModel
    CriticalErrorNotification
    CronEntry
    CronHandle
    DoneContract
    HeatmapStatisticsModel
    HighestProfitContract
    HighestProfitEvent
    HighestProfitStatisticsModel
    IActionSchema
    IActivateScheduledCommitRow
    IAggregatedTradeData
    IBidData
    IBreakevenCommitRow
    IBroker
    ICandleData
    IdlePingContract
    IDumpContext
    IDumpInstance
    IExchangeSchema
    IFrameSchema
    IHeatmapRow
    ILog
    ILogEntry
    ILogger
    IMarkdownDumpOptions
    IMemoryInstance
    InfoErrorNotification
    INotificationUtils
    IOrderBookData
    IPartialLossCommitRow
    IPartialProfitCommitRow
    IPersistBase
    IPersistBreakevenInstance
    IPersistCandleInstance
    IPersistIntervalInstance
    IPersistLogInstance
    IPersistMeasureInstance
    IPersistMemoryInstance
    IPersistNotificationInstance
    IPersistPartialInstance
    IPersistRecentInstance
    IPersistRiskInstance
    IPersistScheduleInstance
    IPersistSessionInstance
    IPersistSignalInstance
    IPersistStateInstance
    IPersistStorageInstance
    IPersistStrategyInstance
    IPositionSizeATRParams
    IPositionSizeFixedPercentageParams
    IPositionSizeKellyParams
    IPublicCandleData
    IPublicSignalRow
    IRecentUtils
    IReportDumpOptions
    IRiskActivePosition
    IRiskCheckArgs
    IRiskSchema
    IRiskSignalRow
    IRiskValidation
    IRiskValidationFn
    IRiskValidationPayload
    IRuntimeInfo
    IRuntimeRange
    IScheduledSignalCancelRow
    IScheduledSignalRow
    ISessionInstance
    ISignalDto
    ISignalIntervalDto
    ISignalRow
    ISizingCalculateParamsATR
    ISizingCalculateParamsFixedPercentage
    ISizingCalculateParamsKelly
    ISizingParamsATR
    ISizingParamsFixedPercentage
    ISizingParamsKelly
    ISizingSchemaATR
    ISizingSchemaFixedPercentage
    ISizingSchemaKelly
    IStateInstance
    IStorageUtils
    IStrategyPnL
    IStrategyResult
    IStrategySchema
    IStrategyTickResultActive
    IStrategyTickResultCancelled
    IStrategyTickResultClosed
    IStrategyTickResultIdle
    IStrategyTickResultOpened
    IStrategyTickResultScheduled
    IStrategyTickResultWaiting
    ITrailingStopCommitRow
    ITrailingTakeCommitRow
    IWalkerResults
    IWalkerSchema
    IWalkerStrategyResult
    LiveStatisticsModel
    MaxDrawdownContract
    MaxDrawdownEvent
    MaxDrawdownStatisticsModel
    MessageModel
    MetricStats
    PartialEvent
    PartialLossAvailableNotification
    PartialLossCommit
    PartialLossCommitNotification
    PartialLossContract
    PartialProfitAvailableNotification
    PartialProfitCommit
    PartialProfitCommitNotification
    PartialProfitContract
    PartialStatisticsModel
    PerformanceContract
    PerformanceStatisticsModel
    ProgressBacktestContract
    ProgressWalkerContract
    RiskContract
    RiskEvent
    RiskRejectionNotification
    RiskStatisticsModel
    ScheduledEvent
    SchedulePingContract
    ScheduleStatisticsModel
    SignalCancelledNotification
    SignalCloseContract
    SignalClosedNotification
    SignalInfoContract
    SignalInfoNotification
    SignalOpenContract
    SignalOpenedNotification
    SignalPingContract
    SignalScheduledNotification
    SignalSyncCloseNotification
    SignalSyncOpenNotification
    StrategyEvent
    StrategyStatisticsModel
    SyncEvent
    SyncStatisticsModel
    TickEvent
    TrailingStopCommit
    TrailingStopCommitNotification
    TrailingTakeCommit
    TrailingTakeCommitNotification
    ValidationErrorNotification
    WalkerCompleteContract
    WalkerContract
    WalkerSignalData
    WalkerStatisticsModel

    Type Aliases

    BreakevenData
    BrokerAverageBuyPayload
    BrokerBreakevenPayload
    BrokerPartialLossPayload
    BrokerPartialProfitPayload
    BrokerSignalClosePayload
    BrokerSignalOpenPayload
    BrokerSignalPendingPayload
    BrokerTrailingStopPayload
    BrokerTrailingTakePayload
    CandleData
    CandleInterval
    ColumnConfig
    CommitPayload
    CronCallback
    EntityId
    FrameInterval
    GlobalConfig
    ICommitRow
    IntervalData
    IPublicAction
    ISizingCalculateParams
    ISizingParams
    ISizingSchema
    IStorageSignalRow
    IStrategyTickResult
    LogData
    MarkdownName
    MeasureData
    MemoryData
    MessageRole
    MessageToolCall
    NotificationData
    NotificationModel
    PartialData
    PerformanceMetricType
    RecentData
    ReportName
    RiskData
    RuntimeData
    ScheduleData
    SessionData
    SignalData
    SignalInterval
    SignalSyncContract
    StateData
    StorageData
    StrategyActionType
    StrategyCancelReason
    StrategyCloseReason
    StrategyCommitContract
    StrategyData
    StrategyStatus
    TBrokerCtor
    TDumpInstanceCtor
    TLogCtor
    TMarkdownBase
    TMemoryInstanceCtor
    TNotificationUtilsCtor
    TPersistBase
    TPersistBaseCtor
    TPersistBreakevenInstanceCtor
    TPersistCandleInstanceCtor
    TPersistIntervalInstanceCtor
    TPersistLogInstanceCtor
    TPersistMeasureInstanceCtor
    TPersistMemoryInstanceCtor
    TPersistNotificationInstanceCtor
    TPersistPartialInstanceCtor
    TPersistRecentInstanceCtor
    TPersistRiskInstanceCtor
    TPersistScheduleInstanceCtor
    TPersistSessionInstanceCtor
    TPersistSignalInstanceCtor
    TPersistStateInstanceCtor
    TPersistStorageInstanceCtor
    TPersistStrategyInstanceCtor
    TRecentUtilsCtor
    TReportBase
    TSessionInstanceCtor
    TStateInstanceCtor
    TStorageUtilsCtor
    WalkerMetric

    Variables

    Backtest
    Breakeven
    Broker
    Cache
    Constant
    Cron
    Dump
    Exchange
    ExecutionContextService
    Heat
    HighestProfit
    Interval
    lib
    Live
    Log
    Lookup
    Markdown
    MarkdownWriter
    MaxDrawdown
    Memory
    MemoryBacktest
    MemoryLive
    MethodContextService
    Notification
    NotificationBacktest
    NotificationLive
    Partial
    PersistBreakevenAdapter
    PersistCandleAdapter
    PersistIntervalAdapter
    PersistLogAdapter
    PersistMeasureAdapter
    PersistMemoryAdapter
    PersistNotificationAdapter
    PersistPartialAdapter
    PersistRecentAdapter
    PersistRiskAdapter
    PersistScheduleAdapter
    PersistSessionAdapter
    PersistSignalAdapter
    PersistStateAdapter
    PersistStorageAdapter
    PersistStrategyAdapter
    PositionSize
    Recent
    RecentBacktest
    RecentLive
    Reflect
    Report
    ReportWriter
    Risk
    Schedule
    Session
    SessionBacktest
    SessionLive
    State
    StateBacktest
    StateLive
    Storage
    StorageBacktest
    StorageLive
    Strategy
    Sync
    System
    Walker

    Functions

    addActionSchema
    addExchangeSchema
    addFrameSchema
    addRiskSchema
    addSizingSchema
    addStrategySchema
    addWalkerSchema
    alignToInterval
    beginContext
    beginTime
    cacheCandles
    checkCandles
    commitActivateScheduled
    commitAverageBuy
    commitBreakeven
    commitCancelScheduled
    commitClosePending
    commitCreateSignal
    commitPartialLoss
    commitPartialLossCost
    commitPartialProfit
    commitPartialProfitCost
    commitSignalNotify
    commitTrailingStop
    commitTrailingStopCost
    commitTrailingTake
    commitTrailingTakeCost
    createSignalState
    dumpAgentAnswer
    dumpError
    dumpJson
    dumpRecord
    dumpTable
    dumpText
    formatPrice
    formatQuantity
    get
    getActionSchema
    getAggregatedTrades
    getAveragePrice
    getBacktestTimeframe
    getBreakeven
    getCandles
    getClosePrice
    getColumns
    getConfig
    getContext
    getDate
    getDefaultColumns
    getDefaultConfig
    getEffectivePriceOpen
    getExchangeSchema
    getFrameSchema
    getLatestSignal
    getMaxDrawdownDistancePnlCost
    getMaxDrawdownDistancePnlPercentage
    getMinutesSinceLatestSignalCreated
    getMode
    getNextCandles
    getOrderBook
    getPendingSignal
    getPositionActiveMinutes
    getPositionCountdownMinutes
    getPositionDrawdownMinutes
    getPositionEffectivePrice
    getPositionEntries
    getPositionEntryOverlap
    getPositionEstimateMinutes
    getPositionHighestMaxDrawdownPnlCost
    getPositionHighestMaxDrawdownPnlPercentage
    getPositionHighestPnlCost
    getPositionHighestPnlPercentage
    getPositionHighestProfitBreakeven
    getPositionHighestProfitDistancePnlCost
    getPositionHighestProfitDistancePnlPercentage
    getPositionHighestProfitMinutes
    getPositionHighestProfitPrice
    getPositionHighestProfitTimestamp
    getPositionInvestedCost
    getPositionInvestedCount
    getPositionLevels
    getPositionMaxDrawdownMinutes
    getPositionMaxDrawdownPnlCost
    getPositionMaxDrawdownPnlPercentage
    getPositionMaxDrawdownPrice
    getPositionMaxDrawdownTimestamp
    getPositionPartialOverlap
    getPositionPartials
    getPositionPnlCost
    getPositionPnlPercent
    getPositionWaitingMinutes
    getPriceScale
    getRawCandles
    getRiskSchema
    getRuntimeInfo
    getScheduledSignal
    getSessionData
    getSignalState
    getSizingSchema
    getStrategySchema
    getStrategyStatus
    getSymbol
    getTimestamp
    getTotalClosed
    getTotalCostClosed
    getTotalPercentClosed
    getWalkerSchema
    hasNoPendingSignal
    hasNoScheduledSignal
    hasTradeContext
    intervalStepMs
    investedCostToPercent
    listenActivePing
    listenActivePingOnce
    listenAfterEnd
    listenAfterEndOnce
    listenBacktestProgress
    listenBeforeStart
    listenBeforeStartOnce
    listenBreakevenAvailable
    listenBreakevenAvailableOnce
    listenDoneBacktest
    listenDoneBacktestOnce
    listenDoneLive
    listenDoneLiveOnce
    listenDoneWalker
    listenDoneWalkerOnce
    listenError
    listenExit
    listenHighestProfit
    listenHighestProfitOnce
    listenIdlePing
    listenIdlePingOnce
    listenMaxDrawdown
    listenMaxDrawdownOnce
    listenPartialLossAvailable
    listenPartialLossAvailableOnce
    listenPartialProfitAvailable
    listenPartialProfitAvailableOnce
    listenPerformance
    listenRisk
    listenRiskOnce
    listenSchedulePing
    listenSchedulePingOnce
    listenSignal
    listenSignalBacktest
    listenSignalBacktestOnce
    listenSignalLive
    listenSignalLiveOnce
    listenSignalNotify
    listenSignalNotifyOnce
    listenSignalOnce
    listenStrategyCommit
    listenStrategyCommitOnce
    listenSync
    listenSyncOnce
    listenValidation
    listenWalker
    listenWalkerComplete
    listenWalkerOnce
    listenWalkerProgress
    listExchangeSchema
    listFrameSchema
    listMemory
    listRiskSchema
    listSizingSchema
    listStrategySchema
    listWalkerSchema
    overrideActionSchema
    overrideExchangeSchema
    overrideFrameSchema
    overrideRiskSchema
    overrideSizingSchema
    overrideStrategySchema
    overrideWalkerSchema
    parseArgs
    percentDiff
    percentToCloseCost
    percentValue
    readMemory
    removeMemory
    roundTicks
    runInMockContext
    searchMemory
    set
    setColumns
    setConfig
    setLogger
    setSessionData
    setSignalState
    shutdown
    slPercentShiftToPrice
    slPriceToPercentShift
    stopStrategy
    toPlainString
    toProfitLossDto
    tpPercentShiftToPrice
    tpPriceToPercentShift
    validate
    validateCandles
    validateCommonSignal
    validatePendingSignal
    validateScheduledSignal
    validateSignal
    waitForCandle
    waitForReady
    warmCandles
    writeMemory
    +types | backtest-kit

    Module types

    Namespaces

    emitters

    Classes

    ActionBase
    BrokerBase
    MarkdownFileBase
    MarkdownFolderBase
    MemoryBacktestAdapter
    MemoryLiveAdapter
    Performance
    PersistBase
    PersistBreakevenInstance
    PersistCandleInstance
    PersistIntervalInstance
    PersistLogInstance
    PersistMeasureInstance
    PersistMemoryInstance
    PersistNotificationInstance
    PersistPartialInstance
    PersistRecentInstance
    PersistRiskInstance
    PersistScheduleInstance
    PersistSessionInstance
    PersistSignalInstance
    PersistStateInstance
    PersistStorageInstance
    PersistStrategyInstance
    Position
    ReportBase
    StateBacktestAdapter
    StateLiveAdapter

    Interfaces

    ActivateScheduledCommit
    ActivateScheduledCommitNotification
    ActivePingContract
    AfterEndContract
    AverageBuyCommit
    AverageBuyCommitNotification
    BacktestStatisticsModel
    BeforeStartContract
    BreakevenAvailableNotification
    BreakevenCommit
    BreakevenCommitNotification
    BreakevenContract
    BreakevenEvent
    BreakevenStatisticsModel
    CancelScheduledCommit
    CancelScheduledCommitNotification
    ClosePendingCommit
    ClosePendingCommitNotification
    ColumnModel
    CriticalErrorNotification
    CronEntry
    CronHandle
    DoneContract
    HeatmapStatisticsModel
    HighestProfitContract
    HighestProfitEvent
    HighestProfitStatisticsModel
    IActionSchema
    IActivateScheduledCommitRow
    IAggregatedTradeData
    IBidData
    IBreakevenCommitRow
    IBroker
    ICandleData
    IdlePingContract
    IDumpContext
    IDumpInstance
    IExchangeSchema
    IFrameSchema
    IHeatmapRow
    ILog
    ILogEntry
    ILogger
    IMarkdownDumpOptions
    IMemoryInstance
    InfoErrorNotification
    INotificationUtils
    IOrderBookData
    IPartialLossCommitRow
    IPartialProfitCommitRow
    IPersistBase
    IPersistBreakevenInstance
    IPersistCandleInstance
    IPersistIntervalInstance
    IPersistLogInstance
    IPersistMeasureInstance
    IPersistMemoryInstance
    IPersistNotificationInstance
    IPersistPartialInstance
    IPersistRecentInstance
    IPersistRiskInstance
    IPersistScheduleInstance
    IPersistSessionInstance
    IPersistSignalInstance
    IPersistStateInstance
    IPersistStorageInstance
    IPersistStrategyInstance
    IPositionSizeATRParams
    IPositionSizeFixedPercentageParams
    IPositionSizeKellyParams
    IPublicCandleData
    IPublicSignalRow
    IRecentUtils
    IReportDumpOptions
    IRiskActivePosition
    IRiskCheckArgs
    IRiskSchema
    IRiskSignalRow
    IRiskValidation
    IRiskValidationFn
    IRiskValidationPayload
    IRuntimeInfo
    IRuntimeRange
    IScheduledSignalCancelRow
    IScheduledSignalRow
    ISessionInstance
    ISignalDto
    ISignalIntervalDto
    ISignalRow
    ISizingCalculateParamsATR
    ISizingCalculateParamsFixedPercentage
    ISizingCalculateParamsKelly
    ISizingParamsATR
    ISizingParamsFixedPercentage
    ISizingParamsKelly
    ISizingSchemaATR
    ISizingSchemaFixedPercentage
    ISizingSchemaKelly
    IStateInstance
    IStorageUtils
    IStrategyPnL
    IStrategyResult
    IStrategySchema
    IStrategyTickResultActive
    IStrategyTickResultCancelled
    IStrategyTickResultClosed
    IStrategyTickResultIdle
    IStrategyTickResultOpened
    IStrategyTickResultScheduled
    IStrategyTickResultWaiting
    ITrailingStopCommitRow
    ITrailingTakeCommitRow
    IWalkerResults
    IWalkerSchema
    IWalkerStrategyResult
    LiveStatisticsModel
    MaxDrawdownContract
    MaxDrawdownEvent
    MaxDrawdownStatisticsModel
    MessageModel
    MetricStats
    PartialEvent
    PartialLossAvailableNotification
    PartialLossCommit
    PartialLossCommitNotification
    PartialLossContract
    PartialProfitAvailableNotification
    PartialProfitCommit
    PartialProfitCommitNotification
    PartialProfitContract
    PartialStatisticsModel
    PerformanceContract
    PerformanceStatisticsModel
    ProgressBacktestContract
    ProgressWalkerContract
    RiskContract
    RiskEvent
    RiskRejectionNotification
    RiskStatisticsModel
    ScheduledEvent
    ScheduleEventContract
    SchedulePingContract
    ScheduleStatisticsModel
    SignalCancelledNotification
    SignalCloseContract
    SignalClosedNotification
    SignalEventContract
    SignalInfoContract
    SignalInfoNotification
    SignalOpenContract
    SignalOpenedNotification
    SignalPingContract
    SignalScheduledNotification
    SignalSyncCloseNotification
    SignalSyncOpenNotification
    StrategyEvent
    StrategyStatisticsModel
    SyncEvent
    SyncStatisticsModel
    TickEvent
    TrailingStopCommit
    TrailingStopCommitNotification
    TrailingTakeCommit
    TrailingTakeCommitNotification
    ValidationErrorNotification
    WalkerCompleteContract
    WalkerContract
    WalkerSignalData
    WalkerStatisticsModel

    Type Aliases

    BreakevenData
    BrokerActivePingPayload
    BrokerAverageBuyPayload
    BrokerBreakevenPayload
    BrokerIdlePingPayload
    BrokerPartialLossPayload
    BrokerPartialProfitPayload
    BrokerPendingClosePayload
    BrokerPendingOpenPayload
    BrokerScheduleCancelledPayload
    BrokerScheduleOpenPayload
    BrokerSchedulePingPayload
    BrokerSignalClosePayload
    BrokerSignalOpenPayload
    BrokerSignalPendingPayload
    BrokerTrailingStopPayload
    BrokerTrailingTakePayload
    CandleData
    CandleInterval
    ColumnConfig
    CommitPayload
    CronCallback
    EntityId
    FrameInterval
    GlobalConfig
    ICommitRow
    IntervalData
    IPublicAction
    ISizingCalculateParams
    ISizingParams
    ISizingSchema
    IStorageSignalRow
    IStrategyTickResult
    LogData
    MarkdownName
    MeasureData
    MemoryData
    MessageRole
    MessageToolCall
    NotificationData
    NotificationModel
    PartialData
    PerformanceMetricType
    RecentData
    ReportName
    RiskData
    RuntimeData
    ScheduleData
    SessionData
    SignalData
    SignalInterval
    SignalSyncContract
    StateData
    StorageData
    StrategyActionType
    StrategyCancelReason
    StrategyCloseReason
    StrategyCommitContract
    StrategyData
    StrategyStatus
    TBrokerCtor
    TDumpInstanceCtor
    TLogCtor
    TMarkdownBase
    TMemoryInstanceCtor
    TNotificationUtilsCtor
    TPersistBase
    TPersistBaseCtor
    TPersistBreakevenInstanceCtor
    TPersistCandleInstanceCtor
    TPersistIntervalInstanceCtor
    TPersistLogInstanceCtor
    TPersistMeasureInstanceCtor
    TPersistMemoryInstanceCtor
    TPersistNotificationInstanceCtor
    TPersistPartialInstanceCtor
    TPersistRecentInstanceCtor
    TPersistRiskInstanceCtor
    TPersistScheduleInstanceCtor
    TPersistSessionInstanceCtor
    TPersistSignalInstanceCtor
    TPersistStateInstanceCtor
    TPersistStorageInstanceCtor
    TPersistStrategyInstanceCtor
    TRecentUtilsCtor
    TReportBase
    TSessionInstanceCtor
    TStateInstanceCtor
    TStorageUtilsCtor
    WalkerMetric

    Variables

    Backtest
    Breakeven
    Broker
    Cache
    Constant
    Cron
    Dump
    Exchange
    ExecutionContextService
    Heat
    HighestProfit
    Interval
    lib
    Live
    Log
    Lookup
    Markdown
    MarkdownWriter
    MaxDrawdown
    Memory
    MemoryBacktest
    MemoryLive
    MethodContextService
    Notification
    NotificationBacktest
    NotificationLive
    Partial
    PersistBreakevenAdapter
    PersistCandleAdapter
    PersistIntervalAdapter
    PersistLogAdapter
    PersistMeasureAdapter
    PersistMemoryAdapter
    PersistNotificationAdapter
    PersistPartialAdapter
    PersistRecentAdapter
    PersistRiskAdapter
    PersistScheduleAdapter
    PersistSessionAdapter
    PersistSignalAdapter
    PersistStateAdapter
    PersistStorageAdapter
    PersistStrategyAdapter
    PositionSize
    Recent
    RecentBacktest
    RecentLive
    Reflect
    Report
    ReportWriter
    Risk
    Schedule
    Session
    SessionBacktest
    SessionLive
    State
    StateBacktest
    StateLive
    Storage
    StorageBacktest
    StorageLive
    Strategy
    Sync
    System
    Walker

    Functions

    addActionSchema
    addExchangeSchema
    addFrameSchema
    addRiskSchema
    addSizingSchema
    addStrategySchema
    addWalkerSchema
    alignToInterval
    beginContext
    beginTime
    cacheCandles
    checkCandles
    commitActivateScheduled
    commitAverageBuy
    commitBreakeven
    commitCancelScheduled
    commitClosePending
    commitCreateSignal
    commitCreateStopLoss
    commitCreateTakeProfit
    commitPartialLoss
    commitPartialLossCost
    commitPartialProfit
    commitPartialProfitCost
    commitSignalNotify
    commitTrailingStop
    commitTrailingStopCost
    commitTrailingTake
    commitTrailingTakeCost
    createSignalState
    dumpAgentAnswer
    dumpError
    dumpJson
    dumpRecord
    dumpTable
    dumpText
    formatPrice
    formatQuantity
    get
    getActionSchema
    getAggregatedTrades
    getAveragePrice
    getBacktestTimeframe
    getBreakeven
    getCandles
    getClosePrice
    getColumns
    getConfig
    getContext
    getDate
    getDefaultColumns
    getDefaultConfig
    getEffectivePriceOpen
    getExchangeSchema
    getFrameSchema
    getLatestSignal
    getMaxDrawdownDistancePnlCost
    getMaxDrawdownDistancePnlPercentage
    getMinutesSinceLatestSignalCreated
    getMode
    getNextCandles
    getOrderBook
    getPendingSignal
    getPositionActiveMinutes
    getPositionCountdownMinutes
    getPositionDrawdownMinutes
    getPositionEffectivePrice
    getPositionEntries
    getPositionEntryOverlap
    getPositionEstimateMinutes
    getPositionHighestMaxDrawdownPnlCost
    getPositionHighestMaxDrawdownPnlPercentage
    getPositionHighestPnlCost
    getPositionHighestPnlPercentage
    getPositionHighestProfitBreakeven
    getPositionHighestProfitDistancePnlCost
    getPositionHighestProfitDistancePnlPercentage
    getPositionHighestProfitMinutes
    getPositionHighestProfitPrice
    getPositionHighestProfitTimestamp
    getPositionInvestedCost
    getPositionInvestedCount
    getPositionLevels
    getPositionMaxDrawdownMinutes
    getPositionMaxDrawdownPnlCost
    getPositionMaxDrawdownPnlPercentage
    getPositionMaxDrawdownPrice
    getPositionMaxDrawdownTimestamp
    getPositionPartialOverlap
    getPositionPartials
    getPositionPnlCost
    getPositionPnlPercent
    getPositionWaitingMinutes
    getPriceScale
    getRawCandles
    getRiskSchema
    getRuntimeInfo
    getScheduledSignal
    getSessionData
    getSignalState
    getSizingSchema
    getStrategySchema
    getStrategyStatus
    getSymbol
    getTimestamp
    getTotalClosed
    getTotalCostClosed
    getTotalPercentClosed
    getWalkerSchema
    hasNoPendingSignal
    hasNoScheduledSignal
    hasTradeContext
    intervalStepMs
    investedCostToPercent
    listenActivePing
    listenActivePingOnce
    listenAfterEnd
    listenAfterEndOnce
    listenBacktestProgress
    listenBeforeStart
    listenBeforeStartOnce
    listenBreakevenAvailable
    listenBreakevenAvailableOnce
    listenDoneBacktest
    listenDoneBacktestOnce
    listenDoneLive
    listenDoneLiveOnce
    listenDoneWalker
    listenDoneWalkerOnce
    listenError
    listenExit
    listenHighestProfit
    listenHighestProfitOnce
    listenIdlePing
    listenIdlePingOnce
    listenMaxDrawdown
    listenMaxDrawdownOnce
    listenPartialLossAvailable
    listenPartialLossAvailableOnce
    listenPartialProfitAvailable
    listenPartialProfitAvailableOnce
    listenPerformance
    listenRisk
    listenRiskOnce
    listenScheduleEvent
    listenScheduleEventOnce
    listenSchedulePing
    listenSchedulePingOnce
    listenSignal
    listenSignalBacktest
    listenSignalBacktestOnce
    listenSignalEvent
    listenSignalEventOnce
    listenSignalLive
    listenSignalLiveOnce
    listenSignalNotify
    listenSignalNotifyOnce
    listenSignalOnce
    listenStrategyCommit
    listenStrategyCommitOnce
    listenSync
    listenSyncOnce
    listenValidation
    listenWalker
    listenWalkerComplete
    listenWalkerOnce
    listenWalkerProgress
    listExchangeSchema
    listFrameSchema
    listMemory
    listRiskSchema
    listSizingSchema
    listStrategySchema
    listWalkerSchema
    overrideActionSchema
    overrideExchangeSchema
    overrideFrameSchema
    overrideRiskSchema
    overrideSizingSchema
    overrideStrategySchema
    overrideWalkerSchema
    parseArgs
    percentDiff
    percentToCloseCost
    percentValue
    readMemory
    removeMemory
    roundTicks
    runInMockContext
    searchMemory
    set
    setColumns
    setConfig
    setLogger
    setSessionData
    setSignalState
    shutdown
    slPercentShiftToPrice
    slPriceToPercentShift
    stopStrategy
    toPlainString
    toProfitLossDto
    tpPercentShiftToPrice
    tpPriceToPercentShift
    validate
    validateCandles
    validateCommonSignal
    validatePendingSignal
    validateScheduledSignal
    validateSignal
    waitForCandle
    waitForReady
    warmCandles
    writeMemory

    Type Alias BreakevenData

    BreakevenData: Record<string, IBreakevenData>

    Type for persisted breakeven data. Stores breakeven state (reached flag) for each signal ID.

    -
    +

    Type Alias BrokerActivePingPayload

    BrokerActivePingPayload: {
        backtest: boolean;
        context: {
            exchangeName: ExchangeName;
            frameName?: FrameName;
            strategyName: StrategyName;
        };
        currentPrice: number;
        pnl: IStrategyPnL;
        position: "long"
        | "short";
        priceOpen: number;
        priceStopLoss: number;
        priceTakeProfit: number;
        signalId: string;
        symbol: string;
    }

    Payload for the active-ping broker event.

    +

    Emitted automatically via activePingSubject on every live tick while a pending (open) signal is +monitored. Forwarded to the registered IBroker adapter via onSignalActivePing. Purely +informational — unlike onOrderCheck a throw here does NOT close the position.

    +

    Type declaration

    • backtest: boolean

      true when called during a backtest run — adapter should skip exchange calls

      +
    • context: {
          exchangeName: ExchangeName;
          frameName?: FrameName;
          strategyName: StrategyName;
      }

      Strategy/exchange/frame routing context

      +
    • currentPrice: number

      Market price at the moment of the ping

      +
    • pnl: IStrategyPnL

      Unrealized PnL of the open position at the moment of the ping

      +
    • position: "long" | "short"

      Position direction

      +
    • priceOpen: number

      Effective entry price (may differ from priceOpen after DCA averaging)

      +
    • priceStopLoss: number

      Effective stop-loss price at the moment of the ping

      +
    • priceTakeProfit: number

      Effective take-profit price at the moment of the ping

      +
    • signalId: string

      Unique signal identifier (UUID v4) of the monitored position

      +
    • symbol: string

      Trading pair symbol, e.g. "BTCUSDT"

      +
    const payload: BrokerActivePingPayload = {
    symbol: "BTCUSDT",
    position: "long",
    currentPrice: 50500,
    priceOpen: 50000,
    priceTakeProfit: 55000,
    priceStopLoss: 48000,
    context: { strategyName: "my-strategy", exchangeName: "binance", frameName: "1h" },
    backtest: false,
    }; +
    + +
    + + + + + + + + + diff --git a/types/types.BrokerAverageBuyPayload.html b/types/types.BrokerAverageBuyPayload.html index 3ec98913b688dac4ff329a1db3c2c58dd292fca3..851016b67edf84009f80d1cad4bbc8caab1e5002 100644 --- a/types/types.BrokerAverageBuyPayload.html +++ b/types/types.BrokerAverageBuyPayload.html @@ -14,7 +14,7 @@ Called explicitly after all validations pass, before strategyCoreService.a
    const payload: BrokerAverageBuyPayload = {
    symbol: "BTCUSDT",
    currentPrice: 42000,
    cost: 100,
    context: { strategyName: "my-strategy", exchangeName: "binance", frameName: "1h" },
    backtest: false,
    };
    -
    +

    Type Alias BrokerIdlePingPayload

    BrokerIdlePingPayload: {
        backtest: boolean;
        context: {
            exchangeName: ExchangeName;
            frameName?: FrameName;
            strategyName: StrategyName;
        };
        currentPrice: number;
        symbol: string;
    }

    Payload for the idle-ping broker event.

    +

    Emitted automatically via idlePingSubject on every live tick while the strategy has no pending or +scheduled signal. Forwarded to the registered IBroker adapter via onSignalIdlePing. Purely +informational — carries no signal because none is active.

    +

    Type declaration

    • backtest: boolean

      true when called during a backtest run — adapter should skip exchange calls

      +
    • context: {
          exchangeName: ExchangeName;
          frameName?: FrameName;
          strategyName: StrategyName;
      }

      Strategy/exchange/frame routing context

      +
    • currentPrice: number

      Market price at the moment of the ping

      +
    • symbol: string

      Trading pair symbol, e.g. "BTCUSDT"

      +
    const payload: BrokerIdlePingPayload = {
    symbol: "BTCUSDT",
    currentPrice: 50500,
    context: { strategyName: "my-strategy", exchangeName: "binance", frameName: "1h" },
    backtest: false,
    }; +
    + +
    + + + + + + + + + diff --git a/types/types.BrokerPartialLossPayload.html b/types/types.BrokerPartialLossPayload.html index 565ed3eb5a2c806593fb0751786ee3f16accc6b9..55df661d065d66ca443d1a61cfefe69ea0b1bf5f 100644 --- a/types/types.BrokerPartialLossPayload.html +++ b/types/types.BrokerPartialLossPayload.html @@ -14,7 +14,7 @@ Called explicitly after all validations pass, before strategyCoreService.p
    const payload: BrokerPartialLossPayload = {
    symbol: "BTCUSDT",
    percentToClose: 40,
    cost: 40,
    currentPrice: 48500,
    context: { strategyName: "my-strategy", exchangeName: "binance", frameName: "1h" },
    backtest: false,
    };
    -
    +

    Type Alias BrokerPendingClosePayload

    BrokerPendingClosePayload: {
        backtest: boolean;
        closeReason?: StrategyCloseReason;
        context: {
            exchangeName: ExchangeName;
            frameName?: FrameName;
            strategyName: StrategyName;
        };
        currentPrice: number;
        position: "long"
        | "short";
        priceOpen: number;
        priceStopLoss: number;
        priceTakeProfit: number;
        signalId: string;
        symbol: string;
    }

    Payload for the pending-signal-close broker event.

    +

    Emitted automatically via signalEventSubject (action "closed") when a pending position is closed. +Forwarded to the registered IBroker adapter via onSignalPendingClose. The closeReason +distinguishes take_profit / stop_loss / time_expired / user-close / broker fill / order gone.

    +

    Type declaration

    • backtest: boolean

      true when called during a backtest run — adapter should skip exchange calls

      +
    • OptionalcloseReason?: StrategyCloseReason

      Why the position closed: "take_profit" / "stop_loss" / "time_expired" / "closed"

      +
    • context: {
          exchangeName: ExchangeName;
          frameName?: FrameName;
          strategyName: StrategyName;
      }

      Strategy/exchange/frame routing context

      +
    • currentPrice: number

      Market price at the moment of close

      +
    • position: "long" | "short"

      Position direction

      +
    • priceOpen: number

      Effective entry price of the closed position

      +
    • priceStopLoss: number

      Effective stop-loss price of the closed position

      +
    • priceTakeProfit: number

      Effective take-profit price of the closed position

      +
    • signalId: string

      Unique signal identifier (UUID v4) of the closed position

      +
    • symbol: string

      Trading pair symbol, e.g. "BTCUSDT"

      +
    const payload: BrokerPendingClosePayload = {
    symbol: "BTCUSDT",
    position: "long",
    currentPrice: 55000,
    priceOpen: 50000,
    priceTakeProfit: 55000,
    priceStopLoss: 48000,
    closeReason: "take_profit",
    context: { strategyName: "my-strategy", exchangeName: "binance", frameName: "1h" },
    backtest: false,
    }; +
    + +
    + + + + + + + + + diff --git a/types/types.BrokerPendingOpenPayload.html b/types/types.BrokerPendingOpenPayload.html new file mode 100644 index 0000000000000000000000000000000000000000..e7b9240581169a503fdce335f4e78c94e659ad93 --- /dev/null +++ b/types/types.BrokerPendingOpenPayload.html @@ -0,0 +1,41 @@ +BrokerPendingOpenPayload | backtest-kit

    Type Alias BrokerPendingOpenPayload

    BrokerPendingOpenPayload: {
        backtest: boolean;
        context: {
            exchangeName: ExchangeName;
            frameName?: FrameName;
            strategyName: StrategyName;
        };
        currentPrice: number;
        position: "long"
        | "short";
        priceOpen: number;
        priceStopLoss: number;
        priceTakeProfit: number;
        signalId: string;
        symbol: string;
    }

    Payload for the pending-signal-open broker event.

    +

    Emitted automatically via signalEventSubject (action "opened") when a pending position is opened +(new signal / immediate entry / scheduled or user activation). Forwarded to the registered IBroker +adapter via onSignalPendingOpen.

    +

    Type declaration

    • backtest: boolean

      true when called during a backtest run — adapter should skip exchange calls

      +
    • context: {
          exchangeName: ExchangeName;
          frameName?: FrameName;
          strategyName: StrategyName;
      }

      Strategy/exchange/frame routing context

      +
    • currentPrice: number

      Effective entry price at the moment the position opened

      +
    • position: "long" | "short"

      Position direction

      +
    • priceOpen: number

      Effective entry price (may differ from currentPrice after DCA averaging)

      +
    • priceStopLoss: number

      Stop-loss price configured for the position

      +
    • priceTakeProfit: number

      Take-profit price configured for the position

      +
    • signalId: string

      Unique signal identifier (UUID v4) of the opened position

      +
    • symbol: string

      Trading pair symbol, e.g. "BTCUSDT"

      +
    const payload: BrokerPendingOpenPayload = {
    symbol: "BTCUSDT",
    position: "long",
    currentPrice: 50000,
    priceOpen: 50000,
    priceTakeProfit: 55000,
    priceStopLoss: 48000,
    context: { strategyName: "my-strategy", exchangeName: "binance", frameName: "1h" },
    backtest: false,
    }; +
    + +
    + + + + + + + + + diff --git a/types/types.BrokerScheduleCancelledPayload.html b/types/types.BrokerScheduleCancelledPayload.html new file mode 100644 index 0000000000000000000000000000000000000000..d5b685946f49cce996363c32aa83c1dd93f88d3b --- /dev/null +++ b/types/types.BrokerScheduleCancelledPayload.html @@ -0,0 +1,42 @@ +BrokerScheduleCancelledPayload | backtest-kit

    Type Alias BrokerScheduleCancelledPayload

    BrokerScheduleCancelledPayload: {
        backtest: boolean;
        context: {
            exchangeName: ExchangeName;
            frameName?: FrameName;
            strategyName: StrategyName;
        };
        currentPrice: number;
        position: "long"
        | "short";
        priceOpen: number;
        priceStopLoss: number;
        priceTakeProfit: number;
        reason?: StrategyCancelReason;
        signalId: string;
        symbol: string;
    }

    Payload for the scheduled-signal-cancelled broker event.

    +

    Emitted automatically via scheduleEventSubject (action "cancelled") when a scheduled signal is +removed before it ever activated. Forwarded to the registered IBroker adapter via +onSignalScheduleCancelled. The reason distinguishes timeout / price reject / user cancel.

    +

    Type declaration

    • backtest: boolean

      true when called during a backtest run — adapter should skip exchange calls

      +
    • context: {
          exchangeName: ExchangeName;
          frameName?: FrameName;
          strategyName: StrategyName;
      }

      Strategy/exchange/frame routing context

      +
    • currentPrice: number

      Market price at the moment of cancellation

      +
    • position: "long" | "short"

      Position direction

      +
    • priceOpen: number

      Pending entry price the scheduled signal had been waiting for

      +
    • priceStopLoss: number

      Stop-loss price that had been configured for the scheduled signal

      +
    • priceTakeProfit: number

      Take-profit price that had been configured for the scheduled signal

      +
    • Optionalreason?: StrategyCancelReason

      Why the scheduled signal was cancelled: "timeout" / "price_reject" / "user"

      +
    • signalId: string

      Unique signal identifier (UUID v4) of the cancelled scheduled signal

      +
    • symbol: string

      Trading pair symbol, e.g. "BTCUSDT"

      +
    const payload: BrokerScheduleCancelledPayload = {
    symbol: "BTCUSDT",
    position: "long",
    currentPrice: 47500,
    priceOpen: 50000,
    priceTakeProfit: 55000,
    priceStopLoss: 48000,
    reason: "price_reject",
    context: { strategyName: "my-strategy", exchangeName: "binance", frameName: "1h" },
    backtest: false,
    }; +
    + +
    + + + + + + + + + diff --git a/types/types.BrokerScheduleOpenPayload.html b/types/types.BrokerScheduleOpenPayload.html new file mode 100644 index 0000000000000000000000000000000000000000..4f7eadbc0fac098953fcbde224c526448c7fee91 --- /dev/null +++ b/types/types.BrokerScheduleOpenPayload.html @@ -0,0 +1,42 @@ +BrokerScheduleOpenPayload | backtest-kit

    Type Alias BrokerScheduleOpenPayload

    BrokerScheduleOpenPayload: {
        backtest: boolean;
        context: {
            exchangeName: ExchangeName;
            frameName?: FrameName;
            strategyName: StrategyName;
        };
        currentPrice: number;
        position: "long"
        | "short";
        priceOpen: number;
        priceStopLoss: number;
        priceTakeProfit: number;
        signalId: string;
        symbol: string;
    }

    Payload for the scheduled-signal-open broker event.

    +

    Emitted automatically via scheduleEventSubject (action "scheduled") when a new scheduled signal is +created and starts waiting for priceOpen activation. Forwarded to the registered IBroker adapter +via onSignalScheduleOpen. The scheduled -> active transition is NOT reported here — activation +arrives through onSignalOpenCommit.

    +

    Type declaration

    • backtest: boolean

      true when called during a backtest run — adapter should skip exchange calls

      +
    • context: {
          exchangeName: ExchangeName;
          frameName?: FrameName;
          strategyName: StrategyName;
      }

      Strategy/exchange/frame routing context

      +
    • currentPrice: number

      Market price at the moment the scheduled signal was created

      +
    • position: "long" | "short"

      Position direction

      +
    • priceOpen: number

      Pending entry price the scheduled signal waits for

      +
    • priceStopLoss: number

      Stop-loss price configured for the scheduled signal

      +
    • priceTakeProfit: number

      Take-profit price configured for the scheduled signal

      +
    • signalId: string

      Unique signal identifier (UUID v4) of the scheduled signal

      +
    • symbol: string

      Trading pair symbol, e.g. "BTCUSDT"

      +
    const payload: BrokerScheduleOpenPayload = {
    symbol: "BTCUSDT",
    position: "long",
    currentPrice: 49800,
    priceOpen: 50000,
    priceTakeProfit: 55000,
    priceStopLoss: 48000,
    context: { strategyName: "my-strategy", exchangeName: "binance", frameName: "1h" },
    backtest: false,
    }; +
    + +
    + + + + + + + + + diff --git a/types/types.BrokerSchedulePingPayload.html b/types/types.BrokerSchedulePingPayload.html new file mode 100644 index 0000000000000000000000000000000000000000..2884ddc2ecaf90c94ba8be7f7a321198119a7e08 --- /dev/null +++ b/types/types.BrokerSchedulePingPayload.html @@ -0,0 +1,41 @@ +BrokerSchedulePingPayload | backtest-kit

    Type Alias BrokerSchedulePingPayload

    BrokerSchedulePingPayload: {
        backtest: boolean;
        context: {
            exchangeName: ExchangeName;
            frameName?: FrameName;
            strategyName: StrategyName;
        };
        currentPrice: number;
        position: "long"
        | "short";
        priceOpen: number;
        priceStopLoss: number;
        priceTakeProfit: number;
        signalId: string;
        symbol: string;
    }

    Payload for the schedule-ping broker event.

    +

    Emitted automatically via schedulePingSubject on every live tick while a scheduled signal is +monitored (waiting for priceOpen activation). Forwarded to the registered IBroker adapter via +onSignalSchedulePing. Purely informational.

    +

    Type declaration

    • backtest: boolean

      true when called during a backtest run — adapter should skip exchange calls

      +
    • context: {
          exchangeName: ExchangeName;
          frameName?: FrameName;
          strategyName: StrategyName;
      }

      Strategy/exchange/frame routing context

      +
    • currentPrice: number

      Market price at the moment of the ping

      +
    • position: "long" | "short"

      Position direction

      +
    • priceOpen: number

      Pending entry price the scheduled signal is waiting for

      +
    • priceStopLoss: number

      Stop-loss price configured for the scheduled signal

      +
    • priceTakeProfit: number

      Take-profit price configured for the scheduled signal

      +
    • signalId: string

      Unique signal identifier (UUID v4) of the scheduled signal

      +
    • symbol: string

      Trading pair symbol, e.g. "BTCUSDT"

      +
    const payload: BrokerSchedulePingPayload = {
    symbol: "BTCUSDT",
    position: "long",
    currentPrice: 49800,
    priceOpen: 50000,
    priceTakeProfit: 55000,
    priceStopLoss: 48000,
    context: { strategyName: "my-strategy", exchangeName: "binance", frameName: "1h" },
    backtest: false,
    }; +
    + +
    + + + + + + + + + diff --git a/types/types.BrokerSignalClosePayload.html b/types/types.BrokerSignalClosePayload.html index 9c5db6095eb580bf4151e6110e8e040d05c9249b..7d6f59b3489d874049241f53f51979cbd4e13ad8 100644 --- a/types/types.BrokerSignalClosePayload.html +++ b/types/types.BrokerSignalClosePayload.html @@ -19,7 +19,7 @@ Forwarded to the registered IBroker adapter via onSignalCloseCommit
    const payload: BrokerSignalClosePayload = {
    symbol: "BTCUSDT",
    cost: 100,
    position: "long",
    currentPrice: 54000,
    priceTakeProfit: 55000,
    priceStopLoss: 48000,
    totalEntries: 2,
    totalPartials: 1,
    pnl: { profit: 80, loss: 0, volume: 100 },
    context: { strategyName: "my-strategy", exchangeName: "binance", frameName: "1h" },
    backtest: false,
    };
    -
    +

    Type Alias BrokerSignalPendingPayload

    BrokerSignalPendingPayload: {
        backtest: boolean;
        context: {
            exchangeName: ExchangeName;
            frameName?: FrameName;
            strategyName: StrategyName;
        };
        currentPrice: number;
        maxDrawdown: IStrategyPnL;
        peakProfit: IStrategyPnL;
        pnl: IStrategyPnL;
        position: "long"
        | "short";
        priceOpen: number;
        priceStopLoss: number;
        priceTakeProfit: number;
        signalId: string;
        symbol: string;
        totalEntries: number;
        totalPartials: number;
    }

    Payload for the pending-order synchronization broker event.

    Emitted automatically via syncPendingSubject on every live tick while a pending signal is monitored, BEFORE the framework evaluates TP/SL/time. Forwarded to the registered IBroker -adapter via onOrderPing.

    +adapter via onOrderCheck.

    The adapter should query the exchange by signalId and THROW ONLY when the order is definitively NOT FOUND by that id (filled, cancelled, or liquidated externally). A throw propagates to CREATE_SYNC_PENDING_FN, which makes the framework close the pending signal with @@ -26,7 +26,7 @@ position. Only a confirmed "order not found by id" response is a valid

    const payload: BrokerSignalPendingPayload = {
    symbol: "BTCUSDT",
    position: "long",
    currentPrice: 50500,
    priceOpen: 50000,
    priceTakeProfit: 55000,
    priceStopLoss: 48000,
    context: { strategyName: "my-strategy", exchangeName: "binance", frameName: "1h" },
    backtest: false,
    };
    -
    +

    Type Alias CandleData

    CandleData: ICandleData

    Type for persisted candle cache data. Each candle is stored as a separate JSON file.

    -
    +

    Type Alias CandleInterval

    CandleInterval:
        | "1m"
        | "3m"
        | "5m"
        | "15m"
        | "30m"
        | "1h"
        | "2h"
        | "4h"
        | "6h"
        | "8h"
        | "1d"

    Candle time interval for fetching historical data.

    -
    +

    Type Alias ColumnConfig

    ColumnConfig: typeof COLUMN_CONFIG

    Type for the column configuration object.

    -
    +

    Type Alias EntityId

    EntityId: string | number

    Entity identifier - string or number.

    -
    +

    Type Alias GlobalConfig

    GlobalConfig: typeof GLOBAL_CONFIG

    Type for global configuration object.

    -
    +

    Type Alias ICommitRow

    ICommitRow:
        | IPartialProfitCommitRow
        | IPartialLossCommitRow
        | IBreakevenCommitRow
        | IAverageBuyCommitRow
        | ITrailingStopCommitRow
        | ITrailingTakeCommitRow
        | IActivateScheduledCommitRow

    Discriminated union of all queued commit events. These are stored in _commitQueue and processed in tick()/backtest().

    -
    +

    Type Alias ISizingCalculateParams

    Discriminated union for position size calculation parameters. Type-safe parameters based on sizing method.

    -
    +

    Type Alias ISizingParams

    ISizingParams:
        | ISizingParamsFixedPercentage
        | ISizingParamsKelly
        | ISizingParamsATR

    Discriminated union for sizing parameters passed to ClientSizing constructor. Extends ISizingSchema with logger instance for internal logging.

    -
    +

    Type Alias ISizingSchema

    ISizingSchema:
        | ISizingSchemaFixedPercentage
        | ISizingSchemaKelly
        | ISizingSchemaATR

    Discriminated union for sizing schemas. Type-safe configuration based on sizing method.

    -
    +

    Type Alias IStorageSignalRow

    IStorageSignalRow:
        | IStorageSignalRowOpened
        | IStorageSignalRowScheduled
        | IStorageSignalRowClosed
        | IStorageSignalRowCancelled

    Discriminated union of storage signal rows. Use type guards: row.status === "closed" for type-safe access to pnl.

    -
    +

    Type Alias IStrategyTickResult

    Discriminated union of all tick results. Use type guards: result.action === "closed" for type safety.

    -
    +

    Type Alias IntervalData

    IntervalData: { data: unknown; id: string; removed: boolean; when: Date }

    Interval.file data type stored in persistence layer.

    -

    Type declaration

    • data: unknown
    • id: string
    • removed: boolean
    • when: Date
    +

    Type declaration

    • data: unknown
    • id: string
    • removed: boolean
    • when: Date

    Type Alias LogData

    LogData: ILogEntry[]

    Type for persisted log data. Each log entry is stored as a separate file keyed by its id.

    -
    +

    Type Alias MarkdownName

    MarkdownName: keyof IMarkdownTarget

    Union type of all valid markdown report names. Used for type-safe identification of markdown services.

    -
    +

    Type Alias MeasureData

    MeasureData: { data: unknown; id: string; removed: boolean }

    Cache.file data type stored in persistence layer.

    -

    Type declaration

    • data: unknown
    • id: string
    • removed: boolean
    +

    Type declaration

    • data: unknown
    • id: string
    • removed: boolean

    Type Alias MemoryData

    MemoryData: {
        data: object;
        index: string;
        priority: number;
        removed: boolean;
        when: number;
    }

    Type for persisted memory entry data. Each memory entry is an arbitrary JSON-serializable object.

    -

    Type declaration

    • data: object
    • index: string
    • priority: number
    • removed: boolean
    • when: number
    +

    Type declaration

    • data: object
    • index: string
    • priority: number
    • removed: boolean
    • when: number

    Type Alias MessageRole

    MessageRole: "assistant" | "system" | "tool" | "user"

    Role of the message sender in an LLM chat history.

    -
    +

    Type Alias NotificationData

    NotificationData: NotificationModel[]

    Type for persisted notification data. Each notification is stored as a separate file keyed by its id.

    -
    +

    Type Alias PartialData

    PartialData: Record<string, IPartialData>

    Type for persisted partial data. Stores profit and loss levels as arrays for JSON serialization.

    -
    +

    Type Alias RecentData

    RecentData: IPublicSignalRow | null

    Type for persisted recent signal data. Stores the latest active signal per context key.

    -
    +

    Type Alias ReportName

    ReportName: keyof IReportTarget

    Union type of all valid report names. Used for type-safe identification of report services.

    -
    +

    Type Alias RiskData

    RiskData: [string, IRiskActivePosition][]

    Type for persisted risk positions data. Stores Map entries as array of [key, value] tuples for JSON serialization.

    -
    +

    Type Alias ScheduleData

    ScheduleData: IScheduledSignalRow | null

    Type for persisted scheduled signal data. Contains nullable scheduled signal for atomic updates.

    -
    +

    Type Alias SessionData

    SessionData: { data: object | null; id: string; when: number }

    Session data structure for session persistence. Each session is identified by a unique id and contains an arbitrary JSON-serializable data object.

    -

    Type declaration

    • data: object | null
    • id: string
    • when: number
    +

    Type declaration

    • data: object | null
    • id: string
    • when: number

    Type Alias SignalData

    SignalData: ISignalRow | null

    Signal data stored in persistence layer. Contains nullable signal for atomic updates.

    -
    +

    Type Alias SignalInterval

    SignalInterval: "1m" | "3m" | "5m" | "15m" | "30m" | "1h"

    Signal generation interval for throttling. Enforces minimum time between getSignal calls.

    -
    +

    Type Alias StateData

    StateData: { data: object; id: string; when: number }

    Type for persisted state entry data. Wraps an arbitrary JSON-serializable object with a unique id.

    -

    Type declaration

    • data: object
    • id: string
    • when: number
    +

    Type declaration

    • data: object
    • id: string
    • when: number

    Type Alias StorageData

    StorageData: IStorageSignalRow[]

    Type for persisted signal storage data. Each signal is stored as a separate file keyed by its id.

    -
    +

    Type Alias StrategyActionType

    StrategyActionType:
        | "cancel-scheduled"
        | "close-pending"
        | "partial-profit"
        | "partial-loss"
        | "trailing-stop"
        | "trailing-take"
        | "breakeven"
        | "activate-scheduled"
        | "average-buy"

    Action types for strategy events. Represents all possible strategy management actions.

    -
    +

    Type Alias StrategyCancelReason

    StrategyCancelReason: "timeout" | "price_reject" | "user"

    Reason why scheduled signal was cancelled. Used in discriminated union for type-safe handling.

    -
    +

    Type Alias StrategyCloseReason

    StrategyCloseReason: "time_expired" | "take_profit" | "stop_loss" | "closed"

    Reason why signal was closed. Used in discriminated union for type-safe handling.

    -
    +

    Type Alias StrategyData

    StrategyData: {
        activatedSignal: IScheduledSignalActivateRow | null;
        cancelledSignal: IScheduledSignalCancelRow | null;
        closedSignal: ISignalCloseRow | null;
        commitQueue: ICommitRow[];
        createdSignal: ISignalDto | null;
        pendingSignalId: string | null;
    }

    Type for persisted deferred strategy state. +StrategyData | backtest-kit

    Type Alias StrategyData

    StrategyData: {
        activatedSignal: IScheduledSignalActivateRow | null;
        cancelledSignal: IScheduledSignalCancelRow | null;
        closedSignal: ISignalCloseRow | null;
        commitQueue: ICommitRow[];
        createdSignal: ISignalDto | null;
        pendingSignalId: string | null;
        stopLossSignal: ISignalCloseRow | null;
        takeProfitSignal: ISignalCloseRow | null;
    }

    Type for persisted deferred strategy state. Snapshot of the in-flight commit queue and deferred user actions that have not yet been forwarded to the broker. Restored on waitForInit after a live crash so the pending broker operations are not silently lost.

    @@ -13,7 +13,13 @@ createPending and createScheduled overwrite the same slot, so only the latest wi or null if there was no pending signal when the snapshot was written. On restore, the deferred fields are applied only when this matches the restored _pendingSignal.id — otherwise the snapshot belongs to a different/stale position and is discarded.

    -
    +
  • stopLossSignal: ISignalCloseRow | null

    Deferred broker-confirmed stop-loss fill (createStopLoss), or null if none pending. +Set when the exchange reports the SL order was actually filled (e.g. by candle high/low), +independent of the VWAP-based SL check. Drained on the next tick to close with "stop_loss".

    +
  • takeProfitSignal: ISignalCloseRow | null

    Deferred broker-confirmed take-profit fill (createTakeProfit), or null if none pending. +Set when the exchange reports the TP order was actually filled (e.g. by candle high/low), +independent of the VWAP-based TP check. Drained on the next tick to close with "take_profit".

    +
  • Type Alias StrategyStatus

    StrategyStatus: {
        activatedSignal: IScheduledSignalActivateRow | null;
        cancelledSignal: IScheduledSignalCancelRow | null;
        closedSignal: ISignalCloseRow | null;
        commitQueue: ICommitRow[];
        createdSignal: ISignalDto | null;
        pendingSignalId: string | null;
    }

    Type for persisted deferred strategy state. +StrategyStatus | backtest-kit

    Type Alias StrategyStatus

    StrategyStatus: {
        activatedSignal: IScheduledSignalActivateRow | null;
        cancelledSignal: IScheduledSignalCancelRow | null;
        closedSignal: ISignalCloseRow | null;
        commitQueue: ICommitRow[];
        createdSignal: ISignalDto | null;
        pendingSignalId: string | null;
        stopLossSignal: ISignalCloseRow | null;
        takeProfitSignal: ISignalCloseRow | null;
    }

    Type for persisted deferred strategy state. Snapshot of the in-flight commit queue and deferred user actions that have not yet been forwarded to the broker. Restored on waitForInit after a live crash so the pending broker operations are not silently lost.

    @@ -13,7 +13,15 @@ createPending and createScheduled overwrite the same slot, so only the latest wi or null if there was no pending signal when the snapshot was written. On restore, the deferred fields are applied only when this matches the restored _pendingSignal.id — otherwise the snapshot belongs to a different/stale position and is discarded.

    -
    +
  • stopLossSignal: ISignalCloseRow | null

    Deferred broker-confirmed stop-loss fill (createStopLoss), or null if none pending. +Set when the external order management system reports the position's SL order was actually +filled on the exchange (e.g. by candle high/low) — independent of the VWAP-based SL check. +Drained on the next tick/backtest to close the position with closeReason "stop_loss".

    +
  • takeProfitSignal: ISignalCloseRow | null

    Deferred broker-confirmed take-profit fill (createTakeProfit), or null if none pending. +Set when the external order management system reports the position's TP order was actually +filled on the exchange (e.g. by candle high/low) — independent of the VWAP-based TP check. +Drained on the next tick/backtest to close the position with closeReason "take_profit".

    +
  • Type Alias TDumpInstanceCtor

    TDumpInstanceCtor: new (
        signalId: string,
        bucketName: string,
        backtest: boolean,
    ) => IDumpInstance

    Constructor type for dump instance implementations. Used for swapping backends via DumpAdapter.useDumpAdapter().

    -
    +

    Type Alias TLogCtor

    TLogCtor: new () => Partial<ILog>

    Constructor type for log adapters. Used for custom log implementations.

    -
    +

    Type Alias TMemoryInstanceCtor

    TMemoryInstanceCtor: new (
        signalId: string,
        bucketName: string,
    ) => IMemoryInstance

    Constructor type for memory instance implementations. Used for swapping backends via MemoryBacktestAdapter / MemoryLiveAdapter.

    -
    +

    Type Alias TNotificationUtilsCtor

    TNotificationUtilsCtor: new () => INotificationUtils

    Constructor type for notification adapters. Used for custom notification implementations.

    -
    +

    Type Alias TPersistBase

    TPersistBase: InstanceType<typeof PersistBase>

    Type helper for PersistBase instance.

    -
    +

    Type Alias TPersistBaseCtor<EntityName, Entity>

    TPersistBaseCtor: new (
        entityName: EntityName,
        baseDir: string,
    ) => IPersistBase<Entity>

    Constructor type for PersistBase. Used for custom persistence adapters.

    -

    Type Parameters

    • EntityName extends string = string
    • Entity extends IEntity | null = IEntity
    +

    Type Parameters

    • EntityName extends string = string
    • Entity extends IEntity | null = IEntity

    Type Alias TPersistBreakevenInstanceCtor

    TPersistBreakevenInstanceCtor: new (
        symbol: string,
        strategyName: StrategyName,
        exchangeName: ExchangeName,
    ) => IPersistBreakevenInstance

    Constructor type for IPersistBreakevenInstance. Used by PersistBreakevenUtils.usePersistBreakevenAdapter() to register custom adapters.

    -
    +

    Type Alias TPersistCandleInstanceCtor

    TPersistCandleInstanceCtor: new (
        symbol: string,
        interval: CandleInterval,
        exchangeName: ExchangeName,
    ) => IPersistCandleInstance

    Constructor type for IPersistCandleInstance. Used by PersistCandleUtils.usePersistCandleAdapter() to register custom adapters.

    -
    +

    Type Alias TPersistIntervalInstanceCtor

    TPersistIntervalInstanceCtor: new (bucket: string) => IPersistIntervalInstance

    Constructor type for IPersistIntervalInstance. Used by PersistIntervalUtils.usePersistIntervalAdapter() to register custom adapters.

    -
    +

    Type Alias TPersistLogInstanceCtor

    TPersistLogInstanceCtor: new () => IPersistLogInstance

    Constructor type for IPersistLogInstance. Used by PersistLogUtils.usePersistLogAdapter() to register custom adapters.

    -
    +

    Type Alias TPersistMeasureInstanceCtor

    TPersistMeasureInstanceCtor: new (bucket: string) => IPersistMeasureInstance

    Constructor type for IPersistMeasureInstance. Used by PersistMeasureUtils.usePersistMeasureAdapter() to register custom adapters.

    -
    +

    Type Alias TPersistMemoryInstanceCtor

    TPersistMemoryInstanceCtor: new (
        signalId: string,
        bucketName: string,
    ) => IPersistMemoryInstance

    Constructor type for IPersistMemoryInstance. Used by PersistMemoryUtils.usePersistMemoryAdapter() to register custom adapters.

    -
    +

    Type Alias TPersistNotificationInstanceCtor

    TPersistNotificationInstanceCtor: new (
        backtest: boolean,
    ) => IPersistNotificationInstance

    Constructor type for IPersistNotificationInstance. Used by PersistNotificationUtils.usePersistNotificationAdapter() to register custom adapters.

    -
    +

    Type Alias TPersistPartialInstanceCtor

    TPersistPartialInstanceCtor: new (
        symbol: string,
        strategyName: StrategyName,
        exchangeName: ExchangeName,
    ) => IPersistPartialInstance

    Constructor type for IPersistPartialInstance. Used by PersistPartialUtils.usePersistPartialAdapter() to register custom adapters.

    -
    +

    Type Alias TPersistRecentInstanceCtor

    TPersistRecentInstanceCtor: new (
        symbol: string,
        strategyName: StrategyName,
        exchangeName: ExchangeName,
        frameName: FrameName,
        backtest: boolean,
    ) => IPersistRecentInstance

    Constructor type for IPersistRecentInstance. Used by PersistRecentUtils.usePersistRecentAdapter() to register custom adapters.

    -
    +

    Type Alias TPersistRiskInstanceCtor

    TPersistRiskInstanceCtor: new (
        riskName: RiskName,
        exchangeName: ExchangeName,
    ) => IPersistRiskInstance

    Constructor type for IPersistRiskInstance. Used by PersistRiskUtils.usePersistRiskAdapter() to register custom adapters.

    -
    +

    Type Alias TPersistScheduleInstanceCtor

    TPersistScheduleInstanceCtor: new (
        symbol: string,
        strategyName: StrategyName,
        exchangeName: ExchangeName,
    ) => IPersistScheduleInstance

    Constructor type for IPersistScheduleInstance. Used by PersistScheduleUtils.usePersistScheduleAdapter() to register custom adapters.

    -
    +

    Type Alias TPersistSessionInstanceCtor

    TPersistSessionInstanceCtor: new (
        strategyName: string,
        exchangeName: string,
        frameName: string,
    ) => IPersistSessionInstance

    Constructor type for IPersistSessionInstance. Used by PersistSessionUtils.usePersistSessionAdapter() to register custom adapters.

    -
    +

    Type Alias TPersistSignalInstanceCtor

    TPersistSignalInstanceCtor: new (
        symbol: string,
        strategyName: StrategyName,
        exchangeName: ExchangeName,
    ) => IPersistSignalInstance

    Constructor type for IPersistSignalInstance. Used by PersistSignalUtils.usePersistSignalAdapter() to register custom adapters.

    -
    +

    Type Alias TPersistStateInstanceCtor

    TPersistStateInstanceCtor: new (
        signalId: string,
        bucketName: string,
    ) => IPersistStateInstance

    Constructor type for IPersistStateInstance. Used by PersistStateUtils.usePersistStateAdapter() to register custom adapters.

    -
    +

    Type Alias TPersistStorageInstanceCtor

    TPersistStorageInstanceCtor: new (backtest: boolean) => IPersistStorageInstance

    Constructor type for IPersistStorageInstance. Used by PersistStorageUtils.usePersistStorageAdapter() to register custom adapters.

    -
    +

    Type Alias TPersistStrategyInstanceCtor

    TPersistStrategyInstanceCtor: new (
        symbol: string,
        strategyName: StrategyName,
        exchangeName: ExchangeName,
    ) => IPersistStrategyInstance

    Constructor type for IPersistStrategyInstance. Used by PersistStrategyUtils.usePersistStrategyAdapter() to register custom adapters.

    -
    +

    Type Alias TRecentUtilsCtor

    TRecentUtilsCtor: new () => IRecentUtils

    Constructor type for recent signal storage adapters.

    -
    +

    Type Alias TSessionInstanceCtor

    TSessionInstanceCtor: new (
        symbol: string,
        strategyName: StrategyName,
        exchangeName: ExchangeName,
        frameName: FrameName,
        backtest: boolean,
    ) => ISessionInstance

    Constructor type for session instance implementations. Used for swapping backends via SessionBacktestAdapter / SessionLiveAdapter.

    -
    +

    Type Alias TStateInstanceCtor

    TStateInstanceCtor: new (
        initialValue: object,
        signalId: string,
        bucketName: string,
    ) => IStateInstance

    Constructor type for state instance implementations. Used for swapping backends via StateBacktestAdapter / StateLiveAdapter.

    -
    +

    Type Alias TStorageUtilsCtor

    TStorageUtilsCtor: new () => IStorageUtils

    Constructor type for storage adapters. Used for custom storage implementations.

    -
    +

    Type Alias WalkerMetric

    WalkerMetric:
        | "sharpeRatio"
        | "annualizedSharpeRatio"
        | "winRate"
        | "totalPnl"
        | "certaintyRatio"
        | "avgPnl"
        | "expectedYearlyReturns"

    Optimization metric for comparing strategies. Higher values are always better (metric is maximized).

    -
    +

    Variable DumpConst

    Dump: DumpAdapter
    +Dump | backtest-kit

    Variable DumpConst

    Dump: DumpAdapter

    Variable HighestProfitConst

    HighestProfit: HighestProfitUtils

    Global singleton instance of HighestProfitUtils.

    -
    +

    Variable LogConst

    Log: LogAdapter

    Global singleton instance of LogAdapter. Provides unified log management with pluggable backends.

    -
    +

    Variable LookupConst

    Lookup: LookupUtils

    Process-wide singleton instance of LookupUtils. Imported by Backtest, Live, WalkerLogicPrivateService (registration sites) and by Candle (read-only consumer via isParallel).

    -
    +

    Variable MarkdownConst

    Markdown: MarkdownAdapter

    Global singleton instance of MarkdownAdapter. Provides markdown report generation with pluggable storage backends.

    -
    +

    Variable MarkdownWriterConst

    MarkdownWriter: MarkdownWriterAdapter
    +MarkdownWriter | backtest-kit

    Variable MarkdownWriterConst

    MarkdownWriter: MarkdownWriterAdapter

    Variable MaxDrawdownConst

    MaxDrawdown: MaxDrawdownUtils

    Global singleton instance of MaxDrawdownUtils.

    -
    +

    Variable MemoryConst

    Memory: MemoryAdapter

    Global singleton instance of MemoryAdapter. Provides unified memory management for backtest and live trading.

    -
    +

    Variable MemoryBacktestConst

    MemoryBacktest: MemoryBacktestAdapter

    Global singleton instance of MemoryBacktestAdapter. Provides backtest memory storage with pluggable backends.

    -
    +

    Variable MemoryLiveConst

    MemoryLive: MemoryLiveAdapter

    Global singleton instance of MemoryLiveAdapter. Provides live trading memory storage with pluggable backends.

    -
    +

    Variable NotificationConst

    Notification: NotificationAdapter

    Global singleton instance of NotificationAdapter. Provides unified notification management for backtest and live trading.

    -
    +

    Variable NotificationBacktestConst

    NotificationBacktest: NotificationBacktestAdapter

    Global singleton instance of NotificationBacktestAdapter. Provides backtest notification storage with pluggable backends.

    -
    +

    Variable NotificationLiveConst

    NotificationLive: NotificationLiveAdapter

    Global singleton instance of NotificationLiveAdapter. Provides live trading notification storage with pluggable backends.

    -
    +

    Variable PersistIntervalAdapterConst

    PersistIntervalAdapter: PersistIntervalUtils

    Global singleton instance of PersistIntervalUtils. Used by Interval.file for persistent once-per-interval signal firing.

    -
    +

    Variable PersistLogAdapterConst

    PersistLogAdapter: PersistLogUtils

    Global singleton instance of PersistLogUtils. Used by LogPersistUtils for log entry persistence.

    -
    +

    Variable PersistMeasureAdapterConst

    PersistMeasureAdapter: PersistMeasureUtils

    Global singleton instance of PersistMeasureUtils. Used by Cache.file for persistent caching of external API responses.

    -
    +

    Variable PersistNotificationAdapterConst

    PersistNotificationAdapter: PersistNotificationUtils

    Global singleton instance of PersistNotificationUtils. Used by NotificationPersistLiveUtils/NotificationPersistBacktestUtils for notification persistence.

    -
    +

    Variable PersistRecentAdapterConst

    PersistRecentAdapter: PersistRecentUtils

    Global singleton instance of PersistRecentUtils. Used by RecentPersistBacktestUtils/RecentPersistLiveUtils for recent signal persistence.

    -
    +

    Variable PersistSessionAdapterConst

    PersistSessionAdapter: PersistSessionUtils

    Global singleton instance of PersistSessionUtils. Used by SessionPersistInstance for crash-safe session persistence.

    -
    +

    Variable PersistStateAdapterConst

    PersistStateAdapter: PersistStateUtils

    Global singleton instance of PersistStateUtils. Used by StatePersistInstance for crash-safe state persistence.

    -
    +

    Variable PersistStorageAdapterConst

    PersistStorageAdapter: PersistStorageUtils

    Global singleton instance of PersistStorageUtils. Used by SignalLiveUtils for signal storage persistence.

    -
    +

    Variable PositionSizeConst

    PositionSize: typeof PositionSizeUtils
    +PositionSize | backtest-kit

    Variable PositionSizeConst

    PositionSize: typeof PositionSizeUtils

    Variable RecentConst

    Recent: RecentAdapter

    Global singleton instance of RecentAdapter. Provides unified recent signal management for backtest and live trading.

    -
    +

    Variable RecentBacktestConst

    RecentBacktest: RecentBacktestAdapter

    Global singleton instance of RecentBacktestAdapter. Provides backtest recent signal storage with pluggable backends.

    -
    +

    Variable RecentLiveConst

    RecentLive: RecentLiveAdapter

    Global singleton instance of RecentLiveAdapter. Provides live trading recent signal storage with pluggable backends.

    -
    +

    Variable ReportConst

    Report: ReportAdapter

    Global singleton instance of ReportAdapter. Provides JSONL event logging with pluggable storage backends.

    -
    +

    Variable ReportWriterConst

    ReportWriter: ReportWriterAdapter
    +ReportWriter | backtest-kit

    Variable ReportWriterConst

    ReportWriter: ReportWriterAdapter

    Variable SessionConst

    Session: SessionAdapter

    Global singleton instance of SessionAdapter. Provides unified session management for backtest and live trading.

    -
    +

    Variable SessionBacktestConst

    SessionBacktest: SessionBacktestAdapter

    Global singleton instance of SessionBacktestAdapter. Provides backtest session storage with pluggable backends.

    -
    +

    Variable SessionLiveConst

    SessionLive: SessionLiveAdapter

    Global singleton instance of SessionLiveAdapter. Provides live trading session storage with pluggable backends.

    -
    +

    Variable StateConst

    State: StateAdapter

    Global singleton instance of StateAdapter. Provides unified state management for backtest and live trading.

    -
    +

    Variable StateBacktestConst

    StateBacktest: StateBacktestAdapter

    Global singleton instance of StateBacktestAdapter. Provides backtest state storage with pluggable backends.

    -
    +

    Variable StateLiveConst

    StateLive: StateLiveAdapter

    Global singleton instance of StateLiveAdapter. Provides live trading state storage with pluggable backends.

    -
    +

    Variable StorageConst

    Storage: StorageAdapter

    Global singleton instance of StorageAdapter. Provides unified signal storage management for backtest and live trading.

    -
    +

    Variable StorageBacktestConst

    StorageBacktest: StorageBacktestAdapter

    Global singleton instance of StorageBacktestAdapter. Provides backtest signal storage with pluggable backends.

    -
    +

    Variable StorageLiveConst

    StorageLive: StorageLiveAdapter

    Global singleton instance of StorageLiveAdapter. Provides live trading signal storage with pluggable backends.

    -
    +

    Variable SystemConst

    System: SystemUtils
    +System | backtest-kit

    Variable SystemConst

    System: SystemUtils

    Variable activePingSubjectConst

    activePingSubject: typeof activePingSubject
    +activePingSubject | backtest-kit

    Variable activePingSubjectConst

    activePingSubject: typeof activePingSubject

    Variable afterEndSubjectConst

    afterEndSubject: typeof afterEndSubject
    +afterEndSubject | backtest-kit

    Variable afterEndSubjectConst

    afterEndSubject: typeof afterEndSubject

    Variable backtestScheduleOpenSubjectConst

    backtestScheduleOpenSubject: typeof backtestScheduleOpenSubject
    +backtestScheduleOpenSubject | backtest-kit

    Variable backtestScheduleOpenSubjectConst

    backtestScheduleOpenSubject: typeof backtestScheduleOpenSubject

    Variable beforeStartSubjectConst

    beforeStartSubject: typeof beforeStartSubject
    +beforeStartSubject | backtest-kit

    Variable beforeStartSubjectConst

    beforeStartSubject: typeof beforeStartSubject

    Variable breakevenSubjectConst

    breakevenSubject: typeof breakevenSubject
    +breakevenSubject | backtest-kit

    Variable breakevenSubjectConst

    breakevenSubject: typeof breakevenSubject

    Variable doneBacktestSubjectConst

    doneBacktestSubject: typeof doneBacktestSubject
    +doneBacktestSubject | backtest-kit

    Variable doneBacktestSubjectConst

    doneBacktestSubject: typeof doneBacktestSubject

    Variable doneLiveSubjectConst

    doneLiveSubject: typeof doneLiveSubject
    +doneLiveSubject | backtest-kit

    Variable doneLiveSubjectConst

    doneLiveSubject: typeof doneLiveSubject

    Variable doneWalkerSubjectConst

    doneWalkerSubject: typeof doneWalkerSubject
    +doneWalkerSubject | backtest-kit

    Variable doneWalkerSubjectConst

    doneWalkerSubject: typeof doneWalkerSubject

    Variable entrySubjectConst

    entrySubject: typeof entrySubject
    +entrySubject | backtest-kit

    Variable entrySubjectConst

    entrySubject: typeof entrySubject

    Variable errorEmitterConst

    errorEmitter: typeof errorEmitter
    +errorEmitter | backtest-kit

    Variable errorEmitterConst

    errorEmitter: typeof errorEmitter

    Variable exitEmitterConst

    exitEmitter: typeof exitEmitter
    +exitEmitter | backtest-kit

    Variable exitEmitterConst

    exitEmitter: typeof exitEmitter

    Variable highestProfitSubjectConst

    highestProfitSubject: typeof highestProfitSubject
    +highestProfitSubject | backtest-kit

    Variable highestProfitSubjectConst

    highestProfitSubject: typeof highestProfitSubject

    Variable idlePingSubjectConst

    idlePingSubject: typeof idlePingSubject
    +idlePingSubject | backtest-kit

    Variable idlePingSubjectConst

    idlePingSubject: typeof idlePingSubject

    Variable maxDrawdownSubjectConst

    maxDrawdownSubject: typeof maxDrawdownSubject
    +maxDrawdownSubject | backtest-kit

    Variable maxDrawdownSubjectConst

    maxDrawdownSubject: typeof maxDrawdownSubject

    Variable partialLossSubjectConst

    partialLossSubject: typeof partialLossSubject
    +partialLossSubject | backtest-kit

    Variable partialLossSubjectConst

    partialLossSubject: typeof partialLossSubject

    Variable partialProfitSubjectConst

    partialProfitSubject: typeof partialProfitSubject
    +partialProfitSubject | backtest-kit

    Variable partialProfitSubjectConst

    partialProfitSubject: typeof partialProfitSubject

    Variable performanceEmitterConst

    performanceEmitter: typeof performanceEmitter
    +performanceEmitter | backtest-kit

    Variable performanceEmitterConst

    performanceEmitter: typeof performanceEmitter

    Variable progressBacktestEmitterConst

    progressBacktestEmitter: typeof progressBacktestEmitter
    +progressBacktestEmitter | backtest-kit

    Variable progressBacktestEmitterConst

    progressBacktestEmitter: typeof progressBacktestEmitter

    Variable progressWalkerEmitterConst

    progressWalkerEmitter: typeof progressWalkerEmitter
    +progressWalkerEmitter | backtest-kit

    Variable progressWalkerEmitterConst

    progressWalkerEmitter: typeof progressWalkerEmitter

    Variable riskSubjectConst

    riskSubject: typeof riskSubject
    +riskSubject | backtest-kit

    Variable riskSubjectConst

    riskSubject: typeof riskSubject

    Variable scheduleEventSubjectConst

    scheduleEventSubject: typeof scheduleEventSubject
    + + + + + + + + + diff --git a/variables/types.emitters.schedulePingSubject.html b/variables/types.emitters.schedulePingSubject.html index f29aaa1c2d3d5271a032f95c0bc9336bb8e8d455..921eb8ee6367e7dfc2cc6a1edbd6141a31a28663 100644 --- a/variables/types.emitters.schedulePingSubject.html +++ b/variables/types.emitters.schedulePingSubject.html @@ -1,4 +1,4 @@ -schedulePingSubject | backtest-kit

    Variable schedulePingSubjectConst

    schedulePingSubject: typeof schedulePingSubject
    +schedulePingSubject | backtest-kit

    Variable schedulePingSubjectConst

    schedulePingSubject: typeof schedulePingSubject

    Variable shutdownEmitterConst

    shutdownEmitter: typeof shutdownEmitter
    +shutdownEmitter | backtest-kit

    Variable shutdownEmitterConst

    shutdownEmitter: typeof shutdownEmitter

    Variable signalBacktestEmitterConst

    signalBacktestEmitter: typeof signalBacktestEmitter
    +signalBacktestEmitter | backtest-kit

    Variable signalBacktestEmitterConst

    signalBacktestEmitter: typeof signalBacktestEmitter

    Variable signalEmitterConst

    signalEmitter: typeof signalEmitter
    +signalEmitter | backtest-kit

    Variable signalEmitterConst

    signalEmitter: typeof signalEmitter

    Variable signalEventSubjectConst

    signalEventSubject: typeof signalEventSubject
    + + + + + + + + + diff --git a/variables/types.emitters.signalLiveEmitter.html b/variables/types.emitters.signalLiveEmitter.html index 369b6473eaa3c164b182f0c4804a54f69f7ddad0..6420da63aee398c2522d90953646b6b6a3c094ae 100644 --- a/variables/types.emitters.signalLiveEmitter.html +++ b/variables/types.emitters.signalLiveEmitter.html @@ -1,4 +1,4 @@ -signalLiveEmitter | backtest-kit

    Variable signalLiveEmitterConst

    signalLiveEmitter: typeof signalLiveEmitter
    +signalLiveEmitter | backtest-kit

    Variable signalLiveEmitterConst

    signalLiveEmitter: typeof signalLiveEmitter

    Variable signalNotifySubjectConst

    signalNotifySubject: typeof signalNotifySubject
    +signalNotifySubject | backtest-kit

    Variable signalNotifySubjectConst

    signalNotifySubject: typeof signalNotifySubject

    Variable strategyCommitSubjectConst

    strategyCommitSubject: typeof strategyCommitSubject
    +strategyCommitSubject | backtest-kit

    Variable strategyCommitSubjectConst

    strategyCommitSubject: typeof strategyCommitSubject

    Variable syncPendingSubjectConst

    syncPendingSubject: typeof syncPendingSubject
    +syncPendingSubject | backtest-kit

    Variable syncPendingSubjectConst

    syncPendingSubject: typeof syncPendingSubject

    Variable syncSubjectConst

    syncSubject: typeof syncSubject
    +syncSubject | backtest-kit

    Variable syncSubjectConst

    syncSubject: typeof syncSubject

    Variable validationSubjectConst

    validationSubject: typeof validationSubject
    +validationSubject | backtest-kit

    Variable validationSubjectConst

    validationSubject: typeof validationSubject

    Variable walkerCompleteSubjectConst

    walkerCompleteSubject: typeof walkerCompleteSubject
    +walkerCompleteSubject | backtest-kit

    Variable walkerCompleteSubjectConst

    walkerCompleteSubject: typeof walkerCompleteSubject

    Variable walkerEmitterConst

    walkerEmitter: typeof walkerEmitter
    +walkerEmitter | backtest-kit

    Variable walkerEmitterConst

    walkerEmitter: typeof walkerEmitter

    Variable walkerStopSubjectConst

    walkerStopSubject: typeof walkerStopSubject
    +walkerStopSubject | backtest-kit

    Variable walkerStopSubjectConst

    walkerStopSubject: typeof walkerStopSubject

    Variable libConst

    lib: {
        actionConnectionService: ActionConnectionService;
        actionCoreService: ActionCoreService;
        actionSchemaService: ActionSchemaService;
        actionValidationService: ActionValidationService;
        backtestCommandService: BacktestCommandService;
        backtestLogicPrivateService: BacktestLogicPrivateService;
        backtestLogicPublicService: BacktestLogicPublicService;
        backtestMarkdownService: BacktestMarkdownService;
        backtestReportService: BacktestReportService;
        breakevenConnectionService: BreakevenConnectionService;
        breakevenGlobalService: BreakevenGlobalService;
        breakevenMarkdownService: BreakevenMarkdownService;
        breakevenReportService: BreakevenReportService;
        columnValidationService: ColumnValidationService;
        configValidationService: ConfigValidationService;
        contextMetaService: {
            executionContextService: { context: IExecutionContext };
            getContextTimestamp: () => number;
            loggerService: {
                _commonLogger: ILogger;
                _executionContext: {};
                _methodContext: {};
                debug: (topic: string, ...args: any[]) => Promise<void>;
                executionContextService: { context: IExecutionContext };
                info: (topic: string, ...args: any[]) => Promise<void>;
                log: (topic: string, ...args: any[]) => Promise<void>;
                methodContextService: { context: IMethodContext };
                setLogger: (logger: ILogger) => void;
                warn: (topic: string, ...args: any[]) => Promise<void>;
            };
        };
        exchangeConnectionService: ExchangeConnectionService;
        exchangeCoreService: ExchangeCoreService;
        exchangeSchemaService: ExchangeSchemaService;
        exchangeValidationService: ExchangeValidationService;
        executionContextService: { context: IExecutionContext };
        frameConnectionService: FrameConnectionService;
        frameCoreService: FrameCoreService;
        frameSchemaService: FrameSchemaService;
        frameValidationService: FrameValidationService;
        heatMarkdownService: HeatMarkdownService;
        heatReportService: HeatReportService;
        highestProfitMarkdownService: HighestProfitMarkdownService;
        highestProfitReportService: HighestProfitReportService;
        liveCommandService: LiveCommandService;
        liveLogicPrivateService: LiveLogicPrivateService;
        liveLogicPublicService: LiveLogicPublicService;
        liveMarkdownService: LiveMarkdownService;
        liveReportService: LiveReportService;
        loggerService: {
            _commonLogger: ILogger;
            _executionContext: {};
            _methodContext: {};
            debug: (topic: string, ...args: any[]) => Promise<void>;
            executionContextService: { context: IExecutionContext };
            info: (topic: string, ...args: any[]) => Promise<void>;
            log: (topic: string, ...args: any[]) => Promise<void>;
            methodContextService: { context: IMethodContext };
            setLogger: (logger: ILogger) => void;
            warn: (topic: string, ...args: any[]) => Promise<void>;
        };
        maxDrawdownMarkdownService: MaxDrawdownMarkdownService;
        maxDrawdownReportService: MaxDrawdownReportService;
        methodContextService: { context: IMethodContext };
        notificationHelperService: NotificationHelperService;
        partialConnectionService: PartialConnectionService;
        partialGlobalService: PartialGlobalService;
        partialMarkdownService: PartialMarkdownService;
        partialReportService: PartialReportService;
        performanceMarkdownService: PerformanceMarkdownService;
        performanceReportService: PerformanceReportService;
        priceMetaService: PriceMetaService;
        riskConnectionService: RiskConnectionService;
        riskGlobalService: RiskGlobalService;
        riskMarkdownService: RiskMarkdownService;
        riskReportService: RiskReportService;
        riskSchemaService: RiskSchemaService;
        riskValidationService: RiskValidationService;
        runtimeMetaService: {
            _getInfo: (
                context: {
                    exchangeName: string;
                    frameName: string;
                    strategyName: string;
                },
            ) => any & functools_kit.IClearableMemoize<string> & functools_kit.IControlMemoize<
                string,
                any,
            >;
            _getRange: (
                context: {
                    exchangeName: string;
                    frameName: string;
                    strategyName: string;
                },
                backtest: boolean,
            ) => any & functools_kit.IClearableMemoize<string> & functools_kit.IControlMemoize<
                string,
                any,
            >;
            frameSchemaService: FrameSchemaService;
            getRuntimeInfo: <Data extends RuntimeData = RuntimeData>(
                symbol: string,
                context: {
                    exchangeName: string;
                    frameName: string;
                    strategyName: string;
                },
                backtest: boolean,
            ) => Promise<IRuntimeInfo<Data>>;
            loggerService: {
                _commonLogger: ILogger;
                _executionContext: {};
                _methodContext: {};
                debug: (topic: string, ...args: any[]) => Promise<void>;
                executionContextService: { context: IExecutionContext };
                info: (topic: string, ...args: any[]) => Promise<void>;
                log: (topic: string, ...args: any[]) => Promise<void>;
                methodContextService: { context: IMethodContext };
                setLogger: (logger: ILogger) => void;
                warn: (topic: string, ...args: any[]) => Promise<void>;
            };
            priceMetaService: PriceMetaService;
            strategySchemaService: StrategySchemaService;
            timeMetaService: TimeMetaService;
        };
        scheduleMarkdownService: ScheduleMarkdownService;
        scheduleReportService: ScheduleReportService;
        sizingConnectionService: SizingConnectionService;
        sizingGlobalService: SizingGlobalService;
        sizingSchemaService: SizingSchemaService;
        sizingValidationService: SizingValidationService;
        strategyConnectionService: StrategyConnectionService;
        strategyCoreService: StrategyCoreService;
        strategyMarkdownService: StrategyMarkdownService;
        strategyReportService: StrategyReportService;
        strategySchemaService: StrategySchemaService;
        strategyValidationService: StrategyValidationService;
        syncMarkdownService: SyncMarkdownService;
        syncReportService: SyncReportService;
        timeMetaService: TimeMetaService;
        walkerCommandService: WalkerCommandService;
        walkerLogicPrivateService: WalkerLogicPrivateService;
        walkerLogicPublicService: WalkerLogicPublicService;
        walkerMarkdownService: WalkerMarkdownService;
        walkerReportService: WalkerReportService;
        walkerSchemaService: WalkerSchemaService;
        walkerValidationService: WalkerValidationService;
    }

    Type declaration

    • actionConnectionService: ActionConnectionService
    • actionCoreService: ActionCoreService
    • actionSchemaService: ActionSchemaService
    • actionValidationService: ActionValidationService
    • backtestCommandService: BacktestCommandService
    • backtestLogicPrivateService: BacktestLogicPrivateService
    • backtestLogicPublicService: BacktestLogicPublicService
    • backtestMarkdownService: BacktestMarkdownService
    • backtestReportService: BacktestReportService
    • breakevenConnectionService: BreakevenConnectionService
    • breakevenGlobalService: BreakevenGlobalService
    • breakevenMarkdownService: BreakevenMarkdownService
    • breakevenReportService: BreakevenReportService
    • columnValidationService: ColumnValidationService
    • configValidationService: ConfigValidationService
    • contextMetaService: {
          executionContextService: { context: IExecutionContext };
          getContextTimestamp: () => number;
          loggerService: {
              _commonLogger: ILogger;
              _executionContext: {};
              _methodContext: {};
              debug: (topic: string, ...args: any[]) => Promise<void>;
              executionContextService: { context: IExecutionContext };
              info: (topic: string, ...args: any[]) => Promise<void>;
              log: (topic: string, ...args: any[]) => Promise<void>;
              methodContextService: { context: IMethodContext };
              setLogger: (logger: ILogger) => void;
              warn: (topic: string, ...args: any[]) => Promise<void>;
          };
      }
    • exchangeConnectionService: ExchangeConnectionService
    • exchangeCoreService: ExchangeCoreService
    • exchangeSchemaService: ExchangeSchemaService
    • exchangeValidationService: ExchangeValidationService
    • executionContextService: { context: IExecutionContext }
    • frameConnectionService: FrameConnectionService
    • frameCoreService: FrameCoreService
    • frameSchemaService: FrameSchemaService
    • frameValidationService: FrameValidationService
    • heatMarkdownService: HeatMarkdownService
    • heatReportService: HeatReportService
    • highestProfitMarkdownService: HighestProfitMarkdownService
    • highestProfitReportService: HighestProfitReportService
    • liveCommandService: LiveCommandService
    • liveLogicPrivateService: LiveLogicPrivateService
    • liveLogicPublicService: LiveLogicPublicService
    • liveMarkdownService: LiveMarkdownService
    • liveReportService: LiveReportService
    • loggerService: {
          _commonLogger: ILogger;
          _executionContext: {};
          _methodContext: {};
          debug: (topic: string, ...args: any[]) => Promise<void>;
          executionContextService: { context: IExecutionContext };
          info: (topic: string, ...args: any[]) => Promise<void>;
          log: (topic: string, ...args: any[]) => Promise<void>;
          methodContextService: { context: IMethodContext };
          setLogger: (logger: ILogger) => void;
          warn: (topic: string, ...args: any[]) => Promise<void>;
      }
    • maxDrawdownMarkdownService: MaxDrawdownMarkdownService
    • maxDrawdownReportService: MaxDrawdownReportService
    • methodContextService: { context: IMethodContext }
    • notificationHelperService: NotificationHelperService
    • partialConnectionService: PartialConnectionService
    • partialGlobalService: PartialGlobalService
    • partialMarkdownService: PartialMarkdownService
    • partialReportService: PartialReportService
    • performanceMarkdownService: PerformanceMarkdownService
    • performanceReportService: PerformanceReportService
    • priceMetaService: PriceMetaService
    • riskConnectionService: RiskConnectionService
    • riskGlobalService: RiskGlobalService
    • riskMarkdownService: RiskMarkdownService
    • riskReportService: RiskReportService
    • riskSchemaService: RiskSchemaService
    • riskValidationService: RiskValidationService
    • runtimeMetaService: {
          _getInfo: (
              context: {
                  exchangeName: string;
                  frameName: string;
                  strategyName: string;
              },
          ) => any & functools_kit.IClearableMemoize<string> & functools_kit.IControlMemoize<
              string,
              any,
          >;
          _getRange: (
              context: {
                  exchangeName: string;
                  frameName: string;
                  strategyName: string;
              },
              backtest: boolean,
          ) => any & functools_kit.IClearableMemoize<string> & functools_kit.IControlMemoize<
              string,
              any,
          >;
          frameSchemaService: FrameSchemaService;
          getRuntimeInfo: <Data extends RuntimeData = RuntimeData>(
              symbol: string,
              context: { exchangeName: string; frameName: string; strategyName: string },
              backtest: boolean,
          ) => Promise<IRuntimeInfo<Data>>;
          loggerService: {
              _commonLogger: ILogger;
              _executionContext: {};
              _methodContext: {};
              debug: (topic: string, ...args: any[]) => Promise<void>;
              executionContextService: { context: IExecutionContext };
              info: (topic: string, ...args: any[]) => Promise<void>;
              log: (topic: string, ...args: any[]) => Promise<void>;
              methodContextService: { context: IMethodContext };
              setLogger: (logger: ILogger) => void;
              warn: (topic: string, ...args: any[]) => Promise<void>;
          };
          priceMetaService: PriceMetaService;
          strategySchemaService: StrategySchemaService;
          timeMetaService: TimeMetaService;
      }
    • scheduleMarkdownService: ScheduleMarkdownService
    • scheduleReportService: ScheduleReportService
    • sizingConnectionService: SizingConnectionService
    • sizingGlobalService: SizingGlobalService
    • sizingSchemaService: SizingSchemaService
    • sizingValidationService: SizingValidationService
    • strategyConnectionService: StrategyConnectionService
    • strategyCoreService: StrategyCoreService
    • strategyMarkdownService: StrategyMarkdownService
    • strategyReportService: StrategyReportService
    • strategySchemaService: StrategySchemaService
    • strategyValidationService: StrategyValidationService
    • syncMarkdownService: SyncMarkdownService
    • syncReportService: SyncReportService
    • timeMetaService: TimeMetaService
    • walkerCommandService: WalkerCommandService
    • walkerLogicPrivateService: WalkerLogicPrivateService
    • walkerLogicPublicService: WalkerLogicPublicService
    • walkerMarkdownService: WalkerMarkdownService
    • walkerReportService: WalkerReportService
    • walkerSchemaService: WalkerSchemaService
    • walkerValidationService: WalkerValidationService
    +lib | backtest-kit

    Variable libConst

    lib: {
        actionConnectionService: ActionConnectionService;
        actionCoreService: ActionCoreService;
        actionSchemaService: ActionSchemaService;
        actionValidationService: ActionValidationService;
        backtestCommandService: BacktestCommandService;
        backtestLogicPrivateService: BacktestLogicPrivateService;
        backtestLogicPublicService: BacktestLogicPublicService;
        backtestMarkdownService: BacktestMarkdownService;
        backtestReportService: BacktestReportService;
        breakevenConnectionService: BreakevenConnectionService;
        breakevenGlobalService: BreakevenGlobalService;
        breakevenMarkdownService: BreakevenMarkdownService;
        breakevenReportService: BreakevenReportService;
        columnValidationService: ColumnValidationService;
        configValidationService: ConfigValidationService;
        contextMetaService: {
            executionContextService: { context: IExecutionContext };
            getContextTimestamp: () => number;
            loggerService: {
                _commonLogger: ILogger;
                _executionContext: {};
                _methodContext: {};
                debug: (topic: string, ...args: any[]) => Promise<void>;
                executionContextService: { context: IExecutionContext };
                info: (topic: string, ...args: any[]) => Promise<void>;
                log: (topic: string, ...args: any[]) => Promise<void>;
                methodContextService: { context: IMethodContext };
                setLogger: (logger: ILogger) => void;
                warn: (topic: string, ...args: any[]) => Promise<void>;
            };
        };
        exchangeConnectionService: ExchangeConnectionService;
        exchangeCoreService: ExchangeCoreService;
        exchangeSchemaService: ExchangeSchemaService;
        exchangeValidationService: ExchangeValidationService;
        executionContextService: { context: IExecutionContext };
        frameConnectionService: FrameConnectionService;
        frameCoreService: FrameCoreService;
        frameSchemaService: FrameSchemaService;
        frameValidationService: FrameValidationService;
        heatMarkdownService: HeatMarkdownService;
        heatReportService: HeatReportService;
        highestProfitMarkdownService: HighestProfitMarkdownService;
        highestProfitReportService: HighestProfitReportService;
        liveCommandService: LiveCommandService;
        liveLogicPrivateService: LiveLogicPrivateService;
        liveLogicPublicService: LiveLogicPublicService;
        liveMarkdownService: LiveMarkdownService;
        liveReportService: LiveReportService;
        loggerService: {
            _commonLogger: ILogger;
            _executionContext: {};
            _methodContext: {};
            debug: (topic: string, ...args: any[]) => Promise<void>;
            executionContextService: { context: IExecutionContext };
            info: (topic: string, ...args: any[]) => Promise<void>;
            log: (topic: string, ...args: any[]) => Promise<void>;
            methodContextService: { context: IMethodContext };
            setLogger: (logger: ILogger) => void;
            warn: (topic: string, ...args: any[]) => Promise<void>;
        };
        maxDrawdownMarkdownService: MaxDrawdownMarkdownService;
        maxDrawdownReportService: MaxDrawdownReportService;
        methodContextService: { context: IMethodContext };
        notificationHelperService: NotificationHelperService;
        partialConnectionService: PartialConnectionService;
        partialGlobalService: PartialGlobalService;
        partialMarkdownService: PartialMarkdownService;
        partialReportService: PartialReportService;
        performanceMarkdownService: PerformanceMarkdownService;
        performanceReportService: PerformanceReportService;
        priceMetaService: PriceMetaService;
        riskConnectionService: RiskConnectionService;
        riskGlobalService: RiskGlobalService;
        riskMarkdownService: RiskMarkdownService;
        riskReportService: RiskReportService;
        riskSchemaService: RiskSchemaService;
        riskValidationService: RiskValidationService;
        runtimeMetaService: {
            _getInfo: (
                context: {
                    exchangeName: string;
                    frameName: string;
                    strategyName: string;
                },
            ) => any & functools_kit.IClearableMemoize<string> & functools_kit.IControlMemoize<
                string,
                any,
            >;
            _getRange: (
                context: {
                    exchangeName: string;
                    frameName: string;
                    strategyName: string;
                },
                backtest: boolean,
            ) => any & functools_kit.IClearableMemoize<string> & functools_kit.IControlMemoize<
                string,
                any,
            >;
            frameSchemaService: FrameSchemaService;
            getRuntimeInfo: <Data extends RuntimeData = RuntimeData>(
                symbol: string,
                context: {
                    exchangeName: string;
                    frameName: string;
                    strategyName: string;
                },
                backtest: boolean,
            ) => Promise<IRuntimeInfo<Data>>;
            loggerService: {
                _commonLogger: ILogger;
                _executionContext: {};
                _methodContext: {};
                debug: (topic: string, ...args: any[]) => Promise<void>;
                executionContextService: { context: IExecutionContext };
                info: (topic: string, ...args: any[]) => Promise<void>;
                log: (topic: string, ...args: any[]) => Promise<void>;
                methodContextService: { context: IMethodContext };
                setLogger: (logger: ILogger) => void;
                warn: (topic: string, ...args: any[]) => Promise<void>;
            };
            priceMetaService: PriceMetaService;
            strategySchemaService: StrategySchemaService;
            timeMetaService: TimeMetaService;
        };
        scheduleMarkdownService: ScheduleMarkdownService;
        scheduleReportService: ScheduleReportService;
        sizingConnectionService: SizingConnectionService;
        sizingGlobalService: SizingGlobalService;
        sizingSchemaService: SizingSchemaService;
        sizingValidationService: SizingValidationService;
        strategyConnectionService: StrategyConnectionService;
        strategyCoreService: StrategyCoreService;
        strategyMarkdownService: StrategyMarkdownService;
        strategyReportService: StrategyReportService;
        strategySchemaService: StrategySchemaService;
        strategyValidationService: StrategyValidationService;
        syncMarkdownService: SyncMarkdownService;
        syncReportService: SyncReportService;
        timeMetaService: TimeMetaService;
        walkerCommandService: WalkerCommandService;
        walkerLogicPrivateService: WalkerLogicPrivateService;
        walkerLogicPublicService: WalkerLogicPublicService;
        walkerMarkdownService: WalkerMarkdownService;
        walkerReportService: WalkerReportService;
        walkerSchemaService: WalkerSchemaService;
        walkerValidationService: WalkerValidationService;
    }

    Type declaration

    • actionConnectionService: ActionConnectionService
    • actionCoreService: ActionCoreService
    • actionSchemaService: ActionSchemaService
    • actionValidationService: ActionValidationService
    • backtestCommandService: BacktestCommandService
    • backtestLogicPrivateService: BacktestLogicPrivateService
    • backtestLogicPublicService: BacktestLogicPublicService
    • backtestMarkdownService: BacktestMarkdownService
    • backtestReportService: BacktestReportService
    • breakevenConnectionService: BreakevenConnectionService
    • breakevenGlobalService: BreakevenGlobalService
    • breakevenMarkdownService: BreakevenMarkdownService
    • breakevenReportService: BreakevenReportService
    • columnValidationService: ColumnValidationService
    • configValidationService: ConfigValidationService
    • contextMetaService: {
          executionContextService: { context: IExecutionContext };
          getContextTimestamp: () => number;
          loggerService: {
              _commonLogger: ILogger;
              _executionContext: {};
              _methodContext: {};
              debug: (topic: string, ...args: any[]) => Promise<void>;
              executionContextService: { context: IExecutionContext };
              info: (topic: string, ...args: any[]) => Promise<void>;
              log: (topic: string, ...args: any[]) => Promise<void>;
              methodContextService: { context: IMethodContext };
              setLogger: (logger: ILogger) => void;
              warn: (topic: string, ...args: any[]) => Promise<void>;
          };
      }
    • exchangeConnectionService: ExchangeConnectionService
    • exchangeCoreService: ExchangeCoreService
    • exchangeSchemaService: ExchangeSchemaService
    • exchangeValidationService: ExchangeValidationService
    • executionContextService: { context: IExecutionContext }
    • frameConnectionService: FrameConnectionService
    • frameCoreService: FrameCoreService
    • frameSchemaService: FrameSchemaService
    • frameValidationService: FrameValidationService
    • heatMarkdownService: HeatMarkdownService
    • heatReportService: HeatReportService
    • highestProfitMarkdownService: HighestProfitMarkdownService
    • highestProfitReportService: HighestProfitReportService
    • liveCommandService: LiveCommandService
    • liveLogicPrivateService: LiveLogicPrivateService
    • liveLogicPublicService: LiveLogicPublicService
    • liveMarkdownService: LiveMarkdownService
    • liveReportService: LiveReportService
    • loggerService: {
          _commonLogger: ILogger;
          _executionContext: {};
          _methodContext: {};
          debug: (topic: string, ...args: any[]) => Promise<void>;
          executionContextService: { context: IExecutionContext };
          info: (topic: string, ...args: any[]) => Promise<void>;
          log: (topic: string, ...args: any[]) => Promise<void>;
          methodContextService: { context: IMethodContext };
          setLogger: (logger: ILogger) => void;
          warn: (topic: string, ...args: any[]) => Promise<void>;
      }
    • maxDrawdownMarkdownService: MaxDrawdownMarkdownService
    • maxDrawdownReportService: MaxDrawdownReportService
    • methodContextService: { context: IMethodContext }
    • notificationHelperService: NotificationHelperService
    • partialConnectionService: PartialConnectionService
    • partialGlobalService: PartialGlobalService
    • partialMarkdownService: PartialMarkdownService
    • partialReportService: PartialReportService
    • performanceMarkdownService: PerformanceMarkdownService
    • performanceReportService: PerformanceReportService
    • priceMetaService: PriceMetaService
    • riskConnectionService: RiskConnectionService
    • riskGlobalService: RiskGlobalService
    • riskMarkdownService: RiskMarkdownService
    • riskReportService: RiskReportService
    • riskSchemaService: RiskSchemaService
    • riskValidationService: RiskValidationService
    • runtimeMetaService: {
          _getInfo: (
              context: {
                  exchangeName: string;
                  frameName: string;
                  strategyName: string;
              },
          ) => any & functools_kit.IClearableMemoize<string> & functools_kit.IControlMemoize<
              string,
              any,
          >;
          _getRange: (
              context: {
                  exchangeName: string;
                  frameName: string;
                  strategyName: string;
              },
              backtest: boolean,
          ) => any & functools_kit.IClearableMemoize<string> & functools_kit.IControlMemoize<
              string,
              any,
          >;
          frameSchemaService: FrameSchemaService;
          getRuntimeInfo: <Data extends RuntimeData = RuntimeData>(
              symbol: string,
              context: { exchangeName: string; frameName: string; strategyName: string },
              backtest: boolean,
          ) => Promise<IRuntimeInfo<Data>>;
          loggerService: {
              _commonLogger: ILogger;
              _executionContext: {};
              _methodContext: {};
              debug: (topic: string, ...args: any[]) => Promise<void>;
              executionContextService: { context: IExecutionContext };
              info: (topic: string, ...args: any[]) => Promise<void>;
              log: (topic: string, ...args: any[]) => Promise<void>;
              methodContextService: { context: IMethodContext };
              setLogger: (logger: ILogger) => void;
              warn: (topic: string, ...args: any[]) => Promise<void>;
          };
          priceMetaService: PriceMetaService;
          strategySchemaService: StrategySchemaService;
          timeMetaService: TimeMetaService;
      }
    • scheduleMarkdownService: ScheduleMarkdownService
    • scheduleReportService: ScheduleReportService
    • sizingConnectionService: SizingConnectionService
    • sizingGlobalService: SizingGlobalService
    • sizingSchemaService: SizingSchemaService
    • sizingValidationService: SizingValidationService
    • strategyConnectionService: StrategyConnectionService
    • strategyCoreService: StrategyCoreService
    • strategyMarkdownService: StrategyMarkdownService
    • strategyReportService: StrategyReportService
    • strategySchemaService: StrategySchemaService
    • strategyValidationService: StrategyValidationService
    • syncMarkdownService: SyncMarkdownService
    • syncReportService: SyncReportService
    • timeMetaService: TimeMetaService
    • walkerCommandService: WalkerCommandService
    • walkerLogicPrivateService: WalkerLogicPrivateService
    • walkerLogicPublicService: WalkerLogicPublicService
    • walkerMarkdownService: WalkerMarkdownService
    • walkerReportService: WalkerReportService
    • walkerSchemaService: WalkerSchemaService
    • walkerValidationService: WalkerValidationService