File Coverage

blib/lib/Finance/InteractiveBrokers/API.pm
Criterion Covered Total %
statement 55 55 100.0
branch 19 24 79.1
condition 4 6 66.6
subroutine 16 16 100.0
pod 10 10 100.0
total 104 111 93.6


line stmt bran cond sub pod time code
1             package Finance::InteractiveBrokers::API;
2             #
3             # Finance::InteractiveBrokers::API - Convenience functions for IB API
4             #
5             # Copyright (c) 2010-2013 Jason McManus
6             #
7             # Full POD documentation after __END__
8             #
9              
10 2     2   105239 use Carp qw( croak confess );
  2         7  
  2         178  
11 2     2   15 use strict;
  2         3  
  2         75  
12 2     2   13 use warnings;
  2         10  
  2         91  
13              
14             ###
15             ### Variables
16             ###
17              
18 2     2   13 use vars qw( @ISA @EXPORT_OK $VERSION $TRUE $FALSE $KEEP $DELETE $REQUIRED );
  2         4  
  2         542  
19             BEGIN
20             {
21 2     2   14 require Exporter;
22 2         116 @ISA = qw( Exporter );
23 2         6 @EXPORT_OK = qw( api_version );
24 2         4567 $VERSION = '0.04';
25             }
26              
27             *TRUE = \1;
28             *FALSE = \0;
29             *KEEP = \0;
30             *DELETE = \1;
31             *REQUIRED = \2;
32              
33             our %our_args = (
34             version => $DELETE | $REQUIRED,
35             );
36              
37             # IB API method and event data structures, keyed by version
38             my $DEFAULT_API_VERSION = '9.64';
39             my $methods = {};
40             my $events = {};
41             my $methods_arr = {
42             '9.64' => [
43             # Our add-ons
44             qw(
45             processMessages
46             setSelectTimeout
47             ),
48             # Official API
49             # XXX: API Docs and source code differ (I use the source code names):
50             # Docs C++ headers
51             # -------------------------------------------
52             # reqIDs() reqIds()
53             # setLogLevel() setServerLogLevel()
54             qw(
55             eConnect
56             eDisconnect
57             isConnected
58             reqCurrentTime
59             serverVersion
60             setServerLogLevel
61             checkMessages
62             TwsConnectionTime
63              
64             reqMktData
65             cancelMktData
66             calculateImpliedVolatility
67             cancelCalculateImpliedVolatility
68             calculateOptionPrice
69             cancelCalculateOptionPrice
70              
71             placeOrder
72             cancelOrder
73             reqOpenOrders
74             reqAllOpenOrders
75             reqAutoOpenOrders
76             reqIds
77             exerciseOptions
78              
79             reqAccountUpdates
80              
81             reqExecutions
82              
83             reqContractDetails
84              
85             reqMktDepth
86             cancelMktDepth
87              
88             reqNewsBulletins
89             cancelNewsBulletins
90              
91             reqManagedAccts
92             requestFA
93             replaceFA
94              
95             reqHistoricalData
96             cancelHistoricalData
97              
98             reqScannerParameters
99             reqScannerSubscription
100             cancelScannerSubscription
101              
102             reqRealTimeBars
103             cancelRealTimeBars
104              
105             reqFundamentalData
106             cancelFundamentalData
107             ),
108             ],
109             };
110             $methods_arr->{'9.65'} = $methods_arr->{'9.64'};
111             $methods_arr->{'9.66'} = [
112             @{ $methods_arr->{'9.65'} },
113             qw(
114             reqMarketDataType
115             ),
116             # UNDOCUMENTED
117             qw(
118             reqGlobalCancel
119             ),
120             ];
121             $methods_arr->{'9.67'} = $methods_arr->{'9.66'};
122              
123             my $events_arr = {
124             '9.64' => [
125             qw(
126             winError
127             error
128             connectionClosed
129             currentTime
130              
131             tickPrice
132             tickSize
133             tickOptionComputation
134             tickGeneric
135             tickString
136             tickEFP
137             tickSnapshotEnd
138              
139             orderStatus
140             openOrder
141             nextValidId
142              
143             updateAccountValue
144             updatePortfolio
145             updateAccountTime
146              
147             updateNewsBulletin
148              
149             contractDetails
150             contractDetailsEnd
151             bondContractDetails
152              
153             execDetails
154             execDetailsEnd
155              
156             updateMktDepth
157             updateMktDepthL2
158              
159             managedAccounts
160             receiveFA
161              
162             historicalData
163              
164             scannerParameters
165             scannerData
166             scannerDataEnd
167              
168             realtimeBar
169              
170             fundamentalData
171              
172             deltaNeutralValidation
173             ),
174             # These are in the headers, but apparently not documented
175             qw(
176             openOrderEnd
177             accountDownloadEnd
178             )
179             ],
180             };
181             $events_arr->{'9.65'} = $events_arr->{'9.64'};
182             $events_arr->{'9.66'} = [
183             @{ $events_arr->{'9.65'} },
184             qw(
185             marketDataType
186             ),
187             ];
188             $events_arr->{'9.67'} = [
189             @{ $events_arr->{'9.66'} },
190             qw(
191             commissionReport
192             ),
193             ];
194              
195             # Cram them into a hash for O(1) lookup time
196             for my $ver ( keys( %$methods_arr ) )
197             {
198             $methods->{$ver} = { map { $_ => 1 } @{ $methods_arr->{$ver} } };
199             }
200             for my $ver ( keys( %$events_arr ) )
201             {
202             $events->{$ver} = { map { $_ => 1 } @{ $events_arr->{$ver} } };
203             }
204              
205             ###
206             ### Constructor
207             ###
208              
209             sub new
210             {
211 6     6 1 11469 my( $class, @args ) = @_;
212 6 50       26 croak( "$class requires an even number of params" ) if( @args & 1 );
213              
214 6         25 my $self = {
215             version => $DEFAULT_API_VERSION, # IB API version
216             };
217              
218 6         19 bless( $self, $class );
219              
220 6         23 my @leftover = $self->initialize( @args );
221              
222             # Make sure we received a valid API version
223 6 100       19 confess( 'API version \'' . $self->api_version . '\' is unknown;' .
224             " usable versions are: " .
225             join( ' ', $self->versions ) . "\n" )
226             unless( exists( $methods->{$self->api_version} ) );
227              
228 5         31 return( $self );
229             }
230              
231             sub initialize
232             {
233 6     6 1 17 my( $self, %args ) = @_;
234              
235             # Cycle through the args, grab what's for us, and delete if appropriate
236 6         23 for( keys( %args ) )
237             {
238 5 50       43 if( exists( $our_args{lc $_} ) )
239             {
240 5         21 $self->{lc $_} = $args{$_};
241 5 50       36 delete( $args{$_} )
242             if( $our_args{lc $_} & $DELETE );
243             }
244             }
245              
246             # Check all required args
247 6         19 for( keys( %our_args ) )
248             {
249 6 50       18 if( $our_args{$_} & $REQUIRED )
250             {
251 6 50 33     46 confess( "$_ is a required argument" )
252             if( ( not exists $self->{lc $_} ) or
253             ( not defined $self->{lc $_} ) );
254             }
255             }
256              
257 6         20 return( %args );
258             }
259              
260             ###
261             ### Class methods
262             ###
263              
264             sub api_versions
265             {
266 3     3 1 1354 return( sort keys( %$methods ) );
267             }
268              
269             ###
270             ### Methods
271             ###
272              
273             sub methods
274             {
275 8     8 1 15 my $self = shift;
276              
277 8         10 return( @{ $methods_arr->{$self->api_version} } );
  8         25  
278             }
279              
280             sub events
281             {
282 8     8 1 2322 my $self = shift;
283              
284 8         12 return( @{ $events_arr->{$self->api_version} } );
  8         19  
285             }
286              
287             sub everything
288             {
289 4     4 1 2228 my $self = shift;
290              
291 4         12 return( ( ( $self->methods() ), ( $self->events() ) ) );
292             }
293              
294             ###
295             ### Predicates
296             ###
297              
298             sub is_method
299             {
300 511     511 1 142956 my( $self, $name ) = ( shift, shift );
301              
302 511 100       1280 return $FALSE unless( defined( $name ) );
303              
304 507 100       1098 return( exists( $methods->{$self->api_version}->{$name} )
305             ? $TRUE
306             : $FALSE );
307             }
308              
309             sub is_event
310             {
311 314     314 1 91589 my( $self, $name ) = ( shift, shift );
312              
313 314 100       802 return $FALSE unless( defined( $name ) );
314              
315 310 100       4377 return( exists( $events->{$self->api_version}->{$name} )
316             ? $TRUE
317             : $FALSE );
318             }
319              
320             sub in_api
321             {
322 331     331 1 734 my( $self, $name ) = ( shift, shift );
323              
324 331 100       850 return $FALSE unless( defined( $name ) );
325              
326 327 100 100     849 return( ( $self->is_method( $name ) or $self->is_event( $name ) )
327             ? $TRUE
328             : $FALSE );
329             }
330              
331             ###
332             ### Accessors
333             ###
334              
335             sub api_version
336             {
337 848     848 1 1103 my $self = shift;
338              
339 848         8318 return( $self->{version} );
340             }
341              
342             ###
343             ### Method aliases
344             ###
345              
346 2     2   18 no warnings 'once';
  2         3  
  2         285  
347             *version = *api_version;
348             *versions = *api_versions;
349              
350             1;
351              
352             __END__