Need Help with Yahoo Finance API Web Request

Hey ..

Well .. I have a need for some help. I am interested in making a stock app .. so that I can check my stocks.

Edit .. I can get the data in the simulator, which is a start.

It is as follows ..

{query=>{results=>{quote=>{OneyrTargetPrice=>null, LowLimit=>null, HoldingsGain=>null, AverageDailyVolume=>934476, Commission=>null, ExDividendDate=>null, MarketCapitalization=>316.96B, HoldingsValueRealtime=>null, LastTradeDate=>2/10/2017, ErrorIndicationreturnedforsymbolchangedinvalid=>null, HighLimit=>null, EPSEstimateNextYear=>null, LastTradePriceOnly=>1.05, Symbol=>LAC.TO, LastTradeTime=>3:59pm, PriceSales=>486880.53, Bid=>1.04, Volume=>1823026, DaysHigh=>1.05, Notes=>null, PriceBook=>6.25, TradeDate=>null, FiftydayMovingAverage=>0.93, PercentChangeFromYearLow=>+141.38%, DaysLow=>1.00, ChangeRealtime=>null, DaysRangeRealtime=>null, PricePaid=>null, PercentChange=>+5.00%, Name=>LITHIUM AMERICAS CORP, symbol=>LAC.TO, AskRealtime=>null, DaysValueChangeRealtime=>null, PriceEPSEstimateNextYear=>null, HoldingsGainPercent=>null, YearHigh=>1.14, EPSEstimateCurrentYear=>0.00, AfterHoursChangeRealtime=>null, BookValue=>0.16, PreviousClose=>1.00, Currency=>CAD, SharesOwned=>null, ChangePercentRealtime=>null, DividendYield=>null, ChangeFromFiftydayMovingAverage=>0.12, EarningsShare=>-0.08, PEGRatio=>0.00, Ask=>1.05, MoreInfo=>null, TickerTrend=>null, PercebtChangeFromYearHigh=>-7.89%, ShortRatio=>0.00, YearLow=>0.44, YearRange=>0.44 - 1.14, Open=>1.02, Change_PercentChange=>+0.05 - +5.00%, TwoHundreddayMovingAverage=>0.86, ChangeFromYearHigh=>-0.09, PERatioRealtime=>null, PercentChangeFromFiftydayMovingAverage=>+13.16%, DaysRange=>1.00 - 1.05, EPSEstimateNextQuarter=>0.00, PriceEPSEstimateCurrentYear=>null, LastTradeWithTime=>3:59pm - <b>1.05</b>, StockExchange=>TOR, MarketCapRealtime=>null, HoldingsValue=>null, PERatio=>null, Change=>+0.05, DaysValueChange=>null, DividendShare=>null, AnnualizedGain=>null, BidRealtime=>null, LastTradeRealtimeWithTime=>null, ChangeFromTwoHundreddayMovingAverage=>0.19, HoldingsGainRealtime=>null, PercentChangeFromTwoHundreddayMovingAverage=>+22.17%, ChangeFromYearLow=>0.61, HoldingsGainPercentRealtime=>null, OrderBookRealtime=>null, EBITDA=>-10.93M, ChangeinPercent=>+5.00%, DividendPayDate=>null}}, created=>2017-02-12T20:08:06Z, count=>1, lang=>en-US}}

My web request is as follows ..

Comm.makeWebRequest("query.yahooapis.com/.../yql, null, {},method(:onWebResponse) );



But I am only interested in really .. the LastTradePrice and the OpeningPrice. I can do the needed math.

If someone would be able to let me know how to parse out the needed data from the above .. that would be nice.

Thanks
Kevin
  • The first place to look is the "WebRequest" sample in the SDK.

    When it comes to the actual request you want to make, you need to see what the site provides... How it needs the ticker symbol, etc, and how to get it to return JSON formated data. Then in the callback for the request, pull out the data you want. If it provides it, do you just want the current price, or do you also want the open and change for the day, as an example...

    While you are working on the URL for the request, you can just do it in a web browser, and the browser while show you what comes back. When you see in in a CIQ app, it will actually be a dictionary though, so your code doesn't have to deal with JSON directly.
  • I can get the data being returned fine .. I just need to know how to retrieve the data from the Dictionary.
    I have determined that it is a dictionary and it is not empty.

    My data returned is ..

    query: {results=>{quote=>[{PreviousClose=>12.06, LastTradePriceOnly=>12.40}, {PreviousClose=>1.00, LastTradePriceOnly=>1.05}, {PreviousClose=>2.56, LastTradePriceOnly=>2.54}]}, created=>2017-02-13T01:12:45Z, count=>3, lang=>en-US}

    I just need to get the 6 numbers from the dictionary.

    Kevin
  • I want to be sure to bring up two things before responding to your question...

    • Use the params parameter to makeWebRequest to encode your parameters to the request. Putting them on the URL yourself may work now, but you are likely to run into problems later. See this post for details.
    • If you aren't already doing so, you should limit the data you request to the minimum. If you don't limit the returned data to what you need, your app/widget will be very slow to respond. See this post for details.


    So, to answer your question... accessing data from json object (dictionary in this case) is done just as it is done for any other dictionary... You index into it using the key for the value you want. For the data you present, it seems you'd write something like this...

    function onWebResponse(code, data) {

    if (code != 200 || data == null) {
    return;
    }

    var query = data["query"];
    if (query == null) {
    return;
    }

    var results = query["results"];
    if (results == null) {
    return;
    }

    var quotes = results["quote"];
    if (quotes == null) {
    return;
    }

    for (var i = 0; i < quotes.size(); ++i) {
    var quote = quotes;

    Sys.println(Lang.format("$1$ PreviousClose=$2$", [ i, quote["PreviousClose"]));
    Sys.println(Lang.format("$1$ LastTradePriceOnly=$2$", [ i, quote["LastTradePriceOnly"]));
    }
    }
    [/code]

    I've often used a helper function to walk the object hierarchy to the element I want..

    // walk an object heirarchy until we find what we want
    hidden function walk(data, path) {
    for (var i = 0; i < path.size(); ++i) {
    if (data == null) {
    return null;
    }
    data = data[path];
    }
    return data;
    }

    function onWebResponse(code, data) {

    if (code != 200) {
    return;
    }

    var quotes = walk(data, ["query", "results", "quote"]);
    if (quotes == null) {
    return;
    }

    for (var i = 0; i < quotes.size(); ++i) {
    var quote = quotes;

    Sys.println(Lang.format("$1$ PreviousClose=$2$", [ i, quote["PreviousClose"]));
    Sys.println(Lang.format("$1$ LastTradePriceOnly=$2$", [ i, quote["LastTradePriceOnly"]));
    }
    }
    [/code]

    Travis
  • Thank you .. I will look at it in the next while.

    I really do appreciate the time you have taken Travis .. and the best thing is that surely someone else will need this exact thing as well.

    Edit .. ok, well I have run into some issues.

    First .. I am using the simulator, and having problems.

    I am finding that:

    Data in Walk Function before for loop .. {query=>{results=>{quote=>[{PreviousClose=>12.06, LastTradePriceOnly=>12.40} ...
    Path before for loop .. [results, quote]
    Path Size .. 2
    Data in Walk Function after for loop .. null

    This is where the problems happen ..

    Btw .. here is my call for the data, which I will do only once when the app starts.

    var url = "query.yahooapis.com/.../yql";

    var options = {
    //:method => Comm.HTTP_REQUEST_METHOD_GET,
    //:headers => headers,
    //:responseType => Comm.HTTP_RESPONSE_CONTENT_TYPE_JSON
    };


    var params =
    {
    "q" => "select LastTradePriceOnly,PreviousClose from yahoo.finance.quotes where symbol in (\"WEED.TO,LAC.TO,ACB.CN\")",
    "format" => "json",
    "env" => "store://datatables.org/alltableswithkeys"
    };


    Comm.makeWebRequest(url, params, options, method(:onWebResponse));


    The data returned ..

    {query=>{results=>{quote=>[{PreviousClose=>12.06, LastTradePriceOnly=>12.40}, {PreviousClose=>1.00, LastTradePriceOnly=>1.05}, {PreviousClose=>2.56, LastTradePriceOnly=>2.54}]}, created=>2017-02-13T06:05:14Z, count=>3, lang=>en-US}}



    Thanks
    Kevin
  • If the results are known and consistent then I would skip the "walking" and just access it directly.

    I totally didn't test this code and it's not clean per se but you should get the idea.

    function onWebResponse(code, data) {
    if (code != 200) {
    return;
    }

    // store in a global, one-dimension array (which is defined elsewhere)
    // double the size since we're store two values per quote
    $.gQuoteInfo = new [data["query"]["results"]["quote"].size()*2];

    for (var i = 0; i < data["query"]["results"]["quote"].size(); ++i) {
    $.gQuoteInfo[i*2] = (data["query"]["results"]["quote"]["PreviousClose"]).toFloat();
    $.gQuoteInfo[i*2+1] = (data["query"]["results"]["quote"]["LastTradePriceOnly"]).toFloat();
    }
    }
    [/CODE]

    Also, I noticed that pulling three quotes using that URL returns 6.8K worth of data, when all you really need is 6 float values. You may want to look at filtering the fields returned or if that's not possible then writing your own intermediate process that filters the results.

    Cheers,
    Douglas
  • ok, well I have run into some issues.


    I had typos in my code. I don't have ConnectIQ installed on my work laptop, and I'm away on a business trip this week. Try again with the updated code above.

    but you should get the idea..


    That code is rather complicated too. Like mine it has a bug.. it doesn't index into the quotes array (data["query"]["results"]["quote"][ i ])
  • Also, I noticed that pulling three quotes using that URL returns 6.8K worth of data, when all you really need is 6 float values. You may want to look at filtering the fields returned or if that's not possible then writing your own intermediate process that filters the results.

    Cheers,
    Douglas


    Another option is to make multiple calls serially (one per symbol), as that would reduce the size of a given call, as 6.8k in one response could be an issue (the max is something like 8K IIRC), and there's nothing else to change if you want to show more data.
  • I think that the amount of data specified was my fault .. as I did not post the correct URL data.

    The data I get for all 3 stocks is as follows.

    I have 3 screens .. and update the display based on the stock needed via a tap. I get the data only when the app is launched currently .. but I would like to add the ability to get the data on demand with a right button press.

    The biggest issue .. the size of the data on the screen, I need it to be a large font size as I cannot see that well close up. :(

    The data retrieved is as follows for all 3 stocks .. so just over 2 sentences in total.

    {query=>{results=>{quote=>[{PreviousClose=>12.40, LastTradePriceOnly=>13.00}, {PreviousClose=>1.05, LastTradePriceOnly=>1.12}, {PreviousClose=>2.54, LastTradePriceOnly=>2.58}]}, created=>2017-02-14T01:29:19Z, count=>3, lang=>en-US}}

    Kevin
  • Wanted to update this thread .. I have my stock app working.

    Is it a work in progress .. yes. Is it sufficiently done that it works .. yes.

    So thanks for all the assistance I have received in this thread. It is greatly appreciated.

    - Kevin -
  • In that thread, I believe there were two problems. One was that the params and options params were being passed in the wrong order. That was an issue with the code I provided and didn't test. The second was some sort of bug caused by making multiple web requests in a short period of time. I had trouble reproducing this on the device, so I don't think it was ever formally reported.

    As far as I can tell from your code, you're only making one web request, so I'm not convinced that your problems are the same. If you are making multiple requests, you might be able to space them out as the author in that thread did. Either way, you should try to make a test case and a post in the Bug Reports forum so that the Garmin guys can have a look.

    Travis