Hey, I am getting this error: Error: “Mandatory parameter ‘timestamp’ was not sent, was empty/null, or malformed.”
I dont know what to do, I feel like I have tried everything. The request seems to be good, the timestamp is definititely right… Well, Im providing my source code below:
#include <iostream>
#include <sstream>
#include <cstring>
#include <cctype>
#include <curl/curl.h>
#include <openssl/hmac.h>
#include <nlohmann/json.hpp>
#include <chrono>
#include <cmath>
const char* api_key = "MY_API_KEY";
const char* api_secret = "MY_SECRET";
// Function to compute the HMAC-SHA256 hash of the message
std::string hmac_sha256(const std::string& key, const std::string& message)
{
unsigned char digest[EVP_MAX_MD_SIZE];
unsigned int digest_len;
HMAC(EVP_sha256(), key.c_str(), key.length(),
(unsigned char*) message.c_str(), message.length(),
digest, &digest_len);
std::stringstream ss;
ss << std::hex << std::setfill('0');
for (unsigned int i = 0; i < digest_len; i++) {
ss << std::setw(2) << static_cast<unsigned int>(digest[i]);
}
std::string mdString = ss.str();
return mdString;
}
// Callback function for CURL to handle the response
size_t curl_callback(void* contents, size_t size, size_t nmemb, void* userp)
{
((std::string*) userp)->append((char*) contents, size * nmemb);
return size * nmemb;
}
// Function to get the server time from the Binance API
std::string get_server_time() {
std::string endpoint = "/fapi/v1/time";
std::string url = "https://fapi.binance.com" + endpoint;
CURL* curl = curl_easy_init();
if (curl) {
std::string response;
curl_easy_setopt(curl, CURLOPT_HTTPGET, 1L);
curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, curl_callback);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response);
CURLcode res = curl_easy_perform(curl);
if (res == CURLE_OK) {
return response;
} else {
std::cerr << "Error: " << curl_easy_strerror(res) << std::endl;
}
curl_easy_cleanup(curl);
}
return "";
}
// Function to send an authenticated GET request to the Binance API
std::string binance_get(const std::string& endpoint, const std::string& data)
{
std::string url = "https://fapi.binance.com" + endpoint;
std::string headers = "X-MBX-APIKEY: " + std::string(api_key);
std::string signature = hmac_sha256(api_secret, data);
std::string get_data = data + "&signature=" + signature;
CURL* curl = curl_easy_init();
if (curl) {
std::string response;
curl_easy_setopt(curl, CURLOPT_HTTPGET, 1L);
curl_easy_setopt(curl, CURLOPT_URL, (url + "?" + get_data).c_str());
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, curl_slist_append(NULL, headers.c_str()));
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, curl_callback);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response);
CURLcode res = curl_easy_perform(curl);
if (res == CURLE_OK) {
return response;
} else {
std::cerr << "Error: " << curl_easy_strerror(res) << std::endl;
}
curl_easy_cleanup(curl);
}
return "";
}
// Function to send an authenticated POST request to the Binance API
std::string binance_post(const std::string& endpoint, const std::string& data)
{
std::string url = "https://fapi.binance.com" + endpoint;
std::string headers = "X-MBX-APIKEY: " + std::string(api_key);
std::string signature = hmac_sha256(api_secret, data);
CURL* curl = curl_easy_init();
if (curl) {
std::string response;
curl_easy_setopt(curl, CURLOPT_POST, 1L);
curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, curl_slist_append(NULL, headers.c_str()));
std::cout << "data: " << data << std::endl;
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, (data + "&signature=" + signature).c_str());
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, curl_callback);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response);
CURLcode res = curl_easy_perform(curl);
if (res == CURLE_OK) {
return response;
} else {
std::cerr << "Error: " << curl_easy_strerror(res) << std::endl;
}
curl_easy_cleanup(curl);
}
return "";
}
bool place_market_order(const std::string& symbol, const std::string& side, double& quantity) {
std::string endpoint = "/fapi/v1/order";
std::string server_time_str = get_server_time();
auto server_time = nlohmann::json::parse(server_time_str)["serverTime"].get<int64_t>();
std::string timestamp = std::to_string(server_time);
std::string quantity_str = std::to_string(quantity);
std::string data = "symbol=" + symbol + "&side=" + side + "&type=MARKET" + "&quantity=" + quantity_str + "×tamp=" + timestamp;
std::string response = binance_post(endpoint, data);
auto json_response = nlohmann::json::parse(response);
if (json_response.find("code") != json_response.end()) {
std::cerr << "Error: " << json_response["msg"] << std::endl;
return false;
} else {
std::cout << "Order successfully placed!" << std::endl;
std::cout << "Symbol: " << json_response["symbol"] << std::endl;
std::cout << "Side: " << json_response["side"] << std::endl;
std::cout << "Type: " << json_response["type"] << std::endl;
std::cout << "Quantity: " << json_response["origQty"] << std::endl;
std::cout << "Price: " << json_response["price"] << std::endl;
return true;
}
}
double get_symbol_price(const std::string& symbol)
{
std::string endpoint = "/fapi/v1/premiumIndex";
std::string data = "symbol=" + symbol;
std::string response = binance_get(endpoint, data);
auto json_response = nlohmann::json::parse(response);
// Check for error response
if (json_response.find("code") != json_response.end()) {
int code = json_response["code"];
if (code != 200) {
throw std::runtime_error("Error getting price for symbol " + symbol + ", error code: " + std::to_string(code));
}
}
std::string mark_price_str = json_response["markPrice"];
double mark_price = std::stod(mark_price_str);
return mark_price;
}
int get_precision(double& price) {
if (price < 10) return 1;
if (price < 100) return 10;
if (price < 1000) return 100;
else return 1000;
}
std::string buy_or_sell(std::string& side) {
if(side == "b" || side == "buy" || side == "BUY") {
side = "BUY";
return "Bought";
}
if(side == "s" || side == "sell" || side == "SELL") {
side = "SELL";
return "Sold";
}
return "None";
}
bool get_input(std::string& symbol, double& qty, std::string& side, double& money) {
std::cout << "Enter your order (b 2500 eth -> buys ETH for 2500$): " << std::endl;
std::cin >> side >> money >> symbol;
if (std::cin.fail()) {
std::cout << "Invalid input." << std::endl;
std::cin.clear(); // clear the error state
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n'); // ignore any remaining characters in the buffer
return false;
}
std::string is_valid_side = buy_or_sell(side);
if (is_valid_side == "None") return false;
std::transform(symbol.begin(), symbol.end(), symbol.begin(), ::toupper);
symbol += "USDT"; // gets the actual symbol to work with
std::cout << symbol << std::endl;
double price = get_symbol_price(symbol);
qty = money / price;
qty = std::round(qty * get_precision(price)) / get_precision(price); // gets the actual quantity to work with
return true;
}
int main() {
std::string symbol;
std::string side;
double qty;
double money;
while(get_input(symbol, qty, side, money)) {
place_market_order(symbol, side, qty);
std::cout << buy_or_sell(side) << " " << qty << " of " << symbol << " for " << money << "$" << std::endl;
}
return 0;
}