From 8bd2082728f5ae4ac9e6a48f06923c2ac1124e10 Mon Sep 17 00:00:00 2001 From: Crypto Chassis Date: Thu, 6 Jul 2023 11:27:41 -0700 Subject: [PATCH 1/8] docs: update README.md --- README.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/README.md b/README.md index ada42fa0..fefa3a36 100644 --- a/README.md +++ b/README.md @@ -57,13 +57,12 @@ Breaking changes in v6: Greetings, Ladies and Gentlemen, we've introduced some s * 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. From d32f42b11ecebcc1d234e5cca6d133896187d551 Mon Sep 17 00:00:00 2001 From: Crypto Chassis Date: Tue, 18 Jul 2023 14:26:15 -0700 Subject: [PATCH 2/8] feat: add java binding --- .gitignore | 1 + README.md | 14 ++-- binding/CMakeLists.txt | 14 +++- binding/java/CMakeLists.txt | 47 ++++++++++++ .../Main.java | 46 +++++++++++ .../market_data_simple_subscription/Main.java | 48 ++++++++++++ binding/python/CMakeLists.txt | 76 +++++++------------ .../{src => }/enable_library_logging/main.py | 0 .../user_specified_cmake_include.cmake | 0 .../main.py | 0 .../main.py | 0 .../example/{src => }/fix_simple/main.py | 0 .../{src => }/handle_exception/main.py | 0 .../market_data_multiple_subscription/main.py | 7 +- .../market_data_simple_request/main.py | 0 .../market_data_simple_subscription/main.py | 0 binding/python/example/src/__init__.py | 0 .../src/enable_library_logging/__init__.py | 0 .../__init__.py | 0 .../__init__.py | 0 .../python/example/src/fix_simple/__init__.py | 0 .../example/src/handle_exception/__init__.py | 0 .../__init__.py | 0 .../market_data_simple_request/__init__.py | 0 .../__init__.py | 0 binding/python/setup.py.in | 1 + include/ccapi_cpp/ccapi_fix_connection.h | 6 +- include/ccapi_cpp/ccapi_queue.h | 2 +- include/ccapi_cpp/service/ccapi_fix_service.h | 2 +- 29 files changed, 199 insertions(+), 65 deletions(-) create mode 100644 binding/java/CMakeLists.txt create mode 100644 binding/java/example/execution_management_simple_request/Main.java create mode 100644 binding/java/example/market_data_simple_subscription/Main.java rename binding/python/example/{src => }/enable_library_logging/main.py (100%) rename binding/python/example/{src => }/enable_library_logging/user_specified_cmake_include.cmake (100%) rename binding/python/example/{src => }/execution_management_simple_request/main.py (100%) rename binding/python/example/{src => }/execution_management_simple_subscription/main.py (100%) rename binding/python/example/{src => }/fix_simple/main.py (100%) rename binding/python/example/{src => }/handle_exception/main.py (100%) rename binding/python/example/{src => }/market_data_multiple_subscription/main.py (84%) rename binding/python/example/{src => }/market_data_simple_request/main.py (100%) rename binding/python/example/{src => }/market_data_simple_subscription/main.py (100%) delete mode 100644 binding/python/example/src/__init__.py delete mode 100644 binding/python/example/src/enable_library_logging/__init__.py delete mode 100644 binding/python/example/src/execution_management_simple_request/__init__.py delete mode 100644 binding/python/example/src/execution_management_simple_subscription/__init__.py delete mode 100644 binding/python/example/src/fix_simple/__init__.py delete mode 100644 binding/python/example/src/handle_exception/__init__.py delete mode 100644 binding/python/example/src/market_data_multiple_subscription/__init__.py delete mode 100644 binding/python/example/src/market_data_simple_request/__init__.py delete mode 100644 binding/python/example/src/market_data_simple_subscription/__init__.py diff --git a/.gitignore b/.gitignore index 1dc60a1b..d96705ae 100644 --- a/.gitignore +++ b/.gitignore @@ -148,3 +148,4 @@ docs/_build/ # Other .project .venv/ +target/ diff --git a/README.md b/README.md index fefa3a36..dad30465 100644 --- a/README.md +++ b/README.md @@ -111,7 +111,7 @@ Breaking changes in v6: Greetings, Ladies and Gentlemen, we've introduced some s mkdir binding/build cd binding/build rm -rf * (if rebuild from scratch) -cmake -DBUILD_PYTHON=ON -DINSTALL_PYTHON=ON .. (optional: -DBUILD_VERSION=) +cmake -DBUILD_PYTHON=ON .. (optional: -DBUILD_VERSION=) cmake --build . cmake --install . ``` @@ -155,7 +155,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 { @@ -228,7 +228,7 @@ For a specific exchange and instrument, whenever the best bid's or ask's price o **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) ``` #include "ccapi_cpp/ccapi_session.h" namespace ccapi { @@ -402,7 +402,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) ``` #include "ccapi_cpp/ccapi_session.h" namespace ccapi { @@ -492,7 +492,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 { @@ -735,7 +735,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 { @@ -879,7 +879,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. ``` diff --git a/binding/CMakeLists.txt b/binding/CMakeLists.txt index df075259..700487fa 100644 --- a/binding/CMakeLists.txt +++ b/binding/CMakeLists.txt @@ -76,6 +76,10 @@ 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}") + set(CMAKE_CXX_STANDARD 17) if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pthread") @@ -212,4 +216,12 @@ add_compile_definitions(CCAPI_ENABLE_EXCHANGE_WHITEBIT) find_package(ZLIB REQUIRED) link_libraries(ZLIB::ZLIB) -add_subdirectory(python) +set(SWIG_INTERFACE ${CCAPI_PROJECT_DIR}/binding/swig_interface.i) + +if(BUILD_PYTHON) + add_subdirectory(python) +endif() + +if(BUILD_JAVA) + add_subdirectory(java) +endif() diff --git a/binding/java/CMakeLists.txt b/binding/java/CMakeLists.txt new file mode 100644 index 00000000..48260a82 --- /dev/null +++ b/binding/java/CMakeLists.txt @@ -0,0 +1,47 @@ +set(NAME binding_java) +project(${NAME}) +set(SWIG_TARGET_NAME ccapi_${NAME}) + +# Find Java and JNI +find_package(Java COMPONENTS Development REQUIRED) +message(STATUS "Java_VERSION: ${Java_VERSION}") +message(STATUS "Java_JAVA_EXECUTABLE: ${Java_JAVA_EXECUTABLE}") +find_package(JNI REQUIRED) +message(STATUS "JNI_FOUND: ${JNI_FOUND}") + +set(JAVA_DOMAIN_NAME "cryptochassis") +set(JAVA_DOMAIN_EXTENSION "com") + +set(JAVA_GROUP "${JAVA_DOMAIN_EXTENSION}.${JAVA_DOMAIN_NAME}") +set(JAVA_ARTIFACT "ccapi") + +set(JAVA_PACKAGE "${JAVA_GROUP}.${JAVA_ARTIFACT}") + +set_property(SOURCE ${SWIG_INTERFACE} PROPERTY CPLUSPLUS ON) +set_property(SOURCE ${SWIG_INTERFACE} PROPERTY COMPILE_OPTIONS "-package;${JAVA_PACKAGE};-doxygen") + +swig_add_library(${SWIG_TARGET_NAME} + LANGUAGE java + OUTPUT_DIR ${CMAKE_BINARY_DIR}/java/${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(JAVA_PACKAGING_TARGET_NAME java_${PACKAGING_DIR}) +add_custom_target(${JAVA_PACKAGING_TARGET_NAME} ALL + COMMAND ${Java_JAVAC_EXECUTABLE} -d ${PACKAGING_DIR_FULL} ${CMAKE_CURRENT_BINARY_DIR}/${SWIG_TARGET_NAME}/*.java + COMMAND ${Java_JAR_EXECUTABLE} cf ${JAVA_ARTIFACT}-${BUILD_VERSION}.jar ${JAVA_DOMAIN_EXTENSION}/${JAVA_DOMAIN_NAME}/${JAVA_ARTIFACT}/** + COMMAND ${CMAKE_COMMAND} -E copy $ ${PACKAGING_DIR_FULL} + WORKING_DIRECTORY ${PACKAGING_DIR_FULL} +) +add_dependencies(${JAVA_PACKAGING_TARGET_NAME} ${SWIG_TARGET_NAME}) diff --git a/binding/java/example/execution_management_simple_request/Main.java b/binding/java/example/execution_management_simple_request/Main.java new file mode 100644 index 00000000..b9329ba5 --- /dev/null +++ b/binding/java/example/execution_management_simple_request/Main.java @@ -0,0 +1,46 @@ +import com.cryptochassis.ccapi.EventHandler; +import com.cryptochassis.ccapi.SessionOptions; +import com.cryptochassis.ccapi.SessionConfigs; +import com.cryptochassis.ccapi.Session; +import com.cryptochassis.ccapi.Request; +import com.cryptochassis.ccapi.Event; +import com.cryptochassis.ccapi.map_string_string; + +public class Main { + static class MyEventHandler extends EventHandler { + @Override + public boolean processEvent(Event event, Session session) { + System.out.println(String.format("Received an event:\n%s", event.toStringPretty(2, 2))); + return true; + } + } + public static void main(String[] args) { + if(System.getenv("BINANCE_API_KEY") == null) { + System.err.println("Please set environment variable BINANCE_API_KEY"); + } + if(System.getenv("BINANCE_API_SECRET") == null) { + System.err.println("Please set environment variable BINANCE_API_SECRET"); + } + System.loadLibrary("ccapi_binding_java"); + var eventHandler = new MyEventHandler(); + var option = new SessionOptions(); + var config = new SessionConfigs(); + var session = new Session(option, config, eventHandler); + var request = new Request(Request.Operation.CREATE_ORDER, "binance", "BTCUSDT"); + var param = new map_string_string(); + param.put("SIDE","BUY"); + param.put("QUANTITY","0.0005"); + param.put("LIMIT_PRICE","20000"); + request.appendParam(param); + session.sendRequest(request); + try + { + Thread.sleep(10000); + } + catch(InterruptedException e) + { + } + session.stop(); + System.out.println("Bye"); + } +} diff --git a/binding/java/example/market_data_simple_subscription/Main.java b/binding/java/example/market_data_simple_subscription/Main.java new file mode 100644 index 00000000..5839f336 --- /dev/null +++ b/binding/java/example/market_data_simple_subscription/Main.java @@ -0,0 +1,48 @@ +import com.cryptochassis.ccapi.EventHandler; +import com.cryptochassis.ccapi.SessionOptions; +import com.cryptochassis.ccapi.SessionConfigs; +import com.cryptochassis.ccapi.Session; +import com.cryptochassis.ccapi.Subscription; +import com.cryptochassis.ccapi.SubscriptionList; +import com.cryptochassis.ccapi.Event; + +public class Main { + static class MyEventHandler extends EventHandler { + @Override + public boolean processEvent(Event event, Session session) { + if (event.getType() == Event.Type.SUBSCRIPTION_DATA) { + for (var message : event.getMessageList()) { + System.out.println(String.format("Best bid and ask at %s are:", message.getTimeISO())); + for (var element : message.getElementList()){ + var elementNameValueMap = element.getNameValueMap(); + for (var entry : elementNameValueMap.entrySet()){ + var name = entry.getKey(); + var value = entry.getValue(); + System.out.println(String.format(" %s = %s", name, value)); + } + } + } + } + return true; + } + } + public static void main(String[] args) { + System.loadLibrary("ccapi_binding_java"); + var eventHandler = new MyEventHandler(); + var option = new SessionOptions(); + var config = new SessionConfigs(); + var session = new Session(option, config, eventHandler); + var subscriptionList = new SubscriptionList(); + subscriptionList.add(new Subscription("coinbase", "BTC-USD", "MARKET_DEPTH")); + session.subscribe(subscriptionList); + try + { + Thread.sleep(10000); + } + catch(InterruptedException e) + { + } + session.stop(); + System.out.println("Bye"); + } +} diff --git a/binding/python/CMakeLists.txt b/binding/python/CMakeLists.txt index 0e836ae0..78896a03 100644 --- a/binding/python/CMakeLists.txt +++ b/binding/python/CMakeLists.txt @@ -1,6 +1,3 @@ -if(NOT BUILD_PYTHON) - return() -endif() set(NAME binding_python) project(${NAME}) set(SWIG_TARGET_NAME ccapi_${NAME}) @@ -15,7 +12,7 @@ message(STATUS "Python_EXECUTABLE: ${Python_EXECUTABLE}") list(APPEND CMAKE_SWIG_FLAGS "-py3") set(SWIG_INTERFACE ${CCAPI_PROJECT_DIR}/binding/swig_interface.i) set_property(SOURCE ${SWIG_INTERFACE} PROPERTY CPLUSPLUS ON) -set_property(SOURCE ${SWIG_INTERFACE} PROPERTY COMPILE_OPTIONS "-builtin;-threads") +set_property(SOURCE ${SWIG_INTERFACE} PROPERTY COMPILE_OPTIONS "-builtin;-threads;-doxygen") swig_add_library(${SWIG_TARGET_NAME} LANGUAGE python OUTPUT_DIR ${CMAKE_BINARY_DIR}/python/${SWIG_TARGET_NAME} @@ -35,71 +32,52 @@ target_link_libraries(${SWIG_TARGET_NAME} PRIVATE ${Python_LIBRARIES}) # ####################### configure_file( setup.py.in - ${CMAKE_CURRENT_BINARY_DIR}/setup.py.in + ${CMAKE_CURRENT_BINARY_DIR}/setup.py @ONLY) -file(GENERATE - OUTPUT $/setup.py - INPUT ${CMAKE_CURRENT_BINARY_DIR}/setup.py.in) # Find if python module MODULE_NAME is available, # if not install it to the Python user install directory. -function(search_python_module MODULE_NAME) - execute_process( - COMMAND ${Python_EXECUTABLE} -c "import ${MODULE_NAME}; print(${MODULE_NAME}.__version__)" - RESULT_VARIABLE _RESULT - OUTPUT_VARIABLE MODULE_VERSION - ERROR_QUIET - OUTPUT_STRIP_TRAILING_WHITESPACE - ) - if(${_RESULT} STREQUAL "0") - message(STATUS "Found python module: ${MODULE_NAME} (found version \"${MODULE_VERSION}\")") - else() - message(WARNING "Can't find python module \"${MODULE_NAME}\", user install it using pip...") - execute_process( - COMMAND ${Python_EXECUTABLE} -m pip install --upgrade ${MODULE_NAME} - OUTPUT_STRIP_TRAILING_WHITESPACE - ) - endif() -endfunction() +# function(search_python_module MODULE_NAME) +# execute_process( +# COMMAND ${Python_EXECUTABLE} -c "import ${MODULE_NAME}; print(${MODULE_NAME}.__version__)" +# RESULT_VARIABLE _RESULT +# OUTPUT_VARIABLE MODULE_VERSION +# ERROR_QUIET +# OUTPUT_STRIP_TRAILING_WHITESPACE +# ) +# if(${_RESULT} STREQUAL "0") +# message(STATUS "Found python module: ${MODULE_NAME} (found version \"${MODULE_VERSION}\")") +# else() +# message(WARNING "Can't find python module \"${MODULE_NAME}\", user install it using pip...") +# execute_process( +# COMMAND ${Python_EXECUTABLE} -m pip install --upgrade ${MODULE_NAME} +# OUTPUT_STRIP_TRAILING_WHITESPACE +# ) +# endif() +# endfunction() # Look for required python modules -search_python_module(setuptools) -search_python_module(wheel) +# search_python_module(setuptools) +# search_python_module(wheel) set(PACKAGING_DIR packaging) -set(PACKAGING_DIR_FULL ${CMAKE_CURRENT_BINARY_DIR}/${PACKAGING_DIR}) +set(PACKAGING_DIR_FULL ${CMAKE_CURRENT_BINARY_DIR}/${PACKAGING_DIR}/${BUILD_VERSION}) file(MAKE_DIRECTORY ${PACKAGING_DIR_FULL}) set(PYTHON_PACKAGING_TARGET_NAME python_${PACKAGING_DIR}) add_custom_target(${PYTHON_PACKAGING_TARGET_NAME} ALL - COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_BINARY_DIR}/$/setup.py ${PACKAGING_DIR_FULL} + COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_BINARY_DIR}/setup.py ${PACKAGING_DIR_FULL} COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_BINARY_DIR}/${SWIG_TARGET_NAME}/ccapi.py ${PACKAGING_DIR_FULL} COMMAND ${CMAKE_COMMAND} -E copy $ ${PACKAGING_DIR_FULL} COMMAND ${Python_EXECUTABLE} setup.py bdist_wheel + COMMAND ${Python_EXECUTABLE} -m pip install --upgrade . WORKING_DIRECTORY ${PACKAGING_DIR_FULL} - ) +) add_dependencies(${PYTHON_PACKAGING_TARGET_NAME} ${SWIG_TARGET_NAME}) -install(CODE " - execute_process(COMMAND ${Python_EXECUTABLE} -m pip install --upgrade . - WORKING_DIRECTORY ${PACKAGING_DIR_FULL}) -") - # Test if(BUILD_TEST) set(TEST_DIR ${CMAKE_CURRENT_BINARY_DIR}/test) - set(VENV_DIR ${TEST_DIR}/.venv) - if(WIN32) - set(VENV_Python_EXECUTABLE "${VENV_DIR}\\Scripts\\python.exe") - else() - set(VENV_Python_EXECUTABLE ${VENV_DIR}/bin/python) - endif() configure_file(test/test.py ${TEST_DIR}/test.py COPYONLY) - add_custom_command(TARGET ${PYTHON_PACKAGING_TARGET_NAME} POST_BUILD - COMMAND ${Python_EXECUTABLE} -m venv ${VENV_DIR} - # Must not call it in a folder containing the setup.py otherwise pip call it - # (i.e. "python setup.py bdist") while we want to consume the wheel package - COMMAND ${VENV_Python_EXECUTABLE} -m pip install --find-links=${PACKAGING_DIR_FULL}/dist ccapi - WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) add_test(NAME test - COMMAND ${VENV_Python_EXECUTABLE} test.py + COMMAND ${Python_EXECUTABLE} test.py WORKING_DIRECTORY ${TEST_DIR}) endif() diff --git a/binding/python/example/src/enable_library_logging/main.py b/binding/python/example/enable_library_logging/main.py similarity index 100% rename from binding/python/example/src/enable_library_logging/main.py rename to binding/python/example/enable_library_logging/main.py diff --git a/binding/python/example/src/enable_library_logging/user_specified_cmake_include.cmake b/binding/python/example/enable_library_logging/user_specified_cmake_include.cmake similarity index 100% rename from binding/python/example/src/enable_library_logging/user_specified_cmake_include.cmake rename to binding/python/example/enable_library_logging/user_specified_cmake_include.cmake diff --git a/binding/python/example/src/execution_management_simple_request/main.py b/binding/python/example/execution_management_simple_request/main.py similarity index 100% rename from binding/python/example/src/execution_management_simple_request/main.py rename to binding/python/example/execution_management_simple_request/main.py diff --git a/binding/python/example/src/execution_management_simple_subscription/main.py b/binding/python/example/execution_management_simple_subscription/main.py similarity index 100% rename from binding/python/example/src/execution_management_simple_subscription/main.py rename to binding/python/example/execution_management_simple_subscription/main.py diff --git a/binding/python/example/src/fix_simple/main.py b/binding/python/example/fix_simple/main.py similarity index 100% rename from binding/python/example/src/fix_simple/main.py rename to binding/python/example/fix_simple/main.py diff --git a/binding/python/example/src/handle_exception/main.py b/binding/python/example/handle_exception/main.py similarity index 100% rename from binding/python/example/src/handle_exception/main.py rename to binding/python/example/handle_exception/main.py diff --git a/binding/python/example/src/market_data_multiple_subscription/main.py b/binding/python/example/market_data_multiple_subscription/main.py similarity index 84% rename from binding/python/example/src/market_data_multiple_subscription/main.py rename to binding/python/example/market_data_multiple_subscription/main.py index a496d513..1daea3e6 100644 --- a/binding/python/example/src/market_data_multiple_subscription/main.py +++ b/binding/python/example/market_data_multiple_subscription/main.py @@ -6,7 +6,8 @@ def __init__(self): def processEvent(self, event: Event, session: Session) -> bool: if event.getType() == Event.Type_SUBSCRIPTION_DATA: for message in event.getMessageList(): - print(f'Best bid and ask at {message.getTimeISO()} are:') + correlationId = message.getCorrelationIdList()[0] + print(f'{correlationId}: Best bid and ask at {message.getTimeISO()} are:') for element in message.getElementList(): elementNameValueMap = element.getNameValueMap() for name, value in elementNameValueMap.items(): @@ -18,8 +19,8 @@ def processEvent(self, event: Event, session: Session) -> bool: config = SessionConfigs() session = Session(option, config, eventHandler) subscriptionList = SubscriptionList() - subscriptionList.append(Subscription('coinbase', 'BTC-USD', 'MARKET_DEPTH')) - subscriptionList.append(Subscription('coinbase', 'ETH-USD', 'MARKET_DEPTH')) + subscriptionList.append(Subscription('coinbase', 'BTC-USD', 'MARKET_DEPTH', '', 'BTC')) + subscriptionList.append(Subscription('coinbase', 'ETH-USD', 'MARKET_DEPTH', '', 'ETH')) session.subscribe(subscriptionList) time.sleep(10) session.stop() diff --git a/binding/python/example/src/market_data_simple_request/main.py b/binding/python/example/market_data_simple_request/main.py similarity index 100% rename from binding/python/example/src/market_data_simple_request/main.py rename to binding/python/example/market_data_simple_request/main.py diff --git a/binding/python/example/src/market_data_simple_subscription/main.py b/binding/python/example/market_data_simple_subscription/main.py similarity index 100% rename from binding/python/example/src/market_data_simple_subscription/main.py rename to binding/python/example/market_data_simple_subscription/main.py diff --git a/binding/python/example/src/__init__.py b/binding/python/example/src/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/binding/python/example/src/enable_library_logging/__init__.py b/binding/python/example/src/enable_library_logging/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/binding/python/example/src/execution_management_simple_request/__init__.py b/binding/python/example/src/execution_management_simple_request/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/binding/python/example/src/execution_management_simple_subscription/__init__.py b/binding/python/example/src/execution_management_simple_subscription/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/binding/python/example/src/fix_simple/__init__.py b/binding/python/example/src/fix_simple/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/binding/python/example/src/handle_exception/__init__.py b/binding/python/example/src/handle_exception/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/binding/python/example/src/market_data_multiple_subscription/__init__.py b/binding/python/example/src/market_data_multiple_subscription/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/binding/python/example/src/market_data_simple_request/__init__.py b/binding/python/example/src/market_data_simple_request/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/binding/python/example/src/market_data_simple_subscription/__init__.py b/binding/python/example/src/market_data_simple_subscription/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/binding/python/setup.py.in b/binding/python/setup.py.in index 6f22d55f..f496749d 100644 --- a/binding/python/setup.py.in +++ b/binding/python/setup.py.in @@ -19,4 +19,5 @@ setup( packages=[''], py_modules = ['ccapi'], package_data={'': ['$']}, + install_requires=['setuptools', 'wheel'], ) diff --git a/include/ccapi_cpp/ccapi_fix_connection.h b/include/ccapi_cpp/ccapi_fix_connection.h index 32d10ae2..4fe4ee3e 100644 --- a/include/ccapi_cpp/ccapi_fix_connection.h +++ b/include/ccapi_cpp/ccapi_fix_connection.h @@ -6,11 +6,11 @@ #include "ccapi_cpp/ccapi_subscription.h" namespace beast = boost::beast; namespace ccapi { +/** + * This class represents a TCP socket connection for the FIX API. + */ template class FixConnection CCAPI_FINAL { - /** - * This class represents a TCP socket connection for the FIX API. - */ public: FixConnection(std::string host, std::string port, Subscription subscription, std::shared_ptr streamPtr) : host(host), port(port), subscription(subscription), streamPtr(streamPtr) { diff --git a/include/ccapi_cpp/ccapi_queue.h b/include/ccapi_cpp/ccapi_queue.h index bbcf5810..a0df0a03 100644 --- a/include/ccapi_cpp/ccapi_queue.h +++ b/include/ccapi_cpp/ccapi_queue.h @@ -6,10 +6,10 @@ #include "ccapi_cpp/ccapi_logger.h" namespace ccapi { -template /** * This class represents a generic FIFO queue. */ +template class Queue { public: std::string EXCEPTION_QUEUE_FULL = "queue is full"; diff --git a/include/ccapi_cpp/service/ccapi_fix_service.h b/include/ccapi_cpp/service/ccapi_fix_service.h index 3ddbde9f..09624268 100644 --- a/include/ccapi_cpp/service/ccapi_fix_service.h +++ b/include/ccapi_cpp/service/ccapi_fix_service.h @@ -11,11 +11,11 @@ #include "hffix.hpp" namespace hff = hffix; namespace ccapi { -template /** * Defines a service which provides access to exchange API and normalizes them. This is a base class that implements generic functionalities for dealing with * exchange FIX APIs. The Session object is responsible for routing requests and subscriptions to the desired concrete service. */ +template class FixService : public Service { public: FixService(std::function*)> eventHandler, SessionOptions sessionOptions, SessionConfigs sessionConfigs, From b5cb1f3af5728985fe68b7ad0ada99baf1eb0827 Mon Sep 17 00:00:00 2001 From: Crypto Chassis Date: Tue, 18 Jul 2023 14:56:33 -0700 Subject: [PATCH 3/8] dev: fix regression in binding/python/CMakeLists.txt --- binding/python/CMakeLists.txt | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/binding/python/CMakeLists.txt b/binding/python/CMakeLists.txt index 78896a03..d14c6784 100644 --- a/binding/python/CMakeLists.txt +++ b/binding/python/CMakeLists.txt @@ -32,8 +32,11 @@ target_link_libraries(${SWIG_TARGET_NAME} PRIVATE ${Python_LIBRARIES}) # ####################### configure_file( setup.py.in - ${CMAKE_CURRENT_BINARY_DIR}/setup.py + ${CMAKE_CURRENT_BINARY_DIR}/setup.py.in @ONLY) +file(GENERATE + OUTPUT setup.py + INPUT ${CMAKE_CURRENT_BINARY_DIR}/setup.py.in) # Find if python module MODULE_NAME is available, # if not install it to the Python user install directory. From afbd7a5f53dcd3b3651e5ebae1095106b4a87460 Mon Sep 17 00:00:00 2001 From: Crypto Chassis Date: Fri, 21 Jul 2023 14:50:33 -0700 Subject: [PATCH 4/8] docs: update README.md --- .gitignore | 1 + README.md | 11 ++- binding/CMakeLists.txt | 33 +++++++-- binding/csharp/CMakeLists.txt | 70 +++++++++++++++++++ binding/csharp/ccapi.csproj.in | 8 +++ .../MainProgram.cs | 39 +++++++++++ .../main.csproj | 13 ++++ .../MainProgram.cs | 36 ++++++++++ .../main.csproj | 13 ++++ .../swig_interface_ccapi_language_specific.i | 2 + .../Main.java | 6 +- binding/python/CMakeLists.txt | 6 +- .../{swig_interface.i => swig_interface.i.in} | 17 +++-- include/ccapi_cpp/ccapi_request.h | 33 ++++----- .../ccapi_execution_management_service.h | 4 +- 15 files changed, 250 insertions(+), 42 deletions(-) create mode 100644 binding/csharp/CMakeLists.txt create mode 100644 binding/csharp/ccapi.csproj.in create mode 100644 binding/csharp/example/execution_management_simple_request/MainProgram.cs create mode 100644 binding/csharp/example/execution_management_simple_request/main.csproj create mode 100644 binding/csharp/example/market_data_simple_subscription/MainProgram.cs create mode 100644 binding/csharp/example/market_data_simple_subscription/main.csproj create mode 100644 binding/csharp/swig_interface_ccapi_language_specific.i rename binding/{swig_interface.i => swig_interface.i.in} (79%) diff --git a/.gitignore b/.gitignore index d96705ae..3c4ed4ee 100644 --- a/.gitignore +++ b/.gitignore @@ -149,3 +149,4 @@ docs/_build/ .project .venv/ target/ +obj/ diff --git a/README.md b/README.md index dad30465..3c8cc75f 100644 --- a/README.md +++ b/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. - **Table of Contents** *generated with [DocToc](https://github.com/thlorenz/doctoc)* @@ -53,7 +51,7 @@ Breaking changes in v6: Greetings, Ladies and Gentlemen, we've introduced some s # 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: @@ -102,8 +100,8 @@ Breaking changes in v6: Greetings, Ladies and Gentlemen, we've introduced some s * "string table overflow at offset \". 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. +### Python and Java +* Require 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. * CMake: https://cmake.org/download/. * Run the following commands. @@ -111,9 +109,8 @@ Breaking changes in v6: Greetings, Ladies and Gentlemen, we've introduced some s mkdir binding/build cd binding/build rm -rf * (if rebuild from scratch) -cmake -DBUILD_PYTHON=ON .. (optional: -DBUILD_VERSION=) +cmake -DBUILD_PYTHON=ON -DBUILD_VERSION=1.0.0 .. (For) 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. diff --git a/binding/CMakeLists.txt b/binding/CMakeLists.txt index 700487fa..07718425 100644 --- a/binding/CMakeLists.txt +++ b/binding/CMakeLists.txt @@ -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) @@ -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") @@ -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) @@ -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() diff --git a/binding/csharp/CMakeLists.txt b/binding/csharp/CMakeLists.txt new file mode 100644 index 00000000..be4def3c --- /dev/null +++ b/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 $ ${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 $ ${PACKAGING_DIR_FULL} diff --git a/binding/csharp/ccapi.csproj.in b/binding/csharp/ccapi.csproj.in new file mode 100644 index 00000000..b9251e94 --- /dev/null +++ b/binding/csharp/ccapi.csproj.in @@ -0,0 +1,8 @@ + + + + net6.0 + enable + + + diff --git a/binding/csharp/example/execution_management_simple_request/MainProgram.cs b/binding/csharp/example/execution_management_simple_request/MainProgram.cs new file mode 100644 index 00000000..061b0aa6 --- /dev/null +++ b/binding/csharp/example/execution_management_simple_request/MainProgram.cs @@ -0,0 +1,39 @@ +using ccapi; +class MainProgram + { + class MyEventHandler : EventHandler { + public override bool ProcessEvent(Event event_, 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 SessionOptions(); + var config = new SessionConfigs(); + var session = new Session(option, config, eventHandler); + var request = new Request(Request.Operation.CREATE_ORDER, "okx", "BTC-USDT"); + var param = new 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"); + } + } diff --git a/binding/csharp/example/execution_management_simple_request/main.csproj b/binding/csharp/example/execution_management_simple_request/main.csproj new file mode 100644 index 00000000..798d616e --- /dev/null +++ b/binding/csharp/example/execution_management_simple_request/main.csproj @@ -0,0 +1,13 @@ + + + Exe + net6.0 + enable + to be provided in command line + + + + $(CcapiLibraryPath) + + + diff --git a/binding/csharp/example/market_data_simple_subscription/MainProgram.cs b/binding/csharp/example/market_data_simple_subscription/MainProgram.cs new file mode 100644 index 00000000..cbbe150e --- /dev/null +++ b/binding/csharp/example/market_data_simple_subscription/MainProgram.cs @@ -0,0 +1,36 @@ +using ccapi; +class MainProgram + { + class MyEventHandler : EventHandler { + public override bool ProcessEvent(Event event_, Session session) { + if (event_.GetType_() == 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 SessionOptions(); + var config = new SessionConfigs(); + var session = new Session(option, config, eventHandler); + var subscriptionList = new SubscriptionList(); + subscriptionList.Add(new Subscription("okx", "BTC-USDT", "MARKET_DEPTH")); + session.Subscribe(subscriptionList); + System.Threading.Thread.Sleep(10000); + session.Stop(); + System.Console.WriteLine("Bye"); + } + } diff --git a/binding/csharp/example/market_data_simple_subscription/main.csproj b/binding/csharp/example/market_data_simple_subscription/main.csproj new file mode 100644 index 00000000..798d616e --- /dev/null +++ b/binding/csharp/example/market_data_simple_subscription/main.csproj @@ -0,0 +1,13 @@ + + + Exe + net6.0 + enable + to be provided in command line + + + + $(CcapiLibraryPath) + + + diff --git a/binding/csharp/swig_interface_ccapi_language_specific.i b/binding/csharp/swig_interface_ccapi_language_specific.i new file mode 100644 index 00000000..310823e9 --- /dev/null +++ b/binding/csharp/swig_interface_ccapi_language_specific.i @@ -0,0 +1,2 @@ +%rename("%(camelcase)s", %$isfunction, %$ismember, %$ispublic) ""; +%rename("%(regex:/^(toString|getType|setType)$/\\u\\1_/)s") ""; diff --git a/binding/java/example/execution_management_simple_request/Main.java b/binding/java/example/execution_management_simple_request/Main.java index b9329ba5..18fb9e23 100644 --- a/binding/java/example/execution_management_simple_request/Main.java +++ b/binding/java/example/execution_management_simple_request/Main.java @@ -4,7 +4,7 @@ import com.cryptochassis.ccapi.Session; import com.cryptochassis.ccapi.Request; import com.cryptochassis.ccapi.Event; -import com.cryptochassis.ccapi.map_string_string; +import com.cryptochassis.ccapi.MapStringString; public class Main { static class MyEventHandler extends EventHandler { @@ -17,9 +17,11 @@ public boolean processEvent(Event event, Session session) { public static void main(String[] args) { if(System.getenv("BINANCE_API_KEY") == null) { System.err.println("Please set environment variable BINANCE_API_KEY"); + return; } if(System.getenv("BINANCE_API_SECRET") == null) { System.err.println("Please set environment variable BINANCE_API_SECRET"); + return; } System.loadLibrary("ccapi_binding_java"); var eventHandler = new MyEventHandler(); @@ -27,7 +29,7 @@ public static void main(String[] args) { var config = new SessionConfigs(); var session = new Session(option, config, eventHandler); var request = new Request(Request.Operation.CREATE_ORDER, "binance", "BTCUSDT"); - var param = new map_string_string(); + var param = new MapStringString(); param.put("SIDE","BUY"); param.put("QUANTITY","0.0005"); param.put("LIMIT_PRICE","20000"); diff --git a/binding/python/CMakeLists.txt b/binding/python/CMakeLists.txt index d14c6784..bb5717d8 100644 --- a/binding/python/CMakeLists.txt +++ b/binding/python/CMakeLists.txt @@ -9,10 +9,10 @@ message(STATUS "Python_EXECUTABLE: ${Python_EXECUTABLE}") if(Python_VERSION VERSION_LESS 3) message(FATAL_ERROR "Require Python 3") endif() -list(APPEND CMAKE_SWIG_FLAGS "-py3") -set(SWIG_INTERFACE ${CCAPI_PROJECT_DIR}/binding/swig_interface.i) +# list(APPEND CMAKE_SWIG_FLAGS "-py3") +# set(SWIG_INTERFACE ${CCAPI_PROJECT_DIR}/binding/swig_interface.i) set_property(SOURCE ${SWIG_INTERFACE} PROPERTY CPLUSPLUS ON) -set_property(SOURCE ${SWIG_INTERFACE} PROPERTY COMPILE_OPTIONS "-builtin;-threads;-doxygen") +set_property(SOURCE ${SWIG_INTERFACE} PROPERTY COMPILE_OPTIONS "-py3;-builtin;-threads;-doxygen") swig_add_library(${SWIG_TARGET_NAME} LANGUAGE python OUTPUT_DIR ${CMAKE_BINARY_DIR}/python/${SWIG_TARGET_NAME} diff --git a/binding/swig_interface.i b/binding/swig_interface.i.in similarity index 79% rename from binding/swig_interface.i rename to binding/swig_interface.i.in index 6b5057b9..0f6a39d2 100644 --- a/binding/swig_interface.i +++ b/binding/swig_interface.i.in @@ -34,18 +34,21 @@ SWIG_exception(SWIG_RuntimeError, s.c_str()); } } -%template(map_string_string) std::map; -%template(map_int_string) std::map; -%template(pair_int_string) std::pair; -%template(pair_long_long_long_long) std::pair; -%template(vector_pair_int_string) std::vector >; +%template(MapStringString) std::map; +%template(MapIntString) std::map; +%template(PairIntString) std::pair; +%template(PairLongLongLongLong) std::pair; +%template(VectorPairIntString) std::vector >; %template(ElementList) std::vector; -%template(vector_string) std::vector; +%template(VectorString) std::vector; %template(MessageList) std::vector; -%template(map_string_map_string_string) std::map >; +%template(MapStringMapStringString) std::map >; %template(EventList) std::vector; %template(SubscriptionList) std::vector; %template(RequestList) std::vector; + +@SWIG_INTERFACE_CCAPI_LANGUAGE_SPECIFIC@ + %include "ccapi_cpp/ccapi_macro.h" %include "ccapi_cpp/ccapi_util.h" %include "ccapi_cpp/ccapi_element.h" diff --git a/include/ccapi_cpp/ccapi_request.h b/include/ccapi_cpp/ccapi_request.h index 19905e96..8f472f66 100644 --- a/include/ccapi_cpp/ccapi_request.h +++ b/include/ccapi_cpp/ccapi_request.h @@ -7,6 +7,15 @@ #include "ccapi_cpp/ccapi_macro.h" #include "ccapi_cpp/ccapi_util_private.h" +// We use macros instead of static constants in the Request class so that SWIG can properly generate C# bindings +#define CCAPI_REQUEST_OPERATION_TYPE_CUSTOM 0x100 + #define CCAPI_REQUEST_OPERATION_TYPE_GENERIC_PUBLIC_REQUEST 0x200 + #define CCAPI_REQUEST_OPERATION_TYPE_GENERIC_PRIVATE_REQUEST 0x300 + #define CCAPI_REQUEST_OPERATION_TYPE_FIX 0x400 + #define CCAPI_REQUEST_OPERATION_TYPE_MARKET_DATA 0x500 + #define CCAPI_REQUEST_OPERATION_TYPE_EXECUTION_MANAGEMENT 0x600 + #define CCAPI_REQUEST_OPERATION_TYPE_EXECUTION_MANAGEMENT_ORDER CCAPI_REQUEST_OPERATION_TYPE_EXECUTION_MANAGEMENT + #define CCAPI_REQUEST_OPERATION_TYPE_EXECUTION_MANAGEMENT_ACCOUNT 0x700 namespace ccapi { /** * A single request. Request objects are created using Request constructors. They are used with Session::sendRequest() or Session::sendRequestByWebsocket() or @@ -16,29 +25,21 @@ namespace ccapi { */ class Request CCAPI_FINAL { public: - static constexpr int operationTypeCustom = 0x100; - static constexpr int operationTypeGenericPublicRequest = 0x200; - static constexpr int operationTypeGenericPrivateRequest = 0x300; - static constexpr int operationTypeFix = 0x400; - static constexpr int operationTypeMarketData = 0x500; - static constexpr int operationTypeExecutionManagement = 0x600; - static constexpr int operationTypeExecutionManagementOrder = operationTypeExecutionManagement; - static constexpr int operationTypeExecutionManagementAccount = 0x700; enum class Operation { - CUSTOM = operationTypeCustom, - GENERIC_PUBLIC_REQUEST = operationTypeGenericPublicRequest, - GENERIC_PRIVATE_REQUEST = operationTypeGenericPrivateRequest, - FIX = operationTypeFix, - GET_RECENT_TRADES = operationTypeMarketData, + CUSTOM = CCAPI_REQUEST_OPERATION_TYPE_CUSTOM, + GENERIC_PUBLIC_REQUEST = CCAPI_REQUEST_OPERATION_TYPE_GENERIC_PUBLIC_REQUEST, + GENERIC_PRIVATE_REQUEST = CCAPI_REQUEST_OPERATION_TYPE_GENERIC_PRIVATE_REQUEST, + FIX = CCAPI_REQUEST_OPERATION_TYPE_FIX, + GET_RECENT_TRADES = CCAPI_REQUEST_OPERATION_TYPE_MARKET_DATA, GET_RECENT_AGG_TRADES, GET_INSTRUMENT, GET_INSTRUMENTS, - CREATE_ORDER = operationTypeExecutionManagementOrder, + CREATE_ORDER = CCAPI_REQUEST_OPERATION_TYPE_EXECUTION_MANAGEMENT_ORDER, CANCEL_ORDER, GET_ORDER, GET_OPEN_ORDERS, CANCEL_OPEN_ORDERS, - GET_ACCOUNTS = operationTypeExecutionManagementAccount, + GET_ACCOUNTS = CCAPI_REQUEST_OPERATION_TYPE_EXECUTION_MANAGEMENT_ACCOUNT, GET_ACCOUNT_BALANCES, GET_ACCOUNT_POSITIONS, }; @@ -111,7 +112,7 @@ class Request CCAPI_FINAL { } else if (operation == Operation::FIX) { this->serviceName = CCAPI_FIX; } else { - this->serviceName = static_cast(operation) >= operationTypeExecutionManagement ? CCAPI_EXECUTION_MANAGEMENT : CCAPI_MARKET_DATA; + this->serviceName = static_cast(operation) >= CCAPI_REQUEST_OPERATION_TYPE_EXECUTION_MANAGEMENT ? CCAPI_EXECUTION_MANAGEMENT : CCAPI_MARKET_DATA; } if (this->correlationId.empty()) { this->correlationId = UtilString::generateRandomString(CCAPI_CORRELATION_ID_GENERATED_LENGTH); diff --git a/include/ccapi_cpp/service/ccapi_execution_management_service.h b/include/ccapi_cpp/service/ccapi_execution_management_service.h index 2a96c8e4..52373e19 100644 --- a/include/ccapi_cpp/service/ccapi_execution_management_service.h +++ b/include/ccapi_cpp/service/ccapi_execution_management_service.h @@ -115,10 +115,10 @@ class ExecutionManagementService : public Service { Request::Operation operation = request.getOperation(); message.setType(this->requestOperationToMessageTypeMap.at(operation)); auto castedOperation = static_cast(operation); - if (castedOperation >= Request::operationTypeExecutionManagementOrder && castedOperation < Request::operationTypeExecutionManagementAccount) { + if (castedOperation >= CCAPI_REQUEST_OPERATION_TYPE_EXECUTION_MANAGEMENT_ORDER && castedOperation < CCAPI_REQUEST_OPERATION_TYPE_EXECUTION_MANAGEMENT_ACCOUNT) { this->extractOrderInfoFromRequest(elementList, request, operation, document); message.setElementList(elementList); - } else if (castedOperation >= Request::operationTypeExecutionManagementAccount) { + } else if (castedOperation >= CCAPI_REQUEST_OPERATION_TYPE_EXECUTION_MANAGEMENT_ACCOUNT) { this->extractAccountInfoFromRequest(elementList, request, operation, document); message.setElementList(elementList); } From 18ff97537d24bf191e881f5a153f34c0f6d88a0b Mon Sep 17 00:00:00 2001 From: Crypto Chassis Date: Mon, 24 Jul 2023 11:22:04 -0700 Subject: [PATCH 5/8] docs: update README.md --- README.md | 47 +++++++---- .../MainProgram.cs | 15 ++-- .../MainProgram.cs | 17 ++-- .../Main.java | 83 ++++++++++--------- .../market_data_simple_subscription/Main.java | 71 ++++++++-------- format.sh | 3 + format_cpp.sh | 2 + format_java.sh | 2 + include/ccapi_cpp/ccapi_request.h | 14 ++-- .../ccapi_execution_management_service.h | 3 +- 10 files changed, 140 insertions(+), 117 deletions(-) create mode 100755 format.sh create mode 100755 format_cpp.sh create mode 100755 format_java.sh diff --git a/README.md b/README.md index 3c8cc75f..e79af6bf 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ - [Branches](#branches) - [Build](#build) - [C++](#c) - - [Python](#python) + - [non-C++](#non-c) - [Constants](#constants) - [Examples](#examples) - [Documentations](#documentations) @@ -100,25 +100,29 @@ * "string table overflow at offset \". 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 and Java +### non-C++ * Require 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. + * 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 -DBUILD_VERSION=1.0.0 .. (For) +cmake -DBUILD_PYTHON=ON -DBUILD_VERSION=1.0.0 .. (Use -DBUILD_JAVA=ON if the target language is Java) cmake --build . ``` * 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. * 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) @@ -139,8 +143,23 @@ cmake --build . --target [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 @@ -217,7 +236,7 @@ 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:** @@ -225,7 +244,7 @@ For a specific exchange and instrument, whenever the best bid's or ask's price o **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 { @@ -399,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 { diff --git a/binding/csharp/example/execution_management_simple_request/MainProgram.cs b/binding/csharp/example/execution_management_simple_request/MainProgram.cs index 061b0aa6..fa90336d 100644 --- a/binding/csharp/example/execution_management_simple_request/MainProgram.cs +++ b/binding/csharp/example/execution_management_simple_request/MainProgram.cs @@ -1,8 +1,7 @@ -using ccapi; class MainProgram { - class MyEventHandler : EventHandler { - public override bool ProcessEvent(Event event_, Session session) { + 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; } @@ -22,11 +21,11 @@ static void Main(string[] args) return; } var eventHandler = new MyEventHandler(); - var option = new SessionOptions(); - var config = new SessionConfigs(); - var session = new Session(option, config, eventHandler); - var request = new Request(Request.Operation.CREATE_ORDER, "okx", "BTC-USDT"); - var param = new MapStringString(); + 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"); diff --git a/binding/csharp/example/market_data_simple_subscription/MainProgram.cs b/binding/csharp/example/market_data_simple_subscription/MainProgram.cs index cbbe150e..ced50acf 100644 --- a/binding/csharp/example/market_data_simple_subscription/MainProgram.cs +++ b/binding/csharp/example/market_data_simple_subscription/MainProgram.cs @@ -1,9 +1,8 @@ -using ccapi; class MainProgram { - class MyEventHandler : EventHandler { - public override bool ProcessEvent(Event event_, Session session) { - if (event_.GetType_() == Event.Type.SUBSCRIPTION_DATA) { + 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()){ @@ -23,11 +22,11 @@ public override bool ProcessEvent(Event event_, Session session) { static void Main(string[] args) { var eventHandler = new MyEventHandler(); - var option = new SessionOptions(); - var config = new SessionConfigs(); - var session = new Session(option, config, eventHandler); - var subscriptionList = new SubscriptionList(); - subscriptionList.Add(new Subscription("okx", "BTC-USDT", "MARKET_DEPTH")); + 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(); diff --git a/binding/java/example/execution_management_simple_request/Main.java b/binding/java/example/execution_management_simple_request/Main.java index 18fb9e23..8a7eaf05 100644 --- a/binding/java/example/execution_management_simple_request/Main.java +++ b/binding/java/example/execution_management_simple_request/Main.java @@ -1,48 +1,49 @@ -import com.cryptochassis.ccapi.EventHandler; -import com.cryptochassis.ccapi.SessionOptions; -import com.cryptochassis.ccapi.SessionConfigs; -import com.cryptochassis.ccapi.Session; -import com.cryptochassis.ccapi.Request; import com.cryptochassis.ccapi.Event; +import com.cryptochassis.ccapi.EventHandler; import com.cryptochassis.ccapi.MapStringString; +import com.cryptochassis.ccapi.Request; +import com.cryptochassis.ccapi.Session; +import com.cryptochassis.ccapi.SessionConfigs; +import com.cryptochassis.ccapi.SessionOptions; public class Main { - static class MyEventHandler extends EventHandler { - @Override - public boolean processEvent(Event event, Session session) { - System.out.println(String.format("Received an event:\n%s", event.toStringPretty(2, 2))); - return true; - } + static class MyEventHandler extends EventHandler { + @Override + public boolean processEvent(Event event, Session session) { + System.out.println(String.format("Received an event:\n%s", event.toStringPretty(2, 2))); + return true; + } + } + public static void main(String[] args) { + if (System.getenv("OKX_API_KEY") == null) { + System.err.println("Please set environment variable OKX_API_KEY"); + return; + } + if (System.getenv("OKX_API_SECRET") == null) { + System.err.println("Please set environment variable OKX_API_SECRET"); + return; + } + if (System.getenv("OKX_API_PASSPHRASE") == null) { + System.err.println("Please set environment variable OKX_API_PASSPHRASE"); + return; } - public static void main(String[] args) { - if(System.getenv("BINANCE_API_KEY") == null) { - System.err.println("Please set environment variable BINANCE_API_KEY"); - return; - } - if(System.getenv("BINANCE_API_SECRET") == null) { - System.err.println("Please set environment variable BINANCE_API_SECRET"); - return; - } - System.loadLibrary("ccapi_binding_java"); - var eventHandler = new MyEventHandler(); - var option = new SessionOptions(); - var config = new SessionConfigs(); - var session = new Session(option, config, eventHandler); - var request = new Request(Request.Operation.CREATE_ORDER, "binance", "BTCUSDT"); - var param = new MapStringString(); - param.put("SIDE","BUY"); - param.put("QUANTITY","0.0005"); - param.put("LIMIT_PRICE","20000"); - request.appendParam(param); - session.sendRequest(request); - try - { - Thread.sleep(10000); - } - catch(InterruptedException e) - { - } - session.stop(); - System.out.println("Bye"); + System.loadLibrary("ccapi_binding_java"); + var eventHandler = new MyEventHandler(); + var option = new SessionOptions(); + var config = new SessionConfigs(); + var session = new Session(option, config, eventHandler); + var request = new Request(Request.Operation.CREATE_ORDER, "okx", "BTC-USDT"); + var param = new MapStringString(); + param.put("SIDE", "BUY"); + param.put("QUANTITY", "0.0005"); + param.put("LIMIT_PRICE", "20000"); + request.appendParam(param); + session.sendRequest(request); + try { + Thread.sleep(10000); + } catch (InterruptedException e) { } + session.stop(); + System.out.println("Bye"); + } } diff --git a/binding/java/example/market_data_simple_subscription/Main.java b/binding/java/example/market_data_simple_subscription/Main.java index 5839f336..7968bdd7 100644 --- a/binding/java/example/market_data_simple_subscription/Main.java +++ b/binding/java/example/market_data_simple_subscription/Main.java @@ -1,48 +1,45 @@ +import com.cryptochassis.ccapi.Event; import com.cryptochassis.ccapi.EventHandler; -import com.cryptochassis.ccapi.SessionOptions; -import com.cryptochassis.ccapi.SessionConfigs; import com.cryptochassis.ccapi.Session; +import com.cryptochassis.ccapi.SessionConfigs; +import com.cryptochassis.ccapi.SessionOptions; import com.cryptochassis.ccapi.Subscription; import com.cryptochassis.ccapi.SubscriptionList; -import com.cryptochassis.ccapi.Event; public class Main { - static class MyEventHandler extends EventHandler { - @Override - public boolean processEvent(Event event, Session session) { - if (event.getType() == Event.Type.SUBSCRIPTION_DATA) { - for (var message : event.getMessageList()) { - System.out.println(String.format("Best bid and ask at %s are:", message.getTimeISO())); - for (var element : message.getElementList()){ - var elementNameValueMap = element.getNameValueMap(); - for (var entry : elementNameValueMap.entrySet()){ - var name = entry.getKey(); - var value = entry.getValue(); - System.out.println(String.format(" %s = %s", name, value)); - } - } - } + static class MyEventHandler extends EventHandler { + @Override + public boolean processEvent(Event event, Session session) { + if (event.getType() == Event.Type.SUBSCRIPTION_DATA) { + for (var message : event.getMessageList()) { + System.out.println(String.format("Best bid and ask at %s are:", message.getTimeISO())); + for (var element : message.getElementList()) { + var elementNameValueMap = element.getNameValueMap(); + for (var entry : elementNameValueMap.entrySet()) { + var name = entry.getKey(); + var value = entry.getValue(); + System.out.println(String.format(" %s = %s", name, value)); } - return true; + } } + } + return true; } - public static void main(String[] args) { - System.loadLibrary("ccapi_binding_java"); - var eventHandler = new MyEventHandler(); - var option = new SessionOptions(); - var config = new SessionConfigs(); - var session = new Session(option, config, eventHandler); - var subscriptionList = new SubscriptionList(); - subscriptionList.add(new Subscription("coinbase", "BTC-USD", "MARKET_DEPTH")); - session.subscribe(subscriptionList); - try - { - Thread.sleep(10000); - } - catch(InterruptedException e) - { - } - session.stop(); - System.out.println("Bye"); + } + public static void main(String[] args) { + System.loadLibrary("ccapi_binding_java"); + var eventHandler = new MyEventHandler(); + var option = new SessionOptions(); + var config = new SessionConfigs(); + var session = new Session(option, config, eventHandler); + var subscriptionList = new SubscriptionList(); + subscriptionList.add(new Subscription("okx", "BTC-USDT", "MARKET_DEPTH")); + session.subscribe(subscriptionList); + try { + Thread.sleep(10000); + } catch (InterruptedException e) { } + session.stop(); + System.out.println("Bye"); + } } diff --git a/format.sh b/format.sh new file mode 100755 index 00000000..9fd3229a --- /dev/null +++ b/format.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +./format_cpp.sh +./format_java.sh diff --git a/format_cpp.sh b/format_cpp.sh new file mode 100755 index 00000000..4beec773 --- /dev/null +++ b/format_cpp.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +find . -type f -not -path "*/dependency/*" -not -path "*/build/*" -not -name "ccapi_hmac.h" \( -name "*.h" -or -name "*.cpp" -or -name "*.hpp" \) -exec clang-format -i -style=file {} \+ diff --git a/format_java.sh b/format_java.sh new file mode 100755 index 00000000..ff318858 --- /dev/null +++ b/format_java.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +find . -type f -path "*/binding/*" -not -path "*/dependency/*" -not -path "*/build/*" -name "*.java" -exec clang-format -i -style=file {} \+ diff --git a/include/ccapi_cpp/ccapi_request.h b/include/ccapi_cpp/ccapi_request.h index 8f472f66..4b02d4c4 100644 --- a/include/ccapi_cpp/ccapi_request.h +++ b/include/ccapi_cpp/ccapi_request.h @@ -9,13 +9,13 @@ #include "ccapi_cpp/ccapi_util_private.h" // We use macros instead of static constants in the Request class so that SWIG can properly generate C# bindings #define CCAPI_REQUEST_OPERATION_TYPE_CUSTOM 0x100 - #define CCAPI_REQUEST_OPERATION_TYPE_GENERIC_PUBLIC_REQUEST 0x200 - #define CCAPI_REQUEST_OPERATION_TYPE_GENERIC_PRIVATE_REQUEST 0x300 - #define CCAPI_REQUEST_OPERATION_TYPE_FIX 0x400 - #define CCAPI_REQUEST_OPERATION_TYPE_MARKET_DATA 0x500 - #define CCAPI_REQUEST_OPERATION_TYPE_EXECUTION_MANAGEMENT 0x600 - #define CCAPI_REQUEST_OPERATION_TYPE_EXECUTION_MANAGEMENT_ORDER CCAPI_REQUEST_OPERATION_TYPE_EXECUTION_MANAGEMENT - #define CCAPI_REQUEST_OPERATION_TYPE_EXECUTION_MANAGEMENT_ACCOUNT 0x700 +#define CCAPI_REQUEST_OPERATION_TYPE_GENERIC_PUBLIC_REQUEST 0x200 +#define CCAPI_REQUEST_OPERATION_TYPE_GENERIC_PRIVATE_REQUEST 0x300 +#define CCAPI_REQUEST_OPERATION_TYPE_FIX 0x400 +#define CCAPI_REQUEST_OPERATION_TYPE_MARKET_DATA 0x500 +#define CCAPI_REQUEST_OPERATION_TYPE_EXECUTION_MANAGEMENT 0x600 +#define CCAPI_REQUEST_OPERATION_TYPE_EXECUTION_MANAGEMENT_ORDER CCAPI_REQUEST_OPERATION_TYPE_EXECUTION_MANAGEMENT +#define CCAPI_REQUEST_OPERATION_TYPE_EXECUTION_MANAGEMENT_ACCOUNT 0x700 namespace ccapi { /** * A single request. Request objects are created using Request constructors. They are used with Session::sendRequest() or Session::sendRequestByWebsocket() or diff --git a/include/ccapi_cpp/service/ccapi_execution_management_service.h b/include/ccapi_cpp/service/ccapi_execution_management_service.h index 52373e19..a5c8ea3f 100644 --- a/include/ccapi_cpp/service/ccapi_execution_management_service.h +++ b/include/ccapi_cpp/service/ccapi_execution_management_service.h @@ -115,7 +115,8 @@ class ExecutionManagementService : public Service { Request::Operation operation = request.getOperation(); message.setType(this->requestOperationToMessageTypeMap.at(operation)); auto castedOperation = static_cast(operation); - if (castedOperation >= CCAPI_REQUEST_OPERATION_TYPE_EXECUTION_MANAGEMENT_ORDER && castedOperation < CCAPI_REQUEST_OPERATION_TYPE_EXECUTION_MANAGEMENT_ACCOUNT) { + if (castedOperation >= CCAPI_REQUEST_OPERATION_TYPE_EXECUTION_MANAGEMENT_ORDER && + castedOperation < CCAPI_REQUEST_OPERATION_TYPE_EXECUTION_MANAGEMENT_ACCOUNT) { this->extractOrderInfoFromRequest(elementList, request, operation, document); message.setElementList(elementList); } else if (castedOperation >= CCAPI_REQUEST_OPERATION_TYPE_EXECUTION_MANAGEMENT_ACCOUNT) { From 8951ef11847a1a684a9fd0449fae7fe0f77a8152 Mon Sep 17 00:00:00 2001 From: Crypto Chassis Date: Mon, 24 Jul 2023 11:25:21 -0700 Subject: [PATCH 6/8] docs: update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index e79af6bf..67fa468e 100644 --- a/README.md +++ b/README.md @@ -143,7 +143,7 @@ cmake --build . --target [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](#non-C++). +* 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 @@ -151,7 +151,7 @@ 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++). +* 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 From c38c8fe2efa1e4699df2893337953cefd0049915 Mon Sep 17 00:00:00 2001 From: Crypto Chassis Date: Mon, 24 Jul 2023 11:26:00 -0700 Subject: [PATCH 7/8] docs: update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 67fa468e..a2622c5f 100644 --- a/README.md +++ b/README.md @@ -143,7 +143,7 @@ cmake --build . --target [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](#non-C). +* 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 @@ -151,7 +151,7 @@ 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). +* 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 From 29627602ee72e812ba4f3459d58835cb20e4eac8 Mon Sep 17 00:00:00 2001 From: Crypto Chassis Date: Mon, 24 Jul 2023 11:28:24 -0700 Subject: [PATCH 8/8] docs: update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index a2622c5f..bf747e81 100644 --- a/README.md +++ b/README.md @@ -112,7 +112,7 @@ rm -rf * (if rebuild from scratch) cmake -DBUILD_PYTHON=ON -DBUILD_VERSION=1.0.0 .. (Use -DBUILD_JAVA=ON if the target language is Java) cmake --build . ``` -* 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. +* 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: * 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.