line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
#!/usr/bin/perl -w |
2
|
|
|
|
|
|
|
# This module is based on the Finance::Quote::yahooJSON module |
3
|
|
|
|
|
|
|
# |
4
|
|
|
|
|
|
|
# This program is free software; you can redistribute it and/or modify |
5
|
|
|
|
|
|
|
# it under the terms of the GNU General Public License as published by |
6
|
|
|
|
|
|
|
# the Free Software Foundation; either version 2 of the License, or |
7
|
|
|
|
|
|
|
# (at your option) any later version. |
8
|
|
|
|
|
|
|
# |
9
|
|
|
|
|
|
|
# This program is distributed in the hope that it will be useful, |
10
|
|
|
|
|
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
11
|
|
|
|
|
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
12
|
|
|
|
|
|
|
# GNU General Public License for more details. |
13
|
|
|
|
|
|
|
# |
14
|
|
|
|
|
|
|
# You should have received a copy of the GNU General Public License |
15
|
|
|
|
|
|
|
# along with this program; if not, write to the Free Software |
16
|
|
|
|
|
|
|
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA |
17
|
|
|
|
|
|
|
# 02110-1301, USA |
18
|
|
|
|
|
|
|
|
19
|
|
|
|
|
|
|
# 2019-12-01: Added additional labels for net and p_change. Set |
20
|
|
|
|
|
|
|
# close to previous close as returned in the JSON. |
21
|
|
|
|
|
|
|
# Bruce Schuck (bschuck at asgard hyphen systems dot com) |
22
|
|
|
|
|
|
|
|
23
|
|
|
|
|
|
|
package Finance::Quote::AlphaVantage; |
24
|
|
|
|
|
|
|
|
25
|
5
|
|
|
5
|
|
2830
|
use strict; |
|
5
|
|
|
|
|
23
|
|
|
5
|
|
|
|
|
186
|
|
26
|
5
|
|
|
5
|
|
27
|
use JSON qw( decode_json ); |
|
5
|
|
|
|
|
10
|
|
|
5
|
|
|
|
|
26
|
|
27
|
5
|
|
|
5
|
|
530
|
use HTTP::Request::Common; |
|
5
|
|
|
|
|
14
|
|
|
5
|
|
|
|
|
7471
|
|
28
|
|
|
|
|
|
|
|
29
|
|
|
|
|
|
|
our $VERSION = '1.58'; # VERSION |
30
|
|
|
|
|
|
|
|
31
|
|
|
|
|
|
|
# Alpha Vantage recommends that API call frequency does not extend far |
32
|
|
|
|
|
|
|
# beyond ~1 call per second so that they can continue to deliver |
33
|
|
|
|
|
|
|
# optimal server-side performance: |
34
|
|
|
|
|
|
|
# https://www.alphavantage.co/support/#api-key |
35
|
|
|
|
|
|
|
our @alphaqueries=(); |
36
|
|
|
|
|
|
|
my $maxQueries = { quantity =>5 , seconds => 60}; # no more than x |
37
|
|
|
|
|
|
|
# queries per y |
38
|
|
|
|
|
|
|
# seconds, based on |
39
|
|
|
|
|
|
|
# https://www.alphavantage.co/support/#support |
40
|
|
|
|
|
|
|
|
41
|
|
|
|
|
|
|
my $ALPHAVANTAGE_URL = |
42
|
|
|
|
|
|
|
'https://www.alphavantage.co/query?function=GLOBAL_QUOTE&datatype=json'; |
43
|
|
|
|
|
|
|
|
44
|
|
|
|
|
|
|
my %currencies_by_suffix = ( |
45
|
|
|
|
|
|
|
|
46
|
|
|
|
|
|
|
# Country City/Exchange Name |
47
|
|
|
|
|
|
|
'.US' => "USD", # USA AMEX, Nasdaq, NYSE |
48
|
|
|
|
|
|
|
'.A' => "USD", # USA American Stock Exchange (ASE) |
49
|
|
|
|
|
|
|
'.B' => "USD", # USA Boston Stock Exchange (BOS) |
50
|
|
|
|
|
|
|
'.N' => "USD", # USA Nasdaq Stock Exchange (NAS) |
51
|
|
|
|
|
|
|
'.O' => "USD", # USA NYSE Stock Exchange (NYS) |
52
|
|
|
|
|
|
|
'.OB' => "USD", # USA OTC Bulletin Board |
53
|
|
|
|
|
|
|
'.PK' => "USD", # USA Pink Sheets |
54
|
|
|
|
|
|
|
'.X' => "USD", # USA US Options |
55
|
|
|
|
|
|
|
'.BA' => "ARS", # Argentina Buenos Aires |
56
|
|
|
|
|
|
|
'.VI' => "EUR", # Austria Vienna |
57
|
|
|
|
|
|
|
'.AX' => "AUD", # Australia |
58
|
|
|
|
|
|
|
'.SA' => "BRL", # Brazil Sao Paolo |
59
|
|
|
|
|
|
|
'.BR' => "EUR", # Belgium Brussels |
60
|
|
|
|
|
|
|
'.TO' => "CAD", # Canada Toronto |
61
|
|
|
|
|
|
|
'.TRV' => "CAD", # Canada Toronto Venture |
62
|
|
|
|
|
|
|
'.V' => "CAD", # Canada Toronto Venture |
63
|
|
|
|
|
|
|
'.TRT' => "CAD", # Canada Toronto |
64
|
|
|
|
|
|
|
'.SN' => "CLP", # Chile Santiago |
65
|
|
|
|
|
|
|
'.SS' => "CNY", # China Shanghai |
66
|
|
|
|
|
|
|
'.SZ' => "CNY", # Shenzhen |
67
|
|
|
|
|
|
|
'.CO' => "DKK", # Denmark Copenhagen |
68
|
|
|
|
|
|
|
'.PA' => "EUR", # France Paris |
69
|
|
|
|
|
|
|
'.BE' => "EUR", # Germany Berlin |
70
|
|
|
|
|
|
|
'.BM' => "EUR", # Bremen |
71
|
|
|
|
|
|
|
'.D' => "EUR", # Dusseldorf |
72
|
|
|
|
|
|
|
'.F' => "EUR", # Frankfurt |
73
|
|
|
|
|
|
|
'.FRK' => "EUR", # Frankfurt |
74
|
|
|
|
|
|
|
'.H' => "EUR", # Hamburg |
75
|
|
|
|
|
|
|
'.HA' => "EUR", # Hanover |
76
|
|
|
|
|
|
|
'.MU' => "EUR", # Munich |
77
|
|
|
|
|
|
|
'.DEX' => "EUR", # Xetra |
78
|
|
|
|
|
|
|
'.ME' => "RUB", # Russia Moscow |
79
|
|
|
|
|
|
|
'.SG' => "EUR", # Stuttgart |
80
|
|
|
|
|
|
|
'.DE' => "EUR", # XETRA |
81
|
|
|
|
|
|
|
'.HK' => "HKD", # Hong Kong |
82
|
|
|
|
|
|
|
'.BO' => "INR", # India Bombay |
83
|
|
|
|
|
|
|
'.CL' => "INR", # Calcutta |
84
|
|
|
|
|
|
|
'.NS' => "INR", # National Stock Exchange |
85
|
|
|
|
|
|
|
'.JK' => "IDR", # Indonesia Jakarta |
86
|
|
|
|
|
|
|
'.I' => "EUR", # Ireland Dublin |
87
|
|
|
|
|
|
|
'.TA' => "ILS", # Israel Tel Aviv |
88
|
|
|
|
|
|
|
'.MI' => "EUR", # Italy Milan |
89
|
|
|
|
|
|
|
'.KS' => "KRW", # Korea Stock Exchange |
90
|
|
|
|
|
|
|
'.KQ' => "KRW", # KOSDAQ |
91
|
|
|
|
|
|
|
'.KL' => "MYR", # Malaysia Kuala Lampur |
92
|
|
|
|
|
|
|
'.MX' => "MXP", # Mexico |
93
|
|
|
|
|
|
|
'.NZ' => "NZD", # New Zealand |
94
|
|
|
|
|
|
|
'.AS' => "EUR", # Netherlands Amsterdam |
95
|
|
|
|
|
|
|
'.AMS' => "EUR", # Netherlands Amsterdam |
96
|
|
|
|
|
|
|
'.OL' => "NOK", # Norway Oslo |
97
|
|
|
|
|
|
|
'.LM' => "PEN", # Peru Lima |
98
|
|
|
|
|
|
|
'.IN' => "EUR", # Portugal Lisbon |
99
|
|
|
|
|
|
|
'.SI' => "SGD", # Singapore |
100
|
|
|
|
|
|
|
'.BC' => "EUR", # Spain Barcelona |
101
|
|
|
|
|
|
|
'.BI' => "EUR", # Bilbao |
102
|
|
|
|
|
|
|
'.MF' => "EUR", # Madrid Fixed Income |
103
|
|
|
|
|
|
|
'.MC' => "EUR", # Madrid SE CATS |
104
|
|
|
|
|
|
|
'.MA' => "EUR", # Madrid |
105
|
|
|
|
|
|
|
'.VA' => "EUR", # Valence |
106
|
|
|
|
|
|
|
'.ST' => "SEK", # Sweden Stockholm |
107
|
|
|
|
|
|
|
'.STO' => "SEK", # Sweden Stockholm |
108
|
|
|
|
|
|
|
'.HE' => "EUR", # Finland Helsinki |
109
|
|
|
|
|
|
|
'.S' => "CHF", # Switzerland Zurich |
110
|
|
|
|
|
|
|
'.TW' => "TWD", # Taiwan Taiwan Stock Exchange |
111
|
|
|
|
|
|
|
'.TWO' => "TWD", # OTC |
112
|
|
|
|
|
|
|
'.BK' => "THB", # Thialand Thailand Stock Exchange |
113
|
|
|
|
|
|
|
'.TH' => "THB", # ??? From Asia.pm, (in Thai Baht) |
114
|
|
|
|
|
|
|
'.L' => "GBP", # United Kingdom London |
115
|
|
|
|
|
|
|
'.IL' => "USD", # United Kingdom London USD*100 |
116
|
|
|
|
|
|
|
'.VX' => "CHF", # Switzerland |
117
|
|
|
|
|
|
|
'.SW' => "CHF", # Switzerland |
118
|
|
|
|
|
|
|
); |
119
|
|
|
|
|
|
|
|
120
|
|
|
|
|
|
|
|
121
|
|
|
|
|
|
|
sub methods { |
122
|
5
|
|
|
5
|
0
|
47
|
return ( alphavantage => \&alphavantage, |
123
|
|
|
|
|
|
|
canada => \&alphavantage, |
124
|
|
|
|
|
|
|
usa => \&alphavantage, |
125
|
|
|
|
|
|
|
nyse => \&alphavantage, |
126
|
|
|
|
|
|
|
nasdaq => \&alphavantage, |
127
|
|
|
|
|
|
|
); |
128
|
|
|
|
|
|
|
} |
129
|
|
|
|
|
|
|
|
130
|
|
|
|
|
|
|
sub parameters { |
131
|
1
|
|
|
1
|
0
|
5
|
return ('API_KEY'); |
132
|
|
|
|
|
|
|
} |
133
|
|
|
|
|
|
|
|
134
|
|
|
|
|
|
|
{ |
135
|
|
|
|
|
|
|
my @labels = qw/date isodate open high low close volume last net p_change/; |
136
|
|
|
|
|
|
|
|
137
|
|
|
|
|
|
|
sub labels { |
138
|
5
|
|
|
5
|
0
|
16
|
return ( alphavantage => \@labels, ); |
139
|
|
|
|
|
|
|
} |
140
|
|
|
|
|
|
|
} |
141
|
|
|
|
|
|
|
|
142
|
|
|
|
|
|
|
sub sleep_before_query { |
143
|
|
|
|
|
|
|
# wait till we can query again |
144
|
0
|
|
|
0
|
0
|
|
my $q = $maxQueries->{quantity}-1; |
145
|
0
|
0
|
|
|
|
|
if ( $#alphaqueries >= $q ) { |
146
|
0
|
|
|
|
|
|
my $time_since_x_queries = time()-$alphaqueries[$q]; |
147
|
|
|
|
|
|
|
# print STDERR "LAST QUERY $time_since_x_queries\n"; |
148
|
0
|
0
|
|
|
|
|
if ($time_since_x_queries < $maxQueries->{seconds}) { |
149
|
0
|
|
|
|
|
|
my $sleeptime = ($maxQueries->{seconds} - $time_since_x_queries) ; |
150
|
|
|
|
|
|
|
# print STDERR "SLEEP $sleeptime\n"; |
151
|
0
|
|
|
|
|
|
sleep( $sleeptime ); |
152
|
|
|
|
|
|
|
# print STDERR "CONTINUE\n"; |
153
|
|
|
|
|
|
|
} |
154
|
|
|
|
|
|
|
} |
155
|
0
|
|
|
|
|
|
unshift @alphaqueries, time(); |
156
|
0
|
|
|
|
|
|
pop @alphaqueries while $#alphaqueries>$q; # remove unnecessary data |
157
|
|
|
|
|
|
|
# print STDERR join(",",@alphaqueries)."\n"; |
158
|
|
|
|
|
|
|
} |
159
|
|
|
|
|
|
|
|
160
|
|
|
|
|
|
|
sub alphavantage { |
161
|
0
|
|
|
0
|
0
|
|
my $quoter = shift; |
162
|
|
|
|
|
|
|
|
163
|
0
|
|
|
|
|
|
my @stocks = @_; |
164
|
0
|
|
|
|
|
|
my $quantity = @stocks; |
165
|
0
|
|
|
|
|
|
my ( %info, $reply, $url, $code, $desc, $body, $ticker, $adjust ); |
166
|
0
|
|
|
|
|
|
my $ua = $quoter->user_agent(); |
167
|
0
|
|
|
|
|
|
my $launch_time = time(); |
168
|
|
|
|
|
|
|
|
169
|
|
|
|
|
|
|
# Since the JSON returned by the GLOBAL_QUOTE API does not specify |
170
|
|
|
|
|
|
|
# the currency of the price data, there is no way to determine the |
171
|
|
|
|
|
|
|
# correct currency without an additional call to the SYMBOL_SEARCH |
172
|
|
|
|
|
|
|
# API. To avoid even slower throttling, this module expects the |
173
|
|
|
|
|
|
|
# user to know which securties from certain countries may be traded |
174
|
|
|
|
|
|
|
# in the non-ISO4217 currency. |
175
|
|
|
|
|
|
|
# Example is LSE traded GBP.L and GBPG.L. GBP.L is traded in GBX, |
176
|
|
|
|
|
|
|
# which is also known as GBp, and GBPG.L is traded in the iso-4217 |
177
|
|
|
|
|
|
|
# currency GBP (Great Britain Pounds). |
178
|
|
|
|
|
|
|
# The user will add ".X" to symbols to return GBX priced securities |
179
|
|
|
|
|
|
|
# as GBP. |
180
|
|
|
|
|
|
|
|
181
|
|
|
|
|
|
|
my $token = exists $quoter->{module_specific_data}->{alphavantage}->{API_KEY} ? |
182
|
|
|
|
|
|
|
$quoter->{module_specific_data}->{alphavantage}->{API_KEY} : |
183
|
0
|
0
|
|
|
|
|
$ENV{"ALPHAVANTAGE_API_KEY"}; |
184
|
|
|
|
|
|
|
|
185
|
0
|
|
|
|
|
|
foreach my $stock (@stocks) { |
186
|
|
|
|
|
|
|
|
187
|
0
|
0
|
|
|
|
|
if ($stock =~ /\.X$/) { |
188
|
0
|
|
|
|
|
|
$adjust = 1; |
189
|
0
|
|
|
|
|
|
($ticker = $stock) =~ s/\.X$//; |
190
|
|
|
|
|
|
|
} else { |
191
|
0
|
|
|
|
|
|
$adjust = 0; |
192
|
0
|
|
|
|
|
|
$ticker = $stock |
193
|
|
|
|
|
|
|
} |
194
|
|
|
|
|
|
|
|
195
|
0
|
0
|
|
|
|
|
if ( !defined $token ) { |
196
|
0
|
|
|
|
|
|
$info{ $stock, 'success' } = 0; |
197
|
0
|
|
|
|
|
|
$info{ $stock, 'errormsg' } = |
198
|
|
|
|
|
|
|
'An AlphaVantage API is required. Get an API key at https://www.alphavantage.co'; |
199
|
0
|
|
|
|
|
|
next; |
200
|
|
|
|
|
|
|
} |
201
|
|
|
|
|
|
|
|
202
|
|
|
|
|
|
|
$url = |
203
|
0
|
|
|
|
|
|
$ALPHAVANTAGE_URL |
204
|
|
|
|
|
|
|
. '&apikey=' |
205
|
|
|
|
|
|
|
. $token |
206
|
|
|
|
|
|
|
. '&symbol=' |
207
|
|
|
|
|
|
|
. $ticker; |
208
|
|
|
|
|
|
|
|
209
|
|
|
|
|
|
|
my $get_content = sub { |
210
|
0
|
|
|
0
|
|
|
sleep_before_query(); |
211
|
0
|
|
|
|
|
|
my $time=int(time()-$launch_time); |
212
|
|
|
|
|
|
|
# print STDERR "Query at:".$time."\n"; |
213
|
0
|
|
|
|
|
|
$reply = $ua->request( GET $url); |
214
|
|
|
|
|
|
|
|
215
|
0
|
|
|
|
|
|
$code = $reply->code; |
216
|
0
|
|
|
|
|
|
$desc = HTTP::Status::status_message($code); |
217
|
0
|
|
|
|
|
|
$body = $reply->content; |
218
|
|
|
|
|
|
|
# print STDERR "AlphaVantage returned: $body\n"; |
219
|
0
|
|
|
|
|
|
}; |
220
|
|
|
|
|
|
|
|
221
|
0
|
|
|
|
|
|
&$get_content(); |
222
|
|
|
|
|
|
|
|
223
|
0
|
0
|
|
|
|
|
if ($code != 200) { |
224
|
0
|
|
|
|
|
|
$info{ $stock, 'success' } = 0; |
225
|
0
|
|
|
|
|
|
$info{ $stock, 'errormsg' } = $desc; |
226
|
0
|
|
|
|
|
|
next; |
227
|
|
|
|
|
|
|
} |
228
|
|
|
|
|
|
|
|
229
|
0
|
|
|
|
|
|
my $json_data; |
230
|
0
|
|
|
|
|
|
eval {$json_data = JSON::decode_json $body}; |
|
0
|
|
|
|
|
|
|
231
|
0
|
0
|
|
|
|
|
if ($@) { |
232
|
0
|
|
|
|
|
|
$info{ $stock, 'success' } = 0; |
233
|
0
|
|
|
|
|
|
$info{ $stock, 'errormsg' } = $@; |
234
|
|
|
|
|
|
|
} |
235
|
|
|
|
|
|
|
|
236
|
0
|
|
|
|
|
|
my $try_cnt = 0; |
237
|
0
|
|
0
|
|
|
|
while (($try_cnt < 5) && ($json_data->{'Note'})) { |
238
|
|
|
|
|
|
|
# print STDERR "NOTE:".$json_data->{'Note'}."\n"; |
239
|
|
|
|
|
|
|
# print STDERR "ADDITIONAL SLEEPING HERE !"; |
240
|
0
|
|
|
|
|
|
sleep (20); |
241
|
0
|
|
|
|
|
|
&$get_content(); |
242
|
0
|
|
|
|
|
|
eval {$json_data = JSON::decode_json $body}; |
|
0
|
|
|
|
|
|
|
243
|
0
|
|
|
|
|
|
$try_cnt += 1; |
244
|
|
|
|
|
|
|
} |
245
|
|
|
|
|
|
|
|
246
|
0
|
0
|
|
|
|
|
if ( !$json_data ) { |
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
247
|
0
|
|
|
|
|
|
$info{ $stock, 'success' } = 0; |
248
|
0
|
|
|
|
|
|
$info{ $stock, 'errormsg' } = 'Query returned no JSON'; |
249
|
0
|
|
|
|
|
|
next; |
250
|
|
|
|
|
|
|
} elsif ( $json_data->{'Error Message'} ) { |
251
|
0
|
|
|
|
|
|
$info{ $stock, 'success' } = 0; |
252
|
0
|
|
|
|
|
|
$info{ $stock, 'errormsg' } = $json_data->{'Error Message'}; |
253
|
0
|
|
|
|
|
|
next; |
254
|
|
|
|
|
|
|
} elsif ( $json_data->{'Information'} ) { |
255
|
0
|
|
|
|
|
|
$info{ $stock, 'success' } = 0; |
256
|
0
|
|
|
|
|
|
$info{ $stock, 'errormsg' } = $json_data->{'Information'}; |
257
|
0
|
|
|
|
|
|
next; |
258
|
|
|
|
|
|
|
} |
259
|
|
|
|
|
|
|
|
260
|
0
|
|
|
|
|
|
my $quote = $json_data->{'Global Quote'}; |
261
|
0
|
0
|
|
|
|
|
if ( ! %{$quote} ) { |
|
0
|
|
|
|
|
|
|
262
|
0
|
|
|
|
|
|
$info{ $stock, 'success' } = 0; |
263
|
0
|
|
|
|
|
|
$info{ $stock, 'errormsg' } = "json_data does not contain Global Quote"; |
264
|
0
|
|
|
|
|
|
next; |
265
|
|
|
|
|
|
|
} |
266
|
|
|
|
|
|
|
|
267
|
|
|
|
|
|
|
# %ts holds data as |
268
|
|
|
|
|
|
|
# { |
269
|
|
|
|
|
|
|
# "Global Quote": { |
270
|
|
|
|
|
|
|
# "01. symbol": "SOLB.BR", |
271
|
|
|
|
|
|
|
# "02. open": "104.2000", |
272
|
|
|
|
|
|
|
# "03. high": "104.9500", |
273
|
|
|
|
|
|
|
# "04. low": "103.4000", |
274
|
|
|
|
|
|
|
# "05. price": "104.0000", |
275
|
|
|
|
|
|
|
# "06. volume": "203059", |
276
|
|
|
|
|
|
|
# "07. latest trading day": "2019-11-29", |
277
|
|
|
|
|
|
|
# "08. previous close": "105.1500", |
278
|
|
|
|
|
|
|
# "09. change": "-1.1500", |
279
|
|
|
|
|
|
|
# "10. change percent": "-1.0937%" |
280
|
|
|
|
|
|
|
# } |
281
|
|
|
|
|
|
|
# } |
282
|
|
|
|
|
|
|
|
283
|
|
|
|
|
|
|
# remove trailing percent sign, if present |
284
|
0
|
|
|
|
|
|
$quote->{'10. change percent'} =~ s/\%$//; |
285
|
|
|
|
|
|
|
|
286
|
0
|
|
|
|
|
|
$info{ $stock, 'success' } = 1; |
287
|
0
|
|
|
|
|
|
$info{ $stock, 'success' } = 1; |
288
|
0
|
|
|
|
|
|
$info{ $stock, 'symbol' } = $quote->{'01. symbol'}; |
289
|
0
|
|
|
|
|
|
$info{ $stock, 'open' } = $quote->{'02. open'}; |
290
|
0
|
|
|
|
|
|
$info{ $stock, 'high' } = $quote->{'03. high'}; |
291
|
0
|
|
|
|
|
|
$info{ $stock, 'low' } = $quote->{'04. low'}; |
292
|
0
|
|
|
|
|
|
$info{ $stock, 'last' } = $quote->{'05. price'}; |
293
|
0
|
|
|
|
|
|
$info{ $stock, 'volume' } = $quote->{'06. volume'}; |
294
|
0
|
|
|
|
|
|
$info{ $stock, 'close' } = $quote->{'08. previous close'}; |
295
|
0
|
|
|
|
|
|
$info{ $stock, 'net' } = $quote->{'09. change'}; |
296
|
0
|
|
|
|
|
|
$info{ $stock, 'p_change' } = $quote->{'10. change percent'}; |
297
|
0
|
|
|
|
|
|
$info{ $stock, 'method' } = 'alphavantage'; |
298
|
0
|
|
|
|
|
|
$quoter->store_date( \%info, $stock, { isodate => $quote->{'07. latest trading day'} } ); |
299
|
|
|
|
|
|
|
|
300
|
|
|
|
|
|
|
# deduce currency |
301
|
0
|
0
|
|
|
|
|
if ( $ticker =~ /(\..*)/ ) { |
302
|
0
|
|
|
|
|
|
my $suffix = uc $1; |
303
|
0
|
0
|
|
|
|
|
if ( $currencies_by_suffix{$suffix} ) { |
304
|
0
|
|
|
|
|
|
$info{ $stock, 'currency' } = $currencies_by_suffix{$suffix}; |
305
|
|
|
|
|
|
|
|
306
|
|
|
|
|
|
|
# divide .X quotes by 100 |
307
|
0
|
0
|
|
|
|
|
if ( $adjust == 1 ) { |
308
|
0
|
|
|
|
|
|
foreach my $field ( $quoter->default_currency_fields ) { |
309
|
0
|
0
|
|
|
|
|
next unless ( $info{ $stock, $field } ); |
310
|
|
|
|
|
|
|
$info{ $stock, $field } = |
311
|
0
|
|
|
|
|
|
$quoter->scale_field( $info{ $stock, $field }, |
312
|
|
|
|
|
|
|
0.01 ); |
313
|
|
|
|
|
|
|
} |
314
|
|
|
|
|
|
|
} |
315
|
|
|
|
|
|
|
# divide USD quotes by 100 if suffix is '.IL' |
316
|
0
|
0
|
0
|
|
|
|
if ( ($suffix eq '.IL') && ($info{$stock,'currency'} eq 'USD') ) { |
317
|
0
|
|
|
|
|
|
foreach my $field ( $quoter->default_currency_fields ) { |
318
|
0
|
0
|
|
|
|
|
next unless ( $info{ $stock, $field } ); |
319
|
|
|
|
|
|
|
$info{ $stock, $field } = |
320
|
0
|
|
|
|
|
|
$quoter->scale_field( $info{ $stock, $field }, |
321
|
|
|
|
|
|
|
0.01 ); |
322
|
|
|
|
|
|
|
} |
323
|
|
|
|
|
|
|
} |
324
|
|
|
|
|
|
|
} |
325
|
|
|
|
|
|
|
} |
326
|
|
|
|
|
|
|
else { |
327
|
0
|
|
|
|
|
|
$info{ $stock, 'currency' } = 'USD'; |
328
|
|
|
|
|
|
|
} |
329
|
|
|
|
|
|
|
|
330
|
0
|
|
|
|
|
|
$info{ $stock, "currency_set_by_fq" } = 1; |
331
|
|
|
|
|
|
|
|
332
|
|
|
|
|
|
|
} |
333
|
|
|
|
|
|
|
|
334
|
0
|
0
|
|
|
|
|
return wantarray() ? %info : \%info; |
335
|
|
|
|
|
|
|
} |
336
|
|
|
|
|
|
|
1; |
337
|
|
|
|
|
|
|
|
338
|
|
|
|
|
|
|
=head1 NAME |
339
|
|
|
|
|
|
|
|
340
|
|
|
|
|
|
|
Finance::Quote::AlphaVantage - Obtain quotes from https://iexcloud.io |
341
|
|
|
|
|
|
|
|
342
|
|
|
|
|
|
|
=head1 SYNOPSIS |
343
|
|
|
|
|
|
|
|
344
|
|
|
|
|
|
|
use Finance::Quote; |
345
|
|
|
|
|
|
|
|
346
|
|
|
|
|
|
|
$q = Finance::Quote->new('AlphaVantage', alphavantage => {API_KEY => 'your-alphavantage-api-key'}); |
347
|
|
|
|
|
|
|
|
348
|
|
|
|
|
|
|
%info = $q->fetch('alphavantage', 'IBM', 'AAPL'); |
349
|
|
|
|
|
|
|
|
350
|
|
|
|
|
|
|
=head1 DESCRIPTION |
351
|
|
|
|
|
|
|
|
352
|
|
|
|
|
|
|
This module fetches information from https://www.alphavantage.co. |
353
|
|
|
|
|
|
|
|
354
|
|
|
|
|
|
|
This module is loaded by default on a Finance::Quote object. It's also possible |
355
|
|
|
|
|
|
|
to load it explicitly by placing "AlphaVantage" in the argument list to |
356
|
|
|
|
|
|
|
Finance::Quote->new(). |
357
|
|
|
|
|
|
|
|
358
|
|
|
|
|
|
|
This module provides the "alphavantage" fetch method. |
359
|
|
|
|
|
|
|
|
360
|
|
|
|
|
|
|
=head1 API_KEY |
361
|
|
|
|
|
|
|
|
362
|
|
|
|
|
|
|
https://www.alphavantage.co requires users to register and obtain an API key, which |
363
|
|
|
|
|
|
|
is also called a token. The token is a sequence of random characters. |
364
|
|
|
|
|
|
|
|
365
|
|
|
|
|
|
|
The API key may be set by either providing a module specific hash to |
366
|
|
|
|
|
|
|
Finance::Quote->new as in the above example, or by setting the environment |
367
|
|
|
|
|
|
|
variable ALPHAVANTAGE_API_KEY. |
368
|
|
|
|
|
|
|
|
369
|
|
|
|
|
|
|
=head1 LABELS RETURNED |
370
|
|
|
|
|
|
|
|
371
|
|
|
|
|
|
|
The following labels may be returned by Finance::Quote::AlphaVantage : |
372
|
|
|
|
|
|
|
symbol, open, close, high, low, last, volume, method, isodate, currency. |
373
|
|
|
|
|
|
|
|
374
|
|
|
|
|
|
|
=head1 CAVEATs |
375
|
|
|
|
|
|
|
|
376
|
|
|
|
|
|
|
Since the JSON returned by the GLOBAL_QUOTE API does not specify |
377
|
|
|
|
|
|
|
the currency of the price data, there is no way to determine the |
378
|
|
|
|
|
|
|
correct currency without an additional call to the SYMBOL_SEARCH |
379
|
|
|
|
|
|
|
API. To avoid even slower throttling, this module expects the |
380
|
|
|
|
|
|
|
user to know which securties from certain countries may be traded |
381
|
|
|
|
|
|
|
in the non-ISO4217 currency. |
382
|
|
|
|
|
|
|
|
383
|
|
|
|
|
|
|
An example are London Stock Exchange traded GBP.L (Global Petroleum Limited) |
384
|
|
|
|
|
|
|
and GBPG.L |
385
|
|
|
|
|
|
|
(Goldman Sachs Access UK Gilts 1-10 Years UCITS ETF CLASS GBP (Dist)). |
386
|
|
|
|
|
|
|
GBP.L is traded in GBX, which is also known as GBp (Great Britain Pence), |
387
|
|
|
|
|
|
|
and GBPG.L is traded in the iso-4217 currency GBP (Great Britain Pounds). |
388
|
|
|
|
|
|
|
The user will need to add ".X" to symbols to return GBX priced securities |
389
|
|
|
|
|
|
|
as GBP. For the example above the user would use the symbol GBP.L.X in |
390
|
|
|
|
|
|
|
the call to the alphavantage method for the prices to be output as GBP. |
391
|
|
|
|
|
|
|
|
392
|
|
|
|
|
|
|
=cut |