You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
130 lines
4.4 KiB
JavaScript
130 lines
4.4 KiB
JavaScript
//import { restClient as PolygonClient } from '@polygon.io/client-js';
|
|
import { createClient as createClickhouseClient } from '@clickhouse/client'
|
|
import { sleep, getPolygonApiKey } from './util.mjs';
|
|
|
|
//const polygonClient = PolygonClient(apiKey, "https://api.polygon.io", {pagination: false, trace: true,}); // automatically call `next_url` if there is one
|
|
|
|
const clickhouse = createClickhouseClient({username:'avraham', password:'buginoo'});
|
|
|
|
const optionContractsTableName = "option_aggregates";
|
|
async function deleteClickhouseTable(){
|
|
await clickhouse.command({
|
|
query: `DROP TABLE IF EXISTS ${optionContractsTableName}`,
|
|
})
|
|
}
|
|
async function createClickhouseTable(){
|
|
await clickhouse.command({
|
|
query: `
|
|
CREATE TABLE ${optionContractsTableName}
|
|
(
|
|
symbol LowCardinality(String),
|
|
asOfDate Date,
|
|
expirationDate Date,
|
|
optionType Enum('call', 'put'),
|
|
strike Decimal64(9)
|
|
)
|
|
ENGINE MergeTree()
|
|
ORDER BY (symbol, asOfDate, expirationDate, optionType, strike)
|
|
`,
|
|
});
|
|
/*
|
|
await clickhouse.command({
|
|
query: `
|
|
CREATE TABLE ${optionAggregatesTableName}
|
|
(
|
|
symbol LowCardinality(String),
|
|
tsStart DateTime32,
|
|
|
|
expirationDate DateTime32,
|
|
optionType Enum('call', 'put'),
|
|
strike Decimal64(9),
|
|
|
|
open Decimal64(9),
|
|
close Decimal64(9),
|
|
low Decimal64(9),
|
|
high Decimal64(9),
|
|
volume UInt64,
|
|
volume_weighted_price Decimal64(9)
|
|
)
|
|
ENGINE MergeTree()
|
|
ORDER BY (tsStart, symbol, expirationDate, optionType, strike)
|
|
`,
|
|
});
|
|
*/
|
|
}
|
|
|
|
async function insertResultsIntoClickhouse(symbol, asOfDate, optionContractsResult){
|
|
await clickhouse.insert({
|
|
table: optionContractsTableName,
|
|
// structure should match the desired format, JSONEachRow in this example
|
|
values: optionContractsResult.results.map(r=>({
|
|
symbol,
|
|
asOfDate,
|
|
expirationDate: r.expiration_date,
|
|
optionType: r.contract_type,
|
|
strike: r.strike_price
|
|
})),
|
|
format: 'JSONEachRow',
|
|
});
|
|
console.log('inserted', symbol);
|
|
}
|
|
|
|
/**
|
|
* Get all available option expirations and strikes, from the point-of-view of a given date
|
|
*/
|
|
async function fetchAvailableOptionExpirationsAndStrikesAsOfDate(symbol, asOfDate){
|
|
const limit = 1000;
|
|
let apiKey = await getPolygonApiKey();
|
|
let optionContractsResult = await (await fetch(`https://api.polygon.io/v3/reference/options/contracts?underlying_ticker=${symbol}&contract_type=call&as_of=${asOfDate}&expired=false&order=asc&limit=${limit}&sort=expiration_date&apiKey=${apiKey}`)).json();
|
|
console.log(optionContractsResult.results.length);
|
|
if(optionContractsResult.status === 'OK' && typeof optionContractsResult.results !== "undefined" && optionContractsResult.results.length > 0){
|
|
await insertResultsIntoClickhouse(symbol, asOfDate, optionContractsResult);
|
|
while(optionContractsResult.hasOwnProperty("next_url")){
|
|
apiKey = await getPolygonApiKey();
|
|
optionContractsResult = await (await fetch(`${optionContractsResult.next_url}&apiKey=${apiKey}`)).json();
|
|
if(optionContractsResult.status === 'OK' && typeof optionContractsResult.results !== "undefined" && optionContractsResult.results.length > 0){
|
|
console.log(optionContractsResult.results.length);
|
|
await insertResultsIntoClickhouse(symbol, asOfDate, optionContractsResult);
|
|
}
|
|
else{
|
|
console.log(optionContractsResult);
|
|
}
|
|
}
|
|
}
|
|
else{
|
|
console.log(optionContractsResult);
|
|
}
|
|
}
|
|
|
|
const stockAggregatesTableName = "stock_aggregates";
|
|
async function fetchMarketDates(){
|
|
return (await (await clickhouse.query({
|
|
query: `SELECT DISTINCT(Date(tsStart)) FROM ${stockAggregatesTableName}`,
|
|
format: 'JSONCompactEachRow'
|
|
})).json()).map((r)=>r[0]);
|
|
}
|
|
|
|
await deleteClickhouseTable();
|
|
await createClickhouseTable();
|
|
|
|
const marketDates = await fetchMarketDates();
|
|
for(let asOfDate of marketDates){
|
|
for(let symbol of ["AAPL", "GOOGL", "MSFT", "TSLA", "AMD", "NFLX", "SPY"]){
|
|
await fetchAvailableOptionExpirationsAndStrikesAsOfDate(symbol, asOfDate);
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* For each day (not aggregate), look-up the available option contracts (i.e.
|
|
* all unique type/strike/exp combinations). Limit is 1000, but it gives you a
|
|
* "nextUrl", so keep calling that until all results are in.
|
|
*/
|
|
|
|
/**
|
|
* For each aggregate and the contracts on that day, get option aggregates
|
|
*/
|
|
|
|
|
|
|
|
await clickhouse.close(); |