Compare commits

..

20 Commits

Author SHA1 Message Date
avraham c83f2ce0a0 use Slider for lookback period 2025-03-03 21:35:51 -05:00
avraham 4d989f10eb gitignore Bruno files 2025-03-02 17:54:41 -05:00
avraham 906e63eb91 use line on stock price chart; more compact data transfer format 2025-03-02 17:53:59 -05:00
avraham 3732680d52 use CLICKHOUSE_URL envvar instead of CLICKHOUSE_HOST 2025-03-02 09:35:43 -05:00
avraham 3c841f488c attempt to remove outliers from chart data 2025-02-24 09:15:57 -05:00
avraham b6cc25b769 begin with narrower lookback period 2025-02-24 09:15:35 -05:00
avraham 14dff05785 fix: case where calendar exit price data is empty 2025-02-24 09:15:09 -05:00
avraham f05831b5f1 return moniness in percentage, not ratio 2025-02-23 13:20:05 -05:00
avraham b7f9d60715 friendlier variable names; use sliders for input 2025-02-23 13:11:34 -05:00
avraham b2169e1da7 adjust moniness step in form 2025-02-07 09:36:05 -05:00
avraham aeac0e1042 update Dockerfile to use latest corepack to fix npm keys 2025-02-07 09:31:34 -05:00
avraham 904d2da84a send strikePercentageFromUnderlyingPriceRange* as ratio not percentage 2025-02-07 09:30:50 -05:00
avraham 694bb38536 update Dockerfile to use latest corepack to fix npm keys 2025-02-07 09:25:33 -05:00
avraham 64a5172ea8 use new clickhouse tables 2025-02-07 09:23:47 -05:00
avraham ac9554ba21 migrated to mui Grid2 2024-10-06 15:14:30 -04:00
avraham 2597c0f6ac attempt fix: trpc routes not found 2024-09-29 20:19:51 -04:00
avraham add21288be fix: Dockerfile - no longer using postcss and tailwind 2024-09-29 20:03:58 -04:00
avraham db809d7b57 remove unused imports 2024-09-29 20:02:55 -04:00
avraham 8986dc4ea9 fully adopt @mui/material; refactor 2024-09-29 20:01:53 -04:00
avraham ea9bd307f3 refactor 2024-09-26 21:00:58 -04:00
25 changed files with 982 additions and 558 deletions
+2 -2
View File
@@ -2,14 +2,14 @@
FROM node:20-slim AS build FROM node:20-slim AS build
ENV PNPM_HOME="/pnpm" ENV PNPM_HOME="/pnpm"
ENV PATH="$PNPM_HOME:$PATH" ENV PATH="$PNPM_HOME:$PATH"
RUN corepack enable RUN npm install -g corepack@latest && corepack enable
WORKDIR /app WORKDIR /app
# copy what's necessary to install dependencies: # copy what's necessary to install dependencies:
COPY package.json pnpm-lock.yaml /app/ COPY package.json pnpm-lock.yaml /app/
# install dependencies: # install dependencies:
RUN --mount=type=cache,id=pnpm,target=/pnpm/store pnpm install --frozen-lockfile RUN --mount=type=cache,id=pnpm,target=/pnpm/store pnpm install --frozen-lockfile
# copy what's necessary to build: # 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 COPY src /app/src
# Vite injects envvars at build time, not runtime: # Vite injects envvars at build time, not runtime:
ENV VITE_SERVER_BASE_URL=https://calendar-optimizer-server.sakal.us ENV VITE_SERVER_BASE_URL=https://calendar-optimizer-server.sakal.us
+4 -6
View File
@@ -7,12 +7,10 @@
"preview": "vite preview" "preview": "vite preview"
}, },
"dependencies": { "dependencies": {
"@date-io/date-fns": "^3.0.0", "@mui/icons-material": "^6.1.1",
"@emotion/react": "^11.13.0", "@mui/material": "^6.1.1",
"@emotion/styled": "^11.13.0", "@mui/system": "^6.1.1",
"@mui/material": "^5.16.6", "@mui/x-date-pickers": "^7.18.0",
"@mui/system": "^5.16.6",
"@mui/x-date-pickers": "^7.12.0",
"@preact/signals": "^1.2.2", "@preact/signals": "^1.2.2",
"@trpc/client": "^10.45.0", "@trpc/client": "^10.45.0",
"chart.js": "^4.4.1", "chart.js": "^4.4.1",
+182 -111
View File
@@ -8,24 +8,18 @@ importers:
.: .:
dependencies: dependencies:
'@date-io/date-fns': '@mui/icons-material':
specifier: ^3.0.0 specifier: ^6.1.1
version: 3.0.0(date-fns@3.6.0) 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)
'@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/material': '@mui/material':
specifier: ^5.16.6 specifier: ^6.1.1
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) 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': '@mui/system':
specifier: ^5.16.6 specifier: ^6.1.1
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) 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': '@mui/x-date-pickers':
specifier: ^7.12.0 specifier: ^7.18.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) 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': '@preact/signals':
specifier: ^1.2.2 specifier: ^1.2.2
version: 1.2.2(preact@10.19.3) version: 1.2.2(preact@10.19.3)
@@ -178,6 +172,10 @@ packages:
resolution: {integrity: sha512-7dRy4DwXwtzBrPbZflqxnvfxLF8kdZXPkhymtDeFoFqE6ldzjQFgYTtYIFARcLEYDrqfBfYcZt1WqFxRoyC9Rw==} resolution: {integrity: sha512-7dRy4DwXwtzBrPbZflqxnvfxLF8kdZXPkhymtDeFoFqE6ldzjQFgYTtYIFARcLEYDrqfBfYcZt1WqFxRoyC9Rw==}
engines: {node: '>=6.9.0'} 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': '@babel/template@7.22.15':
resolution: {integrity: sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==} resolution: {integrity: sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==}
engines: {node: '>=6.9.0'} engines: {node: '>=6.9.0'}
@@ -190,17 +188,6 @@ packages:
resolution: {integrity: sha512-+uarb83brBzPKN38NX1MkB6vb6+mwvR6amUulqAE7ccQw1pEl+bCia9TbdG1lsnFP7lZySvUn37CHyXQdfTwzg==} resolution: {integrity: sha512-+uarb83brBzPKN38NX1MkB6vb6+mwvR6amUulqAE7ccQw1pEl+bCia9TbdG1lsnFP7lZySvUn37CHyXQdfTwzg==}
engines: {node: '>=6.9.0'} 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': '@emotion/babel-plugin@11.12.0':
resolution: {integrity: sha512-y2WQb+oP8Jqvvclh8Q55gLUyb7UFvgv7eJfsj7td5TToBrIUtPay2kMrZi4xjq9qw2vD0ZR5fSho0yqoFgX7Rw==} resolution: {integrity: sha512-y2WQb+oP8Jqvvclh8Q55gLUyb7UFvgv7eJfsj7td5TToBrIUtPay2kMrZi4xjq9qw2vD0ZR5fSho0yqoFgX7Rw==}
@@ -408,57 +395,71 @@ packages:
'@kurkle/color@0.3.2': '@kurkle/color@0.3.2':
resolution: {integrity: sha512-fuscdXJ9G1qb7W8VdHi+IwRqij3lBkosAm4ydQtEmbY58OzHXqQhvlxqEkoz0yssNVn38bcpRWgA9PP+OGoisw==} resolution: {integrity: sha512-fuscdXJ9G1qb7W8VdHi+IwRqij3lBkosAm4ydQtEmbY58OzHXqQhvlxqEkoz0yssNVn38bcpRWgA9PP+OGoisw==}
'@mui/core-downloads-tracker@5.16.6': '@mui/core-downloads-tracker@6.1.1':
resolution: {integrity: sha512-kytg6LheUG42V8H/o/Ptz3olSO5kUXW9zF0ox18VnblX6bO2yif1FPItgc3ey1t5ansb1+gbe7SatntqusQupg==} resolution: {integrity: sha512-VdQC1tPIIcZAnf62L2M1eQif0x2vlKg3YK4kGYbtijSH4niEgI21GnstykW1vQIs+Bc6L+Hua2GATYVjilJ22A==}
'@mui/material@5.16.6': '@mui/icons-material@6.1.1':
resolution: {integrity: sha512-0LUIKBOIjiFfzzFNxXZBRAyr9UQfmTAFzbt6ziOU2FDXhorNN2o3N9/32mNJbCA8zJo2FqFU6d3dtoqUDyIEfA==} resolution: {integrity: sha512-sy/YKwcLPW8VcacNP2uWMYR9xyWuwO9NN9FXuGEU90bRshBXj8pdKk+joe3TCW7oviVS3zXLHlc94wQ0jNsQRQ==}
engines: {node: '>=12.0.0'} 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: peerDependencies:
'@emotion/react': ^11.5.0 '@emotion/react': ^11.5.0
'@emotion/styled': ^11.3.0 '@emotion/styled': ^11.3.0
'@types/react': ^17.0.0 || ^18.0.0 '@mui/material-pigment-css': ^6.1.1
react: ^17.0.0 || ^18.0.0 '@types/react': ^17.0.0 || ^18.0.0 || ^19.0.0
react-dom: ^17.0.0 || ^18.0.0 react: ^17.0.0 || ^18.0.0 || ^19.0.0
react-dom: ^17.0.0 || ^18.0.0 || ^19.0.0
peerDependenciesMeta: peerDependenciesMeta:
'@emotion/react': '@emotion/react':
optional: true optional: true
'@emotion/styled': '@emotion/styled':
optional: true optional: true
'@mui/material-pigment-css':
optional: true
'@types/react': '@types/react':
optional: true optional: true
'@mui/private-theming@5.16.6': '@mui/private-theming@6.1.1':
resolution: {integrity: sha512-rAk+Rh8Clg7Cd7shZhyt2HGTTE5wYKNSJ5sspf28Fqm/PZ69Er9o6KX25g03/FG2dfpg5GCwZh/xOojiTfm3hw==} resolution: {integrity: sha512-JlrjIdhyZUtewtdAuUsvi3ZnO0YS49IW4Mfz19ZWTlQ0sDGga6LNPVwHClWr2/zJK2we2BQx9/i8M32rgKuzrg==}
engines: {node: '>=12.0.0'} engines: {node: '>=14.0.0'}
peerDependencies: peerDependencies:
'@types/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 react: ^17.0.0 || ^18.0.0 || ^19.0.0
peerDependenciesMeta: peerDependenciesMeta:
'@types/react': '@types/react':
optional: true optional: true
'@mui/styled-engine@5.16.6': '@mui/styled-engine@6.1.1':
resolution: {integrity: sha512-zaThmS67ZmtHSWToTiHslbI8jwrmITcN93LQaR2lKArbvS7Z3iLkwRoiikNWutx9MBs8Q6okKvbZq1RQYB3v7g==} resolution: {integrity: sha512-HJyIoMpFb11fnHuRtUILOXgq6vj4LhIlE8maG4SwP/W+E5sa7HFexhnB3vOMT7bKys4UKNxhobC8jwWxYilGsA==}
engines: {node: '>=12.0.0'} engines: {node: '>=14.0.0'}
peerDependencies: peerDependencies:
'@emotion/react': ^11.4.1 '@emotion/react': ^11.4.1
'@emotion/styled': ^11.3.0 '@emotion/styled': ^11.3.0
react: ^17.0.0 || ^18.0.0 react: ^17.0.0 || ^18.0.0 || ^19.0.0
peerDependenciesMeta: peerDependenciesMeta:
'@emotion/react': '@emotion/react':
optional: true optional: true
'@emotion/styled': '@emotion/styled':
optional: true optional: true
'@mui/system@5.16.6': '@mui/system@6.1.1':
resolution: {integrity: sha512-5xgyJjBIMPw8HIaZpfbGAaFYPwImQn7Nyh+wwKWhvkoIeDosQ1ZMVrbTclefi7G8hNmqhip04duYwYpbBFnBgw==} resolution: {integrity: sha512-PaYsCz2tUOcpu3T0okDEsSuP/yCDIj9JZ4Tox1JovRSKIjltHpXPsXZSGr3RiWdtM1MTQMFMCZzu0+CKbyy+Kw==}
engines: {node: '>=12.0.0'} engines: {node: '>=14.0.0'}
peerDependencies: peerDependencies:
'@emotion/react': ^11.5.0 '@emotion/react': ^11.5.0
'@emotion/styled': ^11.3.0 '@emotion/styled': ^11.3.0
'@types/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 react: ^17.0.0 || ^18.0.0 || ^19.0.0
peerDependenciesMeta: peerDependenciesMeta:
'@emotion/react': '@emotion/react':
optional: true optional: true
@@ -467,10 +468,10 @@ packages:
'@types/react': '@types/react':
optional: true optional: true
'@mui/types@7.2.15': '@mui/types@7.2.17':
resolution: {integrity: sha512-nbo7yPhtKJkdf9kcVOF8JZHPZTmqXjJ/tI0bdWgHg5tp9AnIN4Y7f7wm9T+0SyGYJk76+GYZ8Q5XaTYAsUHN0Q==} resolution: {integrity: sha512-oyumoJgB6jDV8JFzRqjBo2daUuHpzDjoO/e3IrRhhHo/FxJlaVhET6mcNrKHUq2E+R+q3ql0qAtvQ4rfWHhAeQ==}
peerDependencies: peerDependencies:
'@types/react': ^17.0.0 || ^18.0.0 '@types/react': ^17.0.0 || ^18.0.0 || ^19.0.0
peerDependenciesMeta: peerDependenciesMeta:
'@types/react': '@types/react':
optional: true optional: true
@@ -485,14 +486,25 @@ packages:
'@types/react': '@types/react':
optional: true optional: true
'@mui/x-date-pickers@7.12.0': '@mui/utils@6.1.1':
resolution: {integrity: sha512-WU5C7QNfSpJ9cP8vl2sY7q35NW+0TUMgEy+sl98fcPhLckq3cgV1wnVxoZnQZ3BxVQAtx+7ag/MpefU03vJcVw==} 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'} engines: {node: '>=14.0.0'}
peerDependencies: peerDependencies:
'@emotion/react': ^11.9.0 '@emotion/react': ^11.9.0
'@emotion/styled': ^11.8.1 '@emotion/styled': ^11.8.1
'@mui/material': ^5.15.14 '@mui/material': ^5.15.14 || ^6.0.0
date-fns: ^2.25.0 || ^3.2.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 date-fns-jalali: ^2.13.0-0 || ^3.2.0-0
dayjs: ^1.10.7 dayjs: ^1.10.7
luxon: ^3.0.2 luxon: ^3.0.2
@@ -521,6 +533,12 @@ packages:
moment-jalaali: moment-jalaali:
optional: true 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': '@popperjs/core@2.11.8':
resolution: {integrity: sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==} resolution: {integrity: sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==}
@@ -573,8 +591,8 @@ packages:
'@types/prop-types@15.7.12': '@types/prop-types@15.7.12':
resolution: {integrity: sha512-5zvhXYtRNRluoE/jAp4GVsSduVUzNWKkOZrCDBWYtE7biZywwdC2AcEzg+cSMLFRfVgeAFqpfNabiPjxFddV1Q==} resolution: {integrity: sha512-5zvhXYtRNRluoE/jAp4GVsSduVUzNWKkOZrCDBWYtE7biZywwdC2AcEzg+cSMLFRfVgeAFqpfNabiPjxFddV1Q==}
'@types/react-transition-group@4.4.10': '@types/react-transition-group@4.4.11':
resolution: {integrity: sha512-hT/+s0VQs2ojCX823m60m5f0sL5idt9SO6Tj6Dg+rdphGPIeJbJ6CxvBYkgkGKrYeDjvIpKTR38UzmtHJOGW3Q==} resolution: {integrity: sha512-RM05tAniPZ5DZPzzNFP+DmrcOdD0efDUxMy3145oljWSl3x9ZV5vhme98gTxFrj2lhXvmGNnUiuDyJgY9IKkNA==}
'@types/react@18.3.3': '@types/react@18.3.3':
resolution: {integrity: sha512-hti/R0pS0q1/xx+TsI73XIqk26eBsISZ2R0wUijXIngRK9R/e7Xw/cXVxQK7R5JjW+SV4zGcn5hXjudkN/pLIw==} resolution: {integrity: sha512-hti/R0pS0q1/xx+TsI73XIqk26eBsISZ2R0wUijXIngRK9R/e7Xw/cXVxQK7R5JjW+SV4zGcn5hXjudkN/pLIw==}
@@ -1107,6 +1125,10 @@ snapshots:
dependencies: dependencies:
regenerator-runtime: 0.14.1 regenerator-runtime: 0.14.1
'@babel/runtime@7.25.6':
dependencies:
regenerator-runtime: 0.14.1
'@babel/template@7.22.15': '@babel/template@7.22.15':
dependencies: dependencies:
'@babel/code-frame': 7.23.5 '@babel/code-frame': 7.23.5
@@ -1134,18 +1156,10 @@ snapshots:
'@babel/helper-validator-identifier': 7.22.20 '@babel/helper-validator-identifier': 7.22.20
to-fast-properties: 2.0.0 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': '@emotion/babel-plugin@11.12.0':
dependencies: dependencies:
'@babel/helper-module-imports': 7.22.15 '@babel/helper-module-imports': 7.22.15
'@babel/runtime': 7.25.0 '@babel/runtime': 7.25.6
'@emotion/hash': 0.9.2 '@emotion/hash': 0.9.2
'@emotion/memoize': 0.9.0 '@emotion/memoize': 0.9.0
'@emotion/serialize': 1.3.0 '@emotion/serialize': 1.3.0
@@ -1155,6 +1169,7 @@ snapshots:
find-root: 1.1.0 find-root: 1.1.0
source-map: 0.5.7 source-map: 0.5.7
stylis: 4.2.0 stylis: 4.2.0
optional: true
'@emotion/cache@11.13.1': '@emotion/cache@11.13.1':
dependencies: dependencies:
@@ -1164,17 +1179,19 @@ snapshots:
'@emotion/weak-memoize': 0.4.0 '@emotion/weak-memoize': 0.4.0
stylis: 4.2.0 stylis: 4.2.0
'@emotion/hash@0.9.2': {} '@emotion/hash@0.9.2':
optional: true
'@emotion/is-prop-valid@1.3.0': '@emotion/is-prop-valid@1.3.0':
dependencies: dependencies:
'@emotion/memoize': 0.9.0 '@emotion/memoize': 0.9.0
optional: true
'@emotion/memoize@0.9.0': {} '@emotion/memoize@0.9.0': {}
'@emotion/react@11.13.0(@types/react@18.3.3)(react@18.3.1)': '@emotion/react@11.13.0(@types/react@18.3.3)(react@18.3.1)':
dependencies: dependencies:
'@babel/runtime': 7.25.0 '@babel/runtime': 7.25.6
'@emotion/babel-plugin': 11.12.0 '@emotion/babel-plugin': 11.12.0
'@emotion/cache': 11.13.1 '@emotion/cache': 11.13.1
'@emotion/serialize': 1.3.0 '@emotion/serialize': 1.3.0
@@ -1185,6 +1202,7 @@ snapshots:
react: 18.3.1 react: 18.3.1
optionalDependencies: optionalDependencies:
'@types/react': 18.3.3 '@types/react': 18.3.3
optional: true
'@emotion/serialize@1.3.0': '@emotion/serialize@1.3.0':
dependencies: dependencies:
@@ -1193,12 +1211,13 @@ snapshots:
'@emotion/unitless': 0.9.0 '@emotion/unitless': 0.9.0
'@emotion/utils': 1.4.0 '@emotion/utils': 1.4.0
csstype: 3.1.3 csstype: 3.1.3
optional: true
'@emotion/sheet@1.4.0': {} '@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)': '@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: dependencies:
'@babel/runtime': 7.25.0 '@babel/runtime': 7.25.6
'@emotion/babel-plugin': 11.12.0 '@emotion/babel-plugin': 11.12.0
'@emotion/is-prop-valid': 1.3.0 '@emotion/is-prop-valid': 1.3.0
'@emotion/react': 11.13.0(@types/react@18.3.3)(react@18.3.1) '@emotion/react': 11.13.0(@types/react@18.3.3)(react@18.3.1)
@@ -1208,12 +1227,15 @@ snapshots:
react: 18.3.1 react: 18.3.1
optionalDependencies: optionalDependencies:
'@types/react': 18.3.3 '@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)': '@emotion/use-insertion-effect-with-fallbacks@1.1.0(react@18.3.1)':
dependencies: dependencies:
react: 18.3.1 react: 18.3.1
optional: true
'@emotion/utils@1.4.0': {} '@emotion/utils@1.4.0': {}
@@ -1304,17 +1326,25 @@ snapshots:
'@kurkle/color@0.3.2': {} '@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: dependencies:
'@babel/runtime': 7.25.0 '@babel/runtime': 7.25.6
'@mui/core-downloads-tracker': 5.16.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': 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) react: 18.3.1
'@mui/types': 7.2.15(@types/react@18.3.3) optionalDependencies:
'@mui/utils': 5.16.6(@types/react@18.3.3)(react@18.3.1) '@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 '@popperjs/core': 2.11.8
'@types/react-transition-group': 4.4.10 '@types/react-transition-group': 4.4.11
clsx: 2.1.1 clsx: 2.1.1
csstype: 3.1.3 csstype: 3.1.3
prop-types: 15.8.1 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) '@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 '@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: dependencies:
'@babel/runtime': 7.25.0 '@babel/runtime': 7.25.6
'@mui/utils': 5.16.6(@types/react@18.3.3)(react@18.3.1) '@mui/utils': 6.1.1(@types/react@18.3.3)(react@18.3.1)
prop-types: 15.8.1 prop-types: 15.8.1
react: 18.3.1 react: 18.3.1
optionalDependencies: optionalDependencies:
'@types/react': 18.3.3 '@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: dependencies:
'@babel/runtime': 7.25.0 '@babel/runtime': 7.25.6
'@emotion/cache': 11.13.1 '@emotion/cache': 11.13.1
'@emotion/sheet': 1.4.0
csstype: 3.1.3 csstype: 3.1.3
prop-types: 15.8.1 prop-types: 15.8.1
react: 18.3.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/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) '@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: dependencies:
'@babel/runtime': 7.25.0 '@babel/runtime': 7.25.6
'@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)
'@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)
'@mui/types': 7.2.15(@types/react@18.3.3) '@mui/types': 7.2.17(@types/react@18.3.3)
'@mui/utils': 5.16.6(@types/react@18.3.3)(react@18.3.1) '@mui/utils': 6.1.1(@types/react@18.3.3)(react@18.3.1)
clsx: 2.1.1 clsx: 2.1.1
csstype: 3.1.3 csstype: 3.1.3
prop-types: 15.8.1 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) '@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 '@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: optionalDependencies:
'@types/react': 18.3.3 '@types/react': 18.3.3
'@mui/utils@5.16.6(@types/react@18.3.3)(react@18.3.1)': '@mui/utils@5.16.6(@types/react@18.3.3)(react@18.3.1)':
dependencies: dependencies:
'@babel/runtime': 7.25.0 '@babel/runtime': 7.25.6
'@mui/types': 7.2.15(@types/react@18.3.3) '@mui/types': 7.2.17(@types/react@18.3.3)
'@types/prop-types': 15.7.12 '@types/prop-types': 15.7.12
clsx: 2.1.1 clsx: 2.1.1
prop-types: 15.8.1 prop-types: 15.8.1
@@ -1379,13 +1410,26 @@ snapshots:
optionalDependencies: optionalDependencies:
'@types/react': 18.3.3 '@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: dependencies:
'@babel/runtime': 7.25.0 '@babel/runtime': 7.25.6
'@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/types': 7.2.17(@types/react@18.3.3)
'@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) '@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) '@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 clsx: 2.1.1
prop-types: 15.8.1 prop-types: 15.8.1
react: 18.3.1 react: 18.3.1
@@ -1398,6 +1442,14 @@ snapshots:
transitivePeerDependencies: transitivePeerDependencies:
- '@types/react' - '@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': {} '@popperjs/core@2.11.8': {}
'@preact/preset-vite@2.8.1(@babel/core@7.23.7)(preact@10.19.3)(vite@4.5.1)': '@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': {} '@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/prop-types@15.7.12': {}
'@types/react-transition-group@4.4.10': '@types/react-transition-group@4.4.11':
dependencies: dependencies:
'@types/react': 18.3.3 '@types/react': 18.3.3
@@ -1475,9 +1528,10 @@ snapshots:
babel-plugin-macros@3.1.0: babel-plugin-macros@3.1.0:
dependencies: dependencies:
'@babel/runtime': 7.25.0 '@babel/runtime': 7.25.6
cosmiconfig: 7.1.0 cosmiconfig: 7.1.0
resolve: 1.22.8 resolve: 1.22.8
optional: true
babel-plugin-transform-hook-names@1.0.2(@babel/core@7.23.7): babel-plugin-transform-hook-names@1.0.2(@babel/core@7.23.7):
dependencies: dependencies:
@@ -1492,7 +1546,8 @@ snapshots:
node-releases: 2.0.14 node-releases: 2.0.14
update-browserslist-db: 1.0.13(browserslist@4.22.2) 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: {} caniuse-lite@1.0.30001575: {}
@@ -1514,7 +1569,8 @@ snapshots:
color-name@1.1.3: {} 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: {} convert-source-map@2.0.0: {}
@@ -1525,6 +1581,7 @@ snapshots:
parse-json: 5.2.0 parse-json: 5.2.0
path-type: 4.0.0 path-type: 4.0.0
yaml: 1.10.2 yaml: 1.10.2
optional: true
css-select@5.1.0: css-select@5.1.0:
dependencies: dependencies:
@@ -1576,6 +1633,7 @@ snapshots:
error-ex@1.3.2: error-ex@1.3.2:
dependencies: dependencies:
is-arrayish: 0.2.1 is-arrayish: 0.2.1
optional: true
esbuild@0.18.20: esbuild@0.18.20:
optionalDependencies: optionalDependencies:
@@ -1606,11 +1664,13 @@ snapshots:
escape-string-regexp@1.0.5: {} 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: {} estree-walker@2.0.2: {}
find-root@1.1.0: {} find-root@1.1.0:
optional: true
fsevents@2.3.3: fsevents@2.3.3:
optional: true optional: true
@@ -1632,13 +1692,16 @@ snapshots:
hoist-non-react-statics@3.3.2: hoist-non-react-statics@3.3.2:
dependencies: dependencies:
react-is: 16.13.1 react-is: 16.13.1
optional: true
import-fresh@3.3.0: import-fresh@3.3.0:
dependencies: dependencies:
parent-module: 1.0.1 parent-module: 1.0.1
resolve-from: 4.0.0 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: is-core-module@2.13.1:
dependencies: dependencies:
@@ -1648,13 +1711,15 @@ snapshots:
jsesc@2.5.2: {} 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: {} json5@2.2.3: {}
kolorist@1.8.0: {} kolorist@1.8.0: {}
lines-and-columns@1.2.4: {} lines-and-columns@1.2.4:
optional: true
loose-envify@1.4.0: loose-envify@1.4.0:
dependencies: dependencies:
@@ -1688,6 +1753,7 @@ snapshots:
parent-module@1.0.1: parent-module@1.0.1:
dependencies: dependencies:
callsites: 3.1.0 callsites: 3.1.0
optional: true
parse-json@5.2.0: parse-json@5.2.0:
dependencies: dependencies:
@@ -1695,10 +1761,12 @@ snapshots:
error-ex: 1.3.2 error-ex: 1.3.2
json-parse-even-better-errors: 2.3.1 json-parse-even-better-errors: 2.3.1
lines-and-columns: 1.2.4 lines-and-columns: 1.2.4
optional: true
path-parse@1.0.7: {} path-parse@1.0.7: {}
path-type@4.0.0: {} path-type@4.0.0:
optional: true
picocolors@1.0.0: {} picocolors@1.0.0: {}
@@ -1761,7 +1829,8 @@ snapshots:
regenerator-runtime@0.14.1: {} regenerator-runtime@0.14.1: {}
resolve-from@4.0.0: {} resolve-from@4.0.0:
optional: true
resolve@1.22.8: resolve@1.22.8:
dependencies: dependencies:
@@ -1781,7 +1850,8 @@ snapshots:
source-map-js@1.2.0: {} source-map-js@1.2.0: {}
source-map@0.5.7: {} source-map@0.5.7:
optional: true
stylis@4.2.0: {} stylis@4.2.0: {}
@@ -1811,4 +1881,5 @@ snapshots:
yallist@3.1.1: {} yallist@3.1.1: {}
yaml@1.10.2: {} yaml@1.10.2:
optional: true
+207 -371
View File
@@ -1,4 +1,3 @@
import { signal, computed } from "@preact/signals";
import { useEffect } from "preact/hooks"; import { useEffect } from "preact/hooks";
import { trpc } from "../trpc.js"; import { trpc } from "../trpc.js";
import { import {
@@ -6,195 +5,65 @@ import {
LinearScale, LinearScale,
CategoryScale, CategoryScale,
PointElement, PointElement,
LineElement,
Tooltip, Tooltip,
Title, Title,
} from "chart.js"; } from "chart.js";
import { Scatter } from "react-chartjs-2"; import { Scatter } from "react-chartjs-2";
import { import {
Container, Container,
Grid, Grid2,
Typography, Typography,
TextField,
Select,
MenuItem,
InputLabel,
FormControl,
Paper, Paper,
Popper,
ClickAwayListener,
Stack,
} from "@mui/material"; } 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 { EditableOpenDTE } from "./HistoricalCalendarPrices/EditableOpenDTE.js";
import { EditableExitDTE } from "./HistoricalCalendarPrices/EditableExitDTE.js";
import { EditableSpan } from "./HistoricalCalendarPrices/EditableSpan.js";
import { EditableLookbackPeriod } from "./HistoricalCalendarPrices/EditableLookbackPeriod.js";
ChartJS.register(LinearScale, CategoryScale, PointElement, Tooltip, Title); ChartJS.register(
LinearScale,
const availableUnderlyings = signal([]); CategoryScale,
const chosenUnderlying = signal(null); PointElement,
LineElement,
const chosenDaysToFrontExpiration = signal(14); Tooltip,
Title
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 = () => { const handleInit = () => {
trpc.getAvailableUnderlyings.query().then((availableUnderlyingsResponse) => { trpc.CalendarCharacteristicsForm.getAvailableUnderlyings
availableUnderlyings.value = availableUnderlyingsResponse; .query()
chosenUnderlying.value = availableUnderlyingsResponse[0]; .then((availableUnderlyingsResponse) => {
refreshHistoricalStockQuoteChartData(); availableUnderlyings.value = availableUnderlyingsResponse;
refreshHistoricalCalendarQuoteChartData(); underlying.value = availableUnderlyingsResponse[0];
refreshHistoricalCalendarExitQuoteChartData(); 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() { export function HistoricalCalendarPrices() {
@@ -202,193 +71,94 @@ export function HistoricalCalendarPrices() {
return ( return (
<Container maxWidth="lg"> <Container maxWidth="lg">
<Grid container spacing={4}> <Grid2 container spacing={4} columns={12}>
<Grid item xs={12}> {/* <Grid2 size={{ xs: 12 }}>
<Typography variant="h4" gutterBottom> <Typography variant="h4" gutterBottom>
Historical Calendar Prices <EditableUnderlying /> :
<EditableSpan />
-Day Calendar @ <EditableStrike />
%-from-the-money
</Typography> </Typography>
</Grid> <Typography variant="h5" gutterBottom sx={{ pl: 1 }}>
<Grid item xs={12} md={6}> Opening at <EditableOpenDTE /> DTE, Closing at <EditableExitDTE />
<Paper elevation={3} sx={{ p: 3 }}> DTE
<Grid container spacing={2}> </Typography>
<Grid item xs={12}> <Typography variant="h5" gutterBottom>
<FormControl fullWidth> <EditableLookbackPeriodStart />-
<InputLabel>Available Underlyings</InputLabel> <EditableLookbackPeriodEnd />
<Select </Typography>
value={chosenUnderlying.value || ""} <ClickAwayListener
onChange={handleUnderlyingChange} onClickAway={() => {
label="Available Underlyings" isPopperOpen.value = false;
> // refreshSimilarCalendarPriceChartData();
{availableUnderlyings.value.map((underlying) => ( console.log("clicked away");
<MenuItem key={underlying} value={underlying}> }}
{underlying} >
</MenuItem> <Popper open={isPopperOpen.value} anchorEl={popperAnchorEl.value}>
))} <Paper elevation={3} sx={{ p: 3 }}>
</Select> {popperContent.value}
</FormControl> </Paper>
</Grid> </Popper>
<Grid item xs={12}> </ClickAwayListener>
<TextField </Grid2> */}
fullWidth
label="Now-to-Front-Month Days to Expiration" <Grid2 size={{ xs: 12 }}>
type="number" <Stack direction="row" spacing={2}>
value={chosenDaysToFrontExpiration.value} <Typography gutterBottom minWidth={"8em"}>
onChange={handleDaysToFrontExpirationChange} Underlying
InputProps={{ endAdornment: "Days" }} </Typography>
/> <EditableUnderlying />
</Grid> </Stack>
<Grid item xs={12}> <Stack direction="row" spacing={2}>
<TextField <Typography gutterBottom minWidth={"8em"}>
fullWidth Open DTE
label="Front-to-Back-Month Days to Expiration Difference" </Typography>
type="number" <EditableOpenDTE />
value={chosenDaysBetweenFrontAndBackExpiration.value} </Stack>
onChange={handleDaysBetweenFrontAndBackExpirationChange} <Stack direction="row" spacing={2}>
InputProps={{ endAdornment: "Days Difference" }} <Typography gutterBottom minWidth={"8em"}>
/> Exit DTE
</Grid> </Typography>
<Grid item xs={6}> <EditableExitDTE />
<TextField </Stack>
fullWidth <Stack direction="row" spacing={2}>
label="Strike % From Underlying Price" <Typography gutterBottom minWidth={"8em"}>
type="number" Span
value={chosenStrikePercentageFromUnderlyingPrice.value} </Typography>
onChange={handleStrikePercentageFromUnderlyingPriceChange} <EditableSpan />
InputProps={{ endAdornment: "%" }} </Stack>
/> <Stack direction="row" spacing={2}>
</Grid> <Typography gutterBottom minWidth={"8em"}>
<Grid item xs={6}> Lookback Period
<TextField </Typography>
fullWidth <EditableLookbackPeriod />
label="Strike % Radius" </Stack>
type="number" <ClickAwayListener
value={chosenStrikePercentageFromUnderlyingPriceRadius.value} onClickAway={() => {
onChange={ isPopperOpen.value = false;
handleStrikePercentageFromUnderlyingPriceRadiusChange // refreshSimilarCalendarPriceChartData();
} console.log("clicked away");
InputProps={{ endAdornment: "%" }} }}
/> >
</Grid> <Popper open={isPopperOpen.value} anchorEl={popperAnchorEl.value}>
<Grid item xs={12}> <Paper elevation={3} sx={{ p: 3 }}>
<TextField {popperContent.value}
fullWidth </Paper>
label="Exit-to-Front-Month Days to Expiration" </Popper>
type="number" </ClickAwayListener>
value={chosenExitToFrontExpiration.value} </Grid2>
onChange={handleExitToFrontExpirationChange}
InputProps={{ endAdornment: "Days" }} <Grid2 size={{ xs: 12, md: 6 }}>
/> <Paper elevation={3} sx={{ p: 3, minHeight: "28em" }}>
</Grid> {underlying.value !== null &&
<Grid item xs={6}> similarCalendarPriceChartData.value.length > 0 ? (
<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>
</Paper>
</Grid>
<Grid item xs={12} md={6}>
<Paper elevation={3} sx={{ p: 3, height: "100%" }}>
{chosenUnderlying.value !== null &&
historicalStockQuoteChartData.value.length > 0 ? (
<Scatter
data={{
datasets: [
{
label: "Stock Open Price",
data: historicalStockQuoteChartData.value,
},
],
}}
options={{
scales: {
x: {
title: {
display: true,
text: "Time",
},
ticks: {
callback: (value, index, ticks) =>
new Date((value as number) * 1000)
.toISOString()
.substring(0, 10),
},
min:
new Date(chosenLookbackPeriodStart.value).getTime() /
1000,
max:
new Date(chosenLookbackPeriodEnd.value).getTime() /
1000,
},
y: {
beginAtZero: false,
ticks: {
callback: (value, index, ticks) =>
`$${value.toString()}`,
},
},
},
elements: {
point: {
radius: 1,
borderWidth: 0,
},
},
plugins: {
tooltip: {
enabled: false,
},
legend: {
display: false,
},
title: {
display: true,
text: "Stock Price",
},
},
animation: false,
maintainAspectRatio: false,
events: [],
}}
/>
) : (
<Typography>Loading Chart...</Typography>
)}
</Paper>
</Grid>
<Grid item xs={12}>
<Paper elevation={3} sx={{ p: 3 }}>
{chosenUnderlying.value !== null &&
historicalCalendarQuoteChartData.value.length > 0 ? (
<Scatter <Scatter
data={{ data={{
datasets: [ datasets: [
{ {
label: "Calendar Open Price", label: "Calendar Open Price",
data: historicalCalendarQuoteChartData.value, data: similarCalendarPriceChartData.value,
}, },
], ],
}} }}
@@ -405,12 +175,8 @@ export function HistoricalCalendarPrices() {
.toISOString() .toISOString()
.substring(0, 10), .substring(0, 10),
}, },
min: min: new Date(lookbackPeriodStart.value).getTime() / 1000,
new Date(chosenLookbackPeriodStart.value).getTime() / max: new Date(lookbackPeriodEnd.value).getTime() / 1000,
1000,
max:
new Date(chosenLookbackPeriodEnd.value).getTime() /
1000,
}, },
y: { y: {
beginAtZero: true, beginAtZero: true,
@@ -443,17 +209,17 @@ export function HistoricalCalendarPrices() {
<Typography>Loading Chart...</Typography> <Typography>Loading Chart...</Typography>
)} )}
</Paper> </Paper>
</Grid> </Grid2>
<Grid item xs={12}> <Grid2 size={{ xs: 12, md: 6 }}>
<Paper elevation={3} sx={{ p: 3 }}> <Paper elevation={3} sx={{ p: 3, minHeight: "28em" }}>
{chosenUnderlying.value !== null && {underlying.value !== null &&
historicalCalendarQuoteChartData.value.length > 0 ? ( calendarExitPriceChartData.value.length > 0 ? (
<Scatter <Scatter
data={{ data={{
datasets: [ datasets: [
{ {
label: "Calendar Exit Price", label: "Calendar Exit Price",
data: historicalCalendarExitQuoteChartData.value, data: calendarExitPriceChartData.value,
}, },
], ],
}} }}
@@ -517,8 +283,78 @@ export function HistoricalCalendarPrices() {
<Typography>Loading Chart...</Typography> <Typography>Loading Chart...</Typography>
)} )}
</Paper> </Paper>
</Grid> </Grid2>
</Grid> <Grid2 size={{ 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: stockPriceChartData.value,
},
],
}}
options={{
showLine: true,
normalized: true,
scales: {
x: {
title: {
display: true,
text: "Time",
},
ticks: {
callback: (value, index, ticks) =>
new Date((value as number) * 1000)
.toISOString()
.substring(0, 10),
},
min: new Date(lookbackPeriodStart.value).getTime() / 1000,
max: new Date(lookbackPeriodEnd.value).getTime() / 1000,
},
y: {
beginAtZero: false,
ticks: {
callback: (value, index, ticks) =>
`$${value.toString()}`,
},
},
},
elements: {
point: {
radius: 2,
borderWidth: 0,
},
line: {
borderWidth: 2,
},
},
plugins: {
tooltip: {
enabled: false,
},
legend: {
display: false,
},
title: {
display: true,
text: "Stock Price",
},
},
animation: false,
maintainAspectRatio: false,
events: [],
}}
/>
) : (
<Typography>Loading Chart...</Typography>
)}
</Paper>
</Grid2>
</Grid2>
</Container> </Container>
); );
} }
@@ -0,0 +1,28 @@
import TextField from "@mui/material/TextField";
import { EditableValue } from "./EditableValue";
import { exitDTE } from "./state";
import { refreshcalendarExitPriceChartData } from "./actions";
import Slider from "@mui/material/Slider";
const handleExitDTEChange = (e) => {
if (exitDTE.value !== Number.parseInt(e.target.value)) {
exitDTE.value = Number.parseInt(e.target.value);
refreshcalendarExitPriceChartData();
}
};
export function EditableExitDTE() {
return (
<Slider
value={exitDTE.value}
onChange={handleExitDTEChange}
min={0}
max={5}
step={1}
valueLabelDisplay="on"
/>
// <EditableValue text={exitDTE.value}>
// <ExitToFrontExpirationChooser />
// </EditableValue>
);
}
@@ -0,0 +1,66 @@
import TextField from "@mui/material/TextField";
import {
refreshcalendarExitPriceChartData,
refreshSimilarCalendarPriceChartData,
refreshStockPriceChartData,
} from "./actions";
import { lookbackPeriodEnd, lookbackPeriodStart } from "./state";
import Slider from "@mui/material/Slider";
const handleLookbackPeriodChange = (
e,
[newLookbackPeriodStart, newLookbackPeriodEnd]: [number, number]
) => {
const [lookbackPeriodStartUnixTime, lookbackPeriodEndUnixTime] = [
new Date(lookbackPeriodStart.value).getTime(),
new Date(lookbackPeriodEnd.value).getTime(),
];
if (lookbackPeriodStartUnixTime !== newLookbackPeriodStart) {
lookbackPeriodStart.value = new Date(newLookbackPeriodStart)
.toISOString()
.substring(0, 10);
refreshStockPriceChartData();
refreshSimilarCalendarPriceChartData();
refreshcalendarExitPriceChartData();
}
if (lookbackPeriodEndUnixTime !== newLookbackPeriodEnd) {
lookbackPeriodEnd.value = new Date(newLookbackPeriodEnd)
.toISOString()
.substring(0, 10);
refreshStockPriceChartData();
refreshSimilarCalendarPriceChartData();
refreshcalendarExitPriceChartData();
}
};
const earliestDate = new Date("2022-03-07");
const DAY = 1000 * 60 * 60 * 24;
function addDays(date, days) {
const result = new Date(date);
result.setDate(result.getDate() + days);
return result.toISOString().substring(0, 10);
}
function daysBetween(date1, date2) {
return Math.round(Math.abs((date2.getTime() - date1.getTime()) / DAY));
}
export function EditableLookbackPeriod() {
return (
<Slider
value={[
new Date(lookbackPeriodStart.value).getTime(),
new Date(lookbackPeriodEnd.value).getTime(),
]}
onChange={handleLookbackPeriodChange}
valueLabelFormat={(unixTimeMs) =>
new Date(unixTimeMs).toISOString().substring(0, 10)
}
getAriaValueText={(unixTimeMs) =>
new Date(unixTimeMs).toISOString().substring(0, 10)
}
min={earliestDate.getTime()}
max={earliestDate.getTime() + 250 * DAY}
step={DAY}
valueLabelDisplay="on"
/>
);
}
@@ -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,26 @@
import { refreshSimilarCalendarPriceChartData } from "./actions";
import { openDTE } from "./state";
import Slider from "@mui/material/Slider";
const handleOpenDTEChange = (e) => {
if (openDTE.value !== Number.parseInt(e.target.value)) {
openDTE.value = Number.parseInt(e.target.value);
refreshSimilarCalendarPriceChartData();
}
};
export function EditableOpenDTE() {
return (
<Slider
value={openDTE.value}
onChange={handleOpenDTEChange}
min={0}
max={5}
step={1}
valueLabelDisplay="on"
/>
// <EditableValue text={openDTE.value}>
// <DaysToFrontExpirationChooser />
// </EditableValue>
);
}
@@ -0,0 +1,45 @@
import TextField from "@mui/material/TextField";
import {
refreshcalendarExitPriceChartData,
refreshSimilarCalendarPriceChartData,
} from "./actions";
import { span } from "./state";
import { EditableValue } from "./EditableValue";
import Slider from "@mui/material/Slider";
const handleSpanChange = (e) => {
if (span.value !== Number.parseInt(e.target.value)) {
span.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={span.value}
onChange={handleSpanChange}
InputProps={{ endAdornment: "Days Difference" }}
/>
);
}
export function EditableSpan() {
return (
<Slider
value={span.value}
onChange={handleSpanChange}
min={3}
max={45}
step={1}
valueLabelDisplay="on"
/>
// <EditableValue text={span.value}>
// <DaysBetweenFrontAndBackExpirationChooser />
// </EditableValue>
);
}
@@ -0,0 +1,65 @@
import Box from "@mui/material/Box";
import { EditableValue } from "./EditableValue";
import { moniness, moninessRadius } from "./state";
import Slider from "@mui/material/Slider";
import { refreshSimilarCalendarPriceChartData } from "./actions";
function MoninessChooser() {
return (
<Slider
fullWidth
label="Strike % From Underlying Price"
value={moniness.value}
valueLabelDisplay="on"
min={0}
max={10}
step={1}
onChange={(e, value) => {
moniness.value = value as number;
}}
onChangeCommitted={(e, value) => {
refreshSimilarCalendarPriceChartData();
}}
InputProps={{ endAdornment: "%" }}
/>
);
}
function MoninessRadiusChooser() {
return (
<Slider
fullWidth
label="Strike % Radius"
value={moninessRadius.value}
valueLabelDisplay="on"
min={0}
max={10}
step={1}
onChange={(e, value) => {
moninessRadius.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={`${moniness.value.toFixed(1)}±${moninessRadius.value.toFixed(2)}`}
>
<Box sx={{ minWidth: "20em" }}>
<MoninessChooser />
<MoninessRadiusChooser />
</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,81 @@
import { trpc } from "../../trpc";
import {
calendarExitPriceChartData,
span,
openDTE,
exitDTE,
lookbackPeriodEnd,
lookbackPeriodStart,
similarCalendarPriceChartData,
stockPriceChartData,
moniness,
moninessRadius,
underlying,
} from "./state";
function debounce(func, wait) {
let timeout;
return function () {
const context = this;
const args = arguments;
clearTimeout(timeout);
timeout = setTimeout(() => func.apply(context, args), wait);
};
}
function throttle(func, limit) {
let inThrottle;
return function () {
const context = this;
const args = arguments;
if (!inThrottle) {
func.apply(context, args);
inThrottle = true;
setTimeout(() => (inThrottle = false), limit);
}
};
}
export const refreshStockPriceChartData = throttle(() => {
stockPriceChartData.value = [];
trpc.StockPriceChart.getChartData
.query({
underlying: underlying.value,
lookbackPeriodStart: lookbackPeriodStart.value,
lookbackPeriodEnd: lookbackPeriodEnd.value,
})
.then((getChartDataResponse) => {
stockPriceChartData.value = getChartDataResponse;
});
}, 400);
export const refreshSimilarCalendarPriceChartData = throttle(() => {
similarCalendarPriceChartData.value = [];
trpc.SimilarCalendarPriceChart.getChartData
.query({
underlying: underlying.value,
daysToFrontExpiration: openDTE.value,
daysBetweenFrontAndBackExpiration: span.value,
strikePercentageFromUnderlyingPriceRangeMin:
(moniness.value - moninessRadius.value) / 100,
strikePercentageFromUnderlyingPriceRangeMax:
(moniness.value + moninessRadius.value) / 100,
lookbackPeriodStart: lookbackPeriodStart.value,
lookbackPeriodEnd: lookbackPeriodEnd.value,
})
.then((getChartDataResponse) => {
similarCalendarPriceChartData.value = getChartDataResponse;
});
}, 400);
export const refreshcalendarExitPriceChartData = throttle(() => {
calendarExitPriceChartData.value = [];
trpc.CalendarExitPriceChart.getChartData
.query({
underlying: underlying.value,
daysToFrontExpiration: exitDTE.value,
daysBetweenFrontAndBackExpiration: span.value,
lookbackPeriodStart: lookbackPeriodStart.value,
lookbackPeriodEnd: lookbackPeriodEnd.value,
})
.then((getChartDataResponse) => {
calendarExitPriceChartData.value = getChartDataResponse;
});
}, 400);
@@ -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 openDTE = signal(14);
export const span = signal(14);
export const moniness = signal(1);
export const moninessRadius = signal(1);
export const exitDTE = signal(2);
export const stockPriceChartData = signal<Array<[number, number]>>([]);
export const similarCalendarPriceChartData = signal([]);
export const calendarExitPriceChartData = signal([]);
export const lookbackPeriodStart = signal("2022-03-01");
export const lookbackPeriodEnd = signal("2022-04-01");
export const maxChartPrice = computed(() =>
Math.max(
Math.max.apply(
null,
similarCalendarPriceChartData.value.map((d) => d.y).slice(0, -2)
),
Math.max.apply(
null,
calendarExitPriceChartData.value.map((d) => d.y).slice(0, -2)
)
)
);
export const maxN = computed(() =>
Math.max.apply(
null,
calendarExitPriceChartData.value.map((d) => d.n)
)
);
+2 -1
View File
@@ -26,4 +26,5 @@ dist-ssr
.env .env
*.db *.db
*.db-lck *.db-lck
Calendar tRPC
+17 -12
View File
@@ -2,22 +2,27 @@
FROM node:20-slim AS base FROM node:20-slim AS base
ENV PNPM_HOME="/pnpm" ENV PNPM_HOME="/pnpm"
ENV PATH="$PNPM_HOME:$PATH" ENV PATH="$PNPM_HOME:$PATH"
RUN corepack enable RUN npm install -g corepack@latest && corepack enable
COPY package.json pnpm-lock.yaml /app/ COPY package.json pnpm-lock.yaml /app/
WORKDIR /app WORKDIR /app
FROM base AS prod-deps
RUN --mount=type=cache,id=pnpm,target=/pnpm/store pnpm install --prod --frozen-lockfile
# install dev dependencies which are needed for building, such as typescript:
FROM base AS build
RUN --mount=type=cache,id=pnpm,target=/pnpm/store pnpm install --frozen-lockfile RUN --mount=type=cache,id=pnpm,target=/pnpm/store pnpm install --frozen-lockfile
COPY tsconfig.json /app/ COPY tsconfig.json /app/
COPY src /app/src COPY src /app/src
RUN pnpm run build CMD [ "pnpm", "tsx", "src/index.ts" ]
FROM base # FROM base AS prod-deps
COPY --from=prod-deps /app/node_modules /app/node_modules # RUN --mount=type=cache,id=pnpm,target=/pnpm/store pnpm install --prod --frozen-lockfile
COPY --from=build /app/dist /app/dist
WORKDIR /app/dist # # install dev dependencies which are needed for building, such as typescript:
CMD [ "node", "index.js" ] # FROM base AS build
# RUN --mount=type=cache,id=pnpm,target=/pnpm/store pnpm install --frozen-lockfile
# COPY tsconfig.json /app/
# COPY src /app/src
# RUN pnpm run build
# FROM base
# COPY --from=prod-deps /app/node_modules /app/node_modules
# COPY --from=build /app/dist /app/dist
# WORKDIR /app/dist
# CMD [ "node", "index.js" ]
+2 -1
View File
@@ -9,11 +9,12 @@
"cli": "tsx src/cli.tsx" "cli": "tsx src/cli.tsx"
}, },
"dependencies": { "dependencies": {
"@clickhouse/client": "^0.2.7", "@clickhouse/client": "^1.4.1",
"@humanwhocodes/env": "^3.0.5", "@humanwhocodes/env": "^3.0.5",
"@sinclair/typebox": "^0.32.5", "@sinclair/typebox": "^0.32.5",
"@trpc/server": "^10.45.0", "@trpc/server": "^10.45.0",
"cors": "^2.8.5", "cors": "^2.8.5",
"date-fns": "^3.6.0",
"execa": "^9.3.0", "execa": "^9.3.0",
"ink": "^4.1.0", "ink": "^4.1.0",
"ink-text-input": "^5.0.1", "ink-text-input": "^5.0.1",
+17 -9
View File
@@ -9,8 +9,8 @@ importers:
.: .:
dependencies: dependencies:
'@clickhouse/client': '@clickhouse/client':
specifier: ^0.2.7 specifier: ^1.4.1
version: 0.2.7 version: 1.4.1
'@humanwhocodes/env': '@humanwhocodes/env':
specifier: ^3.0.5 specifier: ^3.0.5
version: 3.0.5 version: 3.0.5
@@ -23,6 +23,9 @@ importers:
cors: cors:
specifier: ^2.8.5 specifier: ^2.8.5
version: 2.8.5 version: 2.8.5
date-fns:
specifier: ^3.6.0
version: 3.6.0
execa: execa:
specifier: ^9.3.0 specifier: ^9.3.0
version: 9.3.0 version: 9.3.0
@@ -88,11 +91,11 @@ packages:
resolution: {integrity: sha512-3yWxPTq3UQ/FY9p1ErPxIyfT64elWaMvM9lIHnaqpyft63tkxodF5aUElYHrdisWve5cETkh1+KBw1yJuW0aRw==} resolution: {integrity: sha512-3yWxPTq3UQ/FY9p1ErPxIyfT64elWaMvM9lIHnaqpyft63tkxodF5aUElYHrdisWve5cETkh1+KBw1yJuW0aRw==}
engines: {node: '>=14.13.1'} engines: {node: '>=14.13.1'}
'@clickhouse/client-common@0.2.7': '@clickhouse/client-common@1.4.1':
resolution: {integrity: sha512-vgZm+8c5Cu1toIx1/xplF5dEHlCPw+7pJDOOEtLv2CIUVZ0Bl6nGVZ43EWxRdHeah9ivTfoRWhN1zI1PxjH0xQ==} resolution: {integrity: sha512-f5eoTrUSDplrMoi3ddeZ0MzGTn0iGMByEQ8j63eVMoBSOI2+F6jEIPcW2tWofT79Rvnn3RRlveYcShiaIiCJyw==}
'@clickhouse/client@0.2.7': '@clickhouse/client@1.4.1':
resolution: {integrity: sha512-ZiyarrGngHc+f5AjZSA7mkQfvnE/71jgXk304B0ps8V+aBpE2CsFB6AQmE/Mk2YkP5j+8r/JfG+m0AZWmE27ig==} resolution: {integrity: sha512-12iV+MeykxdQySRFHwaVU+hKUv3JP6kdwOI+z3zzyfPVYHynTlV8emJjjGZR0+VfRaj3PCMuQfryfsJ82nh9WQ==}
engines: {node: '>=16'} engines: {node: '>=16'}
'@esbuild/aix-ppc64@0.19.11': '@esbuild/aix-ppc64@0.19.11':
@@ -610,6 +613,9 @@ packages:
csstype@3.1.3: csstype@3.1.3:
resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==} resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==}
date-fns@3.6.0:
resolution: {integrity: sha512-fRHTG8g/Gif+kSh50gaGEdToemgfj74aRX3swtiouboip5JDLAyDE9F11nHMIcvOaXeOC6D7SpNhi7uFyB7Uww==}
debug@4.3.5: debug@4.3.5:
resolution: {integrity: sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==} resolution: {integrity: sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==}
engines: {node: '>=6.0'} engines: {node: '>=6.0'}
@@ -1626,11 +1632,11 @@ snapshots:
ansi-styles: 6.2.1 ansi-styles: 6.2.1
is-fullwidth-code-point: 4.0.0 is-fullwidth-code-point: 4.0.0
'@clickhouse/client-common@0.2.7': {} '@clickhouse/client-common@1.4.1': {}
'@clickhouse/client@0.2.7': '@clickhouse/client@1.4.1':
dependencies: dependencies:
'@clickhouse/client-common': 0.2.7 '@clickhouse/client-common': 1.4.1
'@esbuild/aix-ppc64@0.19.11': '@esbuild/aix-ppc64@0.19.11':
optional: true optional: true
@@ -2021,6 +2027,8 @@ snapshots:
csstype@3.1.3: {} csstype@3.1.3: {}
date-fns@3.6.0: {}
debug@4.3.5: debug@4.3.5:
dependencies: dependencies:
ms: 2.1.2 ms: 2.1.2
+3 -3
View File
@@ -1,5 +1,5 @@
import { query } from "./lib/clickhouse"; import { query } from "./lib/clickhouse.js";
import { publicProcedure, RpcType, router } from "./trpc"; import { publicProcedure, RpcType, router } from "./trpc.js";
import { import {
Object as ObjectT, Object as ObjectT,
String as StringT, String as StringT,
@@ -13,7 +13,7 @@ export const getAvailableUnderlyings = publicProcedure.query(async (opts) => {
// SELECT DISTINCT(symbol) as symbol FROM option_contract_existences WHERE asOfDate = (SELECT max(asOfDate) FROM option_contract_existences) // SELECT DISTINCT(symbol) as symbol FROM option_contract_existences WHERE asOfDate = (SELECT max(asOfDate) FROM option_contract_existences)
// `) // `)
// ).map(({ symbol }) => symbol); // ).map(({ symbol }) => symbol);
return ["AAPL", "AMD", "GOOGL", "MSFT", "NFLX"]; return ["SPY"];
}); });
export const getAvailableAsOfDates = publicProcedure export const getAvailableAsOfDates = publicProcedure
+13 -14
View File
@@ -1,5 +1,5 @@
import { query } from "./lib/clickhouse"; import { query } from "./lib/clickhouse.js";
import { publicProcedure, RpcType, router } from "./trpc"; import { publicProcedure, RpcType, router } from "./trpc.js";
import { import {
Object as ObjectT, Object as ObjectT,
String as StringT, String as StringT,
@@ -30,18 +30,17 @@ export const getChartData = publicProcedure
} = opts.input; } = opts.input;
return await query<[number, number, number]>( return await query<[number, number, number]>(
` `
SELECT SELECT
FLOOR(strikePercentageFromUnderlyingPrice, 1) as x, moniness*100 as x,
FLOOR(calendarPrice, 1) as y, FLOOR(price, 1) as y,
count(*) as n sum(number_of_quotes) as n
FROM calendar_histories FROM calendar_stats
WHERE symbol = '${underlying}' WHERE dte = ${daysToFrontExpiration}
AND daysToFrontExpiration = ${daysToFrontExpiration} AND moniness >= -0.05
AND strikePercentageFromUnderlyingPrice >= -5.0 AND moniness <= 0.05
AND strikePercentageFromUnderlyingPrice <= 5.0 AND span = ${daysBetweenFrontAndBackExpiration}
AND daysBetweenFrontAndBackExpiration = ${daysBetweenFrontAndBackExpiration} AND date >= '${lookbackPeriodStart}'
AND tsStart >= '${lookbackPeriodStart} 00:00:00' AND date <= '${lookbackPeriodEnd}'
AND tsStart <= '${lookbackPeriodEnd} 00:00:00'
GROUP BY x, y GROUP BY x, y
ORDER BY x ASC, y ASC ORDER BY x ASC, y ASC
`, `,
+12 -13
View File
@@ -1,5 +1,5 @@
import { query } from "./lib/clickhouse"; import { query } from "./lib/clickhouse.js";
import { publicProcedure, RpcType, router } from "./trpc"; import { publicProcedure, RpcType, router } from "./trpc.js";
import { import {
Object as ObjectT, Object as ObjectT,
String as StringT, String as StringT,
@@ -34,17 +34,16 @@ export const getChartData = publicProcedure
} = opts.input; } = opts.input;
return await query<[number, number]>( return await query<[number, number]>(
` `
SELECT SELECT
toUnixTimestamp(tsStart) as x, toUnixTimestamp(date) as x,
truncate(calendarPrice, 2) as y price as y
FROM calendar_histories FROM calendar_stats
WHERE symbol = '${underlying}' WHERE dte = ${daysToFrontExpiration}
AND daysToFrontExpiration = ${daysToFrontExpiration} AND moniness >= ${strikePercentageFromUnderlyingPriceRangeMin}
AND strikePercentageFromUnderlyingPrice >= ${strikePercentageFromUnderlyingPriceRangeMin} AND moniness <= ${strikePercentageFromUnderlyingPriceRangeMax}
AND strikePercentageFromUnderlyingPrice <= ${strikePercentageFromUnderlyingPriceRangeMax} AND span = ${daysBetweenFrontAndBackExpiration}
AND daysBetweenFrontAndBackExpiration = ${daysBetweenFrontAndBackExpiration} AND date >= '${lookbackPeriodStart}'
AND tsStart >= '${lookbackPeriodStart} 00:00:00' AND date <= '${lookbackPeriodEnd}'
AND tsStart <= '${lookbackPeriodEnd} 00:00:00'
`, `,
"JSONEachRow" "JSONEachRow"
); );
@@ -1,5 +1,5 @@
import { query } from "./lib/clickhouse"; import { query } from "./lib/clickhouse.js";
import { publicProcedure, RpcType, router } from "./trpc"; import { publicProcedure, RpcType, router } from "./trpc.js";
import { Object as ObjectT, String as StringT } from "@sinclair/typebox"; import { Object as ObjectT, String as StringT } from "@sinclair/typebox";
export const getChartData = publicProcedure export const getChartData = publicProcedure
@@ -17,15 +17,17 @@ export const getChartData = publicProcedure
return await query<[number, number]>( return await query<[number, number]>(
` `
SELECT SELECT
toUnixTimestamp(tsStart) as x, toUnixTimestamp(toStartOfHour(ts)) as x,
open as y avg(price) as y
FROM stock_aggregates FROM stock_aggregates_filled
WHERE symbol = '${underlying}' WHERE symbol = '${underlying}'
AND tsStart >= '${lookbackPeriodStart} 00:00:00' AND ts >= '${lookbackPeriodStart} 00:00:00'
AND tsStart <= '${lookbackPeriodEnd} 00:00:00' AND ts <= '${lookbackPeriodEnd} 00:00:00'
GROUP BY x
ORDER BY x ASC ORDER BY x ASC
`, `,
"JSONEachRow" "JSONCompactEachRow"
// "JSONEachRow"
); );
}); });
+2 -2
View File
@@ -9,7 +9,7 @@ import {
} from "@sinclair/typebox"; } from "@sinclair/typebox";
import { createServer } from "node:http"; import { createServer } from "node:http";
import { Env } from "@humanwhocodes/env"; import { Env } from "@humanwhocodes/env";
import UnderlyingPriceChart from "./UnderlyingPriceChart.js"; import StockPriceChart from "./StockPriceChart.js";
import SimilarCalendarPriceChart from "./SimilarCalendarPriceChart.js"; import SimilarCalendarPriceChart from "./SimilarCalendarPriceChart.js";
import CalendarExitPriceChart from "./CalendarExitPriceChart.js"; import CalendarExitPriceChart from "./CalendarExitPriceChart.js";
import CalendarCharacteristicsForm from "./CalendarCharacteristicsForm.js"; import CalendarCharacteristicsForm from "./CalendarCharacteristicsForm.js";
@@ -71,7 +71,7 @@ export const getOpensForOptionContract = publicProcedure
const appRouter = router({ const appRouter = router({
CalendarCharacteristicsForm, CalendarCharacteristicsForm,
UnderlyingPriceChart, StockPriceChart,
SimilarCalendarPriceChart, SimilarCalendarPriceChart,
CalendarExitPriceChart, CalendarExitPriceChart,
+5 -5
View File
@@ -6,21 +6,21 @@ import { retry } from "./utils/retry.js";
const env = new Env(); const env = new Env();
const { CLICKHOUSE_USER, CLICKHOUSE_PASS } = env.required; const { CLICKHOUSE_USER, CLICKHOUSE_PASS } = env.required;
const CLICKHOUSE_HOST = env.get("CLICKHOUSE_HOST", "http://localhost:8123"); const CLICKHOUSE_URL = env.get("CLICKHOUSE_URL", "http://localhost:8123");
export const clickhouse = createClickhouseClient({ export const clickhouse = createClickhouseClient({
host: CLICKHOUSE_HOST, url: CLICKHOUSE_URL,
username: CLICKHOUSE_USER, username: CLICKHOUSE_USER,
password: CLICKHOUSE_PASS, password: CLICKHOUSE_PASS,
keep_alive: { keep_alive: {
enabled: true, enabled: true,
socket_ttl: 2500, // socket_ttl: 2500,
}, },
}); });
export async function query<T>( export async function query<T>(
queryString: string, queryString: string,
format: DataFormat = "JSONEachRow", format: DataFormat = "JSONEachRow"
): Promise<Array<T>> { ): Promise<Array<T>> {
return await retry( return await retry(
async () => { async () => {
@@ -33,6 +33,6 @@ export async function query<T>(
}); });
return await result.json(); return await result.json();
}, },
{ maxRetries: 5 }, { maxRetries: 5 }
); );
} }