Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 113b6e66e5 | |||
| e6a5002ec0 |
@@ -1,5 +1,5 @@
|
|||||||
import { signal } from "@preact/signals";
|
import { signal, computed } from "@preact/signals";
|
||||||
import { useCallback, useEffect } from "preact/hooks";
|
import { useEffect } from "preact/hooks";
|
||||||
import {trpc} from '../../trpc.js';
|
import {trpc} from '../../trpc.js';
|
||||||
import {
|
import {
|
||||||
Chart as ChartJS,
|
Chart as ChartJS,
|
||||||
@@ -35,6 +35,13 @@ const historicalCalendarExitQuoteChartData = signal([]);
|
|||||||
const chosenLookbackPeriodStart = signal("2022-01-01");
|
const chosenLookbackPeriodStart = signal("2022-01-01");
|
||||||
const chosenLookbackPeriodEnd = signal("2024-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 refreshHistoricalStockQuoteChartData = ()=>{
|
const refreshHistoricalStockQuoteChartData = ()=>{
|
||||||
trpc.getHistoricalStockQuoteChartData
|
trpc.getHistoricalStockQuoteChartData
|
||||||
@@ -212,7 +219,9 @@ export function HistoricalCalendarPrices(){
|
|||||||
callback: function(value, index, ticks) {
|
callback: function(value, index, ticks) {
|
||||||
return (new Date(value as number*1000)).toISOString().substring(0,10);
|
return (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: {
|
y: {
|
||||||
beginAtZero: false,
|
beginAtZero: false,
|
||||||
@@ -271,7 +280,9 @@ export function HistoricalCalendarPrices(){
|
|||||||
callback: function(value, index, ticks) {
|
callback: function(value, index, ticks) {
|
||||||
return (new Date(value as number*1000)).toISOString().substring(0,10);
|
return (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: {
|
y: {
|
||||||
beginAtZero: true,
|
beginAtZero: true,
|
||||||
@@ -279,7 +290,9 @@ export function HistoricalCalendarPrices(){
|
|||||||
callback: function(value, index, ticks) {
|
callback: function(value, index, ticks) {
|
||||||
return "$"+value.toString();
|
return "$"+value.toString();
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
min: 0,
|
||||||
|
max: maxChartPrice.value,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
plugins: {
|
plugins: {
|
||||||
@@ -325,7 +338,7 @@ export function HistoricalCalendarPrices(){
|
|||||||
callback: function(value, index, ticks) {
|
callback: function(value, index, ticks) {
|
||||||
return value.toString()+"%";
|
return value.toString()+"%";
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
y: {
|
y: {
|
||||||
beginAtZero: true,
|
beginAtZero: true,
|
||||||
@@ -333,7 +346,9 @@ export function HistoricalCalendarPrices(){
|
|||||||
callback: function(value, index, ticks) {
|
callback: function(value, index, ticks) {
|
||||||
return "$"+value.toString();
|
return "$"+value.toString();
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
min: 0,
|
||||||
|
max: maxChartPrice.value,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
elements: {
|
elements: {
|
||||||
|
|||||||
+4
-2
@@ -2,7 +2,7 @@
|
|||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "esbuild src/*.ts --platform=node --outdir=dist --format=esm",
|
"build": "esbuild src/*.ts src/**/*.ts --platform=node --outdir=dist --format=esm",
|
||||||
"build-scripts": "esbuild scripts/*.ts --platform=node --outdir=dist/scripts --format=esm",
|
"build-scripts": "esbuild scripts/*.ts --platform=node --outdir=dist/scripts --format=esm",
|
||||||
"dev:node": "node --watch dist/index.js",
|
"dev:node": "node --watch dist/index.js",
|
||||||
"dev:esbuild": "pnpm run build --watch",
|
"dev:esbuild": "pnpm run build --watch",
|
||||||
@@ -13,7 +13,9 @@
|
|||||||
"@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",
|
||||||
"dotenv": "^16.4.1"
|
"dotenv": "^16.4.1",
|
||||||
|
"p-all": "^5.0.0",
|
||||||
|
"p-throttle": "^6.1.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/cors": "^2.8.17",
|
"@types/cors": "^2.8.17",
|
||||||
|
|||||||
Generated
+23
@@ -20,6 +20,12 @@ dependencies:
|
|||||||
dotenv:
|
dotenv:
|
||||||
specifier: ^16.4.1
|
specifier: ^16.4.1
|
||||||
version: 16.4.1
|
version: 16.4.1
|
||||||
|
p-all:
|
||||||
|
specifier: ^5.0.0
|
||||||
|
version: 5.0.0
|
||||||
|
p-throttle:
|
||||||
|
specifier: ^6.1.0
|
||||||
|
version: 6.1.0
|
||||||
|
|
||||||
devDependencies:
|
devDependencies:
|
||||||
'@types/cors':
|
'@types/cors':
|
||||||
@@ -792,6 +798,23 @@ packages:
|
|||||||
object-keys: 1.1.1
|
object-keys: 1.1.1
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/p-all@5.0.0:
|
||||||
|
resolution: {integrity: sha512-pofqu/1FhCVa+78xNAptCGc9V45exFz2pvBRyIvgXkNM0Rh18Py7j8pQuSjA+zpabI46v9hRjNWmL9EAFcEbpw==}
|
||||||
|
engines: {node: '>=16'}
|
||||||
|
dependencies:
|
||||||
|
p-map: 6.0.0
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/p-map@6.0.0:
|
||||||
|
resolution: {integrity: sha512-T8BatKGY+k5rU+Q/GTYgrEf2r4xRMevAN5mtXc2aPc4rS1j3s+vWTaO2Wag94neXuCAUAs8cxBL9EeB5EA6diw==}
|
||||||
|
engines: {node: '>=16'}
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/p-throttle@6.1.0:
|
||||||
|
resolution: {integrity: sha512-eQMdGTxk2+047La67wefUtt0tEHh7D+C8Jl7QXoFCuIiNYeQ9zWs2AZiJdIAs72rSXZ06t11me2bgalRNdy3SQ==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
dev: false
|
||||||
|
|
||||||
/parse-json@4.0.0:
|
/parse-json@4.0.0:
|
||||||
resolution: {integrity: sha512-aOIos8bujGN93/8Ox/jPLh7RwVnPEysynVFE+fQZyg6jKELEHwzgKdLRFHUgXJL6kylijVSBC4BvN9OmsB48Rw==}
|
resolution: {integrity: sha512-aOIos8bujGN93/8Ox/jPLh7RwVnPEysynVFE+fQZyg6jKELEHwzgKdLRFHUgXJL6kylijVSBC4BvN9OmsB48Rw==}
|
||||||
engines: {node: '>=4'}
|
engines: {node: '>=4'}
|
||||||
|
|||||||
@@ -0,0 +1,62 @@
|
|||||||
|
import { clickhouse, query } from "../clickhouse.js";
|
||||||
|
import { getApiKey } from "./polygon.js";
|
||||||
|
import pAll from 'p-all';
|
||||||
|
|
||||||
|
type PolygonResponse = {next_url?:string, results:Array<{ticker:string}>};
|
||||||
|
async function getOptionContracts(underlyingSymbol, asOfDate){
|
||||||
|
let latestBatch = await (await fetch(`https://api.polygon.io/v3/reference/options/contracts?underlying_ticker=${underlyingSymbol}&as_of=${asOfDate}&sort=ticker&limit=1000&apiKey=${await getApiKey()}`)).json() as PolygonResponse;
|
||||||
|
console.log(latestBatch.results.map((r)=>r.ticker));
|
||||||
|
while(latestBatch.hasOwnProperty('next_url')){
|
||||||
|
latestBatch = await (await fetch(`${latestBatch.next_url}&apiKey=${await getApiKey()}`)).json() as PolygonResponse;
|
||||||
|
console.log(latestBatch.results.map((r)=>r.ticker));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//await getOptionContracts('AAPL','2024-01-30');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* For each symbol in `symbols` table, check the latest `asOfDate`
|
||||||
|
* in `symbol_sync_statuses` for that symbol. Then fill-in the rest
|
||||||
|
* of the dates until today's date.
|
||||||
|
*/
|
||||||
|
async function fillSyncStatuses(){
|
||||||
|
const symbols = (await query(`
|
||||||
|
SELECT symbol from symbols
|
||||||
|
`)).map(({symbol})=>symbol);
|
||||||
|
|
||||||
|
console.log('symbols', symbols);
|
||||||
|
await pAll(symbols.map(
|
||||||
|
(symbol)=>
|
||||||
|
()=>query<{latestAsOfDate:string}>(`
|
||||||
|
SELECT
|
||||||
|
latestAsOfDate
|
||||||
|
FROM(
|
||||||
|
SELECT last_value(asOfDate) as latestAsOfDate
|
||||||
|
FROM (
|
||||||
|
SELECT *
|
||||||
|
FROM symbol_sync_statuses
|
||||||
|
WHERE symbol = '${symbol}'
|
||||||
|
ORDER BY asOfDate ASC
|
||||||
|
)
|
||||||
|
)
|
||||||
|
WHERE latestAsOfDate > '2022-02-18'
|
||||||
|
`).then((rows)=>
|
||||||
|
clickhouse.command({
|
||||||
|
query: `
|
||||||
|
INSERT INTO symbol_sync_statuses
|
||||||
|
SELECT
|
||||||
|
'${symbol}' as symbol,
|
||||||
|
Date(dateAdd(DAY,number,'${rows[0]?.latestAsOfDate || '2022-02-19'}')) as asOfDate,
|
||||||
|
'not-started' as status
|
||||||
|
FROM system.numbers
|
||||||
|
WHERE number < dateDiff('days',Date('${rows[0]?.latestAsOfDate || '2022-02-19'}'), Date(now()))
|
||||||
|
AND number > 0
|
||||||
|
`
|
||||||
|
}).then(()=>{console.log(`Done ${symbol}`);})
|
||||||
|
)
|
||||||
|
),
|
||||||
|
{concurrency: 6}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
await fillSyncStatuses();
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
import pThrottle from 'p-throttle';
|
||||||
|
|
||||||
|
const apiKey = 'H95NTsatM1iTWLUwDLxM2J5zhUVYdCEz';
|
||||||
|
export const getApiKey = pThrottle({limit: 5, interval: 60000})(()=>apiKey);
|
||||||
@@ -12,6 +12,15 @@ CREATE TABLE symbols
|
|||||||
ENGINE MergeTree()
|
ENGINE MergeTree()
|
||||||
ORDER BY (symbol);
|
ORDER BY (symbol);
|
||||||
|
|
||||||
|
CREATE TABLE symbol_sync_statuses
|
||||||
|
(
|
||||||
|
symbol String,
|
||||||
|
asOfDate Date,
|
||||||
|
status ENUM('not-started','pending','done')
|
||||||
|
)
|
||||||
|
ENGINE MergeTree()
|
||||||
|
ORDER BY (asOfDate, symbol);
|
||||||
|
|
||||||
CREATE TABLE stock_aggregates
|
CREATE TABLE stock_aggregates
|
||||||
(
|
(
|
||||||
symbol LowCardinality(String),
|
symbol LowCardinality(String),
|
||||||
|
|||||||
Reference in New Issue
Block a user