Skip to content

Commit

Permalink
Merge pull request #405 from crypto-chassis/develop
Browse files Browse the repository at this point in the history
Release
  • Loading branch information
cryptochassis committed Jul 24, 2023
2 parents 5693d89 + af6daee commit 0ea69b4
Show file tree
Hide file tree
Showing 42 changed files with 477 additions and 110 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Expand Up @@ -148,3 +148,5 @@ docs/_build/
# Other
.project
.venv/
target/
obj/
67 changes: 41 additions & 26 deletions README.md
@@ -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,17 +51,16 @@ 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:
* Market data: coinbase, gemini, kraken, kraken-futures, bitstamp, bitfinex, bitmex, binance-us, binance, binance-usds-futures, binance-coin-futures, huobi, huobi-usdt-swap, huobi-coin-swap, okx, erisx (Cboe Digital), kucoin, kucoin-futures, deribit, gateio, gateio-perpetual-futures, cryptocom, bybit, bybit-derivatives, ascendex, bitget, bitget-futures, bitmart, mexc, mexc-futures, whitebit.
* Market Data: coinbase, gemini, kraken, kraken-futures, bitstamp, bitfinex, bitmex, binance-us, binance, binance-usds-futures, binance-coin-futures, huobi, huobi-usdt-swap, huobi-coin-swap, okx, erisx (Cboe Digital), kucoin, kucoin-futures, deribit, gateio, gateio-perpetual-futures, cryptocom, bybit, bybit-derivatives, ascendex, bitget, bitget-futures, bitmart, mexc, mexc-futures, whitebit.
* Execution Management: coinbase, gemini, kraken, kraken-futures, bitstamp, bitfinex, bitmex, binance-us, binance, binance-usds-futures, binance-coin-futures, huobi, huobi-usdt-swap, huobi-coin-swap, okx, erisx (Cboe Digital), kucoin, kucoin-futures, deribit, gateio, gateio-perpetual-futures, cryptocom, bybit, bybit-derivatives, ascendex, bitget, bitget-futures, bitmart, mexc.
* FIX: coinbase, gemini.
* A spot market making application is provided as an end-to-end solution for liquidity providers.
* A single order execution application is provided as an end-to-end solution for executing large orders.
* To spur innovation and industry collaboration, this library is open for use by the public without cost.
* For historical market data, see https://github.com/crypto-chassis/cryptochassis-api-docs.
* We specialize in market data collection, high speed trading system, infrastructure optimization, and proprietary market making. Hire us as engineers, liquidity providers, traders, or asset managers.
* Join us on Discord https://discord.gg/b5EKcp9s8T and Medium https://cryptochassis.medium.com.

Expand Down Expand Up @@ -103,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 -DINSTALL_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 @@ -143,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 All @@ -156,7 +171,7 @@ For a specific exchange and instrument, get recents trades.

**Code 1:**

[C++](example/src/market_data_simple_request/main.cpp) / [Python](binding/python/example/src/market_data_simple_request/main.py)
[C++](example/src/market_data_simple_request/main.cpp) / [Python](binding/python/example/market_data_simple_request/main.py)
```
#include "ccapi_cpp/ccapi_session.h"
namespace ccapi {
Expand Down Expand Up @@ -221,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/src/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 @@ -403,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/src/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 Expand Up @@ -493,7 +508,7 @@ For a specific exchange and instrument, receive order updates.

**Code 2:**

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

**Code:**

[C++](example/src/fix_simple/main.cpp) / [Python](binding/python/example/src/fix_simple/main.py)
[C++](example/src/fix_simple/main.cpp) / [Python](binding/python/example/fix_simple/main.py)
```
#include "ccapi_cpp/ccapi_session.h"
namespace ccapi {
Expand Down Expand Up @@ -880,7 +895,7 @@ An example can be found [here](example/src/market_data_advanced_subscription/mai

#### Enable library logging

[C++](example/src/enable_library_logging/main.cpp) / [Python](binding/python/example/src/enable_library_logging/main.py)
[C++](example/src/enable_library_logging/main.cpp) / [Python](binding/python/example/enable_library_logging/main.py)

Extend a subclass, e.g. `MyLogger`, from class `Logger` and override method `logMessage`. Assign a `MyLogger` pointer to `Logger::logger`. Add one of the following macros in the compiler command line: `CCAPI_ENABLE_LOG_TRACE`, `CCAPI_ENABLE_LOG_DEBUG`, `CCAPI_ENABLE_LOG_INFO`, `CCAPI_ENABLE_LOG_WARN`, `CCAPI_ENABLE_LOG_ERROR`, `CCAPI_ENABLE_LOG_FATAL`. Enable logging if you'd like to inspect raw responses/messages from the exchange for troubleshooting purposes.
```
Expand Down
41 changes: 38 additions & 3 deletions binding/CMakeLists.txt
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,9 +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)
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 @@ -141,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 @@ -212,4 +221,30 @@ add_compile_definitions(CCAPI_ENABLE_EXCHANGE_WHITEBIT)
find_package(ZLIB REQUIRED)
link_libraries(ZLIB::ZLIB)

add_subdirectory(python)
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
@@ -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
@@ -0,0 +1,8 @@
<Project Sdk="Microsoft.NET.Sdk">

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

</Project>
@@ -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");
}
}

0 comments on commit 0ea69b4

Please sign in to comment.