File Coverage

lib/Finance/Robinhood/Equity/Watchlist.pm
Criterion Covered Total %
statement 23 88 26.1
branch 0 8 0.0
condition 10 29 34.4
subroutine 15 22 68.1
pod 5 5 100.0
total 53 152 34.8


line stmt bran cond sub pod time code
1             package Finance::Robinhood::Equity::Watchlist;
2              
3             =encoding utf-8
4              
5             =for stopwords watchlist watchlists untradable urls
6              
7             =head1 NAME
8              
9             Finance::Robinhood::Equity::Watchlist - Represents a Single Robinhood Watchlist
10              
11             =head1 SYNOPSIS
12              
13             use Finance::Robinhood;
14             my $rh = Finance::Robinhood->new->login('user', 'pass');
15             my $watchlist = $rh->watchlist_by_name('Default');
16              
17             # TODO
18              
19             =cut
20              
21             our $VERSION = '0.92_001';
22              
23             sub _test__init {
24 1     1   8175 my $rh = t::Utility::rh_instance(1);
25 0         0 my $watchlist = $rh->equity_watchlist_by_name('Default');
26 0         0 isa_ok( $watchlist, __PACKAGE__ );
27 0         0 t::Utility::stash( 'WATCHLIST', $watchlist ); # Store it for later
28             }
29 1     1   4124 use Mojo::Base 'Finance::Robinhood::Utility::Iterator', -signatures;
  1         3  
  1         10  
30 1     1   284 use Mojo::URL;
  1         2  
  1         8  
31 1   0 1   79 use overload '""' => sub ( $s, @ ) { $s->{_next_page} // $s->{_first_page} }, fallback => 1;
  1     0   4  
  1         11  
  0         0  
  0         0  
  0         0  
  0         0  
32 1     1   594 use Finance::Robinhood::Equity::Watchlist::Element;
  1         3  
  1         6  
33              
34             sub _test_stringify {
35 1   50 1   1822 t::Utility::stash('WATCHLIST') // skip_all();
36 0         0 is( +t::Utility::stash('WATCHLIST'), 'https://api.robinhood.com/watchlists/Default/' );
37             }
38              
39             =head1 METHODS
40              
41             This is a subclass of Finance::Robinhood::Utility::Iterator. All the sweet,
42             sugary goodness from there works here. Note that C, C,
43             etc. return Finance::Robinhood::Equity::Watchlist::Element objects.
44              
45             =cut
46              
47             # Inherits _rh from Iterator
48              
49             =head2 C
50              
51             warn $watchlist->name;
52              
53             Returns the name given to this watchlist.
54              
55             =cut
56              
57             has 'name' => sub ($s) {
58             $s->{results}->[0]->{watchlist} =~ m[.+\/(\w+)\/$];
59             $1;
60             };
61              
62             sub _test_name {
63 1   50 1   1823 t::Utility::stash('WATCHLIST') // skip_all();
64 0         0 is( t::Utility::stash('WATCHLIST')->name, 'Default' );
65             }
66              
67             # Private
68             has 'url' => sub ($s) {
69             sprintf 'https://api.robinhood.com/watchlists/%s/', $s->name;
70             };
71              
72             sub _test_url {
73 1   50 1   1876 t::Utility::stash('WATCHLIST') // skip_all();
74 0         0 is( t::Utility::stash('WATCHLIST')->url, 'https://api.robinhood.com/watchlists/Default/' );
75             }
76              
77             # Override methods from Iterator
78             has _class => sub ($s) {'Finance::Robinhood::Equity::Watchlist::Element'};
79             has _next_page => sub ($s) { $s->{url} };
80              
81             sub _test_current {
82 1   50 1   1885 t::Utility::stash('WATCHLIST') // skip_all();
83 0         0 t::Utility::stash('WATCHLIST')->reset;
84 0         0 isa_ok(
85             t::Utility::stash('WATCHLIST')->current,
86             'Finance::Robinhood::Equity::Watchlist::Element'
87             );
88             }
89              
90             sub _test_next {
91 1   50 1   1889 t::Utility::stash('WATCHLIST') // skip_all();
92 0         0 t::Utility::stash('WATCHLIST')->reset;
93 0         0 isa_ok(
94             t::Utility::stash('WATCHLIST')->next,
95             'Finance::Robinhood::Equity::Watchlist::Element'
96             );
97             }
98              
99             =head2 C
100              
101             $watchlist->populate('MSFT', 'QQQ', 'BA');
102              
103             Adds a list of equity instruments in bulk by their ticker symbol and returns a
104             boolean.
105              
106             =cut
107              
108 0     0 1 0 sub populate ( $s, @symbols ) {
  0         0  
  0         0  
  0         0  
109              
110             # Split symbols into groups of 32 to keep URL length down
111 0         0 my $res;
112 0         0 while (@symbols) {
113 0         0 $res = $s->_rh->_post( $s->url . 'bulk_add/', symbols => splice @symbols, 0, 32 );
114 0 0       0 return Finance::Robinhood::Error->new( $res->json ) if !$res->is_success;
115             }
116 0   0     0 return $res->is_success
117             || Finance::Robinhood::Error->new(
118             $res->is_server_error ? ( details => $res->message ) : $res->json );
119             }
120              
121             sub _test_populate {
122 1   50 1   1830 t::Utility::stash('WATCHLIST') // skip_all();
123 0         0 t::Utility::stash('WATCHLIST')->reset;
124 0         0 ok( t::Utility::stash('WATCHLIST')->populate('MSFT'), 'adding MSFT' );
125 0     0   0 todo( "Test that the instrument was added by checking watchlist size" => sub { pass('ugh') } );
  0         0  
126             }
127              
128             =head2 C
129              
130             $watchlist->add_instrument($msft);
131              
132             Adds an equity instrument. If successful, a
133             Finance::Robinhood::Equity::Watchlist::Element object is returned.
134              
135             =cut
136              
137 0     0 1 0 sub add_instrument ( $s, $instrument ) {
  0         0  
  0         0  
  0         0  
138 0         0 my $res = $s->_rh->_post( $s->url, instrument => $instrument );
139             return $res->is_success
140 0 0       0 ? Finance::Robinhood::Equity::Watchlist::Element->new( _rh => $s->_rh, %{ $res->json } )
  0 0       0  
141             : Finance::Robinhood::Error->new(
142             $res->is_server_error ? ( details => $res->message ) : $res->json );
143             }
144              
145             sub _test_add_instrument {
146 1   50 1   1973 t::Utility::stash('WATCHLIST') // skip_all();
147 0         0 t::Utility::stash('WATCHLIST')->reset;
148 0         0 my $result
149             = t::Utility::stash('WATCHLIST')
150             ->add_instrument(
151             t::Utility::stash('WATCHLIST')->_rh->equity_instrument_by_symbol('MSFT') );
152 0 0       0 isa_ok(
153             $result,
154             $result ? 'Finance::Robinhood::Equity::Watchlist::Element' : 'Finance::Robinhood::Error'
155             );
156             }
157              
158             =head2 C
159              
160             my @instruments = $watchlist->instruments();
161              
162             This method makes a call to grab data for every equity instrument on the
163             watchlist and returns them as a list.
164              
165             =cut
166              
167 0     0 1 0 sub instruments ($s) {
  0         0  
  0         0  
168 0         0 $s->_rh->equity_instruments_by_id( map { $_->id } $s->all );
  0         0  
169             }
170              
171             sub _test_instruments {
172 1   50 1   1877 t::Utility::stash('WATCHLIST') // skip_all();
173 0         0 t::Utility::stash('WATCHLIST')->reset;
174 0         0 my @instruments = t::Utility::stash('WATCHLIST')->instruments;
175 0         0 isa_ok( $_, 'Finance::Robinhood::Equity::Instrument' ) for @instruments;
176             }
177              
178             =head2 C
179              
180             my @ids = $watchlist->ids();
181              
182             Returns the instrument id for all equity instruments as a list.
183              
184             =cut
185              
186 0     0 1 0 sub ids ($s) {
  0         0  
  0         0  
187 0         0 map { $_->id } $s->all;
  0         0  
188             }
189              
190             sub _test_ids {
191 1   50 1   1840 t::Utility::stash('WATCHLIST') // skip_all();
192 0         0 t::Utility::stash('WATCHLIST')->reset;
193 0         0 my @ids = t::Utility::stash('WATCHLIST')->ids;
194 0         0 like( $_, qr[^[0-9a-f]{8}(?:\-[0-9a-f]{4}){3}\-[0-9a-f]{12}$]i, $_ ) for @ids;
195             }
196              
197             =head2 C
198              
199             $watchlist->reorder( @ids );
200              
201             This method moves items of the watchlist around.
202              
203             =cut
204              
205 0     0 1 0 sub reorder ( $s, @ids ) {
  0         0  
  0         0  
  0         0  
206 0         0 my $res = $s->_rh->_post( $s->url . 'reorder/', uuids => join ',', @ids );
207 0   0     0 return $res->is_success || Finance::Robinhood::Error->new( %{ $res->json } );
208             }
209              
210             sub _test_reorder {
211 1   50 1   1889 t::Utility::stash('WATCHLIST') // skip_all();
212 0           t::Utility::stash('WATCHLIST')->reset;
213 0           my @ids = t::Utility::stash('WATCHLIST')->ids;
214 0           ok( t::Utility::stash('WATCHLIST')->reorder( reverse @ids ), 'reorder(...)' );
215 0           t::Utility::stash('WATCHLIST')->reset;
216 0           my @reordered = t::Utility::stash('WATCHLIST')->ids;
217 0           is( [ reverse @ids ], \@reordered );
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;