NAME

POE::Component::Client::opentick::OTClient - An opentick.com otFeed-compatible interface for the POE opentick client.

SYNOPSIS

#!/usr/bin/perl

package OTTest;

use strict;
use POE qw( Component::Client::opentick::OTClient );
use base qw( POE::Component::Client::opentick::OTClient );

sub onLogin {
   my( $self, @args ) = @_;
   print "Logged in.\n";
   $self->requestEquityInit( 'Q' => 'MSFT' );
}

sub onEquityInit
{
   my( $self, $req_id, $cmd_id, $record ) = @_;
   print "Data: ", join( ', ', $record->get_data() ), "\n";
   print "Logging out.\n";
   $self->logout();
}

sub onError {
   my( $self, $req_id, $cmd_id, $error ) = @_;
   print "ERROR: $error\n";
}

sub startup {
   my( $self ) = @_;
   print "Connecting to opentick server...\n";
   $self->login();
}

package main;

use strict;
use POE qw( Component::Client::opentick::OTClient );

my $user = 'CHANGEME';
my $pass = 'CHANGEMETOO';

my $opentick = OTTest->new( $user, $pass );

$poe_kernel->run();
exit(0);

QUICK START FOR THE IMPATIENT

See examples/OTClient-example.pl.

But please read this documentation when you are done. 99% of your questions will be answered below.

DESCRIPTION

This facade interface component allows you to easily interact with opentick.com's market data feed service using the power of POE to handle the asynchronous, simultaneous requests allowed with their protocol.

The full documentation for the otFeed Standard API is available at:

http://www.opentick.com/dokuwiki/doku.php?id=general:standard

The API documentation will not be fully repeated here. This documentation builds upon the material on their website, to explain how to use this particular implementation of their standard.

It is not 100%-compatible with their standard, especially in the returned objects for the event handlers. The entire functionality of the opentick service can be accessed, with many additional features, using the base POE::Component::Client::opentick module. This is primarily provided as a usability bridge, based upon a much more robust and current underlying implementation.

DIFFERENCES WITH THE MAINLINE API

startup() callback

Your main entry point is provided in an additional "startup()" callback.

You should overload this and place your client initialization code into it.

Other callbacks

Instead of having numerous subclasses, you simply receive a POE::Component::Client::opentick::Record object for EACH INDIVIDUAL RECORD of data from the message.

This means that, if you use "requestListExchanges()", and there are 15 exchanges available, "onListExchanges()" will be called 15 times, once per record, and passed a POE::Component::Client::opentick::Record object with each call.

The documentation for POE::Component::Client::opentick::Record covers the available accessor methods in detail.

If it should prove useful in the future to add the remaining classes back into this facade interface, I may consider doing so. It doesn't strike me as necessary at this time, as I generally want the data itself, and both the data and the field names for all response types are available in POE::Component::Client::opentick::Record, so I personally find this interface much cleaner.

Constants

Instead of the $Package::SubPackage::CONSTANT_NAME syntax from the mainline client, use the OTConstant( 'OT_STATUS_OK' ) syntax.

OTConstant() is exported from POE::Component::Client::opentick::Constants.

Example:

use POE::Component::Client::opentick::Constant;

OTConstant('OT_FLAG_HIGH')

It's a bit more terse, and jives with the philosophy, "export behaviour, not data."

new() constructor

The new() constructor of the base class takes the otFeed Standard API $username and $password arguments, but in addition, you can pass any of the parameters available to POE::Component::Client::opentick, to initialize the object in a more complete fashion. Please see the respective documentation for these additional parameters.

You probably shouldn't overload the Notifyee and Events parameters, but others worth noting might be:

AutoLogin
Servers
Port
Realtime
Debug

In addition, so that you don't have to store your username/password in a file on the filesystem, you can simply not pass them in, and use the "OPENTICK_USER" and "OPENTICK_PASS" environment variables (detailed in "ENVIRONMENT" below) to have them passed in automagically.

If you do this, and still pass other arguments, you must use the following constructor syntax:

my $opentick = OTClient->new( undef, undef, AutoLogin => 1, ... );

Since, to follow the API, $username and $password are the first 2 arguments.

setHosts() / clearHosts()

These will work, but they are not paired as hostname:port combinations like you are likely used to.

Because the underlying implementation uses these differently, you should probably just not use these, and just rely upon the hostnames provided within the main application. I keep these updated regularly, and you can additionally use the Servers => [] and Port => XXXXX arguments to new() to explicitly pass them in at object construction time, for the (all-too-often) occasion when opentick's servers become unavailable.

As long as you disconnect and reconnect, you can indeed change the servers using these methods, though.

SUBCLASSING

This module is designed to be subclassed, and you are intended to overload the event handler methods with handlers of your own, as they do nothing by default.

You should overload all methods that you want to trap, named under "EVENT HANDLERS AND CALLBACKS", especially "startup()", as this callback is where you should place your own initialization code for what you wish to do once the opentick client object has been instantiated.

METHODS

new()

my $obj = new( $username, $password, \%args );

Create a new OTClient object, connect to the opentick server, log in, and get ready for action.

RETURNS: blessed $object, or undef

ARGUMENTS:

All arguments are of the hash form Var => Value. new() will carp and exit if they do not follow this form.

$username [ required ] (but see NOTE)
$password [ required ] (but see NOTE)

These are your login credentials for opentick.com. If you do not have an opentick.com account, please visit their website ("SEE ALSO") to create one. Note, that it is not a free service, but it is very inexpensive. (Also, I don't work for them.)

If you do not have an account with them, this component is fairly useless to you, so what are you still doing reading this?

NOTE: A username and password MUST be specified either as arguments to new() or via the "OPENTICK_USER" and/or "OPENTICK_PASS" environment variables (detailed in "ENVIRONMENT" below), or the component will throw an exception and exit.

If you wish to use the environment variables, do so as such:

my $object = new( undef, undef, \%args );

ALL OTHER ARGUMENTS, passed in via the 3rd argument as a hashref, are handed off as options to the constructor for the primary ::opentick component. Please refer to "spawn()" in POE::Component::Client::opentick for details on these arguments.

initialize()

$object->initialize( %args );

This is not part of the official spec. It initializes the object and starts initalizes the object, and starts the appropriate POE sessions. Useful for subclassing.

Put your application startup code in "startup()". This is for OBJECT INSTANCE INITIALIZATION.

OPENTICK API METHODS

The opentick.com API provides several commands that you may send. All of the API requests return a unique numeric $request_id for the particular command you issue. You properly send these commands by using the $object->call() method (or the $poe_kernel->call() method with the session ID of the component), so that you receive a numeric $request_id as a return value. (yield() and post() are asynchronous, and do not return the $request_id).

Getting this $request_id into your client is essential to keep track of and match your individual requests with their corresponding responses.

It is left as an exercise to the implementor (YOU!) as to how best keep track of your requests, although a %hash would work quite well. See the examples/ directory for some examples of how to do this if you are not sure.

Here are the API-related events that you can issue to the POE component, which correspond to the opentick.com API. If and where they deviate from the official otFeed Standard API, it will be noted.

addHost()

$object->addHost( $hostname, $port );

clearHosts()

$object->clearHosts();

getStatus()

$object->getStatus();

isLoggedIn()

$object->isLoggedIn();

setPlatformId()

$object->setPlatformId( $id );

login()

$object->login();

logout()

$object->logout();

getEntityById()

my( $exchange, $symbol ) = $otclient->getEntityById( $request_id );

Works differently from the API; returns a list consisting of the exchange and symbol for which the request was issued. Returns the 2-item list directly, rather than storing into an OTDataEntity object.

requestTickStream()

my $req_id = $object->requestTickStream( $exchange, $symbol [, $flags ] );

requestBookStream()

my $req_id = $object->requestBookStream( $exchange, $symbol, [, $flags ] );

requestMarketDepth()

my $req_id = requestMarketDepth( $exchange, $symbol );

requestOptionChain()

my $req_id = $object->requestOptionChain( $exchange, $symbol, $expMonth, $expYear, $mask );

requestEquityInit()

my $req_id = $object->requestEquityInit( $exchange, $symbol );

requestHistData()

my $req_id = $object->requestHistData( $exchange, $symbol, $startDate, $endDate, $dt, $interval );

requestHistTicks()

my $req_id = requestHistTicks( $exchange, $symbol, $startDate, $endDate, $mask );

requestTodaysOHL()

my $req_id = $object->requestTodaysOHL( $exchange, $symbol );

requestListExchanges()

my $req_id = $object->requestListExchanges();

requestListSymbols()

my $req_id = $object->requestListSymbols( $exchange );

requestHistBooks()

my $req_id = $object->requestHistBooks( $exchange, $symbol, $startDate, $endDate, $mask );

requestOptionInit()

my $req_id = $object->requestOptionInit( $exchange, $symbol, $expMonth, $expYear, $minStrike, $maxStrike, $paramsType );

requestSplits()

my $req_id = $object->requestSplits( $exchange, $symbol, $startDate, $endDate );

requestDividends()

my $req_id = $object->requestDividends( $exchange, $symbol, $startDate, $endDate );

requestTickSnapshot()

my $req_id = requestTickSnapshot( $exchange, $symbol, $mask );

requestOptionChainSnapshot()

my $req_id = $object->requestOptionChainSnapshot( $exchange, $symbol, $expMonth, $expYear, $mask, $minStrike, $maxStrike, $paramsType );

cancelTickStream()

my $cancel_id = $object->cancelTickStream( $req_id );

cancelBookStream()

my $cancel_id = $object->cancelBookStream( $req_id );

cancelMarketDepth()

my $cancel_id = $object->cancelMarketDepth( $req_id );

cancelOptionChain()

my $cancel_id = $object->cancelOptionChain( $req_id );

cancelHistData()

my $cancel_id = $object->cancelHistData( $req_id );

More information regarding the opentick API, exchange codes, required arguments, field definitions, etc., can be found at http://www.opentick.com/dokuwiki/doku.php?id=general:standard

EVENT HANDLERS AND CALLBACKS

The methods listed below are called automatically by OTClient, when receiving responses to requests or at other specified times.

startup()

This is a custom extension to the main API. This method is called after the opentick object initializes, and is a hook for you to start placing your application startup code into, for instance, such commands as "login()", etc.

It is called as an object method, and so receives the object handle as the first parameter, so you can call other object methods from it.

e.g.

sub startup
{
    my( $self ) = @_;

    $self->login();

    return;
}

The remainder of the methods listed below, follow the otFeed Standard API. The otFeed Standard API specifies this list of event handlers, which you may overload to receive notifications for particular events.

They all receive the following arguments (unless otherwise noted):

( $self, $request_id, $command_id, $record )
$self

The object handle.

$request_id

The numeric request ID, to match up with the response from request*

$command_id

The numeric command ID of this request, as delineated in the opentick protocol specification.

$record

An object of type POE::Component::Client::opentick::Record, containing the results of your request, accessible by its class methods.

otFeed Standard API Callbacks:

onLogin()

void -- receives no arguments.

onRestoreConnection()

void -- receives no arguments.

onStatusChanged( $state )

$state -- The new state you have entered. Follows the otFeed Standard API.

onError( $req_id, $cmd_id, $error )

$req_id - The request_id of the request that returned $error

$cmd_id - The command_id of the request that returned $error

$error -- An object of type POE::Component::Client::opentick::Error. But it is overloaded with formatted stringification, if you would prefer to, you may simply print it.

See POE::Component::Client::opentick::Error for class methods.

onMessage()
onMessage( $req_id, $cmd_id, $constant, $message )

$req_id - The request_id of the corresponding request.

$cmd_id - The command_id of the corresponding request.

$constant -- 10 = End of Data, 20 = Request cancelled.

$message -- a $string containing a text message to the same effect.

onListExchanges()
onListSymbols()
onRealtimeTrade()
onRealtimeQuote()
onRealtimeBBO()
onRealtimeMMQuote()
onTodaysOHL()
onEquityInit()
onBookCancel()
onBookChange()
onBookDelete()
onBookExecute()
onBookOrder()
onBookPriceLevel()
onBookPurge()
onBookReplace()
onHistQuote()
onHistMMQuote()
onHistTrade()
onHistBBO()
onHistOHLC()
onHistBookCancel()
onHistBookChange()
onHistBookDelete()
onHistBookExecute()
onHistBookOrder()
onHistBookPriceLevel()
onHistBookPurge()
onHistBookReplace()
onSplit()
onDividend()
onOptionInit()

NOTE: You will NOT receive an "onMessage()" event upon the completion of "requestListExchanges()" or "requestListSymbols()", so plan accordingly.

ENVIRONMENT

This module suite uses the following environment variables:

OPENTICK_USER

OPENTICK_PASS

These are used as a fallback mechanism, in case Username or Password are not passed as arguments to "spawn()" in POE::Component::Client::opentick. If after exhausting these two possibilities, the username and password are not set, the suite will throw an exception and exit.

They are also provided as a security option, since many people do not desire to store passwords directly in their software.

OPENTICK_LIB

This is used in the official opentick otFeed Standard API software. This module suite will also use this environment variable when attempting to locate the original opentick library, to preload constant values used in the protocol.

POE::Component::Client::opentick::Constants attempts to load the original libraries from @INC, and will prepend the directory specified in OPENTICK_LIB to the @INC search path, if it is set.

If the original libraries are not found, this is not a problem; we use our own values. This is only an attempt to maintain derived compatibility with the mainline software itself should they suddenly change features between versions of this software.

SEE ALSO

POE::Component::Client::opentick

The main POE documentation.

http://poe.perl.org/

http://www.opentick.com/

http://www.opentick.com/dokuwiki/doku.php

The examples/ directory of this module's distribution.

ACKNOWLEDGEMENTS

Thank you, Rocco Caputo (dngor) for inventing and unleashing POE upon the world!

AUTHOR

Jason McManus (INFIDEL) - infidel AT cpan.org

LICENSE

Copyright (c) Jason McManus

This module may be used, modified, and distributed under the same terms as Perl itself. Please see the license that came with your Perl distribution for details.

The data from opentick.com are under an entirely separate license that varies according to exchange rules, etc. It is your responsibility to follow the opentick.com and exchange license agreements with the data.

Further details are available on http://www.opentick.com/.