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