<!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>