added date prompt
This commit is contained in:
parent
7d78598129
commit
08e40a87df
@ -1,5 +1,5 @@
|
||||
{
|
||||
"tasks": {
|
||||
"scrape": "deno run -A scraper.ts"
|
||||
"scraper": "deno run -A scraper.ts"
|
||||
}
|
||||
}
|
||||
|
||||
133
scraper.ts
133
scraper.ts
@ -62,10 +62,103 @@ async function fetchSP500Tickers(): Promise<string[]> {
|
||||
// ------------------------------------------------------------
|
||||
// Yahoo Finance fetch
|
||||
// ------------------------------------------------------------
|
||||
const now = Math.floor(Date.now() / 1000);
|
||||
const thirtyDaysAgo = now - 30 * 24 * 60 * 60;
|
||||
const args = `?period1=${thirtyDaysAgo}&period2=${now}&interval=1d`;
|
||||
const closingEndpoint =(ticker:string)=>`https://query1.finance.yahoo.com/v8/finance/chart/${ticker}${args}`;
|
||||
function parseDate(dateStr: string): number {
|
||||
const date = new Date(dateStr);
|
||||
if (isNaN(date.getTime())) {
|
||||
throw new Error(`Invalid date format: ${dateStr}. Use YYYY-MM-DD`);
|
||||
}
|
||||
return Math.floor(date.getTime() / 1000);
|
||||
}
|
||||
|
||||
async function getDateRange(): Promise<{ period1: number; period2: number }> {
|
||||
const args = Deno.args;
|
||||
|
||||
// If command line args provided, use them
|
||||
if (args.length === 1) {
|
||||
const days = parseInt(args[0], 10);
|
||||
if (isNaN(days) || days <= 0) {
|
||||
throw new Error(`Invalid number of days: ${args[0]}`);
|
||||
}
|
||||
const now = Math.floor(Date.now() / 1000);
|
||||
const daysAgo = now - days * 24 * 60 * 60;
|
||||
console.log(`Using last ${days} days.`);
|
||||
return { period1: daysAgo, period2: now };
|
||||
}
|
||||
|
||||
if (args.length >= 2) {
|
||||
const startDate = parseDate(args[0]);
|
||||
const endDate = parseDate(args[1]);
|
||||
|
||||
if (startDate > endDate) {
|
||||
throw new Error("Start date must be before end date");
|
||||
}
|
||||
|
||||
console.log(`Using date range from ${args[0]} to ${args[1]}.`);
|
||||
return { period1: startDate, period2: endDate };
|
||||
}
|
||||
|
||||
// Interactive mode
|
||||
console.log("\n=== Date Range Selection ===");
|
||||
console.log("1. Last 30 days (default)");
|
||||
console.log("2. Last N days (custom)");
|
||||
console.log("3. Custom date range (YYYY-MM-DD)");
|
||||
|
||||
const choice = prompt("Choose an option (1-3):", "1");
|
||||
|
||||
if (choice === "1" || choice === null) {
|
||||
// Default: last 30 days
|
||||
const now = Math.floor(Date.now() / 1000);
|
||||
const thirtyDaysAgo = now - 30 * 24 * 60 * 60;
|
||||
console.log("Using last 30 days.");
|
||||
return { period1: thirtyDaysAgo, period2: now };
|
||||
}
|
||||
|
||||
if (choice === "2") {
|
||||
const daysStr = prompt("Enter number of days:", "30");
|
||||
if (!daysStr) {
|
||||
throw new Error("No days specified");
|
||||
}
|
||||
const days = parseInt(daysStr, 10);
|
||||
if (isNaN(days) || days <= 0) {
|
||||
throw new Error(`Invalid number of days: ${daysStr}`);
|
||||
}
|
||||
const now = Math.floor(Date.now() / 1000);
|
||||
const daysAgo = now - days * 24 * 60 * 60;
|
||||
console.log(`Using last ${days} days.`);
|
||||
return { period1: daysAgo, period2: now };
|
||||
}
|
||||
|
||||
if (choice === "3") {
|
||||
const dateRangeStr = prompt("Enter date range (YYYY-MM-DD YYYY-MM-DD):", "2025-12-18 2026-01-17");
|
||||
if (!dateRangeStr) {
|
||||
throw new Error("No date range specified");
|
||||
}
|
||||
|
||||
const dates = dateRangeStr.trim().split(/\s+/);
|
||||
if (dates.length !== 2) {
|
||||
throw new Error("Please provide two dates in format: YYYY-MM-DD YYYY-MM-DD");
|
||||
}
|
||||
|
||||
const startStr = dates[0];
|
||||
const endStr = dates[1];
|
||||
|
||||
const startDate = parseDate(startStr);
|
||||
const endDate = parseDate(endStr);
|
||||
|
||||
if (startDate > endDate) {
|
||||
throw new Error("Start date must be before end date");
|
||||
}
|
||||
|
||||
console.log(`Using date range from ${startStr} to ${endStr}.`);
|
||||
return { period1: startDate, period2: endDate };
|
||||
}
|
||||
|
||||
throw new Error("Invalid option selected");
|
||||
}
|
||||
|
||||
let dateRange: { period1: number; period2: number };
|
||||
let args: string;
|
||||
let closingEndpoint: (ticker: string) => string;
|
||||
|
||||
async function fetchLast30Closes(ticker: string): Promise<number[]> {
|
||||
|
||||
@ -122,6 +215,7 @@ async function throttle<T>(
|
||||
|
||||
function buildHtmlTable(
|
||||
results: { ticker: string; model: ReturnType<typeof linearRegression> }[],
|
||||
dateRangeLabel: string,
|
||||
): string {
|
||||
const rows = results.map(({ ticker, model }) => {
|
||||
const link = `<a href="https://www.tradingview.com/symbols/NASDAQ-${ticker}/?timeframe=6M" target="_blank">${ticker}</a>`;
|
||||
@ -153,6 +247,7 @@ function buildHtmlTable(
|
||||
</head>
|
||||
<body>
|
||||
<h1>S&P 500 Regression Results</h1>
|
||||
<p><em>Date Range: ${dateRangeLabel}</em></p>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
@ -160,7 +255,7 @@ function buildHtmlTable(
|
||||
<th class="extra">Slope</th>
|
||||
<th class="extra">Intercept</th>
|
||||
<th class="extra">R²</th>
|
||||
<th>Growth (30d)</th>
|
||||
<th>Growth</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@ -177,7 +272,31 @@ function buildHtmlTable(
|
||||
// ------------------------------------------------------------
|
||||
// Main Dump
|
||||
// ------------------------------------------------------------
|
||||
function getDateRangeLabel(): string {
|
||||
const args = Deno.args;
|
||||
|
||||
if (args.length === 0) {
|
||||
return "Last 30 days";
|
||||
}
|
||||
|
||||
if (args.length === 1) {
|
||||
const days = parseInt(args[0], 10);
|
||||
return `Last ${days} days`;
|
||||
}
|
||||
|
||||
if (args.length >= 2) {
|
||||
return `${args[0]} to ${args[1]}`;
|
||||
}
|
||||
|
||||
return "Unknown range";
|
||||
}
|
||||
|
||||
async function Dump() {
|
||||
// Initialize date range interactively
|
||||
dateRange = await getDateRange();
|
||||
args = `?period1=${dateRange.period1}&period2=${dateRange.period2}&interval=1d`;
|
||||
closingEndpoint = (ticker: string) => `https://query1.finance.yahoo.com/v8/finance/chart/${ticker}${args}`;
|
||||
|
||||
const spx = await ComputeTicker("^GSPC");
|
||||
if (!spx) {
|
||||
console.error("Could not get S&P Index data");
|
||||
@ -215,11 +334,11 @@ async function Dump() {
|
||||
results.sort((a, b) => b.model.growth - a.model.growth);
|
||||
|
||||
// Build HTML
|
||||
const html = buildHtmlTable(results);
|
||||
const dateRangeLabel = getDateRangeLabel();
|
||||
const html = buildHtmlTable(results, dateRangeLabel);
|
||||
|
||||
await Deno.writeTextFile("sp500_regression.html", html);
|
||||
console.log("Dumped output to sp500_regression.html");
|
||||
}
|
||||
|
||||
Dump();
|
||||
//console.log(closingEndpoint("^GSPC"))
|
||||
|
||||
Loading…
Reference in New Issue
Block a user