File Coverage

blib/lib/POE/Component/Client/opentick/Record.pm
Criterion Covered Total %
statement 89 89 100.0
branch 20 26 76.9
condition 5 6 83.3
subroutine 23 23 100.0
pod 16 16 100.0
total 153 160 95.6


line stmt bran cond sub pod time code
1             package POE::Component::Client::opentick::Record;
2             #
3             # opentick.com POE client
4             #
5             # Protocol message response encapsulation, corresponding with a single
6             # RECORD of data.
7             #
8             # infi/2008
9             #
10             # $Id: Record.pm 56 2009-01-08 16:51:14Z infidel $
11             #
12             # See comments at beginning of Protocol.pm for implementation
13             #
14             # Full user POD documentation after __END__
15             #
16              
17 3     3   1472 use strict;
  3         20  
  3         109  
18 3     3   18 use warnings;
  3         6  
  3         84  
19 3     3   15 use Data::Dumper;
  3         5  
  3         138  
20              
21             # Ours
22 3     3   85 use POE::Component::Client::opentick::Constants;
  3         6  
  3         515  
23 3     3   592 use POE::Component::Client::opentick::Util;
  3         6  
  3         311  
24              
25 3     3   24 use vars qw( $VERSION $TRUE $FALSE $KEEP $DELETE );
  3         6  
  3         6101  
26              
27             ###
28             ### Variables
29             ###
30              
31             ($VERSION) = q$Revision: 56 $ =~ /(\d+)/;
32             *TRUE = \1;
33             *FALSE = \0;
34             *KEEP = \0;
35             *DELETE = \1;
36              
37             # FIXME: comment out the unneeded entries when testing is complete.
38             my $field_names = {
39             OTConstant('OT_LOGIN') => [
40             qw( SessionID RedirectFlag RedirectHostName RedirectPortNum ),
41             ],
42             OTConstant('OT_LOGOUT') => [], # none
43             OTConstant('OT_REQUEST_TICK_STREAM') => [],
44             OTConstant('OT_REQUEST_TICK_STREAM_EX') => [],
45             OTConstant('OT_REQUEST_HIST_DATA') => [],
46             OTConstant('OT_REQUEST_HIST_TICKS') => [],
47             OTConstant('OT_REQUEST_LIST_EXCHANGES') => [
48             qw( ExchangeCode ExchangeAvail ExchangeTitle ExchanceDesc ),
49             ],
50             OTConstant('OT_REQUEST_LIST_SYMBOLS') => [
51             qw( Currency Symbol Type Company ),
52             ],
53             OTConstant('OT_REQUEST_EQUITY_INIT') => [],
54             # qw( DataType Currency InstrumentType Company
55             # PrevClosePrice PrevCloseDate AnnualHighPrice AnnualHighDate
56             # AnnualLowPrice AnnualLowDate EarningsPrice EarningsDate
57             # TotalShares AverageVolume CUSIP ISIN
58             # IsUPC11830 IsSmallCap IsTestIssue ),
59             # ],
60             OTConstant('OT_REQUEST_OPTION_CHAIN') => [],
61             OTConstant('OT_REQUEST_OPTION_CHAIN_EX') => [],
62             OTConstant('OT_REQUEST_BOOK_STREAM') => [],
63             OTConstant('OT_HEARTBEAT') => [], # none
64             OTConstant('OT_CANCEL_TICK_STREAM') => [], # none
65             OTConstant('OT_CANCEL_HIST_DATA') => [], # none
66             OTConstant('OT_CANCEL_OPTION_CHAIN') => [], # none
67             OTConstant('OT_CANCEL_BOOK_STREAM') => [], # none
68             OTConstant('OT_REQUEST_SPLITS') => [
69             qw( DataType ToFactor ForFactor
70             DeclarationDate ExecutionDate RecordDate PaymentDate ),
71             ],
72             OTConstant('OT_REQUEST_DIVIDENDS') => [
73             qw( DataType Price DeclarationDate ExecutionDate
74             RecordDate PaymentDate Flags Special ),
75             ],
76             OTConstant('OT_REQUEST_HIST_BOOKS') => [],
77             OTConstant('OT_REQUEST_BOOK_STREAM_EX') => [],
78             OTConstant('OT_REQUEST_OPTION_CHAIN_U') => [],
79             OTConstant('OT_REQUEST_OPTION_INIT') => [
80             qw( DataType UnderlyerSymbol Symbol StrikePrice
81             ContractSize ExpYear ExpMonth ExpDay
82             ExerciseStyle UnderlyerCUSIP Currency OptionMarker ),
83             ],
84             OTConstant('OT_REQUEST_LIST_SYMBOLS_EX') => [],
85             OTConstant('OT_REQUEST_TICK_SNAPSHOT') => [],
86             OTConstant('OT_REQUEST_OPTION_CHAIN_SNAPSHOT') => [],
87             };
88              
89             my $field_datatypes = {
90             OTConstant( 'OT_DATATYPE_QUOTE' ) => [
91             qw( Datatype Timestamp
92             BidSize AskSize BidPrice AskPrice
93             AskExchange Indicator TickIndicator ),
94             ],
95             OTConstant( 'OT_DATATYPE_MMQUOTE' ) => [
96             qw( Datatype Timestamp
97             BidSize AskSize BidPrice AskPrice
98             MMID Indicator TickExchange ),
99             ],
100             OTConstant( 'OT_DATATYPE_TRADE' ) => [
101             qw( Datatype Timestamp
102             Price Size Volume SeqNumber
103             Indicator TickIndicator Flags TickExchange ),
104             ],
105             OTConstant( 'OT_DATATYPE_BBO' ) => [
106             qw( Datatype Timestamp
107             Price Size Side ),
108             ],
109             OTConstant( 'OT_DATATYPE_OHLC' ) => [
110             qw( Datatype Timestamp
111             Open High Low Close Volume ),
112             ],
113             OTConstant( 'OT_DATATYPE_OHL_TODAY' ) => [
114             qw( Open High Low ),
115             ],
116             OTConstant( 'OT_DATATYPE_CANCEL' ) => [
117             qw( OrderRef Size ),
118             ],
119             OTConstant( 'OT_DATATYPE_CHANGE' ) => [
120             qw( OrderRef Price Size ),
121             ],
122             OTConstant( 'OT_DATATYPE_DELETE' ) => [
123             qw( OrderRef DeleteType Side ),
124             ],
125             OTConstant( 'OT_DATATYPE_EXECUTE' ) => [
126             qw( OrderRef Size MatchNumber ),
127             ],
128             OTConstant( 'OT_DATATYPE_ORDER' ) => [
129             qw( OrderRef Price Size Side Display ),
130             ],
131             OTConstant( 'OT_DATATYPE_PRICELEVEL' ) => [
132             qw( Price Size Side LevelId ),
133             ],
134             OTConstant( 'OT_DATATYPE_PURGE' ) => [
135             qw( ECNNameRoot ),
136             ],
137             OTConstant( 'OT_DATATYPE_REPLACE' ) => [
138             qw( OrderRef Price Size Side ),
139             ],
140             OTConstant( 'OT_DATATYPE_EQ_INIT' ) => [
141             qw( DataType Currency InstrumentType Company
142             PrevClosePrice PrevCloseDate AnnualHighPrice AnnualHighDate
143             AnnualLowPrice AnnualLowDate EarningsPrice EarningsDate
144             TotalShares AverageVolume CUSIP ISIN
145             IsUPC11830 IsSmallCap IsTestIssue ),
146             ],
147             OTConstant('OT_DATATYPE_OPTION_INIT') => [
148             qw( DataType UnderlyerSymbol Symbol StrikePrice
149             ContractSize ExpYear ExpMonth ExpDay
150             ExerciseStyle UnderlyerCUSIP Currency OptionMarker ),
151             ],
152             };
153              
154             # Valid arguments that can be passed to the constructor.
155             my $valid_args = {
156             requestid => $KEEP,
157             commandid => $KEEP,
158             datatype => $KEEP,
159             data => $KEEP,
160             };
161              
162             #######################################################################
163             ### Public methods ###
164             #######################################################################
165              
166             sub new
167             {
168 23     23 1 8703 my( $class, @args ) = @_;
169 23 50       77 croak( "$class requires an even number of parameters" ) if( @args & 1 );
170              
171 23         97 my $self = {
172             requestid => undef,
173             commandid => undef,
174             datatype => undef,
175             data => [],
176             };
177              
178 23         75 bless( $self, $class );
179              
180 23         63 $self->initialize( @args );
181              
182 23         74 return( $self );
183             }
184              
185             sub initialize
186             {
187 23     23 1 124 my( $self, %args ) = @_;
188              
189 23         78 for( keys( %args ) )
190             {
191 86 50       319 $self->{lc $_} = $args{$_} if( exists( $valid_args->{lc $_} ) );
192             }
193              
194             # SPECIAL CASES FOR 64-BIT SIMULATION. Really stupid.
195             # See POD documentation for details.
196 23         41 my @fields;
197 23 100 100     128 if( defined( $self->{datatype} )
      66        
198             && ( $self->{datatype} == OTConstant( 'OT_DATATYPE_TRADE' )
199             || $self->{datatype} == OTConstant( 'OT_DATATYPE_EQ_INIT' )
200             || $self->{datatype} == OTConstant( 'OT_DATATYPE_OHLC' ) ) )
201             {
202 3         16 @fields = OT64bit( $self->{datatype} );
203             }
204 23 100       99 $self->_expand_64bit_fields( @fields ) if( @fields );
205             # END special case
206              
207 23         66 return;
208             }
209              
210             #######################################################################
211             ### Accessor methods ###
212             #######################################################################
213              
214             # Requires an arrayref (row) of data to store.
215             sub set_data
216             {
217 1     1 1 3 my $self = shift;
218 1 50       4 my $data = ref( $_[0] ) eq 'ARRAY' ? $_[0] : [ @_ ];
219              
220 1         2 $self->{data} = $data;
221              
222 1         2 return( scalar( @{ $self->{data} = $data } ) );
  1         2  
223             }
224              
225             sub set_datatype
226             {
227 1     1 1 308 my( $self, $datatype ) = @_;
228 1 50       6 return unless( $datatype =~ /^\d+$/ );
229              
230 1         3 return( $self->{datatype} = $datatype );
231             }
232              
233             sub set_command_id
234             {
235 1     1 1 2 my( $self, $cmd_id ) = @_;
236              
237 1         3 return( $self->{commandid} = $cmd_id );
238             }
239              
240             sub get_data
241             {
242 3     3 1 300 my $self = shift;
243              
244 3 100       12 if( ref( $_[0] ) eq 'ARRAY' )
    100          
245             {
246 1         2 @{$_[0]} = @{ $self->get_data_as_arrayref() };
  1         3  
  1         3  
247 1         1 return( @{ $_[0] } );
  1         4  
248             }
249             elsif( ref( $_[0] ) eq 'HASH' )
250             {
251 1         2 %{$_[0]} = %{ $self->get_data_as_hashref() };
  1         4  
  1         4  
252 1         3 return( keys( %{ $_[0] } ) );
  1         5  
253             }
254             else
255             {
256 1         2 return( @{ $self->{data} } );
  1         5  
257             }
258             }
259              
260             sub get_data_as_hashref
261             {
262 1     1 1 1 my( $self ) = @_;
263              
264 1         1 my %hash;
265 1         2 @hash{ $self->get_field_names() } = @{ $self->{data} };
  1         3  
266              
267 1         4 return( \%hash );
268             }
269              
270             sub get_data_as_arrayref
271             {
272 1     1 1 3 return( $_[0]->get_raw_data() );
273             }
274              
275             sub get_raw_data
276             {
277 3     3 1 6 my( $self ) = @_;
278              
279 3         15 return( $self->{data} );
280             }
281              
282             sub as_string
283             {
284 2     2 1 3 my( $self, $separator ) = @_;
285              
286 2 100       8 $separator = ' ' unless( defined( $separator ) );
287              
288 2         3 return( join( $separator, @{ $self->{data} } ) );
  2         12  
289             }
290              
291             sub get_field_names
292             {
293 23     23 1 210 my( $self ) = @_;
294              
295 16         65 my @fields = $self->{datatype}
296             ? exists( $field_datatypes->{ $self->{datatype} } )
297 7         28 ? @{ $field_datatypes->{ $self->{datatype} } }
298             : ()
299             : exists( $field_names->{ $self->{commandid} } )
300 23 50       104 ? @{ $field_names->{ $self->{commandid} } }
    50          
    100          
301             : ();
302             # give them only enough field names to correspond with data!
303 2         6 @fields = @fields[0..$#{ $self->{data} }]
  23         67  
304 23 100       33 if( $#{$self->{data}} < scalar( @fields ) );
305              
306 23         182 return( @fields );
307             }
308              
309             sub get_command_id
310             {
311 3     3 1 6 my( $self ) = @_;
312              
313 3         18 return( $self->{commandid} );
314             }
315              
316             sub get_command_name
317             {
318 2     2 1 9 my( $self ) = @_;
319              
320 2         8 return( OTCommand( $self->{commandid} ) );
321             }
322              
323             sub get_request_id
324             {
325 3     3 1 6 my( $self ) = @_;
326              
327 3         11 return( $self->{requestid} );
328             }
329              
330             sub get_datatype
331             {
332 1     1 1 2 my( $self ) = @_;
333              
334 1         5 return( $self->{datatype} );
335             }
336              
337             # is this an EOD record?
338             sub is_eod
339             {
340 2     2 1 7 my( $self ) = @_;
341              
342 2         14 return( OTeod( $self->{datatype} ) );
343             }
344              
345             ###
346             ### Private methods
347             ###
348              
349             sub _expand_64bit_fields
350             {
351 3     3   7 my( $self, @fields ) = @_;
352              
353 3         24 $self->{data}->[$_] = asc2longlong( $self->{data}->[$_] ) for( @fields );
354              
355 3         9 return;
356             }
357              
358             1;
359              
360             __END__