I have created a new library, Binance Beast. It is a complete redesign, using Boost's Beast/ASIO and JSON libraries rather than cpprest. It has a much cleaner interface and is more usable. Use Binance Beast instead of this library:
https://github.com/subatomicdev/binancebeast
Binance Futures C++ is a C++17 library for Binance's REST and websockets API.
The project uses Microsoft's cpprestsdk for asynchronous websockets/HTTP functionality.
bfcpplib The library which handles all communications with the exchange
bfcpptest A test app to show how to use the library.
The API is thin - it returns data in structs, which are wrappers for vectors and maps which contain the JSON.
This is to avoid creating and populating objects when users will either already have, or intend to, create a class structure for their needs.
Websocket streams are opened using the monitor functions, such as monitorMarkPrice()
.
The monitor functions return a MonitorToken
and take an std::function<std::any>
argument. The MonitorToken is used when cancelling the monitor function.
MonitorToken monitorMarkPrice(std::function<void(std::any)> onData);
Most of the Rest calls are synchronous, returning an appropriate object, e.g.:
AllOrdersResult allOrders(map<string, string>&& query)
There are some which have an asynchronous version, such as newOrderAsync()
This monitors the mark price and mini tickers for all symbols.
#include <iostream>
#include <future>
#include <Futures.hpp>
#include <Logger.hpp>
int main(int argc, char** argv)
{
std::cout << "\n\n--- USD-M Futures Multiple Streams on Futures ---\n";
auto markPriceHandler = [](std::any data)
{
auto priceData = std::any_cast<MarkPriceStream> (data);
std::stringstream ss;
for (const auto& pair : priceData.prices)
{
std::for_each(std::begin(pair), std::end(pair), [&ss](auto pair) { ss << "\n" << pair.first << "=" << pair.second; });
}
logg(ss.str());
};
auto onSymbolMiniTickHandler = [](std::any data)
{
auto ticker = std::any_cast<AllMarketMiniTickerStream> (data);
stringstream ss;
for (auto& tick : ticker.data)
{
std::for_each(std::begin(tick), std::end(tick), [&ss](auto pair) { ss << "\n" << pair.first << "=" << pair.second; });
}
logg(ss.str());
};
UsdFuturesMarket usdFutures;
usdFutures.monitorMarkPrice(markPriceHandler);
usdFutures.monitorMiniTicker(onSymbolMiniTickHandler);
std::this_thread::sleep_for(10s);
return 0;
}
This shows how to create orders asynchronously. The newOrder()
returns a pplx::task
which contains the API result (NewOrderResult).
Each task is stored in a vector then we use pplx::when_all()
to wait for all to complete.
#include <iostream>
#include <future>
#include <Futures.hpp>
#include <Logger.hpp>
static size_t NumNewOrders = 5;
int main(int argc, char** argv)
{
std::cout << "\n\n--- USD-M Futures New Order Async ---\n";
UsdFuturesTestMarket market{ {"YOUR API KEY", "YOUR SECRET KEY"} };
vector<pplx::task<NewOrderResult>> results;
results.reserve(NumNewOrders);
logg("Sending orders");
for (size_t i = 0; i < NumNewOrders; ++i)
{
map<string, string> order =
{
{"symbol", "BTCUSDT"},
{"side", "BUY"},
{"type", "MARKET"},
{"quantity", "0.001"}
};
results.emplace_back(std::move(market.newOrderAsync(std::move(order))));
}
logg("Waiting for all to complete");
// note: you could use pplx::when_any() to handle each task as it completes,
// then call when_any() until all are finished.
// wait for the new order tasks to return, the majority of which is due to the REST call latency
pplx::when_all(std::begin(results), std::end(results)).wait();
logg("Done: ");
stringstream ss;
ss << "\nOrder Ids: ";
for (auto& task : results)
{
NewOrderResult result = task.get();
if (result.valid())
{
// do stuff with result
ss << "\n" << result.response["orderId"];
}
}
std::cout << ss.str();
return 0;
}
Output:
[18:31:50.436] Sending orders
[18:31:50.438] Waiting for all to complete
[18:31:51.193] Done:
[18:31:51.194]
Order Ids:
2649069688
2649069693
2649069694
2649069692
2649069691
int main(int argc, char** argv)
{
UsdFuturesTestMarket futuresTest { ApiAccess {"YOUR API KEY", "YOUR SECRET KEY"} };
framework::ScopedTimer timer;
auto result = futuresTest.allOrders({ {"symbol", "BTCUSDT"} });
stringstream ss;
ss << "\nFound " << result.response.size() << " orders in " << timer.stopLong() << " ms";
for (const auto& order : result.response)
{
ss << "\n{";
for (const auto& values : order)
{
ss << "\n\t" << values.first << "=" << values.second;
}
ss << "\n}";
}
std::cout << ss.str();
return 0;
}
Dependencies are handled by vcpkg, a cross platform package manager.
- Build vcpkg: open a command prompt in vcpkg_win and run:
bootstrap-vcpkg.bat
- Install dependencies: in the same prompt run:
.\vcpkg install cpprestsdk[websockets] poco boost-asio --triplet x64-windows-static
- Open the VS solution
bfcpp/bfcpp.sln
- Change to 'Release', right-click on the 'bfcpptest' project and select "Setup as startup project"
- Run
NOTE: testing on Linux has been limited, I hope to improve this in the coming weeks
- Build vcpkg: open shell in vcpkg_linux and run:
bootstrap-vcpkg.sh
- Install dependencies: in the same prompt run:
./vcpkg install cpprestsdk[websockets] poco boost-asio --triplet x64-linux
- Go up a directory then into 'bfcpp' directory and run:
cmake . -DCMAKE_BUILD_TYPE=Release && make
- The binary is in the 'bfcpptest' sub-dir ('bfcpp/bfcpptest' from the top level directory)
The provided bfcpptest/bfcpptest.cpp
has a few functions to show the basics.
- Some functions can run without an API or secret key, such as Kline/Candlesticks
- You can pass an api/secret key by editing code or using a key file. The key file has 3 lines:
<live | test>
<api key>
<secret key>
e.g. :
test
myapiKeyMyKey723423Ju&jNhuayNahas617238Jaiasjd31as52v46523435vs
8LBwbPvcub5GHtxLgWDZnm23KFcXwXwXwXwLBwbLBwbAABBca-sdasdasdas123
Run: >./bfcpptest /path/to/mykeyfile.txt