diff --git a/frontend/.env.development b/frontend/.env.development new file mode 100644 index 0000000..8e79cb2 --- /dev/null +++ b/frontend/.env.development @@ -0,0 +1 @@ +VITE_SERVER_BASE_URL=http://127.0.0.1:3005 \ No newline at end of file diff --git a/frontend/package.json b/frontend/package.json index d71fd97..33d93c0 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -10,6 +10,7 @@ "@preact/signals": "^1.2.2", "@trpc/client": "^10.45.0", "chart.js": "^4.4.1", + "dotenv": "^16.4.1", "preact": "^10.13.1", "preact-iso": "^2.3.2", "preact-render-to-string": "^6.3.1", diff --git a/frontend/pnpm-lock.yaml b/frontend/pnpm-lock.yaml index e73e4ba..1785f4b 100644 --- a/frontend/pnpm-lock.yaml +++ b/frontend/pnpm-lock.yaml @@ -14,6 +14,9 @@ dependencies: chart.js: specifier: ^4.4.1 version: 4.4.1 + dotenv: + specifier: ^16.4.1 + version: 16.4.1 preact: specifier: ^10.13.1 version: 10.19.3 @@ -724,6 +727,11 @@ packages: domhandler: 5.0.3 dev: true + /dotenv@16.4.1: + resolution: {integrity: sha512-CjA3y+Dr3FyFDOAMnxZEGtnW9KBR2M0JvvUtXNW+dYJL5ROWxP9DUHCwgFqpMk0OXCc0ljhaNTr2w/kutYIcHQ==} + engines: {node: '>=12'} + dev: false + /electron-to-chromium@1.4.623: resolution: {integrity: sha512-lKoz10iCYlP1WtRYdh5MvocQPWVRoI7ysp6qf18bmeBgR8abE6+I2CsfyNKztRDZvhdWc+krKT6wS7Neg8sw3A==} dev: true diff --git a/frontend/src/env.ts b/frontend/src/env.ts new file mode 100644 index 0000000..428b1a9 --- /dev/null +++ b/frontend/src/env.ts @@ -0,0 +1,7 @@ +import dotenv from 'dotenv'; + +if(process.env.NODE_DEV==="development"){ + dotenv.config({ path:"../.env.development" }); +} + +export default null; \ No newline at end of file diff --git a/frontend/src/index.tsx b/frontend/src/index.tsx index f66fb47..0fa2b63 100644 --- a/frontend/src/index.tsx +++ b/frontend/src/index.tsx @@ -1,3 +1,4 @@ +import _ from './env'; import { render } from 'preact'; import { LocationProvider, Router, Route } from 'preact-iso'; diff --git a/frontend/src/pages/HistoricalCalendarPrices/HistoricalCalendarPrices.tsx b/frontend/src/pages/HistoricalCalendarPrices/HistoricalCalendarPrices.tsx index d2ae7df..57bb858 100644 --- a/frontend/src/pages/HistoricalCalendarPrices/HistoricalCalendarPrices.tsx +++ b/frontend/src/pages/HistoricalCalendarPrices/HistoricalCalendarPrices.tsx @@ -32,12 +32,17 @@ const historicalCalendarQuoteChartData = signal([]); const historicalCalendarExitQuoteChartData = signal([]); +const chosenLookbackPeriodStart = signal("2022-01-01"); +const chosenLookbackPeriodEnd = signal("2024-01-01"); + export function HistoricalCalendarPrices(){ const refreshHistoricalStockQuoteChartData = useCallback(()=>{ trpc.getHistoricalStockQuoteChartData .query({ underlying:chosenUnderlying.value, + lookbackPeriodStart:chosenLookbackPeriodStart.value, + lookbackPeriodEnd:chosenLookbackPeriodEnd.value, }) .then((getHistoricalStockQuoteChartDataResponse)=>{ historicalStockQuoteChartData.value = getHistoricalStockQuoteChartDataResponse; @@ -51,6 +56,8 @@ export function HistoricalCalendarPrices(){ daysBetweenFrontAndBackExpiration:chosenDaysBetweenFrontAndBackExpiration.value, strikePercentageFromUnderlyingPriceRangeMin:chosenStrikePercentageFromUnderlyingPrice.value - chosenStrikePercentageFromUnderlyingPriceRadius.value, strikePercentageFromUnderlyingPriceRangeMax:chosenStrikePercentageFromUnderlyingPrice.value + chosenStrikePercentageFromUnderlyingPriceRadius.value, + lookbackPeriodStart:chosenLookbackPeriodStart.value, + lookbackPeriodEnd:chosenLookbackPeriodEnd.value, }) .then((getHistoricalCalendarQuoteChartDataResponse)=>{ historicalCalendarQuoteChartData.value = getHistoricalCalendarQuoteChartDataResponse; @@ -62,6 +69,8 @@ export function HistoricalCalendarPrices(){ underlying:chosenUnderlying.value, daysToFrontExpiration:chosenExitToFrontExpiration.value, daysBetweenFrontAndBackExpiration:chosenDaysBetweenFrontAndBackExpiration.value, + lookbackPeriodStart:chosenLookbackPeriodStart.value, + lookbackPeriodEnd:chosenLookbackPeriodEnd.value, }) .then((getHistoricalCalendarExitQuoteChartDataResponse)=>{ historicalCalendarExitQuoteChartData.value = getHistoricalCalendarExitQuoteChartDataResponse; @@ -106,6 +115,19 @@ export function HistoricalCalendarPrices(){ refreshHistoricalCalendarExitQuoteChartData(); },[]); + const handleLookbackPeriodStartChange = useCallback((e)=>{ + chosenLookbackPeriodStart.value = e.target.value; + refreshHistoricalStockQuoteChartData(); + refreshHistoricalCalendarQuoteChartData(); + refreshHistoricalCalendarExitQuoteChartData(); + },[]); + const handleLookbackPeriodEndChange = useCallback((e)=>{ + chosenLookbackPeriodEnd.value = e.target.value; + refreshHistoricalStockQuoteChartData(); + refreshHistoricalCalendarQuoteChartData(); + refreshHistoricalCalendarExitQuoteChartData(); + },[]); + useEffect(handleInit, []); return ( @@ -145,6 +167,12 @@ export function HistoricalCalendarPrices(){ Days +
+ + + - + +
{chosenUnderlying.value!==null && historicalStockQuoteChartData.value.length>0 ?
diff --git a/server/.env.development b/server/.env.development new file mode 100644 index 0000000..cca970c --- /dev/null +++ b/server/.env.development @@ -0,0 +1,2 @@ +CLICKHOUSE_HOST=http://localhost:8123 +LISTEN_PORT=3005 \ No newline at end of file diff --git a/server/package.json b/server/package.json index d6716fe..0ffcf46 100644 --- a/server/package.json +++ b/server/package.json @@ -12,7 +12,8 @@ "@clickhouse/client": "^0.2.7", "@sinclair/typebox": "^0.32.5", "@trpc/server": "^10.45.0", - "cors": "^2.8.5" + "cors": "^2.8.5", + "dotenv": "^16.4.1" }, "devDependencies": { "@types/cors": "^2.8.17", diff --git a/server/pnpm-lock.yaml b/server/pnpm-lock.yaml index 882e5ce..de42440 100644 --- a/server/pnpm-lock.yaml +++ b/server/pnpm-lock.yaml @@ -17,6 +17,9 @@ dependencies: cors: specifier: ^2.8.5 version: 2.8.5 + dotenv: + specifier: ^16.4.1 + version: 16.4.1 devDependencies: '@types/cors': @@ -386,6 +389,11 @@ packages: object-keys: 1.1.1 dev: true + /dotenv@16.4.1: + resolution: {integrity: sha512-CjA3y+Dr3FyFDOAMnxZEGtnW9KBR2M0JvvUtXNW+dYJL5ROWxP9DUHCwgFqpMk0OXCc0ljhaNTr2w/kutYIcHQ==} + engines: {node: '>=12'} + dev: false + /error-ex@1.3.2: resolution: {integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==} dependencies: diff --git a/server/src/env.ts b/server/src/env.ts new file mode 100644 index 0000000..428b1a9 --- /dev/null +++ b/server/src/env.ts @@ -0,0 +1,7 @@ +import dotenv from 'dotenv'; + +if(process.env.NODE_DEV==="development"){ + dotenv.config({ path:"../.env.development" }); +} + +export default null; \ No newline at end of file diff --git a/server/src/index.ts b/server/src/index.ts index ebb00c1..131ba97 100644 --- a/server/src/index.ts +++ b/server/src/index.ts @@ -1,6 +1,7 @@ +import _ from './env'; import { publicProcedure, router } from './trpc.js'; import { query } from './clickhouse.js'; -import { createHTTPHandler, createHTTPServer } from '@trpc/server/adapters/standalone'; +import { createHTTPHandler } from '@trpc/server/adapters/standalone'; import cors from 'cors'; import { Object as ObjectT, String as StringT, TSchema, Number as NumberT } from '@sinclair/typebox'; import { TypeCompiler } from '@sinclair/typebox/compiler'; @@ -140,15 +141,19 @@ const appRouter = router({ getHistoricalStockQuoteChartData: publicProcedure .input(RpcType(ObjectT({ underlying:StringT(), + lookbackPeriodStart:StringT(), + lookbackPeriodEnd:StringT(), }))) .query(async (opts)=>{ - const {underlying, } = opts.input; + const { underlying, lookbackPeriodStart, lookbackPeriodEnd } = opts.input; return (await query<[number,number]>(` SELECT toUnixTimestamp(tsStart) as x, open as y FROM stock_aggregates WHERE symbol = '${underlying}' + AND tsStart >= '${lookbackPeriodStart} 00:00:00' + AND tsStart <= '${lookbackPeriodEnd} 00:00:00' ORDER BY x ASC `,'JSONEachRow')); }), @@ -159,9 +164,11 @@ const appRouter = router({ daysBetweenFrontAndBackExpiration:NumberT(), strikePercentageFromUnderlyingPriceRangeMin:NumberT(), strikePercentageFromUnderlyingPriceRangeMax:NumberT(), + lookbackPeriodStart:StringT(), + lookbackPeriodEnd:StringT(), }))) .query(async (opts)=>{ - const {underlying, daysToFrontExpiration, daysBetweenFrontAndBackExpiration, strikePercentageFromUnderlyingPriceRangeMin, strikePercentageFromUnderlyingPriceRangeMax, } = opts.input; + const {underlying, daysToFrontExpiration, daysBetweenFrontAndBackExpiration, strikePercentageFromUnderlyingPriceRangeMin, strikePercentageFromUnderlyingPriceRangeMax, lookbackPeriodStart, lookbackPeriodEnd, } = opts.input; return (await query<[number,number]>(` SELECT toUnixTimestamp(tsStart) as x, @@ -172,6 +179,8 @@ const appRouter = router({ AND strikePercentageFromUnderlyingPrice >= ${strikePercentageFromUnderlyingPriceRangeMin} AND strikePercentageFromUnderlyingPrice <= ${strikePercentageFromUnderlyingPriceRangeMax} AND daysBetweenFrontAndBackExpiration = ${daysBetweenFrontAndBackExpiration} + AND tsStart >= '${lookbackPeriodStart} 00:00:00' + AND tsStart <= '${lookbackPeriodEnd} 00:00:00' `,'JSONEachRow')); }), getHistoricalCalendarExitQuoteChartData: publicProcedure @@ -179,9 +188,11 @@ const appRouter = router({ underlying:StringT(), daysToFrontExpiration:NumberT(), daysBetweenFrontAndBackExpiration:NumberT(), + lookbackPeriodStart:StringT(), + lookbackPeriodEnd:StringT(), }))) .query(async (opts)=>{ - const {underlying, daysToFrontExpiration, daysBetweenFrontAndBackExpiration, } = opts.input; + const {underlying, daysToFrontExpiration, daysBetweenFrontAndBackExpiration, lookbackPeriodStart, lookbackPeriodEnd, } = opts.input; return (await query<[number,number]>(` SELECT FLOOR(strikePercentageFromUnderlyingPrice, 1) as x, @@ -192,6 +203,8 @@ const appRouter = router({ AND strikePercentageFromUnderlyingPrice >= -5.0 AND strikePercentageFromUnderlyingPrice <= 5.0 AND daysBetweenFrontAndBackExpiration = ${daysBetweenFrontAndBackExpiration} + AND tsStart >= '${lookbackPeriodStart} 00:00:00' + AND tsStart <= '${lookbackPeriodEnd} 00:00:00' ORDER BY x ASC `,'JSONEachRow')); }),