File Coverage

blib/lib/Finance/TW/TSEQuote.pm
Criterion Covered Total %
statement 42 112 37.5
branch 3 32 9.3
condition 1 9 11.1
subroutine 12 14 85.7
pod 4 4 100.0
total 62 171 36.2


(.+)/) {
line stmt bran cond sub pod time code
1             package Finance::TW::TSEQuote;
2 1     1   28366 use 5.10.1;
  1         4  
  1         63  
3 1     1   5 use strict;
  1         2  
  1         53  
4             our $VERSION = '0.28';
5              
6 1     1   957 use LWP::Simple ();
  1         88297  
  1         31  
7 1     1   9 use Encode 'from_to';
  1         2  
  1         87  
8 1     1   6 use URI::Escape;
  1         2  
  1         61  
9 1     1   972 use App::Cache;
  1         109892  
  1         14  
10 1     1   52 use Digest::MD5 qw(md5_hex);
  1         3  
  1         221  
11              
12             sub resolve {
13 1     1 1 3 my $self = shift;
14 1 50       4 $self = bless {}, __PACKAGE__ unless ref($self) eq __PACKAGE__;
15 1         3 my $name = shift;
16 1   33     17 $self->{cache} ||= App::Cache->new({ ttl => 7 * 24 * 60 * 60 }); # a week
17 1         393 my $cache = $self->{cache};
18 1         8 my $key = md5_hex($name);
19              
20 1 50       5 unless ($cache->get($key)) {
21 1         285 my $url = "http://brk.twse.com.tw:8000/isin/C_public.jsp?strMode=2";
22 1         6 my $content = $cache->get_url($url);
23              
24 0         0 from_to($content, 'big5', 'utf-8');
25 1     1   1380 use HTML::TableExtract;
  1         18545  
  1         10  
26 0         0 my $te = HTML::TableExtract->new(
27             headers => [qw(證券代號及名稱 上市日)]);
28 0         0 $te->parse($content);
29 0         0 foreach my $ts ($te->tables) {
30 0         0 foreach my $row ($ts->rows) {
31 0         0 my ($symbol, $company)
32             = $row->[0] =~ m|(\S+)\s+\xe3\x80\x80(.*?)$|o;
33 0 0       0 next unless $symbol;
34 0         0 my $board_date = $row->[1];
35 0         0 $cache->set(md5_hex($company),
36             { id => $symbol, date => $board_date });
37             }
38             }
39             }
40 0         0 my $id = $cache->get($key)->{id};
41              
42 0 0       0 die "can't resolve symbol: $name" unless $id;
43              
44 0         0 @{$self}{qw/id/} = ($id);
  0         0  
45              
46 0         0 return $id;
47              
48             }
49              
50             sub new {
51 1     1 1 14 my ($class, $target) = @_;
52 1         4 my $self = bless {}, $class;
53              
54 1 50       8 $self->resolve($target)
55             unless $target =~ /^\d+$/;
56              
57 0   0       $self->{id} ||= $target;
58              
59 0           return $self;
60             }
61              
62 1     1   1602 no utf8;
  1         13  
  1         6  
63 1     1   1962 no encoding;
  1         17617  
  1         11  
64              
65             sub get {
66 0     0 1   my $self = shift;
67 0 0         my $stockno = ref $self ? $self->{id} : shift;
68 0           my $content
69             = LWP::Simple::get("http://mis.twse.com.tw/data/$stockno.csv");
70 0           from_to($content, 'big5', 'utf-8');
71              
72 0           my $result;
73 0           $content =~ s/["\n\r]//g;
74 0           my @info = split /,/, $content;
75 0           my $cmap = [ undef, 'UpDown', 'time', 'UpPrice',
76             'DownPrice', 'OpenPrice', 'HighPrice', 'LowPrice',
77             'MatchPrice', 'MatchQty', 'DQty' ];
78 0           $result->{ $cmap->[$_] } = $info[$_] foreach (0 .. 10);
79 0           $result->{name} = $info[32];
80 0           $result->{name} =~ s/\s//g;
81 0 0 0       $self->{name} ||= $result->{name} if ref $self;
82              
83 0 0         if ($result->{MatchPrice} == $result->{UpPrice}) {
    0          
    0          
    0          
84 0           $result->{UpDownMark} = '♁';
85             } elsif ($result->{MatchPrice} == $result->{DownPrice}) {
86 0           $result->{UpDownMark} = '?';
87             } elsif ($result->{UpDown} > 0) {
88 0           $result->{UpDownMark} = '+';
89             } elsif ($result->{UpDown} < 0) {
90 0           $result->{UpDownMark} = '-';
91             }
92              
93             $result->{Bid}{Buy}[$_]{ $info[ 11 + $_ * 2 ] } = $info[ 12 + $_ * 2 ]
94 0           foreach (0 .. 4);
95             $result->{Bid}{Sell}[$_]{ $info[ 21 + $_ * 2 ] } = $info[ 22 + $_ * 2 ]
96 0           foreach (0 .. 4);
97 0           $result->{BuyPrice} = $info[11];
98 0           $result->{SellPrice} = $info[21];
99              
100 0 0         $self->{quote} = $result if ref $self;
101              
102 0           return $result;
103             }
104              
105             sub fetchMarketFile {
106 0     0 1   my $self = shift;
107 0           my ($stock, $year, $month) = @_;
108 0           my @fields = ();
109 0           my ($i, $url, $file, $arg, $outfile);
110              
111 0 0         $month = "0" . $month if $month < 10;
112 0           $url
113             = "http://www.twse.com.tw/ch/trading/exchange/STOCK_DAY/genpage/Report"
114             . $year
115             . $month . "/";
116 0           $file = $year . $month . "_F3_1_8_" . $stock . ".php?STK_NO=" . $stock;
117 0           $arg = "&myear=" . $year . "&mmon=" . $month;
118 0           my $content = LWP::Simple::get("$url$file$arg");
119 0           my $result;
120              
121 0 0         if ($content) {
122 0 0         if ($content =~ /
123 0           $content = $1;
124 0           $content =~ s// /g;
125 0           $content =~ s// /g;
126 0           $content =~ s// /g;
127 0           $content =~ s/<\/tr(.)*?>/ /g;
128 0           $content =~ s/<\/td(.)*?>/ /g;
129 0           $content =~ s// /g;
130 0           $content =~ s/<\/div(.)*?>/ /g;
131 0           $content =~ s/ / /g;
132 0           $content =~ s/.*µ§¼Æ\s*//;
133 0           $content =~ s/\s+/ /g;
134 0           $content =~ s/,//g;
135 0           @fields = split / /, $content;
136              
137 0           for ($i = 18; $i <= $#fields; $i += 9) {
138 0           my $date = $fields[ $i - 3 ];
139 0           my ($yy, $mm, $dd) = split /\//, $date;
140 0 0         $fields[ $i - 3 ] = (1911 + $yy) . "-" . $mm . "-" . $dd
141             if $mm;
142              
143 0           $result
144             .= $fields[$i] . "\t"
145             . $fields[ $i + 1 ] . "\t"
146             . $fields[ $i + 2 ] . "\t"
147             . $fields[ $i + 3 ] . "\t"
148             . $fields[ $i + 5 ] . "\t"
149             . $fields[ $i - 3 ] . "\n";
150              
151             }
152             }
153             }
154 0           return $result;
155             }
156              
157             1;
158              
159             =head1 NAME
160              
161             Finance::TW::TSEQuote - Check stock quotes from Taiwan Security Exchange
162              
163             =head1 SYNOPSIS
164              
165             use Finance::TW::TSEQuote;
166              
167             my $quote = Finance::TW::TSEQuote->new('2002');
168              
169             while (1) { print $quote->get->{MatchPrice}.$/; sleep 30 }
170              
171             =head1 DESCRIPTION
172              
173             This module provides interface to stock information available from
174             Taiwan Security Exchange. You could resolve company name to stock
175             symbol, as well as getting the real time quote.
176              
177             =head1 CLASS METHODS
178              
179             =over 4
180              
181             =item new
182              
183             Create a stock quote object. Resolve the name to symbol
184             if the argument is not a symbol.
185              
186             =item resolve
187              
188             Resolve the company name to stock symbol.
189              
190             =item fetchMarketFile
191              
192             Fetch the Een-Of-Day stock information for specific company
193             by year and month.
194              
195             =item get
196              
197             Get the real time stock information.
198             Return a hash containing stock information. The keys are:
199              
200             =over 4
201              
202             =item Bid
203              
204             a hash of array of best 5 matching Sell and Buy bids
205              
206             =item DQty
207              
208             current volume
209              
210             =item MatchQty
211              
212             daily volume
213              
214             =item MatchPrice
215              
216             current price
217              
218             =item OpenPrice
219              
220             opening price
221              
222             =item HighPrice
223              
224             daily high
225              
226             =item LowPrice
227              
228             daily low
229              
230             =back
231              
232             =back
233              
234             =head1 AUTHORS
235              
236             Chia-liang Kao Eclkao@clkao.orgE
237              
238             Cheng-Lung Sung
239              
240             =head1 COPYRIGHT
241              
242             Copyright 2003-2012 by Chia-liang Kao Eclkao@clkao.orgE.
243              
244             This program is free software; you can redistribute it and/or modify it
245             under the same terms as Perl itself.
246              
247             See L
248              
249             =cut
250