feat: Financial Times tracking
Build and publish / build (push) Successful in 44s

This commit is contained in:
Lino Silva
2026-05-13 00:10:00 +01:00
parent 5a851a15ae
commit 730353baa7
3 changed files with 56 additions and 0 deletions
+45
View File
@@ -18,6 +18,10 @@ const providers: Record<ProviderType, Provider> = {
baseUrl:
"https://www.deco.proteste.pt/investe/investimentos/fundos/${symbol}",
},
[ProviderType.FT]: {
type: ProviderType.FT,
baseUrl: "https://markets.ft.com/data/funds/tearsheet/summary?s=${symbol}",
},
};
interface SymbolConfig {
@@ -67,6 +71,8 @@ async function getLatestPrice(symbol: string) {
return await scrapeBPI(page, symbol, config);
case ProviderType.DECO:
return await scrapeDeco(page, symbol, config);
case ProviderType.FT:
return await scrapeFT(page, symbol, config);
default:
throw new Error(`Unsupported type: ${config.type}`);
}
@@ -155,6 +161,43 @@ async function scrapeBPI(page: Page, symbol: string, config: SymbolConfig) {
};
}
async function scrapeFT(page: Page, symbol: string, config: SymbolConfig) {
// Interact with the DOM to retrieve the price and date
const price = await page.evaluate(() => {
const spanTags = document.getElementsByTagName("span");
const priceSearchText = "Price (EUR)";
let priceElementFound;
for (let i = 0; i < spanTags.length; i++) {
if (spanTags[i].textContent.trim() == priceSearchText) {
priceElementFound = spanTags[i];
if (priceElementFound) break;
}
}
if (!priceElementFound) {
throw new Error("Could not find price element");
}
return priceElementFound?.nextSibling?.textContent;
});
const marketPrice = parseFloat(
price?.replace("€", "").trim().replace(",", ".") || "0",
);
return {
symbol,
name: config.name,
currency: "EUR",
price: marketPrice,
// date in FT is not available, so we use the current date as a placeholder
// yyyy-mm-dd format
date: new Date().toISOString().split("T")[0],
timestamp: new Date().toISOString(),
};
}
// API endpoint to get latest price for a symbol
app.get("/price/:symbol", async (req, res) => {
const { symbol } = req.params;
@@ -186,6 +229,7 @@ app.get("/", (req, res) => {
health: "/health",
"price-bpi": "/price/bpi/:symbol",
"price-deco": "/price/deco/:symbol",
"price-ft": "/price/ft/:symbol",
},
example: `/price/bpi/BPIDEST2040`,
});
@@ -194,5 +238,6 @@ app.get("/", (req, res) => {
// Start the server
app.listen(PORT, () => {
console.log(`Server running on http://localhost:${PORT}`);
console.log("Available symbols:", Object.keys(availableSymbols).join(", "));
console.log(`Example: http://localhost:${PORT}/price/bpi/BPIDEST2040`);
});