diff --git a/.dockerignore b/.dockerignore
index d07c51f7..d8d4c498 100644
--- a/.dockerignore
+++ b/.dockerignore
@@ -9,6 +9,7 @@ LICENSE
**/*secret.json
data/log
data/secret
+data/serialized
!data/secret/secret_test.json
monitoring
resources
diff --git a/.github/workflows/ubuntu-monitoring.yml b/.github/workflows/ubuntu-special.yml
similarity index 85%
rename from .github/workflows/ubuntu-monitoring.yml
rename to .github/workflows/ubuntu-special.yml
index a0dc9091..d7554cff 100644
--- a/.github/workflows/ubuntu-monitoring.yml
+++ b/.github/workflows/ubuntu-special.yml
@@ -1,4 +1,4 @@
-name: Monitoring
+name: Special
on:
push:
@@ -7,14 +7,14 @@ on:
pull_request:
jobs:
- ubuntu-monitoring-build:
- name: Build on Ubuntu with monitoring support
+ ubuntu-special-build:
+ name: Build on Ubuntu with monitoring / protobuf support
runs-on: ubuntu-latest
strategy:
matrix:
compiler: [g++-11]
buildmode: [Debug]
- build-prometheus-from-source: [0, 1]
+ build-special-from-source: [0, 1]
steps:
- name: Checkout repository code
@@ -38,7 +38,7 @@ jobs:
ninja
sudo cmake --install .
- if: matrix.build-prometheus-from-source == 0
+ if: matrix.build-special-from-source == 0
- name: Create Build Environment
run: cmake -E make_directory ${{github.workspace}}/build
@@ -46,7 +46,7 @@ jobs:
- name: Configure CMake
working-directory: ${{github.workspace}}/build
shell: bash
- run: cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=${{matrix.buildmode}} -DCMAKE_CXX_COMPILER=${{matrix.compiler}} -DCCT_BUILD_PROMETHEUS_FROM_SRC=${{matrix.build-prometheus-from-source}} -GNinja
+ run: cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=${{matrix.buildmode}} -DCMAKE_CXX_COMPILER=${{matrix.compiler}} -DCCT_BUILD_PROMETHEUS_FROM_SRC=${{matrix.build-special-from-source}} -DCCT_ENABLE_PROTO=${{matrix.build-special-from-source}} -GNinja
- name: Build
working-directory: ${{github.workspace}}/build
diff --git a/.gitignore b/.gitignore
index 8c01a78d..0e8592b9 100644
--- a/.gitignore
+++ b/.gitignore
@@ -66,6 +66,7 @@ cscope*
data/cache
data/log
data/secret
+data/serialized
data/static/exchangeconfig.json
data/static/generalconfig.json
monitoring/data/grafana/*
diff --git a/CMakeLists.txt b/CMakeLists.txt
index dc63a7a1..658e11a8 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -36,6 +36,7 @@ option(CCT_ENABLE_TESTS "Build the unit tests" ${MAIN_PROJECT})
option(CCT_BUILD_EXEC "Build an executable instead of a static library" ${MAIN_PROJECT})
option(CCT_ENABLE_ASAN "Compile with AddressSanitizer" ${CCT_ASAN_BUILD})
option(CCT_ENABLE_CLANG_TIDY "Compile with clang-tidy checks" OFF)
+option(CCT_ENABLE_PROTO "Compile with protobuf support (to export data to the outside world)" ON)
option(CCT_BUILD_PROMETHEUS_FROM_SRC "Fetch and build from prometheus-cpp sources" OFF)
set(CCT_DATA_DIR "${CMAKE_CURRENT_SOURCE_DIR}/data" CACHE PATH "Needed data directory for coincenter. Can also be overriden at runtime with this environment variable")
@@ -135,6 +136,34 @@ else()
endif()
endif()
+if(CCT_ENABLE_PROTO)
+ find_package(Protobuf CONFIG)
+ if(protobuf_FOUND)
+ message(STATUS "Linking with protobuf ${protobuf_VERSION}")
+ else()
+ set(PROTOBUF_VERSION v25.3)
+ if (MSVC)
+ protobuf v25 does not compile with MSVC: https://github.com/protocolbuffers/protobuf/issues/14602
+ set(PROTOBUF_VERSION v26.0-rc2)
+ endif()
+
+ message(STATUS "Compiling protobuf ${PROTOBUF_VERSION} from sources")
+
+ set(protobuf_BUILD_TESTS OFF)
+ set(ABSL_PROPAGATE_CXX_STD ON)
+
+ FetchContent_Declare(
+ protobuf
+ GIT_REPOSITORY https://github.com/protocolbuffers/protobuf.git
+ GIT_TAG ${PROTOBUF_VERSION}
+ )
+ FetchContent_MakeAvailable(protobuf)
+
+ include(${protobuf_SOURCE_DIR}/cmake/protobuf-generate.cmake)
+
+ endif()
+endif()
+
# Unit Tests
#[[ Create an executable
@@ -250,13 +279,20 @@ if(CCT_ENABLE_PROMETHEUS)
add_compile_definitions(CCT_ENABLE_PROMETHEUS)
endif()
+if(CCT_ENABLE_PROTO)
+ add_compile_definitions(CCT_ENABLE_PROTO)
+ add_compile_definitions("CCT_PROTOBUF_VERSION=\"${PROTOBUF_VERSION}\"")
+endif()
+
# Link to sub folders CMakeLists.txt, from the lowest level to the highest level for documentation
# (beware of cyclic dependencies)
add_subdirectory(src/tech)
add_subdirectory(src/monitoring)
add_subdirectory(src/http-request)
add_subdirectory(src/objects)
+add_subdirectory(src/serialization)
add_subdirectory(src/api-objects)
+add_subdirectory(src/trading)
add_subdirectory(src/api)
add_subdirectory(src/engine)
add_subdirectory(src/main)
diff --git a/CONFIG.md b/CONFIG.md
index efba43e0..b2c031c0 100644
--- a/CONFIG.md
+++ b/CONFIG.md
@@ -150,6 +150,7 @@ Refer to the hardcoded default json example as a model in case of doubt.
| *query* | **updateFrequency.depositWallet** | Duration string (ex: `1min`) | Minimum duration between two consecutive requests of deposit information (including wallet) |
| *query* | **updateFrequency.currencyInfo** | Duration string (ex: `4h`) | Minimum duration between two consecutive requests of dynamic currency info retrieval on Bithumb only (used for place order) |
| *query* | **placeSimulateRealOrder** | Boolean (`true` or `false`) | If `true`, in trade simulation mode (with `--sim`) exchanges which do not support simulated mode in place order will actually place a real order, with the following characteristics:
- trade strategy forced to `maker`
- price will be changed to a maximum for a sell, to a minimum for a buy
This will allow place of a 'real' order that cannot be matched in practice (if it is, lucky you!) |
+| *query* | **marketDataSerialization** | Boolean (`true` or `false`) | If `true` and `coincenter` is compiled with **protobuf** support, some market data will automatically be exported in the `data/serialization` directory (`orderbook` and `last-trades`) for a long term storage |
| *query* | **multiTradeAllowedByDefault** | Boolean (`true` or `false`) | If `true`, [multi-trade](README.md#multi-trade) will be allowed by default for `trade`, `buy` and `sell`. It can be overridden at command line level with `--no-multi-trade` and `--multi-trade`. |
| *query* | **validateApiKey** | Boolean (`true` or `false`) | If `true`, each loaded private key will be tested at start of the program. In case of a failure, it will be removed from the list of private accounts loaded by `coincenter`, so that later queries do not consider it instead of raising a runtime exception. The downside is that it will make an additional check that will make startup slower. | |
| *tradefees* | **maker** | String as decimal number representing a percentage (for instance, "0.15") | Trade fees occurring when a maker order is matched |
diff --git a/Dockerfile b/Dockerfile
index 73202ad0..7aee1bbe 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -4,7 +4,7 @@ FROM ubuntu:22.04 AS build
# Install base & build dependencies, needed certificates for curl to work with https
RUN apt update && \
apt upgrade -y && \
- apt install build-essential curl libcurl4-gnutls-dev libssl-dev cmake git ca-certificates gzip -y && \
+ apt install build-essential curl libcurl4-gnutls-dev libssl-dev cmake git ca-certificates gzip --no-install-recommends -y && \
curl -L -o /usr/local/bin/ninja.gz https://github.com/ninja-build/ninja/releases/latest/download/ninja-linux.zip && \
gunzip /usr/local/bin/ninja.gz && \
chmod a+x /usr/local/bin/ninja
@@ -23,12 +23,14 @@ ARG BUILD_MODE=Release
ARG BUILD_TEST=0
ARG BUILD_ASAN=0
ARG BUILD_WITH_PROMETHEUS=1
+ARG BUILD_WITH_PROTOBUF=1
# Build and launch tests if any
RUN cmake -DCMAKE_BUILD_TYPE=${BUILD_MODE} \
-DCCT_ENABLE_TESTS=${BUILD_TEST} \
-DCCT_ENABLE_ASAN=${BUILD_ASAN} \
-DCCT_BUILD_PROMETHEUS_FROM_SRC=${BUILD_WITH_PROMETHEUS} \
+ -DCCT_ENABLE_PROTO=${BUILD_WITH_PROTOBUF} \
-GNinja .. && \
ninja && \
if [ "$BUILD_TEST" = "1" -o "$BUILD_TEST" = "ON" ]; then \
@@ -56,4 +58,4 @@ COPY --from=build /app/bin/coincenter /app/coincenter
# 'data' directory of host machine can be mounted when launching the container.
# To do this, you can use --mount option:
# docker run --mount type=bind,source=,target=/app/data sjanel/coincenter
-ENTRYPOINT [ "/app/coincenter" ]
\ No newline at end of file
+ENTRYPOINT [ "/app/coincenter" ]
diff --git a/alpine.Dockerfile b/alpine.Dockerfile
index b52cab0b..da56099f 100644
--- a/alpine.Dockerfile
+++ b/alpine.Dockerfile
@@ -2,7 +2,7 @@
FROM alpine:3.19.1 AS build
# Install base & build dependencies, needed certificates for curl to work with https
-RUN apk add --update --upgrade --no-cache g++ libc-dev curl-dev cmake ninja git ca-certificates
+RUN apk add --update --upgrade --no-cache g++ linux-headers libc-dev curl-dev cmake ninja git ca-certificates
# Set default directory for application
WORKDIR /app
@@ -18,12 +18,14 @@ ARG BUILD_MODE=Release
ARG BUILD_TEST=0
ARG BUILD_ASAN=0
ARG BUILD_WITH_PROMETHEUS=1
+ARG BUILD_WITH_PROTOBUF=1
# Build and launch tests if any
RUN cmake -DCMAKE_BUILD_TYPE=${BUILD_MODE} \
-DCCT_ENABLE_TESTS=${BUILD_TEST} \
-DCCT_ENABLE_ASAN=${BUILD_ASAN} \
-DCCT_BUILD_PROMETHEUS_FROM_SRC=${BUILD_WITH_PROMETHEUS} \
+ -DCCT_ENABLE_PROTO=${BUILD_WITH_PROTOBUF} \
-GNinja .. && \
ninja && \
if [ "$BUILD_TEST" = "1" -o "$BUILD_TEST" = "ON" ]; then \
diff --git a/src/api-objects/include/closed-order.hpp b/src/api-objects/include/closed-order.hpp
new file mode 100644
index 00000000..eeddb7c7
--- /dev/null
+++ b/src/api-objects/include/closed-order.hpp
@@ -0,0 +1,29 @@
+#pragma once
+
+#include
+#include
+
+#include "cct_string.hpp"
+#include "cct_type_traits.hpp"
+#include "market.hpp"
+#include "monetaryamount.hpp"
+#include "order.hpp"
+#include "orderid.hpp"
+#include "timedef.hpp"
+#include "tradeside.hpp"
+
+namespace cct {
+
+class ClosedOrder : public Order {
+ public:
+ ClosedOrder(OrderId id, MonetaryAmount matchedVolume, MonetaryAmount price, TimePoint placedTime,
+ TimePoint matchedTime, TradeSide side);
+
+ TimePoint matchedTime() const { return _matchedTime; }
+
+ string matchedTimeStr() const;
+
+ private:
+ TimePoint _matchedTime;
+};
+} // namespace cct
\ No newline at end of file
diff --git a/src/api-objects/include/exchangeprivateapitypes.hpp b/src/api-objects/include/exchangeprivateapitypes.hpp
index 3351fd76..a41c6997 100644
--- a/src/api-objects/include/exchangeprivateapitypes.hpp
+++ b/src/api-objects/include/exchangeprivateapitypes.hpp
@@ -2,8 +2,9 @@
#include "cct_flatset.hpp"
#include "cct_vector.hpp"
+#include "closed-order.hpp"
#include "deposit.hpp"
-#include "order.hpp"
+#include "opened-order.hpp"
#include "tradedamounts.hpp"
#include "withdraw.hpp"
@@ -14,8 +15,10 @@ using DepositsSet = FlatSet;
using Withdraws = vector;
using WithdrawsSet = FlatSet;
-using Orders = vector;
-using OrdersSet = FlatSet;
+using OpenedOrderVector = vector;
+using OpenedOrderSet = FlatSet;
+
+using ClosedOrders = vector;
using TradedAmountsVector = vector;
diff --git a/src/api-objects/include/exchangepublicapitypes.hpp b/src/api-objects/include/exchangepublicapitypes.hpp
index f1e28e2f..7b8d8eec 100644
--- a/src/api-objects/include/exchangepublicapitypes.hpp
+++ b/src/api-objects/include/exchangepublicapitypes.hpp
@@ -12,9 +12,12 @@
#include "publictrade.hpp"
namespace cct {
+
using MarketSet = FlatSet;
using MarketOrderBookMap = std::unordered_map;
using MarketPriceMap = std::unordered_map;
using MarketsPath = SmallVector;
using TradesVector = vector;
-} // namespace cct
\ No newline at end of file
+using MarketOrderBookVector = vector;
+
+} // namespace cct
diff --git a/src/api-objects/include/opened-order.hpp b/src/api-objects/include/opened-order.hpp
new file mode 100644
index 00000000..72536216
--- /dev/null
+++ b/src/api-objects/include/opened-order.hpp
@@ -0,0 +1,22 @@
+#pragma once
+
+#include "monetaryamount.hpp"
+#include "order.hpp"
+#include "orderid.hpp"
+#include "timedef.hpp"
+#include "tradeside.hpp"
+
+namespace cct {
+
+class OpenedOrder : public Order {
+ public:
+ OpenedOrder(OrderId id, MonetaryAmount matchedVolume, MonetaryAmount remainingVolume, MonetaryAmount price,
+ TimePoint placedTime, TradeSide side);
+
+ MonetaryAmount originalVolume() const { return matchedVolume() + _remainingVolume; }
+ MonetaryAmount remainingVolume() const { return _remainingVolume; }
+
+ private:
+ MonetaryAmount _remainingVolume;
+};
+} // namespace cct
\ No newline at end of file
diff --git a/src/api-objects/include/order.hpp b/src/api-objects/include/order.hpp
index 2510148c..108b8f37 100644
--- a/src/api-objects/include/order.hpp
+++ b/src/api-objects/include/order.hpp
@@ -15,25 +15,13 @@ namespace cct {
class Order {
public:
- Order(const char *id, MonetaryAmount matchedVolume, MonetaryAmount remainingVolume, MonetaryAmount price,
- TimePoint placedTime, TradeSide side)
- : Order(OrderId(id), matchedVolume, remainingVolume, price, placedTime, side) {}
-
- Order(std::string_view id, MonetaryAmount matchedVolume, MonetaryAmount remainingVolume, MonetaryAmount price,
- TimePoint placedTime, TradeSide side);
-
- Order(OrderId &&id, MonetaryAmount matchedVolume, MonetaryAmount remainingVolume, MonetaryAmount price,
- TimePoint placedTime, TradeSide side);
-
- MonetaryAmount originalVolume() const { return _matchedVolume + _remainingVolume; }
- MonetaryAmount matchedVolume() const { return _matchedVolume; }
- MonetaryAmount remainingVolume() const { return _remainingVolume; }
- MonetaryAmount price() const { return _price; }
+ TimePoint placedTime() const { return _placedTime; }
OrderId &id() { return _id; }
const OrderId &id() const { return _id; }
- TimePoint placedTime() const { return _placedTime; }
+ MonetaryAmount matchedVolume() const { return _matchedVolume; }
+ MonetaryAmount price() const { return _price; }
TradeSide side() const { return _side; }
@@ -47,11 +35,13 @@ class Order {
using trivially_relocatable = is_trivially_relocatable::type;
+ protected:
+ Order(OrderId id, MonetaryAmount matchedVolume, MonetaryAmount price, TimePoint placedTime, TradeSide side);
+
private:
TimePoint _placedTime;
OrderId _id; // exchange internal id, format specific to each exchange
MonetaryAmount _matchedVolume;
- MonetaryAmount _remainingVolume;
MonetaryAmount _price;
TradeSide _side;
};
diff --git a/src/api-objects/src/closed-order.cpp b/src/api-objects/src/closed-order.cpp
new file mode 100644
index 00000000..3b3b0344
--- /dev/null
+++ b/src/api-objects/src/closed-order.cpp
@@ -0,0 +1,19 @@
+#include "closed-order.hpp"
+
+#include
+
+#include "cct_string.hpp"
+#include "monetaryamount.hpp"
+#include "order.hpp"
+#include "timedef.hpp"
+#include "timestring.hpp"
+#include "tradeside.hpp"
+
+namespace cct {
+
+ClosedOrder::ClosedOrder(OrderId id, MonetaryAmount matchedVolume, MonetaryAmount price, TimePoint placedTime,
+ TimePoint matchedTime, TradeSide side)
+ : Order(std::move(id), matchedVolume, price, placedTime, side), _matchedTime(matchedTime) {}
+
+string ClosedOrder::matchedTimeStr() const { return ToString(_matchedTime); }
+} // namespace cct
\ No newline at end of file
diff --git a/src/api-objects/src/opened-order.cpp b/src/api-objects/src/opened-order.cpp
new file mode 100644
index 00000000..aa7ea5aa
--- /dev/null
+++ b/src/api-objects/src/opened-order.cpp
@@ -0,0 +1,11 @@
+#include "opened-order.hpp"
+
+#include
+
+namespace cct {
+
+OpenedOrder::OpenedOrder(string id, MonetaryAmount matchedVolume, MonetaryAmount remainingVolume, MonetaryAmount price,
+ TimePoint placedTime, TradeSide side)
+ : Order(std::move(id), matchedVolume, price, placedTime, side), _remainingVolume(remainingVolume) {}
+
+} // namespace cct
\ No newline at end of file
diff --git a/src/api-objects/src/order.cpp b/src/api-objects/src/order.cpp
index 6f412a3c..49fcd6c3 100644
--- a/src/api-objects/src/order.cpp
+++ b/src/api-objects/src/order.cpp
@@ -11,23 +11,8 @@
namespace cct {
-Order::Order(std::string_view id, MonetaryAmount matchedVolume, MonetaryAmount remainingVolume, MonetaryAmount price,
- TimePoint placedTime, TradeSide side)
- : _placedTime(placedTime),
- _id(id),
- _matchedVolume(matchedVolume),
- _remainingVolume(remainingVolume),
- _price(price),
- _side(side) {}
-
-Order::Order(string &&id, MonetaryAmount matchedVolume, MonetaryAmount remainingVolume, MonetaryAmount price,
- TimePoint placedTime, TradeSide side)
- : _placedTime(placedTime),
- _id(std::move(id)),
- _matchedVolume(matchedVolume),
- _remainingVolume(remainingVolume),
- _price(price),
- _side(side) {}
+Order::Order(string id, MonetaryAmount matchedVolume, MonetaryAmount price, TimePoint placedTime, TradeSide side)
+ : _placedTime(placedTime), _id(std::move(id)), _matchedVolume(matchedVolume), _price(price), _side(side) {}
std::string_view Order::sideStr() const { return SideStr(_side); }
diff --git a/src/api/common/include/exchangeprivateapi.hpp b/src/api/common/include/exchangeprivateapi.hpp
index b465c7f0..afd53af1 100644
--- a/src/api/common/include/exchangeprivateapi.hpp
+++ b/src/api/common/include/exchangeprivateapi.hpp
@@ -61,7 +61,8 @@ class ExchangePrivate : public ExchangeBase {
virtual bool canGenerateDepositAddress() const = 0;
/// Get opened orders filtered according to given constraints
- virtual Orders queryOpenedOrders(const OrdersConstraints &openedOrdersConstraints = OrdersConstraints()) = 0;
+ virtual OpenedOrderVector queryOpenedOrders(
+ const OrdersConstraints &openedOrdersConstraints = OrdersConstraints()) = 0;
/// Cancel all opened orders on the exchange that matches given constraints
/// @return number of opened orders cancelled
diff --git a/src/api/common/include/exchangeprivateapi_mock.hpp b/src/api/common/include/exchangeprivateapi_mock.hpp
index 2377e768..95a9d013 100644
--- a/src/api/common/include/exchangeprivateapi_mock.hpp
+++ b/src/api/common/include/exchangeprivateapi_mock.hpp
@@ -27,7 +27,7 @@ class MockExchangePrivate : public ExchangePrivate {
MOCK_METHOD(BalancePortfolio, queryAccountBalance, (const BalanceOptions &), (override));
MOCK_METHOD(Wallet, queryDepositWallet, (CurrencyCode), (override));
MOCK_METHOD(bool, canGenerateDepositAddress, (), (const override));
- MOCK_METHOD(Orders, queryOpenedOrders, (const OrdersConstraints &), (override));
+ MOCK_METHOD(OpenedOrderVector, queryOpenedOrders, (const OrdersConstraints &), (override));
MOCK_METHOD(int, cancelOpenedOrders, (const OrdersConstraints &), (override));
MOCK_METHOD(DepositsSet, queryRecentDeposits, (const DepositsConstraints &), (override));
diff --git a/src/api/exchanges/include/binanceprivateapi.hpp b/src/api/exchanges/include/binanceprivateapi.hpp
index e6897e98..8bda0327 100644
--- a/src/api/exchanges/include/binanceprivateapi.hpp
+++ b/src/api/exchanges/include/binanceprivateapi.hpp
@@ -46,7 +46,7 @@ class BinancePrivate : public ExchangePrivate {
bool canGenerateDepositAddress() const override { return true; }
- Orders queryOpenedOrders(const OrdersConstraints& openedOrdersConstraints = OrdersConstraints()) override;
+ OpenedOrderVector queryOpenedOrders(const OrdersConstraints& openedOrdersConstraints = OrdersConstraints()) override;
int cancelOpenedOrders(const OrdersConstraints& openedOrdersConstraints = OrdersConstraints()) override;
diff --git a/src/api/exchanges/include/bithumbprivateapi.hpp b/src/api/exchanges/include/bithumbprivateapi.hpp
index 5cb816cf..66929426 100644
--- a/src/api/exchanges/include/bithumbprivateapi.hpp
+++ b/src/api/exchanges/include/bithumbprivateapi.hpp
@@ -32,7 +32,7 @@ class BithumbPrivate : public ExchangePrivate {
bool canGenerateDepositAddress() const override { return false; }
- Orders queryOpenedOrders(const OrdersConstraints& openedOrdersConstraints = OrdersConstraints()) override;
+ OpenedOrderVector queryOpenedOrders(const OrdersConstraints& openedOrdersConstraints = OrdersConstraints()) override;
int cancelOpenedOrders(const OrdersConstraints& openedOrdersConstraints = OrdersConstraints()) override;
diff --git a/src/api/exchanges/include/huobiprivateapi.hpp b/src/api/exchanges/include/huobiprivateapi.hpp
index 57b8d6ae..172ce73f 100644
--- a/src/api/exchanges/include/huobiprivateapi.hpp
+++ b/src/api/exchanges/include/huobiprivateapi.hpp
@@ -30,7 +30,7 @@ class HuobiPrivate : public ExchangePrivate {
bool canGenerateDepositAddress() const override { return true; }
- Orders queryOpenedOrders(const OrdersConstraints& openedOrdersConstraints = OrdersConstraints()) override;
+ OpenedOrderVector queryOpenedOrders(const OrdersConstraints& openedOrdersConstraints = OrdersConstraints()) override;
int cancelOpenedOrders(const OrdersConstraints& openedOrdersConstraints = OrdersConstraints()) override;
diff --git a/src/api/exchanges/include/krakenprivateapi.hpp b/src/api/exchanges/include/krakenprivateapi.hpp
index 79c87b56..18f8b1d3 100644
--- a/src/api/exchanges/include/krakenprivateapi.hpp
+++ b/src/api/exchanges/include/krakenprivateapi.hpp
@@ -31,7 +31,7 @@ class KrakenPrivate : public ExchangePrivate {
bool canGenerateDepositAddress() const override { return true; }
- Orders queryOpenedOrders(const OrdersConstraints& openedOrdersConstraints = OrdersConstraints()) override;
+ OpenedOrderVector queryOpenedOrders(const OrdersConstraints& openedOrdersConstraints = OrdersConstraints()) override;
int cancelOpenedOrders(const OrdersConstraints& openedOrdersConstraints = OrdersConstraints()) override;
diff --git a/src/api/exchanges/include/kucoinprivateapi.hpp b/src/api/exchanges/include/kucoinprivateapi.hpp
index c8b13127..31abbca4 100644
--- a/src/api/exchanges/include/kucoinprivateapi.hpp
+++ b/src/api/exchanges/include/kucoinprivateapi.hpp
@@ -30,7 +30,7 @@ class KucoinPrivate : public ExchangePrivate {
bool canGenerateDepositAddress() const override { return true; }
- Orders queryOpenedOrders(const OrdersConstraints& openedOrdersConstraints = OrdersConstraints()) override;
+ OpenedOrderVector queryOpenedOrders(const OrdersConstraints& openedOrdersConstraints = OrdersConstraints()) override;
int cancelOpenedOrders(const OrdersConstraints& openedOrdersConstraints = OrdersConstraints()) override;
diff --git a/src/api/exchanges/include/upbitprivateapi.hpp b/src/api/exchanges/include/upbitprivateapi.hpp
index b0c967b3..4b59a16d 100644
--- a/src/api/exchanges/include/upbitprivateapi.hpp
+++ b/src/api/exchanges/include/upbitprivateapi.hpp
@@ -42,7 +42,7 @@ class UpbitPrivate : public ExchangePrivate {
bool canGenerateDepositAddress() const override { return true; }
- Orders queryOpenedOrders(const OrdersConstraints& openedOrdersConstraints = OrdersConstraints()) override;
+ OpenedOrderVector queryOpenedOrders(const OrdersConstraints& openedOrdersConstraints = OrdersConstraints()) override;
int cancelOpenedOrders(const OrdersConstraints& openedOrdersConstraints = OrdersConstraints()) override;
diff --git a/src/api/exchanges/src/binanceprivateapi.cpp b/src/api/exchanges/src/binanceprivateapi.cpp
index dbc75c07..e2ed98bb 100644
--- a/src/api/exchanges/src/binanceprivateapi.cpp
+++ b/src/api/exchanges/src/binanceprivateapi.cpp
@@ -286,8 +286,8 @@ bool BinancePrivate::checkMarketAppendSymbol(Market mk, CurlPostData& params) {
return true;
}
-Orders BinancePrivate::queryOpenedOrders(const OrdersConstraints& openedOrdersConstraints) {
- Orders openedOrders;
+OpenedOrderVector BinancePrivate::queryOpenedOrders(const OrdersConstraints& openedOrdersConstraints) {
+ OpenedOrderVector openedOrders;
CurlPostData params;
if (openedOrdersConstraints.isMarketDefined()) {
// Symbol (which corresponds to a market) is optional - however, it costs 40 credits if omitted and should exist
@@ -364,12 +364,12 @@ int BinancePrivate::cancelOpenedOrders(const OrdersConstraints& openedOrdersCons
}
}
- Orders openedOrders = queryOpenedOrders(openedOrdersConstraints);
+ OpenedOrderVector openedOrders = queryOpenedOrders(openedOrdersConstraints);
- using OrdersByMarketMap = std::unordered_map>;
+ using OrdersByMarketMap = std::unordered_map>;
OrdersByMarketMap ordersByMarketMap;
std::for_each(std::make_move_iterator(openedOrders.begin()), std::make_move_iterator(openedOrders.end()),
- [&ordersByMarketMap](Order&& order) {
+ [&ordersByMarketMap](OpenedOrder&& order) {
Market mk = order.market();
ordersByMarketMap[mk].push_back(std::move(order));
});
@@ -384,7 +384,7 @@ int BinancePrivate::cancelOpenedOrders(const OrdersConstraints& openedOrdersCons
PrivateQuery(_curlHandle, _apiKey, HttpRequestType::kDelete, "/api/v3/openOrders", _queryDelay, params);
nbOrdersCancelled += static_cast(cancelledOrders.size());
} else {
- for (const Order& order : orders) {
+ for (const OpenedOrder& order : orders) {
params.set("orderId", order.id());
PrivateQuery(_curlHandle, _apiKey, HttpRequestType::kDelete, "/api/v3/order", _queryDelay, params);
}
diff --git a/src/api/exchanges/src/bithumbprivateapi.cpp b/src/api/exchanges/src/bithumbprivateapi.cpp
index af90b000..81367497 100644
--- a/src/api/exchanges/src/bithumbprivateapi.cpp
+++ b/src/api/exchanges/src/bithumbprivateapi.cpp
@@ -393,7 +393,7 @@ Wallet BithumbPrivate::DepositWalletFunc::operator()(CurrencyCode currencyCode)
return wallet;
}
-Orders BithumbPrivate::queryOpenedOrders(const OrdersConstraints& openedOrdersConstraints) {
+OpenedOrderVector BithumbPrivate::queryOpenedOrders(const OrdersConstraints& openedOrdersConstraints) {
CurlPostData params;
SmallVector orderCurrencies;
@@ -428,7 +428,7 @@ Orders BithumbPrivate::queryOpenedOrders(const OrdersConstraints& openedOrdersCo
}
}
- Orders openedOrders;
+ OpenedOrderVector openedOrders;
if (openedOrdersConstraints.isPlacedTimeAfterDefined()) {
params.append("after", TimestampToMs(openedOrdersConstraints.placedAfter()));
}
@@ -470,8 +470,8 @@ Orders BithumbPrivate::queryOpenedOrders(const OrdersConstraints& openedOrdersCo
int BithumbPrivate::cancelOpenedOrders(const OrdersConstraints& openedOrdersConstraints) {
// No faster way to cancel several orders at once with Bithumb, doing a simple for loop
- Orders orders = queryOpenedOrders(openedOrdersConstraints);
- for (const Order& order : orders) {
+ OpenedOrderVector orders = queryOpenedOrders(openedOrdersConstraints);
+ for (const OpenedOrder& order : orders) {
TradeContext tradeContext(order.market(), order.side());
cancelOrderProcess(order.id(), tradeContext);
}
diff --git a/src/api/exchanges/src/huobiprivateapi.cpp b/src/api/exchanges/src/huobiprivateapi.cpp
index c6c5efb6..03fcd2d8 100644
--- a/src/api/exchanges/src/huobiprivateapi.cpp
+++ b/src/api/exchanges/src/huobiprivateapi.cpp
@@ -188,7 +188,7 @@ Wallet HuobiPrivate::DepositWalletFunc::operator()(CurrencyCode currencyCode) {
return wallet;
}
-Orders HuobiPrivate::queryOpenedOrders(const OrdersConstraints& openedOrdersConstraints) {
+OpenedOrderVector HuobiPrivate::queryOpenedOrders(const OrdersConstraints& openedOrdersConstraints) {
CurlPostData params;
MarketSet markets;
@@ -203,7 +203,7 @@ Orders HuobiPrivate::queryOpenedOrders(const OrdersConstraints& openedOrdersCons
}
json data = PrivateQuery(_curlHandle, _apiKey, HttpRequestType::kGet, "/v1/order/openOrders", std::move(params));
- Orders openedOrders;
+ OpenedOrderVector openedOrders;
for (const json& orderDetails : data["data"]) {
string marketStr = ToUpper(orderDetails["symbol"].get());
@@ -254,12 +254,12 @@ int HuobiPrivate::cancelOpenedOrders(const OrdersConstraints& openedOrdersConstr
if (openedOrdersConstraints.isOrderIdOnlyDependent()) {
return batchCancel(openedOrdersConstraints.orderIdSet());
}
- Orders openedOrders = queryOpenedOrders(openedOrdersConstraints);
+ OpenedOrderVector openedOrders = queryOpenedOrders(openedOrdersConstraints);
vector orderIds;
orderIds.reserve(openedOrders.size());
std::transform(std::make_move_iterator(openedOrders.begin()), std::make_move_iterator(openedOrders.end()),
- std::back_inserter(orderIds), [](Order&& order) -> OrderId&& { return std::move(order.id()); });
+ std::back_inserter(orderIds), [](OpenedOrder&& order) -> OrderId&& { return std::move(order.id()); });
return batchCancel(OrdersConstraints::OrderIdSet(std::move(orderIds)));
}
diff --git a/src/api/exchanges/src/krakenprivateapi.cpp b/src/api/exchanges/src/krakenprivateapi.cpp
index c042fc0c..574a346c 100644
--- a/src/api/exchanges/src/krakenprivateapi.cpp
+++ b/src/api/exchanges/src/krakenprivateapi.cpp
@@ -176,7 +176,7 @@ BalancePortfolio KrakenPrivate::queryAccountBalance(const BalanceOptions& balanc
// Kraken returns total balance, including the amounts in use
if (!withBalanceInUse) {
// We need to query the opened orders to remove the balance in use
- for (const Order& order : queryOpenedOrders()) {
+ for (const OpenedOrder& order : queryOpenedOrders()) {
MonetaryAmount remVolume = order.remainingVolume();
switch (order.side()) {
case TradeSide::kBuy: {
@@ -282,10 +282,10 @@ Wallet KrakenPrivate::DepositWalletFunc::operator()(CurrencyCode currencyCode) {
return wallet;
}
-Orders KrakenPrivate::queryOpenedOrders(const OrdersConstraints& openedOrdersConstraints) {
+OpenedOrderVector KrakenPrivate::queryOpenedOrders(const OrdersConstraints& openedOrdersConstraints) {
auto [res, err] = PrivateQuery(_curlHandle, _apiKey, "/private/OpenOrders", {{"trades", "true"}});
auto openedPartIt = res.find("open");
- Orders openedOrders;
+ OpenedOrderVector openedOrders;
if (openedPartIt != res.end()) {
MarketSet markets;
@@ -339,8 +339,8 @@ int KrakenPrivate::cancelOpenedOrders(const OrdersConstraints& openedOrdersConst
auto [cancelledOrders, err] = PrivateQuery(_curlHandle, _apiKey, "/private/CancelAll");
return cancelledOrders["count"].get();
}
- Orders openedOrders = queryOpenedOrders(openedOrdersConstraints);
- for (const Order& order : openedOrders) {
+ OpenedOrderVector openedOrders = queryOpenedOrders(openedOrdersConstraints);
+ for (const OpenedOrder& order : openedOrders) {
cancelOrderProcess(order.id());
}
return openedOrders.size();
diff --git a/src/api/exchanges/src/kucoinprivateapi.cpp b/src/api/exchanges/src/kucoinprivateapi.cpp
index c924268c..2de92bdc 100644
--- a/src/api/exchanges/src/kucoinprivateapi.cpp
+++ b/src/api/exchanges/src/kucoinprivateapi.cpp
@@ -35,7 +35,7 @@
#include "kucoinpublicapi.hpp"
#include "market.hpp"
#include "monetaryamount.hpp"
-#include "order.hpp"
+#include "opened-order.hpp"
#include "orderid.hpp"
#include "ordersconstraints.hpp"
#include "permanentcurloptions.hpp"
@@ -221,7 +221,7 @@ Wallet KucoinPrivate::DepositWalletFunc::operator()(CurrencyCode currencyCode) {
return wallet;
}
-Orders KucoinPrivate::queryOpenedOrders(const OrdersConstraints& openedOrdersConstraints) {
+OpenedOrderVector KucoinPrivate::queryOpenedOrders(const OrdersConstraints& openedOrdersConstraints) {
CurlPostData params{{"status", "active"}, {"tradeType", "TRADE"}};
if (openedOrdersConstraints.isCur1Defined()) {
@@ -238,7 +238,7 @@ Orders KucoinPrivate::queryOpenedOrders(const OrdersConstraints& openedOrdersCon
}
json data = PrivateQuery(_curlHandle, _apiKey, HttpRequestType::kGet, "/api/v1/orders", std::move(params))["data"];
- Orders openedOrders;
+ OpenedOrderVector openedOrders;
for (json& orderDetails : data["items"]) {
std::string_view marketStr = orderDetails["symbol"].get();
std::size_t dashPos = marketStr.find('-');
@@ -293,8 +293,8 @@ int KucoinPrivate::cancelOpenedOrders(const OrdersConstraints& openedOrdersConst
}
return nbCancelledOrders;
}
- Orders openedOrders = queryOpenedOrders(openedOrdersConstraints);
- for (const Order& order : openedOrders) {
+ OpenedOrderVector openedOrders = queryOpenedOrders(openedOrdersConstraints);
+ for (const OpenedOrder& order : openedOrders) {
cancelOrderProcess(order.id());
}
return openedOrders.size();
diff --git a/src/api/exchanges/src/upbitprivateapi.cpp b/src/api/exchanges/src/upbitprivateapi.cpp
index 5c2724e5..dcd086b7 100644
--- a/src/api/exchanges/src/upbitprivateapi.cpp
+++ b/src/api/exchanges/src/upbitprivateapi.cpp
@@ -41,7 +41,7 @@
#include "httprequesttype.hpp"
#include "market.hpp"
#include "monetaryamount.hpp"
-#include "order.hpp"
+#include "opened-order.hpp"
#include "orderid.hpp"
#include "ordersconstraints.hpp"
#include "permanentcurloptions.hpp"
@@ -246,7 +246,7 @@ Wallet UpbitPrivate::DepositWalletFunc::operator()(CurrencyCode currencyCode) {
return wallet;
}
-Orders UpbitPrivate::queryOpenedOrders(const OrdersConstraints& openedOrdersConstraints) {
+OpenedOrderVector UpbitPrivate::queryOpenedOrders(const OrdersConstraints& openedOrdersConstraints) {
CurlPostData params{{"state", "wait"}};
if (openedOrdersConstraints.isCur1Defined()) {
@@ -260,7 +260,7 @@ Orders UpbitPrivate::queryOpenedOrders(const OrdersConstraints& openedOrdersCons
}
json data = PrivateQuery(_curlHandle, _apiKey, HttpRequestType::kGet, "/v1/orders", std::move(params));
- Orders openedOrders;
+ OpenedOrderVector openedOrders;
for (json& orderDetails : data) {
std::string_view marketStr = orderDetails["market"].get();
std::size_t dashPos = marketStr.find('-');
@@ -300,8 +300,8 @@ Orders UpbitPrivate::queryOpenedOrders(const OrdersConstraints& openedOrdersCons
int UpbitPrivate::cancelOpenedOrders(const OrdersConstraints& openedOrdersConstraints) {
// No faster way to cancel several orders at once, doing a simple for loop
- Orders openedOrders = queryOpenedOrders(openedOrdersConstraints);
- for (const Order& order : openedOrders) {
+ OpenedOrderVector openedOrders = queryOpenedOrders(openedOrdersConstraints);
+ for (const OpenedOrder& order : openedOrders) {
TradeContext tradeContext(order.market(), order.side());
cancelOrder(order.id(), tradeContext);
}
diff --git a/src/api/exchanges/test/exchangecommonapi_test.hpp b/src/api/exchanges/test/exchangecommonapi_test.hpp
index c0fe6e91..afa222dc 100644
--- a/src/api/exchanges/test/exchangecommonapi_test.hpp
+++ b/src/api/exchanges/test/exchangecommonapi_test.hpp
@@ -220,9 +220,9 @@ class TestAPI {
}
if (exchangePrivateOpt && !sampleMarkets.empty()) {
Market mk = sampleMarkets.front();
- Orders baseOpenedOrders = exchangePrivateOpt->queryOpenedOrders(OrdersConstraints(mk.base()));
+ OpenedOrderVector baseOpenedOrders = exchangePrivateOpt->queryOpenedOrders(OrdersConstraints(mk.base()));
if (!baseOpenedOrders.empty()) {
- const Order &openedOrder = baseOpenedOrders.front();
+ const OpenedOrder &openedOrder = baseOpenedOrders.front();
EXPECT_TRUE(openedOrder.market().canTrade(mk.base()));
EXPECT_LT(openedOrder.matchedVolume(), openedOrder.originalVolume());
}
@@ -315,6 +315,6 @@ class TestAPI {
TEST(TestAPIType##Test, DepositWallet) { testAPI.testDepositWallet(); } \
TEST(TestAPIType##Test, RecentDeposits) { testAPI.testRecentDeposits(); } \
TEST(TestAPIType##Test, RecentWithdraws) { testAPI.testRecentWithdraws(); } \
- TEST(TestAPIType##Test, Orders) { testAPI.testOpenedOrders(); } \
+ TEST(TestAPIType##Test, OpenedOrders) { testAPI.testOpenedOrders(); } \
TEST(TestAPIType##Test, Trade) { testAPI.testTrade(); }
} // namespace cct::api
\ No newline at end of file
diff --git a/src/api/interface/CMakeLists.txt b/src/api/interface/CMakeLists.txt
index a17d1968..df998a70 100644
--- a/src/api/interface/CMakeLists.txt
+++ b/src/api/interface/CMakeLists.txt
@@ -3,6 +3,7 @@ aux_source_directory(src API_INTERFACE_SRC)
add_library(coincenter_api-interface STATIC ${API_INTERFACE_SRC})
target_link_libraries(coincenter_api-interface PUBLIC coincenter_api-exchange)
+target_link_libraries(coincenter_api-interface PUBLIC coincenter_serialization)
target_link_libraries(coincenter_api-interface PRIVATE coincenter_monitoring)
target_include_directories(coincenter_api-interface PUBLIC include)
diff --git a/src/api/interface/include/exchange.hpp b/src/api/interface/include/exchange.hpp
index ba5510dd..a4725c23 100644
--- a/src/api/interface/include/exchange.hpp
+++ b/src/api/interface/include/exchange.hpp
@@ -1,7 +1,9 @@
#pragma once
+#include
#include
#include
+#include
#include "cct_exception.hpp"
#include "currencycode.hpp"
@@ -12,22 +14,30 @@
#include "exchangeprivateapi.hpp"
#include "exchangepublicapi.hpp"
#include "exchangepublicapitypes.hpp"
+#include "market.hpp"
#include "marketorderbook.hpp"
#include "monetaryamount.hpp"
#include "monetaryamountbycurrencyset.hpp"
+#include "time-window.hpp"
namespace cct {
+
+class AbstractMarketDataDeserializer;
+class AbstractMarketDataSerializer;
+
class Exchange {
public:
using ExchangePublic = api::ExchangePublic;
/// Builds a Exchange without private exchange. All private requests will be forbidden.
- Exchange(const ExchangeConfig &exchangeConfig, api::ExchangePublic &exchangePublic);
+ Exchange(std::string_view dataDir, const ExchangeConfig &exchangeConfig, api::ExchangePublic &exchangePublic);
/// Build a Exchange with both private and public exchanges
- Exchange(const ExchangeConfig &exchangeConfig, api::ExchangePublic &exchangePublic,
+ Exchange(std::string_view dataDir, const ExchangeConfig &exchangeConfig, api::ExchangePublic &exchangePublic,
api::ExchangePrivate &exchangePrivate);
+ ~Exchange();
+
std::string_view name() const { return _exchangePublic.name(); }
std::string_view keyName() const { return apiPrivate().keyName(); }
@@ -86,16 +96,12 @@ class Exchange {
return _exchangePublic.queryAllApproximatedOrderBooks(depth);
}
- MarketOrderBook queryOrderBook(Market mk, int depth = ExchangePublic::kDefaultDepth) {
- return _exchangePublic.queryOrderBook(mk, depth);
- }
+ MarketOrderBook queryOrderBook(Market mk, int depth = ExchangePublic::kDefaultDepth);
MonetaryAmount queryLast24hVolume(Market mk) { return _exchangePublic.queryLast24hVolume(mk); }
/// Retrieve an ordered vector of recent last trades
- TradesVector queryLastTrades(Market mk, int nbTrades = ExchangePublic::kNbLastTradesDefault) {
- return _exchangePublic.queryLastTrades(mk, nbTrades);
- }
+ TradesVector queryLastTrades(Market mk, int nbTrades = ExchangePublic::kNbLastTradesDefault);
/// Retrieve the last price of given market.
MonetaryAmount queryLastPrice(Market mk) { return _exchangePublic.queryLastPrice(mk); }
@@ -108,11 +114,24 @@ class Exchange {
return name() == exchangeName.name() && (!exchangeName.isKeyNameDefined() || keyName() == exchangeName.keyName());
}
+ MarketSet pullAvailableMarketsForReplay(TimeWindow timeWindow);
+
+ TradesVector pullTradesForReplay(Market market, TimeWindow timeWindow);
+
+ MarketOrderBookVector pullMarketOrderBooksForReplay(Market market, TimeWindow timeWindow);
+
void updateCacheFile() const;
+ using trivially_relocatable = std::true_type;
+
private:
+ Exchange(std::string_view dataDir, const ExchangeConfig &exchangeConfig, api::ExchangePublic &exchangePublic,
+ api::ExchangePrivate *pExchangePrivate);
+
api::ExchangePublic &_exchangePublic;
api::ExchangePrivate *_pExchangePrivate = nullptr;
const ExchangeConfig &_exchangeConfig;
+ std::unique_ptr _marketDataDeserializerPtr;
+ std::unique_ptr _marketDataSerializerPtr;
};
} // namespace cct
diff --git a/src/api/interface/src/exchange.cpp b/src/api/interface/src/exchange.cpp
index b6ed7dd8..2f8ffc5b 100644
--- a/src/api/interface/src/exchange.cpp
+++ b/src/api/interface/src/exchange.cpp
@@ -1,6 +1,7 @@
#include "exchange.hpp"
#include
+#include
#include "cct_log.hpp"
#include "currencycode.hpp"
@@ -8,17 +9,46 @@
#include "exchangeconfig.hpp"
#include "exchangeprivateapi.hpp"
#include "exchangepublicapi.hpp"
+#include "exchangepublicapitypes.hpp"
+
+#ifdef CCT_ENABLE_PROTO
+#include "proto-market-data-deserializer.hpp"
+#include "proto-market-data-serializer.hpp"
+#else
+#include "dummy-market-data-deserializer.hpp"
+#include "dummy-market-data-serializer.hpp"
+#endif
namespace cct {
-Exchange::Exchange(const ExchangeConfig &exchangeConfig, api::ExchangePublic &exchangePublic,
+#ifdef CCT_ENABLE_PROTO
+using MarketDataDeserializer = ProtoMarketDataDeserializer;
+using MarketDataSerializer = ProtoMarketDataSerializer;
+#else
+using MarketDataDeserializer = DummyMarketDataDeserializer;
+using MarketDataSerializer = DummyMarketDataSerializer;
+#endif
+
+Exchange::Exchange(std::string_view dataDir, const ExchangeConfig &exchangeConfig, api::ExchangePublic &exchangePublic,
api::ExchangePrivate &exchangePrivate)
+ : Exchange(dataDir, exchangeConfig, exchangePublic, std::addressof(exchangePrivate)) {}
+
+Exchange::Exchange(std::string_view dataDir, const ExchangeConfig &exchangeConfig, api::ExchangePublic &exchangePublic)
+ : Exchange(dataDir, exchangeConfig, exchangePublic, nullptr) {}
+
+Exchange::Exchange(std::string_view dataDir, const ExchangeConfig &exchangeConfig, api::ExchangePublic &exchangePublic,
+ api::ExchangePrivate *pExchangePrivate)
: _exchangePublic(exchangePublic),
- _pExchangePrivate(std::addressof(exchangePrivate)),
- _exchangeConfig(exchangeConfig) {}
+ _pExchangePrivate(pExchangePrivate),
+ _exchangeConfig(exchangeConfig),
+ _marketDataDeserializerPtr(_exchangeConfig.withMarketDataSerialization()
+ ? new MarketDataDeserializer(dataDir, exchangePublic.name())
+ : nullptr),
+ _marketDataSerializerPtr(_exchangeConfig.withMarketDataSerialization()
+ ? new MarketDataSerializer(dataDir, exchangePublic.name())
+ : nullptr) {}
-Exchange::Exchange(const ExchangeConfig &exchangeConfig, api::ExchangePublic &exchangePublic)
- : _exchangePublic(exchangePublic), _exchangeConfig(exchangeConfig) {}
+Exchange::~Exchange() = default; // declared here to have definition of ~MarketDataSerializer
bool Exchange::canWithdraw(CurrencyCode currencyCode, const CurrencyExchangeFlatSet ¤cyExchangeSet) const {
if (_exchangeConfig.excludedCurrenciesWithdrawal().contains(currencyCode)) {
@@ -41,6 +71,47 @@ bool Exchange::canDeposit(CurrencyCode currencyCode, const CurrencyExchangeFlatS
return lb->canDeposit();
}
+MarketOrderBook Exchange::queryOrderBook(Market mk, int depth) {
+ auto marketOrderBook = _exchangePublic.queryOrderBook(mk, depth);
+ if (_marketDataSerializerPtr) {
+ _marketDataSerializerPtr->push(marketOrderBook);
+ }
+ return marketOrderBook;
+}
+
+/// Retrieve an ordered vector of recent last trades
+TradesVector Exchange::queryLastTrades(Market mk, int nbTrades) {
+ auto lastTrades = _exchangePublic.queryLastTrades(mk, nbTrades);
+ if (_marketDataSerializerPtr) {
+ _marketDataSerializerPtr->push(lastTrades);
+ }
+ return lastTrades;
+}
+
+MarketSet Exchange::pullAvailableMarketsForReplay(TimeWindow timeWindow) {
+ MarketSet ret;
+ if (_marketDataDeserializerPtr) {
+ ret = MarketSet(_marketDataDeserializerPtr->pullMarketOrderBooksMarkets(timeWindow));
+ const auto tradesMarkets = _marketDataDeserializerPtr->pullTradeMarkets(timeWindow);
+ ret.insert(tradesMarkets.begin(), tradesMarkets.end());
+ }
+ return ret;
+}
+
+TradesVector Exchange::pullTradesForReplay(Market market, TimeWindow timeWindow) {
+ if (_marketDataDeserializerPtr) {
+ return _marketDataDeserializerPtr->pullTrades(market, timeWindow);
+ }
+ return {};
+}
+
+MarketOrderBookVector Exchange::pullMarketOrderBooksForReplay(Market market, TimeWindow timeWindow) {
+ if (_marketDataDeserializerPtr) {
+ return _marketDataDeserializerPtr->pullMarketOrderBooks(market, timeWindow);
+ }
+ return {};
+}
+
void Exchange::updateCacheFile() const {
_exchangePublic.updateCacheFile();
if (_pExchangePrivate != nullptr) {
diff --git a/src/api/interface/src/exchangepool.cpp b/src/api/interface/src/exchangepool.cpp
index 1d04d5ef..6886f76f 100644
--- a/src/api/interface/src/exchangepool.cpp
+++ b/src/api/interface/src/exchangepool.cpp
@@ -31,6 +31,7 @@ ExchangePool::ExchangePool(const CoincenterInfo& coincenterInfo, FiatConverter&
_krakenPublic(_coincenterInfo, _fiatConverter, _commonAPI),
_kucoinPublic(_coincenterInfo, _fiatConverter, _commonAPI),
_upbitPublic(_coincenterInfo, _fiatConverter, _commonAPI) {
+ const auto dataDir = coincenterInfo.dataDir();
for (std::string_view exchangeStr : kSupportedExchanges) {
api::ExchangePublic* exchangePublic;
if (exchangeStr == "binance") {
@@ -81,10 +82,10 @@ ExchangePool::ExchangePool(const CoincenterInfo& coincenterInfo, FiatConverter&
}
}
- _exchanges.emplace_back(exchangeConfig, *exchangePublic, *exchangePrivate);
+ _exchanges.emplace_back(dataDir, exchangeConfig, *exchangePublic, *exchangePrivate);
}
} else {
- _exchanges.emplace_back(exchangeConfig, *exchangePublic);
+ _exchanges.emplace_back(dataDir, exchangeConfig, *exchangePublic);
}
}
_exchanges.shrink_to_fit();
diff --git a/src/engine/CMakeLists.txt b/src/engine/CMakeLists.txt
index 3e5f241e..26a6a692 100644
--- a/src/engine/CMakeLists.txt
+++ b/src/engine/CMakeLists.txt
@@ -6,6 +6,7 @@ target_link_libraries(coincenter_engine PUBLIC coincenter_api-common)
target_link_libraries(coincenter_engine PUBLIC coincenter_api-exchange)
target_link_libraries(coincenter_engine PUBLIC coincenter_api-interface)
target_link_libraries(coincenter_engine PUBLIC coincenter_objects)
+target_link_libraries(coincenter_engine PUBLIC coincenter_trading-common)
target_include_directories(coincenter_engine PUBLIC include)
add_unit_test(
diff --git a/src/engine/include/coincentercommand.hpp b/src/engine/include/coincentercommand.hpp
index fe736333..366dc7b6 100644
--- a/src/engine/include/coincentercommand.hpp
+++ b/src/engine/include/coincentercommand.hpp
@@ -12,6 +12,7 @@
#include "market.hpp"
#include "monetaryamount.hpp"
#include "ordersconstraints.hpp"
+#include "timedef.hpp"
#include "tradeoptions.hpp"
#include "withdrawoptions.hpp"
#include "withdrawsconstraints.hpp"
@@ -50,15 +51,14 @@ class CoincenterCommand {
CoincenterCommand& setCur1(CurrencyCode cur1);
CoincenterCommand& setCur2(CurrencyCode cur2);
+ CoincenterCommand& setDuration(Duration dur);
+
CoincenterCommand& setPercentageAmount(bool value = true);
CoincenterCommand& withBalanceInUse(bool value = true);
bool isPublic() const;
bool isPrivate() const { return !isPublic(); }
- bool isReadOnly() const;
- bool isWrite() const { return !isReadOnly(); }
-
const ExchangeNames& exchangeNames() const { return _exchangeNames; }
const OrdersConstraints& ordersConstraints() const { return std::get(_specialOptions); }
@@ -86,13 +86,16 @@ class CoincenterCommand {
bool isPercentageAmount() const { return _isPercentageAmount; }
bool withBalanceInUse() const { return _withBalanceInUse; }
+ Duration duration() const { return std::get(_specialOptions); }
+
bool operator==(const CoincenterCommand&) const noexcept = default;
using trivially_relocatable = std::integral_constant &&
is_trivially_relocatable_v>::type;
private:
- using SpecialOptions = std::variant;
+ using SpecialOptions =
+ std::variant;
ExchangeNames _exchangeNames;
SpecialOptions _specialOptions;
diff --git a/src/engine/include/coincenteroptions.hpp b/src/engine/include/coincenteroptions.hpp
index 7a11cf91..86a6b252 100644
--- a/src/engine/include/coincenteroptions.hpp
+++ b/src/engine/include/coincenteroptions.hpp
@@ -95,6 +95,9 @@ class CoincenterCmdLineOptions {
std::string_view lastTrades;
+ std::optional replay;
+ std::optional replayMarkets;
+
CommandLineOptionalInt repeats;
int nbLastTrades = api::ExchangePublic::kNbLastTradesDefault;
int monitoringPort = CoincenterCmdLineOptionsDefinitions::kDefaultMonitoringPort;
diff --git a/src/engine/include/coincenteroptionsdef.hpp b/src/engine/include/coincenteroptionsdef.hpp
index 7aeaafcc..fd603482 100644
--- a/src/engine/include/coincenteroptionsdef.hpp
+++ b/src/engine/include/coincenteroptionsdef.hpp
@@ -309,14 +309,14 @@ struct CoincenterAllowedOptions : private CoincenterCmdLineOptionsDefinitions {
&OptValueType::minAge},
{{{"Private queries", 3902}, "--max-age", "