File Coverage

blib/lib/Finance/Quote/YahooJSON.pm
Criterion Covered Total %
statement 23 86 26.7
branch 0 12 0.0
condition 0 3 0.0
subroutine 9 10 90.0
pod 0 3 0.0
total 32 114 28.0


line stmt bran cond sub pod time code
1             #!/usr/bin/perl -w
2             # This module is based on the Finance::Quote::BSERO module
3             # It was first called BOMSE but has been renamed to yahooJSON
4             # since it gets a lot of quotes besides Indian
5             #
6             # The code has been modified by Abhijit K to
7             # retrieve stock information from Yahoo Finance through json calls
8             #
9             # This program is free software; you can redistribute it and/or modify
10             # it under the terms of the GNU General Public License as published by
11             # the Free Software Foundation; either version 2 of the License, or
12             # (at your option) any later version.
13             #
14             # This program is distributed in the hope that it will be useful,
15             # but WITHOUT ANY WARRANTY; without even the implied warranty of
16             # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17             # GNU General Public License for more details.
18             #
19             # You should have received a copy of the GNU General Public License
20             # along with this program; if not, write to the Free Software
21             # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
22             # 02110-1301, USA
23              
24             package Finance::Quote::YahooJSON;
25              
26             require 5.005;
27              
28 5     5   2813 use strict;
  5         16  
  5         182  
29 5     5   85 use JSON qw( decode_json );
  5         15  
  5         34  
30 5     5   511 use vars qw($VERSION $YIND_URL_HEAD $YIND_URL_TAIL);
  5         10  
  5         248  
31 5     5   30 use LWP::UserAgent;
  5         12  
  5         31  
32 5     5   127 use HTTP::Request::Common;
  5         26  
  5         349  
33 5     5   36 use HTML::TableExtract;
  5         10  
  5         31  
34 5     5   172 use Time::Piece;
  5         22  
  5         31  
35              
36             our $VERSION = '1.58_01'; # TRIAL VERSION
37              
38             my $YIND_URL_HEAD = 'https://query2.finance.yahoo.com/v11/finance/quoteSummary/?symbol=';
39             my $YIND_URL_TAIL = '&modules=price,summaryDetail,defaultKeyStatistics';
40              
41             sub methods {
42 5     5 0 22 return ( yahoo_json => \&yahoo_json,
43             );
44             }
45             {
46             my @labels = qw/name last date isodate volume currency method exchange type
47             div_yield eps pe year_range open high low close/;
48              
49             sub labels {
50 5     5 0 13 return ( yahoo_json => \@labels,
51             );
52             }
53             }
54              
55             sub yahoo_json {
56              
57 0     0 0   my $quoter = shift;
58 0           my @stocks = @_;
59 0           my ( %info, $reply, $url, $te, $ts, $row, @cells, $ce );
60 0           my ( $my_date, $amp_stocks );
61 0           my $ua = $quoter->user_agent();
62              
63 0           foreach my $stocks (@stocks) {
64              
65             # Issue 202 - Fix symbols with Ampersand
66             # Can also be written as
67             # $amp_stocks = $stocks =~ s/&/%26/gr;
68 0           ($amp_stocks = $stocks) =~ s/&/%26/g;
69              
70 0           $url = $YIND_URL_HEAD . $amp_stocks . $YIND_URL_TAIL;
71 0           $reply = $ua->request( GET $url);
72              
73 0           my $code = $reply->code;
74 0           my $desc = HTTP::Status::status_message($code);
75 0           my $headers = $reply->headers_as_string;
76 0           my $body = $reply->content;
77              
78             #Response variables available:
79             #Response code: $code
80             #Response description: $desc
81             #HTTP Headers: $headers
82             #Response body $body
83              
84 0           $info{ $stocks, "symbol" } = $stocks;
85              
86 0 0         if ( $code == 200 ) {
87              
88             #HTTP_Response succeeded - parse the data
89 0           my $json_data = JSON::decode_json $body;
90              
91             # Requests for invalid symbols sometimes return 200 with an empty
92             # JSON result array
93             my $json_data_count
94 0           = scalar @{ $json_data->{'quoteSummary'}{'result'} };
  0            
95              
96 0 0         if ( $json_data_count < 1 ) {
97 0           $info{ $stocks, "success" } = 0;
98 0           $info{ $stocks, "errormsg" } =
99             "Error retrieving quote for $stocks - no listing for this name found. Please check symbol and the two letter extension (if any)";
100              
101             }
102             else {
103              
104 0           my $json_resources_price = $json_data->{'quoteSummary'}{'result'}[0]{'price'};
105 0           my $json_resources_summaryDetail = $json_data->{'quoteSummary'}{'result'}[0]{'summaryDetail'};
106 0           my $json_resources_defaultKeyStatistics = $json_data->{'quoteSummary'}{'result'}[0]{'defaultKeyStatistics'};
107              
108             # TODO: Check if $json_response_type is "Quote"
109             # before attempting anything else
110 0           my $json_symbol = $json_resources_price->{'symbol'};
111             # || $json_resources->{'resource'}{'fields'}{'symbol'};
112 0           my $json_volume = $json_resources_price->{'regularMarketVolume'}{'raw'};
113             my $json_timestamp =
114 0           $json_resources_price->{'regularMarketTime'};
115 0           my $json_name = $json_resources_price->{'shortName'};
116 0           my $json_type = $json_resources_price->{'quoteType'};
117             my $json_price =
118 0           $json_resources_price->{'regularMarketPrice'}{'raw'};
119              
120 0           $info{ $stocks, "success" } = 1;
121             $info{ $stocks, "exchange" } =
122 0           $json_resources_price->{'exchangeName'};
123 0           $info{ $stocks, "method" } = "yahoo_json";
124 0           $info{ $stocks, "name" } = $stocks . ' (' . $json_name . ')';
125 0           $info{ $stocks, "type" } = $json_type;
126 0           $info{ $stocks, "last" } = $json_price;
127 0           $info{ $stocks, "currency"} = $json_resources_price->{'currency'};
128 0           $info{ $stocks, "volume" } = $json_volume;
129              
130             # The Yahoo JSON interface returns London prices in GBp (pence) instead of GBP (pounds)
131             # and the Yahoo Base had a hack to convert them to GBP. In theory all the callers
132             # would correctly handle GBp as not the same as GBP, but they don't, and since
133             # we had the hack before, let's add it back now.
134             #
135             # Convert GBp or GBX to GBP (divide price by 100).
136              
137 0 0 0       if ( ($info{$stocks,"currency"} eq "GBp") ||
138             ($info{$stocks,"currency"} eq "GBX")) {
139 0           $info{$stocks,"last"}=$info{$stocks,"last"}/100;
140 0           $info{ $stocks, "currency"} = "GBP";
141             }
142              
143             # Apply the same hack for Johannesburg Stock Exchange
144             # (JSE) prices as they are returned in ZAc (cents)
145             # instead of ZAR (rands). JSE symbols are suffixed
146             # with ".JO" when querying Yahoo e.g. ANG.JO
147              
148 0 0         if ($info{$stocks,"currency"} eq "ZAc") {
149 0           $info{$stocks,"last"}=$info{$stocks,"last"}/100;
150 0           $info{ $stocks, "currency"} = "ZAR";
151             }
152              
153             # Apply the same hack for Tel Aviv Stock Exchange
154             # (TASE) prices as they are returned in ILA (Agorot)
155             # instead of ILS (Shekels). TASE symbols are suffixed
156             # with ".TA" when querying Yahoo e.g. POLI.TA
157              
158 0 0         if ($info{$stocks,"currency"} eq "ILA") {
159 0           $info{$stocks,"last"}=$info{$stocks,"last"}/100;
160 0           $info{ $stocks, "currency"} = "ILS";
161             }
162              
163             # Add extra fields using names as per yahoo to make it easier
164             # to switch from yahoo to yahooJSON
165             # Code added by goodvibes
166             {
167             # turn off warnings in this block to fix bogus
168             # 'Use of uninitialized value in multiplication' warning
169             # in Strawberry perl 5.18.2 in Windows
170 0           local $^W = 0;
  0            
171             $info{ $stocks, "div_yield" } =
172 0           $json_resources_summaryDetail->{'trailingAnnualDividendYield'}{'raw'} * 100;
173             }
174             $info{ $stocks, "eps"} =
175 0           $json_resources_defaultKeyStatistics->{'trailingEps'}{'raw'};
176             # $json_resources_summaryDetail->{'epsTrailingTwelveMonths'};
177 0           $info{ $stocks, "pe"} = $json_resources_summaryDetail->{'trailingPE'}{'raw'};
178             $info{ $stocks, "year_range"} =
179             sprintf("%12s - %s",
180             $json_resources_summaryDetail->{"fiftyTwoWeekLow"}{'raw'},
181 0           $json_resources_summaryDetail->{'fiftyTwoWeekHigh'}{'raw'});
182             $info{ $stocks, "open"} =
183 0           $json_resources_price->{'regularMarketOpen'}{'raw'};
184             $info{ $stocks, "high"} =
185 0           $json_resources_price->{'regularMarketDayHigh'}{'raw'};
186             $info{ $stocks, "low"} =
187 0           $json_resources_price->{'regularMarketDayLow'}{'raw'};
188             $info{ $stocks, "close"} =
189 0           $json_resources_summaryDetail->{'regularMarketPreviousClose'}{'raw'};
190              
191             # MS Windows strftime() does not support %T so use %H:%M:%S
192             # instead.
193 0           $my_date =
194             localtime($json_timestamp)->strftime('%d.%m.%Y %H:%M:%S');
195              
196 0           $quoter->store_date( \%info, $stocks,
197             { eurodate => $my_date } );
198              
199             }
200             }
201              
202             #HTTP request fail
203             else {
204 0           $info{ $stocks, "success" } = 0;
205 0           $info{ $stocks, "errormsg" } =
206             "Error retrieving quote for $stocks. Attempt to fetch the URL $url resulted in HTTP response $code ($desc)";
207             }
208              
209             }
210              
211 0 0         return wantarray() ? %info : \%info;
212 0           return \%info;
213             }
214              
215             1;
216              
217             =head1 NAME
218              
219             Finance::Quote::YahooJSON - Obtain quotes from Yahoo Finance through JSON call
220              
221             =head1 SYNOPSIS
222              
223             use Finance::Quote;
224              
225             $q = Finance::Quote->new;
226              
227             %info = $q->fetch('yahoo_json','SBIN.NS');
228              
229             =head1 DESCRIPTION
230              
231             This module fetches information from Yahoo as JSON
232              
233             This module is loaded by default on a Finance::Quote object. It's
234             also possible to load it explicitly by placing "YahooJSON" in the argument
235             list to Finance::Quote->new().
236              
237             This module provides the "yahoo_json" fetch method.
238              
239             =head1 LABELS RETURNED
240              
241             The following labels may be returned by Finance::Quote::YahooJSON :
242             name, last, isodate, volume, currency, method, exchange, type,
243             div_yield eps pe year_range open high low close.
244              
245             =head1 SEE ALSO
246              
247             =cut