|
|
@ -1,12 +1,17 @@
|
|
|
|
import _ from './env';
|
|
|
|
import _ from "./env";
|
|
|
|
import { publicProcedure, router } from './trpc.js';
|
|
|
|
import { publicProcedure, router } from "./trpc.js";
|
|
|
|
import { query } from './clickhouse.js';
|
|
|
|
import { query } from "./clickhouse.js";
|
|
|
|
import { createHTTPHandler } from '@trpc/server/adapters/standalone';
|
|
|
|
import { createHTTPHandler } from "@trpc/server/adapters/standalone";
|
|
|
|
import cors from 'cors';
|
|
|
|
import cors from "cors";
|
|
|
|
import { Object as ObjectT, String as StringT, TSchema, Number as NumberT } from '@sinclair/typebox';
|
|
|
|
import {
|
|
|
|
import { TypeCompiler } from '@sinclair/typebox/compiler';
|
|
|
|
Object as ObjectT,
|
|
|
|
import { TRPCError } from '@trpc/server';
|
|
|
|
String as StringT,
|
|
|
|
import { createServer } from 'http';
|
|
|
|
TSchema,
|
|
|
|
|
|
|
|
Number as NumberT,
|
|
|
|
|
|
|
|
} from "@sinclair/typebox";
|
|
|
|
|
|
|
|
import { TypeCompiler } from "@sinclair/typebox/compiler";
|
|
|
|
|
|
|
|
import { TRPCError } from "@trpc/server";
|
|
|
|
|
|
|
|
import { createServer } from "http";
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
/**
|
|
|
|
* Generate a TRPC-compatible validator function given a Typebox schema.
|
|
|
|
* Generate a TRPC-compatible validator function given a Typebox schema.
|
|
|
@ -15,94 +20,128 @@ import { createServer } from 'http';
|
|
|
|
* @returns A TRPC-compatible validator function
|
|
|
|
* @returns A TRPC-compatible validator function
|
|
|
|
*/
|
|
|
|
*/
|
|
|
|
export function RpcType<T extends TSchema>(schema: T) {
|
|
|
|
export function RpcType<T extends TSchema>(schema: T) {
|
|
|
|
const check = TypeCompiler.Compile(schema)
|
|
|
|
const check = TypeCompiler.Compile(schema);
|
|
|
|
return (value: unknown) => {
|
|
|
|
return (value: unknown) => {
|
|
|
|
if (check.Check(value)) return value
|
|
|
|
if (check.Check(value)) return value;
|
|
|
|
const { path, message } = check.Errors(value).First()!
|
|
|
|
const { path, message } = check.Errors(value).First()!;
|
|
|
|
throw new TRPCError({ message: `${message} for ${path}`, code: 'BAD_REQUEST' })
|
|
|
|
throw new TRPCError({
|
|
|
|
}
|
|
|
|
message: `${message} for ${path}`,
|
|
|
|
|
|
|
|
code: "BAD_REQUEST",
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
};
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const appRouter = router({
|
|
|
|
const appRouter = router({
|
|
|
|
getAvailableUnderlyings: publicProcedure
|
|
|
|
getAvailableUnderlyings: publicProcedure.query(async (opts) => {
|
|
|
|
.query(async (opts) => {
|
|
|
|
// return (await query<{symbol:string}>(`
|
|
|
|
return (await query<{symbol:string}>(`
|
|
|
|
// SELECT DISTINCT(symbol) as symbol FROM option_contracts
|
|
|
|
SELECT DISTINCT(symbol) as symbol FROM option_contracts
|
|
|
|
// `))
|
|
|
|
`))
|
|
|
|
// .map(({symbol})=>symbol);
|
|
|
|
.map(({symbol})=>symbol);
|
|
|
|
return ["GOOGL", "AAPL", "NFLX", "AMD", "MSFT"];
|
|
|
|
}),
|
|
|
|
}),
|
|
|
|
getAvailableAsOfDates: publicProcedure
|
|
|
|
getAvailableAsOfDates: publicProcedure
|
|
|
|
.input(RpcType(ObjectT({underlying:StringT()})))
|
|
|
|
.input(RpcType(ObjectT({ underlying: StringT() })))
|
|
|
|
.query(async (opts) => {
|
|
|
|
.query(async (opts) => {
|
|
|
|
const underlying = opts.input.underlying;
|
|
|
|
const underlying = opts.input.underlying;
|
|
|
|
return (await query<{asOfDate:string}>(`
|
|
|
|
return (
|
|
|
|
|
|
|
|
await query<{ asOfDate: string }>(`
|
|
|
|
SELECT
|
|
|
|
SELECT
|
|
|
|
DISTINCT(asOfDate) as asOfDate
|
|
|
|
DISTINCT(asOfDate) as asOfDate
|
|
|
|
FROM option_contracts
|
|
|
|
FROM option_contracts
|
|
|
|
WHERE symbol = '${underlying}'
|
|
|
|
WHERE symbol = '${underlying}'
|
|
|
|
`))
|
|
|
|
`)
|
|
|
|
.map(({asOfDate})=>asOfDate);
|
|
|
|
).map(({ asOfDate }) => asOfDate);
|
|
|
|
}),
|
|
|
|
}),
|
|
|
|
getExpirationsForUnderlying: publicProcedure
|
|
|
|
getExpirationsForUnderlying: publicProcedure
|
|
|
|
.input(RpcType(ObjectT({
|
|
|
|
.input(
|
|
|
|
underlying:StringT({maxLength:5}),
|
|
|
|
RpcType(
|
|
|
|
asOfDate:StringT()
|
|
|
|
ObjectT({
|
|
|
|
})))
|
|
|
|
underlying: StringT({ maxLength: 5 }),
|
|
|
|
.query(async (opts)=>{
|
|
|
|
asOfDate: StringT(),
|
|
|
|
const {underlying, asOfDate} = opts.input;
|
|
|
|
})
|
|
|
|
return (await query<{expirationDate:string}>(`
|
|
|
|
)
|
|
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
.query(async (opts) => {
|
|
|
|
|
|
|
|
const { underlying, asOfDate } = opts.input;
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
|
|
|
await query<{ expirationDate: string }>(`
|
|
|
|
SELECT
|
|
|
|
SELECT
|
|
|
|
DISTINCT(expirationDate)
|
|
|
|
DISTINCT(expirationDate)
|
|
|
|
FROM option_contracts
|
|
|
|
FROM option_contracts
|
|
|
|
WHERE symbol = '${underlying}'
|
|
|
|
WHERE symbol = '${underlying}'
|
|
|
|
AND asOfDate = '${asOfDate}'
|
|
|
|
AND asOfDate = '${asOfDate}'
|
|
|
|
`))
|
|
|
|
`)
|
|
|
|
.map(({expirationDate})=>expirationDate);
|
|
|
|
).map(({ expirationDate }) => expirationDate);
|
|
|
|
}),
|
|
|
|
}),
|
|
|
|
getStrikesForUnderlying: publicProcedure
|
|
|
|
getStrikesForUnderlying: publicProcedure
|
|
|
|
.input(RpcType(ObjectT({
|
|
|
|
.input(
|
|
|
|
underlying:StringT({maxLength:5}),
|
|
|
|
RpcType(
|
|
|
|
asOfDate:StringT(),
|
|
|
|
ObjectT({
|
|
|
|
expirationDate:StringT(),
|
|
|
|
underlying: StringT({ maxLength: 5 }),
|
|
|
|
})))
|
|
|
|
asOfDate: StringT(),
|
|
|
|
.query(async (opts)=>{
|
|
|
|
expirationDate: StringT(),
|
|
|
|
const {underlying, asOfDate, expirationDate} = opts.input;
|
|
|
|
})
|
|
|
|
return (await query<{strike:string}>(`
|
|
|
|
)
|
|
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
.query(async (opts) => {
|
|
|
|
|
|
|
|
const { underlying, asOfDate, expirationDate } = opts.input;
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
|
|
|
await query<{ strike: string }>(`
|
|
|
|
SELECT
|
|
|
|
SELECT
|
|
|
|
DISTINCT(strike)
|
|
|
|
DISTINCT(strike)
|
|
|
|
FROM option_contracts
|
|
|
|
FROM option_contracts
|
|
|
|
WHERE symbol = '${underlying}'
|
|
|
|
WHERE symbol = '${underlying}'
|
|
|
|
AND asOfDate = '${asOfDate}'
|
|
|
|
AND asOfDate = '${asOfDate}'
|
|
|
|
AND expirationDate = '${expirationDate}'
|
|
|
|
AND expirationDate = '${expirationDate}'
|
|
|
|
`))
|
|
|
|
`)
|
|
|
|
.map(({strike})=>strike);
|
|
|
|
).map(({ strike }) => strike);
|
|
|
|
}),
|
|
|
|
}),
|
|
|
|
getOpensForUnderlying: publicProcedure
|
|
|
|
getOpensForUnderlying: publicProcedure
|
|
|
|
.input(RpcType(ObjectT({
|
|
|
|
.input(
|
|
|
|
underlying:StringT({maxLength:5})
|
|
|
|
RpcType(
|
|
|
|
})))
|
|
|
|
ObjectT({
|
|
|
|
.query(async (opts)=>{
|
|
|
|
underlying: StringT({ maxLength: 5 }),
|
|
|
|
const {underlying} = opts.input;
|
|
|
|
})
|
|
|
|
return (await query<[number,number]>(`
|
|
|
|
)
|
|
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
.query(async (opts) => {
|
|
|
|
|
|
|
|
const { underlying } = opts.input;
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
|
|
|
await query<[number, number]>(
|
|
|
|
|
|
|
|
`
|
|
|
|
SELECT
|
|
|
|
SELECT
|
|
|
|
toUnixTimestamp(tsStart),
|
|
|
|
toUnixTimestamp(tsStart),
|
|
|
|
open
|
|
|
|
open
|
|
|
|
FROM stock_aggregates
|
|
|
|
FROM stock_aggregates
|
|
|
|
WHERE symbol = '${underlying}'
|
|
|
|
WHERE symbol = '${underlying}'
|
|
|
|
ORDER BY tsStart ASC
|
|
|
|
ORDER BY tsStart ASC
|
|
|
|
`,'JSONCompactEachRow'))
|
|
|
|
`,
|
|
|
|
.reduce((columns, row)=>{ columns[0].push(row[0]); columns[1].push(row[1]); return columns; },[[],[]]);
|
|
|
|
"JSONCompactEachRow"
|
|
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
).reduce(
|
|
|
|
|
|
|
|
(columns, row) => {
|
|
|
|
|
|
|
|
columns[0].push(row[0]);
|
|
|
|
|
|
|
|
columns[1].push(row[1]);
|
|
|
|
|
|
|
|
return columns;
|
|
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
[[], []]
|
|
|
|
|
|
|
|
);
|
|
|
|
}),
|
|
|
|
}),
|
|
|
|
getOpensForOptionContract: publicProcedure
|
|
|
|
getOpensForOptionContract: publicProcedure
|
|
|
|
.input(RpcType(ObjectT({
|
|
|
|
.input(
|
|
|
|
underlying:StringT({maxLength:5}),
|
|
|
|
RpcType(
|
|
|
|
expirationDate:StringT(),
|
|
|
|
ObjectT({
|
|
|
|
strike:NumberT()
|
|
|
|
underlying: StringT({ maxLength: 5 }),
|
|
|
|
})))
|
|
|
|
expirationDate: StringT(),
|
|
|
|
.query(async (opts)=>{
|
|
|
|
strike: NumberT(),
|
|
|
|
const {underlying, expirationDate, strike} = opts.input;
|
|
|
|
})
|
|
|
|
return (await query<[number,number]>(`
|
|
|
|
)
|
|
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
.query(async (opts) => {
|
|
|
|
|
|
|
|
const { underlying, expirationDate, strike } = opts.input;
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
|
|
|
await query<[number, number]>(
|
|
|
|
|
|
|
|
`
|
|
|
|
SELECT
|
|
|
|
SELECT
|
|
|
|
toUnixTimestamp(tsStart),
|
|
|
|
toUnixTimestamp(tsStart),
|
|
|
|
open
|
|
|
|
open
|
|
|
@ -112,20 +151,41 @@ const appRouter = router({
|
|
|
|
AND strike = ${strike}
|
|
|
|
AND strike = ${strike}
|
|
|
|
AND optionType = 'call'
|
|
|
|
AND optionType = 'call'
|
|
|
|
ORDER BY tsStart ASC
|
|
|
|
ORDER BY tsStart ASC
|
|
|
|
`,'JSONCompactEachRow'))
|
|
|
|
`,
|
|
|
|
.reduce((columns, row)=>{ columns[0].push(row[0]); columns[1].push(row[1]); return columns; },[[],[]]);
|
|
|
|
"JSONCompactEachRow"
|
|
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
).reduce(
|
|
|
|
|
|
|
|
(columns, row) => {
|
|
|
|
|
|
|
|
columns[0].push(row[0]);
|
|
|
|
|
|
|
|
columns[1].push(row[1]);
|
|
|
|
|
|
|
|
return columns;
|
|
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
[[], []]
|
|
|
|
|
|
|
|
);
|
|
|
|
}),
|
|
|
|
}),
|
|
|
|
getHistoricalCalendarPrices: publicProcedure
|
|
|
|
getHistoricalCalendarPrices: publicProcedure
|
|
|
|
.input(RpcType(ObjectT({
|
|
|
|
.input(
|
|
|
|
underlying:StringT({maxLength:5}),
|
|
|
|
RpcType(
|
|
|
|
daysToFrontExpiration:NumberT(),
|
|
|
|
ObjectT({
|
|
|
|
daysBetweenFrontAndBackExpiration:NumberT(),
|
|
|
|
underlying: StringT({ maxLength: 5 }),
|
|
|
|
strikePercentageFromUnderlyingPriceRangeMin:NumberT(),
|
|
|
|
daysToFrontExpiration: NumberT(),
|
|
|
|
strikePercentageFromUnderlyingPriceRangeMax:NumberT(),
|
|
|
|
daysBetweenFrontAndBackExpiration: NumberT(),
|
|
|
|
})))
|
|
|
|
strikePercentageFromUnderlyingPriceRangeMin: NumberT(),
|
|
|
|
.query(async (opts)=>{
|
|
|
|
strikePercentageFromUnderlyingPriceRangeMax: NumberT(),
|
|
|
|
const {underlying, daysToFrontExpiration, daysBetweenFrontAndBackExpiration, strikePercentageFromUnderlyingPriceRangeMin, strikePercentageFromUnderlyingPriceRangeMax, } = opts.input;
|
|
|
|
})
|
|
|
|
return (await query<[number,number]>(`
|
|
|
|
)
|
|
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
.query(async (opts) => {
|
|
|
|
|
|
|
|
const {
|
|
|
|
|
|
|
|
underlying,
|
|
|
|
|
|
|
|
daysToFrontExpiration,
|
|
|
|
|
|
|
|
daysBetweenFrontAndBackExpiration,
|
|
|
|
|
|
|
|
strikePercentageFromUnderlyingPriceRangeMin,
|
|
|
|
|
|
|
|
strikePercentageFromUnderlyingPriceRangeMax,
|
|
|
|
|
|
|
|
} = opts.input;
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
|
|
|
await query<[number, number]>(
|
|
|
|
|
|
|
|
`
|
|
|
|
SELECT
|
|
|
|
SELECT
|
|
|
|
toUnixTimestamp(tsStart) as asOfTs,
|
|
|
|
toUnixTimestamp(tsStart) as asOfTs,
|
|
|
|
calendarPrice
|
|
|
|
calendarPrice
|
|
|
@ -135,18 +195,32 @@ const appRouter = router({
|
|
|
|
AND strikePercentageFromUnderlyingPrice >= ${strikePercentageFromUnderlyingPriceRangeMin}
|
|
|
|
AND strikePercentageFromUnderlyingPrice >= ${strikePercentageFromUnderlyingPriceRangeMin}
|
|
|
|
AND strikePercentageFromUnderlyingPrice <= ${strikePercentageFromUnderlyingPriceRangeMax}
|
|
|
|
AND strikePercentageFromUnderlyingPrice <= ${strikePercentageFromUnderlyingPriceRangeMax}
|
|
|
|
AND daysBetweenFrontAndBackExpiration = ${daysBetweenFrontAndBackExpiration}
|
|
|
|
AND daysBetweenFrontAndBackExpiration = ${daysBetweenFrontAndBackExpiration}
|
|
|
|
`,'JSONCompactEachRow'))
|
|
|
|
`,
|
|
|
|
.reduce((columns, row)=>{ columns[0].push(row[0]); columns[1].push(row[1]); return columns; },[[],[]]);
|
|
|
|
"JSONCompactEachRow"
|
|
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
).reduce(
|
|
|
|
|
|
|
|
(columns, row) => {
|
|
|
|
|
|
|
|
columns[0].push(row[0]);
|
|
|
|
|
|
|
|
columns[1].push(row[1]);
|
|
|
|
|
|
|
|
return columns;
|
|
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
[[], []]
|
|
|
|
|
|
|
|
);
|
|
|
|
}),
|
|
|
|
}),
|
|
|
|
getHistoricalStockQuoteChartData: publicProcedure
|
|
|
|
getHistoricalStockQuoteChartData: publicProcedure
|
|
|
|
.input(RpcType(ObjectT({
|
|
|
|
.input(
|
|
|
|
underlying:StringT({maxLength:5}),
|
|
|
|
RpcType(
|
|
|
|
lookbackPeriodStart:StringT(),
|
|
|
|
ObjectT({
|
|
|
|
lookbackPeriodEnd:StringT(),
|
|
|
|
underlying: StringT({ maxLength: 5 }),
|
|
|
|
})))
|
|
|
|
lookbackPeriodStart: StringT(),
|
|
|
|
.query(async (opts)=>{
|
|
|
|
lookbackPeriodEnd: StringT(),
|
|
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
.query(async (opts) => {
|
|
|
|
const { underlying, lookbackPeriodStart, lookbackPeriodEnd } = opts.input;
|
|
|
|
const { underlying, lookbackPeriodStart, lookbackPeriodEnd } = opts.input;
|
|
|
|
return (await query<[number,number]>(`
|
|
|
|
return await query<[number, number]>(
|
|
|
|
|
|
|
|
`
|
|
|
|
SELECT
|
|
|
|
SELECT
|
|
|
|
toUnixTimestamp(tsStart) as x,
|
|
|
|
toUnixTimestamp(tsStart) as x,
|
|
|
|
open as y
|
|
|
|
open as y
|
|
|
@ -155,21 +229,36 @@ const appRouter = router({
|
|
|
|
AND tsStart >= '${lookbackPeriodStart} 00:00:00'
|
|
|
|
AND tsStart >= '${lookbackPeriodStart} 00:00:00'
|
|
|
|
AND tsStart <= '${lookbackPeriodEnd} 00:00:00'
|
|
|
|
AND tsStart <= '${lookbackPeriodEnd} 00:00:00'
|
|
|
|
ORDER BY x ASC
|
|
|
|
ORDER BY x ASC
|
|
|
|
`,'JSONEachRow'));
|
|
|
|
`,
|
|
|
|
|
|
|
|
"JSONEachRow"
|
|
|
|
|
|
|
|
);
|
|
|
|
}),
|
|
|
|
}),
|
|
|
|
getHistoricalCalendarQuoteChartData: publicProcedure
|
|
|
|
getHistoricalCalendarQuoteChartData: publicProcedure
|
|
|
|
.input(RpcType(ObjectT({
|
|
|
|
.input(
|
|
|
|
underlying:StringT({maxLength:5}),
|
|
|
|
RpcType(
|
|
|
|
daysToFrontExpiration:NumberT(),
|
|
|
|
ObjectT({
|
|
|
|
daysBetweenFrontAndBackExpiration:NumberT(),
|
|
|
|
underlying: StringT({ maxLength: 5 }),
|
|
|
|
strikePercentageFromUnderlyingPriceRangeMin:NumberT(),
|
|
|
|
daysToFrontExpiration: NumberT(),
|
|
|
|
strikePercentageFromUnderlyingPriceRangeMax:NumberT(),
|
|
|
|
daysBetweenFrontAndBackExpiration: NumberT(),
|
|
|
|
lookbackPeriodStart:StringT(),
|
|
|
|
strikePercentageFromUnderlyingPriceRangeMin: NumberT(),
|
|
|
|
lookbackPeriodEnd:StringT(),
|
|
|
|
strikePercentageFromUnderlyingPriceRangeMax: NumberT(),
|
|
|
|
})))
|
|
|
|
lookbackPeriodStart: StringT(),
|
|
|
|
.query(async (opts)=>{
|
|
|
|
lookbackPeriodEnd: StringT(),
|
|
|
|
const {underlying, daysToFrontExpiration, daysBetweenFrontAndBackExpiration, strikePercentageFromUnderlyingPriceRangeMin, strikePercentageFromUnderlyingPriceRangeMax, lookbackPeriodStart, lookbackPeriodEnd, } = opts.input;
|
|
|
|
})
|
|
|
|
return (await query<[number,number]>(`
|
|
|
|
)
|
|
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
.query(async (opts) => {
|
|
|
|
|
|
|
|
const {
|
|
|
|
|
|
|
|
underlying,
|
|
|
|
|
|
|
|
daysToFrontExpiration,
|
|
|
|
|
|
|
|
daysBetweenFrontAndBackExpiration,
|
|
|
|
|
|
|
|
strikePercentageFromUnderlyingPriceRangeMin,
|
|
|
|
|
|
|
|
strikePercentageFromUnderlyingPriceRangeMax,
|
|
|
|
|
|
|
|
lookbackPeriodStart,
|
|
|
|
|
|
|
|
lookbackPeriodEnd,
|
|
|
|
|
|
|
|
} = opts.input;
|
|
|
|
|
|
|
|
return await query<[number, number]>(
|
|
|
|
|
|
|
|
`
|
|
|
|
SELECT
|
|
|
|
SELECT
|
|
|
|
toUnixTimestamp(tsStart) as x,
|
|
|
|
toUnixTimestamp(tsStart) as x,
|
|
|
|
calendarPrice as y
|
|
|
|
calendarPrice as y
|
|
|
@ -181,19 +270,34 @@ const appRouter = router({
|
|
|
|
AND daysBetweenFrontAndBackExpiration = ${daysBetweenFrontAndBackExpiration}
|
|
|
|
AND daysBetweenFrontAndBackExpiration = ${daysBetweenFrontAndBackExpiration}
|
|
|
|
AND tsStart >= '${lookbackPeriodStart} 00:00:00'
|
|
|
|
AND tsStart >= '${lookbackPeriodStart} 00:00:00'
|
|
|
|
AND tsStart <= '${lookbackPeriodEnd} 00:00:00'
|
|
|
|
AND tsStart <= '${lookbackPeriodEnd} 00:00:00'
|
|
|
|
`,'JSONEachRow'));
|
|
|
|
`,
|
|
|
|
|
|
|
|
"JSONEachRow"
|
|
|
|
|
|
|
|
);
|
|
|
|
}),
|
|
|
|
}),
|
|
|
|
getHistoricalCalendarExitQuoteChartData: publicProcedure
|
|
|
|
getHistoricalCalendarExitQuoteChartData: publicProcedure
|
|
|
|
.input(RpcType(ObjectT({
|
|
|
|
.input(
|
|
|
|
underlying:StringT({maxLength:5}),
|
|
|
|
RpcType(
|
|
|
|
daysToFrontExpiration:NumberT(),
|
|
|
|
ObjectT({
|
|
|
|
daysBetweenFrontAndBackExpiration:NumberT(),
|
|
|
|
underlying: StringT({ maxLength: 5 }),
|
|
|
|
lookbackPeriodStart:StringT({pattern:'[0-9]{4}\-[0-9]{2}\-[0-9]{2}'}),
|
|
|
|
daysToFrontExpiration: NumberT(),
|
|
|
|
lookbackPeriodEnd:StringT({pattern:'[0-9]{4}\-[0-9]{2}\-[0-9]{2}'}),
|
|
|
|
daysBetweenFrontAndBackExpiration: NumberT(),
|
|
|
|
})))
|
|
|
|
lookbackPeriodStart: StringT({
|
|
|
|
.query(async (opts)=>{
|
|
|
|
pattern: "[0-9]{4}-[0-9]{2}-[0-9]{2}",
|
|
|
|
const {underlying, daysToFrontExpiration, daysBetweenFrontAndBackExpiration, lookbackPeriodStart, lookbackPeriodEnd, } = opts.input;
|
|
|
|
}),
|
|
|
|
return (await query<[number,number]>(`
|
|
|
|
lookbackPeriodEnd: StringT({ pattern: "[0-9]{4}-[0-9]{2}-[0-9]{2}" }),
|
|
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
.query(async (opts) => {
|
|
|
|
|
|
|
|
const {
|
|
|
|
|
|
|
|
underlying,
|
|
|
|
|
|
|
|
daysToFrontExpiration,
|
|
|
|
|
|
|
|
daysBetweenFrontAndBackExpiration,
|
|
|
|
|
|
|
|
lookbackPeriodStart,
|
|
|
|
|
|
|
|
lookbackPeriodEnd,
|
|
|
|
|
|
|
|
} = opts.input;
|
|
|
|
|
|
|
|
return await query<[number, number]>(
|
|
|
|
|
|
|
|
`
|
|
|
|
SELECT
|
|
|
|
SELECT
|
|
|
|
FLOOR(strikePercentageFromUnderlyingPrice, 1) as x,
|
|
|
|
FLOOR(strikePercentageFromUnderlyingPrice, 1) as x,
|
|
|
|
calendarPrice as y
|
|
|
|
calendarPrice as y
|
|
|
@ -206,7 +310,9 @@ const appRouter = router({
|
|
|
|
AND tsStart >= '${lookbackPeriodStart} 00:00:00'
|
|
|
|
AND tsStart >= '${lookbackPeriodStart} 00:00:00'
|
|
|
|
AND tsStart <= '${lookbackPeriodEnd} 00:00:00'
|
|
|
|
AND tsStart <= '${lookbackPeriodEnd} 00:00:00'
|
|
|
|
ORDER BY x ASC
|
|
|
|
ORDER BY x ASC
|
|
|
|
`,'JSONEachRow'));
|
|
|
|
`,
|
|
|
|
|
|
|
|
"JSONEachRow"
|
|
|
|
|
|
|
|
);
|
|
|
|
}),
|
|
|
|
}),
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
@ -214,7 +320,6 @@ const appRouter = router({
|
|
|
|
// NOT the router itself.
|
|
|
|
// NOT the router itself.
|
|
|
|
export type AppRouter = typeof appRouter;
|
|
|
|
export type AppRouter = typeof appRouter;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const handler = createHTTPHandler({
|
|
|
|
const handler = createHTTPHandler({
|
|
|
|
middleware: cors(),
|
|
|
|
middleware: cors(),
|
|
|
|
router: appRouter,
|
|
|
|
router: appRouter,
|
|
|
@ -223,14 +328,13 @@ const handler = createHTTPHandler({
|
|
|
|
},
|
|
|
|
},
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
const server = createServer((req, res)=>{
|
|
|
|
const server = createServer((req, res) => {
|
|
|
|
if(req.url.startsWith("/healthz")){
|
|
|
|
if (req.url.startsWith("/healthz")) {
|
|
|
|
res.statusCode = 200;
|
|
|
|
res.statusCode = 200;
|
|
|
|
res.end("OK");
|
|
|
|
res.end("OK");
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
else{
|
|
|
|
|
|
|
|
handler(req, res);
|
|
|
|
handler(req, res);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
server.listen(parseInt(process.env.LISTEN_PORT) || 3005);
|
|
|
|
server.listen(parseInt(process.env.LISTEN_PORT) || 3005);
|
|
|
|