org.otfeed Driver is the client-side library (JAR archive), providing access to the Opentick financial data.
Opentick provides client-side drivers in many languages, including CPP, .NET, and Java. Unfortunately, their Java client has inferior quality as compared to the .NET one. At the time of this writing, their Java client has many bugs and introduction of new features in Java code lag behind as comapred to the .NET client.
org.otfeeed presents to the user a different (better) API, as comapred to Opentick's client. Therefore, org.otfeed client can not be used as a drop-in replacement for the Opentick's client.
Following enumerates the differences between org.otfeed Driver, and Opentick's Java client:
First, download the Driver, save it, and make sure that it is on your Java CLASSPATH.
Download Javadoc reference, or use the online one .
Get familiar with the following important interfaces and classes:
org.otfeed.IConnectionFactory
the root interface - factory of the connections. org.otfeed.IConnection
represents connection to the server. org.otfeed.IRequest
represents the handler to a prepared request, allows to sumbit the request, cancel it, etc. org.otfeed.event.IDataDelegate
callback interface (a delegate) for receiving the data events (i.e. quotes, trades, etc.). org.otfeed.event.ICompletionDelegate
callback interface (a delegate) for receiving end-of-data and error events.
Look into the classes in org.otfeed.command
package: these
are the commands that can be sent to the server.
Next step is to look at this code that lists all possible exchanges:
import org.otfeed.*; import org.otfeed.event.*; import org.otfeed.command.*; import org.otfeed.support.*; public class ListExchangesSample { public static void main(String ... av) throws Exception { /// Create connection factory OTConnectionFactory factory = new OTConnectionFactory(); /// Create connection specification, and configure it OTConnectionSpec spec = new OTConnectionSpec(); spec.getHosts().add(new OTHost("feed1.opentick.com:10015")); spec.setUsername("your_username"); spec.setPassword("your_password"); /// Open connection to the server. Use SimpleConnectionStateListener /// to monitor connection progress. IConnection connection = factory.connect(spec, new SimpleConnectionStateListener()); /// Create the command. Use simple inline implementation /// of dataDelegate that just prints the event to the screen. ListExchangesCommand command = new ListExchangesCommand(); command.setDataDelegate(new IDataDelegate<OTExchange>(){ public void onData(OTExchange data) { System.out.println(data); } }); command.setCompletionDelegate(new ICompletionDelegate() { public void onDataEnd(OTError error) { if(error != null) { System.err.println("ERROR: " + error); } else { System.out.println("no more data"); } } }); try { /// Prepare the request (nothing is shipped to the server yet) IRequest request = connection.prepareRequest(command); /// Now we have prepared request. Send it to the server. request.submit(); /// Wait till request finishes request.waitForCompletion(); } finally { /// Disconnect from the server connection.shutdown(); /// Wait till connection is closed and all resources are freed connection.waitForCompletion(); } } }
The most important code in the listing is the one that creates and configures the command:
ListExchangesCommand command = new ListExchangesCommand(); command.setDataDelegate(new IDataDelegate<OTExchange>(){ public void onData(OTExchange data) { System.out.println(data); } }); command.setCompletionDelegate(new ICompletionDelegate() { public void onDataEnd(OTError error) { if(error != null) { System.err.println("ERROR: " + error); } else { System.out.println("no more data"); } } });
completionDelegate
.
This is optional step.IConnectionStateListener
to the factory's connect method.
This listener is used to monitor the connection status.
Lets take another look at the workflow in the listing.
This time we want to stress that all calls there, except the ones that are
named waitForCompletion
are non-blocking. Specifically,
connection instance is returned immediately, while the actual connection
process will be happening in a separate thread. We call it the
event-dispatching thread.
This means, that we may prepare a request, and event call submit method on the request handle well before the real connection is established. The request will be queued and actually sent to the server after connection is established and a successfull logon completed.
One can submit as many requests as she wishes. The requests will be sent to the server in the order they were submitted. The server will respond, and the resulting events will be dispatched to corresponding data handlers (delegates) in the order they come from the server. Note that this order is not well-defined (it depends on how server is processing the requests: answer to a request that was sent last may come first).
All calls to the delegates are made from the same thread (the event-dispatching thread). Therefore, normally there is no need to synchronize the delegate implementation.
There is one event-dispatching thread per connection. Formally, it is possible to open several simultaneous connections from one factory. However, this is very rarely needed and generally is not recommended, because it gives no real benefits. Its much more effective to use a single connection to submit all your requests. Single connection approach has the advantage of having only one event-dispatching thread, and, therefore, eliminates the need to synchroize objects that are common to multiple connections. It takes less local resources (one socket and three threads per connection), and is capable of processing multiple requests simultaneously.