File Coverage

blib/lib/Finance/YahooJPN/Quote.pm
Criterion Covered Total %
statement 199 261 76.2
branch 48 92 52.1
condition 26 35 74.2
subroutine 15 18 83.3
pod 5 6 83.3
total 293 412 71.1


\n\n\n\n\n\n\n
line stmt bran cond sub pod time code
1             package Finance::YahooJPN::Quote;
2              
3 1     1   39837 use 5.16.3;
  1         4  
  1         36  
4 1     1   6 use warnings;
  1         1  
  1         109  
5 1     1   1034 use utf8;
  1         16  
  1         5  
6              
7             our $VERSION = '1.08'; # 2014-07-18 (since 2001-05-30)
8              
9 1     1   53 use Carp;
  1         2  
  1         102  
10 1     1   6837 use IO::Socket;
  1         30862  
  1         5  
11 1     1   1918 use Encode;
  1         13787  
  1         116  
12 1     1   981 use Module::Load;
  1         1307  
  1         6  
13              
14             =head1 NAME
15              
16             Finance::YahooJPN::Quote -- Fetch historical Japanese stock quotes on Yahoo! Japan Finance.
17              
18             =head1 SYNOPSIS
19              
20             use Finance::YahooJPN::Quote;
21            
22             # Get the quote of Sony Corp. at the Tokyo stock exchange.
23             my @quote = Finance::YahooJPN::Quote->historical('6758.t');
24            
25             print join("\n", @quote);
26              
27             =head1 DESCRIPTION
28              
29             Historical quote data is basis for analyzing stock market. Here in Japan, standard quote data is indicated as a set of data: the four prices (open, high, low, close) and the volume of each day. This module provides its user some functions to get historical quote of a company.
30              
31             =cut
32              
33             # initialize global variables of this package
34             my $Japan_Standard_Time = time + 32400; # 9h * 60m * 60s = 32400s
35             my $Today = join '-', (
36             ( gmtime($Japan_Standard_Time) )[5] + 1900 ,
37             sprintf('%02d', ( gmtime($Japan_Standard_Time) )[4] + 1 ),
38             sprintf('%02d', ( gmtime($Japan_Standard_Time) )[3] ),
39             );
40             undef $Japan_Standard_Time;
41              
42             my $Server = 'info.finance.yahoo.co.jp';
43              
44             my $Debug = 0;
45              
46             =head1 METHODS
47              
48             =over
49              
50             =item historical($symbol [, 'start' => $start] [, 'noadjust' => 1])
51              
52             This class method automatically C and C then C a historical series of quote of the stock which specified with C<$symbol> argument.
53              
54             See the descriptions about the following methods for the argument and attributes: C<$symbol>, C and C.
55              
56             =cut
57              
58             sub debug {
59 0     0 0 0 my($class, $level, $symbol, $start, $last) = @_;
60 0 0       0 if ($level !~ m/^[1-6]$/) {
61 0         0 croak 'You must specify debug level [1-6]';
62             }
63 0         0 $Debug = $level;
64            
65 0         0 my $self = $class->new($symbol);
66 0         0 $self->scan('start' => $start, 'last' => $last);
67 0 0       0 say join("\n", $self->output('noadjust' => 1)) if $Debug == 5;
68 0 0       0 say join("\n", $self->output( )) if $Debug == 6;
69             }
70              
71             sub historical {
72 4     4 1 3577689 my($class, $symbol, %option) = @_;
73 4         28 my $self = $class->new($symbol);
74            
75 4         24 foreach my $key (keys %option) {
76 8         60 my $lowercase = $key;
77 8         22 $lowercase =~ tr/A-Z/a-z/;
78 8 50 66     54 unless ($lowercase eq 'start' or $lowercase eq 'last' or $lowercase eq 'noadjust') {
      33        
79 0         0 carp "unknown attribute name: $key (will be ignored)";
80             }
81 8         28 $option{$lowercase} = $option{$key};
82             }
83            
84 4 50       17 if ($option{'start'}) {
    0          
85 4 50       14 if ($option{'last'}) {
86 4         25 $self->scan('start' => $option{'start'}, 'last' => $option{'last'});
87             } else {
88 0         0 $self->scan('start' => $option{'start'});
89             }
90             } elsif ($option{'last'}) {
91 0         0 $self->scan('last' => $option{'last'});
92             } else {
93 0         0 $self->scan();
94             }
95            
96 4 50 33     33 if ($option{'noadjust'} and $option{'noadjust'} == 1) {
97 0         0 $self->output('noadjust' => 1);
98             } else {
99 4         32 $self->output();
100             }
101             }
102              
103             =item new($symbol)
104              
105             Constructor class method. A stock C<$symbol> should be given with 4-digit code number and optionaly followed by a letter extension (dot `.' and an alphabet). (i.e. `6758' or `6758.t')
106              
107             Japanese stock markets use 4-digit code numbers for stock symbols. In addtion to that, an alphabetical letter extention is used for indicating its exchanging place. For example, the stock symbol code of Sony Corp. is '6758' and the letter extention of the Tokyo Stock Exchange is '.t'. Hence, the stock quote of Sony Corp. at Tokyo Stock Exchange is specified as '6758.t'.
108              
109             According to the Yahoo-Japan-Finance's description L the letter extentions of exchanging place are:
110              
111             .t: Tokyo Stock Exchange
112             .q: JASDAQ
113             .n: Nagoya Stock Exchange
114             .s: Sapporo Stock Exchange
115             .f: Fukuoka Stock Exchange
116              
117             Letter extention is omittable. When it is omit, the default exchange market is chosen by the Yahoo-Japan-Finance's server. It is not certain but I guess that the default one should be the main exchange market of the stock. Note: since almost symbols should work without letter extention, I have experienced certain problems with a few symbols those which have originally `.j' letter extention. This is of course not for the module but owe to the Yahoo-Japan-Finance server's behavior.
118              
119             There is an exception for above. A few symbols of index are indicated in 5 to 7 digit code numbers. They are '998405' (TOPIX), '998407' (NIKKEI) and '23337' (JASDAQ). L
120              
121             =cut
122              
123             sub new {
124 8     8 1 3929855 my($class, $symbol) = @_;
125 8         27 my $self = {};
126 8         27 bless $self, $class;
127            
128 8 50       48 unless ($symbol) {
129 0         0 croak "'symbol' argument can't be omittable";
130             }
131 8 50 100     160 if (
      100        
      66        
132             $symbol eq '998405'
133             or $symbol eq '998407'
134             or $symbol eq '23337'
135             or $symbol =~ /^\d{4}(\.[a-zA-Z]){0,1}$/
136             ) {
137 8         40 $self->{'symbol'} = $symbol;
138             }
139             else {
140 0         0 croak "Stock symbol must be given in a 4-digit number and optionally which can be\nfollowed by a letter extension (a dot `.' and an alphabet).\n\tFor example: `6758' or `6758.t'\nExcept for these special index codes: 998405, 998407 and 23337.\n\n"; }
141            
142 8         20 return $self;
143             }
144              
145             my $MAX_RETRY = 10;
146              
147             # _fetch($url)
148             # This private method is for fetching a web page.
149             sub _fetch {
150 563     563   1188 my($self, $abs_path) = @_;
151            
152 563         797 my @html;
153 563         3540 for (my $i = 0; $i < $MAX_RETRY; $i++) {
154 563         1124 my $sock;
155 563 50       28204 unless ($sock = IO::Socket::INET->new(
156             PeerAddr => $Server,
157             PeerPort => 'http(80)',
158             Proto => 'tcp',
159             Timeout => 10,
160             )) {
161             # retry upto $MAX_RETRY times
162 0 0       0 if ($i < $MAX_RETRY - 1) {
163 0         0 sleep 20;
164 0         0 next;
165             } else {
166 0         0 die "Network connection error to $Server; reached max retry: $MAX_RETRY";
167             }
168             }
169            
170 563         158684088 print $sock <<"EOF";
171             GET $abs_path HTTP/1.1
172             Host: $Server
173             Connection: close
174              
175             EOF
176            
177 563         550508864 @html = <$sock>;
178 563         251183 close $sock;
179            
180 563 50       11071 if ($html[0] =~ /^HTTP\/1\.1 200 OK/) {
181 563         12328 last;
182             } else {
183             # retry upto $MAX_RETRY times
184 0 0       0 if ($i < $MAX_RETRY - 1) {
185 0         0 sleep 10;
186 0         0 next;
187             } else {
188 0         0 die "Network communication error with $Server; reached max retry: $MAX_RETRY";
189             }
190             }
191             }
192            
193 563         101472 my $html = join '', @html;
194             # newline character unification
195 563         777981 $html =~ s/\x0D\x0A|\x0D|\x0A/\n/g;
196            
197 563         85728 return $html;
198             }
199              
200             =item set_proxy($proxy [, 'socks_version' => $version]) *EXPERIMENTAL*
201              
202             Set proxy. C<$proxy> must be given in format like '192.168.0.1:8080' (port is needed).
203              
204             If the proxy server is other than SOCKS5 (inevitably it is SOCKS4), you must give c<$socks_version> (i.e. 'socks_version' => 4).
205              
206             Unfortunately, I can offer very limited support for this feature since I don't have proper testing environment for proxy. So this feature is just experimental and I have no plan for upgrading it to non-experimental state in the future. And also, the install package's test suite is only for non-proxy.
207              
208             =cut
209              
210             sub set_proxy {
211 0     0 1 0 my $self = shift;
212 0         0 $self->{'proxy'} = shift;
213 0         0 my %option = @_;
214            
215 0   0     0 $self->{'socks_version'} = $option{'version'} || 5;
216            
217 0         0 return $self;
218             }
219              
220             # _fetch_proxy($url)
221             # Another method for fetching a web page with proxy.
222             sub _fetch_proxy {
223 0     0   0 load 'IO::Socket::Socks';
224 0         0 my($self, $abs_path) = @_;
225            
226 0         0 my($proxy_addr, $proxy_port) = split ':', $self->{'proxy'};
227            
228 0         0 my @html;
229 0         0 for (my $i = 0; $i < $MAX_RETRY; $i++) {
230 0 0       0 my $socks = IO::Socket::Socks->new(
231             ConnectAddr => $Server,
232             ConnectPort => 80,
233             Proto => 'tcp',
234             ProxyAddr => $proxy_addr,
235             ProxyPort => $proxy_port,
236             SocksVersion => $self->{'socks_version'}, # default 5
237             # SocksDebug => 1,
238             # Timeout => 10,
239             ) or die "Couldn't connect to $Server via " . $self->{'proxy'};
240            
241 0         0 print $socks <<"EOF";
242             GET $abs_path HTTP/1.1
243             Host: $Server
244             Connection: close
245              
246             EOF
247            
248 0         0 @html = <$socks>;
249 0         0 close $socks;
250            
251 0 0       0 if ($html[0] =~ /^HTTP\/1\.1 200 OK/) {
252 0         0 last;
253             } else {
254             # retry upto $MAX_RETRY times
255 0 0       0 if ($i >= $MAX_RETRY - 2) {
256 0         0 die 'Network connection error: reached $MAX_RETRY';
257             }
258             }
259             }
260            
261 0         0 my $html = join '', @html;
262             # newline character unification
263 0         0 $html =~ s/\x0D\x0A|\x0D|\x0A/\n/g;
264            
265 0         0 return $html;
266             }
267              
268             =item scan(['start' => $start])
269              
270             This object method is for scanning the stock's historical quote pages of Yahoo-Japan-Finance from the C<$start> date to the current date. And for picking up quote data of each day on those pages.
271              
272             Date of C<$start> must be given in the format `YYYY-MM-DD' (ex. `2003-08-14'). Be careful, don't forget to quote the word, because bare word 2000-01-01 will be comprehend by Perl as '2000 - 1 - 1 = 1998'. This attribute is omittable. The default value of C<$start> is '1990-01-01'.
273              
274             You cannot specify a date of last day. Because, to find the splits you must scan the quote during whole of the period from the C<$start> day. Without split data, estimation of value adjustment for split cannot be done exactly.
275              
276             Note that datetime of this module is based on JST (Japan Standard Time: GMT +09:00).
277              
278             =cut
279              
280             sub scan {
281 8     8 1 43007 my($self, %term) = @_;
282            
283 8         35 $self->{'start'} = '1983-01-01';
284 8         26 $self->{'last' } = $Today;
285            
286 8         39 foreach my $key (keys %term) {
287 16         28 my $lowercase = $key;
288 16         170 $lowercase =~ tr/A-Z/a-z/;
289 16 50 66     84 unless ($lowercase eq 'start' or $lowercase eq 'last') {
290 0         0 carp "unknown attribute name: $key (will be ignored)";
291             }
292 16 50       112 unless ($term{$key} =~ /^\d{4}-\d{2}-\d{2}$/) {
293 0         0 croak "A date should be given in the format `YYYY-MM-DD'. (ex. `2003-08-14')";
294             }
295 16         56 $self->{$lowercase} = $term{$key};
296             }
297            
298             # estimate term to fetch
299 8         56 my($yearStart, $monthStart, $dayStart) = split /-/, $self->{'start'};
300 8         37 my($yearEnd, $monthEnd, $dayEnd) = split /-/, $self->{'last' };
301            
302             # multi page fetching
303 8         11 while (1) {
304             # 50rows/1page is max at Yahoo-Japan-Finance
305             # So the poor Yahoo-Japan-Finance's paging algorithm has a certain serious bug that I can't utilize paging method.
306            
307 563         1649 my $abs_path;
308 563 100 100     2442 if ($yearEnd == $yearStart && $monthEnd == $monthStart) {
309 8         63 $abs_path = "/history/?code=$self->{'symbol'}&sy=$yearEnd&sm=$monthEnd&sd=$dayStart&ey=$yearEnd&em=$monthEnd&ed=$dayEnd&tm=d";
310             } else {
311 555         6605 $abs_path = "/history/?code=$self->{'symbol'}&sy=$yearEnd&sm=$monthEnd&sd=01&ey=$yearEnd&em=$monthEnd&ed=$dayEnd&tm=d";
312             }
313 563         1785 my $remotedoc;
314 563 50       2149 if ($self->{'proxy'}) {
315 0         0 $remotedoc = decode('utf-8', $self->_fetch_proxy($abs_path));
316             } else {
317 563         5368 $remotedoc = decode('utf-8', $self->_fetch($abs_path));
318             }
319            
320             # testing whether it is valid symbol or not.
321 563 100       1275588 if ($remotedoc =~ m/該当する銘柄はありません。/) {
322 1 50       8 say '該当する銘柄はありません。' if $Debug == 1;
323 1         5 last;
324             }
325             # testing whether it is valid term or not.
326 562 50       21196 if ($remotedoc =~ m/該当する期間のデータはありません。/) {
327 0 0       0 say '該当する期間のデータはありません。' if $Debug == 1;
328 0         0 last;
329             }
330             # testing whether it is the overrun page (with bulk quote table) or not (currently it is no use withou paging method)
331             #if ($remotedoc =~ m|日付始値高値安値終値出来高調整後終値\*
|) { 332             # say 'page was overun' if $Debug == 1; 333             # last; 334             #} 335             336 562 50       2609 if ($Debug == 1) { 337             # debug level 1 (it should output a raw html) 338 0         0 utf8::encode($remotedoc); 339 0         0 say $remotedoc; 340             } else { 341 562 100 100     22420 if ($self->{'symbol'} eq '998405'       100         342             or $self->{'symbol'} eq '998407' 343             or $self->{'symbol'} eq '23337' 344             ) { 345             # for index 346 120         1304 $self->_collect_for_index($remotedoc); 347             } else { 348             # for stock 349 442         4356 $self->_collect($remotedoc); 350             } 351             } 352             353 562 100 100     5106 if ($yearEnd == $yearStart && $monthEnd == $monthStart) { 354 7 50       32 say 'reached to the last date' if $Debug == 1; 355 7         22 last; 356             } 357             358 555 100       2141 if ($dayEnd != 31) { 359 6         10 $dayEnd = 31; 360             } 361             362 555 100       2085 if ($monthEnd == 1) { 363 45         279 $yearEnd--; 364 45         181 $monthEnd = 12; 365             } else { 366 510         1627 $monthEnd--; 367             } 368             } 369             370 8         67 return $self; 371             } 372               373             # _collect($html) 374             # This private object method is for collecting historical quote of stock 375             # on the C<$html> which was fetched from Yahoo-Japan-Finance. 376             sub _collect { 377 442     442   1536 my($self, $html) = @_; 378             379             # split the page to some lines 380 442         528721 my @html = split /\n/, $html; 381             382             # find the target line which includes the quote rows. 383 442         20996 my $quoteLine; 384 442         4330 while (@html) { 385 109616         236251 my $line = shift @html; 386 109616 100       548901 if ($line =~ m|^調整後終値\*$|) { 387 442         1190 $quoteLine = shift @html; 388 442         19695 $quoteLine =~ s/^<\/tr>//; 389 442         10054 $quoteLine =~ s/<\/table>$//; 390 442         1823 last; 391             } 392             } 393             394             # debug level 2 (it should output a line of html which has cropped ) 395 442 50       3548 if ($Debug == 2) { 396 0         0 say encode('utf8', $quoteLine); 397 0         0 exit; 398             } 399             400             # split to every quote rows 401 442         17010 $quoteLine =~ s/^//; 402 442         11645 $quoteLine =~ s/<\/tr>$//; 403 442         89527 my @row = split /<\/tr>/, $quoteLine; 404             405             # debug level 3 (it should output multi-line of quote rows) 406 442 50       2685 if ($Debug == 3) { 407 0         0 say encode('utf8', join("\n", @row)); 408 0         0 exit; 409             } 410             411 442         4076 foreach my $row (@row) { 412 8846 100       38318 if ($row =~ m/class="through"/) { 413             # this is a split data 414 7         56 $row =~ m/(\d{4})年(\d{1,2})月(\d{1,2})日<\/td>/; 415 7         64 my $date = join '-', $1, sprintf('%02d', $2), sprintf('%02d', $3); 416 7         47 $row =~ m/分割: (.+?)株 -> (.+?)株/; 417 7         23 my($split_pre, $split_post) = ($1, $2); 418             419             # store this split datum (a hash) as an object member 420 7         11 push @{ $self->{'splits'} }, {'date' => $date, 'pre' => $split_pre, 'post' => $split_post};   7         76   421 7 50       69 say join("\t", $date, $split_pre, $split_post) if $Debug == 4; 422             423 7         15 next; 424             } 425             426             # split to every columns 427             # (the ajusted closing price is discarded) 428 8839         47329 $row =~ s/^//; 429 8839         68358 $row =~ s/<\/td>$//; 430 8839         91436 my($date, $open, $high, $low, $close, $volume, undef) = split /<\/td>/, $row; 431               432             # date reformatting 433 8839         162218 $date =~ m/(\d{4})年(\d{1,2})月(\d{1,2})日/; 434 8839         74495 $date = join '-', $1, sprintf('%02d', $2), sprintf('%02d', $3); 435               436             # remove comma signs from each number 437 8839         21377 foreach my $num ($open, $high, $low, $close, $volume) { 438 44195         123032 $num =~ tr/,//d; 439             } 440             441             # store the quote data in a field object 442 8839         13644 unshift @{ $self->{'q_noadjust'} }, join("\t", $date, $open, $high, $low, $close, $volume);   8839         85488   443             444 8839 50       59940 if ($Debug == 4) { 445 0         0 say join("\t", $date, $open, $high, $low, $close, $volume); 446             } 447             } 448             449 442         3823 $self->_adjustment(); 450             451 442         116613 return $self; 452             } 453               454             # _collect_for_index($html) 455             # a customized version of _collect($html) 456             sub _collect_for_index { 457 120     120   353 my($self, $html) = @_; 458             459             # split the page to some lines 460 120         144151 my @html = split /\n/, $html; 461             462             # find the target line which includes the quote rows. 463 120         3206 my $quoteLine; 464 120         792 while (@html) { 465 27720         60288 my $line = shift @html; 466 27720 100       143776 if ($line =~ m|^終値$|) { 467 120         409 $quoteLine = shift @html; 468 120         5750 $quoteLine =~ s/^<\/tr>//; 469 120         36479 $quoteLine =~ s/<\/table>$//; 470 120         390 last; 471             } 472             } 473             474             # debug level 2 (it should output a line of html which has cropped ) 475 120 50       481 if ($Debug == 2) { 476 0         0 say encode('utf8', $quoteLine); 477 0         0 exit; 478             } 479             480             # split to every quote rows 481 120         2612 $quoteLine =~ s/^//; 482 120         2098 $quoteLine =~ s/<\/tr>$//; 483 120         7205 my @row = split /<\/tr>/, $quoteLine; 484             485             # debug level 3 (it should output multi-line of quote rows) 486 120 50       536 if ($Debug == 3) { 487 0         0 say encode('utf8', join("\n", @row)); 488 0         0 exit; 489             } 490             491 120         497 foreach my $row (@row) { 492             # an index has no concept of splitting 493             494             # split to every columns (index has no volume data) 495 2433         16282 $row =~ s/^//; 496 2433         15456 $row =~ s/<\/td>$//; 497 2433         25205 my($date, $open, $high, $low, $close) = split /<\/td>/, $row; 498               499             # date reformatting 500 2433         16461 $date =~ m/(\d{4})年(\d{1,2})月(\d{1,2})日/; 501 2433         21481 $date = join '-', $1, sprintf('%02d', $2), sprintf('%02d', $3); 502               503             # remove comma signs from each number and normalize floating point format 504 2433         6865 foreach my $num ($open, $high, $low, $close) { 505 9732         19447 $num =~ tr/,//d; 506 9732         71004 $num = sprintf('%.2f', $num); 507             } 508             509             # store the quote data in a field object 510 2433         3611 unshift @{ $self->{'q_noadjust'} }, join("\t", $date, $open, $high, $low, $close);   2433         14819   511             512 2433 50       11416 if ($Debug == 4) { 513 0         0 say join("\t", $date, $open, $high, $low, $close); 514             } 515             } 516             517             # Since an index has no concept of adjustment, the adjusted equals to the non-adjusted. 518 120         277 @{ $self->{'q_adjust'} } = @{ $self->{'q_noadjust'} };   120         25962     120         489   519             520 120         10940 return $self; 521             } 522               523             # _adjustment() 524             # This private object method is for calculating the stock's historical quote 525             # data which is adjusted for splits. 526             sub _adjustment { 527 442     442   902 my $self = shift; 528             529 442         756 @{ $self->{'q_adjust'} } = @{ $self->{'q_noadjust'} };   442         401852     442         14247   530 442         56428 my $last = $#{ $self->{'q_adjust'} };   442         2145   531             532             # calculate cumulative values of each split ratio. 533             # * splits are stored in descending order. 534 442         1919 my($cumulativePre, $cumulativePost) = (1, 1); 535 442         2779 for (my $i = 0; $i <= $#{ $self->{'splits'} }; $i++) {   944         4215   536             # calculate cumulative values from the current split values. 537 502         2585 $cumulativePre *= $self->{'splits'}->[$i]->{'pre'}; 538 502         2127 $cumulativePost *= $self->{'splits'}->[$i]->{'post'}; 539             # calculate ratios from the cumulative values and store them as members of the object 540 502         2849 $self->{'splits'}->[$i]->{'ratio_price'} = $cumulativePre / $cumulativePost; 541 502         1408 $self->{'splits'}->[$i]->{'ratio_volume'} = $cumulativePost / $cumulativePre; 542             } 543             544             # In order to process splits in ascending order, reverse order for-loop is used. 545 442         1775 my $start = 0; 546 442         1334 for (my $i = $#{ $self->{'splits'} }; $i >= 0; $i--) {   442         2003   547 502         6480 my($split_date, $ratio_price, $ratio_volume) = ($self->{'splits'}->[$i]->{'date'}, $self->{'splits'}->[$i]->{'ratio_price'}, $self->{'splits'}->[$i]->{'ratio_volume'}); 548             549 502         1106 for (my $j = $start; $j <= $#{ $self->{'q_adjust'} }; $j++) {   365002         1653193   550 365002         2914607 my($date, $open, $high, $low, $close, $volume) = split /\t/, $self->{'q_adjust'}->[$j]; 551             552 365002 100       1579616 if ($date eq $split_date) { 553             # this is start period of the next split; quit this loop and go next loop. 554 502         3471 $start = $j; 555 502         4753 last; 556             } 557             558 364500         797996 foreach my $price ($open, $high, $low, $close) { 559             # The value 0.50000000000008 was derived from Math::Round::half 560 1458000         3844468 $price = int($price * $ratio_price + 0.50000000000008); 561             } 562 364500         984655 $volume = int($volume * $ratio_volume + 0.50000000000008); 563             564 364500         3792223 $self->{'q_adjust'}->[$j] = "$date\t$open\t$high\t$low\t$close\t$volume"; 565             } 566             } 567             568 442         3028 return 1; 569             } 570               571             =item output(['noadjust' => 1]) 572               573             This object method is for returning the collected quote data in a list. 574               575             By C option you can turn on/off the function of value adjustment for splits. If you omit this option or set this value '0', adjustment function is effective (by default). If you set this value other than '0', adjustment function is ineffective. 576               577             Output data is formatted in TSV (Tab Separated Values). Each row represents quote of each day in the order with 1)date, 2)open, 3)high, 4)low, 5)close and 6)volume. 578               579             =back 580               581             =cut 582               583             sub output { 584 8     8 1 65 my($self, %noadjust) = @_; 585             586             # in case the symbol is invalid (no data exists) 587 8 100       42 unless (exists $self->{'q_noadjust'}) { 588 1         6 return; 589             } 590 7 100       26 if (%noadjust) { 591 1         4 foreach my $key (keys %noadjust) { 592 1         2 my $lowercase = $key; 593 1         4 $lowercase =~ tr/A-Z/a-z/; 594 1 50       5 unless ($lowercase eq 'noadjust') { 595 0         0 carp "unknown attribute name: $key (will be ignored)"; 596             } 597 1 50       5 if ($noadjust{$key} != 0) { 598 1         2 return @{ $self->{'q_noadjust'} };   1         719   599             } 600             } 601             } 602             603 6         17 return @{ $self->{'q_adjust'} };   6         4363   604             } 605               606             1; 607             __END__