Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| add21288be | |||
| db809d7b57 | |||
| 8986dc4ea9 | |||
| ea9bd307f3 |
+1
-1
@@ -9,7 +9,7 @@ COPY package.json pnpm-lock.yaml /app/
|
||||
# install dependencies:
|
||||
RUN --mount=type=cache,id=pnpm,target=/pnpm/store pnpm install --frozen-lockfile
|
||||
# copy what's necessary to build:
|
||||
COPY tsconfig.json vite.config.ts index.html index.css postcss.config.js tailwind.config.js /app/
|
||||
COPY tsconfig.json vite.config.ts index.html index.css /app/
|
||||
COPY src /app/src
|
||||
# Vite injects envvars at build time, not runtime:
|
||||
ENV VITE_SERVER_BASE_URL=https://calendar-optimizer-server.sakal.us
|
||||
|
||||
@@ -7,12 +7,10 @@
|
||||
"preview": "vite preview"
|
||||
},
|
||||
"dependencies": {
|
||||
"@date-io/date-fns": "^3.0.0",
|
||||
"@emotion/react": "^11.13.0",
|
||||
"@emotion/styled": "^11.13.0",
|
||||
"@mui/material": "^5.16.6",
|
||||
"@mui/system": "^5.16.6",
|
||||
"@mui/x-date-pickers": "^7.12.0",
|
||||
"@mui/icons-material": "^6.1.1",
|
||||
"@mui/material": "^6.1.1",
|
||||
"@mui/system": "^6.1.1",
|
||||
"@mui/x-date-pickers": "^7.18.0",
|
||||
"@preact/signals": "^1.2.2",
|
||||
"@trpc/client": "^10.45.0",
|
||||
"chart.js": "^4.4.1",
|
||||
|
||||
Generated
+182
-111
@@ -8,24 +8,18 @@ importers:
|
||||
|
||||
.:
|
||||
dependencies:
|
||||
'@date-io/date-fns':
|
||||
specifier: ^3.0.0
|
||||
version: 3.0.0(date-fns@3.6.0)
|
||||
'@emotion/react':
|
||||
specifier: ^11.13.0
|
||||
version: 11.13.0(@types/react@18.3.3)(react@18.3.1)
|
||||
'@emotion/styled':
|
||||
specifier: ^11.13.0
|
||||
version: 11.13.0(@emotion/react@11.13.0(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react@18.3.1)
|
||||
'@mui/icons-material':
|
||||
specifier: ^6.1.1
|
||||
version: 6.1.1(@mui/material@6.1.1(@emotion/react@11.13.0(@types/react@18.3.3)(react@18.3.1))(@emotion/styled@11.13.0(@emotion/react@11.13.0(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@types/react@18.3.3)(react@18.3.1)
|
||||
'@mui/material':
|
||||
specifier: ^5.16.6
|
||||
version: 5.16.6(@emotion/react@11.13.0(@types/react@18.3.3)(react@18.3.1))(@emotion/styled@11.13.0(@emotion/react@11.13.0(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
specifier: ^6.1.1
|
||||
version: 6.1.1(@emotion/react@11.13.0(@types/react@18.3.3)(react@18.3.1))(@emotion/styled@11.13.0(@emotion/react@11.13.0(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
'@mui/system':
|
||||
specifier: ^5.16.6
|
||||
version: 5.16.6(@emotion/react@11.13.0(@types/react@18.3.3)(react@18.3.1))(@emotion/styled@11.13.0(@emotion/react@11.13.0(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react@18.3.1)
|
||||
specifier: ^6.1.1
|
||||
version: 6.1.1(@emotion/react@11.13.0(@types/react@18.3.3)(react@18.3.1))(@emotion/styled@11.13.0(@emotion/react@11.13.0(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react@18.3.1)
|
||||
'@mui/x-date-pickers':
|
||||
specifier: ^7.12.0
|
||||
version: 7.12.0(@emotion/react@11.13.0(@types/react@18.3.3)(react@18.3.1))(@emotion/styled@11.13.0(@emotion/react@11.13.0(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react@18.3.1))(@mui/material@5.16.6(@emotion/react@11.13.0(@types/react@18.3.3)(react@18.3.1))(@emotion/styled@11.13.0(@emotion/react@11.13.0(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@types/react@18.3.3)(date-fns@3.6.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
specifier: ^7.18.0
|
||||
version: 7.18.0(@emotion/react@11.13.0(@types/react@18.3.3)(react@18.3.1))(@emotion/styled@11.13.0(@emotion/react@11.13.0(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react@18.3.1))(@mui/material@6.1.1(@emotion/react@11.13.0(@types/react@18.3.3)(react@18.3.1))(@emotion/styled@11.13.0(@emotion/react@11.13.0(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mui/system@6.1.1(@emotion/react@11.13.0(@types/react@18.3.3)(react@18.3.1))(@emotion/styled@11.13.0(@emotion/react@11.13.0(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(date-fns@3.6.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
'@preact/signals':
|
||||
specifier: ^1.2.2
|
||||
version: 1.2.2(preact@10.19.3)
|
||||
@@ -178,6 +172,10 @@ packages:
|
||||
resolution: {integrity: sha512-7dRy4DwXwtzBrPbZflqxnvfxLF8kdZXPkhymtDeFoFqE6ldzjQFgYTtYIFARcLEYDrqfBfYcZt1WqFxRoyC9Rw==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
|
||||
'@babel/runtime@7.25.6':
|
||||
resolution: {integrity: sha512-VBj9MYyDb9tuLq7yzqjgzt6Q+IBQLrGZfdjOekyEirZPHxXWoTSGUTMrpsfi58Up73d13NfYLv8HT9vmznjzhQ==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
|
||||
'@babel/template@7.22.15':
|
||||
resolution: {integrity: sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
@@ -190,17 +188,6 @@ packages:
|
||||
resolution: {integrity: sha512-+uarb83brBzPKN38NX1MkB6vb6+mwvR6amUulqAE7ccQw1pEl+bCia9TbdG1lsnFP7lZySvUn37CHyXQdfTwzg==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
|
||||
'@date-io/core@3.0.0':
|
||||
resolution: {integrity: sha512-S3j+IAQVBYNkQzchVVhX40eBkGDreBpScy9RXwTS5j2+k07+62pMVPisQ44Gq76Rqy5AOG/EZXCwBpY/jbemvA==}
|
||||
|
||||
'@date-io/date-fns@3.0.0':
|
||||
resolution: {integrity: sha512-hsLAbsdP8LKfi7OQ729cXMWfmHQEq0hn3ysXfAAoc92j6j6sBq0s0tplnkWu6O4iBUpVCYRPGuNjQQhTaOu2AA==}
|
||||
peerDependencies:
|
||||
date-fns: ^3.2.0
|
||||
peerDependenciesMeta:
|
||||
date-fns:
|
||||
optional: true
|
||||
|
||||
'@emotion/babel-plugin@11.12.0':
|
||||
resolution: {integrity: sha512-y2WQb+oP8Jqvvclh8Q55gLUyb7UFvgv7eJfsj7td5TToBrIUtPay2kMrZi4xjq9qw2vD0ZR5fSho0yqoFgX7Rw==}
|
||||
|
||||
@@ -408,57 +395,71 @@ packages:
|
||||
'@kurkle/color@0.3.2':
|
||||
resolution: {integrity: sha512-fuscdXJ9G1qb7W8VdHi+IwRqij3lBkosAm4ydQtEmbY58OzHXqQhvlxqEkoz0yssNVn38bcpRWgA9PP+OGoisw==}
|
||||
|
||||
'@mui/core-downloads-tracker@5.16.6':
|
||||
resolution: {integrity: sha512-kytg6LheUG42V8H/o/Ptz3olSO5kUXW9zF0ox18VnblX6bO2yif1FPItgc3ey1t5ansb1+gbe7SatntqusQupg==}
|
||||
'@mui/core-downloads-tracker@6.1.1':
|
||||
resolution: {integrity: sha512-VdQC1tPIIcZAnf62L2M1eQif0x2vlKg3YK4kGYbtijSH4niEgI21GnstykW1vQIs+Bc6L+Hua2GATYVjilJ22A==}
|
||||
|
||||
'@mui/material@5.16.6':
|
||||
resolution: {integrity: sha512-0LUIKBOIjiFfzzFNxXZBRAyr9UQfmTAFzbt6ziOU2FDXhorNN2o3N9/32mNJbCA8zJo2FqFU6d3dtoqUDyIEfA==}
|
||||
engines: {node: '>=12.0.0'}
|
||||
'@mui/icons-material@6.1.1':
|
||||
resolution: {integrity: sha512-sy/YKwcLPW8VcacNP2uWMYR9xyWuwO9NN9FXuGEU90bRshBXj8pdKk+joe3TCW7oviVS3zXLHlc94wQ0jNsQRQ==}
|
||||
engines: {node: '>=14.0.0'}
|
||||
peerDependencies:
|
||||
'@mui/material': ^6.1.1
|
||||
'@types/react': ^17.0.0 || ^18.0.0 || ^19.0.0
|
||||
react: ^17.0.0 || ^18.0.0 || ^19.0.0
|
||||
peerDependenciesMeta:
|
||||
'@types/react':
|
||||
optional: true
|
||||
|
||||
'@mui/material@6.1.1':
|
||||
resolution: {integrity: sha512-b+eULldTqtqTCbN++2BtBWCir/1LwEYw+2mIlOt2GiEUh1EBBw4/wIukGKKNt3xrCZqRA80yLLkV6tF61Lq3cA==}
|
||||
engines: {node: '>=14.0.0'}
|
||||
peerDependencies:
|
||||
'@emotion/react': ^11.5.0
|
||||
'@emotion/styled': ^11.3.0
|
||||
'@types/react': ^17.0.0 || ^18.0.0
|
||||
react: ^17.0.0 || ^18.0.0
|
||||
react-dom: ^17.0.0 || ^18.0.0
|
||||
'@mui/material-pigment-css': ^6.1.1
|
||||
'@types/react': ^17.0.0 || ^18.0.0 || ^19.0.0
|
||||
react: ^17.0.0 || ^18.0.0 || ^19.0.0
|
||||
react-dom: ^17.0.0 || ^18.0.0 || ^19.0.0
|
||||
peerDependenciesMeta:
|
||||
'@emotion/react':
|
||||
optional: true
|
||||
'@emotion/styled':
|
||||
optional: true
|
||||
'@mui/material-pigment-css':
|
||||
optional: true
|
||||
'@types/react':
|
||||
optional: true
|
||||
|
||||
'@mui/private-theming@5.16.6':
|
||||
resolution: {integrity: sha512-rAk+Rh8Clg7Cd7shZhyt2HGTTE5wYKNSJ5sspf28Fqm/PZ69Er9o6KX25g03/FG2dfpg5GCwZh/xOojiTfm3hw==}
|
||||
engines: {node: '>=12.0.0'}
|
||||
'@mui/private-theming@6.1.1':
|
||||
resolution: {integrity: sha512-JlrjIdhyZUtewtdAuUsvi3ZnO0YS49IW4Mfz19ZWTlQ0sDGga6LNPVwHClWr2/zJK2we2BQx9/i8M32rgKuzrg==}
|
||||
engines: {node: '>=14.0.0'}
|
||||
peerDependencies:
|
||||
'@types/react': ^17.0.0 || ^18.0.0
|
||||
react: ^17.0.0 || ^18.0.0
|
||||
'@types/react': ^17.0.0 || ^18.0.0 || ^19.0.0
|
||||
react: ^17.0.0 || ^18.0.0 || ^19.0.0
|
||||
peerDependenciesMeta:
|
||||
'@types/react':
|
||||
optional: true
|
||||
|
||||
'@mui/styled-engine@5.16.6':
|
||||
resolution: {integrity: sha512-zaThmS67ZmtHSWToTiHslbI8jwrmITcN93LQaR2lKArbvS7Z3iLkwRoiikNWutx9MBs8Q6okKvbZq1RQYB3v7g==}
|
||||
engines: {node: '>=12.0.0'}
|
||||
'@mui/styled-engine@6.1.1':
|
||||
resolution: {integrity: sha512-HJyIoMpFb11fnHuRtUILOXgq6vj4LhIlE8maG4SwP/W+E5sa7HFexhnB3vOMT7bKys4UKNxhobC8jwWxYilGsA==}
|
||||
engines: {node: '>=14.0.0'}
|
||||
peerDependencies:
|
||||
'@emotion/react': ^11.4.1
|
||||
'@emotion/styled': ^11.3.0
|
||||
react: ^17.0.0 || ^18.0.0
|
||||
react: ^17.0.0 || ^18.0.0 || ^19.0.0
|
||||
peerDependenciesMeta:
|
||||
'@emotion/react':
|
||||
optional: true
|
||||
'@emotion/styled':
|
||||
optional: true
|
||||
|
||||
'@mui/system@5.16.6':
|
||||
resolution: {integrity: sha512-5xgyJjBIMPw8HIaZpfbGAaFYPwImQn7Nyh+wwKWhvkoIeDosQ1ZMVrbTclefi7G8hNmqhip04duYwYpbBFnBgw==}
|
||||
engines: {node: '>=12.0.0'}
|
||||
'@mui/system@6.1.1':
|
||||
resolution: {integrity: sha512-PaYsCz2tUOcpu3T0okDEsSuP/yCDIj9JZ4Tox1JovRSKIjltHpXPsXZSGr3RiWdtM1MTQMFMCZzu0+CKbyy+Kw==}
|
||||
engines: {node: '>=14.0.0'}
|
||||
peerDependencies:
|
||||
'@emotion/react': ^11.5.0
|
||||
'@emotion/styled': ^11.3.0
|
||||
'@types/react': ^17.0.0 || ^18.0.0
|
||||
react: ^17.0.0 || ^18.0.0
|
||||
'@types/react': ^17.0.0 || ^18.0.0 || ^19.0.0
|
||||
react: ^17.0.0 || ^18.0.0 || ^19.0.0
|
||||
peerDependenciesMeta:
|
||||
'@emotion/react':
|
||||
optional: true
|
||||
@@ -467,10 +468,10 @@ packages:
|
||||
'@types/react':
|
||||
optional: true
|
||||
|
||||
'@mui/types@7.2.15':
|
||||
resolution: {integrity: sha512-nbo7yPhtKJkdf9kcVOF8JZHPZTmqXjJ/tI0bdWgHg5tp9AnIN4Y7f7wm9T+0SyGYJk76+GYZ8Q5XaTYAsUHN0Q==}
|
||||
'@mui/types@7.2.17':
|
||||
resolution: {integrity: sha512-oyumoJgB6jDV8JFzRqjBo2daUuHpzDjoO/e3IrRhhHo/FxJlaVhET6mcNrKHUq2E+R+q3ql0qAtvQ4rfWHhAeQ==}
|
||||
peerDependencies:
|
||||
'@types/react': ^17.0.0 || ^18.0.0
|
||||
'@types/react': ^17.0.0 || ^18.0.0 || ^19.0.0
|
||||
peerDependenciesMeta:
|
||||
'@types/react':
|
||||
optional: true
|
||||
@@ -485,14 +486,25 @@ packages:
|
||||
'@types/react':
|
||||
optional: true
|
||||
|
||||
'@mui/x-date-pickers@7.12.0':
|
||||
resolution: {integrity: sha512-WU5C7QNfSpJ9cP8vl2sY7q35NW+0TUMgEy+sl98fcPhLckq3cgV1wnVxoZnQZ3BxVQAtx+7ag/MpefU03vJcVw==}
|
||||
'@mui/utils@6.1.1':
|
||||
resolution: {integrity: sha512-HlRrgdJSPbYDXPpoVMWZV8AE7WcFtAk13rWNWAEVWKSanzBBkymjz3km+Th/Srowsh4pf1fTSP1B0L116wQBYw==}
|
||||
engines: {node: '>=14.0.0'}
|
||||
peerDependencies:
|
||||
'@types/react': ^17.0.0 || ^18.0.0 || ^19.0.0
|
||||
react: ^17.0.0 || ^18.0.0 || ^19.0.0
|
||||
peerDependenciesMeta:
|
||||
'@types/react':
|
||||
optional: true
|
||||
|
||||
'@mui/x-date-pickers@7.18.0':
|
||||
resolution: {integrity: sha512-12tXIoMj9vpS8fS/bS3kWPCoVrH38vNGCxgplI0vOnUrN9rJuYJz3agLPJe1S0xciTw+9W8ZSe3soaW+owoz1Q==}
|
||||
engines: {node: '>=14.0.0'}
|
||||
peerDependencies:
|
||||
'@emotion/react': ^11.9.0
|
||||
'@emotion/styled': ^11.8.1
|
||||
'@mui/material': ^5.15.14
|
||||
date-fns: ^2.25.0 || ^3.2.0
|
||||
'@mui/material': ^5.15.14 || ^6.0.0
|
||||
'@mui/system': ^5.15.14 || ^6.0.0
|
||||
date-fns: ^2.25.0 || ^3.2.0 || ^4.0.0
|
||||
date-fns-jalali: ^2.13.0-0 || ^3.2.0-0
|
||||
dayjs: ^1.10.7
|
||||
luxon: ^3.0.2
|
||||
@@ -521,6 +533,12 @@ packages:
|
||||
moment-jalaali:
|
||||
optional: true
|
||||
|
||||
'@mui/x-internals@7.18.0':
|
||||
resolution: {integrity: sha512-lzCHOWIR0cAIY1bGrWSprYerahbnH5C31ql/2OWCEjcngL2NAV1M6oKI2Vp4HheqzJ822c60UyWyapvyjSzY/A==}
|
||||
engines: {node: '>=14.0.0'}
|
||||
peerDependencies:
|
||||
react: ^17.0.0 || ^18.0.0
|
||||
|
||||
'@popperjs/core@2.11.8':
|
||||
resolution: {integrity: sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==}
|
||||
|
||||
@@ -573,8 +591,8 @@ packages:
|
||||
'@types/prop-types@15.7.12':
|
||||
resolution: {integrity: sha512-5zvhXYtRNRluoE/jAp4GVsSduVUzNWKkOZrCDBWYtE7biZywwdC2AcEzg+cSMLFRfVgeAFqpfNabiPjxFddV1Q==}
|
||||
|
||||
'@types/react-transition-group@4.4.10':
|
||||
resolution: {integrity: sha512-hT/+s0VQs2ojCX823m60m5f0sL5idt9SO6Tj6Dg+rdphGPIeJbJ6CxvBYkgkGKrYeDjvIpKTR38UzmtHJOGW3Q==}
|
||||
'@types/react-transition-group@4.4.11':
|
||||
resolution: {integrity: sha512-RM05tAniPZ5DZPzzNFP+DmrcOdD0efDUxMy3145oljWSl3x9ZV5vhme98gTxFrj2lhXvmGNnUiuDyJgY9IKkNA==}
|
||||
|
||||
'@types/react@18.3.3':
|
||||
resolution: {integrity: sha512-hti/R0pS0q1/xx+TsI73XIqk26eBsISZ2R0wUijXIngRK9R/e7Xw/cXVxQK7R5JjW+SV4zGcn5hXjudkN/pLIw==}
|
||||
@@ -1107,6 +1125,10 @@ snapshots:
|
||||
dependencies:
|
||||
regenerator-runtime: 0.14.1
|
||||
|
||||
'@babel/runtime@7.25.6':
|
||||
dependencies:
|
||||
regenerator-runtime: 0.14.1
|
||||
|
||||
'@babel/template@7.22.15':
|
||||
dependencies:
|
||||
'@babel/code-frame': 7.23.5
|
||||
@@ -1134,18 +1156,10 @@ snapshots:
|
||||
'@babel/helper-validator-identifier': 7.22.20
|
||||
to-fast-properties: 2.0.0
|
||||
|
||||
'@date-io/core@3.0.0': {}
|
||||
|
||||
'@date-io/date-fns@3.0.0(date-fns@3.6.0)':
|
||||
dependencies:
|
||||
'@date-io/core': 3.0.0
|
||||
optionalDependencies:
|
||||
date-fns: 3.6.0
|
||||
|
||||
'@emotion/babel-plugin@11.12.0':
|
||||
dependencies:
|
||||
'@babel/helper-module-imports': 7.22.15
|
||||
'@babel/runtime': 7.25.0
|
||||
'@babel/runtime': 7.25.6
|
||||
'@emotion/hash': 0.9.2
|
||||
'@emotion/memoize': 0.9.0
|
||||
'@emotion/serialize': 1.3.0
|
||||
@@ -1155,6 +1169,7 @@ snapshots:
|
||||
find-root: 1.1.0
|
||||
source-map: 0.5.7
|
||||
stylis: 4.2.0
|
||||
optional: true
|
||||
|
||||
'@emotion/cache@11.13.1':
|
||||
dependencies:
|
||||
@@ -1164,17 +1179,19 @@ snapshots:
|
||||
'@emotion/weak-memoize': 0.4.0
|
||||
stylis: 4.2.0
|
||||
|
||||
'@emotion/hash@0.9.2': {}
|
||||
'@emotion/hash@0.9.2':
|
||||
optional: true
|
||||
|
||||
'@emotion/is-prop-valid@1.3.0':
|
||||
dependencies:
|
||||
'@emotion/memoize': 0.9.0
|
||||
optional: true
|
||||
|
||||
'@emotion/memoize@0.9.0': {}
|
||||
|
||||
'@emotion/react@11.13.0(@types/react@18.3.3)(react@18.3.1)':
|
||||
dependencies:
|
||||
'@babel/runtime': 7.25.0
|
||||
'@babel/runtime': 7.25.6
|
||||
'@emotion/babel-plugin': 11.12.0
|
||||
'@emotion/cache': 11.13.1
|
||||
'@emotion/serialize': 1.3.0
|
||||
@@ -1185,6 +1202,7 @@ snapshots:
|
||||
react: 18.3.1
|
||||
optionalDependencies:
|
||||
'@types/react': 18.3.3
|
||||
optional: true
|
||||
|
||||
'@emotion/serialize@1.3.0':
|
||||
dependencies:
|
||||
@@ -1193,12 +1211,13 @@ snapshots:
|
||||
'@emotion/unitless': 0.9.0
|
||||
'@emotion/utils': 1.4.0
|
||||
csstype: 3.1.3
|
||||
optional: true
|
||||
|
||||
'@emotion/sheet@1.4.0': {}
|
||||
|
||||
'@emotion/styled@11.13.0(@emotion/react@11.13.0(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react@18.3.1)':
|
||||
dependencies:
|
||||
'@babel/runtime': 7.25.0
|
||||
'@babel/runtime': 7.25.6
|
||||
'@emotion/babel-plugin': 11.12.0
|
||||
'@emotion/is-prop-valid': 1.3.0
|
||||
'@emotion/react': 11.13.0(@types/react@18.3.3)(react@18.3.1)
|
||||
@@ -1208,12 +1227,15 @@ snapshots:
|
||||
react: 18.3.1
|
||||
optionalDependencies:
|
||||
'@types/react': 18.3.3
|
||||
optional: true
|
||||
|
||||
'@emotion/unitless@0.9.0': {}
|
||||
'@emotion/unitless@0.9.0':
|
||||
optional: true
|
||||
|
||||
'@emotion/use-insertion-effect-with-fallbacks@1.1.0(react@18.3.1)':
|
||||
dependencies:
|
||||
react: 18.3.1
|
||||
optional: true
|
||||
|
||||
'@emotion/utils@1.4.0': {}
|
||||
|
||||
@@ -1304,17 +1326,25 @@ snapshots:
|
||||
|
||||
'@kurkle/color@0.3.2': {}
|
||||
|
||||
'@mui/core-downloads-tracker@5.16.6': {}
|
||||
'@mui/core-downloads-tracker@6.1.1': {}
|
||||
|
||||
'@mui/material@5.16.6(@emotion/react@11.13.0(@types/react@18.3.3)(react@18.3.1))(@emotion/styled@11.13.0(@emotion/react@11.13.0(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
|
||||
'@mui/icons-material@6.1.1(@mui/material@6.1.1(@emotion/react@11.13.0(@types/react@18.3.3)(react@18.3.1))(@emotion/styled@11.13.0(@emotion/react@11.13.0(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@types/react@18.3.3)(react@18.3.1)':
|
||||
dependencies:
|
||||
'@babel/runtime': 7.25.0
|
||||
'@mui/core-downloads-tracker': 5.16.6
|
||||
'@mui/system': 5.16.6(@emotion/react@11.13.0(@types/react@18.3.3)(react@18.3.1))(@emotion/styled@11.13.0(@emotion/react@11.13.0(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react@18.3.1)
|
||||
'@mui/types': 7.2.15(@types/react@18.3.3)
|
||||
'@mui/utils': 5.16.6(@types/react@18.3.3)(react@18.3.1)
|
||||
'@babel/runtime': 7.25.6
|
||||
'@mui/material': 6.1.1(@emotion/react@11.13.0(@types/react@18.3.3)(react@18.3.1))(@emotion/styled@11.13.0(@emotion/react@11.13.0(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
react: 18.3.1
|
||||
optionalDependencies:
|
||||
'@types/react': 18.3.3
|
||||
|
||||
'@mui/material@6.1.1(@emotion/react@11.13.0(@types/react@18.3.3)(react@18.3.1))(@emotion/styled@11.13.0(@emotion/react@11.13.0(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
|
||||
dependencies:
|
||||
'@babel/runtime': 7.25.6
|
||||
'@mui/core-downloads-tracker': 6.1.1
|
||||
'@mui/system': 6.1.1(@emotion/react@11.13.0(@types/react@18.3.3)(react@18.3.1))(@emotion/styled@11.13.0(@emotion/react@11.13.0(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react@18.3.1)
|
||||
'@mui/types': 7.2.17(@types/react@18.3.3)
|
||||
'@mui/utils': 6.1.1(@types/react@18.3.3)(react@18.3.1)
|
||||
'@popperjs/core': 2.11.8
|
||||
'@types/react-transition-group': 4.4.10
|
||||
'@types/react-transition-group': 4.4.11
|
||||
clsx: 2.1.1
|
||||
csstype: 3.1.3
|
||||
prop-types: 15.8.1
|
||||
@@ -1327,19 +1357,20 @@ snapshots:
|
||||
'@emotion/styled': 11.13.0(@emotion/react@11.13.0(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react@18.3.1)
|
||||
'@types/react': 18.3.3
|
||||
|
||||
'@mui/private-theming@5.16.6(@types/react@18.3.3)(react@18.3.1)':
|
||||
'@mui/private-theming@6.1.1(@types/react@18.3.3)(react@18.3.1)':
|
||||
dependencies:
|
||||
'@babel/runtime': 7.25.0
|
||||
'@mui/utils': 5.16.6(@types/react@18.3.3)(react@18.3.1)
|
||||
'@babel/runtime': 7.25.6
|
||||
'@mui/utils': 6.1.1(@types/react@18.3.3)(react@18.3.1)
|
||||
prop-types: 15.8.1
|
||||
react: 18.3.1
|
||||
optionalDependencies:
|
||||
'@types/react': 18.3.3
|
||||
|
||||
'@mui/styled-engine@5.16.6(@emotion/react@11.13.0(@types/react@18.3.3)(react@18.3.1))(@emotion/styled@11.13.0(@emotion/react@11.13.0(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react@18.3.1))(react@18.3.1)':
|
||||
'@mui/styled-engine@6.1.1(@emotion/react@11.13.0(@types/react@18.3.3)(react@18.3.1))(@emotion/styled@11.13.0(@emotion/react@11.13.0(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react@18.3.1))(react@18.3.1)':
|
||||
dependencies:
|
||||
'@babel/runtime': 7.25.0
|
||||
'@babel/runtime': 7.25.6
|
||||
'@emotion/cache': 11.13.1
|
||||
'@emotion/sheet': 1.4.0
|
||||
csstype: 3.1.3
|
||||
prop-types: 15.8.1
|
||||
react: 18.3.1
|
||||
@@ -1347,13 +1378,13 @@ snapshots:
|
||||
'@emotion/react': 11.13.0(@types/react@18.3.3)(react@18.3.1)
|
||||
'@emotion/styled': 11.13.0(@emotion/react@11.13.0(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react@18.3.1)
|
||||
|
||||
'@mui/system@5.16.6(@emotion/react@11.13.0(@types/react@18.3.3)(react@18.3.1))(@emotion/styled@11.13.0(@emotion/react@11.13.0(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react@18.3.1)':
|
||||
'@mui/system@6.1.1(@emotion/react@11.13.0(@types/react@18.3.3)(react@18.3.1))(@emotion/styled@11.13.0(@emotion/react@11.13.0(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react@18.3.1)':
|
||||
dependencies:
|
||||
'@babel/runtime': 7.25.0
|
||||
'@mui/private-theming': 5.16.6(@types/react@18.3.3)(react@18.3.1)
|
||||
'@mui/styled-engine': 5.16.6(@emotion/react@11.13.0(@types/react@18.3.3)(react@18.3.1))(@emotion/styled@11.13.0(@emotion/react@11.13.0(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react@18.3.1))(react@18.3.1)
|
||||
'@mui/types': 7.2.15(@types/react@18.3.3)
|
||||
'@mui/utils': 5.16.6(@types/react@18.3.3)(react@18.3.1)
|
||||
'@babel/runtime': 7.25.6
|
||||
'@mui/private-theming': 6.1.1(@types/react@18.3.3)(react@18.3.1)
|
||||
'@mui/styled-engine': 6.1.1(@emotion/react@11.13.0(@types/react@18.3.3)(react@18.3.1))(@emotion/styled@11.13.0(@emotion/react@11.13.0(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react@18.3.1))(react@18.3.1)
|
||||
'@mui/types': 7.2.17(@types/react@18.3.3)
|
||||
'@mui/utils': 6.1.1(@types/react@18.3.3)(react@18.3.1)
|
||||
clsx: 2.1.1
|
||||
csstype: 3.1.3
|
||||
prop-types: 15.8.1
|
||||
@@ -1363,14 +1394,14 @@ snapshots:
|
||||
'@emotion/styled': 11.13.0(@emotion/react@11.13.0(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react@18.3.1)
|
||||
'@types/react': 18.3.3
|
||||
|
||||
'@mui/types@7.2.15(@types/react@18.3.3)':
|
||||
'@mui/types@7.2.17(@types/react@18.3.3)':
|
||||
optionalDependencies:
|
||||
'@types/react': 18.3.3
|
||||
|
||||
'@mui/utils@5.16.6(@types/react@18.3.3)(react@18.3.1)':
|
||||
dependencies:
|
||||
'@babel/runtime': 7.25.0
|
||||
'@mui/types': 7.2.15(@types/react@18.3.3)
|
||||
'@babel/runtime': 7.25.6
|
||||
'@mui/types': 7.2.17(@types/react@18.3.3)
|
||||
'@types/prop-types': 15.7.12
|
||||
clsx: 2.1.1
|
||||
prop-types: 15.8.1
|
||||
@@ -1379,13 +1410,26 @@ snapshots:
|
||||
optionalDependencies:
|
||||
'@types/react': 18.3.3
|
||||
|
||||
'@mui/x-date-pickers@7.12.0(@emotion/react@11.13.0(@types/react@18.3.3)(react@18.3.1))(@emotion/styled@11.13.0(@emotion/react@11.13.0(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react@18.3.1))(@mui/material@5.16.6(@emotion/react@11.13.0(@types/react@18.3.3)(react@18.3.1))(@emotion/styled@11.13.0(@emotion/react@11.13.0(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@types/react@18.3.3)(date-fns@3.6.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
|
||||
'@mui/utils@6.1.1(@types/react@18.3.3)(react@18.3.1)':
|
||||
dependencies:
|
||||
'@babel/runtime': 7.25.0
|
||||
'@mui/material': 5.16.6(@emotion/react@11.13.0(@types/react@18.3.3)(react@18.3.1))(@emotion/styled@11.13.0(@emotion/react@11.13.0(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
'@mui/system': 5.16.6(@emotion/react@11.13.0(@types/react@18.3.3)(react@18.3.1))(@emotion/styled@11.13.0(@emotion/react@11.13.0(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react@18.3.1)
|
||||
'@babel/runtime': 7.25.6
|
||||
'@mui/types': 7.2.17(@types/react@18.3.3)
|
||||
'@types/prop-types': 15.7.12
|
||||
clsx: 2.1.1
|
||||
prop-types: 15.8.1
|
||||
react: 18.3.1
|
||||
react-is: 18.3.1
|
||||
optionalDependencies:
|
||||
'@types/react': 18.3.3
|
||||
|
||||
'@mui/x-date-pickers@7.18.0(@emotion/react@11.13.0(@types/react@18.3.3)(react@18.3.1))(@emotion/styled@11.13.0(@emotion/react@11.13.0(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react@18.3.1))(@mui/material@6.1.1(@emotion/react@11.13.0(@types/react@18.3.3)(react@18.3.1))(@emotion/styled@11.13.0(@emotion/react@11.13.0(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mui/system@6.1.1(@emotion/react@11.13.0(@types/react@18.3.3)(react@18.3.1))(@emotion/styled@11.13.0(@emotion/react@11.13.0(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(date-fns@3.6.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
|
||||
dependencies:
|
||||
'@babel/runtime': 7.25.6
|
||||
'@mui/material': 6.1.1(@emotion/react@11.13.0(@types/react@18.3.3)(react@18.3.1))(@emotion/styled@11.13.0(@emotion/react@11.13.0(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
'@mui/system': 6.1.1(@emotion/react@11.13.0(@types/react@18.3.3)(react@18.3.1))(@emotion/styled@11.13.0(@emotion/react@11.13.0(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react@18.3.1)
|
||||
'@mui/utils': 5.16.6(@types/react@18.3.3)(react@18.3.1)
|
||||
'@types/react-transition-group': 4.4.10
|
||||
'@mui/x-internals': 7.18.0(@types/react@18.3.3)(react@18.3.1)
|
||||
'@types/react-transition-group': 4.4.11
|
||||
clsx: 2.1.1
|
||||
prop-types: 15.8.1
|
||||
react: 18.3.1
|
||||
@@ -1398,6 +1442,14 @@ snapshots:
|
||||
transitivePeerDependencies:
|
||||
- '@types/react'
|
||||
|
||||
'@mui/x-internals@7.18.0(@types/react@18.3.3)(react@18.3.1)':
|
||||
dependencies:
|
||||
'@babel/runtime': 7.25.6
|
||||
'@mui/utils': 5.16.6(@types/react@18.3.3)(react@18.3.1)
|
||||
react: 18.3.1
|
||||
transitivePeerDependencies:
|
||||
- '@types/react'
|
||||
|
||||
'@popperjs/core@2.11.8': {}
|
||||
|
||||
'@preact/preset-vite@2.8.1(@babel/core@7.23.7)(preact@10.19.3)(vite@4.5.1)':
|
||||
@@ -1456,11 +1508,12 @@ snapshots:
|
||||
|
||||
'@trpc/server@10.45.0': {}
|
||||
|
||||
'@types/parse-json@4.0.2': {}
|
||||
'@types/parse-json@4.0.2':
|
||||
optional: true
|
||||
|
||||
'@types/prop-types@15.7.12': {}
|
||||
|
||||
'@types/react-transition-group@4.4.10':
|
||||
'@types/react-transition-group@4.4.11':
|
||||
dependencies:
|
||||
'@types/react': 18.3.3
|
||||
|
||||
@@ -1475,9 +1528,10 @@ snapshots:
|
||||
|
||||
babel-plugin-macros@3.1.0:
|
||||
dependencies:
|
||||
'@babel/runtime': 7.25.0
|
||||
'@babel/runtime': 7.25.6
|
||||
cosmiconfig: 7.1.0
|
||||
resolve: 1.22.8
|
||||
optional: true
|
||||
|
||||
babel-plugin-transform-hook-names@1.0.2(@babel/core@7.23.7):
|
||||
dependencies:
|
||||
@@ -1492,7 +1546,8 @@ snapshots:
|
||||
node-releases: 2.0.14
|
||||
update-browserslist-db: 1.0.13(browserslist@4.22.2)
|
||||
|
||||
callsites@3.1.0: {}
|
||||
callsites@3.1.0:
|
||||
optional: true
|
||||
|
||||
caniuse-lite@1.0.30001575: {}
|
||||
|
||||
@@ -1514,7 +1569,8 @@ snapshots:
|
||||
|
||||
color-name@1.1.3: {}
|
||||
|
||||
convert-source-map@1.9.0: {}
|
||||
convert-source-map@1.9.0:
|
||||
optional: true
|
||||
|
||||
convert-source-map@2.0.0: {}
|
||||
|
||||
@@ -1525,6 +1581,7 @@ snapshots:
|
||||
parse-json: 5.2.0
|
||||
path-type: 4.0.0
|
||||
yaml: 1.10.2
|
||||
optional: true
|
||||
|
||||
css-select@5.1.0:
|
||||
dependencies:
|
||||
@@ -1576,6 +1633,7 @@ snapshots:
|
||||
error-ex@1.3.2:
|
||||
dependencies:
|
||||
is-arrayish: 0.2.1
|
||||
optional: true
|
||||
|
||||
esbuild@0.18.20:
|
||||
optionalDependencies:
|
||||
@@ -1606,11 +1664,13 @@ snapshots:
|
||||
|
||||
escape-string-regexp@1.0.5: {}
|
||||
|
||||
escape-string-regexp@4.0.0: {}
|
||||
escape-string-regexp@4.0.0:
|
||||
optional: true
|
||||
|
||||
estree-walker@2.0.2: {}
|
||||
|
||||
find-root@1.1.0: {}
|
||||
find-root@1.1.0:
|
||||
optional: true
|
||||
|
||||
fsevents@2.3.3:
|
||||
optional: true
|
||||
@@ -1632,13 +1692,16 @@ snapshots:
|
||||
hoist-non-react-statics@3.3.2:
|
||||
dependencies:
|
||||
react-is: 16.13.1
|
||||
optional: true
|
||||
|
||||
import-fresh@3.3.0:
|
||||
dependencies:
|
||||
parent-module: 1.0.1
|
||||
resolve-from: 4.0.0
|
||||
optional: true
|
||||
|
||||
is-arrayish@0.2.1: {}
|
||||
is-arrayish@0.2.1:
|
||||
optional: true
|
||||
|
||||
is-core-module@2.13.1:
|
||||
dependencies:
|
||||
@@ -1648,13 +1711,15 @@ snapshots:
|
||||
|
||||
jsesc@2.5.2: {}
|
||||
|
||||
json-parse-even-better-errors@2.3.1: {}
|
||||
json-parse-even-better-errors@2.3.1:
|
||||
optional: true
|
||||
|
||||
json5@2.2.3: {}
|
||||
|
||||
kolorist@1.8.0: {}
|
||||
|
||||
lines-and-columns@1.2.4: {}
|
||||
lines-and-columns@1.2.4:
|
||||
optional: true
|
||||
|
||||
loose-envify@1.4.0:
|
||||
dependencies:
|
||||
@@ -1688,6 +1753,7 @@ snapshots:
|
||||
parent-module@1.0.1:
|
||||
dependencies:
|
||||
callsites: 3.1.0
|
||||
optional: true
|
||||
|
||||
parse-json@5.2.0:
|
||||
dependencies:
|
||||
@@ -1695,10 +1761,12 @@ snapshots:
|
||||
error-ex: 1.3.2
|
||||
json-parse-even-better-errors: 2.3.1
|
||||
lines-and-columns: 1.2.4
|
||||
optional: true
|
||||
|
||||
path-parse@1.0.7: {}
|
||||
|
||||
path-type@4.0.0: {}
|
||||
path-type@4.0.0:
|
||||
optional: true
|
||||
|
||||
picocolors@1.0.0: {}
|
||||
|
||||
@@ -1761,7 +1829,8 @@ snapshots:
|
||||
|
||||
regenerator-runtime@0.14.1: {}
|
||||
|
||||
resolve-from@4.0.0: {}
|
||||
resolve-from@4.0.0:
|
||||
optional: true
|
||||
|
||||
resolve@1.22.8:
|
||||
dependencies:
|
||||
@@ -1781,7 +1850,8 @@ snapshots:
|
||||
|
||||
source-map-js@1.2.0: {}
|
||||
|
||||
source-map@0.5.7: {}
|
||||
source-map@0.5.7:
|
||||
optional: true
|
||||
|
||||
stylis@4.2.0: {}
|
||||
|
||||
@@ -1811,4 +1881,5 @@ snapshots:
|
||||
|
||||
yallist@3.1.1: {}
|
||||
|
||||
yaml@1.10.2: {}
|
||||
yaml@1.10.2:
|
||||
optional: true
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import { signal, computed } from "@preact/signals";
|
||||
import { useEffect } from "preact/hooks";
|
||||
import { trpc } from "../trpc.js";
|
||||
import {
|
||||
@@ -14,188 +13,50 @@ import {
|
||||
Container,
|
||||
Grid,
|
||||
Typography,
|
||||
TextField,
|
||||
Select,
|
||||
MenuItem,
|
||||
InputLabel,
|
||||
FormControl,
|
||||
Paper,
|
||||
Popper,
|
||||
ClickAwayListener,
|
||||
} from "@mui/material";
|
||||
import {
|
||||
availableUnderlyings,
|
||||
calendarExitPriceChartData,
|
||||
isPopperOpen,
|
||||
lookbackPeriodEnd,
|
||||
lookbackPeriodStart,
|
||||
maxChartPrice,
|
||||
maxN,
|
||||
popperAnchorEl,
|
||||
popperContent,
|
||||
similarCalendarPriceChartData,
|
||||
stockPriceChartData,
|
||||
underlying,
|
||||
} from "./HistoricalCalendarPrices/state.js";
|
||||
import { EditableStrike } from "./HistoricalCalendarPrices/EditableStrike.js";
|
||||
import {
|
||||
refreshcalendarExitPriceChartData,
|
||||
refreshSimilarCalendarPriceChartData,
|
||||
refreshStockPriceChartData,
|
||||
} from "./HistoricalCalendarPrices/actions.js";
|
||||
import { EditableUnderlying } from "./HistoricalCalendarPrices/EditableUnderlying.js";
|
||||
import { EditableDaysToFrontExpiration } from "./HistoricalCalendarPrices/EditableDaysToFrontExpiration.js";
|
||||
import { EditableExitToFrontExpiration } from "./HistoricalCalendarPrices/EditableExitToFrontExpiration.js";
|
||||
import { EditableDaysBetweenFrontAndBackExpiration } from "./HistoricalCalendarPrices/EditableDaysBetweenFrontAndBackExpiration.js";
|
||||
import { EditableLookbackPeriodStart } from "./HistoricalCalendarPrices/EditableLookbackPeriodStart.js";
|
||||
import { EditableLookbackPeriodEnd } from "./HistoricalCalendarPrices/EditableLookbackPeriodEnd.js";
|
||||
|
||||
ChartJS.register(LinearScale, CategoryScale, PointElement, Tooltip, Title);
|
||||
|
||||
const availableUnderlyings = signal([]);
|
||||
const chosenUnderlying = signal(null);
|
||||
|
||||
const chosenDaysToFrontExpiration = signal(14);
|
||||
|
||||
const chosenDaysBetweenFrontAndBackExpiration = signal(14);
|
||||
|
||||
const chosenStrikePercentageFromUnderlyingPrice = signal(1.4);
|
||||
const chosenStrikePercentageFromUnderlyingPriceRadius = signal(0.05);
|
||||
|
||||
const chosenExitToFrontExpiration = signal(2);
|
||||
|
||||
const historicalStockQuoteChartData = signal([]);
|
||||
|
||||
const historicalCalendarQuoteChartData = signal([]);
|
||||
|
||||
const historicalCalendarExitQuoteChartData = signal([]);
|
||||
|
||||
const chosenLookbackPeriodStart = signal("2022-01-01");
|
||||
const chosenLookbackPeriodEnd = signal("2024-01-01");
|
||||
|
||||
const maxChartPrice = computed(() =>
|
||||
Math.max(
|
||||
Math.max.apply(
|
||||
null,
|
||||
historicalCalendarQuoteChartData.value.map((d) => d.y),
|
||||
),
|
||||
Math.max.apply(
|
||||
null,
|
||||
historicalCalendarExitQuoteChartData.value.map((d) => d.y),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
const maxN = computed(() =>
|
||||
Math.max.apply(
|
||||
null,
|
||||
historicalCalendarExitQuoteChartData.value.map((d) => d.n),
|
||||
),
|
||||
);
|
||||
|
||||
const refreshHistoricalStockQuoteChartData = () => {
|
||||
historicalStockQuoteChartData.value = [];
|
||||
trpc.getHistoricalStockQuoteChartData
|
||||
.query({
|
||||
underlying: chosenUnderlying.value,
|
||||
lookbackPeriodStart: chosenLookbackPeriodStart.value,
|
||||
lookbackPeriodEnd: chosenLookbackPeriodEnd.value,
|
||||
})
|
||||
.then((getHistoricalStockQuoteChartDataResponse) => {
|
||||
historicalStockQuoteChartData.value =
|
||||
getHistoricalStockQuoteChartDataResponse;
|
||||
});
|
||||
};
|
||||
const refreshHistoricalCalendarQuoteChartData = () => {
|
||||
historicalCalendarQuoteChartData.value = [];
|
||||
trpc.getHistoricalCalendarQuoteChartData
|
||||
.query({
|
||||
underlying: chosenUnderlying.value,
|
||||
daysToFrontExpiration: chosenDaysToFrontExpiration.value,
|
||||
daysBetweenFrontAndBackExpiration:
|
||||
chosenDaysBetweenFrontAndBackExpiration.value,
|
||||
strikePercentageFromUnderlyingPriceRangeMin:
|
||||
chosenStrikePercentageFromUnderlyingPrice.value -
|
||||
chosenStrikePercentageFromUnderlyingPriceRadius.value,
|
||||
strikePercentageFromUnderlyingPriceRangeMax:
|
||||
chosenStrikePercentageFromUnderlyingPrice.value +
|
||||
chosenStrikePercentageFromUnderlyingPriceRadius.value,
|
||||
lookbackPeriodStart: chosenLookbackPeriodStart.value,
|
||||
lookbackPeriodEnd: chosenLookbackPeriodEnd.value,
|
||||
})
|
||||
.then((getHistoricalCalendarQuoteChartDataResponse) => {
|
||||
historicalCalendarQuoteChartData.value =
|
||||
getHistoricalCalendarQuoteChartDataResponse;
|
||||
});
|
||||
};
|
||||
const refreshHistoricalCalendarExitQuoteChartData = () => {
|
||||
historicalCalendarExitQuoteChartData.value = [];
|
||||
trpc.getHistoricalCalendarExitQuoteChartData
|
||||
.query({
|
||||
underlying: chosenUnderlying.value,
|
||||
daysToFrontExpiration: chosenExitToFrontExpiration.value,
|
||||
daysBetweenFrontAndBackExpiration:
|
||||
chosenDaysBetweenFrontAndBackExpiration.value,
|
||||
lookbackPeriodStart: chosenLookbackPeriodStart.value,
|
||||
lookbackPeriodEnd: chosenLookbackPeriodEnd.value,
|
||||
})
|
||||
.then((getHistoricalCalendarExitQuoteChartDataResponse) => {
|
||||
historicalCalendarExitQuoteChartData.value =
|
||||
getHistoricalCalendarExitQuoteChartDataResponse;
|
||||
});
|
||||
};
|
||||
const handleInit = () => {
|
||||
trpc.getAvailableUnderlyings.query().then((availableUnderlyingsResponse) => {
|
||||
trpc.CalendarCharacteristicsForm.getAvailableUnderlyings
|
||||
.query()
|
||||
.then((availableUnderlyingsResponse) => {
|
||||
availableUnderlyings.value = availableUnderlyingsResponse;
|
||||
chosenUnderlying.value = availableUnderlyingsResponse[0];
|
||||
refreshHistoricalStockQuoteChartData();
|
||||
refreshHistoricalCalendarQuoteChartData();
|
||||
refreshHistoricalCalendarExitQuoteChartData();
|
||||
underlying.value = availableUnderlyingsResponse[0];
|
||||
refreshStockPriceChartData();
|
||||
refreshSimilarCalendarPriceChartData();
|
||||
refreshcalendarExitPriceChartData();
|
||||
});
|
||||
};
|
||||
const handleUnderlyingChange = (e) => {
|
||||
if (chosenUnderlying.value !== e.target.value) {
|
||||
chosenUnderlying.value = e.target.value;
|
||||
refreshHistoricalStockQuoteChartData();
|
||||
refreshHistoricalCalendarQuoteChartData();
|
||||
refreshHistoricalCalendarExitQuoteChartData();
|
||||
}
|
||||
};
|
||||
const handleDaysToFrontExpirationChange = (e) => {
|
||||
if (chosenDaysToFrontExpiration.value !== Number.parseInt(e.target.value)) {
|
||||
chosenDaysToFrontExpiration.value = Number.parseInt(e.target.value);
|
||||
refreshHistoricalCalendarQuoteChartData();
|
||||
}
|
||||
};
|
||||
const handleDaysBetweenFrontAndBackExpirationChange = (e) => {
|
||||
if (
|
||||
chosenDaysBetweenFrontAndBackExpiration.value !==
|
||||
Number.parseInt(e.target.value)
|
||||
) {
|
||||
chosenDaysBetweenFrontAndBackExpiration.value = Number.parseInt(
|
||||
e.target.value,
|
||||
);
|
||||
refreshHistoricalCalendarQuoteChartData();
|
||||
refreshHistoricalCalendarExitQuoteChartData();
|
||||
}
|
||||
};
|
||||
const handleStrikePercentageFromUnderlyingPriceChange = (e) => {
|
||||
if (
|
||||
chosenStrikePercentageFromUnderlyingPrice.value !==
|
||||
Number.parseFloat(e.target.value)
|
||||
) {
|
||||
chosenStrikePercentageFromUnderlyingPrice.value = Number.parseFloat(
|
||||
e.target.value,
|
||||
);
|
||||
refreshHistoricalCalendarQuoteChartData();
|
||||
}
|
||||
};
|
||||
const handleStrikePercentageFromUnderlyingPriceRadiusChange = (e) => {
|
||||
if (
|
||||
chosenStrikePercentageFromUnderlyingPriceRadius.value !==
|
||||
Number.parseFloat(e.target.value)
|
||||
) {
|
||||
chosenStrikePercentageFromUnderlyingPriceRadius.value = Number.parseFloat(
|
||||
e.target.value,
|
||||
);
|
||||
refreshHistoricalCalendarQuoteChartData();
|
||||
}
|
||||
};
|
||||
const handleExitToFrontExpirationChange = (e) => {
|
||||
if (chosenExitToFrontExpiration.value !== Number.parseInt(e.target.value)) {
|
||||
chosenExitToFrontExpiration.value = Number.parseInt(e.target.value);
|
||||
refreshHistoricalCalendarExitQuoteChartData();
|
||||
}
|
||||
};
|
||||
|
||||
const handleLookbackPeriodStartChange = (e) => {
|
||||
if (chosenLookbackPeriodStart.value !== e.target.value) {
|
||||
chosenLookbackPeriodStart.value = e.target.value;
|
||||
refreshHistoricalStockQuoteChartData();
|
||||
refreshHistoricalCalendarQuoteChartData();
|
||||
refreshHistoricalCalendarExitQuoteChartData();
|
||||
}
|
||||
};
|
||||
const handleLookbackPeriodEndChange = (e) => {
|
||||
if (chosenLookbackPeriodEnd.value !== e.target.value) {
|
||||
chosenLookbackPeriodEnd.value = e.target.value;
|
||||
refreshHistoricalStockQuoteChartData();
|
||||
refreshHistoricalCalendarQuoteChartData();
|
||||
refreshHistoricalCalendarExitQuoteChartData();
|
||||
}
|
||||
};
|
||||
|
||||
export function HistoricalCalendarPrices() {
|
||||
useEffect(handleInit, []);
|
||||
@@ -205,121 +66,44 @@ export function HistoricalCalendarPrices() {
|
||||
<Grid container spacing={4}>
|
||||
<Grid item xs={12}>
|
||||
<Typography variant="h4" gutterBottom>
|
||||
Historical Calendar Prices
|
||||
<EditableUnderlying /> :
|
||||
<EditableDaysBetweenFrontAndBackExpiration />
|
||||
-Day Calendar @ <EditableStrike />
|
||||
%-from-the-money
|
||||
</Typography>
|
||||
</Grid>
|
||||
<Grid item xs={12} md={6}>
|
||||
<Paper elevation={3} sx={{ p: 3 }}>
|
||||
<Grid container spacing={2}>
|
||||
<Grid item xs={12}>
|
||||
<FormControl fullWidth>
|
||||
<InputLabel>Available Underlyings</InputLabel>
|
||||
<Select
|
||||
value={chosenUnderlying.value || ""}
|
||||
onChange={handleUnderlyingChange}
|
||||
label="Available Underlyings"
|
||||
<Typography variant="h5" gutterBottom sx={{ pl: 1 }}>
|
||||
Opening at <EditableDaysToFrontExpiration /> DTE, Closing at{" "}
|
||||
<EditableExitToFrontExpiration />
|
||||
DTE
|
||||
</Typography>
|
||||
<Typography variant="h5" gutterBottom>
|
||||
<EditableLookbackPeriodStart />-
|
||||
<EditableLookbackPeriodEnd />
|
||||
</Typography>
|
||||
<ClickAwayListener
|
||||
onClickAway={() => {
|
||||
isPopperOpen.value = false;
|
||||
// refreshSimilarCalendarPriceChartData();
|
||||
console.log("clicked away");
|
||||
}}
|
||||
>
|
||||
{availableUnderlyings.value.map((underlying) => (
|
||||
<MenuItem key={underlying} value={underlying}>
|
||||
{underlying}
|
||||
</MenuItem>
|
||||
))}
|
||||
</Select>
|
||||
</FormControl>
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<TextField
|
||||
fullWidth
|
||||
label="Now-to-Front-Month Days to Expiration"
|
||||
type="number"
|
||||
value={chosenDaysToFrontExpiration.value}
|
||||
onChange={handleDaysToFrontExpirationChange}
|
||||
InputProps={{ endAdornment: "Days" }}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<TextField
|
||||
fullWidth
|
||||
label="Front-to-Back-Month Days to Expiration Difference"
|
||||
type="number"
|
||||
value={chosenDaysBetweenFrontAndBackExpiration.value}
|
||||
onChange={handleDaysBetweenFrontAndBackExpirationChange}
|
||||
InputProps={{ endAdornment: "Days Difference" }}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={6}>
|
||||
<TextField
|
||||
fullWidth
|
||||
label="Strike % From Underlying Price"
|
||||
type="number"
|
||||
value={chosenStrikePercentageFromUnderlyingPrice.value}
|
||||
onChange={handleStrikePercentageFromUnderlyingPriceChange}
|
||||
InputProps={{ endAdornment: "%" }}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={6}>
|
||||
<TextField
|
||||
fullWidth
|
||||
label="Strike % Radius"
|
||||
type="number"
|
||||
value={chosenStrikePercentageFromUnderlyingPriceRadius.value}
|
||||
onChange={
|
||||
handleStrikePercentageFromUnderlyingPriceRadiusChange
|
||||
}
|
||||
InputProps={{ endAdornment: "%" }}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<TextField
|
||||
fullWidth
|
||||
label="Exit-to-Front-Month Days to Expiration"
|
||||
type="number"
|
||||
value={chosenExitToFrontExpiration.value}
|
||||
onChange={handleExitToFrontExpirationChange}
|
||||
InputProps={{ endAdornment: "Days" }}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={6}>
|
||||
<TextField
|
||||
fullWidth
|
||||
label="Lookback Period Start"
|
||||
type="date"
|
||||
value={chosenLookbackPeriodStart.value}
|
||||
onChange={(e) =>
|
||||
handleLookbackPeriodStartChange({
|
||||
target: { value: e.target.value },
|
||||
})
|
||||
}
|
||||
InputLabelProps={{ shrink: true }}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={6}>
|
||||
<TextField
|
||||
fullWidth
|
||||
label="Lookback Period End"
|
||||
type="date"
|
||||
value={chosenLookbackPeriodEnd.value}
|
||||
onChange={(e) =>
|
||||
handleLookbackPeriodEndChange({
|
||||
target: { value: e.target.value },
|
||||
})
|
||||
}
|
||||
InputLabelProps={{ shrink: true }}
|
||||
/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
<Popper open={isPopperOpen.value} anchorEl={popperAnchorEl.value}>
|
||||
<Paper elevation={3} sx={{ p: 3 }}>
|
||||
{popperContent.value}
|
||||
</Paper>
|
||||
</Popper>
|
||||
</ClickAwayListener>
|
||||
</Grid>
|
||||
<Grid item xs={12} md={6}>
|
||||
<Paper elevation={3} sx={{ p: 3, height: "100%" }}>
|
||||
{chosenUnderlying.value !== null &&
|
||||
historicalStockQuoteChartData.value.length > 0 ? (
|
||||
<Grid item xs={12}>
|
||||
<Paper elevation={3} sx={{ p: 3, minHeight: "28em", height: "100%" }}>
|
||||
{underlying.value !== null &&
|
||||
stockPriceChartData.value.length > 0 ? (
|
||||
<Scatter
|
||||
data={{
|
||||
datasets: [
|
||||
{
|
||||
label: "Stock Open Price",
|
||||
data: historicalStockQuoteChartData.value,
|
||||
data: stockPriceChartData.value,
|
||||
},
|
||||
],
|
||||
}}
|
||||
@@ -336,12 +120,8 @@ export function HistoricalCalendarPrices() {
|
||||
.toISOString()
|
||||
.substring(0, 10),
|
||||
},
|
||||
min:
|
||||
new Date(chosenLookbackPeriodStart.value).getTime() /
|
||||
1000,
|
||||
max:
|
||||
new Date(chosenLookbackPeriodEnd.value).getTime() /
|
||||
1000,
|
||||
min: new Date(lookbackPeriodStart.value).getTime() / 1000,
|
||||
max: new Date(lookbackPeriodEnd.value).getTime() / 1000,
|
||||
},
|
||||
y: {
|
||||
beginAtZero: false,
|
||||
@@ -379,16 +159,16 @@ export function HistoricalCalendarPrices() {
|
||||
)}
|
||||
</Paper>
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<Paper elevation={3} sx={{ p: 3 }}>
|
||||
{chosenUnderlying.value !== null &&
|
||||
historicalCalendarQuoteChartData.value.length > 0 ? (
|
||||
<Grid item xs={12} md={6}>
|
||||
<Paper elevation={3} sx={{ p: 3, minHeight: "28em" }}>
|
||||
{underlying.value !== null &&
|
||||
similarCalendarPriceChartData.value.length > 0 ? (
|
||||
<Scatter
|
||||
data={{
|
||||
datasets: [
|
||||
{
|
||||
label: "Calendar Open Price",
|
||||
data: historicalCalendarQuoteChartData.value,
|
||||
data: similarCalendarPriceChartData.value,
|
||||
},
|
||||
],
|
||||
}}
|
||||
@@ -405,12 +185,8 @@ export function HistoricalCalendarPrices() {
|
||||
.toISOString()
|
||||
.substring(0, 10),
|
||||
},
|
||||
min:
|
||||
new Date(chosenLookbackPeriodStart.value).getTime() /
|
||||
1000,
|
||||
max:
|
||||
new Date(chosenLookbackPeriodEnd.value).getTime() /
|
||||
1000,
|
||||
min: new Date(lookbackPeriodStart.value).getTime() / 1000,
|
||||
max: new Date(lookbackPeriodEnd.value).getTime() / 1000,
|
||||
},
|
||||
y: {
|
||||
beginAtZero: true,
|
||||
@@ -444,16 +220,16 @@ export function HistoricalCalendarPrices() {
|
||||
)}
|
||||
</Paper>
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<Paper elevation={3} sx={{ p: 3 }}>
|
||||
{chosenUnderlying.value !== null &&
|
||||
historicalCalendarQuoteChartData.value.length > 0 ? (
|
||||
<Grid item xs={12} md={6}>
|
||||
<Paper elevation={3} sx={{ p: 3, minHeight: "28em" }}>
|
||||
{underlying.value !== null &&
|
||||
similarCalendarPriceChartData.value.length > 0 ? (
|
||||
<Scatter
|
||||
data={{
|
||||
datasets: [
|
||||
{
|
||||
label: "Calendar Exit Price",
|
||||
data: historicalCalendarExitQuoteChartData.value,
|
||||
data: calendarExitPriceChartData.value,
|
||||
},
|
||||
],
|
||||
}}
|
||||
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
import TextField from "@mui/material/TextField";
|
||||
import {
|
||||
refreshcalendarExitPriceChartData,
|
||||
refreshSimilarCalendarPriceChartData,
|
||||
} from "./actions";
|
||||
import { daysBetweenFrontAndBackExpiration } from "./state";
|
||||
import { EditableValue } from "./EditableValue";
|
||||
|
||||
const handleDaysBetweenFrontAndBackExpirationChange = (e) => {
|
||||
if (
|
||||
daysBetweenFrontAndBackExpiration.value !== Number.parseInt(e.target.value)
|
||||
) {
|
||||
daysBetweenFrontAndBackExpiration.value = Number.parseInt(e.target.value);
|
||||
refreshSimilarCalendarPriceChartData();
|
||||
refreshcalendarExitPriceChartData();
|
||||
}
|
||||
};
|
||||
|
||||
function DaysBetweenFrontAndBackExpirationChooser() {
|
||||
return (
|
||||
<TextField
|
||||
fullWidth
|
||||
label="Front-to-Back-Month Days to Expiration Difference"
|
||||
type="number"
|
||||
value={daysBetweenFrontAndBackExpiration.value}
|
||||
onChange={handleDaysBetweenFrontAndBackExpirationChange}
|
||||
InputProps={{ endAdornment: "Days Difference" }}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
export function EditableDaysBetweenFrontAndBackExpiration() {
|
||||
return (
|
||||
<EditableValue text={daysBetweenFrontAndBackExpiration.value}>
|
||||
<DaysBetweenFrontAndBackExpirationChooser />
|
||||
</EditableValue>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
import TextField from "@mui/material/TextField";
|
||||
import { refreshSimilarCalendarPriceChartData } from "./actions";
|
||||
import { EditableValue } from "./EditableValue";
|
||||
import { daysToFrontExpiration } from "./state";
|
||||
|
||||
const handleDaysToFrontExpirationChange = (e) => {
|
||||
if (daysToFrontExpiration.value !== Number.parseInt(e.target.value)) {
|
||||
daysToFrontExpiration.value = Number.parseInt(e.target.value);
|
||||
refreshSimilarCalendarPriceChartData();
|
||||
}
|
||||
};
|
||||
|
||||
function DaysToFrontExpirationChooser() {
|
||||
return (
|
||||
<TextField
|
||||
fullWidth
|
||||
label="Now-to-Front-Month Days to Expiration"
|
||||
type="number"
|
||||
value={daysToFrontExpiration.value}
|
||||
onChange={handleDaysToFrontExpirationChange}
|
||||
InputProps={{ endAdornment: "Days" }}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
export function EditableDaysToFrontExpiration() {
|
||||
return (
|
||||
<EditableValue text={daysToFrontExpiration.value}>
|
||||
<DaysToFrontExpirationChooser />
|
||||
</EditableValue>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
import TextField from "@mui/material/TextField";
|
||||
import { EditableValue } from "./EditableValue";
|
||||
import { exitToFrontExpiration } from "./state";
|
||||
import { refreshcalendarExitPriceChartData } from "./actions";
|
||||
|
||||
const handleExitToFrontExpirationChange = (e) => {
|
||||
if (exitToFrontExpiration.value !== Number.parseInt(e.target.value)) {
|
||||
exitToFrontExpiration.value = Number.parseInt(e.target.value);
|
||||
refreshcalendarExitPriceChartData();
|
||||
}
|
||||
};
|
||||
|
||||
function ExitToFrontExpirationChooser() {
|
||||
return (
|
||||
<TextField
|
||||
fullWidth
|
||||
label="Exit-to-Front-Month Days to Expiration"
|
||||
type="number"
|
||||
value={exitToFrontExpiration.value}
|
||||
onChange={handleExitToFrontExpirationChange}
|
||||
InputProps={{ endAdornment: "Days" }}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
export function EditableExitToFrontExpiration() {
|
||||
return (
|
||||
<EditableValue text={exitToFrontExpiration.value}>
|
||||
<ExitToFrontExpirationChooser />
|
||||
</EditableValue>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
import TextField from "@mui/material/TextField";
|
||||
import {
|
||||
refreshcalendarExitPriceChartData,
|
||||
refreshSimilarCalendarPriceChartData,
|
||||
refreshStockPriceChartData,
|
||||
} from "./actions";
|
||||
import { lookbackPeriodEnd } from "./state";
|
||||
import { EditableValue } from "./EditableValue";
|
||||
|
||||
const handleLookbackPeriodEndChange = (e) => {
|
||||
if (lookbackPeriodEnd.value !== e.target.value) {
|
||||
lookbackPeriodEnd.value = e.target.value;
|
||||
refreshStockPriceChartData();
|
||||
refreshSimilarCalendarPriceChartData();
|
||||
refreshcalendarExitPriceChartData();
|
||||
}
|
||||
};
|
||||
|
||||
function LookbackPeriodEndChooser() {
|
||||
return (
|
||||
<TextField
|
||||
fullWidth
|
||||
label="Lookback Period End"
|
||||
type="date"
|
||||
value={lookbackPeriodEnd.value}
|
||||
onChange={handleLookbackPeriodEndChange}
|
||||
InputLabelProps={{ shrink: true }}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
export function EditableLookbackPeriodEnd() {
|
||||
return (
|
||||
<EditableValue text={lookbackPeriodEnd.value}>
|
||||
<LookbackPeriodEndChooser />
|
||||
</EditableValue>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
import TextField from "@mui/material/TextField";
|
||||
import {
|
||||
refreshcalendarExitPriceChartData,
|
||||
refreshSimilarCalendarPriceChartData,
|
||||
refreshStockPriceChartData,
|
||||
} from "./actions";
|
||||
import { lookbackPeriodStart } from "./state";
|
||||
import { EditableValue } from "./EditableValue";
|
||||
|
||||
const handleLookbackPeriodStartChange = (e) => {
|
||||
if (lookbackPeriodStart.value !== e.target.value) {
|
||||
lookbackPeriodStart.value = e.target.value;
|
||||
refreshStockPriceChartData();
|
||||
refreshSimilarCalendarPriceChartData();
|
||||
refreshcalendarExitPriceChartData();
|
||||
}
|
||||
};
|
||||
|
||||
function LookbackPeriodStartChooser() {
|
||||
return (
|
||||
<TextField
|
||||
fullWidth
|
||||
label="Lookback Period Start"
|
||||
type="date"
|
||||
value={lookbackPeriodStart.value}
|
||||
onChange={handleLookbackPeriodStartChange}
|
||||
InputLabelProps={{ shrink: true }}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
export function EditableLookbackPeriodStart() {
|
||||
return (
|
||||
<EditableValue text={lookbackPeriodStart.value}>
|
||||
<LookbackPeriodStartChooser />
|
||||
</EditableValue>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
import Box from "@mui/material/Box";
|
||||
import { EditableValue } from "./EditableValue";
|
||||
import {
|
||||
strikePercentageFromUnderlyingPrice,
|
||||
strikePercentageFromUnderlyingPriceRadius,
|
||||
} from "./state";
|
||||
import Slider from "@mui/material/Slider";
|
||||
import { refreshSimilarCalendarPriceChartData } from "./actions";
|
||||
|
||||
function StrikePercentageFromUnderlyingPriceChooser() {
|
||||
return (
|
||||
<Slider
|
||||
fullWidth
|
||||
label="Strike % From Underlying Price"
|
||||
value={strikePercentageFromUnderlyingPrice.value}
|
||||
valueLabelDisplay="on"
|
||||
min={0}
|
||||
max={10}
|
||||
step={0.1}
|
||||
onChange={(e, value) => {
|
||||
strikePercentageFromUnderlyingPrice.value = value as number;
|
||||
}}
|
||||
onChangeCommitted={(e, value) => {
|
||||
refreshSimilarCalendarPriceChartData();
|
||||
}}
|
||||
InputProps={{ endAdornment: "%" }}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
function StrikePercentageFromUnderlyingPriceRadiusChooser() {
|
||||
return (
|
||||
<Slider
|
||||
fullWidth
|
||||
label="Strike % Radius"
|
||||
value={strikePercentageFromUnderlyingPriceRadius.value}
|
||||
valueLabelDisplay="on"
|
||||
min={0}
|
||||
max={0.5}
|
||||
step={0.05}
|
||||
onChange={(e, value) => {
|
||||
strikePercentageFromUnderlyingPriceRadius.value = value as number;
|
||||
}}
|
||||
onChangeCommitted={(e, value) => {
|
||||
refreshSimilarCalendarPriceChartData();
|
||||
}}
|
||||
InputProps={{ endAdornment: "%" }}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
/** This is its own component so that sliding the slider with the mouse is
|
||||
* smoother. Preact detects reads from the "slider" signal values, and
|
||||
* associates them with the component that read them and redraws that component.
|
||||
* If this was not its own component, it would redraw the entire UI. It was very
|
||||
* slow. */
|
||||
export function EditableStrike() {
|
||||
return (
|
||||
<EditableValue
|
||||
text={`${strikePercentageFromUnderlyingPrice.value.toFixed(
|
||||
1
|
||||
)}±${strikePercentageFromUnderlyingPriceRadius.value.toFixed(2)}`}
|
||||
>
|
||||
<Box sx={{ minWidth: "20em" }}>
|
||||
<StrikePercentageFromUnderlyingPriceChooser />
|
||||
<StrikePercentageFromUnderlyingPriceRadiusChooser />
|
||||
</Box>
|
||||
</EditableValue>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
import Select from "@mui/material/Select";
|
||||
import { EditableValue } from "./EditableValue";
|
||||
import { availableUnderlyings, underlying } from "./state";
|
||||
import MenuItem from "@mui/material/MenuItem";
|
||||
import {
|
||||
refreshcalendarExitPriceChartData,
|
||||
refreshSimilarCalendarPriceChartData,
|
||||
refreshStockPriceChartData,
|
||||
} from "./actions";
|
||||
|
||||
const handleUnderlyingChange = (e) => {
|
||||
if (underlying.value !== e.target.value) {
|
||||
underlying.value = e.target.value;
|
||||
refreshStockPriceChartData();
|
||||
refreshSimilarCalendarPriceChartData();
|
||||
refreshcalendarExitPriceChartData();
|
||||
}
|
||||
};
|
||||
|
||||
function UnderlyingChooser() {
|
||||
return (
|
||||
<Select
|
||||
value={underlying.value || ""}
|
||||
onChange={handleUnderlyingChange}
|
||||
label="Available Underlyings"
|
||||
>
|
||||
{availableUnderlyings.value.map((underlying) => (
|
||||
<MenuItem key={underlying} value={underlying}>
|
||||
{underlying}
|
||||
</MenuItem>
|
||||
))}
|
||||
</Select>
|
||||
);
|
||||
}
|
||||
|
||||
export function EditableUnderlying() {
|
||||
return (
|
||||
<EditableValue text={underlying.value}>
|
||||
<UnderlyingChooser />
|
||||
</EditableValue>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
import Button from "@mui/material/Button";
|
||||
import { isPopperOpen, popperAnchorEl, popperContent } from "./state";
|
||||
|
||||
export function EditableValue({ text, children }) {
|
||||
return (
|
||||
<Button
|
||||
variant="text"
|
||||
size="large"
|
||||
sx={{
|
||||
textDecoration: "underline",
|
||||
textUnderlineOffset: "3px",
|
||||
fontSize: "1.0em",
|
||||
}}
|
||||
onClick={(e) => {
|
||||
// stop propagation so it's not caught by the ClickAwayListener:
|
||||
e.stopPropagation();
|
||||
if (isPopperOpen.value === false) {
|
||||
isPopperOpen.value = true;
|
||||
popperAnchorEl.value = e.currentTarget;
|
||||
popperContent.value = children;
|
||||
} else {
|
||||
isPopperOpen.value = false;
|
||||
}
|
||||
}}
|
||||
>
|
||||
{text}
|
||||
</Button>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
import { trpc } from "../../trpc";
|
||||
import {
|
||||
calendarExitPriceChartData,
|
||||
daysBetweenFrontAndBackExpiration,
|
||||
daysToFrontExpiration,
|
||||
exitToFrontExpiration,
|
||||
lookbackPeriodEnd,
|
||||
lookbackPeriodStart,
|
||||
similarCalendarPriceChartData,
|
||||
stockPriceChartData,
|
||||
strikePercentageFromUnderlyingPrice,
|
||||
strikePercentageFromUnderlyingPriceRadius,
|
||||
underlying,
|
||||
} from "./state";
|
||||
|
||||
export const refreshStockPriceChartData = () => {
|
||||
stockPriceChartData.value = [];
|
||||
trpc.StockPriceChart.getChartData
|
||||
.query({
|
||||
underlying: underlying.value,
|
||||
lookbackPeriodStart: lookbackPeriodStart.value,
|
||||
lookbackPeriodEnd: lookbackPeriodEnd.value,
|
||||
})
|
||||
.then((getChartDataResponse) => {
|
||||
stockPriceChartData.value = getChartDataResponse;
|
||||
});
|
||||
};
|
||||
export const refreshSimilarCalendarPriceChartData = () => {
|
||||
similarCalendarPriceChartData.value = [];
|
||||
trpc.SimilarCalendarPriceChart.getChartData
|
||||
.query({
|
||||
underlying: underlying.value,
|
||||
daysToFrontExpiration: daysToFrontExpiration.value,
|
||||
daysBetweenFrontAndBackExpiration:
|
||||
daysBetweenFrontAndBackExpiration.value,
|
||||
strikePercentageFromUnderlyingPriceRangeMin:
|
||||
strikePercentageFromUnderlyingPrice.value -
|
||||
strikePercentageFromUnderlyingPriceRadius.value,
|
||||
strikePercentageFromUnderlyingPriceRangeMax:
|
||||
strikePercentageFromUnderlyingPrice.value +
|
||||
strikePercentageFromUnderlyingPriceRadius.value,
|
||||
lookbackPeriodStart: lookbackPeriodStart.value,
|
||||
lookbackPeriodEnd: lookbackPeriodEnd.value,
|
||||
})
|
||||
.then((getChartDataResponse) => {
|
||||
similarCalendarPriceChartData.value = getChartDataResponse;
|
||||
});
|
||||
};
|
||||
export const refreshcalendarExitPriceChartData = () => {
|
||||
calendarExitPriceChartData.value = [];
|
||||
trpc.CalendarExitPriceChart.getChartData
|
||||
.query({
|
||||
underlying: underlying.value,
|
||||
daysToFrontExpiration: exitToFrontExpiration.value,
|
||||
daysBetweenFrontAndBackExpiration:
|
||||
daysBetweenFrontAndBackExpiration.value,
|
||||
lookbackPeriodStart: lookbackPeriodStart.value,
|
||||
lookbackPeriodEnd: lookbackPeriodEnd.value,
|
||||
})
|
||||
.then((getChartDataResponse) => {
|
||||
calendarExitPriceChartData.value = getChartDataResponse;
|
||||
});
|
||||
};
|
||||
@@ -0,0 +1,46 @@
|
||||
import { computed, signal } from "@preact/signals";
|
||||
|
||||
export const isPopperOpen = signal(false);
|
||||
export const popperAnchorEl = signal(null);
|
||||
export const popperContent = signal(null);
|
||||
|
||||
export const availableUnderlyings = signal([]);
|
||||
export const underlying = signal(null);
|
||||
|
||||
export const daysToFrontExpiration = signal(14);
|
||||
|
||||
export const daysBetweenFrontAndBackExpiration = signal(14);
|
||||
|
||||
export const strikePercentageFromUnderlyingPrice = signal(1.4);
|
||||
export const strikePercentageFromUnderlyingPriceRadius = signal(0.05);
|
||||
|
||||
export const exitToFrontExpiration = signal(2);
|
||||
|
||||
export const stockPriceChartData = signal([]);
|
||||
|
||||
export const similarCalendarPriceChartData = signal([]);
|
||||
|
||||
export const calendarExitPriceChartData = signal([]);
|
||||
|
||||
export const lookbackPeriodStart = signal("2022-01-01");
|
||||
export const lookbackPeriodEnd = signal("2024-01-01");
|
||||
|
||||
export const maxChartPrice = computed(() =>
|
||||
Math.max(
|
||||
Math.max.apply(
|
||||
null,
|
||||
similarCalendarPriceChartData.value.map((d) => d.y)
|
||||
),
|
||||
Math.max.apply(
|
||||
null,
|
||||
calendarExitPriceChartData.value.map((d) => d.y)
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
export const maxN = computed(() =>
|
||||
Math.max.apply(
|
||||
null,
|
||||
calendarExitPriceChartData.value.map((d) => d.n)
|
||||
)
|
||||
);
|
||||
@@ -1,5 +1,5 @@
|
||||
import { query } from "./lib/clickhouse";
|
||||
import { publicProcedure, RpcType, router } from "./trpc";
|
||||
import { query } from "./lib/clickhouse.js";
|
||||
import { publicProcedure, RpcType, router } from "./trpc.js";
|
||||
import {
|
||||
Object as ObjectT,
|
||||
String as StringT,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { query } from "./lib/clickhouse";
|
||||
import { publicProcedure, RpcType, router } from "./trpc";
|
||||
import { query } from "./lib/clickhouse.js";
|
||||
import { publicProcedure, RpcType, router } from "./trpc.js";
|
||||
import {
|
||||
Object as ObjectT,
|
||||
String as StringT,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { query } from "./lib/clickhouse";
|
||||
import { publicProcedure, RpcType, router } from "./trpc";
|
||||
import { query } from "./lib/clickhouse.js";
|
||||
import { publicProcedure, RpcType, router } from "./trpc.js";
|
||||
import {
|
||||
Object as ObjectT,
|
||||
String as StringT,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { query } from "./lib/clickhouse";
|
||||
import { publicProcedure, RpcType, router } from "./trpc";
|
||||
import { query } from "./lib/clickhouse.js";
|
||||
import { publicProcedure, RpcType, router } from "./trpc.js";
|
||||
import { Object as ObjectT, String as StringT } from "@sinclair/typebox";
|
||||
|
||||
export const getChartData = publicProcedure
|
||||
+2
-2
@@ -9,7 +9,7 @@ import {
|
||||
} from "@sinclair/typebox";
|
||||
import { createServer } from "node:http";
|
||||
import { Env } from "@humanwhocodes/env";
|
||||
import UnderlyingPriceChart from "./UnderlyingPriceChart.js";
|
||||
import StockPriceChart from "./StockPriceChart.js";
|
||||
import SimilarCalendarPriceChart from "./SimilarCalendarPriceChart.js";
|
||||
import CalendarExitPriceChart from "./CalendarExitPriceChart.js";
|
||||
import CalendarCharacteristicsForm from "./CalendarCharacteristicsForm.js";
|
||||
@@ -71,7 +71,7 @@ export const getOpensForOptionContract = publicProcedure
|
||||
|
||||
const appRouter = router({
|
||||
CalendarCharacteristicsForm,
|
||||
UnderlyingPriceChart,
|
||||
StockPriceChart,
|
||||
SimilarCalendarPriceChart,
|
||||
CalendarExitPriceChart,
|
||||
|
||||
|
||||
Reference in New Issue
Block a user