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