Skip to content

Commit

Permalink
Merge pull request #404 from crypto-chassis/java
Browse files Browse the repository at this point in the history
docs: update README.md
  • Loading branch information
cryptochassis authored Jul 24, 2023
2 parents e82dae8 + 2962760 commit af6daee
Show file tree
Hide file tree
Showing 19 changed files with 360 additions and 129 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -149,3 +149,4 @@ docs/_build/
.project
.venv/
target/
obj/
56 changes: 36 additions & 20 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
Breaking changes in v6: Greetings, Ladies and Gentlemen, we've introduced some simplifications and breaking changes to our build process. Compared to v5, it should be much easier. If you have any questions, feel free to ping us on Discord https://discord.gg/b5EKcp9s8T. Thank you.

<!-- START doctoc generated TOC please keep comment here to allow auto update -->
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
**Table of Contents** *generated with [DocToc](https://github.com/thlorenz/doctoc)*
Expand All @@ -8,7 +6,7 @@ Breaking changes in v6: Greetings, Ladies and Gentlemen, we've introduced some s
- [Branches](#branches)
- [Build](#build)
- [C++](#c)
- [Python](#python)
- [non-C++](#non-c)
- [Constants](#constants)
- [Examples](#examples)
- [Documentations](#documentations)
Expand Down Expand Up @@ -53,7 +51,7 @@ Breaking changes in v6: Greetings, Ladies and Gentlemen, we've introduced some s
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
# ccapi
* A header-only C++ library for streaming market data and executing trades directly from cryptocurrency exchanges (i.e. the connections are between your server and the exchange server without anything in-between).
* Bindings for other languages such as Python are provided.
* Bindings for other languages such as Python and Java are provided.
* Code closely follows Bloomberg's API: https://www.bloomberg.com/professional/support/api-library/.
* It is ultra fast thanks to very careful optimizations: move semantics, regex optimization, locality of reference, lock contention minimization, etc.
* Supported exchanges:
Expand Down Expand Up @@ -102,26 +100,29 @@ Breaking changes in v6: Greetings, Ladies and Gentlemen, we've introduced some s
* "string table overflow at offset \<a>". Try to add optimization flag `-O1` or `-O2`. See https://stackoverflow.com/questions/14125007/gcc-string-table-overflow-error-during-compilation.
* On Windows, if you still encounter resource related issues, try to add optimization flag `-O3 -DNDEBUG`.

### Python
* Require Python 3, SWIG, and CMake.
* SWIG: On macOS, `brew install SWIG`. On Linux, `sudo apt-get install -y swig`. On Windows, http://www.swig.org/Doc4.0/Windows.html#Windows.
### non-C++
* Require SWIG and CMake.
* SWIG: On macOS, `brew install SWIG`. On Linux, `sudo apt-get install -y swig`.
* CMake: https://cmake.org/download/.
* Run the following commands.
```
mkdir binding/build
cd binding/build
rm -rf * (if rebuild from scratch)
cmake -DBUILD_PYTHON=ON .. (optional: -DBUILD_VERSION=<anything>)
cmake -DBUILD_PYTHON=ON -DBUILD_VERSION=1.0.0 .. (Use -DBUILD_JAVA=ON if the target language is Java)
cmake --build .
cmake --install .
```
* If a virtual environment (managed by `venv` or `conda`) is active (i.e. the `activate` script has been evaluated), the package will be installed into the virtual environment rather than globally.
* Currently not working on Windows.
* Python: If a virtual environment (managed by `venv` or `conda`) is active (i.e. the `activate` script has been evaluated), the package will be installed into the virtual environment rather than globally.
* Troubleshoot:
* "CMake Error at python/CMakeLists.txt:... (message): Require Python 3". Try to create and activate a virtual environment (managed by `venv` or `conda`) with Python 3.
* "Could NOT find OpenSSL, try to set the path to OpenSSL root folder in the system variable OPENSSL_ROOT_DIR (missing: OPENSSL_INCLUDE_DIR)". Try `cmake -DOPENSSL_ROOT_DIR=...`. On macOS, you might be missing headers for OpenSSL, `brew install openssl` and `cmake -DOPENSSL_ROOT_DIR=/usr/local/opt/openssl`. On Ubuntu, `sudo apt-get install libssl-dev`. On Windows, `vcpkg install openssl:x64-windows` and `cmake -DOPENSSL_ROOT_DIR=C:/vcpkg/installed/x64-windows-static`.
* "Fatal Python error: Segmentation fault". If the macOS version is relatively new and the Python version is relatively old, please upgrade Python to a relatively new version.
* "‘_PyObject_GC_UNTRACK’ was not declared in this scope". If you use Python >= 3.8, please use SWIG >= 4.0.
* Python:
* "CMake Error at python/CMakeLists.txt:... (message): Require Python 3". Try to create and activate a virtual environment (managed by `venv` or `conda`) with Python 3.
* "Could NOT find OpenSSL, try to set the path to OpenSSL root folder in the system variable OPENSSL_ROOT_DIR (missing: OPENSSL_INCLUDE_DIR)". Try `cmake -DOPENSSL_ROOT_DIR=...`. On macOS, you might be missing headers for OpenSSL, `brew install openssl` and `cmake -DOPENSSL_ROOT_DIR=/usr/local/opt/openssl`. On Ubuntu, `sudo apt-get install libssl-dev`. On Windows, `vcpkg install openssl:x64-windows` and `cmake -DOPENSSL_ROOT_DIR=C:/vcpkg/installed/x64-windows-static`.
* "Fatal Python error: Segmentation fault". If the macOS version is relatively new and the Python version is relatively old, please upgrade Python to a relatively new version.
* "‘_PyObject_GC_UNTRACK’ was not declared in this scope". If you use Python >= 3.8, please use SWIG >= 4.0.
* Java:
* "Could NOT find JNI (missing: JAVA_INCLUDE_PATH JAVA_INCLUDE_PATH2 JAVA_AWT_INCLUDE_PATH)". Check that the environment variable `JAVA_HOME` is correct.
* "../Main.java:1: error: package com.cryptochassis.ccapi does not exist". Check that `javac`'s classpath includes `binding/build/java/packaging/1.0.0/ccapi-1.0.0.jar`.
* "Exception in thread "main" java.lang.UnsatisfiedLinkError: no ccapi_binding_java in java.library.path: ...". Check that `java`'s `java.library.path` property includes `binding/build/java/packaging/1.0.0`. See https://stackoverflow.com/questions/1403788/java-lang-unsatisfiedlinkerror-no-dll-in-java-library-path.

## Constants
[`include/ccapi_cpp/ccapi_macro.h`](include/ccapi_cpp/ccapi_macro.h)
Expand All @@ -142,8 +143,23 @@ cmake --build . --target <example-name>

[Python](binding/python/example)
* Python API is nearly identical to C++ API and covers nearly all the functionalities from C++ API.
* Build and install the Python binding as shown [above](#python).
* Run `python3 main.py`.
* Build and install the Python binding as shown [above](#non-c).
* Inside a concrete example directory (e.g. binding/python/example/market_data_simple_subscription), run
```
python3 main.py
```

[Java](binding/java/example)
* Java API is nearly identical to C++ API and covers nearly all the functionalities from C++ API.
* Build and install the Java binding as shown [above](#non-c).
* Inside a concrete example directory (e.g. binding/python/example/market_data_simple_subscription), run
```
mkdir build
cd build
rm -rf * (if rebuild from scratch)
javac -cp ../../../../build/java/packaging/1.0.0/ccapi-1.0.0.jar -d . ../Main.java
java -cp .:../../../../build/java/packaging/1.0.0/ccapi-1.0.0.jar -Djava.library.path=../../../../build/java/packaging/1.0.0 Main
```

## Documentations

Expand Down Expand Up @@ -220,15 +236,15 @@ Bye
```
* Request operation types: `GET_INSTRUMENT`, `GET_INSTRUMENTS`, `GET_RECENT_TRADES`, `GET_RECENT_AGG_TRADES`(only applicable to binance family: https://binance-docs.github.io/apidocs/spot/en/#compressed-aggregate-trades-list).
* Request parameter names: `LIMIT`, `INSTRUMENT_TYPE`. Instead of these convenient names you can also choose to use arbitrary parameter names and they will be passed to the exchange's native API. See [this example](example/src/market_data_advanced_request/main.cpp).
* Message's `time` represents the exchange's reported timestamp. Its `timeReceived` represents the library's receiving timestamp. `time` can be retrieved by `getTime` method and `timeReceived` can be retrieved by `getTimeReceived` method. (For Python, please use `getTimeUnix` and `getTimeReceivedUnix` methods or `getTimeISO` and `getTimeReceivedISO` methods).
* Message's `time` represents the exchange's reported timestamp. Its `timeReceived` represents the library's receiving timestamp. `time` can be retrieved by `getTime` method and `timeReceived` can be retrieved by `getTimeReceived` method. (For non-C++, please use `getTimeUnix` and `getTimeReceivedUnix` methods or `getTimeISO` and `getTimeReceivedISO` methods).

**Objective 2:**

For a specific exchange and instrument, whenever the best bid's or ask's price or size changes, print the market depth snapshot at that moment.

**Code 2:**

[C++](example/src/market_data_simple_subscription/main.cpp) / [Python](binding/python/example/market_data_simple_subscription/main.py)
[C++](example/src/market_data_simple_subscription/main.cpp) / [Python](binding/python/example/market_data_simple_subscription/main.py) / [Java](binding/java/example/market_data_simple_subscription/Main.java)
```
#include "ccapi_cpp/ccapi_session.h"
namespace ccapi {
Expand Down Expand Up @@ -402,7 +418,7 @@ For a specific exchange and instrument, submit a simple limit order.

**Code 1:**

[C++](example/src/execution_management_simple_request/main.cpp) / [Python](binding/python/example/execution_management_simple_request/main.py)
[C++](example/src/execution_management_simple_request/main.cpp) / [Python](binding/python/example/execution_management_simple_request/main.py) / [Java](binding/java/example/execution_management_simple_request/Main.java)
```
#include "ccapi_cpp/ccapi_session.h"
namespace ccapi {
Expand Down
33 changes: 28 additions & 5 deletions binding/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ project(${NAME} LANGUAGES CXX)

list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}")

if(POLICY CMP0122)
cmake_policy(SET CMP0122 NEW)
endif()

# Apple: Don't modify install_name when touching RPATH.
if(POLICY CMP0068)
cmake_policy(SET CMP0068 NEW)
Expand Down Expand Up @@ -73,13 +77,14 @@ else()
endif()

option(BUILD_PYTHON "Build Python Library" OFF)
option(INSTALL_PYTHON "Install Python Library" OFF)
message(STATUS "Build Python: ${BUILD_PYTHON}")

option(BUILD_JAVA "Build Java Library" OFF)
option(INSTALL_JAVA "Install Java Library" OFF)
message(STATUS "Build Java: ${BUILD_JAVA}")

option(BUILD_CSHARP "Build C# Library" OFF)
message(STATUS "Build C#: ${BUILD_CSHARP}")

set(CMAKE_CXX_STANDARD 17)
if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pthread")
Expand Down Expand Up @@ -145,7 +150,7 @@ link_libraries(OpenSSL::Crypto OpenSSL::SSL)

set(CMAKE_POSITION_INDEPENDENT_CODE ON)
set(SOURCE_LOGGER ${CCAPI_PROJECT_DIR}/binding/ccapi_logger.cpp)
set(CMAKE_SWIG_FLAGS)
# set(CMAKE_SWIG_FLAGS)
find_package(SWIG REQUIRED)
include(UseSWIG)
if(BUILD_TEST)
Expand Down Expand Up @@ -216,12 +221,30 @@ add_compile_definitions(CCAPI_ENABLE_EXCHANGE_WHITEBIT)
find_package(ZLIB REQUIRED)
link_libraries(ZLIB::ZLIB)

set(SWIG_INTERFACE ${CCAPI_PROJECT_DIR}/binding/swig_interface.i)

if(BUILD_PYTHON)
configure_file(
swig_interface.i.in
${CMAKE_BINARY_DIR}/python/swig_interface.i
@ONLY)
set(SWIG_INTERFACE ${CMAKE_BINARY_DIR}/python/swig_interface.i)
add_subdirectory(python)
endif()

if(BUILD_JAVA)
configure_file(
swig_interface.i.in
${CMAKE_BINARY_DIR}/java/swig_interface.i
@ONLY)
set(SWIG_INTERFACE ${CMAKE_BINARY_DIR}/java/swig_interface.i)
add_subdirectory(java)
endif()

if(BUILD_CSHARP)
file(READ csharp/swig_interface_ccapi_language_specific.i SWIG_INTERFACE_CCAPI_LANGUAGE_SPECIFIC)
configure_file(
swig_interface.i.in
${CMAKE_BINARY_DIR}/csharp/swig_interface.i
@ONLY)
set(SWIG_INTERFACE ${CMAKE_BINARY_DIR}/csharp/swig_interface.i)
add_subdirectory(csharp)
endif()
70 changes: 70 additions & 0 deletions binding/csharp/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
set(NAME binding_csharp)
project(${NAME})
set(SWIG_TARGET_NAME ccapi_${NAME})

# Find dotnet cli
find_program(DOTNET_EXECUTABLE NAMES dotnet REQUIRED)
if(NOT DOTNET_EXECUTABLE)
message(FATAL_ERROR "Check for dotnet Program: not found")
else()
message(STATUS "Found dotnet Program: ${DOTNET_EXECUTABLE}")
endif()

execute_process(
COMMAND ${DOTNET_EXECUTABLE} --version
OUTPUT_VARIABLE DOTNET_EXECUTABLE_VERSION
OUTPUT_STRIP_TRAILING_WHITESPACE
)
message(STATUS "Dotnet version: ${DOTNET_EXECUTABLE_VERSION}")

# set(CSHARP_DOMAIN_NAME "cryptochassis")
# set(CSHARP_DOMAIN_EXTENSION "com")

# set(CSHARP_GROUP "${CSHARP_DOMAIN_EXTENSION}.${CSHARP_DOMAIN_NAME}")
# set(CSHARP_ARTIFACT "ccapi")

set(CSHARP_NAMESPACE "ccapi")

set_property(SOURCE ${SWIG_INTERFACE} PROPERTY CPLUSPLUS ON)
set_property(SOURCE ${SWIG_INTERFACE} PROPERTY COMPILE_OPTIONS "-namespace;${CSHARP_NAMESPACE};-dllimport;${SWIG_TARGET_NAME}.so")
# set_property(SOURCE ${SWIG_INTERFACE} PROPERTY COMPILE_OPTIONS "-package;${CSHARP_PACKAGE};-doxygen")

swig_add_library(${SWIG_TARGET_NAME}
LANGUAGE csharp
OUTPUT_DIR ${CMAKE_BINARY_DIR}/csharp/${SWIG_TARGET_NAME}
SOURCES ${SWIG_INTERFACE} ${SOURCE_LOGGER})

if(NOT CCAPI_LEGACY_USE_WEBSOCKETPP)
add_dependencies(${SWIG_TARGET_NAME} boost rapidjson hffix)
endif()
# set_property(TARGET ${SWIG_TARGET_NAME} PROPERTY SWIG_USE_TARGET_INCLUDE_DIRECTORIES ON)
# target_include_directories(${SWIG_TARGET_NAME}
# PRIVATE
# ${JNI_INCLUDE_DIRS}
# )



set(PACKAGING_DIR packaging)
set(PACKAGING_DIR_FULL ${CMAKE_CURRENT_BINARY_DIR}/${PACKAGING_DIR}/${BUILD_VERSION})
file(MAKE_DIRECTORY ${PACKAGING_DIR_FULL})

set(SRC_DIR_FULL ${CMAKE_CURRENT_BINARY_DIR}/src)
file(MAKE_DIRECTORY ${SRC_DIR_FULL})

configure_file(
ccapi.csproj.in
${SRC_DIR_FULL}/ccapi.csproj
@ONLY)
set(CSHARP_PACKAGING_TARGET_NAME csharp_${PACKAGING_DIR})
add_custom_target(${CSHARP_PACKAGING_TARGET_NAME} ALL
COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_BINARY_DIR}/${SWIG_TARGET_NAME}/*.cs ${SRC_DIR_FULL}
# COMMAND ${DOTNET_EXECUTABLE} build -c ${CMAKE_BUILD_TYPE} ccapi.csproj
COMMAND ${DOTNET_EXECUTABLE} build -c ${CMAKE_BUILD_TYPE} -o ${PACKAGING_DIR_FULL} ccapi.csproj
COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_FILE:${SWIG_TARGET_NAME}> ${PACKAGING_DIR_FULL}
WORKING_DIRECTORY ${SRC_DIR_FULL}
)
add_dependencies(${CSHARP_PACKAGING_TARGET_NAME} ${SWIG_TARGET_NAME})

# COMMAND ${Java_JAVAC_EXECUTABLE} -d ${PACKAGING_DIR_FULL} ${CMAKE_CURRENT_BINARY_DIR}/${SWIG_TARGET_NAME}/*.java
# COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_FILE:${SWIG_TARGET_NAME}> ${PACKAGING_DIR_FULL}
8 changes: 8 additions & 0 deletions binding/csharp/ccapi.csproj.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<Nullable>enable</Nullable>
</PropertyGroup>

</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
class MainProgram
{
class MyEventHandler : ccapi.EventHandler {
public override bool ProcessEvent(ccapi.Event event_, ccapi.Session session) {
System.Console.WriteLine(System.String.Format("Received an event:\n%s", event_.ToStringPretty(2, 2)));
return true;
}
}
static void Main(string[] args)
{
if(System.Environment.GetEnvironmentVariable("OKX_API_KEY") is null) {
System.Console.Error.WriteLine("Please set environment variable OKX_API_KEY");
return;
}
if(System.Environment.GetEnvironmentVariable("OKX_API_SECRET") is null) {
System.Console.Error.WriteLine("Please set environment variable OKX_API_SECRET");
return;
}
if(System.Environment.GetEnvironmentVariable("OKX_API_PASSPHRASE") is null) {
System.Console.Error.WriteLine("Please set environment variable OKX_API_PASSPHRASE");
return;
}
var eventHandler = new MyEventHandler();
var option = new ccapi.SessionOptions();
var config = new ccapi.SessionConfigs();
var session = new ccapi.Session(option, config, eventHandler);
var request = new ccapi.Request(Request.Operation.CREATE_ORDER, "okx", "BTC-USDT");
var param = new ccapi.MapStringString();
param.Add("SIDE","BUY");
param.Add("QUANTITY","0.0005");
param.Add("LIMIT_PRICE","20000");
request.AppendParam(param);
session.SendRequest(request);
System.Threading.Thread.Sleep(10000);
session.Stop();
System.Console.WriteLine("Bye");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
<Nullable>enable</Nullable>
<CcapiLibraryPath>to be provided in command line</CcapiLibraryPath>
</PropertyGroup>
<ItemGroup>
<Reference Include="ccapi">
<HintPath>$(CcapiLibraryPath)</HintPath>
</Reference>
</ItemGroup>
</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
class MainProgram
{
class MyEventHandler : ccapi.EventHandler {
public override bool ProcessEvent(ccapi.Event event_, ccapi.Session session) {
if (event_.GetType_() == ccapi.Event.Type.SUBSCRIPTION_DATA) {
foreach (var message in event_.GetMessageList()) {
System.Console.WriteLine(System.String.Format("Best bid and ask at {0} are:", message.GetTimeISO()));
foreach (var element in message.GetElementList()){
var elementNameValueMap = element.GetNameValueMap();
foreach(var entry in elementNameValueMap)
{
var name = entry.Key;
var value = entry.Value;
System.Console.WriteLine(System.String.Format(" {0} = {1}", name, value));
}
}
}
}
return true;
}
}
static void Main(string[] args)
{
var eventHandler = new MyEventHandler();
var option = new ccapi.SessionOptions();
var config = new ccapi.SessionConfigs();
var session = new ccapi.Session(option, config, eventHandler);
var subscriptionList = new ccapi.SubscriptionList();
subscriptionList.Add(new ccapi.Subscription("okx", "BTC-USDT", "MARKET_DEPTH"));
session.Subscribe(subscriptionList);
System.Threading.Thread.Sleep(10000);
session.Stop();
System.Console.WriteLine("Bye");
}
}
13 changes: 13 additions & 0 deletions binding/csharp/example/market_data_simple_subscription/main.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
<Nullable>enable</Nullable>
<CcapiLibraryPath>to be provided in command line</CcapiLibraryPath>
</PropertyGroup>
<ItemGroup>
<Reference Include="ccapi">
<HintPath>$(CcapiLibraryPath)</HintPath>
</Reference>
</ItemGroup>
</Project>
2 changes: 2 additions & 0 deletions binding/csharp/swig_interface_ccapi_language_specific.i
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
%rename("%(camelcase)s", %$isfunction, %$ismember, %$ispublic) "";
%rename("%(regex:/^(toString|getType|setType)$/\\u\\1_/)s") "";
Loading

0 comments on commit af6daee

Please sign in to comment.