Skip to content

Instantly share code, notes, and snippets.

@raymelon
Forked from fcfort/YahooPrices.gs
Created November 10, 2024 11:45
Show Gist options
  • Save raymelon/0a5314b97b1e8ad24c51ec2e1db2ed29 to your computer and use it in GitHub Desktop.
Save raymelon/0a5314b97b1e8ad24c51ec2e1db2ed29 to your computer and use it in GitHub Desktop.

Revisions

  1. @fcfort fcfort created this gist May 10, 2016.
    176 changes: 176 additions & 0 deletions YahooPrices.gs
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,176 @@
    var _ = Underscore.load();


    /*
    * Queries Yahoo finance API for historical prices for a given list of tickers
    *
    * @param {Array} tickers A list of tickers
    * @param {Date} date Date to query for. Must be a date the markets were open
    * @return A map of ticker to adjusted close prices
    */
    function getYahooPrices(tickers, date) {
    if(tickers.length == 0) {
    return {};
    }

    Logger.log('Getting prices for %s for date %s', tickers, date)
    var yql_query = _createRangePriceQuery(tickers, getDaysAgo(date, 5), date);
    var url = 'http://query.yahooapis.com/v1/public/yql?q=' + encodeURI(yql_query) +
    '&format=json' + '&diagnostics=false' + '&env=store://datatables.org/alltableswithkeys' + '&callback=';

    var data = _getUrlData(url)

    if(!data || !data.query.results) {
    Logger.log("Unable to find prices for " + tickers + " and date " + date + ' Got JSON data ' + data);
    return {};
    }

    Utilities.sleep(1000); // avoid Yahoo errors

    var priceList = [];
    if(data.query.count == 1) {
    priceList = [data.query.results.quote];
    } else {
    priceList = data.query.results.quote;
    }

    Logger.log('Got quotes %s', priceList);

    var priceMap = {};

    for(var len = priceList.length, i = 0; i < len; i++) {
    var quote = priceList[i];
    var symbol = quote['Symbol'];
    var date = quote['Date'];
    var price = quote['Close'];
    if(symbol in priceMap) {
    if(date > priceMap[symbol]['date']) {
    priceMap[symbol]['price'] = price;
    priceMap[symbol]['date'] = date;
    }
    } else {
    priceMap[symbol] = {'price': price, 'date': date};
    }
    }

    // maintain old dict format of symbol -> price
    for(var k in priceMap) {
    priceMap[k] = priceMap[k]['price'];
    }

    return priceMap;
    }


    /**
    * http://stackoverflow.com/questions/25097779/getting-stocks-historical-data
    * @private
    */
    function _createRangePriceQuery(tickers, startDate, endDate) {
    endDate = endDate || startDate;

    var tickerStrings = [];
    for(var len = tickers.length, i = 0; i < len; i++) {
    tickerStrings.push('"' + tickers[i] + '"');
    }

    // We want actual Close since we have actual historical positions and we're not
    // back calculating a current position historically.
    var yql_query = 'select Symbol, Close, Date from yahoo.finance.historicaldata where symbol in (' +
    tickerStrings.join(',') + ') and startDate = "' + _dateToString(startDate) + '" and endDate = "' + _dateToString(endDate) + '"';
    Logger.log(yql_query);
    return yql_query;
    }



    /**
    * Returns the price of a ticker on a given date
    *
    * @param {String} ticker Stock ticker
    * @return {Number} Price
    * @customfunction
    */
    function YAHOO_PRICE(ticker) {
    return +_getCurrentYahooPrices([ticker])[ticker];
    }

    /**
    * @private
    */
    function _getCurrentYahooPrices(tickers) {
    var yql_query = _createCurrentPriceQuery(tickers);

    Utilities.sleep(1000); // avoid Yahoo errors

    var data = _getUrlData(_getYahooQueryUrl(yql_query));

    if(!data) { return {}; }

    var priceList = [];
    if(data.query.count == 1) {
    priceList = [data.query.results.quote];
    } else {
    priceList = data.query.results.quote;
    }
    Logger.log('Got quotes %s', priceList);

    var priceMap = {};

    for(var len = priceList.length, i = 0; i < len; i++) {
    var symbol = priceList[i]['Symbol'];
    var ask = priceList[i]['Ask'];
    var previousClose = priceList[i]['PreviousClose'];
    Logger.log('ask %s, previousClose %s', ask, previousClose);
    priceMap[symbol] = ask == null ? previousClose : ask;
    priceMap[symbol] = previousClose;
    }

    Logger.log('price map %s',priceMap);

    return priceMap;
    }


    /**
    * @private
    */
    function _createCurrentPriceQuery(tickers) {
    var tickerStrings = [];
    for(var len = tickers.length, i = 0; i < len; i++) {
    tickerStrings.push('"' + tickers[i] + '"');
    }
    var yql_query = 'select Symbol, Ask, PreviousClose from yahoo.finance.quotes where symbol in (' + tickerStrings.join(',') + ')';
    Logger.log(yql_query);
    return yql_query;
    }


    /**
    * @private
    */
    function _getYahooQueryUrl(yql_query) {
    var url = 'http://query.yahooapis.com/v1/public/yql?q=' + encodeURI(yql_query) +
    '&format=json' + '&diagnostics=false' + '&env=store://datatables.org/alltableswithkeys' + '&callback=';
    return url;
    }


    /**
    * @private
    */
    function _getUrlData(query_url) {
    var response = UrlFetchApp.fetch(query_url);
    var json = response.getContentText();
    return JSON.parse(json);
    }


    /**
    * @private
    */
    function _dateToString(date) {
    var mon = padDate(date.getMonth()+1);
    var day = padDate(date.getDate());
    return date.getYear() + '-' + mon + '-' + day;
    }