Compare commits
7 Commits
93d5ac8a30
...
15a5d7c67b
| Author | SHA1 | Date | |
|---|---|---|---|
| 15a5d7c67b | |||
| fe1265810d | |||
| 8d908521fd | |||
| 5b3e9f85f6 | |||
| 666ff16583 | |||
| 35b3278d08 | |||
| 704d59a363 |
@@ -1,2 +1,4 @@
|
||||
.pnpm-store
|
||||
node_modules
|
||||
.aider*
|
||||
.env
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
nodejs 20.15.1
|
||||
python 3.12.4
|
||||
@@ -28,6 +28,7 @@
|
||||
"@types/node": "^20.10.7",
|
||||
"esbuild": "^0.19.11",
|
||||
"npm-run-all": "^4.1.5",
|
||||
"tsx": "^4.17.0",
|
||||
"typescript": "^5.3.3"
|
||||
}
|
||||
}
|
||||
Generated
+283
@@ -63,6 +63,9 @@ importers:
|
||||
npm-run-all:
|
||||
specifier: ^4.1.5
|
||||
version: 4.1.5
|
||||
tsx:
|
||||
specifier: ^4.17.0
|
||||
version: 4.17.0
|
||||
typescript:
|
||||
specifier: ^5.3.3
|
||||
version: 5.3.3
|
||||
@@ -82,138 +85,282 @@ packages:
|
||||
cpu: [ppc64]
|
||||
os: [aix]
|
||||
|
||||
'@esbuild/aix-ppc64@0.23.0':
|
||||
resolution: {integrity: sha512-3sG8Zwa5fMcA9bgqB8AfWPQ+HFke6uD3h1s3RIwUNK8EG7a4buxvuFTs3j1IMs2NXAk9F30C/FF4vxRgQCcmoQ==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [ppc64]
|
||||
os: [aix]
|
||||
|
||||
'@esbuild/android-arm64@0.19.11':
|
||||
resolution: {integrity: sha512-aiu7K/5JnLj//KOnOfEZ0D90obUkRzDMyqd/wNAUQ34m4YUPVhRZpnqKV9uqDGxT7cToSDnIHsGooyIczu9T+Q==}
|
||||
engines: {node: '>=12'}
|
||||
cpu: [arm64]
|
||||
os: [android]
|
||||
|
||||
'@esbuild/android-arm64@0.23.0':
|
||||
resolution: {integrity: sha512-EuHFUYkAVfU4qBdyivULuu03FhJO4IJN9PGuABGrFy4vUuzk91P2d+npxHcFdpUnfYKy0PuV+n6bKIpHOB3prQ==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [arm64]
|
||||
os: [android]
|
||||
|
||||
'@esbuild/android-arm@0.19.11':
|
||||
resolution: {integrity: sha512-5OVapq0ClabvKvQ58Bws8+wkLCV+Rxg7tUVbo9xu034Nm536QTII4YzhaFriQ7rMrorfnFKUsArD2lqKbFY4vw==}
|
||||
engines: {node: '>=12'}
|
||||
cpu: [arm]
|
||||
os: [android]
|
||||
|
||||
'@esbuild/android-arm@0.23.0':
|
||||
resolution: {integrity: sha512-+KuOHTKKyIKgEEqKbGTK8W7mPp+hKinbMBeEnNzjJGyFcWsfrXjSTNluJHCY1RqhxFurdD8uNXQDei7qDlR6+g==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [arm]
|
||||
os: [android]
|
||||
|
||||
'@esbuild/android-x64@0.19.11':
|
||||
resolution: {integrity: sha512-eccxjlfGw43WYoY9QgB82SgGgDbibcqyDTlk3l3C0jOVHKxrjdc9CTwDUQd0vkvYg5um0OH+GpxYvp39r+IPOg==}
|
||||
engines: {node: '>=12'}
|
||||
cpu: [x64]
|
||||
os: [android]
|
||||
|
||||
'@esbuild/android-x64@0.23.0':
|
||||
resolution: {integrity: sha512-WRrmKidLoKDl56LsbBMhzTTBxrsVwTKdNbKDalbEZr0tcsBgCLbEtoNthOW6PX942YiYq8HzEnb4yWQMLQuipQ==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [x64]
|
||||
os: [android]
|
||||
|
||||
'@esbuild/darwin-arm64@0.19.11':
|
||||
resolution: {integrity: sha512-ETp87DRWuSt9KdDVkqSoKoLFHYTrkyz2+65fj9nfXsaV3bMhTCjtQfw3y+um88vGRKRiF7erPrh/ZuIdLUIVxQ==}
|
||||
engines: {node: '>=12'}
|
||||
cpu: [arm64]
|
||||
os: [darwin]
|
||||
|
||||
'@esbuild/darwin-arm64@0.23.0':
|
||||
resolution: {integrity: sha512-YLntie/IdS31H54Ogdn+v50NuoWF5BDkEUFpiOChVa9UnKpftgwzZRrI4J132ETIi+D8n6xh9IviFV3eXdxfow==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [arm64]
|
||||
os: [darwin]
|
||||
|
||||
'@esbuild/darwin-x64@0.19.11':
|
||||
resolution: {integrity: sha512-fkFUiS6IUK9WYUO/+22omwetaSNl5/A8giXvQlcinLIjVkxwTLSktbF5f/kJMftM2MJp9+fXqZ5ezS7+SALp4g==}
|
||||
engines: {node: '>=12'}
|
||||
cpu: [x64]
|
||||
os: [darwin]
|
||||
|
||||
'@esbuild/darwin-x64@0.23.0':
|
||||
resolution: {integrity: sha512-IMQ6eme4AfznElesHUPDZ+teuGwoRmVuuixu7sv92ZkdQcPbsNHzutd+rAfaBKo8YK3IrBEi9SLLKWJdEvJniQ==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [x64]
|
||||
os: [darwin]
|
||||
|
||||
'@esbuild/freebsd-arm64@0.19.11':
|
||||
resolution: {integrity: sha512-lhoSp5K6bxKRNdXUtHoNc5HhbXVCS8V0iZmDvyWvYq9S5WSfTIHU2UGjcGt7UeS6iEYp9eeymIl5mJBn0yiuxA==}
|
||||
engines: {node: '>=12'}
|
||||
cpu: [arm64]
|
||||
os: [freebsd]
|
||||
|
||||
'@esbuild/freebsd-arm64@0.23.0':
|
||||
resolution: {integrity: sha512-0muYWCng5vqaxobq6LB3YNtevDFSAZGlgtLoAc81PjUfiFz36n4KMpwhtAd4he8ToSI3TGyuhyx5xmiWNYZFyw==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [arm64]
|
||||
os: [freebsd]
|
||||
|
||||
'@esbuild/freebsd-x64@0.19.11':
|
||||
resolution: {integrity: sha512-JkUqn44AffGXitVI6/AbQdoYAq0TEullFdqcMY/PCUZ36xJ9ZJRtQabzMA+Vi7r78+25ZIBosLTOKnUXBSi1Kw==}
|
||||
engines: {node: '>=12'}
|
||||
cpu: [x64]
|
||||
os: [freebsd]
|
||||
|
||||
'@esbuild/freebsd-x64@0.23.0':
|
||||
resolution: {integrity: sha512-XKDVu8IsD0/q3foBzsXGt/KjD/yTKBCIwOHE1XwiXmrRwrX6Hbnd5Eqn/WvDekddK21tfszBSrE/WMaZh+1buQ==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [x64]
|
||||
os: [freebsd]
|
||||
|
||||
'@esbuild/linux-arm64@0.19.11':
|
||||
resolution: {integrity: sha512-LneLg3ypEeveBSMuoa0kwMpCGmpu8XQUh+mL8XXwoYZ6Be2qBnVtcDI5azSvh7vioMDhoJFZzp9GWp9IWpYoUg==}
|
||||
engines: {node: '>=12'}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
|
||||
'@esbuild/linux-arm64@0.23.0':
|
||||
resolution: {integrity: sha512-j1t5iG8jE7BhonbsEg5d9qOYcVZv/Rv6tghaXM/Ug9xahM0nX/H2gfu6X6z11QRTMT6+aywOMA8TDkhPo8aCGw==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
|
||||
'@esbuild/linux-arm@0.19.11':
|
||||
resolution: {integrity: sha512-3CRkr9+vCV2XJbjwgzjPtO8T0SZUmRZla+UL1jw+XqHZPkPgZiyWvbDvl9rqAN8Zl7qJF0O/9ycMtjU67HN9/Q==}
|
||||
engines: {node: '>=12'}
|
||||
cpu: [arm]
|
||||
os: [linux]
|
||||
|
||||
'@esbuild/linux-arm@0.23.0':
|
||||
resolution: {integrity: sha512-SEELSTEtOFu5LPykzA395Mc+54RMg1EUgXP+iw2SJ72+ooMwVsgfuwXo5Fn0wXNgWZsTVHwY2cg4Vi/bOD88qw==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [arm]
|
||||
os: [linux]
|
||||
|
||||
'@esbuild/linux-ia32@0.19.11':
|
||||
resolution: {integrity: sha512-caHy++CsD8Bgq2V5CodbJjFPEiDPq8JJmBdeyZ8GWVQMjRD0sU548nNdwPNvKjVpamYYVL40AORekgfIubwHoA==}
|
||||
engines: {node: '>=12'}
|
||||
cpu: [ia32]
|
||||
os: [linux]
|
||||
|
||||
'@esbuild/linux-ia32@0.23.0':
|
||||
resolution: {integrity: sha512-P7O5Tkh2NbgIm2R6x1zGJJsnacDzTFcRWZyTTMgFdVit6E98LTxO+v8LCCLWRvPrjdzXHx9FEOA8oAZPyApWUA==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [ia32]
|
||||
os: [linux]
|
||||
|
||||
'@esbuild/linux-loong64@0.19.11':
|
||||
resolution: {integrity: sha512-ppZSSLVpPrwHccvC6nQVZaSHlFsvCQyjnvirnVjbKSHuE5N24Yl8F3UwYUUR1UEPaFObGD2tSvVKbvR+uT1Nrg==}
|
||||
engines: {node: '>=12'}
|
||||
cpu: [loong64]
|
||||
os: [linux]
|
||||
|
||||
'@esbuild/linux-loong64@0.23.0':
|
||||
resolution: {integrity: sha512-InQwepswq6urikQiIC/kkx412fqUZudBO4SYKu0N+tGhXRWUqAx+Q+341tFV6QdBifpjYgUndV1hhMq3WeJi7A==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [loong64]
|
||||
os: [linux]
|
||||
|
||||
'@esbuild/linux-mips64el@0.19.11':
|
||||
resolution: {integrity: sha512-B5x9j0OgjG+v1dF2DkH34lr+7Gmv0kzX6/V0afF41FkPMMqaQ77pH7CrhWeR22aEeHKaeZVtZ6yFwlxOKPVFyg==}
|
||||
engines: {node: '>=12'}
|
||||
cpu: [mips64el]
|
||||
os: [linux]
|
||||
|
||||
'@esbuild/linux-mips64el@0.23.0':
|
||||
resolution: {integrity: sha512-J9rflLtqdYrxHv2FqXE2i1ELgNjT+JFURt/uDMoPQLcjWQA5wDKgQA4t/dTqGa88ZVECKaD0TctwsUfHbVoi4w==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [mips64el]
|
||||
os: [linux]
|
||||
|
||||
'@esbuild/linux-ppc64@0.19.11':
|
||||
resolution: {integrity: sha512-MHrZYLeCG8vXblMetWyttkdVRjQlQUb/oMgBNurVEnhj4YWOr4G5lmBfZjHYQHHN0g6yDmCAQRR8MUHldvvRDA==}
|
||||
engines: {node: '>=12'}
|
||||
cpu: [ppc64]
|
||||
os: [linux]
|
||||
|
||||
'@esbuild/linux-ppc64@0.23.0':
|
||||
resolution: {integrity: sha512-cShCXtEOVc5GxU0fM+dsFD10qZ5UpcQ8AM22bYj0u/yaAykWnqXJDpd77ublcX6vdDsWLuweeuSNZk4yUxZwtw==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [ppc64]
|
||||
os: [linux]
|
||||
|
||||
'@esbuild/linux-riscv64@0.19.11':
|
||||
resolution: {integrity: sha512-f3DY++t94uVg141dozDu4CCUkYW+09rWtaWfnb3bqe4w5NqmZd6nPVBm+qbz7WaHZCoqXqHz5p6CM6qv3qnSSQ==}
|
||||
engines: {node: '>=12'}
|
||||
cpu: [riscv64]
|
||||
os: [linux]
|
||||
|
||||
'@esbuild/linux-riscv64@0.23.0':
|
||||
resolution: {integrity: sha512-HEtaN7Y5UB4tZPeQmgz/UhzoEyYftbMXrBCUjINGjh3uil+rB/QzzpMshz3cNUxqXN7Vr93zzVtpIDL99t9aRw==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [riscv64]
|
||||
os: [linux]
|
||||
|
||||
'@esbuild/linux-s390x@0.19.11':
|
||||
resolution: {integrity: sha512-A5xdUoyWJHMMlcSMcPGVLzYzpcY8QP1RtYzX5/bS4dvjBGVxdhuiYyFwp7z74ocV7WDc0n1harxmpq2ePOjI0Q==}
|
||||
engines: {node: '>=12'}
|
||||
cpu: [s390x]
|
||||
os: [linux]
|
||||
|
||||
'@esbuild/linux-s390x@0.23.0':
|
||||
resolution: {integrity: sha512-WDi3+NVAuyjg/Wxi+o5KPqRbZY0QhI9TjrEEm+8dmpY9Xir8+HE/HNx2JoLckhKbFopW0RdO2D72w8trZOV+Wg==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [s390x]
|
||||
os: [linux]
|
||||
|
||||
'@esbuild/linux-x64@0.19.11':
|
||||
resolution: {integrity: sha512-grbyMlVCvJSfxFQUndw5mCtWs5LO1gUlwP4CDi4iJBbVpZcqLVT29FxgGuBJGSzyOxotFG4LoO5X+M1350zmPA==}
|
||||
engines: {node: '>=12'}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
|
||||
'@esbuild/linux-x64@0.23.0':
|
||||
resolution: {integrity: sha512-a3pMQhUEJkITgAw6e0bWA+F+vFtCciMjW/LPtoj99MhVt+Mfb6bbL9hu2wmTZgNd994qTAEw+U/r6k3qHWWaOQ==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
|
||||
'@esbuild/netbsd-x64@0.19.11':
|
||||
resolution: {integrity: sha512-13jvrQZJc3P230OhU8xgwUnDeuC/9egsjTkXN49b3GcS5BKvJqZn86aGM8W9pd14Kd+u7HuFBMVtrNGhh6fHEQ==}
|
||||
engines: {node: '>=12'}
|
||||
cpu: [x64]
|
||||
os: [netbsd]
|
||||
|
||||
'@esbuild/netbsd-x64@0.23.0':
|
||||
resolution: {integrity: sha512-cRK+YDem7lFTs2Q5nEv/HHc4LnrfBCbH5+JHu6wm2eP+d8OZNoSMYgPZJq78vqQ9g+9+nMuIsAO7skzphRXHyw==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [x64]
|
||||
os: [netbsd]
|
||||
|
||||
'@esbuild/openbsd-arm64@0.23.0':
|
||||
resolution: {integrity: sha512-suXjq53gERueVWu0OKxzWqk7NxiUWSUlrxoZK7usiF50C6ipColGR5qie2496iKGYNLhDZkPxBI3erbnYkU0rQ==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [arm64]
|
||||
os: [openbsd]
|
||||
|
||||
'@esbuild/openbsd-x64@0.19.11':
|
||||
resolution: {integrity: sha512-ysyOGZuTp6SNKPE11INDUeFVVQFrhcNDVUgSQVDzqsqX38DjhPEPATpid04LCoUr2WXhQTEZ8ct/EgJCUDpyNw==}
|
||||
engines: {node: '>=12'}
|
||||
cpu: [x64]
|
||||
os: [openbsd]
|
||||
|
||||
'@esbuild/openbsd-x64@0.23.0':
|
||||
resolution: {integrity: sha512-6p3nHpby0DM/v15IFKMjAaayFhqnXV52aEmv1whZHX56pdkK+MEaLoQWj+H42ssFarP1PcomVhbsR4pkz09qBg==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [x64]
|
||||
os: [openbsd]
|
||||
|
||||
'@esbuild/sunos-x64@0.19.11':
|
||||
resolution: {integrity: sha512-Hf+Sad9nVwvtxy4DXCZQqLpgmRTQqyFyhT3bZ4F2XlJCjxGmRFF0Shwn9rzhOYRB61w9VMXUkxlBy56dk9JJiQ==}
|
||||
engines: {node: '>=12'}
|
||||
cpu: [x64]
|
||||
os: [sunos]
|
||||
|
||||
'@esbuild/sunos-x64@0.23.0':
|
||||
resolution: {integrity: sha512-BFelBGfrBwk6LVrmFzCq1u1dZbG4zy/Kp93w2+y83Q5UGYF1d8sCzeLI9NXjKyujjBBniQa8R8PzLFAUrSM9OA==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [x64]
|
||||
os: [sunos]
|
||||
|
||||
'@esbuild/win32-arm64@0.19.11':
|
||||
resolution: {integrity: sha512-0P58Sbi0LctOMOQbpEOvOL44Ne0sqbS0XWHMvvrg6NE5jQ1xguCSSw9jQeUk2lfrXYsKDdOe6K+oZiwKPilYPQ==}
|
||||
engines: {node: '>=12'}
|
||||
cpu: [arm64]
|
||||
os: [win32]
|
||||
|
||||
'@esbuild/win32-arm64@0.23.0':
|
||||
resolution: {integrity: sha512-lY6AC8p4Cnb7xYHuIxQ6iYPe6MfO2CC43XXKo9nBXDb35krYt7KGhQnOkRGar5psxYkircpCqfbNDB4uJbS2jQ==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [arm64]
|
||||
os: [win32]
|
||||
|
||||
'@esbuild/win32-ia32@0.19.11':
|
||||
resolution: {integrity: sha512-6YOrWS+sDJDmshdBIQU+Uoyh7pQKrdykdefC1avn76ss5c+RN6gut3LZA4E2cH5xUEp5/cA0+YxRaVtRAb0xBg==}
|
||||
engines: {node: '>=12'}
|
||||
cpu: [ia32]
|
||||
os: [win32]
|
||||
|
||||
'@esbuild/win32-ia32@0.23.0':
|
||||
resolution: {integrity: sha512-7L1bHlOTcO4ByvI7OXVI5pNN6HSu6pUQq9yodga8izeuB1KcT2UkHaH6118QJwopExPn0rMHIseCTx1CRo/uNA==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [ia32]
|
||||
os: [win32]
|
||||
|
||||
'@esbuild/win32-x64@0.19.11':
|
||||
resolution: {integrity: sha512-vfkhltrjCAb603XaFhqhAF4LGDi2M4OrCRrFusyQ+iTLQ/o60QQXxc9cZC/FFpihBI9N1Grn6SMKVJ4KP7Fuiw==}
|
||||
engines: {node: '>=12'}
|
||||
cpu: [x64]
|
||||
os: [win32]
|
||||
|
||||
'@esbuild/win32-x64@0.23.0':
|
||||
resolution: {integrity: sha512-Arm+WgUFLUATuoxCJcahGuk6Yj9Pzxd6l11Zb/2aAuv5kWWvvfhLFo2fni4uSK5vzlUdCGZ/BdV5tH8klj8p8g==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [x64]
|
||||
os: [win32]
|
||||
|
||||
'@gar/promisify@1.1.3':
|
||||
resolution: {integrity: sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw==}
|
||||
|
||||
@@ -462,6 +609,11 @@ packages:
|
||||
engines: {node: '>=12'}
|
||||
hasBin: true
|
||||
|
||||
esbuild@0.23.0:
|
||||
resolution: {integrity: sha512-1lvV17H2bMYda/WaFb2jLPeHU3zml2k4/yagNMG8Q/YtfMjCwEUZa2eXXMgZTVSL5q1n4H7sQ0X6CdJDqqeCFA==}
|
||||
engines: {node: '>=18'}
|
||||
hasBin: true
|
||||
|
||||
escape-string-regexp@1.0.5:
|
||||
resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==}
|
||||
engines: {node: '>=0.8.0'}
|
||||
@@ -497,6 +649,11 @@ packages:
|
||||
fs.realpath@1.0.0:
|
||||
resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==}
|
||||
|
||||
fsevents@2.3.3:
|
||||
resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==}
|
||||
engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
|
||||
os: [darwin]
|
||||
|
||||
function-bind@1.1.2:
|
||||
resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==}
|
||||
|
||||
@@ -523,6 +680,9 @@ packages:
|
||||
resolution: {integrity: sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
get-tsconfig@4.7.6:
|
||||
resolution: {integrity: sha512-ZAqrLlu18NbDdRaHq+AKXzAmqIUPswPWKUchfytdAjiRFnCe5ojG2bstg6mRiZabkKfCoL/e98pbBELIV/YCeA==}
|
||||
|
||||
github-from-package@0.0.0:
|
||||
resolution: {integrity: sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==}
|
||||
|
||||
@@ -986,6 +1146,9 @@ packages:
|
||||
resolution: {integrity: sha512-sy6TXMN+hnP/wMy+ISxg3krXx7BAtWVO4UouuCN/ziM9UEne0euamVNafDfvC83bRNr95y0V5iijeDQFUNpvrg==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
resolve-pkg-maps@1.0.0:
|
||||
resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==}
|
||||
|
||||
resolve@1.22.8:
|
||||
resolution: {integrity: sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==}
|
||||
hasBin: true
|
||||
@@ -1164,6 +1327,11 @@ packages:
|
||||
resolution: {integrity: sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==}
|
||||
engines: {node: '>=10'}
|
||||
|
||||
tsx@4.17.0:
|
||||
resolution: {integrity: sha512-eN4mnDA5UMKDt4YZixo9tBioibaMBpoxBkD+rIPAjVmYERSG0/dWEY1CEFuV89CgASlKL499q8AhmkMnnjtOJg==}
|
||||
engines: {node: '>=18.0.0'}
|
||||
hasBin: true
|
||||
|
||||
tunnel-agent@0.6.0:
|
||||
resolution: {integrity: sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==}
|
||||
|
||||
@@ -1252,72 +1420,144 @@ snapshots:
|
||||
'@esbuild/aix-ppc64@0.19.11':
|
||||
optional: true
|
||||
|
||||
'@esbuild/aix-ppc64@0.23.0':
|
||||
optional: true
|
||||
|
||||
'@esbuild/android-arm64@0.19.11':
|
||||
optional: true
|
||||
|
||||
'@esbuild/android-arm64@0.23.0':
|
||||
optional: true
|
||||
|
||||
'@esbuild/android-arm@0.19.11':
|
||||
optional: true
|
||||
|
||||
'@esbuild/android-arm@0.23.0':
|
||||
optional: true
|
||||
|
||||
'@esbuild/android-x64@0.19.11':
|
||||
optional: true
|
||||
|
||||
'@esbuild/android-x64@0.23.0':
|
||||
optional: true
|
||||
|
||||
'@esbuild/darwin-arm64@0.19.11':
|
||||
optional: true
|
||||
|
||||
'@esbuild/darwin-arm64@0.23.0':
|
||||
optional: true
|
||||
|
||||
'@esbuild/darwin-x64@0.19.11':
|
||||
optional: true
|
||||
|
||||
'@esbuild/darwin-x64@0.23.0':
|
||||
optional: true
|
||||
|
||||
'@esbuild/freebsd-arm64@0.19.11':
|
||||
optional: true
|
||||
|
||||
'@esbuild/freebsd-arm64@0.23.0':
|
||||
optional: true
|
||||
|
||||
'@esbuild/freebsd-x64@0.19.11':
|
||||
optional: true
|
||||
|
||||
'@esbuild/freebsd-x64@0.23.0':
|
||||
optional: true
|
||||
|
||||
'@esbuild/linux-arm64@0.19.11':
|
||||
optional: true
|
||||
|
||||
'@esbuild/linux-arm64@0.23.0':
|
||||
optional: true
|
||||
|
||||
'@esbuild/linux-arm@0.19.11':
|
||||
optional: true
|
||||
|
||||
'@esbuild/linux-arm@0.23.0':
|
||||
optional: true
|
||||
|
||||
'@esbuild/linux-ia32@0.19.11':
|
||||
optional: true
|
||||
|
||||
'@esbuild/linux-ia32@0.23.0':
|
||||
optional: true
|
||||
|
||||
'@esbuild/linux-loong64@0.19.11':
|
||||
optional: true
|
||||
|
||||
'@esbuild/linux-loong64@0.23.0':
|
||||
optional: true
|
||||
|
||||
'@esbuild/linux-mips64el@0.19.11':
|
||||
optional: true
|
||||
|
||||
'@esbuild/linux-mips64el@0.23.0':
|
||||
optional: true
|
||||
|
||||
'@esbuild/linux-ppc64@0.19.11':
|
||||
optional: true
|
||||
|
||||
'@esbuild/linux-ppc64@0.23.0':
|
||||
optional: true
|
||||
|
||||
'@esbuild/linux-riscv64@0.19.11':
|
||||
optional: true
|
||||
|
||||
'@esbuild/linux-riscv64@0.23.0':
|
||||
optional: true
|
||||
|
||||
'@esbuild/linux-s390x@0.19.11':
|
||||
optional: true
|
||||
|
||||
'@esbuild/linux-s390x@0.23.0':
|
||||
optional: true
|
||||
|
||||
'@esbuild/linux-x64@0.19.11':
|
||||
optional: true
|
||||
|
||||
'@esbuild/linux-x64@0.23.0':
|
||||
optional: true
|
||||
|
||||
'@esbuild/netbsd-x64@0.19.11':
|
||||
optional: true
|
||||
|
||||
'@esbuild/netbsd-x64@0.23.0':
|
||||
optional: true
|
||||
|
||||
'@esbuild/openbsd-arm64@0.23.0':
|
||||
optional: true
|
||||
|
||||
'@esbuild/openbsd-x64@0.19.11':
|
||||
optional: true
|
||||
|
||||
'@esbuild/openbsd-x64@0.23.0':
|
||||
optional: true
|
||||
|
||||
'@esbuild/sunos-x64@0.19.11':
|
||||
optional: true
|
||||
|
||||
'@esbuild/sunos-x64@0.23.0':
|
||||
optional: true
|
||||
|
||||
'@esbuild/win32-arm64@0.19.11':
|
||||
optional: true
|
||||
|
||||
'@esbuild/win32-arm64@0.23.0':
|
||||
optional: true
|
||||
|
||||
'@esbuild/win32-ia32@0.19.11':
|
||||
optional: true
|
||||
|
||||
'@esbuild/win32-ia32@0.23.0':
|
||||
optional: true
|
||||
|
||||
'@esbuild/win32-x64@0.19.11':
|
||||
optional: true
|
||||
|
||||
'@esbuild/win32-x64@0.23.0':
|
||||
optional: true
|
||||
|
||||
'@gar/promisify@1.1.3':
|
||||
optional: true
|
||||
|
||||
@@ -1658,6 +1898,33 @@ snapshots:
|
||||
'@esbuild/win32-ia32': 0.19.11
|
||||
'@esbuild/win32-x64': 0.19.11
|
||||
|
||||
esbuild@0.23.0:
|
||||
optionalDependencies:
|
||||
'@esbuild/aix-ppc64': 0.23.0
|
||||
'@esbuild/android-arm': 0.23.0
|
||||
'@esbuild/android-arm64': 0.23.0
|
||||
'@esbuild/android-x64': 0.23.0
|
||||
'@esbuild/darwin-arm64': 0.23.0
|
||||
'@esbuild/darwin-x64': 0.23.0
|
||||
'@esbuild/freebsd-arm64': 0.23.0
|
||||
'@esbuild/freebsd-x64': 0.23.0
|
||||
'@esbuild/linux-arm': 0.23.0
|
||||
'@esbuild/linux-arm64': 0.23.0
|
||||
'@esbuild/linux-ia32': 0.23.0
|
||||
'@esbuild/linux-loong64': 0.23.0
|
||||
'@esbuild/linux-mips64el': 0.23.0
|
||||
'@esbuild/linux-ppc64': 0.23.0
|
||||
'@esbuild/linux-riscv64': 0.23.0
|
||||
'@esbuild/linux-s390x': 0.23.0
|
||||
'@esbuild/linux-x64': 0.23.0
|
||||
'@esbuild/netbsd-x64': 0.23.0
|
||||
'@esbuild/openbsd-arm64': 0.23.0
|
||||
'@esbuild/openbsd-x64': 0.23.0
|
||||
'@esbuild/sunos-x64': 0.23.0
|
||||
'@esbuild/win32-arm64': 0.23.0
|
||||
'@esbuild/win32-ia32': 0.23.0
|
||||
'@esbuild/win32-x64': 0.23.0
|
||||
|
||||
escape-string-regexp@1.0.5: {}
|
||||
|
||||
eventemitter3@5.0.1: {}
|
||||
@@ -1698,6 +1965,9 @@ snapshots:
|
||||
fs.realpath@1.0.0:
|
||||
optional: true
|
||||
|
||||
fsevents@2.3.3:
|
||||
optional: true
|
||||
|
||||
function-bind@1.1.2: {}
|
||||
|
||||
function.prototype.name@1.1.6:
|
||||
@@ -1738,6 +2008,10 @@ snapshots:
|
||||
call-bind: 1.0.5
|
||||
get-intrinsic: 1.2.2
|
||||
|
||||
get-tsconfig@4.7.6:
|
||||
dependencies:
|
||||
resolve-pkg-maps: 1.0.0
|
||||
|
||||
github-from-package@0.0.0: {}
|
||||
|
||||
glob@7.2.3:
|
||||
@@ -2256,6 +2530,8 @@ snapshots:
|
||||
define-properties: 1.2.1
|
||||
set-function-name: 2.0.1
|
||||
|
||||
resolve-pkg-maps@1.0.0: {}
|
||||
|
||||
resolve@1.22.8:
|
||||
dependencies:
|
||||
is-core-module: 2.13.1
|
||||
@@ -2473,6 +2749,13 @@ snapshots:
|
||||
mkdirp: 1.0.4
|
||||
yallist: 4.0.0
|
||||
|
||||
tsx@4.17.0:
|
||||
dependencies:
|
||||
esbuild: 0.23.0
|
||||
get-tsconfig: 4.7.6
|
||||
optionalDependencies:
|
||||
fsevents: 2.3.3
|
||||
|
||||
tunnel-agent@0.6.0:
|
||||
dependencies:
|
||||
safe-buffer: 5.2.1
|
||||
|
||||
+23
-22
@@ -1,7 +1,6 @@
|
||||
import { stockDatabase } from "./stockdb/clickhouse.js";
|
||||
import { stockDatabase } from "./stockdb/lmdbx.js";
|
||||
import { calendarDatabase } from "./calendardb/optiondb-lmdbx.js";
|
||||
import type { CalendarKey } from "./calendardb/interfaces.js";
|
||||
import type { Aggregate } from "./interfaces.js";
|
||||
import { nextDate } from "./lib/utils/nextDate.js";
|
||||
|
||||
type BacktestInput = {
|
||||
@@ -38,49 +37,51 @@ export async function backtest({
|
||||
// for each minute of that day for which we have a stock candlestick:
|
||||
for (const stockAggregate of stockAggregates) {
|
||||
// console.log("Current Time:", new Date(stockAggregate.tsStart));
|
||||
// filter-out calendars that are far-from-the-money (10%)
|
||||
console.log("Current Date:", date, stockAggregate.tsStart);
|
||||
// filter-out calendars that are far-from-the-money (5%)
|
||||
const calendarsNearTheMoney = calendars.filter(
|
||||
({ strike }) =>
|
||||
Math.abs((stockAggregate.open - strike) / stockAggregate.open) < 0.1,
|
||||
Math.abs((stockAggregate.open - strike) / stockAggregate.open) < 0.05
|
||||
);
|
||||
console.log(
|
||||
"Current Date:",
|
||||
new Intl.DateTimeFormat("en-US", {
|
||||
timeZone: "America/New_York",
|
||||
dateStyle: "full",
|
||||
timeStyle: "long",
|
||||
}).format(new Date(stockAggregate.tsStart)),
|
||||
";",
|
||||
`${calendarsNearTheMoney.length} Calendars Near The Money`
|
||||
);
|
||||
// for each relevant calendar on that day:
|
||||
for (const calendar of calendarsNearTheMoney) {
|
||||
const strikePercentageFromTheMoney = Math.abs(
|
||||
(stockAggregate.open - calendar.strike) / stockAggregate.open,
|
||||
(stockAggregate.open - calendar.strike) / stockAggregate.open
|
||||
);
|
||||
/** In days. */
|
||||
const calendarSpan =
|
||||
/** Number of days between the back and front expiration dates. */
|
||||
const calendarSpanInDays =
|
||||
(new Date(calendar.backExpirationDate).valueOf() -
|
||||
new Date(calendar.frontExpirationDate).valueOf()) /
|
||||
(1000 * 60 * 60 * 24);
|
||||
const targetCalendarPrice =
|
||||
await calendarDatabase.getTargetPriceByProbability({
|
||||
symbol,
|
||||
calendarSpan,
|
||||
calendarSpan: calendarSpanInDays,
|
||||
strikePercentageFromTheMoney,
|
||||
historicalProbabilityOfSuccess,
|
||||
});
|
||||
const calendarAggregates = calendarDatabase.getAggregatesSync({
|
||||
const calendarAggregateAtCurrentTime =
|
||||
await calendarDatabase.getAggregate({
|
||||
key: {
|
||||
...calendar,
|
||||
},
|
||||
date,
|
||||
tsStart: stockAggregate.tsStart,
|
||||
});
|
||||
// console.log(
|
||||
// "Calendar Aggregates:",
|
||||
// calendar,
|
||||
// calendarAggregates.length,
|
||||
// );
|
||||
const calendarAggregateAtCurrentTime = calendarAggregates.find(
|
||||
({ tsStart }) => tsStart === stockAggregate.tsStart,
|
||||
);
|
||||
// if there exists a matching calendar candlestick for the current minute:
|
||||
if (calendarAggregateAtCurrentTime) {
|
||||
// if the current candlestick is a good price (i.e. less than the target price):
|
||||
const minCalendarPriceInCandlestick = Math.min(
|
||||
calendarAggregateAtCurrentTime.open,
|
||||
calendarAggregateAtCurrentTime.close,
|
||||
calendarAggregateAtCurrentTime.close
|
||||
);
|
||||
if (
|
||||
minCalendarPriceInCandlestick < targetCalendarPrice &&
|
||||
@@ -99,7 +100,7 @@ export async function backtest({
|
||||
minCalendarPriceInCandlestick * 100,
|
||||
"...$",
|
||||
buyingPower,
|
||||
"left",
|
||||
"left"
|
||||
);
|
||||
didBuyCalendar = true;
|
||||
}
|
||||
@@ -131,7 +132,7 @@ export async function backtest({
|
||||
calendarClosingPrice,
|
||||
"...$",
|
||||
buyingPower,
|
||||
"left",
|
||||
"left"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,13 +3,11 @@ import { open } from "lmdbx";
|
||||
|
||||
const calendarAggregatesDb = open({
|
||||
path: "./calendar-aggregates.db",
|
||||
// any options go here, we can turn on compression like this:
|
||||
compression: true,
|
||||
});
|
||||
|
||||
const calendarExistenceDb = open({
|
||||
path: "./calendar-existence.db",
|
||||
// any options go here, we can turn on compression like this:
|
||||
compression: true,
|
||||
});
|
||||
|
||||
@@ -65,6 +63,19 @@ function makeCalendarDatabase(): CalendarDatabase {
|
||||
low: value.low,
|
||||
})).asArray;
|
||||
},
|
||||
getAggregate: async ({
|
||||
key: { symbol, frontExpirationDate, backExpirationDate, strike, type },
|
||||
tsStart,
|
||||
}) => {
|
||||
return await calendarAggregatesDb.get([
|
||||
symbol,
|
||||
frontExpirationDate,
|
||||
backExpirationDate,
|
||||
strike,
|
||||
type,
|
||||
tsStart,
|
||||
]);
|
||||
},
|
||||
insertAggregates: async (aggregates) => {
|
||||
await calendarExistenceDb.batch(() => {
|
||||
for (const aggregate of aggregates) {
|
||||
@@ -77,7 +88,7 @@ function makeCalendarDatabase(): CalendarDatabase {
|
||||
aggregate.key.strike,
|
||||
aggregate.key.type,
|
||||
],
|
||||
null,
|
||||
null
|
||||
);
|
||||
}
|
||||
});
|
||||
@@ -97,7 +108,7 @@ function makeCalendarDatabase(): CalendarDatabase {
|
||||
close: aggregate.close,
|
||||
high: aggregate.high,
|
||||
low: aggregate.low,
|
||||
},
|
||||
}
|
||||
);
|
||||
}
|
||||
});
|
||||
@@ -105,11 +116,12 @@ function makeCalendarDatabase(): CalendarDatabase {
|
||||
getClosingPrice: async ({
|
||||
key: { symbol, strike, type, frontExpirationDate, backExpirationDate },
|
||||
}) => {
|
||||
const startOfLastHourUnix = new Date(
|
||||
`${frontExpirationDate}T00:00:00Z`,
|
||||
const startOfExpirationDateUnix = new Date(
|
||||
`${frontExpirationDate}T23:59:59Z`
|
||||
).valueOf();
|
||||
const endOfExpirationDateUnix = new Date(
|
||||
`${frontExpirationDate}T00:00:00Z`
|
||||
).valueOf();
|
||||
const endOfLastHourUnix = startOfLastHourUnix + 3600 * 1000;
|
||||
let minPrice = 0;
|
||||
for (const { value } of calendarAggregatesDb.getRange({
|
||||
start: [
|
||||
symbol,
|
||||
@@ -117,7 +129,7 @@ function makeCalendarDatabase(): CalendarDatabase {
|
||||
backExpirationDate,
|
||||
strike,
|
||||
type,
|
||||
startOfLastHourUnix,
|
||||
startOfExpirationDateUnix,
|
||||
],
|
||||
end: [
|
||||
symbol,
|
||||
@@ -125,14 +137,15 @@ function makeCalendarDatabase(): CalendarDatabase {
|
||||
backExpirationDate,
|
||||
strike,
|
||||
type,
|
||||
endOfLastHourUnix,
|
||||
endOfExpirationDateUnix,
|
||||
],
|
||||
reverse: true,
|
||||
})) {
|
||||
if (value.close < minPrice || minPrice === 0) {
|
||||
minPrice = value.close;
|
||||
if (value.close > 0) {
|
||||
return value.close;
|
||||
}
|
||||
}
|
||||
return minPrice;
|
||||
return 0;
|
||||
},
|
||||
getTargetPriceByProbability: async ({
|
||||
symbol,
|
||||
|
||||
@@ -68,14 +68,22 @@ function makeCalendarDatabase(): CalendarDatabase {
|
||||
return optionContracts.flatMap(
|
||||
(frontOptionContract, i, optionContracts) =>
|
||||
optionContracts
|
||||
.filter((_, j) => i !== j)
|
||||
.filter(
|
||||
(potientialBackOptionContract) =>
|
||||
frontOptionContract.strike ===
|
||||
potientialBackOptionContract.strike &&
|
||||
frontOptionContract.type ===
|
||||
potientialBackOptionContract.type &&
|
||||
frontOptionContract.expirationDate <
|
||||
potientialBackOptionContract.expirationDate
|
||||
)
|
||||
.map((backOptionContract) => ({
|
||||
symbol,
|
||||
frontExpirationDate: frontOptionContract.expirationDate,
|
||||
backExpirationDate: backOptionContract.expirationDate,
|
||||
strike: frontOptionContract.strike,
|
||||
type: frontOptionContract.type,
|
||||
})),
|
||||
}))
|
||||
);
|
||||
},
|
||||
getAggregates: async ({
|
||||
@@ -93,9 +101,10 @@ function makeCalendarDatabase(): CalendarDatabase {
|
||||
getClosingPrice: async ({
|
||||
key: { symbol, strike, type, frontExpirationDate, backExpirationDate },
|
||||
}) => {
|
||||
// get unix timestamp, in milliseconds, of the start of the last hour, which is 03:30PM in the `America/New_York` timezone on the front expiration date:
|
||||
const startOfLastHourUnix = new Date(
|
||||
`${frontExpirationDate}T00:00:00Z`,
|
||||
).valueOf();
|
||||
`${frontExpirationDate}T19:30:00Z`
|
||||
).getTime();
|
||||
const endOfLastHourUnix = startOfLastHourUnix + 3600 * 1000;
|
||||
const frontOptionContractAggregates = (
|
||||
await optionContractDatabase.getAggregates({
|
||||
@@ -104,7 +113,7 @@ function makeCalendarDatabase(): CalendarDatabase {
|
||||
})
|
||||
).filter(
|
||||
({ tsStart }) =>
|
||||
tsStart >= startOfLastHourUnix && tsStart < endOfLastHourUnix,
|
||||
tsStart >= startOfLastHourUnix && tsStart < endOfLastHourUnix
|
||||
);
|
||||
const backOptionContractAggregates = (
|
||||
await optionContractDatabase.getAggregates({
|
||||
@@ -113,7 +122,7 @@ function makeCalendarDatabase(): CalendarDatabase {
|
||||
})
|
||||
).filter(
|
||||
({ tsStart }) =>
|
||||
tsStart >= startOfLastHourUnix && tsStart < endOfLastHourUnix,
|
||||
tsStart >= startOfLastHourUnix && tsStart < endOfLastHourUnix
|
||||
);
|
||||
let i = 0;
|
||||
let j = 0;
|
||||
@@ -128,7 +137,7 @@ function makeCalendarDatabase(): CalendarDatabase {
|
||||
) {
|
||||
const calendarClosePrice =
|
||||
backOptionContractAggregates[j].close -
|
||||
frontOptionContractAggregates[j].close;
|
||||
frontOptionContractAggregates[i].close;
|
||||
if (calendarClosePrice < minPrice || minPrice === 0) {
|
||||
minPrice = calendarClosePrice;
|
||||
}
|
||||
@@ -145,6 +154,40 @@ function makeCalendarDatabase(): CalendarDatabase {
|
||||
}
|
||||
return minPrice;
|
||||
},
|
||||
getAggregate: async ({
|
||||
key: { symbol, frontExpirationDate, backExpirationDate, strike, type },
|
||||
tsStart,
|
||||
}) => {
|
||||
const [frontOptionContractAggregate, backOptionContractAggregate] =
|
||||
await Promise.all([
|
||||
optionContractDatabase.getAggregate({
|
||||
key: { symbol, expirationDate: frontExpirationDate, strike, type },
|
||||
tsStart,
|
||||
}),
|
||||
optionContractDatabase.getAggregate({
|
||||
key: { symbol, expirationDate: backExpirationDate, strike, type },
|
||||
tsStart,
|
||||
}),
|
||||
]);
|
||||
// only return the calendar aggregate if its constituent front and back option contract aggregates exist:
|
||||
if (frontOptionContractAggregate && backOptionContractAggregate) {
|
||||
return {
|
||||
tsStart,
|
||||
open:
|
||||
backOptionContractAggregate.open -
|
||||
frontOptionContractAggregate.open,
|
||||
close:
|
||||
backOptionContractAggregate.close -
|
||||
frontOptionContractAggregate.close,
|
||||
high:
|
||||
backOptionContractAggregate.high -
|
||||
frontOptionContractAggregate.high,
|
||||
low:
|
||||
backOptionContractAggregate.low - frontOptionContractAggregate.low,
|
||||
};
|
||||
}
|
||||
return undefined;
|
||||
},
|
||||
getTargetPriceByProbability: async ({
|
||||
symbol,
|
||||
calendarSpan,
|
||||
|
||||
@@ -15,15 +15,32 @@ export type AggregateDatabase<T> = {
|
||||
getKeys: ({
|
||||
key,
|
||||
date,
|
||||
}: { key?: T | Partial<T>; date?: string }) => Promise<Array<T>>;
|
||||
}: {
|
||||
key?: T | Partial<T>;
|
||||
date?: string;
|
||||
}) => Promise<Array<T>>;
|
||||
getAggregates: ({
|
||||
key,
|
||||
date,
|
||||
}: { key: T; date: string }) => Promise<Array<Omit<Aggregate<T>, "key">>>;
|
||||
}: {
|
||||
key: T;
|
||||
date: string;
|
||||
}) => Promise<Array<Omit<Aggregate<T>, "key">>>;
|
||||
/** Since an aggregate may not exist at the specified `tsStart`, return `undefined` if it doesn't exist. */
|
||||
getAggregate: ({
|
||||
key,
|
||||
tsStart,
|
||||
}: {
|
||||
key: T;
|
||||
tsStart: number;
|
||||
}) => Promise<Omit<Aggregate<T>, "key"> | undefined>;
|
||||
getAggregatesSync?: ({
|
||||
key,
|
||||
date,
|
||||
}: { key: T; date: string }) => Array<Omit<Aggregate<T>, "key">>;
|
||||
}: {
|
||||
key: T;
|
||||
date: string;
|
||||
}) => Array<Omit<Aggregate<T>, "key">>;
|
||||
insertAggregates: (aggregates: Array<Aggregate<T>>) => Promise<void>;
|
||||
getClosingPrice: ({ key }: { key: T }) => Promise<number>;
|
||||
};
|
||||
|
||||
@@ -28,8 +28,8 @@ function makeOptionContractDatabase(): OptionContractDatabase {
|
||||
start: [symbol, expirationDate, strike, type, startOfDayUnix],
|
||||
end: [symbol, expirationDate, strike, type, endOfDayUnix],
|
||||
})
|
||||
.map(({ value }) => ({
|
||||
tsStart: value.tsStart,
|
||||
.map(({ key, value }) => ({
|
||||
tsStart: key[4],
|
||||
open: value.open,
|
||||
close: value.close,
|
||||
high: value.high,
|
||||
@@ -73,7 +73,7 @@ function makeOptionContractDatabase(): OptionContractDatabase {
|
||||
aggregate.key.strike,
|
||||
aggregate.key.type,
|
||||
],
|
||||
null,
|
||||
null
|
||||
);
|
||||
}
|
||||
});
|
||||
@@ -92,7 +92,7 @@ function makeOptionContractDatabase(): OptionContractDatabase {
|
||||
close: aggregate.close,
|
||||
high: aggregate.high,
|
||||
low: aggregate.low,
|
||||
},
|
||||
}
|
||||
);
|
||||
}
|
||||
});
|
||||
@@ -101,7 +101,7 @@ function makeOptionContractDatabase(): OptionContractDatabase {
|
||||
key: { symbol, strike, type, expirationDate },
|
||||
}) => {
|
||||
const startOfLastHourUnix = new Date(
|
||||
`${expirationDate}T00:00:00Z`,
|
||||
`${expirationDate}T00:00:00Z`
|
||||
).valueOf();
|
||||
const endOfLastHourUnix = startOfLastHourUnix + 3600 * 1000;
|
||||
let minPrice = 0;
|
||||
@@ -115,6 +115,18 @@ function makeOptionContractDatabase(): OptionContractDatabase {
|
||||
}
|
||||
return minPrice;
|
||||
},
|
||||
getAggregate: async ({
|
||||
key: { symbol, expirationDate, strike, type },
|
||||
tsStart,
|
||||
}) => {
|
||||
return await optionContractAggregatesDb.get([
|
||||
symbol,
|
||||
expirationDate,
|
||||
strike,
|
||||
type,
|
||||
tsStart,
|
||||
]);
|
||||
},
|
||||
};
|
||||
|
||||
return {
|
||||
|
||||
Reference in New Issue
Block a user