File Coverage

lib/Finance/Robinhood/Equity/Market/Hours.pm
Criterion Covered Total %
statement 87 87 100.0
branch 10 16 62.5
condition 16 32 50.0
subroutine 21 21 100.0
pod 7 7 100.0
total 141 163 86.5


line stmt bran cond sub pod time code
1             package Finance::Robinhood::Equity::Market::Hours;
2              
3             =encoding utf-8
4              
5             =for stopwords watchlist watchlists untradable urls
6              
7             =head1 NAME
8              
9             Finance::Robinhood::Equity::Market::Hours - Represents an Equity Market's
10             Operating Hours
11              
12             =head1 SYNOPSIS
13              
14             use Finance::Robinhood;
15             my $rh = Finance::Robinhood->new;
16             my $nyse = $rh->equity_market_by_mic('XNAS');
17              
18             CORE::say 'The Nasdaq is ' . ($nyse->hours->is_open ? '' : 'not ' ) . 'open today';
19              
20             =cut
21              
22             our $VERSION = '0.92_001';
23 1     1   6 use Mojo::Base-base, -signatures;
  1         2  
  1         6  
24 1     1   177 use Mojo::URL;
  1         2  
  1         5  
25 1     1   23 use Time::Moment;
  1         2  
  1         191  
26              
27             sub _test__init {
28 1     1   14125 my $rh = t::Utility::rh_instance(0);
29 1         13 my $open = $rh->equity_market_by_mic('XNAS')->hours( Time::Moment->from_epoch(1552613507) )
30             ; # NASDAQ - March 15th, 2019
31 1         647 isa_ok( $open, __PACKAGE__ );
32 1         387 t::Utility::stash( 'HOURS_OPEN', $open ); # Store it for later
33 1         19 my $closed = $rh->equity_market_by_mic('XNAS')->hours( Time::Moment->from_epoch(1552699907) )
34             ; # NASDAQ - March 16th, 2019
35 1         552 isa_ok( $closed, __PACKAGE__ );
36 1         387 t::Utility::stash( 'HOURS_CLOSED', $closed ); # Store it for later
37             }
38 1     1   7 use overload '""' => sub ( $s, @ ) { $s->{date} }, fallback => 1;
  1     18   1  
  1         15  
  18         29  
  18         85  
  18         708  
  18         35  
39              
40             sub _test_stringify {
41 1   50 1   2874 t::Utility::stash('HOURS_OPEN') // skip_all();
42 1         4 is( +t::Utility::stash('HOURS_OPEN'), '2019-03-15' );
43 1   50     262 t::Utility::stash('HOURS_CLOSED') // skip_all();
44 1         5 is( +t::Utility::stash('HOURS_CLOSED'), '2019-03-16' );
45             }
46             #
47             has _rh => undef => weak => 1;
48              
49             =head1 METHODS
50              
51             =head2 C
52              
53             Returns a true value if opens for trading on this date.
54              
55             =cut
56              
57             has ['is_open'];
58              
59             =head2 C
60              
61             $hours->opens_at;
62              
63             If the market opens today, this returns a Time::Moment object.
64              
65             =cut
66              
67 2     2 1 17 sub opens_at ($s) {
  2         5  
  2         4  
68 2 100       24 $s->{closes_at} ? Time::Moment->from_string( $s->{opens_at} ) : ();
69             }
70              
71             sub _test_opens_at {
72 1   50 1   2923 t::Utility::stash('HOURS_OPEN') // skip_all();
73 1         4 is( t::Utility::stash('HOURS_OPEN')->opens_at->to_string, '2019-03-15T13:30:00Z' );
74 1   50     481 t::Utility::stash('HOURS_CLOSED') // skip_all();
75 1         4 is( t::Utility::stash('HOURS_CLOSED')->opens_at, () );
76             }
77              
78             =head2 C
79              
80             $hours->closes_at;
81              
82             If the market was open, this returns a Time::Moment object.
83              
84             =cut
85              
86 2     2 1 19 sub closes_at ($s) {
  2         3  
  2         5  
87 2 100       66 $s->{closes_at} ? Time::Moment->from_string( $s->{closes_at} ) : ();
88             }
89              
90             sub _test_closes_at {
91 1   50 1   2206 t::Utility::stash('HOURS_OPEN') // skip_all();
92 1         4 is( t::Utility::stash('HOURS_OPEN')->closes_at->to_string, '2019-03-15T20:00:00Z' );
93 1   50     593 t::Utility::stash('HOURS_CLOSED') // skip_all();
94 1         4 is( t::Utility::stash('HOURS_CLOSED')->closes_at, () );
95             }
96              
97             =head2 C
98              
99             $hours->extended_opens_at;
100              
101             If the market was open and had an extended hours trading session, this returns
102             a Time::Moment object.
103              
104             =cut
105              
106 2     2 1 17 sub extended_opens_at ($s) {
  2         2  
  2         4  
107 2 100       25 $s->{extended_opens_at} ? Time::Moment->from_string( $s->{extended_opens_at} ) : ();
108             }
109              
110             sub _test_extended_opens_at {
111 1   50 1   2404 t::Utility::stash('HOURS_OPEN') // skip_all();
112 1         4 is( t::Utility::stash('HOURS_OPEN')->extended_opens_at->to_string, '2019-03-15T13:00:00Z' );
113 1   50     487 t::Utility::stash('HOURS_CLOSED') // skip_all();
114 1         5 is( t::Utility::stash('HOURS_CLOSED')->extended_opens_at, () );
115             }
116              
117             =head2 C
118              
119             $hours->extended_closes_at;
120              
121             If the market was open and had an extended hours trading session, this returns
122             a Time::Moment object.
123              
124             =cut
125              
126 2     2 1 18 sub extended_closes_at ($s) {
  2         4  
  2         3  
127 2 100       24 $s->{extended_closes_at} ? Time::Moment->from_string( $s->{extended_closes_at} ) : ();
128             }
129              
130             sub _test_extended_closes_at {
131 1   50 1   2433 t::Utility::stash('HOURS_OPEN') // skip_all();
132 1         5 is( t::Utility::stash('HOURS_OPEN')->extended_closes_at->to_string, '2019-03-15T22:00:00Z' );
133 1   50     488 t::Utility::stash('HOURS_CLOSED') // skip_all();
134 1         5 is( t::Utility::stash('HOURS_CLOSED')->extended_closes_at, () );
135             }
136              
137             =head2 C
138              
139             $hours->date;
140              
141             Returns a Time::Moment object.
142              
143             =cut
144              
145 8     8 1 2184 sub date ($s) {
  8         21  
  8         14  
146 8         299 Time::Moment->from_string( $s->{date} . 'T00:00:00Z' );
147             }
148              
149             sub _test_date {
150 1   50 1   2333 t::Utility::stash('HOURS_OPEN') // skip_all();
151 1         4 is( t::Utility::stash('HOURS_OPEN')->date->to_string, '2019-03-15T00:00:00Z' );
152 1   50     492 t::Utility::stash('HOURS_CLOSED') // skip_all();
153 1         5 is( t::Utility::stash('HOURS_CLOSED')->date->to_string, '2019-03-16T00:00:00Z' );
154             }
155              
156             =head2 C
157              
158             This returns a Finance::Robinhood::Equity::Market::Hours object for the next
159             day the market is open.
160              
161             =cut
162              
163 2     2 1 19 sub next_open_hours( $s ) {
  2         4  
  2         2  
164 2         9 my $res = $s->_rh->_get( $s->{next_open_hours} );
165             $res->is_success
166 2 0       57 ? Finance::Robinhood::Equity::Market::Hours->new( _rh => $s->_rh, %{ $res->json } )
  2 50       58  
167             : Finance::Robinhood::Error->new(
168             $res->is_server_error ? ( details => $res->message ) : $res->json );
169             }
170              
171             sub _test_next_open_hours {
172 1   50 1   2315 t::Utility::stash('HOURS_OPEN') // skip_all();
173 1         4 is( t::Utility::stash('HOURS_OPEN')->next_open_hours->date->to_string, '2019-03-18T00:00:00Z' );
174 1   50     701 t::Utility::stash('HOURS_CLOSED') // skip_all();
175 1         5 is(
176             t::Utility::stash('HOURS_CLOSED')->next_open_hours->date->to_string,
177             '2019-03-18T00:00:00Z'
178             );
179             }
180              
181             =head2 C
182              
183             This returns a Finance::Robinhood::Equity::Market::Hours object for the
184             previous day the market was open.
185              
186             =cut
187              
188 2     2 1 34 sub previous_open_hours( $s ) {
  2         5  
  2         4  
189 2         7 my $res = $s->_rh->_get( $s->{previous_open_hours} );
190             $res->is_success
191 2 0       59 ? Finance::Robinhood::Equity::Market::Hours->new( _rh => $s->_rh, %{ $res->json } )
  2 50       54  
192             : Finance::Robinhood::Error->new(
193             $res->is_server_error ? ( details => $res->message ) : $res->json );
194             }
195              
196             sub _test_previous_open_hours {
197 1   50 1   2305 t::Utility::stash('HOURS_OPEN') // skip_all();
198 1         5 is(
199             t::Utility::stash('HOURS_OPEN')->previous_open_hours->date->to_string,
200             '2019-03-14T00:00:00Z'
201             );
202 1   50     975 t::Utility::stash('HOURS_CLOSED') // skip_all();
203 1         5 is(
204             t::Utility::stash('HOURS_CLOSED')->previous_open_hours->date->to_string,
205             '2019-03-15T00:00:00Z'
206             );
207             }
208              
209             =head1 LEGAL
210              
211             This is a simple wrapper around the API used in the official apps. The author
212             provides no investment, legal, or tax advice and is not responsible for any
213             damages incurred while using this software. This software is not affiliated
214             with Robinhood Financial LLC in any way.
215              
216             For Robinhood's terms and disclosures, please see their website at
217             https://robinhood.com/legal/
218              
219             =head1 LICENSE
220              
221             Copyright (C) Sanko Robinson.
222              
223             This library is free software; you can redistribute it and/or modify it under
224             the terms found in the Artistic License 2. Other copyrights, terms, and
225             conditions may apply to data transmitted through this module. Please refer to
226             the L section.
227              
228             =head1 AUTHOR
229              
230             Sanko Robinson Esanko@cpan.orgE
231              
232             =cut
233              
234             1;