<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Yahoo Finance WDC</title>
<script src="https://connectors.tableau.com/libs/tableauwdc-2.3.latest.js"></script>
<style>
body { font-family: Arial, sans-serif; margin: 1em; }
input, button { padding: 0.5em; margin: 0.5em 0; width: 100%; }
label { margin-top: 1em; display: block; }
</style>
</head>
<body>
<h2>Yahoo Finance WDC</h2>
<p>Enter a comma-separated list of tickers (e.g. ^DJI,^GSPC,^IXIC), start date and end date.</p>
<label>
Tickers:<br/>
<input id="tickers" type="text" value="^DJI,^GSPC,^IXIC"/>
</label>
<label>
Start date (YYYY-MM-DD):<br/>
<input id="start" type="date" value="2020-01-01"/>
</label>
<label>
End date (YYYY-MM-DD):<br/>
<input id="end" type="date" value="2025-07-01"/>
</label>
<button id="submitButton">Get Data</button>
<script>
(function() {
const myConnector = tableau.makeConnector();
myConnector.getSchema = function(schemaCallback) {
const cols = [
{ id: "Date", alias: "Date", dataType: tableau.dataTypeEnum.date },
{ id: "IndexName", alias: "IndexName", dataType: tableau.dataTypeEnum.string },
{ id: "Open", alias: "Open", dataType: tableau.dataTypeEnum.float },
{ id: "High", alias: "High", dataType: tableau.dataTypeEnum.float },
{ id: "Low", alias: "Low", dataType: tableau.dataTypeEnum.float },
{ id: "Close", alias: "Close", dataType: tableau.dataTypeEnum.float },
{ id: "AdjClose",alias: "AdjClose",dataType: tableau.dataTypeEnum.float },
{ id: "Volume", alias: "Volume", dataType: tableau.dataTypeEnum.int }
];
const tableSchema = {
id: "yahooIndices",
alias: "Daily index prices from Yahoo Finance",
columns: cols
};
schemaCallback([tableSchema]);
};
myConnector.getData = async function(table, doneCallback) {
const config = JSON.parse(tableau.connectionData);
const [symbols, start, end] = [config.tickers, config.start, config.end];
const tickers = symbols.split(",").map(s => s.trim());
let tableData = [];
for (let ticker of tickers) {
const s = new Date(start).getTime()/1000;
const e = new Date(end).getTime()/1000;
const url =
`https://query1.finance.yahoo.com/v7/finance/download/${encodeURIComponent(ticker)}`
+ `?period1=${s}&period2=${e}&interval=1d&events=history`;
try {
const resp = await fetch(url);
const text = await resp.text();
const lines = text.split("\n").filter(r=>r.length);
const headers = lines[0].split(",");
const idxMap = headers.reduce((m,h,i)=>{ m[h]=i; return m; }, {});
for (let i=1; i<lines.length; i++) {
const row = lines[i].split(",");
tableData.push({
Date: row[idxMap["Date"]],
IndexName: ticker,
Open: parseFloat(row[idxMap["Open"]]) || null,
High: parseFloat(row[idxMap["High"]]) || null,
Low: parseFloat(row[idxMap["Low"]]) || null,
Close: parseFloat(row[idxMap["Close"]]) || null,
AdjClose:parseFloat(row[idxMap["Adj Close"]]) || null,
Volume: parseInt(row[idxMap["Volume"]], 10) || null
});
}
} catch (err) {
console.error(`Error fetching ${ticker}:`, err);
}
}
table.appendRows(tableData);
doneCallback();
};
tableau.registerConnector(myConnector);
document.querySelector("#submitButton").addEventListener("click", () => {
const cfg = {
tickers: document.querySelector("#tickers").value,
start: document.querySelector("#start").value,
end: document.querySelector("#end").value
};
tableau.connectionData = JSON.stringify(cfg);
tableau.connectionName = "Yahoo Finance Indices";
tableau.submit();
});
})();
</script>
</body>
</html>