view release on metacpan or search on metacpan
Makefile.PL view on Meta::CPAN
VERSION_FROM => 'lib/App/Chart.pm',
ABSTRACT => 'Stock and commodity charting program.',
AUTHOR => 'Kevin Ryde <user42_kevin@yahoo.com.au>',
SIGN => 1,
MIN_PERL_VERSION => '5.010',
# valid LICENSE values per Module::Build::Base::valid_licenses(), or at
# least the ones there have urls to link
LICENSE => 'gpl_3',
# ExtUtils::MM_Unix "fixin()" changes #!perl to #!/usr/bin/perl
EXE_FILES => [ 'chart' ],
PREREQ_PM => \%PREREQ_PM,
TEST_REQUIRES => \%TEST_REQUIRES,
clean => { FILES => join(' ',
'doc/chart.dvi',
'doc/chart.ps',
'doc/chart.pdf',
'doc/*.dvi',
doc/chart.texi view on Meta::CPAN
@end table
@c @ifinfo
@c @sp 1
@c @end ifinfo
@section Locale Selection
@cindex Locale selection
@cindex Language
@cindex @env{LANG}
On a typical Unix/POSIX-style system the locale is selected with the
@env{LANG} environment variable, set to a language code and optional territory
and charset. For example US English,
@example
LANG=en_US
export LANG
@end example
This is often set by the system administrator, but you can do it yourself in
your @file{~/.profile} (@pxref{Bash Startup Files,,, bashref, Bash Features}).
lib/App/Chart/Database/Create.pm view on Meta::CPAN
my $create_preference = <<'HERE';
CREATE TABLE preference (
key TEXT NOT NULL,
value TEXT NOT NULL,
PRIMARY KEY (key))
HERE
# DATABASE_SCHEMA_VERSION revisions
#
# Schema 1, version 99.015
# - "latest" - fetch_timestamp rather than fetch_unixtime
# - "intraday_image" - fetch_timestamp likewise
# - "extra" - timestamp strings rather than unixtime numbers
# - "info" - new exchange column
#
# Schema 2, version 99.023
# - "preference" - missed PRIMARY KEY
#
sub upgrade_database {
my ($dbh, $dbversion) = @_;
print "Chart: Upgrading database from $dbversion to ",
App::Chart::DBI::DATABASE_SCHEMA_VERSION(),"\n";
require App::Chart::Download;
App::Chart::Database::call_with_transaction
($dbh, sub {
# version 1 adopting timestamps instead of unixtime
if ($dbversion <= 0) { _upgrade_0_to_1 ($dbh); }
if ($dbversion <= 1) { _upgrade_1_to_2 ($dbh); }
$dbh->do ("INSERT OR REPLACE INTO extra (symbol,key,value)
VALUES ('','database-schema-version',?)",
undef,
App::Chart::DBI::DATABASE_SCHEMA_VERSION());
});
}
sub _upgrade_0_to_1 {
my ($dbh) = @_;
$dbh->do ('ALTER TABLE info ADD COLUMN
exchange TEXT DEFAULT NULL');
$dbh->do ('DROP TABLE latest');
$dbh->do ($create_latest);
$dbh->do ('DROP TABLE intraday_image');
$dbh->do ($create_intraday_image);
$dbh->do ("DELETE FROM extra WHERE key like '%unixtime'");
App::Chart::Download::consider_latest_from_daily
([ App::Chart::Database->symbols_list() ]);
}
sub _upgrade_1_to_2 {
my $nbh = nbh();
$nbh->do ('DROP TABLE preference');
$nbh->do ($create_preference);
}
lib/App/Chart/Series/Derived/PFE.pm view on Meta::CPAN
$pfe = $ema_proc->($raw);
}
unshift @values, $value;
if (@values > $N) { pop @values }
return $pfe;
};
}
# could use Math::Libm hypot() here for a touch more accuracy, but not sure
# how good its portability is on non-Unix systems
sub _hypot {
my ($x,$y) = @_;
return sqrt($x*$x + $y*$y);
}
1;
__END__
# =head1 NAME
#
lib/App/Chart/Suffix/NZ.pm view on Meta::CPAN
// die "NZX dividends parse failed";
# print JSON->new->pretty->encode($marketDividends), "\n"; exit 0;
# eg. "amount" : "23.000000000",
# "currencyCode" : "NZD",
# "imputationCreditAmount" : "0.08166667",
# "baseQuantity" : "100",
# "expectedDate" : 1724673600
# "payableDate" : 1727352000,
# "supplementaryAmount" : "0.03705882",
# Dates are Unix seconds since 1970 GMT and in NZ timezone is
# midnight on the relevant date.
#
foreach my $href (@$marketDividends) {
my $isin = $href->{'isin'};
my $symbol = $isin_to_symbol{$href->{'isin'}}
// die "NZX dividends, no symbol for ISIN $isin";
my $amount = App::Chart::Download::trim_decimals
(App::Chart::Download::cents_to_dollars($href->{'amount'}),
2);
lib/App/Chart/Yahoo.pm view on Meta::CPAN
}
#------------------------------------------------------------------------------
# Latest
#
# This uses for example
#
# https://query1.finance.yahoo.com/v7/finance/chart/BHP.AX?period1=1718841600&period2=1719532800&interval=1d&events=history&close=unadjusted
#
# periodi1 and period2 are Unix style seconds since 1 Jan 1970 GMT.
#
# https://stackoverflow.com/questions/47076404/currency-helper-of-yahoo-sorry-unable-to-process-request-at-this-time-erro
# ->
# https://stackoverflow.com/questions/47064776/has-yahoo-suddenly-today-terminated-its-finance-download-api
#
# FUTURE: Intending to switch this over to v8 the same as the daily
# data, and possibly a single common parse. But this latest quote
# way has survived without problem during cooking and crumb troubles,
# not don't need to rush to change what's working.
lib/App/Chart/Yahoo.pm view on Meta::CPAN
proc => \&latest_download,
max_symbols => 1); # downloads go 1 at a time
sub latest_download {
my ($symbol_list) = @_;
foreach my $symbol (@$symbol_list) {
my $tdate = daily_available_tdate ($symbol);
App::Chart::Download::status(__('Yahoo quote'), $symbol);
my $lo_timet = tdate_to_unix($tdate - 4);
my $hi_timet = tdate_to_unix($tdate + 2);
my $events = 'history';
my $url = "https://query1.finance.yahoo.com/v7/finance/chart/"
. URI::Escape::uri_escape($symbol)
."?period1=$lo_timet"
."&period2=$hi_timet"
."&interval=1d"
."&events=$events"
."&close=unadjusted";
lib/App/Chart/Yahoo.pm view on Meta::CPAN
}
#-----------------------------------------------------------------------------
# Download Data, including dividends and splits
#
# This uses the "v8" historical prices downloads in JSON format like
#
# https://query2.finance.yahoo.com/v8/finance/chart/IBM?period1=1504028419&period2=1504428419&interval=1d&events=div%7Csplit&close=unadjusted
#
# period1 is the start time, period2 the end time, both as Unix
# seconds since 1 Jan 1970 in GMT.
#
# close=unadjusted means prices are without any adjustment for
# splits, so prices as traded at the time.
#
# If no trading in the date range (eg. before first listing) then
#
# 400 Bad Request
# {"chart":{"result":null,"error":{"code":"Bad Request","description":"Data doesn't exist for startDate = 1565827200, endDate = 1596153600"}}}
#
lib/App/Chart/Yahoo.pm view on Meta::CPAN
# As of September 2017, daily data is present for the current
# day's trade, during the trading session.
# Try reckoning it complete at 6pm.
return App::Chart::Download::tdate_today_after
(18,0, App::Chart::TZ->for_symbol ($symbol));
}
sub daily_url_func {
my ($symbol, $lo_tdate, $hi_tdate) = @_;
my $lo_timet = tdate_to_unix($lo_tdate - 2);
my $hi_timet = tdate_to_unix($hi_tdate);
# As of September 2024, dividends only appear on (or after?)
# the ex date. But try hi_timet well ahead hoping for
# upcoming dividends (ex date announced).
if ($hi_tdate >= daily_available_tdate($symbol)) {
$hi_timet += 60 * 86400;
}
return "https://query1.finance.yahoo.com/v8/finance/chart/"
. URI::Escape::uri_escape($symbol)
lib/App/Chart/Yahoo.pm view on Meta::CPAN
$got = 0;
$str .= '.';
}
if ((my $add = $decimals - $got) > 0) {
$str .= '0' x $add;
}
return $str;
}
# Return seconds since 00:00:00, 1 Jan 1970 GMT.
sub tdate_to_unix {
my ($tdate) = @_;
my $adate = App::Chart::tdate_to_adate ($tdate);
return ($adate + 4)*86400;
}
#------------------------------------------------------------------------------
1;
__END__
lib/App/Chart/doc/chart.html view on Meta::CPAN
<ul class="mini-toc">
<li><a href="#Locale-Selection" accesskey="1">Locale Selection</a></li>
</ul>
<div class="section-level-extent" id="Locale-Selection">
<h3 class="section"><span>17.1 Locale Selection<a class="copiable-link" href="#Locale-Selection"> ¶</a></span></h3>
<a class="index-entry-id" id="index-Locale-selection"></a>
<a class="index-entry-id" id="index-Language"></a>
<a class="index-entry-id" id="index-LANG"></a>
<p>On a typical Unix/POSIX-style system the locale is selected with the
<code class="env">LANG</code> environment variable, set to a language code and optional territory
and charset. For example US English,
</p>
<div class="example">
<pre class="example-preformatted">LANG=en_US
export LANG
</pre></div>
<p>This is often set by the system administrator, but you can do it yourself in
your <samp class="file">~/.profile</samp> (see <a data-manual="bashref" href="http://www.gnu.org/software/bash/manual/html_node/Bash-Startup-Files.html">Bash Startup Files</a> in <cite class="cite">Bash Features</cite>).
maybe/unused.pm view on Meta::CPAN
#------------------------------------------------------------------------------
sub delete_extra {
my ($symbol, $key) = @_;
my $dbh = App::Chart::DBI->instance;
$dbh->do ('DELETE FROM extra WHERE symbol=? AND key=?', {}, $symbol, $key);
}
sub strftime_unixtime_local {
my ($format, $unixtime) = @_;
my $time = $unixtime + $App::Chart::unixtime_base;
return App::Chart::strftime_wide ($format, localtime ($time));
}
#------------------------------------------------------------------------------
=item App::Chart::unixtime ()
Return the current time in Unix style seconds since midnight 1 Jan
1970. This function always uses 1970 as the epoch, unlike C<time()> which
is either 1970 or 1904 depending on the platform (1904 on MacOS).
=cut
our $unixtime_base = Date::Calc::Date_to_Time (1970,1,1, 0,0,0);
sub unixtime {
return (time () - $unixtime_base);
}
misc/t-yahoo.pl view on Meta::CPAN
# SCT.AX Scout Security, 1 old -> 100 new consolidation Aug 2024
# As of September 2024, split appears 4 times
# Think one only 5 Aug 24 price 0.52 up from 0.0052
# 1718409600
# 1719446400
my $symbol = 'SCT.AX';
$symbol = 'ORD.AX';
my $lo_tdate = App::Chart::ymd_to_tdate_floor(2024,6,1);
my $hi_tdate = App::Chart::ymd_to_tdate_floor(2024,9,1);
my $lo_timet = App::Chart::Yahoo::tdate_to_unix($lo_tdate);
my $hi_timet = App::Chart::Yahoo::tdate_to_unix($hi_tdate);
my $url = "https://query1.finance.yahoo.com/v8/finance/chart/"
. URI::Escape::uri_escape($symbol)
."?period1=$lo_timet"
."&period2=$hi_timet"
."&interval=1d"
."&events=". URI::Escape::uri_escape('div|split')
."&close=unadjusted";
print "$url\n";
misc/t-yahoo.pl view on Meta::CPAN
}
{
# v8 dividends ahead
# https://www.intelligentinvestor.com.au/investment-tools/shares/dividends
# https://query2.finance.yahoo.com/v8/finance/chart/IBM?formatted=true&lang=en-US®ion=US&period1=1487372400&period2=1495058400&interval=1d&events=div%7Csplit&corsDomain=finance.yahoo.com
my $symbol = 'NKLA.MX';
$symbol = 'WBCPK.AX';
my $tdate = App::Chart::Yahoo::daily_available_tdate ($symbol);
my $lo_timet = App::Chart::Yahoo::tdate_to_unix($tdate - 30);
my $hi_timet = App::Chart::Yahoo::tdate_to_unix($tdate + 100);
my $url = "https://query1.finance.yahoo.com/v8/finance/chart/"
. URI::Escape::uri_escape($symbol)
."?period1=$lo_timet"
."&period2=$hi_timet"
."&interval=1d"
."&events=". URI::Escape::uri_escape('div|split')
."&close=unadjusted";
print "$url\n";
# uncomment this to run the ### lines
# use Smart::Comments;
if ($have_test_mocktime) {
diag "Test::MockTime version ", Test::MockTime->VERSION;
diag "Test::MockTime::DateCalc version ", Test::MockTime::DateCalc->VERSION;
}
#------------------------------------------------------------------------------
# tdate_to_unix()
# 1 Jan 1970 Thu 0*secsperday
# 2 Jan 1970 Fri 1
# 3 Jan 1970 Sat 2
# 4 Jan 1970 Sun 3
# 5 Jan 1970 Mon 4
#
is (App::Chart::Yahoo::tdate_to_unix(0), 4*86400,
"tdate 0 is 5 Jan 1970");
{
my $base_adate = App::Chart::ymd_to_adate(1970,1,1);
is ($base_adate, -4, "adate of 1 Jan 1970");
my $tdate = 12345;
my $got = App::Chart::Yahoo::tdate_to_unix($tdate);
my $want = (App::Chart::tdate_to_adate($tdate) - $base_adate) * 86400;
is ($got, $want, 'tdate_to_unix()');
}
#------------------------------------------------------------------------------
# round_decimals()
is (App::Chart::Yahoo::round_decimals('1.23456',1), '1.2');
is (App::Chart::Yahoo::round_decimals('1.23456',2), '1.23');
is (App::Chart::Yahoo::round_decimals('1.23456',3), '1.235');
is (App::Chart::Yahoo::round_decimals('1.23456',4), '1.2346');
unused/Yahoo-v7.pm view on Meta::CPAN
}
#------------------------------------------------------------------------------
# Latest
#
# This uses for example
#
# https://query1.finance.yahoo.com/v7/finance/chart/BHP.AX?period1=1718841600&period2=1719532800&interval=1d&events=history&close=unadjusted
#
# periodi1 and period2 are Unix style seconds since 1 Jan 1970 GMT.
#
# https://stackoverflow.com/questions/47076404/currency-helper-of-yahoo-sorry-unable-to-process-request-at-this-time-erro
# ->
# https://stackoverflow.com/questions/47064776/has-yahoo-suddenly-today-terminated-its-finance-download-api
App::Chart::LatestHandler->new
(pred => $latest_pred,
proc => \&latest_download,
max_symbols => 1); # downloads go 1 at a time
sub latest_download {
my ($symbol_list) = @_;
foreach my $symbol (@$symbol_list) {
my $tdate = daily_available_tdate ($symbol);
App::Chart::Download::status(__('Yahoo quote'), $symbol);
my $lo_timet = tdate_to_unix($tdate - 4);
my $hi_timet = tdate_to_unix($tdate + 2);
my $events = 'history';
my $url = "https://query1.finance.yahoo.com/v7/finance/chart/"
. URI::Escape::uri_escape($symbol)
."?period1=$lo_timet"
."&period2=$hi_timet"
."&interval=1d"
."&events=$events"
."&close=unadjusted";
unused/Yahoo-v7.pm view on Meta::CPAN
# and contains buried within 1.5 mbytes of hideous script
#
# <script type="application/json" data-sveltekit-fetched data-url="https://query1.finance.yahoo.com/v1/test/getcrumb?lang=en-US&region=US" data-ttl="59">{"status":200,"statusText":"OK","headers":{},"body":"DKVWQE/ggh4"}</script>
#
# Any \u002F or similar is escaped "/" character or similar.
# The crumb is included in a CSV download query like the following
# (alas can't use http, it redirects to https)
#
# https://query1.finance.yahoo.com/v7/finance/download/AMP.AX?period1=1503810440&period2=1504415240&interval=1d&events=history&crumb=hdDX/HGsZ0Q
#
# period1 is the start time, period2 the end time, both as Unix seconds
# since 1 Jan 1970. Not sure of the timezone needed. Some experiments
# suggest it depends on the timezone of the symbol. http works as well as
# https. The result is like
#
# Date,Open,High,Low,Close,Adj Close,Volume
# 2017-09-07,30.299999,30.379999,30.000000,30.170000,30.170000,3451099
#
# The "9999s" are some bad rounding off to what would be usually at most
# 3 (maybe 4?) decimal places.
#
unused/Yahoo-v7.pm view on Meta::CPAN
my $crumb_errors = 0;
SYMBOL: foreach my $symbol (@$symbol_list) {
my $lo_tdate = App::Chart::Download::start_tdate_for_update (@$symbol_list);
my $hi_tdate = daily_available_tdate ($symbol);
App::Chart::Download::status
(__('Yahoo data'), $symbol,
App::Chart::Download::tdate_range_string ($lo_tdate, $hi_tdate));
my $lo_timet = tdate_to_unix($lo_tdate - 2);
my $hi_timet = tdate_to_unix($hi_tdate + 2);
# my $data = cookie_and_crumb_data();
# if (! defined $data) {
# print "Yahoo $symbol no daily cookie data\n";
# next SYMBOL;
# }
# my $crumb = URI::Escape::uri_escape($data->{'crumb'});
# my $jar = http_cookies_from_string($data->{'cookies'} // '');
my $h = { source => __PACKAGE__,
unused/Yahoo-v7.pm view on Meta::CPAN
sub timezone_gmtoffset_at_ymd {
my ($timezone, $year, $month, $day) = @_;
my $timet = $timezone->call(\&POSIX::mktime,
0, 0, 0, $day, $month-1, $year-1900);
my ($sec,$min,$hour,$gmt_day) = gmtime($timet);
return $sec + 60*$min + 3600*$hour + 86400*($gmt_day - $day);
}
# Return seconds since 00:00:00, 1 Jan 1970 GMT.
sub tdate_to_unix {
my ($tdate) = @_;
my $adate = App::Chart::tdate_to_adate ($tdate);
return ($adate + 4)*86400;
}
# $str is a string from previous HTTP::Cookies ->as_string()
# Return a new HTTP::Cookies object with that content.
sub http_cookies_from_string {
my ($str) = @_;
require File::Temp;
unused/YahooOld.pm view on Meta::CPAN
#
# # App::Chart::Download::verbose_message ("Yahoo crumb $crumb cookies\n"
# # . $jar->as_string);
#
# my $crumb_errors = 0;
# SYMBOL: foreach my $symbol (@$symbol_list) {
# my $tdate = daily_available_tdate ($symbol);
#
# App::Chart::Download::status(__('Yahoo quote'), $symbol);
#
# my $lo_timet = tdate_to_unix($tdate - 4);
# my $hi_timet = tdate_to_unix($tdate + 2);
#
# my $data = daily_cookie_data($symbol);
# if (! defined $data) {
# print "Yahoo $symbol does not exist\n";
# next SYMBOL;
# }
# my $crumb = URI::Escape::uri_escape($data->{'crumb'});
# my $jar = http_cookies_from_string($data->{'cookies'} // '');
#
# my $events = 'history';
unused/YahooOld.pm view on Meta::CPAN
# and contains buried within 1.5 mbytes of hideous script
#
# <script type="application/json" data-sveltekit-fetched data-url="https://query1.finance.yahoo.com/v1/test/getcrumb?lang=en-US&region=US" data-ttl="59">{"status":200,"statusText":"OK","headers":{},"body":"DKVWQE/ggh4"}</script>
#
# Any \u002F or similar is escaped "/" character or similar.
# The crumb is included in a CSV download query like the following
# (alas can't use http, it redirects to https)
#
# https://query1.finance.yahoo.com/v7/finance/download/AMP.AX?period1=1503810440&period2=1504415240&interval=1d&events=history&crumb=hdDX/HGsZ0Q
#
# period1 is the start time, period2 the end time, both as Unix seconds
# since 1 Jan 1970. Not sure of the timezone needed. Some experiments
# suggest it depends on the timezone of the symbol. http works as well as
# https. The result is like
#
# Date,Open,High,Low,Close,Adj Close,Volume
# 2017-09-07,30.299999,30.379999,30.000000,30.170000,30.170000,3451099
#
# The "9999s" are some bad rounding off to what would be usually at most
# 3 (maybe 4?) decimal places.
#
unused/YahooOld.pm view on Meta::CPAN
my $crumb_errors = 0;
SYMBOL: foreach my $symbol (@$symbol_list) {
my $lo_tdate = App::Chart::Download::start_tdate_for_update (@$symbol_list);
my $hi_tdate = daily_available_tdate ($symbol);
App::Chart::Download::status
(__('Yahoo data'), $symbol,
App::Chart::Download::tdate_range_string ($lo_tdate, $hi_tdate));
my $lo_timet = tdate_to_unix($lo_tdate - 2);
my $hi_timet = tdate_to_unix($hi_tdate + 2);
my $data = daily_cookie_data($symbol);
if (! defined $data) {
print "Yahoo $symbol no daily cookie data\n";
next SYMBOL;
}
my $crumb = URI::Escape::uri_escape($data->{'crumb'});
my $jar = http_cookies_from_string($data->{'cookies'} // '');
my $h = { source => __PACKAGE__,