Skip to content

Commit

Permalink
Merge pull request #20 from crypto-chassis/refactor/service
Browse files Browse the repository at this point in the history
refactor: service
  • Loading branch information
cryptochassis authored Nov 22, 2020
2 parents 9b76b00 + 4848de0 commit 5b245d7
Show file tree
Hide file tree
Showing 42 changed files with 1,497 additions and 1,505 deletions.
5 changes: 2 additions & 3 deletions .github/workflows/build_cmake.yml
Original file line number Diff line number Diff line change
Expand Up @@ -149,11 +149,10 @@ jobs:
set(path_separator ";")
endif()
set(ENV{PATH} "$ENV{GITHUB_WORKSPACE}${path_separator}$ENV{PATH}")
set(ENV{ENABLE_ALL_EXCHANGE} "true")
execute_process(
COMMAND ${{ steps.cmake_and_ninja.outputs.cmake_dir }}/cmake
-S ./example
-S ./include
-B build
-D CMAKE_BUILD_TYPE=$ENV{BUILD_TYPE}
-G Ninja
Expand Down Expand Up @@ -201,7 +200,7 @@ jobs:
execute_process(COMMAND ccache -z)
execute_process(
COMMAND ${{ steps.cmake_and_ninja.outputs.cmake_dir }}/cmake --build build
COMMAND ${{ steps.cmake_and_ninja.outputs.cmake_dir }}/cmake --build build -j
RESULT_VARIABLE result
)
if (NOT result EQUAL 0)
Expand Down
17 changes: 13 additions & 4 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,6 @@ jobs:
steps:
- uses: actions/checkout@v1
- uses: actions/setup-node@v1
# with:
# node-version: 12
- run: 'echo ''{
"name": "ccapi_cpp",
"version": "1.0.0",
Expand All @@ -22,13 +20,24 @@ jobs:
"release": {
"branches": ["master"],
"plugins": [["@semantic-release/commit-analyzer", {
"preset": "conventionalcommits"
"preset": "conventionalcommits",
"releaseRules": [
{"type": "fix", "release": "patch"},
{"type": "feat", "release": "minor"},
{"type": "build", "release": "patch"},
{"type": "chore", "release": "patch"},
{"type": "ci", "release": "patch"},
{"type": "docs", "release": "patch"},
{"type": "style", "release": "patch"},
{"type": "refactor", "release": "patch"},
{"type": "perf", "release": "patch"},
{"type": "test", "release": "patch"}
]
}], "@semantic-release/github"]
}
}'' > "package.json"'
- run: npm install
- run: npm ci
- env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
# NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
run: npx semantic-release
166 changes: 82 additions & 84 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,24 @@
- [ccapi_cpp](#ccapi_cpp)
- [Usage](#usage)
- [Build](#build)
- [Constants](#constants)
- [Examples](#examples)
- [Simple](#simple)
- [Advanced](#advanced)
- [Multiple exchanges and/or instruments](#multiple-exchanges-andor-instruments)
- [Specify market depth](#specify-market-depth)
- [Only receive events at periodic intervals](#only-receive-events-at-periodic-intervals)
- [Only receive events at periodic intervals including when the market depth snapshot has not changed yet](#only-receive-events-at-periodic-intervals-including-when-the-market-depth-snapshot-has-not-changed-yet)
- [Dispatching events from multiple threads](#dispatching-events-from-multiple-threads)
- [Synchronous Event Handling](#synchronous-event-handling)
- [Specify correlation id](#specify-correlation-id)
- [Normalize instrument name](#normalize-instrument-name)
- [Multiple exchanges and/or instruments](#multiple-exchanges-andor-instruments)
- [Receive events at periodic intervals](#receive-events-at-periodic-intervals)
- [Receive events at periodic intervals including when the market depth snapshot hasn't changed](#receive-events-at-periodic-intervals-including-when-the-market-depth-snapshot-hasnt-changed)
- [Dispatch events to multiple threads](#dispatch-events-to-multiple-threads)
- [Handle Events Synchronously](#handle-events-synchronously)
- [Enable library logging](#enable-library-logging)
- [Contributing](#contributing)

<!-- END doctoc generated TOC please keep comment here to allow auto update -->

**NEW**: Version 2.0.0 has been released. The APIs remain to be largely the same to version 1.x.x except for a few small breaking changes with the most prominent one being renaming of some of the macros needed at build time.
# ccapi_cpp
* A header-only C++ library for streaming public market data directly from cryptocurrency exchanges (i.e. the connections are between your server and the exchange server without anything in-between).
* Code closely follows Bloomberg's API: https://www.bloomberg.com/professional/support/api-library/.
Expand All @@ -38,7 +42,7 @@
* Example CMake: example/CMakeLists.txt.
* Require C++14 and OpenSSL.
* Definitions in the compiler command line:
* Define service enablement macro ENABLE_MARKET_DATA_SERVICE and exchange enablement macros such as ENABLE_COINBASE, etc. These macros can be found at the top of include/ccapi_cpp/ccapi_session.h.
* Define service enablement macro ENABLE_SERVICE_MARKET_DATA and exchange enablement macros such as ENABLE_EXCHANGE_COINBASE, etc. These macros can be found at the top of include/ccapi_cpp/ccapi_session.h.
* If your OpenSSL version is older than 1.1, define macro OPENSSL_VERSION_MAJOR and OPENSSL_VERSION_MINOR (e.g. for OpenSSL 1.0.2s, define OPENSSL_VERSION_MAJOR to be 1 and OPENSSL_VERSION_MINOR to be 0).
* Include directories:
* include
Expand All @@ -54,8 +58,11 @@
* "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=...(e.g. /usr/local/opt/openssl)
* "No such file or directory" for thread-related headers if Windows MinGW without posix threads is used: please enable it (https://stackoverflow.com/questions/17242516/mingw-w64-threads-posix-vs-win32) or use Boost (so that e.g. boost/thread.hpp can be found).

## Constants
include/ccapi_cpp/ccapi_macro.h

## Examples
[Detail](example)
[Source](example)
### Simple
**Objective:**

Expand Down Expand Up @@ -86,128 +93,119 @@ class MyEventHandler : public EventHandler {
int main(int argc, char **argv) {
using namespace ccapi; // NOLINT(build/namespaces)
SessionOptions sessionOptions;
std::string instrument = "my cool naming";
std::string symbol = "BTC-USD";
// Coinbase names a trading pair using upper case concatenated by dash
// Since symbol normalization is a tedious task, you can choose to use a reference file at https://marketdata-e0323a9039add2978bf5b49550572c7c-public.s3.amazonaws.com/supported_exchange_instrument_subscription_data.csv.gz which we frequently update.
SessionConfigs sessionConfigs({{
CCAPI_EXCHANGE_NAME_COINBASE, {{
instrument, symbol
}}
}});
SessionConfigs sessionConfigs;
MyEventHandler eventHandler;
Session session(sessionOptions, sessionConfigs, &eventHandler);
SubscriptionList subscriptionList;
std::string topic = std::string("/") + CCAPI_EXCHANGE_NAME_COINBASE + "/" + instrument;
std::string fields = CCAPI_EXCHANGE_NAME_MARKET_DEPTH;
std::string options;
CorrelationId correlationId("this is my correlation id");
Subscription subscription(topic, fields, options, correlationId);
subscriptionList.add(subscription);
session.subscribe(subscriptionList);
return 0;
Subscription subscription("coinbase", "BTC-USD", "MARKET_DEPTH");
session.subscribe(subscription);
std::this_thread::sleep_for(std::chrono::seconds(10));
session.stop();
std::cout << "Bye" << std::endl;
return EXIT_SUCCESS;
}
```
**Output:**
```console
Top 10 bids and asks at 2020-07-27T23:56:51.884855000Z are:
Best bid and ask at 2020-07-27T23:56:51.884855000Z are:
{BID_PRICE=10995, BID_SIZE=0.22187803}
{BID_PRICE=10994.03, BID_SIZE=0.2}
{BID_PRICE=10993.71, BID_SIZE=5.229}
{BID_PRICE=10993.61, BID_SIZE=0.27282}
{BID_PRICE=10993.58, BID_SIZE=0.1248}
{BID_PRICE=10992.13, BID_SIZE=0.4162}
{BID_PRICE=10992.08, BID_SIZE=0.27282}
{BID_PRICE=10991.71, BID_SIZE=0.622}
{BID_PRICE=10991.19, BID_SIZE=3.9}
{BID_PRICE=10990.02, BID_SIZE=5.308}
{ASK_PRICE=10995.44, ASK_SIZE=2}
{ASK_PRICE=10998.95, ASK_SIZE=1.359}
{ASK_PRICE=10999.81, ASK_SIZE=0.19414243}
{ASK_PRICE=10999.9, ASK_SIZE=0.00827739}
{ASK_PRICE=10999.91, ASK_SIZE=0.79238425}
{ASK_PRICE=10999.92, ASK_SIZE=1.27862516}
{ASK_PRICE=11000, ASK_SIZE=7.27699068}
{ASK_PRICE=11001.94, ASK_SIZE=0.012}
{ASK_PRICE=11002.16, ASK_SIZE=1.361}
{ASK_PRICE=11002.86, ASK_SIZE=1.13036461}
Top 10 bids and asks at 2020-07-27T23:56:51.935993000Z are:
Best bid and ask at 2020-07-27T23:56:51.935993000Z are:
...
```

### Advanced
#### Multiple exchanges and/or instruments
#### Specify market depth

Instantiate Subscription with option MARKET_DEPTH_MAX set to be the desired market depth.
```
Subscription subscription("coinbase", "BTC-USD", "MARKET_DEPTH", "MARKET_DEPTH_MAX=10");
```

#### Specify correlation id

Instantiate Subscription with the desired correlationId.
```
Subscription subscription("coinbase", "BTC-USD", "MARKET_DEPTH", "", "cool correlation id");
```

Instantiate SessionConfigs with a map containing the exchange names, the instrument names specified by you, and the instrument names specified by the exchange.
#### Normalize instrument name

Instantiate SessionConfigs with a map mapping the exchange name and the normalized instrument name to the instrument's symbol on the exchange.
```
std::map<std::string, std::map<std::string, std::string> > exchangeInstrumentSymbolMap;
exchangeInstrumentSymbolMap[CCAPI_EXCHANGE_NAME_COINBASE]["btc-usd name specified by you"] = "BTC-USD"; // Coinbase names a trading pair using upper case concatenated by dash
exchangeInstrumentSymbolMap[CCAPI_EXCHANGE_NAME_COINBASE]["eth-usd name specified by you"] = "ETH-USD"; // Coinbase names a trading pair using upper case concatenated by dash
std::string coolName = "btc_usd";
exchangeInstrumentSymbolMap["coinbase"][coolName] = "BTC-USD";
SessionConfigs sessionConfigs(exchangeInstrumentSymbolMap);
Session session(sessionOptions, sessionConfigs, &eventHandler);
Subscription subscription("coinbase", coolName, "MARKET_DEPTH");
```

#### Specify market depth
#### Multiple exchanges and/or instruments

Instantiate Subscription with option CCAPI_EXCHANGE_NAME_MARKET_DEPTH_MAX set to be the desired market depth, e.g.
Subscribe a std::vector<Subscription>.
```
std::string options = std::string(CCAPI_EXCHANGE_NAME_MARKET_DEPTH_MAX) + "=2";
Subscription subscription(topic, fields, options, correlationId);
std::vector<Subscription> subscriptionList;
Subscription subscription_1("coinbase", "BTC-USD", "MARKET_DEPTH", "", "coinbase|btc_usd");
subscriptionList.push_back(subscription_1);
Subscription subscription_2("binance-us", "ethusd", "MARKET_DEPTH", "", "binance-us|eth_usd");
subscriptionList.push_back(subscription_2);
session.subscribe(subscriptionList);
```

#### Only receive events at periodic intervals
#### Receive events at periodic intervals

Instantiate Subscription with option CCAPI_EXCHANGE_NAME_CONFLATE_INTERVAL_MILLISECONDS set to be the desired interval, e.g. if you want to only receive market depth snapshots at whole seconds
Instantiate Subscription with option CONFLATE_INTERVAL_MILLISECONDS set to be the desired interval.
```
std::string options = std::string(CCAPI_EXCHANGE_NAME_CONFLATE_INTERVAL_MILLISECONDS) + "=1000";
Subscription subscription(topic, fields, options, correlationId);
Subscription subscription("coinbase", "BTC-USD", "MARKET_DEPTH", "CONFLATE_INTERVAL_MILLISECONDS=1000");
```

#### Only receive events at periodic intervals including when the market depth snapshot has not changed yet
#### Receive events at periodic intervals including when the market depth snapshot hasn't changed

Instantiate Subscription with option CCAPI_EXCHANGE_NAME_CONFLATE_INTERVAL_MILLISECONDS set to be the desired interval and CCAPI_EXCHANGE_NAME_CONFLATE_GRACE_PERIOD_MILLISECONDS to be your network latency, e.g. if you want to only receive market depth snapshots at each and every second regardless of whether the market depth snapshot hasn't changed or not, and your network is faster than the speed of light
Instantiate Subscription with option CCAPI_EXCHANGE_NAME_CONFLATE_INTERVAL_MILLISECONDS set to be the desired interval and CCAPI_EXCHANGE_NAME_CONFLATE_GRACE_PERIOD_MILLISECONDS to be your network latency.
```
std::string options = std::string(CCAPI_EXCHANGE_NAME_CONFLATE_INTERVAL_MILLISECONDS) + "=1000&" + CCAPI_EXCHANGE_NAME_CONFLATE_GRACE_PERIOD_MILLISECONDS + "=0";
Subscription subscription(topic, fields, options, correlationId);
Subscription subscription("coinbase", "BTC-USD", "MARKET_DEPTH", "CONFLATE_INTERVAL_MILLISECONDS=1000&CONFLATE_GRACE_PERIOD_MILLISECONDS=0");
```

#### Dispatching events from multiple threads
#### Dispatch events to multiple threads

Instantiate EventDispatcher with numDispatcherThreads set to be the desired number, e.g.
Instantiate EventDispatcher with numDispatcherThreads set to be the desired number.
```
EventDispatcher eventDispatcher(2);
Session session(sessionOptions, sessionConfigs, &eventHandler, &eventDispatcher);
```

#### Synchronous Event Handling
#### Handle Events Synchronously

Instantiate Session without EventHandler, then obtain the events to be processed by calling session.eventQueue.purge(), e.g.
Instantiate Session without EventHandler, then obtain the events to be processed by calling session.eventQueue.purge().
```
Session session(sessionOptions, sessionConfigs);
...
while (true) {
std::vector<Event> eventList = session.eventQueue.purge();
...
}
Subscription subscription("coinbase", "BTC-USD", "MARKET_DEPTH");
session.subscribe(subscription);
std::this_thread::sleep_for(std::chrono::seconds(5));
std::vector<Event> eventList = session.eventQueue.purge();
```

#### Enable library logging

Add one of the following macros in the compiler command line: ENABLE_TRACE_LOG, ENABLE_DEBUG_LOG, ENABLE_INFO_LOG, ENABLE_WARN_LOG, ENABLE_ERROR_LOG, ENABLE_FATAL_LOG. 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: ENABLE_LOG_TRACE, ENABLE_LOG_DEBUG, ENABLE_LOG_INFO, ENABLE_LOG_WARN, ENABLE_LOG_ERROR, ENABLE_LOG_FATAL. Extend a subclass, e.g. MyLogger, from class Logger and override method logMessage. Assign a MyLogger pointer to Logger::logger.
```
Logger* Logger::logger = 0; // This line is needed.
class MyLogger final: public Logger {
public:
virtual void logMessage(Logger::Severity severity, std::thread::id threadId,
std::chrono::system_clock::time_point time,
std::string fileName, int lineNumber,
std::string message) override {
std::cout << threadId << ": [" << UtilTime::getISOTimestamp(time) << "] {"
<< fileName << ":" << lineNumber << "} "
<< Logger::severityToString(severity) << std::string(8, ' ') << message
<< std::endl;
}
};
namespace ccapi {
Logger* Logger::logger = 0; // This line is needed.
class MyLogger final: public Logger {
public:
virtual void logMessage(Logger::Severity severity, std::thread::id threadId,
std::chrono::system_clock::time_point time,
std::string fileName, int lineNumber,
std::string message) override {
std::cout << threadId << ": [" << UtilTime::getISOTimestamp(time) << "] {"
<< fileName << ":" << lineNumber << "} "
<< Logger::severityToString(severity) << std::string(8, ' ') << message
<< std::endl;
}
};
}
...
using namespace ccapi;
MyLogger myLogger;
Logger::logger = &myLogger;
```
Expand Down
23 changes: 9 additions & 14 deletions example/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,23 +1,18 @@
cmake_minimum_required (VERSION 3.14)
project (example)
cmake_minimum_required(VERSION 3.14)
project(example)
set(CMAKE_CXX_STANDARD 14)
IF(NOT APPLE AND NOT MSVC)
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pthread")
ENDIF()
if(NOT APPLE AND NOT MSVC)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pthread")
endif()
get_filename_component(CCAPI_CPP_PROJECT_DIR ../ ABSOLUTE)
message("CCAPI_CPP_PROJECT_DIR: ${CCAPI_CPP_PROJECT_DIR}")
message(STATUS "CCAPI_CPP_PROJECT_DIR: ${CCAPI_CPP_PROJECT_DIR}")
set(RAPIDJSON_INCLUDE_DIR ${CCAPI_CPP_PROJECT_DIR}/dependency/rapidjson/include)
set(WEBSOCKETPP_INCLUDE_DIR ${CCAPI_CPP_PROJECT_DIR}/dependency/websocketpp)
set(BOOST_INCLUDE_DIR ${CCAPI_CPP_PROJECT_DIR}/dependency/boost)
set(DATE_INCLUDE_DIR ${CCAPI_CPP_PROJECT_DIR}/dependency/date/include)
find_package(OpenSSL REQUIRED)
find_package(ZLIB REQUIRED)
set(OPENSSL_USE_STATIC_LIBS TRUE)
add_definitions(-DENABLE_MARKET_DATA_SERVICE)
add_definitions(-DENABLE_COINBASE)
include_directories(${CCAPI_CPP_PROJECT_DIR}/include ${WEBSOCKETPP_INCLUDE_DIR} ${BOOST_INCLUDE_DIR} ${RAPIDJSON_INCLUDE_DIR} ${DATE_INCLUDE_DIR} ${OPENSSL_INCLUDE_DIR})
link_libraries(OpenSSL::Crypto OpenSSL::SSL ZLIB::ZLIB)
file(GLOB SOURCES_SIMPLE src/simple.cpp)
add_executable(simple ${SOURCES_SIMPLE})
file(GLOB SOURCES_ADVANCED src/advanced.cpp)
add_executable(advanced ${SOURCES_ADVANCED})
link_libraries(OpenSSL::Crypto OpenSSL::SSL)
add_subdirectory(src/market_data_simple)
add_subdirectory(src/market_data_advanced)
Loading

0 comments on commit 5b245d7

Please sign in to comment.