view release on metacpan or search on metacpan
Makefile.PL
README
cpanfile
dist.ini
lib/Finance/Calendar.pm
lib/Finance/Calendar.pod
t/00-check-deps.t
t/00-compile.t
t/00-report-prereqs.dd
t/00-report-prereqs.t
t/calendar.t
t/rc/perlcriticrc
t/rc/perltidyrc
t/tactical_exchanges.t
xt/author/critic.t
xt/author/distmeta.t
xt/author/eol.t
xt/author/minimum-version.t
xt/author/mojibake.t
xt/author/no-tabs.t
xt/author/pod-syntax.t
{
"abstract" : "represents the trading calendar.",
"author" : [
"binary.com <BINARY@cpan.org>"
],
"dynamic_config" : 0,
"generated_by" : "Dist::Zilla version 6.029, CPAN::Meta::Converter version 2.150010",
"license" : [
"perl_5"
],
"meta-spec" : {
"url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec",
---
abstract: 'represents the trading calendar.'
author:
- 'binary.com <BINARY@cpan.org>'
build_requires:
ExtUtils::MakeMaker: '0'
File::Spec: '0'
IO::Handle: '0'
IPC::Open3: '0'
Test::CheckDeps: '0.010'
Test::FailWarnings: '0.008'
Test::MockTime: '0'
Makefile.PL view on Meta::CPAN
# This file was automatically generated by Dist::Zilla::Plugin::MakeMaker v6.029.
use strict;
use warnings;
use 5.006;
use ExtUtils::MakeMaker 7.64;
my %WriteMakefileArgs = (
"ABSTRACT" => "represents the trading calendar.",
"AUTHOR" => "binary.com <BINARY\@cpan.org>",
"CONFIGURE_REQUIRES" => {
"ExtUtils::MakeMaker" => "7.64"
},
"DISTNAME" => "Finance-Calendar",
"LICENSE" => "perl",
"MIN_PERL_VERSION" => "5.006",
"NAME" => "Finance::Calendar",
"PREREQ_PM" => {
"Carp" => 0,
NAME
Finance::Calendar - represents the trading calendar.
SYNOPSIS
use Finance::Calendar;
use Date::Utility;
my $calendar = {
holidays => {
"25-Dec-2013" => {
"Christmas Day" => [qw(FOREX METAL)],
},
"1-Jan-2014" => {
"New Year's Day" => [qw( FOREX METAL)],
},
"1-Apr-2013" => {
"Easter Monday" => [qw( USD)],
},
'22-Dec-2016' => {
'18:00' => ['FOREX', 'METAL'],
},
},
late_opens => {
'24-Dec-2010' => {
'14:30' => ['HKSE'],
},
},
};
my $calendar = Finance::Calendar->new(calendar => $calendar);
my $now = Date::Utility->new;
# Does London Stocks Exchange trade on $now
$calendar->trades_on(Finance::Exchange->create_exchange('LSE'), $now);
# Is it a country holiday for the United States on $now
$calendar->is_holiday_for('USD', $now);
# Returns the opening time of Australian Stocks Exchange on $now
$calendar->opening_on(Finance::Exchange->create_exchange('ASX'), $now);
# Returns the closing time of Forex on $now
$calendar->closing_on(Finance::Exchange->create_exchange('FOREX'), $now);
...
DESCRIPTION
This class is responsible for providing trading times or holidays
related information of a given financial stock exchange on a specific
date.
ATTRIBUTES - Object Construction
calendar
A hash reference that has information on: - exchange and country
holidays - late opens - early closes
METHODS - TRADING DAYS RELATED
trades_on
->trades_on($exchange_object, $date_object);
->trading_date_for($exchange_object, $date_object);
The date on which trading is considered to be taking place even if it
is not the same as the GMT date. Note that this does not handle trading
dates are offset forward beyond the next day (24h). It will need
additional work if these are found to exist.
Returns a Date object representing midnight GMT of the trading date.
calendar_days_to_trade_date_after
->calendar_days_to_trade_date_after($exchange_object, $date_object);
Returns the number of calendar days between a given Date::Utility and
the next day on which trading is open.
trading_days_between
->trading_days_between($exchange_object,
Date::Utility->new('4-May-10'),Date::Utility->new('5-May-10'));
Returns the number of trading days _between_ two given dates.
holiday_days_between
trading days. Currently, this applies on: - Sundays (for RSI exchanges
opening times) - Fridays (for closing times).
exchange - a Finance::Exchange instance
when - a Date::Utility instance
Examples:
# Friday closing adjustment for FOREX
my $changes = $calendar->regularly_adjusts_trading_hours_on(
Finance::Exchange->create_exchange('FOREX'),
Date::Utility->new('2023-02-17') # Friday
);
# Returns a hashref with adjusted closing time on Fridays:
# {
# 'daily_close' => {
# 'to' => '20h55m',
# 'rule' => 'Fridays'
# }
# }
# Sunday opening adjustment for RSI exchanges
my $changes = $calendar->regularly_adjusts_trading_hours_on(
Finance::Exchange->create_exchange('TACTICAL_FOREX_EURUSD'),
Date::Utility->new('2023-02-12') # Sunday
);
# Returns a hashref with adjusted opening time on Sundays:
# {
# 'daily_open' => {
# 'to' => '22h35m',
# 'rule' => 'Sundays' # or 'Sundays (DST)' if in DST
# }
# }
lib/Finance/Calendar.pm view on Meta::CPAN
package Finance::Calendar;
=head1 NAME
Finance::Calendar - represents the trading calendar.
=head1 SYNOPSIS
use Finance::Calendar;
use Date::Utility;
my $calendar = {
holidays => {
"25-Dec-2013" => {
"Christmas Day" => [qw(FOREX METAL)],
},
"1-Jan-2014" => {
"New Year's Day" => [qw( FOREX METAL)],
},
"1-Apr-2013" => {
"Easter Monday" => [qw( USD)],
},
lib/Finance/Calendar.pm view on Meta::CPAN
'22-Dec-2016' => {
'18:00' => ['FOREX', 'METAL'],
},
},
late_opens => {
'24-Dec-2010' => {
'14:30' => ['HKSE'],
},
},
};
my $calendar = Finance::Calendar->new(calendar => $calendar);
my $now = Date::Utility->new;
# Does London Stocks Exchange trade on $now
$calendar->trades_on(Finance::Exchange->create_exchange('LSE'), $now);
# Is it a country holiday for the United States on $now
$calendar->is_holiday_for('USD', $now);
# Returns the opening time of Australian Stocks Exchange on $now
$calendar->opening_on(Finance::Exchange->create_exchange('ASX'), $now);
# Returns the closing time of Forex on $now
$calendar->closing_on(Finance::Exchange->create_exchange('FOREX'), $now);
...
=head1 DESCRIPTION
This class is responsible for providing trading times or holidays related information of a given financial stock exchange on a specific date.
=cut
use Moose;
our $VERSION = '0.07';
use List::Util qw(min max first);
use Date::Utility;
use Memoize;
use Finance::Exchange;
use Carp qw(croak);
=head1 ATTRIBUTES - Object Construction
=head2 calendar
A hash reference that has information on:
- exchange and country holidays
- late opens
- early closes
=cut
has calendar => (
is => 'ro',
required => 1,
);
has _cache => (
is => 'ro',
default => sub { {} },
);
sub _get_cache {
lib/Finance/Calendar.pm view on Meta::CPAN
return $date->truncate_to_day unless ($exchange->trading_date_can_differ);
my $next_day = $date->plus_time_interval('1d')->truncate_to_day;
my $open_ti =
$exchange->market_times->{$self->_times_dst_key($exchange, $next_day)}->{daily_open};
return $next_day if ($open_ti and $next_day->epoch + $open_ti->seconds <= $date->epoch);
return $date->truncate_to_day;
}
=head2 calendar_days_to_trade_date_after
->calendar_days_to_trade_date_after($exchange_object, $date_object);
Returns the number of calendar days between a given Date::Utility
and the next day on which trading is open.
=cut
sub calendar_days_to_trade_date_after {
my ($self, $exchange, $when) = @_;
if (my $cache = $self->_get_cache('calendar_days_to_trade_date_after', $exchange, $when)) {
return $cache;
}
my $number_of_days = $self->trade_date_after($exchange, $when)->days_between($when);
$self->_set_cache($number_of_days, 'calendar_days_to_trade_date_after', $exchange, $when);
return $number_of_days;
}
=head2 trading_days_between
->trading_days_between($exchange_object, Date::Utility->new('4-May-10'),Date::Utility->new('5-May-10'));
Returns the number of trading days _between_ two given dates.
lib/Finance/Calendar.pm view on Meta::CPAN
=item C<exchange> - a L<Finance::Exchange> instance
=item C<when> - a L<Date::Utility> instance
=back
Examples:
# Friday closing adjustment for FOREX
my $changes = $calendar->regularly_adjusts_trading_hours_on(
Finance::Exchange->create_exchange('FOREX'),
Date::Utility->new('2023-02-17') # Friday
);
# Returns a hashref with adjusted closing time on Fridays:
# {
# 'daily_close' => {
# 'to' => '20h55m',
# 'rule' => 'Fridays'
# }
# }
# Sunday opening adjustment for RSI exchanges
my $changes = $calendar->regularly_adjusts_trading_hours_on(
Finance::Exchange->create_exchange('TACTICAL_FOREX_EURUSD'),
Date::Utility->new('2023-02-12') # Sunday
);
# Returns a hashref with adjusted opening time on Sundays:
# {
# 'daily_open' => {
# 'to' => '22h35m',
# 'rule' => 'Sundays' # or 'Sundays (DST)' if in DST
# }
# }
lib/Finance/Calendar.pm view on Meta::CPAN
return Date::Utility->new($epoch)->is_dst_in_zone($exchange->trading_timezone);
}
### PRIVATE ###
sub _get_holidays_for {
my ($self, $symbol, $when) = @_;
my $date = $when->truncate_to_day->epoch;
my $calendar = $self->calendar->{holidays};
my $holiday = $calendar->{$date};
return undef unless $holiday;
foreach my $holiday_desc (keys %$holiday) {
return $holiday_desc if (first { $symbol eq $_ } @{$holiday->{$holiday_desc}});
}
return undef;
}
lib/Finance/Calendar.pm view on Meta::CPAN
my $epoch = (ref $when) ? $when->epoch : $when;
return 'dst' if $self->is_in_dst_at($exchange, $epoch);
return 'standard';
}
# get partial trading data for a given exchange
sub _get_partial_trading_for {
my ($self, $exchange, $type, $when) = @_;
my $cached = $self->calendar->{$type};
my $date = $when->truncate_to_day->epoch;
my $partial_defined = $cached->{$date};
return undef unless $partial_defined;
foreach my $close_time (keys %{$cached->{$date}}) {
my $symbols = $cached->{$date}{$close_time};
return $close_time if (first { $exchange->symbol eq $_ } @$symbols);
}
lib/Finance/Calendar.pm view on Meta::CPAN
# - opened : undefined if market is closed, contains the seconds the market has
# been open.
#
#
########
sub _market_opens {
my ($self, $exchange, $when) = @_;
my $date = $when;
# Figure out which "trading day" we are on
# even if it differs from the GMT calendar day.
my $next_day = $date->plus_time_interval('1d')->truncate_to_day;
my $next_open = $self->opening_on($exchange, $next_day);
$date = $next_day if ($next_open and not $date->is_before($next_open));
my $open = $self->opening_on($exchange, $date);
my $close = $self->closing_on($exchange, $date);
if (not $open) {
# date is not a trading day: will not and has not been open today
lib/Finance/Calendar.pod view on Meta::CPAN
this file, but rather the original, inline with Finance::Calendar
at lib/Finance/Calendar.pm
(on the system that originally ran this).
If you do edit this file, and don't want your changes to be removed, make
sure you change the first line.
=cut
=head1 NAME
Finance::Calendar - represents the trading calendar.
=head1 SYNOPSIS
use Finance::Calendar;
use Date::Utility;
my $calendar = {
holidays => {
"25-Dec-2013" => {
"Christmas Day" => [qw(FOREX METAL)],
},
"1-Jan-2014" => {
"New Year's Day" => [qw( FOREX METAL)],
},
"1-Apr-2013" => {
"Easter Monday" => [qw( USD)],
},
lib/Finance/Calendar.pod view on Meta::CPAN
'22-Dec-2016' => {
'18:00' => ['FOREX', 'METAL'],
},
},
late_opens => {
'24-Dec-2010' => {
'14:30' => ['HKSE'],
},
},
};
my $calendar = Finance::Calendar->new(calendar => $calendar);
my $now = Date::Utility->new;
# Does London Stocks Exchange trade on $now
$calendar->trades_on(Finance::Exchange->create_exchange('LSE'), $now);
# Is it a country holiday for the United States on $now
$calendar->is_holiday_for('USD', $now);
# Returns the opening time of Australian Stocks Exchange on $now
$calendar->opening_on(Finance::Exchange->create_exchange('ASX'), $now);
# Returns the closing time of Forex on $now
$calendar->closing_on(Finance::Exchange->create_exchange('FOREX'), $now);
...
=head1 DESCRIPTION
This class is responsible for providing trading times or holidays related information of a given financial stock exchange on a specific date.
=head1 ATTRIBUTES - Object Construction
=head2 calendar
A hash reference that has information on:
- exchange and country holidays
- late opens
- early closes
=head1 METHODS - TRADING DAYS RELATED
=head2 trades_on
lib/Finance/Calendar.pod view on Meta::CPAN
=head2 trading_date_for
->trading_date_for($exchange_object, $date_object);
The date on which trading is considered to be taking place even if it is not the same as the GMT date.
Note that this does not handle trading dates are offset forward beyond the next day (24h). It will need additional work if these are found to exist.
Returns a Date object representing midnight GMT of the trading date.
=head2 calendar_days_to_trade_date_after
->calendar_days_to_trade_date_after($exchange_object, $date_object);
Returns the number of calendar days between a given Date::Utility
and the next day on which trading is open.
=head2 trading_days_between
->trading_days_between($exchange_object, Date::Utility->new('4-May-10'),Date::Utility->new('5-May-10'));
Returns the number of trading days _between_ two given dates.
=head2 holiday_days_between
lib/Finance/Calendar.pod view on Meta::CPAN
=item C<exchange> - a L<Finance::Exchange> instance
=item C<when> - a L<Date::Utility> instance
=back
Examples:
# Friday closing adjustment for FOREX
my $changes = $calendar->regularly_adjusts_trading_hours_on(
Finance::Exchange->create_exchange('FOREX'),
Date::Utility->new('2023-02-17') # Friday
);
# Returns a hashref with adjusted closing time on Fridays:
# {
# 'daily_close' => {
# 'to' => '20h55m',
# 'rule' => 'Fridays'
# }
# }
# Sunday opening adjustment for RSI exchanges
my $changes = $calendar->regularly_adjusts_trading_hours_on(
Finance::Exchange->create_exchange('TACTICAL_FOREX_EURUSD'),
Date::Utility->new('2023-02-12') # Sunday
);
# Returns a hashref with adjusted opening time on Sundays:
# {
# 'daily_open' => {
# 'to' => '22h35m',
# 'rule' => 'Sundays' # or 'Sundays (DST)' if in DST
# }
# }
t/calendar.t view on Meta::CPAN
use Test::MockTime qw( :all );
use Test::Most;
use Test::FailWarnings;
use Time::Local ();
use Finance::Exchange;
use Finance::Calendar;
my $date = Date::Utility->new('2013-12-01'); # first of December 2014
my $calendar = {
holidays => {
1367798400 => {
"Early May Bank Holiday" => [qw(LSE)],
},
1387929600 => {
"Christmas Day" => [qw(LSE FOREX METAL)],
},
1388534400 => {
"New Year's Day" => [qw(LSE FOREX METAL)],
},
t/calendar.t view on Meta::CPAN
'18h' => ['FOREX', 'METAL'],
},
},
late_opens => {
1293148800 => {
'2h30m' => ['HKSE'],
},
},
};
my $tc = Finance::Calendar->new(calendar => $calendar);
my ($LSE, $RANDOM, $FOREX, $ASX, $HKSE, $METAL, $JSC, $SWX) =
map { Finance::Exchange->create_exchange($_) } qw(LSE RANDOM FOREX ASX HKSE METAL JSC SWX);
subtest 'trades_on' => sub {
ok !$tc->trades_on($LSE, Date::Utility->new('1-Jan-14')), 'LSE doesn\'t trade on 1-Jan-14 because it is on holiday.';
ok !$tc->trades_on($LSE, Date::Utility->new('12-May-13')), 'LSE doesn\'t trade on weekend (12-May-13).';
ok $tc->trades_on($LSE, Date::Utility->new('3-May-13')), 'LSE trades on normal day 4-May-13.';
ok !$tc->trades_on($LSE, Date::Utility->new('5-May-13')), 'LSE doesn\'t trade on 5-May-13 as it is a weekend.';
ok $tc->trades_on($RANDOM, Date::Utility->new('5-May-13')), 'RANDOM trades on 5-May-13 as it is open on weekends.';
};
t/calendar.t view on Meta::CPAN
subtest 'trading_date_for' => sub {
my $non_dst_asx = Date::Utility->new('2017-09-30 15:59:59');
my $dst_asx = Date::Utility->new('2017-09-30 16:00:00');
ok !$tc->is_in_dst_at($ASX, $non_dst_asx->epoch);
ok $tc->is_in_dst_at($ASX, $dst_asx->epoch);
is $tc->trading_date_for($ASX, $non_dst_asx)->epoch, $non_dst_asx->truncate_to_day->epoch, 'same day on non dst';
is $tc->trading_date_for($ASX, $dst_asx)->epoch, $dst_asx->truncate_to_day->epoch, 'same day if time is before open on dst';
is $tc->trading_date_for($ASX, $dst_asx->plus_time_interval('7h'))->epoch, $dst_asx->plus_time_interval('1d')->truncate_to_day->epoch, 'next day';
};
subtest 'calendar_days_to_trade_date_after' => sub {
is($tc->calendar_days_to_trade_date_after($FOREX, Date::Utility->new('20-Dec-13')),
3, '3 calendar days until next trading day on FOREX after 20-Dec-13');
is($tc->calendar_days_to_trade_date_after($FOREX, Date::Utility->new('27-Dec-13')),
3, '3 calendar days until next trading day on FOREX after 27-Dec-13');
is($tc->calendar_days_to_trade_date_after($FOREX, Date::Utility->new('7-Mar-13')),
1, '1 calendar day until next trading day on FOREX after 7-Mar-13');
is($tc->calendar_days_to_trade_date_after($FOREX, Date::Utility->new('8-Mar-13')),
3, '3 calendar days until next trading day on FOREX after 8-Mar-13');
is($tc->calendar_days_to_trade_date_after($FOREX, Date::Utility->new('9-Mar-13')),
2, '2 calendar days until next trading day on FOREX after 9-Mar-13');
is($tc->calendar_days_to_trade_date_after($FOREX, Date::Utility->new('10-Mar-13')),
1, '1 calendar day until next trading day on FOREX after 10-Mar-13');
};
subtest 'trading_days_between' => sub {
is($tc->trading_days_between($LSE, Date::Utility->new('29-Mar-13'), Date::Utility->new('1-Apr-13')),
0, 'No trading days between 29th Mar and 1st Apr on LSE');
is($tc->trading_days_between($LSE, Date::Utility->new('11-May-13'), Date::Utility->new('12-May-13')),
0, 'No trading days between 11th and 12th May on LSE (over weekend)');
is($tc->trading_days_between($LSE, Date::Utility->new('4-May-13'), Date::Utility->new('6-May-13')),
0, 'No trading days between 4th May and 6th May on LSE (over weekend, then holiday on Monday)');
is($tc->trading_days_between($LSE, Date::Utility->new('10-May-13'), Date::Utility->new('14-May-13')),
xt/author/eol.t view on Meta::CPAN
use Test::More 0.88;
use Test::EOL;
my @files = (
'lib/Finance/Calendar.pm',
'lib/Finance/Calendar.pod',
't/00-check-deps.t',
't/00-compile.t',
't/00-report-prereqs.dd',
't/00-report-prereqs.t',
't/calendar.t',
't/rc/perlcriticrc',
't/rc/perltidyrc',
't/tactical_exchanges.t',
'xt/author/critic.t',
'xt/author/distmeta.t',
'xt/author/eol.t',
'xt/author/minimum-version.t',
'xt/author/mojibake.t',
'xt/author/no-tabs.t',
'xt/author/pod-syntax.t',
xt/author/no-tabs.t view on Meta::CPAN
use Test::More 0.88;
use Test::NoTabs;
my @files = (
'lib/Finance/Calendar.pm',
'lib/Finance/Calendar.pod',
't/00-check-deps.t',
't/00-compile.t',
't/00-report-prereqs.dd',
't/00-report-prereqs.t',
't/calendar.t',
't/rc/perlcriticrc',
't/rc/perltidyrc',
't/tactical_exchanges.t',
'xt/author/critic.t',
'xt/author/distmeta.t',
'xt/author/eol.t',
'xt/author/minimum-version.t',
'xt/author/mojibake.t',
'xt/author/no-tabs.t',
'xt/author/pod-syntax.t',