This is Huobi C++ SDK, This is a lightweight c++ library, you can import to your C++ project and use this SDK to query all market data, trading and manage your account.
The SDK supports both synchronous RESTful API invoking, and subscribe the market data from the Websocket connection.
-
- Reference data
- Market data
- Account
- Wallet
- Trading
- Margin Loan
- Apply loan
- Reply loan
- Loan history
- [Transfer Asset btween Spot Trading Account and Cross Margin Account](#Transfer-Asset-btween-Spot-Trading-Account-and-Cross-Margin Account)
- Request a Margin Loan
- Search Past Margin Orders
- Repay Margin Loan
- Get the Balance of the Margin Loan Account
The SDK is compiled by C++ 11.
编译器可以使用gcc也可以使用clang.
Currently, The SDK has the compatibility on linux system(centos 7 and ubuntu 18.04) only.
Later, macOS and windows.
Please make sure the CMake is installed on your OS.
If not, you can follow https://cmake.org/install/ to install it.
The minimum required version of CMake is 2.8, but we suggest to use the lastest CMake version.
Please make sure the 3rd party libraries have been installed in your system. If not, please install them.
OpenSSL - https://github.com/openssl/openssl
curl - https://github.com/curl/curl
libwebsocket - https://libwebsockets.org/git/libwebsockets/tree/?h=v3.1-stable
ubuntu 18.04:
$ sudo apt install cmake
#openssl 1.1.1
$ sudo apt install openssl
$ sudo apt install libssl-dev
#curl
$ sudo apt install curl libcurl4-openssl-dev
#zip
$ sudo apt install zlib1g-dev
centos 7
$ sudo yum install cmake
#openssl 1.0.2
$ sudo yum install openssl openssl-devel
#curl
$ sudo yum install libcurl libcurl-devel
#libwebsockets v3.1.0
$ sudo yum install epel-release
$ sudo yum install libwebsockets libwebsockets-devel
#zip
$ sudo yum install zlib zlib-devel
$ sudo yum install centos-release-scl-rh centos-release-scl scl-utils-build scl-utils
$ sudo yum check-update
#安装clang 最低3.4.2 最高5.0.1 此处使用5.0.1
$ sudo yum install devtoolset-7-llvm
$ echo "source /opt/rh/llvm-toolset-7/enable" >> $HOME/.bashrc
$ source $HOME/.bashrc
#安装gcc 最低4.9.2 最高7.3.1 此处使用7.3.1
$ sudo yum install devtoolset-7-toolchain
$ echo "source /opt/rh/devtoolset-7/enable" >> $HOME/.bashrc
$ source $HOME/.bashrc
macOS 10.14.5
#openssl 1.0.2
$ brew install openssl
#libwebsockets v3.1.0
$ brew install libwebsockets
#curl
$ brew install curl curl-openssl
#zlib
$ brew install zlib
#gtest
$ brew install --HEAD https://gist.githubusercontent.com/huobiapi/e81f3714d37c7d92c3e9e6b6566a4cbe/raw/39f1a42024cecb40d0436b03acd67c0abe6d9571/gtest.rb
从源码编译安装libwebsockets v3.1.0:
参考: https://libwebsockets.org/
$ git clone https://github.com/warmcat/libwebsockets.git
$ git reset --hard 89eedcaa94e1c8a97ea3af10642fd224bcea068f
$ cd libwebsockets
$ mkdir build
$ cd build
$ cmake ..
$ make
$ sudo make install
You should check the C++ 11 build environment.
To build the SDK, you should build the decnumber firstly.
$ git clone https://github.com/huobiapi/libdecnumber.git
$ cd libdecnumber
$ mkdir build
$ cd build
#使用clang
$ cmake .. -G "Unix Makefiles" -DCMAKE_BUILD_TYPE=Release -DCMAKE_COMPILER_TYPE=CLANG
#使用gcc
$ cmake .. -G "Unix Makefiles" -DCMAKE_BUILD_TYPE=Release -DCMAKE_COMPILER_TYPE=GCC
$ make
$ sudo make install
Then build the SDK library
$ git clone https://github.com/huobiapi/huobi_Cpp.git
$ cd huobi_Cpp
$ mkdir build
$ cd build
#使用clang
$ cmake .. -G "Unix Makefiles" -DCMAKE_BUILD_TYPE=Release -DCMAKE_COMPILER_TYPE=CLANG
#使用gcc
$ cmake .. -G "Unix Makefiles" -DCMAKE_BUILD_TYPE=Release -DCMAKE_COMPILER_TYPE=GCC
$ make
$ sudo make install
<In huobi_Cpp folder>
$ cd examples
$ cd GetCandlestickData
$ mkdir build
$ cd build
#使用clang
$ cmake .. -G "Unix Makefiles" -DCMAKE_BUILD_TYPE=Release -DCMAKE_COMPILER_TYPE=CLANG
#使用gcc
$ cmake .. -G "Unix Makefiles" -DCMAKE_BUILD_TYPE=Release -DCMAKE_COMPILER_TYPE=GCC
$ make
In your c++ project, you can follow below steps:
- include Huobi/HuobiClient.h (All classes are under namespace Huobi)
- Create the client instance.
- Call the interfaces provided by client.
- If you want to release the memory of client, delete it directly.
using namespace Huobi;
RequestClient* request = createRequestClient();
// Get the timestamp from Huobi server and print on console
long timestamp = request->getExchangeTimestamp();
std::cout << timestamp << std::endl;
// Get the latest btcusdt‘s candlestick data and print the highest price on console
std::vector<Candlestick> candlestickVes = request->getLatestCandlestick("btcusdt", CandlestickInterval::day1, 20);
for (Candlestick item : candlestickVes)
std::cout << item.high << std::endl;
Please NOTE:
All timestamp which is got from SDK is the Unix timestamp based on UTC.
Huobi API supports 2 types of invoking.
- Request method: You can use request method to trade, withdraw and loan. You can also use it to get the market related data from Huobi server.
- Subscription method: You can subscribe the market updated data and account change from Huobi server. For example, if you subscribed the price depth update, you will receive the price depth message when the price depth updates on Huobi server.
We recommend developers to use request method to trade, withdraw and loan, to use subscription method to access the market related data.
There are 2 clients, one is for request method, RequestClient
, another is for subscription method SubscriptionClient
.
-
RequestClient: It is a synchronous request, it will invoke the Huobi API via synchronous method, all invoking will be blocked until receiving the response from server.
-
SubscriptionClient: It is the subscription, it is used for subscribing any market data update and account change. It is asynchronous, so you must implement
callback()
function. The server will push any update for the client. if client receive the update, thecallback()
function will be called. See Subscription usage for detail.
You can assign the API key and Secret key when you create the client. See below:
RequestClient* request = createRequestClient(
"xxxxxxxx-xxxxxxxx-xxxxxxxx-xxxxx",
"xxxxxxxx-xxxxxxxx-xxxxxxxx-xxxxx");
SubscriptionClient* subscription = createSubscriptionClient(
"xxxxxxxx-xxxxxxxx-xxxxxxxx-xxxxx",
"xxxxxxxx-xxxxxxxx-xxxxxxxx-xxxxx");
The API key and Secret key are used for authentication.
Some APIs related with account, trading, deposit and withdraw etc require the authentication. We can name them after private interface.
The APIs only return the market data don't need the authentication. We can name them after public interface.
If you want to invoke both public interface and private interface. You must apply API Key and Secret Key from Huobi and put them into the client you created.
If the authentication cannot pass, the invoking of private interface will fail.
If you want to invoke public interface only. You can create the client as follow:
RequestClient* request = createRequestClient();
SubscriptionClient* subscription = createSubscriptionClient();
To support huobi cloud, you can specify the custom host.
- Set your custom host to
RequestClient
orSubscriptionClient
. - Set the url or uri string to client when creating the client instance.
See below example
//Set custom host for request
RequestOptions reqOp;
reqOp.url = "https://www.xxx.yyy/";
RequestClient* request = createRequestClient(
"xxxxxxxx-xxxxxxxx-xxxxxxxx-xxxxx",
"xxxxxxxx-xxxxxxxx-xxxxxxxx-xxxxx",
reqOp);
// Set custom host for subscription
SubscriptionOptions subOp;
subOp.url = "wss://www.xxx.yyy";
SubscriptionClient* subscription = createSubscriptionClient(
"xxxxxxxx-xxxxxxxx-xxxxxxxx-xxxxx",
"xxxxxxxx-xxxxxxxx-xxxxxxxx-xxxxx",
subOp);
If you do not set yout custom host, below default host will be used:
For request: https://api.huobi.pro
For subscription: wss://api.huobi.pro
To invoke the interface by synchronous, you can create the RequestClient
and call the API directly.
RequestClient* request = createRequestClient();
// Get the best bid and ask for btcusdt, print the best ask price and amount on console.
BestQuote bestQuote = request->getBestQuote("btcusdt");
std::cout<< bestQuote.askPrice << std::endl;
std::cout<< bestQuote.askAmount << std::endl;
To receive the subscribed data, you can create the SubscriptionClient
. When subscribing the event, you should define your callback function. See below example:
SubscriptionClient* subscription = createSubscriptionClient();
// Subscribe the candlestickEvent update for btcusdt.
subscription->subscribeCandlestickEvent(
"btcusdt",
CandlestickInterval::min15,
[](const CandlestickEvent& candlestickEvent){
std::cout <<"Timestamp: " << candlestickEvent.data.timestamp << std::endl;
std::cout <<"High: " << candlestickEvent.data.high << std::endl;
std::cout <<"Low: " << candlestickEvent.data.low << std::endl;
});
subscription->startService();
The subscription method supports multi-symbol string. Each symbol should be separated by a comma.
SubscriptionClient* subscription = createSubscriptionClient();
subscription->subscribeCandlestickEvent(
"btcusdt,ethusdt",
CandlestickInterval::min15,
[](const CandlestickEvent& candlestickEvent){
std::cout << "Timestamp: " <<candlestickEvent.data.timestamp << std::endl;
std::cout << "High: " <<candlestickEvent.data.high << std::endl;
});
subscription->startService();
After invoking the subscription interface, you must call startService()
to start the subscription. Please note the startService()
will start a loop and block the current thread.
####For request
In error case, such as you set the invalid symbol to getBestQuote()
. The HuobiApiException
will be thrown. See below example:
RequestClient* request = createRequestClient();
try {
request->getBestQuote("???");
} catch (HuobiApiException exception) {
std::cout << exception.errorCode << std::endl;
std::cout << exception.errorMsg << std::endl;
}
####For Subscription
If you want to check the error, you should implement your errorHandler
. See below example:
SubscriptionClient*client = createSubscriptionClient();
client->subscribeCandlestickEvent(
"btcusdt",
CandlestickInterval::min15,
[](CandlestickEvent candlestickEvent){
std::cout <<"Timestamp: "<< candlestickEvent.data.timestamp << std::endl;
std::cout <<"High: "<< candlestickEvent.data.high << std::endl;},
[](HuobiApiException exception){
std::cout << exception.errorCode << std::endl;
std::cout << exception.errorMsg << std::endl;
});
client->startService();
Any error made during subscription will be output to a log file, If you do not define your errorHandler
, the error will be output to log only.
The SDK is using the common logging module, you can set the log mode setlogMode()
,0 is no log,1 is print in console, 2 is print in the specified file, you can set the file setLogfilelocate()
, bigger than 2 is same as 0. The default is 2.Using WriteLog()
if you want record log somewhere. You can follow below steps before create the client:
Logger::setlogMode(2);
Logger::setLogfilelocate("your log locate");
RequestClient* request = createRequestClient();
long timestamp = request->getExchangeTimestamp();
std::cout << timestamp << std::endl;
RequestClient* request = createRequestClient();
ExchangeInfo exchangeInfo = request->getExchangeInfo();
for (Symbols symbols : exchangeInfo.symbolsList) {
std::cout << symbols.symbol << std::endl;
}
for (std::string currency : exchangeInfo.currencies) {
std::cout << currency << std::endl;
}
RequestClient* request = createRequestClient();
std::vector<Symbols> symbolsList = request->getSymbols();
for (Symbols symbols : symbolsList) {
std::cout << symbols.symbol << std::endl;
std::cout << symbols.pricePrecision << std::endl;
}
RequestClient* request = createRequestClient();
std::vector<std::string> stringList =request->getCurrencies();
for (std::string currency : stringList) {
std::cout << currency << std::endl;
}
RequestClient* request = createRequestClient();
CurrencyChainsRequest currencyChainsRequest;
std::vector<CurrencyChain> chains =request->getReferenceCurrencies();
for (CurrencyChain currencyChain : chains) {
std::cout << "currency: " << currencyChain.currency << std::endl;
std::cout << "instStatus: " << currencyChain.instStatus << std::endl;
}
RequestClient* request = createRequestClient();
std::vector<Candlestick>candelves = request->getLatestCandlestick(
"btcusdt",
CandlestickInterval::min1);
for (Candlestick candlestick : candelves) {
std::cout << "High: " << candlestick.high << std::endl;
std::cout << "Low: " << candlestick.low << std::endl;
}
RequestClient* request = createRequestClient();
PriceDepth depth = request->getPriceDepth("btcusdt", 5);
for (DepthEntry entry : depth.bids) {
std::cout <<"price: "<< entry.price << std::endl;
}
RequestClient* request = createRequestClient();
Trade trade = request->getLastTrade("ethusdt");
std::cout << trade.price << std::endl;
RequestClient* request = createRequestClient();
BestQuote bestQuote = request->getBestQuote("btcusdt");
std::cout<< bestQuote.askPrice << std::endl;
std::cout<< bestQuote.askAmount << std::endl;
RequestClient* request = createRequestClient();
std::vector<Trade> tradeVes=request->getHistoricalTrade("ethusdt", 3);
std::cout << tradeVes[0].price << std::endl;
RequestClient* request = createRequestClient();
TradeStatistics tradeStatistics = request->get24HTradeStatistics("ethusdt");
std::cout << trade_statistics.open << std::endl;
RequestClient* request = createRequestClient();
Trade trade = request->getMarketTrade("ethusdt");
std::cout << trade.price << std::endl;
Authentication is required.
RequestClient* request = createRequestClient("your apikey", "your secretKey");
Account account = request->getAccountBalance(Account::spot);
std::cout << account.getBalance("btc")[0].balance << std::endl;
RequestClient* request = createRequestClient("your apikey", "your secretKey");
TransferMasterRequest req(12345L, TransferMasterType::master_transfer_in, "btc", Decimal(1.0));
request->transferBetweenParentAndSub(req);
RequestClient* request = createRequestClient("your apikey", "your secretKey");
AccountHistoryRequest req(12345L);
request->getAccountHistory(req);
RequestClient* request = createRequestClient("your apikey", "your secretKey");
request->getSpecifyAccountBalance(12345L);
RequestClient* request = createRequestClient("your apikey", "your secretKey");
request->getCurrentUserAggregatedBalance();
RequestClient* request = createRequestClient("your apikey", "your secretKey");
request->subUserManage(12345L,LockAction::lock);
Authentication is required.
RequestClient* request = createRequestClient("your apikey","your secretKey");
WithdrawRequest withdrawReq("xxx", Decimal(0.1), "btc");
long id = request->withdraw(withdrawReq);
std::cout<<id<<std::endl;
Authentication is required.
request->cancelWithdraw("btc", id);
Authentication is required.
std::vector<Withdraw> withdrawVes = request->getWithdrawHistory("btc", id, 10);
std::cout << withdrawVes[0].amount << std::endl;
std::vector<Deposit> depositVes = request->getDepositHistory("btc", id, 10);
std::cout << depositVes[0].amount << std::endl;
DepositAddressRequest depositAddressRequest("btc");
request->getDepositAddress(depositAddressRequest);
WithdrawQuotaRequest withdrawQuotaRequest("btc");
request->getWithdrawQuota(withdrawQuotaRequest);
Authentication is required.
NewOrderRequest order("btcusdt",AccountType::spot,OrderType::buy_limit,
Decimal(1),Decimal(0.1));
long id = request->createOrder(order);
std::cout << id << std::endl;
Authentication is required.
request->cancelOrder("btcusdt", orderId);
Authentication is required.
CancelOpenOrderRequest cancel("btcusdt",AccountType::spot);
BatchCancelResult result = request->cancelOpenOrders(cancel);
std::cout << result.successCount << std::endl;
Authentication is required.
Order order = request->getOrder("symbol", orderId);
std::cout << order.price << std::endl;
Authentication is required.
HistoricalOrdersRequest historicalOrder("btcusdt", OrderState::canceled);
std::vector<Order> orderVes = request->getHistoricalOrders(historicalOrder);
std::cout << orderVes[0].price << std::endl;
Authentication is required.
Order order = request->getOrderByClientOrderId(clientOrderId);
std::cout << order.price << std::endl;
Authentication is required.
request->cancelOrderByClientOrderId(clientOrderId);
Authentication is required.
std::vector<FeeRate> feeRates = request->getFeeRate("btcusdt");
for (FeeRate feeRate : feeRates) {
std::cout << feeRate.symbol << std::endl;
std::cout << feeRate.maker_fee << std::endl;
std::cout << feeRate.taker_fee << std::endl;
}
Authentication is required.
Get historical orders in the last 48 hours.
OrdersHistoryRequest ordersHistory;
std::vector<Order> orderVes = request->getOrderHistory(ordersHistory);
std::cout << orderVes[0].price << std::endl;
NewOrderRequest order("btcusdt",AccountType::spot,OrderType::buy_limit,
Decimal(1),Decimal(0.1));
std::list<NewOrderRequest> orders;
orders.push_back(order);
request->batchOrders(orders);
std::list<long> orderIds;
orderIds.push_back(12345L);
std::list<std::string> clientOrderIds;
clientOrderIds.push_back("1234");
request->cancelOrders("btcusdt",orderIds);
request->cancelClientIdOrders("btcusdt",clientOrderIds);
####Apply loan
Authentication is required.
long id = applyLoan("btcusdt", "btc", Decimal(10.0));
std::cout << id << std::endl;
Authentication is required.
long id = repayLoan(loadId,Decimal(10.0));
std::cout << id << std::endl;
####Loan history
Authentication is required.
LoanOrderRequest loanReq("btcusdt");
std::vector<Loan> loanVes = request->getLoanHistory(loanReq);
std::cout << loanVes[0].loanAmount << std::endl;
Authentication is required.
request->crossMaginTransferIn(crossMarginTransferRequest);
request->crossMaginTransferOut(crossMarginTransferRequest);
Authentication is required.
request->crossMaginApplyLoan(crossMarginApplyLoanRequest);
Authentication is required.
request->crossMaginGetLoanOrders(crossMarginLoanOrdersRequest);
Authentication is required.
request->crossMaginRepayLoan(crossMarginRepayLoanRequest);
Authentication is required.
request->crossMaginGetLoanBalance();
subscriptionClient->subscribeTradeEvent(
"btcusdt",
[](const TradeEvent& tradeEvent) {
std::cout << tradeEvent.symbol << std::endl;
for (Trade trade : tradeEvent.tradeList) {
std::cout<<trade.price<<std::endl;
}
});
###Subscribe candlestick/KLine update
subscriptionClient->subscribeCandlestickEvent(
"btcusdt",
CandlestickInterval::min15,
[](const CandlestickEvent& candlestickEvent){
std::cout << "High: " << candlestickEvent.data.high << std::endl;
});
Authentication is required.
subscriptionClient->subscribeOrderUpdateEvent(
"btcusdt",
[](const OrderUpdateEvent& orderEvent) {
std::cout << orderEvent.data.price << std::endl;
});
Authentication is required.
subscriptionClient->subscribeAccountEvent(
BalanceMode::available,
[](const AccountEvent& accountEvent) {
for (AccountChange change : accountEvent.accountChangeList) {
std::cout << "Account: " << change.accountType.getValue() << std::endl;
}
});
Authentication is required. Recommend to use this new sub ,lower data latency and more accurate message order.
subscriptionClient->subscribeOrderUpdateNewEvent(
"btcusdt",
[](const OrderUpdateEvent& orderEvent) {
std::cout << orderEvent.data.price << std::endl;
});
Authentication is required.
subscriptionClient->subscribeAccountUpdateEvent(AccountsUpdateMode::balanceAndaAvailable, [](AccountUpdateEvent event) {
cout << "---- accountId: " << event.accountId << " ----" << endl;
cout << "---- accountType: " << event.accountType.getValue() << " ----" << endl;
cout << "---- available: " << event.available << " ----" << endl;
cout << "---- balance: " << event.balance << " ----" << endl;
cout << "---- changeTime: " << event.changeTime << " ----" << endl;
cout << "---- changeType: " << event.changeType.getValue() << " ----" << endl;
cout << "---- currency: " << event.currency << " ----" << endl;
});
Authentication is required.
subscriptionClient->subscribeTradeClearingEvent("htusdt", [](TradeClearingEvent event) {
cout << "---- aggressor: " << event.aggressor << " ----" << endl;
cout << "---- feeDeduct: " << event.feeDeduct << " ----" << endl;
cout << "---- feeDeductType: " << event.feeDeductType << " ----" << endl;
cout << "---- orderId: " << event.orderId << " ----" << endl;
cout << "---- orderSide: " << event.orderSide.getValue() << " ----" << endl;
cout << "---- orderType: " << event.orderType.getValue() << " ----" << endl;
cout << "---- symbol: " << event.symbol << " ----" << endl;
cout << "---- tradeId: " << event.tradeId << " ----" << endl;
cout << "---- tradePrice: " << event.tradePrice << " ----" << endl;
cout << "---- tradeTime: " << event.tradeTime << " ----" << endl;
cout << "---- tradeVolume: " << event.tradeVolume << " ----" << endl;
cout << "---- transactFee: " << event.transactFee << " ----" << endl;
});
subscriptionClient->subscribeMarketDepthMBP("btcusdt", MBPLevel::LEVEL150, [](MarketDepthMBPEvent event) {
cout << "---- seqNum: " << event.seqNum << " ----" << endl;
});
You can should start subscription by calling startService()
.
subscriptionClient->startService();
进入到根目录:
$ cd huobi_Cpp
构建镜像:
#ubuntu
$ docker build -t huobisdkubuntu -f ./docker/ubuntu/Dockerfile .
#centos
$ docker build -t huobisdkcentos -f ./docker/centos/Dockerfile .
启动:
#ubuntu
$ docker run -itd --network host -v $PWD:/home/jovyan/work huobisdkubuntu
#centos
$ docker run -itd --network host -v $PWD:/home/jovyan/work huobisdkcentos
进入容器内部:
$ docker exec -it $(docker ps -qa | head -1) /bin/bash