{"id":13813237,"url":"https://github.com/crypto-chassis/ccapi","last_synced_at":"2026-01-28T07:17:14.659Z","repository":{"id":37622317,"uuid":"283317455","full_name":"crypto-chassis/ccapi","owner":"crypto-chassis","description":"A header-only C++ library for interacting with crypto exchanges. Bindings for Python, Java, C#, Go, and Javascript are provided.","archived":false,"fork":false,"pushed_at":"2025-04-27T17:38:57.000Z","size":63602,"stargazers_count":623,"open_issues_count":8,"forks_count":207,"subscribers_count":39,"default_branch":"develop","last_synced_at":"2025-04-27T18:32:38.638Z","etag":null,"topics":["algo-trading","api","arbitrage","automated-trading","bitcoin","c-plus-plus","crypto","cryptocurrency","csharp","exchange","execution","fixprotocol","go","java","javascript","library","market-data","python","strategy","trading-bot"],"latest_commit_sha":null,"homepage":"https://discord.gg/b5EKcp9s8T","language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/crypto-chassis.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2020-07-28T20:14:24.000Z","updated_at":"2025-04-27T17:39:49.000Z","dependencies_parsed_at":"2023-09-26T23:33:03.357Z","dependency_job_id":"7e799a9b-7f01-4b19-96d0-75cdf90c9feb","html_url":"https://github.com/crypto-chassis/ccapi","commit_stats":null,"previous_names":[],"tags_count":181,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/crypto-chassis%2Fccapi","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/crypto-chassis%2Fccapi/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/crypto-chassis%2Fccapi/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/crypto-chassis%2Fccapi/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/crypto-chassis","download_url":"https://codeload.github.com/crypto-chassis/ccapi/tar.gz/refs/heads/develop","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254239940,"owners_count":22037798,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["algo-trading","api","arbitrage","automated-trading","bitcoin","c-plus-plus","crypto","cryptocurrency","csharp","exchange","execution","fixprotocol","go","java","javascript","library","market-data","python","strategy","trading-bot"],"created_at":"2024-08-04T04:01:08.691Z","updated_at":"2026-01-05T23:08:24.562Z","avatar_url":"https://github.com/crypto-chassis.png","language":"C++","readme":"\u003c!-- START doctoc generated TOC please keep comment here to allow auto update --\u003e\n\u003c!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE --\u003e\n**Table of Contents**  *generated with [DocToc](https://github.com/ktechhub/doctoc)*\n\n- [ccapi](#ccapi)\n  - [Branches](#branches)\n  - [Build](#build)\n    - [C++](#c)\n    - [non-C++](#non-c)\n  - [Constants](#constants)\n  - [Examples](#examples)\n  - [Documentations](#documentations)\n    - [Simple Market Data](#simple-market-data)\n    - [Advanced Market Data](#advanced-market-data)\n      - [Complex request parameters](#complex-request-parameters)\n      - [Specify subscription market depth](#specify-subscription-market-depth)\n      - [Specify correlation id](#specify-correlation-id)\n      - [Multiple exchanges and/or instruments](#multiple-exchanges-andor-instruments)\n      - [Receive subscription events at periodic intervals](#receive-subscription-events-at-periodic-intervals)\n      - [Receive subscription events at periodic intervals including when the market depth snapshot hasn't changed](#receive-subscription-events-at-periodic-intervals-including-when-the-market-depth-snapshot-hasnt-changed)\n      - [Receive subscription market depth updates](#receive-subscription-market-depth-updates)\n      - [Receive subscription trade events](#receive-subscription-trade-events)\n      - [Receive subscription calculated-candlestick events at periodic intervals](#receive-subscription-calculated-candlestick-events-at-periodic-intervals)\n      - [Receive subscription exchange-provided-candlestick events at periodic intervals](#receive-subscription-exchange-provided-candlestick-events-at-periodic-intervals)\n      - [Send generic public requests](#send-generic-public-requests)\n      - [Make generic public subscriptions](#make-generic-public-subscriptions)\n      - [Send generic private requests](#send-generic-private-requests)\n    - [Simple Execution Management](#simple-execution-management)\n    - [Advanced Execution Management](#advanced-execution-management)\n      - [Specify correlation id](#specify-correlation-id-1)\n      - [Multiple exchanges and/or instruments](#multiple-exchanges-andor-instruments-1)\n      - [Multiple subscription fields](#multiple-subscription-fields)\n      - [Make Session::sendRequest blocking](#make-sessionsendrequest-blocking)\n      - [Provide API credentials for an exchange](#provide-api-credentials-for-an-exchange)\n      - [Complex request parameters](#complex-request-parameters-1)\n      - [Send request by Websocket API](#send-request-by-websocket-api)\n      - [Specify instrument type](#specify-instrument-type)\n    - [FIX API](#fix-api)\n    - [More Advanced Topics](#more-advanced-topics)\n      - [Handle events in \"immediate\" vs. \"batching\" mode](#handle-events-in-immediate-vs-batching-mode)\n      - [Thread safety](#thread-safety)\n      - [Enable library logging](#enable-library-logging)\n      - [Set timer](#set-timer)\n      - [Heartbeat](#heartbeat)\n      - [Use multiple sessions](#use-multiple-sessions)\n      - [Override exchange urls](#override-exchange-urls)\n      - [Connect to a proxy](#connect-to-a-proxy)\n      - [Reduce build time](#reduce-build-time)\n  - [Performance Tuning](#performance-tuning)\n  - [Known Issues and Workarounds](#known-issues-and-workarounds)\n\n\u003c!-- END doctoc generated TOC please keep comment here to allow auto update --\u003e\n\n# ccapi\n* 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).\n* Bindings for other languages such as Python, Java, C#, Go, and Javascript are provided.\n* Code closely follows Bloomberg's API: https://www.bloomberg.com/professional/support/api-library/.\n* It is ultra fast thanks to very careful optimizations.\n* Supported exchanges:\n  * Market Data: ascendex, [binance](https://accounts.maxweb.academy/register?ref=1116718520), [binance-usds-futures](https://accounts.maxweb.academy/register?ref=1116718520), [binance-coin-futures](https://accounts.maxweb.academy/register?ref=1116718520), bitfinex, bitget, bitget-futures, bitmart, bitmex, bitstamp, [bybit](https://www.bybit.com/invite?ref=XNYP2K), coinbase, [cryptocom](https://crypto.com/exch/tqj4b8x48w), deribit, erisx (Cboe Digital), [gateio](https://www.gate.com/signup/VLUQXVFWAW?ref_type=103), [gateio-perpetual-futures](https://www.gate.com/signup/VLUQXVFWAW?ref_type=103), gemini, [huobi](https://www.htx.com/invite/en-us/1f?invite_code=rmw7d223), [huobi-usdt-swap](https://www.htx.com/invite/en-us/1f?invite_code=rmw7d223), [huobi-coin-swap](https://www.htx.com/invite/en-us/1f?invite_code=rmw7d223), kraken, kraken-futures, kucoin, kucoin-futures, mexc, mexc-futures, [okx](https://www.okx.com/join/47636709), whitebit.\n  * Execution Management: ascendex, [binance](https://accounts.maxweb.academy/register?ref=1116718520), [binance-usds-futures](https://accounts.maxweb.academy/register?ref=1116718520), [binance-coin-futures](https://accounts.maxweb.academy/register?ref=1116718520), bitfinex, bitget, bitget-futures, bitmart, bitmex, bitstamp, [bybit](https://www.bybit.com/invite?ref=XNYP2K), coinbase, [cryptocom](https://crypto.com/exch/tqj4b8x48w), deribit, erisx (Cboe Digital), [gateio](https://www.gate.com/signup/VLUQXVFWAW?ref_type=103), [gateio-perpetual-futures](https://www.gate.com/signup/VLUQXVFWAW?ref_type=103), gemini, [huobi](https://www.htx.com/invite/en-us/1f?invite_code=rmw7d223), [huobi-usdt-swap](https://www.htx.com/invite/en-us/1f?invite_code=rmw7d223), [huobi-coin-swap](https://www.htx.com/invite/en-us/1f?invite_code=rmw7d223), kraken, kraken-futures, kucoin, kucoin-futures, mexc, [okx](https://www.okx.com/join/47636709).\n  * FIX: [binance](https://accounts.maxweb.academy/register?ref=1116718520), coinbase, gemini.\n* Join us on Discord https://discord.gg/b5EKcp9s8T and Medium https://cryptochassis.medium.com.\n* For any questions, email hello@cryptochassis.com.\n* We’re experts in market data collection, high-speed trading system, infrastructure optimization, and proprietary market making. Hire us as engineers, liquidity providers, traders, or asset managers.\n\n## Branches\n* The `develop` branch may contain experimental features.\n* The `master` branch represents the most recent stable release.\n\n## Build\n\n### C++\n* This library is header-only.\n* Example CMake: example/CMakeLists.txt.\n* Require C++17 and OpenSSL.\n* Macros in the compiler command line:\n  * Define service enablement macro such as `CCAPI_ENABLE_SERVICE_MARKET_DATA`, `CCAPI_ENABLE_SERVICE_EXECUTION_MANAGEMENT`, `CCAPI_ENABLE_SERVICE_FIX`, etc. and exchange enablement macros such as `CCAPI_ENABLE_EXCHANGE_BYBIT`, etc. These macros can be found at the top of [`include/ccapi_cpp/ccapi_session.h`](include/ccapi_cpp/ccapi_session.h).\n* Dependencies:\n  * boost https://archives.boost.io/release/1.87.0/source/boost_1_87_0.tar.gz (notice that its include directory is boost).\n  * rapidjson https://github.com/Tencent/rapidjson/archive/refs/tags/v1.1.0.tar.gz (notice that its include directory is rapidjson/include).\n  * If you use FIX API, also need hffix https://github.com/jamesdbrock/hffix/archive/refs/tags/v1.4.1.tar.gz (notice that its include directory is hffix/include).\n* Include directory for this library:\n  * include.\n* Link libraries:\n  * OpenSSL: libssl.\n  * OpenSSL: libcrypto.\n  * If you need market data for huobi/huobi-usdt-swap/huobi-coin-swap or execution management for huobi-usdt-swap/huobi-coin-swap/bitmart, also link ZLIB.\n  * On Windows, also link ws2_32.\n* Compiler flags:\n  * `-pthread` for GCC and MinGW.\n* Tested platforms:\n  * macOS: Clang.\n  * Linux: GCC.\n  * Windows: MinGW.\n* Troubleshoot:\n  * Try to remove all build artifacts and start from scratch (e.g. for cmake remove all the contents inside your build directory).\n  * \"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`.\n  * \"Fatal error: can't write \\\u003ca\u003e bytes to section .text of \\\u003cb\u003e: 'File too big'\". Try to add compiler flag `-Wa,-mbig-obj`. See https://github.com/assimp/assimp/issues/2067.\n  * \"string table overflow at offset \\\u003ca\u003e\". Try to add optimization flag `-O1` or `-O2`. See https://stackoverflow.com/questions/14125007/gcc-string-table-overflow-error-during-compilation.\n  * On Windows, if you still encounter resource related issues, try to add optimization flag `-O3 -DNDEBUG`.\n\n### non-C++\n* Require SWIG and CMake.\n  * SWIG: On macOS, `brew install SWIG`. On Linux, `sudo apt-get install -y swig`.\n  * CMake: https://cmake.org/download/.\n* Run the following commands.\n```\nmkdir binding/build\ncd binding/build\nrm -rf * (if rebuild from scratch)\ncmake -DBUILD_PYTHON=ON -DBUILD_VERSION=1.0.0 .. (Use -DBUILD_JAVA=ON if the target language is Java, -DBUILD_CSHARP=ON if the target language is C#, -DBUILD_GO=ON if the target language is Go, -DBUILD_JAVASCRIPT=ON if the target language is Javascript)\ncmake --build .\n```\n* The packaged build artifacts are located in the `binding/build/\u003clanguage\u003e/packaging/\u003cBUILD_VERSION\u003e` directory. SWIG generated raw files and build artifacts are located in the `binding/build/\u003clanguage\u003e/ccapi_binding_\u003clanguage\u003e` directory.\n* 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.\n* C#: The shared library is built using the .NET framework.\n* Troubleshoot:\n  * \"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`.\n  * Python:\n    * \"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.\n    * \"‘_PyObject_GC_UNTRACK’ was not declared in this scope\". If you use Python \u003e= 3.8, please use SWIG \u003e= 4.0.\n  * Java:\n    * \"Could NOT find JNI (missing: JAVA_INCLUDE_PATH JAVA_INCLUDE_PATH2 JAVA_AWT_INCLUDE_PATH)\". Check that the environment variable `JAVA_HOME` is correct.\n  * Javascript:\n    * \"Check for node-gyp Program: not found\". You can install node-gyp using npm: `npm install -g node-gyp`\n\n## Constants\n[`include/ccapi_cpp/ccapi_macro.h`](include/ccapi_cpp/ccapi_macro.h)\n\n## Examples\n[C++](example)\n* Require CMake.\n  * CMake: https://cmake.org/download/.\n* Run the following commands.\n```\nmkdir example/build\ncd example/build\nrm -rf * (if rebuild from scratch)\ncmake ..\ncmake --build . --target \u003cexample-name\u003e\n```\n* The executable is `example/build/src/\u003cexample-name\u003e/\u003cexample-name\u003e`. Run it.\n\n[Python](binding/python/example)\n* Python API is nearly identical to C++ API and covers nearly all the functionalities from C++ API.\n* Build and install the Python binding as shown [above](#non-c).\n* Inside a concrete example directory (e.g. binding/python/example/market_data_simple_subscription), run\n```\npython3 main.py\n```\n* Troubleshoot:\n  * \"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.\n\n[Java](binding/java/example)\n* Java API is nearly identical to C++ API and covers nearly all the functionalities from C++ API.\n* Build and install the Java binding as shown [above](#non-c).\n* Inside a concrete example directory (e.g. binding/python/example/market_data_simple_subscription), run\n```\nmkdir build\ncd build\nrm -rf * (if rebuild from scratch)\njavac -cp ../../../../build/java/packaging/1.0.0/ccapi-1.0.0.jar -d . ../Main.java\njava -cp .:../../../../build/java/packaging/1.0.0/ccapi-1.0.0.jar -Djava.library.path=../../../../build/java/packaging/1.0.0  Main\n```\n* Troubleshoot:\n  * \"../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`.\n  * \"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.\n\n[C#](binding/csharp/example)\n* C# API is nearly identical to C++ API and covers nearly all the functionalities from C++ API.\n* Build and install the C# binding as shown [above](#non-c).\n* Inside a concrete example directory (e.g. binding/csharp/example/market_data_simple_subscription), run\n```\ndotnet clean (if rebuild from scratch)\nenv LD_LIBRARY_PATH=\"$LD_LIBRARY_PATH:../../../build/csharp/packaging/1.0.0\" dotnet run --property:CcapiLibraryPath=../../../build/csharp/packaging/1.0.0/ccapi.dll -c Release\n```\n* Troubleshoot:\n  * \"error CS0246: The type or namespace name 'ccapi' could not be found\". Check that you aren't missing the ccapi assembly reference.\n  * \"System.DllNotFoundException: Unable to load shared library 'ccapi_binding_csharp.so' or one of its dependencies.\". Check that environment variable `LD_LIBRARY_PATH` includes `binding/build/csharp/packaging/1.0.0`.\n\n[Go](binding/go/example)\n* Go API is nearly identical to C++ API and covers nearly all the functionalities from C++ API.\n* Build and install the Go binding as shown [above](#non-c).\n* Inside a concrete example directory (e.g. binding/go/example/market_data_simple_subscription), run\n```\ngo clean (if rebuild from scratch)\nsource ../../../build/go/packaging/1.0.0/export_compiler_options.sh (this step is important)\ngo build .\n./main\n```\n* Troubleshoot:\n  * Some C/C++ header files not found. Check that you sourced the export_compiler_options.sh file which provides important environment variables needed by the cgo tool.\n\n[Javascript](binding/javascript/example)\n* Javascript API is nearly identical to C++ API and covers nearly all the functionalities from C++ API.\n* Build and install the Javascript binding as shown [above](#non-c).\n* Inside a concrete example directory (e.g. binding/javascript/example/market_data_simple_subscription), run\n```\nrm -rf node_modules (if rebuild from scratch)\nnpm install\nnode index.js\n```\n\n## Documentations\n\n### Simple Market Data\n\n**Objective 1:**\n\nFor a specific exchange and instrument, get recents trades.\n\n**Code 1:**\n\n[C++](example/src/market_data_simple_request/main.cpp) / [Python](binding/python/example/market_data_simple_request/main.py) / [Java](binding/java/example/market_data_simple_request/Main.java) / [C#](binding/csharp/example/market_data_simple_request/MainProgram.cs) / [Go](binding/go/example/market_data_simple_request/main.go) / [Javascript](binding/javascript/example/market_data_simple_request/index.js)\n```\n#include \"ccapi_cpp/ccapi_session.h\"\n\nnamespace ccapi {\n\nLogger* Logger::logger = nullptr;  // This line is needed.\n\nclass MyEventHandler : public EventHandler {\n public:\n  void processEvent(const Event\u0026 event, Session* sessionPtr) override {\n    std::cout \u003c\u003c \"Received an event:\\n\" + event.toPrettyString(2, 2) \u003c\u003c std::endl;\n  }\n};\n\n} /* namespace ccapi */\n\nusing ::ccapi::MyEventHandler;\nusing ::ccapi::Request;\nusing ::ccapi::Session;\nusing ::ccapi::SessionConfigs;\nusing ::ccapi::SessionOptions;\n\nint main(int argc, char** argv) {\n  SessionOptions sessionOptions;\n  SessionConfigs sessionConfigs;\n  MyEventHandler eventHandler;\n  Session session(sessionOptions, sessionConfigs, \u0026eventHandler);\n  Request request(Request::Operation::GET_RECENT_TRADES, \"bybit\", \"BTCUSDT\");\n  request.appendParam({\n      {\"LIMIT\", \"1\"},\n  });\n  session.sendRequest(request);\n  std::this_thread::sleep_for(std::chrono::seconds(10));\n  session.stop();\n  std::cout \u003c\u003c \"Bye\" \u003c\u003c std::endl;\n  return EXIT_SUCCESS;\n}\n\n```\n\n**Output 1:**\n```console\nReceived an event:\n  Event [\n    type = RESPONSE,\n    messageList = [\n      Message [\n        type = GET_RECENT_TRADES,\n        recapType = UNKNOWN,\n        time = 2021-05-25T03:23:31.124000000Z,\n        timeReceived = 2021-05-25T03:23:31.239734000Z,\n        elementList = [\n          Element [\n            nameValueMap = {\n              IS_BUYER_MAKER = 1,\n              LAST_PRICE = 38270.71,\n              LAST_SIZE = 0.001,\n              TRADE_ID = 178766798\n            }\n          ]\n        ],\n        correlationIdList = [ 5PN2qmWqBlQ9wQj99nsQzldVI5ZuGXbE ]\n      ]\n    ]\n  ]\nBye\n```\n* Request operation types: `GET_SERVER_TIME`, `GET_INSTRUMENT`, `GET_INSTRUMENTS`, `GET_BBOS`, `GET_RECENT_TRADES`, `GET_HISTORICAL_TRADES`, `GET_RECENT_CANDLESTICKS`, `GET_HISTORICAL_CANDLESTICKS`, `GET_RECENT_AGG_TRADES`, `GET_HISTORICAL_AGG_TRADES`(only applicable to binance family: https://binance-docs.github.io/apidocs/spot/en/#compressed-aggregate-trades-list), ``.\n* Request parameter names: `LIMIT`, `INSTRUMENT_TYPE`, `CANDLESTICK_INTERVAL_SECONDS`, `START_TIME_SECONDS`, `END_TIME_SECONDS`, `START_TRADE_ID`, `END_TRADE_ID`, `START_AGG_TRADE_ID`, `END_AGG_TRADE_ID`. 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).\n* 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).\n\n**Objective 2:**\n\nFor 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.\n\n**Code 2:**\n\n[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) / [C#](binding/csharp/example/market_data_simple_subscription/MainProgram.cs) / [Go](binding/go/example/market_data_simple_subscription/main.go) / [Javascript](binding/javascript/example/market_data_simple_subscription/index.js)\n```\n#include \"ccapi_cpp/ccapi_session.h\"\n\nnamespace ccapi {\n\nLogger* Logger::logger = nullptr;  // This line is needed.\n\nclass MyEventHandler : public EventHandler {\n public:\n  void processEvent(const Event\u0026 event, Session* sessionPtr) override {\n    if (event.getType() == Event::Type::SUBSCRIPTION_STATUS) {\n      std::cout \u003c\u003c \"Received an event of type SUBSCRIPTION_STATUS:\\n\" + event.toPrettyString(2, 2) \u003c\u003c std::endl;\n    } else if (event.getType() == Event::Type::SUBSCRIPTION_DATA) {\n      for (const auto\u0026 message : event.getMessageList()) {\n        std::cout \u003c\u003c std::string(\"Best bid and ask at \") + UtilTime::getISOTimestamp(message.getTime()) + \" are:\" \u003c\u003c std::endl;\n        for (const auto\u0026 element : message.getElementList()) {\n          // They key std::string_view is created from a string literal and therefore is safe, because string\n          // literals have static storage duration, meaning they live for the entire duration of the program.\n          const std::map\u003cstd::string_view, std::string\u003e\u0026 elementNameValueMap = element.getNameValueMap();\n          std::cout \u003c\u003c \"  \" + toString(elementNameValueMap) \u003c\u003c std::endl;\n        }\n      }\n    }\n  }\n};\n\n} /* namespace ccapi */\n\nusing ::ccapi::MyEventHandler;\nusing ::ccapi::Session;\nusing ::ccapi::SessionConfigs;\nusing ::ccapi::SessionOptions;\nusing ::ccapi::Subscription;\nusing ::ccapi::toString;\n\nint main(int argc, char** argv) {\n  SessionOptions sessionOptions;\n  SessionConfigs sessionConfigs;\n  MyEventHandler eventHandler;\n  Session session(sessionOptions, sessionConfigs, \u0026eventHandler);\n  Subscription subscription(\"bybit\", \"BTCUSDT\", \"MARKET_DEPTH\");\n  session.subscribe(subscription);\n  std::this_thread::sleep_for(std::chrono::seconds(10));\n  session.stop();\n  std::cout \u003c\u003c \"Bye\" \u003c\u003c std::endl;\n  return EXIT_SUCCESS;\n}\n\n```\n\n**Output 2:**\n```console\nBest bid and ask at 2020-07-27T23:56:51.884855000Z are:\n  {BID_PRICE=10995, BID_SIZE=0.22187803}\n  {ASK_PRICE=10995.44, ASK_SIZE=2}\nBest bid and ask at 2020-07-27T23:56:51.935993000Z are:\n  ...\n```\n* Subscription fields: `MARKET_DEPTH`, `TRADE`, `CANDLESTICK`, `AGG_TRADE`(only applicable to binance family: https://binance-docs.github.io/apidocs/spot/en/#aggregate-trade-streams).\n\n### Advanced Market Data\n\n#### Complex request parameters\nPlease follow the exchange's API documentations: e.g. https://bybit-exchange.github.io/docs/v5/market/instrument.\n```\nRequest request(Request::Operation::GET_INSTRUMENTS, \"bybit\");\nrequest.appendParam({\n    {\"category\", \"linear\"},\n    {\"limit\", \"1000\"},\n});\n```\n\n#### Specify subscription market depth\n\nInstantiate `Subscription` with option `MARKET_DEPTH_MAX` set to be the desired market depth (e.g. you want to receive market depth snapshot whenever the top 10 bid's or ask's price or size changes).\n```\nSubscription subscription(\"bybit\", \"BTCUSDT\", \"MARKET_DEPTH\", \"MARKET_DEPTH_MAX=10\");\n```\n\n#### Specify correlation id\n\nInstantiate `Request` with the desired correlationId. The `correlationId` should be unique.\n```\nRequest request(Request::Operation::GET_RECENT_TRADES, \"bybit\", \"BTCUSDT\", \"cool correlation id\");\n```\nInstantiate `Subscription` with the desired correlationId.\n```\nSubscription subscription(\"bybit\", \"BTCUSDT\", \"MARKET_DEPTH\", \"\", \"cool correlation id\");\n```\nThis is used to match a particular request or subscription with its returned data. Within each `Message` there is a `correlationIdList` to identify the request or subscription that requested the data.\n\n#### Multiple exchanges and/or instruments\n\nSend a `std::vector\u003cRequest\u003e`.\n```\nRequest request_1(Request::Operation::GET_RECENT_TRADES, \"bybit\", \"BTCUSDT\", \"cool correlation id for BTC\");\nrequest_1.appendParam(...);\nRequest request_2(Request::Operation::GET_RECENT_TRADES, \"binance\", \"ETH-USDT\", \"cool correlation id for ETH\");\nrequest_2.appendParam(...);\nstd::vector\u003cccapi::Request\u003e requests = {request_1, request_2};\nsession.sendRequest(requests);\n```\nSubscribe a `std::vector\u003cSubscription\u003e`.\n```\nSubscription subscription_1(\"bybit\", \"BTCUSDT\", \"MARKET_DEPTH\", \"\", \"cool correlation id for bybit BTCUSDT\");\nSubscription subscription_2(\"binance\", \"ETHUSDT\", \"MARKET_DEPTH\", \"\", \"cool correlation id for binance ETHUSDT\");\nstd::vector\u003cccapi::Subscription\u003e subscriptions = {subscription_1, subscription_2};\nsession.subscribe(subscriptions);\n```\n\n#### Receive subscription events at periodic intervals\n\nInstantiate `Subscription` with option `CONFLATE_INTERVAL_MILLISECONDS` set to be the desired interval.\n```\nSubscription subscription(\"bybit\", \"BTCUSDT\", \"MARKET_DEPTH\", \"CONFLATE_INTERVAL_MILLISECONDS=1000\");\n```\n\n#### Receive subscription events at periodic intervals including when the market depth snapshot hasn't changed\n\nInstantiate `Subscription` with option `CONFLATE_INTERVAL_MILLISECONDS` set to be the desired interval and `CONFLATE_GRACE_PERIOD_MILLISECONDS` to be the grace period for late events.\n```\nSubscription subscription(\"bybit\", \"BTCUSDT\", \"MARKET_DEPTH\", \"CONFLATE_INTERVAL_MILLISECONDS=1000\u0026CONFLATE_GRACE_PERIOD_MILLISECONDS=0\");\n```\n\n#### Receive subscription market depth updates\n\nInstantiate `Subscription` with option `MARKET_DEPTH_RETURN_UPDATE` set to 1. This will return the order book updates instead of snapshots.\n```\nSubscription subscription(\"bybit\", \"BTCUSDT\", \"MARKET_DEPTH\", \"MARKET_DEPTH_RETURN_UPDATE=1\u0026MARKET_DEPTH_MAX=2\");\n```\n\n#### Receive subscription trade events\n\nInstantiate `Subscription` with field `TRADE`.\n```\nSubscription subscription(\"bybit\", \"BTCUSDT\", \"TRADE\");\n```\n\n#### Receive subscription calculated-candlestick events at periodic intervals\n\nInstantiate `Subscription` with field `TRADE` and option `CONFLATE_INTERVAL_MILLISECONDS` set to be the desired interval and `CONFLATE_GRACE_PERIOD_MILLISECONDS` to be your network latency.\n```\nSubscription subscription(\"bybit\", \"BTCUSDT\", \"TRADE\", \"CONFLATE_INTERVAL_MILLISECONDS=5000\u0026CONFLATE_GRACE_PERIOD_MILLISECONDS=0\");\n```\n\n#### Receive subscription exchange-provided-candlestick events at periodic intervals\n\nInstantiate `Subscription` with field `CANDLESTICK` and option `CANDLESTICK_INTERVAL_SECONDS` set to be the desired interval.\n```\nSubscription subscription(\"bybit\", \"BTCUSDT\", \"CANDLESTICK\", \"CANDLESTICK_INTERVAL_SECONDS=60\");\n```\n\n#### Send generic public requests\n\nInstantiate `Request` with operation `GENERIC_PUBLIC_REQUEST`. Provide request parameters `HTTP_METHOD`, `HTTP_PATH`, and optionally `HTTP_QUERY_STRING` (query string parameter values should be url-encoded), `HTTP_BODY`.\n```\nRequest request(Request::Operation::GENERIC_PUBLIC_REQUEST, \"bybit\", \"\", \"Check Server Time\");\nrequest.appendParam({\n    {\"HTTP_METHOD\", \"GET\"},\n    {\"HTTP_PATH\", \"/api/v5/public/time\"},\n});\n```\n\n#### Make generic public subscriptions\n\nInstantiate `Subscription` with empty instrument, field `GENERIC_PUBLIC_SUBSCRIPTION` and options set to be the desired websocket payload.\n```\nSubscription subscription(\"bybit\", \"\", \"GENERIC_PUBLIC_SUBSCRIPTION\", R\"({\"type\":\"subscribe\",\"channels\":[{\"name\":\"status\"}]})\");\n```\n\n#### Send generic private requests\n\nInstantiate `Request` with operation `GENERIC_PRIVATE_REQUEST`. Provide request parameters `HTTP_METHOD`, `HTTP_PATH`, and optionally `HTTP_QUERY_STRING` (query string parameter values should be url-encoded), `HTTP_BODY`.\n```\nRequest request(Request::Operation::GENERIC_PRIVATE_REQUEST, \"bybit\", \"\", \"close all positions\");\nrequest.appendParam({\n    {\"HTTP_METHOD\", \"POST\"},\n    {\"HTTP_PATH\", \"/api/v5/trade/close-position\"},\n    {\"HTTP_BODY\", R\"({\n      \"instId\": \"BTC-USDT-SWAP\",\n      \"mgnMode\": \"cross\"\n  })\"},\n});\n```\n\n### Simple Execution Management\n\n**Objective 1:**\n\nFor a specific exchange and instrument, submit a simple limit order.\n\n**Code 1:**\n\n[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) / [C#](binding/csharp/example/execution_management_simple_request/MainProgram.cs) / [Go](binding/go/example/execution_management_simple_request/main.go) / [Javascript](binding/javascript/example/execution_management_simple_request/index.js)\n```\n#include \"ccapi_cpp/ccapi_session.h\"\n\nnamespace ccapi {\n\nLogger* Logger::logger = nullptr;  // This line is needed.\n\nclass MyEventHandler : public EventHandler {\n public:\n  void processEvent(const Event\u0026 event, Session* sessionPtr) override {\n    std::cout \u003c\u003c \"Received an event:\\n\" + event.toPrettyString(2, 2) \u003c\u003c std::endl;\n  }\n};\n\n} /* namespace ccapi */\n\nusing ::ccapi::MyEventHandler;\nusing ::ccapi::Request;\nusing ::ccapi::Session;\nusing ::ccapi::SessionConfigs;\nusing ::ccapi::SessionOptions;\nusing ::ccapi::toString;\nusing ::ccapi::UtilSystem;\n\nint main(int argc, char** argv) {\n  if (UtilSystem::getEnvAsString(\"BYBIT_API_KEY\").empty()) {\n    std::cerr \u003c\u003c \"Please set environment variable BYBIT_API_KEY\" \u003c\u003c std::endl;\n    return EXIT_FAILURE;\n  }\n  if (UtilSystem::getEnvAsString(\"BYBIT_API_SECRET\").empty()) {\n    std::cerr \u003c\u003c \"Please set environment variable BYBIT_API_SECRET\" \u003c\u003c std::endl;\n    return EXIT_FAILURE;\n  }\n\n\n  SessionOptions sessionOptions;\n  SessionConfigs sessionConfigs;\n  MyEventHandler eventHandler;\n  Session session(sessionOptions, sessionConfigs, \u0026eventHandler);\n  Request request(Request::Operation::CREATE_ORDER, \"bybit\", \"BTCUSDT\");\n  request.appendParam({\n      {\"SIDE\", \"BUY\"},\n      {\"QUANTITY\", \"0.0005\"},\n      {\"LIMIT_PRICE\", \"100000\"},\n  });\n  session.sendRequest(request);\n  std::this_thread::sleep_for(std::chrono::seconds(10));\n  session.stop();\n  std::cout \u003c\u003c \"Bye\" \u003c\u003c std::endl;\n  return EXIT_SUCCESS;\n}\n\n```\n\n**Output 1:**\n```console\nReceived an event:\n  Event [\n    type = RESPONSE,\n    messageList = [\n      Message [\n        type = CREATE_ORDER,\n        recapType = UNKNOWN,\n        time = 1970-01-01T00:00:00.000000000Z,\n        timeReceived = 2021-05-25T03:47:15.599562000Z,\n        elementList = [\n          Element [\n            nameValueMap = {\n              CLIENT_ORDER_ID = wBgmzOJbbMTCLJlwTrIeiH,\n              CUMULATIVE_FILLED_PRICE_TIMES_QUANTITY = 0,\n              CUMULATIVE_FILLED_QUANTITY = 0,\n              INSTRUMENT = BTC-USDT,\n              LIMIT_PRICE = 100000,\n              ORDER_ID = 383781246,\n              QUANTITY = 0.0005,\n              SIDE = BUY,\n              STATUS = live\n            }\n          ]\n        ],\n        correlationIdList = [ 5PN2qmWqBlQ9wQj99nsQzldVI5ZuGXbE ]\n      ]\n    ]\n  ]\nBye\n```\n* Request operation types: `CREATE_ORDER`, `CANCEL_ORDER`, `GET_ORDER`, `GET_OPEN_ORDERS`, `CANCEL_OPEN_ORDERS`, `GET_ACCOUNTS`, `GET_ACCOUNT_BALANCES`, `GET_ACCOUNT_POSITIONS`.\n* Request parameter names: `SIDE`, `QUANTITY`, `LIMIT_PRICE`, `ACCOUNT_ID`, `ACCOUNT_TYPE`, `ORDER_ID`, `CLIENT_ORDER_ID`, `PARTY_ID`, `ORDER_TYPE`, `LEVERAGE`. 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/execution_management_advanced_request/main.cpp).\n\n**Objective 2:**\n\nFor a specific exchange and instrument, receive order updates.\n\n**Code 2:**\n\n[C++](example/src/execution_management_simple_subscription/main.cpp) / [Python](binding/python/example/execution_management_simple_subscription/main.py) / [Java](binding/java/example/execution_management_simple_subscription/Main.java) / [C#](binding/csharp/example/execution_management_simple_subscription/MainProgram.cs) / [Go](binding/go/example/execution_management_simple_subscription/main.go) / [Javascript](binding/javascript/example/execution_management_simple_subscription/index.js)\n```\n#include \"ccapi_cpp/ccapi_session.h\"\n\nnamespace ccapi {\n\nLogger* Logger::logger = nullptr;  // This line is needed.\n\nclass MyEventHandler : public EventHandler {\n public:\n  void processEvent(const Event\u0026 event, Session* sessionPtr) override {\n    if (event.getType() == Event::Type::SUBSCRIPTION_STATUS) {\n      std::cout \u003c\u003c \"Received an event of type SUBSCRIPTION_STATUS:\\n\" + event.toPrettyString(2, 2) \u003c\u003c std::endl;\n      auto message = event.getMessageList().at(0);\n      if (message.getType() == Message::Type::SUBSCRIPTION_STARTED) {\n        Request request(Request::Operation::CREATE_ORDER, \"bybit\", \"BTCUSDT\");\n        request.appendParam({\n            {\"SIDE\", \"BUY\"},\n            {\"LIMIT_PRICE\", \"20000\"},\n            {\"QUANTITY\", \"0.001\"},\n            {\"CLIENT_ORDER_ID\", request.generateNextClientOrderId()},\n        });\n        sessionPtr-\u003esendRequest(request);\n      }\n    } else if (event.getType() == Event::Type::SUBSCRIPTION_DATA) {\n      std::cout \u003c\u003c \"Received an event of type SUBSCRIPTION_DATA:\\n\" + event.toPrettyString(2, 2) \u003c\u003c std::endl;\n    }\n  }\n};\n\n} /* namespace ccapi */\n\nusing ::ccapi::MyEventHandler;\nusing ::ccapi::Request;\nusing ::ccapi::Session;\nusing ::ccapi::SessionConfigs;\nusing ::ccapi::SessionOptions;\nusing ::ccapi::Subscription;\nusing ::ccapi::UtilSystem;\n\nint main(int argc, char** argv) {\n  if (UtilSystem::getEnvAsString(\"BYBIT_API_KEY\").empty()) {\n    std::cerr \u003c\u003c \"Please set environment variable BYBIT_API_KEY\" \u003c\u003c std::endl;\n    return EXIT_FAILURE;\n  }\n  if (UtilSystem::getEnvAsString(\"BYBIT_API_SECRET\").empty()) {\n    std::cerr \u003c\u003c \"Please set environment variable BYBIT_API_SECRET\" \u003c\u003c std::endl;\n    return EXIT_FAILURE;\n  }\n\n  SessionOptions sessionOptions;\n  SessionConfigs sessionConfigs;\n  MyEventHandler eventHandler;\n  Session session(sessionOptions, sessionConfigs, \u0026eventHandler);\n  Subscription subscription(\"bybit\", \"BTCUSDT\", \"ORDER_UPDATE\");\n  session.subscribe(subscription);\n  std::this_thread::sleep_for(std::chrono::seconds(10));\n  session.stop();\n  std::cout \u003c\u003c \"Bye\" \u003c\u003c std::endl;\n  return EXIT_SUCCESS;\n}\n\n```\n\n**Output 2:**\n```console\nReceived an event of type SUBSCRIPTION_STATUS:\n  Event [\n    type = SUBSCRIPTION_STATUS,\n    messageList = [\n      Message [\n        type = SUBSCRIPTION_STARTED,\n        recapType = UNKNOWN,\n        time = 1970-01-01T00:00:00.000000000Z,\n        timeReceived = 2021-05-25T04:22:25.906197000Z,\n        elementList = [\n\n        ],\n        correlationIdList = [ 5PN2qmWqBlQ9wQj99nsQzldVI5ZuGXbE ]\n      ]\n    ]\n  ]\nReceived an event of type SUBSCRIPTION_DATA:\n  Event [\n    type = SUBSCRIPTION_DATA,\n    messageList = [\n      Message [\n        type = EXECUTION_MANAGEMENT_EVENTS_ORDER_UPDATE,\n        recapType = UNKNOWN,\n        time = 2021-05-25T04:22:26.653785000Z,\n        timeReceived = 2021-05-25T04:22:26.407419000Z,\n        elementList = [\n          Element [\n            nameValueMap = {\n              CLIENT_ORDER_ID = ,\n              INSTRUMENT = BTC-USDT,\n              LIMIT_PRICE = 20000,\n              ORDER_ID = 6ca39186-be79-4777-97ab-1695fccd0ce4,\n              QUANTITY = 0.001,\n              SIDE = BUY,\n              STATUS = live\n            }\n          ]\n        ],\n        correlationIdList = [ 5PN2qmWqBlQ9wQj99nsQzldVI5ZuGXbE ]\n      ]\n    ]\n  ]\nBye\n```\n* Subscription fields: `ORDER_UPDATE`, `PRIVATE_TRADE`, `PRIVATE_TRADE_LITE`, `BALANCE_UPDATE`, `POSITION_UPDATE`.\n\n### Advanced Execution Management\n\n#### Specify correlation id\n\nInstantiate `Request` with the desired `correlationId`. The `correlationId` should be unique.\n```\nRequest request(Request::Operation::CREATE_ORDER, \"bybit\", \"BTCUSDT\", \"cool correlation id\");\n```\nInstantiate `Subscription` with the desired `correlationId`.\n```\nSubscription subscription(\"bybit\", \"BTCUSDT\", \"ORDER_UPDATE\", \"\", \"cool correlation id\");\n```\nThis is used to match a particular request or subscription with its returned data. Within each `Message` there is a `correlationIdList` to identify the request or subscription that requested the data.\n\n#### Multiple exchanges and/or instruments\n\nSend a `std::vector\u003cRequest\u003e`.\n```\nRequest request_1(Request::Operation::CREATE_ORDER, \"bybit\", \"BTCUSDT\", \"cool correlation id for BTC\");\nrequest_1.appendParam(...);\nRequest request_2(Request::Operation::CREATE_ORDER, \"bybit\", \"ETH-USDT\", \"cool correlation id for ETH\");\nrequest_2.appendParam(...);\nstd::vector\u003cccapi::Request\u003e requests = {request_1, request_2};\nsession.sendRequest(requests);\n```\nSubscribe one `Subscription` per exchange with a comma separated string of instruments.\n```\nSubscription subscription(\"bybit\", \"BTC-USDT,ETH-USDT\", \"ORDER_UPDATE\");\n```\n\n#### Multiple subscription fields\n\nSubscribe one `Subscription` with a comma separated string of fields.\n```\nSubscription subscription(\"bybit\", \"BTCUSDT\", \"ORDER_UPDATE,PRIVATE_TRADE\");\n```\n\n#### Make Session::sendRequest blocking\nInstantiate `Session` without `EventHandler` argument, and pass a pointer to `Queue\u003cEvent\u003e` as an additional argument.\n```\nSession session(sessionOptions, sessionConfigs);\n...\nQueue\u003cEvent\u003e eventQueue;\nsession.sendRequest(request, \u0026eventQueue);  // block until a response is received\nstd::vector\u003cEvent\u003e eventList = eventQueue.purge();\n```\n\n#### Provide API credentials for an exchange\nThere are 3 ways to provide API credentials (listed with increasing priority).\n* Set the relevent environment variables. Some exchanges might need additional credentials other than API keys and secrets: e.g. `OKX_API_PASSPHRASE`, `KUCOIN_API_PASSPHRASE`, `BINANCE_USDS_FUTURES_WEBSOCKET_ORDER_ENTRY_API_KEY`, `BINANCE_USDS_FUTURES_WEBSOCKET_ORDER_ENTRY_API_PRIVATE_KEY_PATH`, `BINANCE_COIN_FUTURES_WEBSOCKET_ORDER_ENTRY_API_KEY`, `BINANCE_COIN_FUTURES_WEBSOCKET_ORDER_ENTRY_API_PRIVATE_KEY_PATH`, `BINANCE_WEBSOCKET_ORDER_ENTRY_API_KEY`, `BINANCE_WEBSOCKET_ORDER_ENTRY_API_PRIVATE_KEY_PATH`. See section \"exchange API credentials\" in [`include/ccapi_cpp/ccapi_macro.h`](include/ccapi_cpp/ccapi_macro.h).\n* Provide credentials to `SessionConfigs`.\n```\nsessionConfigs.setCredential({\n  {\"BYBIT_API_KEY\", ...},\n  {\"BYBIT_API_SECRET\", ...}\n});\n```\n* Provide credentials to `Request` or `Subscription`.\n```\nRequest request(Request::Operation::CREATE_ORDER, \"bybit\", \"BTCUSDT\", \"\", {\n  {\"BYBIT_API_KEY\", ...},\n  {\"BYBIT_API_SECRET\", ...}\n});\n```\n```\nSubscription subscription(\"bybit\", \"BTCUSDT\", \"ORDER_UPDATE\", \"\", \"\", {\n  {\"BYBIT_API_KEY\", ...},\n  {\"BYBIT_API_SECRET\", ...}\n});\n```\n\n#### Complex request parameters\nPlease follow the exchange's API documentations: e.g. https://bybit-exchange.github.io/docs/v5/order/create-order.\n```\nRequest request(Request::Operation::CREATE_ORDER, \"bybit\", \"BTCUSDT\");\nrequest.appendParam({\n    {\"isLeverage\", \"1\"},\n});\n```\n\n#### Send request by Websocket API\nFor okx, cryptocom:\n```\nstd::string websocketOrderEntrySubscriptionCorrelationId(\"any\");\nSubscription subscription(\"bybit\", \"\", \"ORDER_UPDATE\", \"\", websocketOrderEntrySubscriptionCorrelationId);\nsession.subscribe(subscription);\n...\nRequest request(Request::Operation::CREATE_ORDER, \"bybit\", \"BTCUSDT\");\nrequest.appendParam({\n    {\"SIDE\", \"BUY\"},\n    {\"LIMIT_PRICE\", \"20000\"},\n    {\"QUANTITY\", \"0.001\"},\n});\nsession.sendRequestByWebsocket(websocketOrderEntrySubscriptionCorrelationId, request);\n```\nFor bybit, binance, binance-usds-futures, binance-coin-futures:\n```\nstd::string websocketOrderEntrySubscriptionCorrelationId(\"any\");\nSubscription subscription_1(\"bybit\", \"\", \"ORDER_UPDATE\");\nSubscription subscription_2(\"bybit\", \"\", \"WEBSOCKET_ORDER_ENTRY\", \"\", websocketOrderEntrySubscriptionCorrelationId);\nstd::vector\u003cccapi::Subscription\u003e subscriptions = {subscription_1, subscription_2};\nsession.subscribe(subscriptions);\n...\nRequest request(Request::Operation::CREATE_ORDER, \"bybit\", \"BTCUSDT\");\nrequest.appendParam({\n    {\"SIDE\", \"BUY\"},\n    {\"LIMIT_PRICE\", \"20000\"},\n    {\"QUANTITY\", \"0.001\"},\n});\nsession.sendRequestByWebsocket(websocketOrderEntrySubscriptionCorrelationId, request);\n```\n\n#### Specify instrument type\nSome exchanges (i.e. bybit) might need instrument type for `Subscription`. Use `Subscription`'s `setInstrumentType` method.\n```\nSubscription subscription(\"bybit\", \"BTCUSDT\", \"MARKET_DEPTH\");\nsubscription.setInstrumentType(\"spot\");\nsession.subscribe(subscription);\n```\n\n### FIX API\n\n**Objective:**\n\nFor a specific exchange and instrument, submit a simple limit order.\n\n**Code:**\n\n[C++](example/src/fix_simple/main.cpp) / [Python](binding/python/example/fix_simple/main.py) / [Java](binding/java/example/fix_simple/Main.java) / [C#](binding/csharp/example/fix_simple/MainProgram.cs) / [Go](binding/go/example/fix_simple/main.go) / [Javascript](binding/javascript/example/fix_simple/index.js)\n```\n#include \"ccapi_cpp/ccapi_session.h\"\n\nnamespace ccapi {\n\nLogger* Logger::logger = nullptr;  // This line is needed.\n\nclass MyEventHandler : public EventHandler {\n public:\n  MyEventHandler(const std::string\u0026 fixSubscriptionCorrelationId) : fixSubscriptionCorrelationId(fixSubscriptionCorrelationId) {}\n\n  void processEvent(const Event\u0026 event, Session* sessionPtr) override {\n    std::cout \u003c\u003c \"Received an event:\\n\" + event.toPrettyString(2, 2) \u003c\u003c std::endl;\n    if (!willSendRequest) {\n      sessionPtr-\u003esetTimer(\"id\", 1000, nullptr, [this, sessionPtr]() {\n        Request request(Request::Operation::FIX, \"binance\");\n        request.appendFixParam({\n            {35, \"D\"},\n            {11, request.generateNextClientOrderId()},\n            {55, \"BTCUSDT\"},\n            {54, \"1\"},\n            {44, \"100000\"},\n            {38, \"0.0001\"},\n            {40, \"2\"},\n            {59, \"1\"},\n        });\n        sessionPtr-\u003esendRequestByFix(this-\u003efixSubscriptionCorrelationId, request);\n      });\n      willSendRequest = true;\n    }\n  }\n\n private:\n  std::string fixSubscriptionCorrelationId;\n  bool willSendRequest{};\n};\n\n} /* namespace ccapi */\n\nusing ::ccapi::MyEventHandler;\nusing ::ccapi::Session;\nusing ::ccapi::SessionConfigs;\nusing ::ccapi::SessionOptions;\nusing ::ccapi::Subscription;\nusing ::ccapi::UtilSystem;\n\nint main(int argc, char** argv) {\n  if (UtilSystem::getEnvAsString(\"BINANCE_FIX_API_KEY\").empty()) {\n    std::cerr \u003c\u003c \"Please set environment variable BINANCE_FIX_API_KEY\" \u003c\u003c std::endl;\n    return EXIT_FAILURE;\n  }\n  if (UtilSystem::getEnvAsString(\"BINANCE_FIX_API_PRIVATE_KEY_PATH\").empty()) {\n    std::cerr \u003c\u003c \"Please set environment variable BINANCE_FIX_API_PRIVATE_KEY_PATH\" \u003c\u003c std::endl;\n    return EXIT_FAILURE;\n  }\n  SessionOptions sessionOptions;\n  SessionConfigs sessionConfigs;\n  std::string fixSubscriptionCorrelationId(\"any\");\n  MyEventHandler eventHandler(fixSubscriptionCorrelationId);\n  Session session(sessionOptions, sessionConfigs, \u0026eventHandler);\n  Subscription subscription(\"binance\", \"\", \"FIX\", \"\", fixSubscriptionCorrelationId);\n  session.subscribe(subscription);\n  std::this_thread::sleep_for(std::chrono::seconds(10));\n  session.stop();\n  std::cout \u003c\u003c \"Bye\" \u003c\u003c std::endl;\n  return EXIT_SUCCESS;\n}\n```\n**Output:**\n```console\nReceived an event:\n  Event [\n    type = SESSION_STATUS,\n    messageList = [\n      Message [\n        type = SESSION_CONNECTION_UP,\n        recapType = UNKNOWN,\n        time = 1970-01-01T00:00:00.000000000Z,\n        timeReceived = 2025-08-08T18:50:06.816550779Z,\n        elementList = [\n          Element [\n            tagValueList = [\n\n            ],\n            nameValueMap = {\n              CONNECTION_ID = IF8j4HbdLP0,\n              CONNECTION_URL = tcp+tls://fix-oe.binance.com:9000\n            }\n          ]\n        ],\n        correlationIdList = [ any ],\n      ]\n    ]\n  ]\nReceived an event:\n  Event [\n    type = AUTHORIZATION_STATUS,\n    messageList = [\n      Message [\n        type = AUTHORIZATION_SUCCESS,\n        recapType = UNKNOWN,\n        time = 1970-01-01T00:00:00.000000000Z,\n        timeReceived = 2025-08-08T18:50:06.819417404Z,\n        elementList = [\n          Element [\n            tagValueList = [\n              (35, \"A\"),\n              (98, \"0\"),\n              (108, \"60\"),\n              (25037, \"e9ed8253-8f49-4a1b-bba9-718ff73991e5\")\n            ],\n            nameValueMap = {\n\n            }\n          ]\n        ],\n        correlationIdList = [ any ],\n      ]\n    ]\n  ]\nReceived an event:\n  Event [\n    type = FIX,\n    messageList = [\n      Message [\n        type = FIX,\n        recapType = UNKNOWN,\n        time = 1970-01-01T00:00:00.000000000Z,\n        timeReceived = 2025-08-08T18:50:07.820112736Z,\n        elementList = [\n          Element [\n            tagValueList = [\n              (35, \"8\"),\n              (17, \"100146443390\"),\n              (11, \"x-XHKUG2CH-1754679007000\"),\n              (37, \"47156106695\"),\n              (38, \"0.00010000\"),\n              (40, \"2\"),\n              (54, \"1\"),\n              (55, \"BTCUSDT\"),\n              (44, \"100000.00000000\"),\n              (59, \"1\"),\n              (60, \"20250808-18:50:07.819027\"),\n              (25018, \"20250808-18:50:07.819027\"),\n              (25001, \"3\"),\n              (150, \"0\"),\n              (14, \"0.00000000\"),\n              (151, \"0.00010000\"),\n              (25017, \"0.00000000\"),\n              (1057, \"Y\"),\n              (32, \"0.00000000\"),\n              (39, \"0\"),\n              (636, \"Y\"),\n              (25023, \"20250808-18:50:07.819027\")\n            ],\n            nameValueMap = {\n\n            }\n          ]\n        ],\n        correlationIdList = [ any ],\n      ]\n    ]\n  ]\nBye\n```\n\n### More Advanced Topics\n\n#### Handle events in \"immediate\" vs. \"batching\" mode\n\nIn general there are 2 ways to handle events.\n* When a `Session` is instantiated with an `eventHandler` argument, it will handle events in immediate mode. The `processEvent` method in the `eventHandler` will be invoked immediately when an `Event` is available, and the invocation will run on the thread where `boost::asio::io_context` runs. When a `Session` is instantiated with an `eventHandler` and an `eventDispatcher` argument, it will also handle events in immediate mode. The `processEvent` method in the `eventHandler` will also be invoked immediately when an `Event` is available, but the invocation will run in the thread(s) provided by the `eventDispatcher` therefore not blocking the thread where `boost::asio::io_context` runs. `EventHandler`s and/or `EventDispatcher`s can be shared among different sessions. Otherwise, different sessions are independent from each other.\nAn example can be found [here](example/src/market_data_advanced_subscription/main.cpp).\n* When a `Session` is instantiated without an `eventHandler` argument, it will handle events in batching mode. The events will be batched into an internal `Queue\u003cEvent\u003e` and can be retrieved by\n```\nstd::vector\u003cEvent\u003e eventList = session.getEventQueue().purge();\n```\nAn example can be found [here](example/src/market_data_advanced_subscription/main.cpp).\n\n#### Thread safety\n* The following methods are implemented to be thread-safe: `Session::sendRequest`, `Session::subscribe`, `Session::sendRequestByFix`, `Session::setTimer`, all public methods in `Queue`.\n* If you choose to inject an external `boost::asio::io_context` to `ServiceContext`, the `boost::asio::io_context` has to run on a single thread to ensure thread safety.\n\n#### Enable library logging\n\n[C++](example/src/enable_library_logging/main.cpp) / [Python](binding/python/example/enable_library_logging/main.py) / [Java](binding/java/example/enable_library_logging/Main.java) / [C#](binding/csharp/example/enable_library_logging/MainProgram.cs) / [Go](binding/go/example/enable_library_logging/main.go)\n\nExtend 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.\n```\nnamespace ccapi {\n\nclass MyLogger final : public Logger {\n public:\n  void logMessage(const std::string\u0026 severity, const std::string\u0026 threadId, const std::string\u0026 timeISO, const std::string\u0026 fileName,\n                  const std::string\u0026 lineNumber, const std::string\u0026 message) override {\n    std::lock_guard\u003cstd::mutex\u003e lock(m);\n    std::cout \u003c\u003c threadId \u003c\u003c \": [\" \u003c\u003c timeISO \u003c\u003c \"] {\" \u003c\u003c fileName \u003c\u003c \":\" \u003c\u003c lineNumber \u003c\u003c \"} \" \u003c\u003c severity \u003c\u003c std::string(8, ' ') \u003c\u003c message \u003c\u003c std::endl;\n  }\n\n private:\n  std::mutex m;\n};\n\nMyLogger myLogger;\nLogger* Logger::logger = \u0026myLogger;\n\n} /* namespace ccapi */\n```\n\n#### Set timer\n\n[C++](example/src/set_timer/main.cpp)\n\nTo perform an asynchronous wait, use the utility method `setTimer` in class `Session`. The handlers are invoked in the same threads as the `processEvent` method in the `EventHandler` class. The `id` of the timer should be unique. `delayMilliseconds` can be 0.\n```\nsessionPtr-\u003esetTimer(\n    \"id\", 1000,\n    [](const boost::system::error_code\u0026) {\n      std::cout \u003c\u003c std::string(\"Timer error handler is triggered at \") + UtilTime::getISOTimestamp(UtilTime::now()) \u003c\u003c std::endl;\n    },\n    []() { std::cout \u003c\u003c std::string(\"Timer success handler is triggered at \") + UtilTime::getISOTimestamp(UtilTime::now()) \u003c\u003c std::endl; });\n```\n\n#### Heartbeat\n\n[C++](example/src/heartbeat/main.cpp)\n\nTo receive heartbeat events, instantiate a `Subscription` object with field `HEARTBEAT` and subscribe it.\n```\nSubscription subscription(\"\", \"\", \"HEARTBEAT\", \"HEARTBEAT_INTERVAL_MILLISECONDS=1000\");\nsession.subscribe(subscription);\n```\n\n#### Use multiple sessions\n\n[C++](example/src/use_multiple_sessions/main.cpp)\n\nMultiple `session` instances, each with their own `SessionOptions` and `SessionConfigs`, can share a common `EventHandler`. If no `EventDispatcher` is provided, thread safety must be maintained by using a shared `ServiceContext`.\n```\nSubscription subscription(\"\", \"\", \"HEARTBEAT\", \"HEARTBEAT_INTERVAL_MILLISECONDS=1000\");\nsession.subscribe(subscription);\n```\n\n#### Override exchange urls\nYou can override exchange urls at compile time by using macros. See section \"exchange REST urls\", \"exchange WS urls\", and \"exchange FIX urls\" in [`include/ccapi_cpp/ccapi_macro.h`](include/ccapi_cpp/ccapi_macro.h). You can also override exchange urls at runtime. See [this example](example/src/override_exchange_url_at_runtime/main.cpp). These can be useful if you need to connect to test accounts (e.g. https://testnet.bybit.com/).\n\n#### Connect to a proxy\nInstantiate `Subscription` with the desired `proxyUrl`.\n```\nSubscription subscription(\"bybit\", \"BTCUSDT\", \"MARKET_DEPTH\", \"\", \"\", {}, \"172.30.0.146:9000\");\n```\n\n#### Reduce build time\nThe Pimpl (Pointer to Implementation) idiom in C++ can significantly reduce build time. This reduction is achieved by minimizing compilation dependencies and isolating implementation details. See [this example](example/src/reduce_build_time).\n\n## Performance Tuning\n* Turn on compiler optimization flags (e.g. `cmake -DCMAKE_BUILD_TYPE=Release ...`).\n* Enable link time optimization (e.g. in CMakeLists.txt `set(CMAKE_INTERPROCEDURAL_OPTIMIZATION TRUE)` before a target is created). Note that link time optimization is only applicable to static linking.\n* Only enable the services and exchanges that you need.\n* Handle events in [\"batching\" mode](#handle-events-in-immediate-vs-batching-mode) if your application (e.g. market data archiver) isn't latency sensitive.\n\n## Known Issues and Workarounds\n* Kraken invalid nonce errors. Give the API key a nonce window (https://support.kraken.com/hc/en-us/articles/360001148023-What-is-a-nonce-window-). We use unix timestamp with microsecond resolution as nonce and therefore a nonce window of 500000 translates to a tolerance of 0.5 second.\n","funding_links":[],"categories":["C++"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcrypto-chassis%2Fccapi","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcrypto-chassis%2Fccapi","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcrypto-chassis%2Fccapi/lists"}