WARNING: in early development; not stable; interface subject to change
The java wrapper, like the python wrapper, extends the underlying C/C++ interface. It uses Java Native Access(JNA) to load and access the underlying DLL, wrapping these calls in a more user-friendly API. Currently(unlike the python wrapper) there is no virtual layer for use on non-windows systems.
IMPORTANT: You still must install the underlying C/C++ modules. You also must be sure the build of these modules matches the build of the Java Runtime Environment(JRE) you plan to use.
NOTE: If the library build is different than your JRE, init() with throw, indicating it can't find the native library in the resource path.
-
Add java/tosdatabridge.jar to your project's classpath.
-
Find the path of the appropriate DLL(version and build) to pass to TOSDataBridge.init(...)
-
Add the requisite API calls and objects found in the io.github.jeog.tosdatabridge package(see below).
-
Compile and run.
An example using java/examples/TimeAndSales:
C:\...\TOSDataBridge\java\examples\TimeAndSales\> javac -classpath "../../tosdatabridge.jar" -d "." src/TimeAndSales.java
C:\...\TOSDataBridge\java\examples\TimeAndSales\> java -classpath "../../tosdatabridge.jar;." TimeAndSales
An example using test/java/TOSDataBridgeTest.java:
C:\...\TOSDataBridge\test\java\> javac -classpath "../../java/tosdatabridge.jar" TOSDataBridgeTest.java
C:\...\TOSDataBridge\test\java\> java -classpath "../../java/tosdatabridge.jar;." TOSDataBridgeTest "../../bin/Release/x64/tos-databridge-0.9-x64.dll"
As mentioned, the java wrapper mirrors the python wrapper in many important ways. It's recommended you skim the (more thorough) python docs and tutorial - even the C/C++ docs - for an explanation of the core concepts. The source is pretty straight forward:
-
TOSDataBridge.java: constants, exceptions, and some of the (high-level) administrative calls.
-
DataBlock.java: user-instantiated object used to pull data from the engine/platform (very similar to python's TOSDB_DataBlock)
-
DataBlockWithDateTime.java: extends DataBlock, includes a DateTime object with each primary data-point
-
DateTime.java: date-time object that wraps the C tm struct with an added millisecond field; returned in DateTimePair<Type> by the 'WithDateTime' methods
-
Topic.java: enum that holds all the topics(LAST, BID, VOLUME etc.) that can be added to the block
import io.github.jeog.tosdatabridge.TOSDataBridge;
try{
// path to the C Lib; tries to load lib and calls connect()
TOSDataBridge.init(".\bin\Release\x64\tos-databridge-0.9-x64.dll");
switch( TOSDataBridge.connectionState() ){
case TOSDataBridge.CONN_NONN:
// Not connected to engine
// TOSDataBridge.connected() == false;
break;
case TOSDataBridge.CONN_ENGINE:
// Only connected to Engine (only access to admin calls)
// TOSDataBridge.connected() == false;
break;
case TOSDataBridge.CONN_ENGINE_TOS:
// Connected to Engine AND TOS Platform (can get data from engine/platform)
// TOSDataBridge.connected() == true;
break;
}
}catch(LibraryNotLoaded){
// init(...) was not successfull or the library was freed
}
There are two types of objects used to get real-time data. Both require a size paramater to indicate the maximum number of (historical) data-points the block can hold.
import io.github.jeog.tosdatabridge.DataBlock;
import io.github.jeog.tosdatabridge.DataBlockWithDateTime;
int blockSz = 10000;
try{
/* only primary data */
DataBlock block = new DataBlock(blockSz);
/* include a DateTime object with each primary data-point
extends DataBlock, adds 'WithDateTime' versions of the get methods */
DataBlockWithDateTime blockDT = new DataBlockWithDateTime(blockSz);
}catch(LibraryNotLoaded){
// init(...) was not successfull or the library was freed
}catch(CLibException){
// an error was thrown from the C Lib (see CError.java)
}
Data are stored in 'streams' which are created internally as a result of topics and items being added.
If we add two topics and three items we have six streams:
SPY | QQQ | GOOG | |
---|---|---|---|
LAST | X | X | X |
VOLUME | X | X | X |
Clearly we need items AND topics. Items(topics) added before any topics(items) exist in the block will be pre-cached, i.e they won't be visible to the interface until a topic(item) is added; likewise if all the items(topics) are removed, thereby leaving only topics(items).
import io.github.jeog.tosdatabridge.Topic
try{
blockDT.addItem("SPY"); // goes into pre-cache
blockDT.addItem("QQQ"); // goes into pre-cache
Set<String> myPrecachedItems = blockDT.getItemsPreCached() // {'SPY','QQQ'}
blockDT.addTopic(Topic.LAST); // pulls items out of pre-cache
Set<String> myItems = blockDT.getItems(); // {'SPY','QQQ'}
Set<Topic> myTopics = blockDT.getTopics(); // {Topic.LAST}
myPrecachedItems = blockDT.getItemsPreCached() // { }
blockDT.removeTopic(Topic.LAST); // items go back into pre-cache
blockDT.containsItem('SPY'); // false
blockDT.containsItemPreCached('SPY') // true
}catch(LibraryNotLoaded){
// init(...) was not successfull or the library was freed
}catch(CLibException){
// an error was thrown from the C Lib (see CError.java)
}catch(InvalidItemOrTopic){
// item string was empty, too long, or null; topic enum was null or NULL_TOPIC
}
Like the C/C++ interfaces we have type-specific calls. If you call the wrong version the C lib will try to (safely) cast the value for you. If it can't it will return ERROR_GET_DATA and java will throw CLibException.
Notice below we use the base classes of the exception hierarchy for illustrative purposes.
import io.github.jeog.tosdatabridge.DateTime.DateTimePair;
try{
switch( TOSDataBridge.getTopicType(Topic.LAST) ){
case TOSDataBridge.TOPIC_IS_LONG:
...
break;
case TOSDataBridge.TOPIC_IS_DOUBLE: /* Topic.LAST stores doubles ... */
// most recent 'LAST' for 'SPY'
Double d = blockDT.getDouble("SPY", Topic.LAST);
if(d == null){
// no data in block yet
}
// 9 data-points older than most recent, with DateTime
DateTimePair<Double> dDT = blockDT.getDoubleWithDateTime("SPY", Topic.LAST, 9);
if(dDT == null){
// no data at this index/position yet
}
break;
case TOSDataBridge.TOPIC_IS_STRING:
...
break;
}
}catch(DataBlockException){ /*extends TOSDataBridgeException, so need to catch first*/
// InvalidItemOrTopic
// DataIndexException
// DirtyMarkerException (see next section)
}catch(TOSDataBridgeException){ /* TOSDataBridgeException is (indirect) base to ALL */
// LibraryNotLoaded
// CLibException
// DataBlockException
}
'WithDateTime' versions return DateTimePair object(s):
public class DateTime {
//...
public static class DateTimePair<T> extends Pair<T,DateTime>{
public final T first; // inherited
public final DateTime second; //inherited
}
//...
}
Methods with a plural type in the name(e.g getStreamSnapshotLongs) return a List(ArrayList).
'StreamSnapshot' calls return an array of data between 'beg' and 'end', with a number of overloads.
'StreamSnapshotFromMarker' calls provide client code a guarantee that it won't miss data between calls, assuming the 'marker' doesn't hit the back of the stream, becoming 'dirty'. (See python and C/C++ docs for a complete explanation.)
try{
switch( TOSDataBridge.getTopicType(Topic.LAST) ){
case TOSDataBridge.TOPIC_IS_LONG:
...
break;
case TOSDataBridge.TOPIC_IS_DOUBLE: /* Topic.LAST stores doubles ... */
// 10 most recent data-points (index 0 to 9, inclusive)
List<Double> dd = blockDT.getStreamSnapshotDoubles("SPY", Topic.LAST, 9, 0);
// ALL valid data-points, with DateTime
List<DateTimePair<Double>> ddDT =
blockDT.getStreamSnapshotDoublesWithDateTime("SPY", Topic.LAST);
/*
* use 'FromMarker' methods (below) to guarantee contiguous data BETWEEN calls
* (see python and C/C++ docs for complete explanation)
*/
// 10 most recent values - THIS MOVES THE MARKER to 'beg' index (0 in this case)
List<DateTimePair<Double>> oldLasts =
blockDT.getStreamSnapshotDoublesWithDateTime("SPY", Topic.LAST, 9);
// add some time between the calls so data can come into stream
Thread.sleep(1000);
// as data comes into the stream the 'marker' is moving backwards
// all the data-points up to the marker - THIS ALSO MOVES THE MARKER (as above)
List<DateTimePair<Double>> newLasts =
blockDT.getStreamSnapshotDoublesFromMarkerWithDateTime("SPY", Topic.LAST);
// concatenating the two lists will guarantee we got ALL the data
newLasts.addAll(oldLasts); // most recent first
for(DateTimePair<Double> p : newLasts){
System.out.println(p);
}
/*
* we can keep using the marker calls in this way; if the 'marker' hits
* the back of the stream(becomes 'dirty') the next 'Marker' call will
* throw DirtyMarkerException; use the 'IgnoreDirty' versions to avoid
* this behavior, allowing it to return as much valid data as possible
*/
break;
case TOSDataBridge.TOPIC_IS_STRING:
...
break;
}
}catch(LibraryNotLoaded){
// init(...) was not successfull or the library was freed
}catch(CLibException){
// an error was thrown from the C Lib (see CError.java)
}catch(InvalidItemOrTopic){
/* item string was empty, too long, or null; topic enum was null or NULL_TOPIC -or-
item or topic is currently not in the block -or-
item or topic is currently in the pre-cache */
}catch(DataIndexException){
// we tried to access data in a position that isn't possible for that block size
}catch((DirtyMarkerException){
// we are NOT using an 'IgnoreDirty' version and getStreamSnapshotFromMarker has a 'dirty' marker (see python/C/C++ docs)
}
Frame methods are used to get most recent data (as strings) in some 'logical' way:
- All the values (getTotalFrame)
- All the topic values for an item (getTopicFrame)
- All the item values for a topic (getItemFrame)
import java.util.Map;
try{
// get most-recent 'LAST' vals (as strings) for ALL items in the block
Map<String,String> itemFrame = blockDT.getItemFrame(Topic.LAST)
// get ALL most-recent topic vals (as strings) for 'SPY'
Map<Topic, String> topicFrame = blockDT.getTopicFrame('SPY')
// get 'matrix' of ALL most-recent topic and item vals (as strings)
Map<String, Map<Topic,String>> totalFrame = blockDT.getTotalFrame();
}catch(LibraryNotLoaded){
// init(...) was not successfull or the library was freed
}catch(CLibException){
// an error was thrown from the C Lib (see CError.java)
}catch(InvalidItemOrTopic){
/* item string was empty, too long, or null; topic enum was null or NULL_TOPIC -or-
item or topic is currently not in the block -or-
item or topic is currently in the pre-cache */
}
/*
* DataBlock's finalize() method calls close() on destruction but we can't
* guarantee when/if that will happend; IT'S RECOMMENDED you explicitly tell
* the C Lib to close the underlying block when you're done with it.
*/
block.close();
blockDT.close();