Public
Edited
Mar 15
Insert cell
Insert cell
FinalChart = GoogleFinanceChart(processedStocks, {x: "Date", y: "Close", color: "#34A853" })
Insert cell
finnhub_apiKey = 'cunfbvhr01qqo191k230cunfbvhr01qqo191k23g';
Insert cell
newsdata_apikey = "pub_74726ce435dd3216e6e6c1c13084d5f6ae9b5"
Insert cell
newsapi_apiKey = '48e5bbb183604b0fa043f21d0f719144';
Insert cell
apiKey = "1LBNCLLNS0F929NO";
Insert cell
today = new Date();
Insert cell
formattedDate = formatDate(currentDate);

Insert cell
//formatDate = d3.timeFormat("%Y-%m-%d"); // Format as YYYY-MM-DD

Insert cell
endDate = new Date("2025-02-22");

Insert cell
currentDate = new Date();

Insert cell
startDate = new Date(today.getFullYear(), today.getMonth() - 2, today.getDate());

Insert cell
function formatDate(date) {
return date.toISOString().split("T")[0];
}
Insert cell
function dateFormatter(date) {
return date.toISOString().split("T")[0];
}

Insert cell
symbol = "aapl";

Insert cell
async function fetchNews(type, symbol, months, finnhub_apiKey) {
const today = new Date();
const monthsAgo = new Date();
monthsAgo.setMonth(today.getMonth() - months);

const newsData = [];
let currentStartDate = new Date(monthsAgo);

if (type === 'generalxx') {
//const response = await fetch(`https://finnhub.io/api/v1/news?category=general&token=${finnhub_apiKey}`);
const response = await fetch(`https://newsapi.org/v2/top-headlines?country=us&apiKey=${newsapi_apiKey}`);
const data = await response.json();
newsData.push(...data); // Merge results
} else {
while (currentStartDate <= today) {
const currentEndDate = new Date(currentStartDate);
currentEndDate.setDate(currentEndDate.getDate() + 14); // Fetch 15 days at a time

// Ensure we don't exceed today's date
if (currentEndDate > today) {
currentEndDate.setDate(today.getDate());
}
const from = dateFormatter(currentStartDate);
const to = dateFormatter(currentEndDate);
try {
let response = null; // Use let instead of const
if (type === 'stock') {
response = await fetch(`https://finnhub.io/api/v1/company-news?symbol=${symbol}&from=${from}&to=${to}&token=${finnhub_apiKey}`);
} else {
//response = await fetch(`https://finnhub.io/api/v1/news?category=general&from=${from}&to=${to}&token=${finnhub_apiKey}`);
response = await fetch(`https://newsapi.org/v2/top-headlines?country=us&apiKey=${newsapi_apiKey}`);
}
const data = await response.json();
newsData.push(...data); // Merge results
} catch (error) {
console.error(`Error fetching news from ${from} to ${to}:`, error);
}

// Move to the next 15-day period
currentStartDate.setDate(currentStartDate.getDate() + 15);
}
}
return newsData;
}

Insert cell
newsSixMonths = fetchNews("stock", "AAPL", 2, finnhub_apiKey)
.catch(error => console.error("Error fetching 6 months of news:", error));
Insert cell
newsGeneral = fetchNews("", "", 2, newsapi_apiKey)
.catch(error => console.error("Error fetching 6 months of news:", error));
Insert cell
news = await fetch(`https://finnhub.io/api/v1/company-news?symbol=${symbol}&from=${formatDate(startDate)}&to=${formattedDate}&token=${finnhub_apiKey}`).then(response => response.json())
.catch(error => console.error("Fetch error:", error));


Insert cell
news2 = await fetch(`https://newsapi.org/v2/top-headlines?country=us&apiKey=${newsapi_apiKey}`).then(response => response.json())
.catch(error => console.error("Fetch error:", error));

Insert cell
newsMap = new Map(newsSixMonths.map(item => [item.datetime, item.headline]));
Insert cell
generalNewsMap = new Map(newsGeneral.map(item => [item.datetime, item.headline]));
Insert cell
console.log(generalNewsMap);
Insert cell
newsByDate = new Map(
[...newsMap.entries()].map(([timestamp, headline]) => {
const formattedDate = new Date(timestamp * 1000).toISOString().split("T")[0]; // Convert to YYYY-MM-DD
return [formattedDate, headline];
})
);
Insert cell
generalNewsByDate = new Map(
[...generalNewsMap.entries()].map(([timestamp, headline]) => {
const formattedDate = new Date(timestamp * 1000).toISOString().split("T")[0]; // Convert to YYYY-MM-DD
return [formattedDate, headline];
})
);
Insert cell
new Map([...newsByDate].filter(([key, value]) => value.includes("Apple Stock: What to Expect Before Fiscal Q4 Result")));
Insert cell
Insert cell
// Fetch stock data
stocks = await d3.json(`https://www.alphavantage.co/query?function=TIME_SERIES_DAILY&symbol=${symbol}&apikey=${apiKey}&outputsize=full`)

Insert cell
processedStocks = Object.entries(stocks["Time Series (Daily)"])
.map(([date, values]) => {
const parsedDate = new Date(date);
const formattedDate = parsedDate.toISOString().split("T")[0]; // Convert to YYYY-MM-DD
return {
Date: parsedDate, // Original Date object
FormattedDate: formattedDate, // Formatted date for matching
Close: +values["4. close"],
Headline: newsByDate.get(formattedDate) || null, // Match directly with newsByDate
GeneralHeadline: generalNewsByDate.get(formattedDate) || null // Match directly with newsByDate
};
})
.filter(d => d.Date >= startDate && d.Date <= currentDate);
Insert cell
Insert cell
svg
Insert cell
import {note, details} from "@observablehq/notes"
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more