Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion cppsrc/StarQuant/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ include_directories(${StarQuantCpp_SOURCE_DIR}/StarQuant)
set(StarQuantCppSrc
./Common/datastruct.cpp
./Common/util.cpp
./Common/fxmacrodata.cpp
./Common/logger.cpp
./Common/config.cpp
./Common/msgq.cpp
Expand Down Expand Up @@ -43,4 +44,4 @@ target_link_libraries(starquant
m)
set(SQSERVER_SRC ./Services/sqserver.cpp )
add_executable(apiserver.exe ${SQSERVER_SRC})
TARGET_LINK_LIBRARIES(apiserver.exe starquant)
TARGET_LINK_LIBRARIES(apiserver.exe starquant)
200 changes: 200 additions & 0 deletions cppsrc/StarQuant/Common/fxmacrodata.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,200 @@
/*****************************************************************************
* Copyright [2026]
*
* Licensed under the Apache License, Version 2.0 (the "License");
*****************************************************************************/

#include <Common/fxmacrodata.h>

#include <cctype>
#include <iomanip>
#include <sstream>
#include <stdexcept>

namespace StarQuant {
namespace {

std::string trimTrailingSlash(std::string value) {
while (!value.empty() && value.back() == '/') {
value.pop_back();
}
return value;
}

std::string ensureLeadingSlash(const std::string& path) {
if (!path.empty() && path.front() == '/') {
return path;
}
return "/" + path;
}

std::string lower(std::string value) {
for (char& ch : value) {
ch = static_cast<char>(std::tolower(static_cast<unsigned char>(ch)));
}
return value;
}

std::string encode(const std::string& value) {
std::ostringstream out;
out << std::uppercase << std::hex;
for (unsigned char ch : value) {
if (std::isalnum(ch) || ch == '-' || ch == '_' || ch == '.' || ch == '~') {
out << static_cast<char>(ch);
} else {
out << '%' << std::setw(2) << std::setfill('0') << static_cast<int>(ch);
}
}
return out.str();
}

} // namespace

FxMacroDataClient::FxMacroDataClient(std::string api_key,
std::string base_url,
Transport transport)
: api_key_(std::move(api_key)),
base_url_(trimTrailingSlash(std::move(base_url))),
transport_(std::move(transport)) {}

std::string FxMacroDataClient::buildUrl(const std::string& path, QueryParams params) const {
if (!api_key_.empty()) {
params.push_back({"api_key", api_key_});
}

std::ostringstream url;
url << base_url_ << ensureLeadingSlash(path);
char separator = '?';
for (const auto& param : params) {
url << separator << encode(param.first) << '=' << encode(param.second);
separator = '&';
}
return url.str();
}

std::string FxMacroDataClient::send(const std::string& method,
const std::string& path,
QueryParams params,
const std::string& body) const {
if (!transport_) {
throw std::runtime_error("FxMacroDataClient requires a transport callback");
}
return transport_(method, buildUrl(path, std::move(params)), body);
}

std::string FxMacroDataClient::dataCatalogue(const std::string& currency,
QueryParams params) const {
return send("GET", "/data_catalogue/" + encode(lower(currency)), std::move(params));
}

std::string FxMacroDataClient::announcements(const std::string& currency,
const std::string& indicator,
QueryParams params) const {
return send("GET", "/announcements/" + encode(lower(currency)) + "/" + encode(indicator),
std::move(params));
}

std::string FxMacroDataClient::latestAnnouncements(const std::string& currency,
QueryParams params) const {
return send("GET", "/announcements/" + encode(lower(currency)) + "/latest",
std::move(params));
}

std::string FxMacroDataClient::announcementChanges(QueryParams params) const {
return send("GET", "/announcements/changes", std::move(params));
}

std::string FxMacroDataClient::calendar(const std::string& currency,
QueryParams params) const {
return send("GET", "/calendar/" + encode(lower(currency)), std::move(params));
}

std::string FxMacroDataClient::predictions(const std::string& currency,
const std::string& indicator,
QueryParams params) const {
return send("GET", "/predictions/" + encode(lower(currency)) + "/" + encode(indicator),
std::move(params));
}

std::string FxMacroDataClient::forex(const std::string& base,
const std::string& quote,
QueryParams params) const {
return send("GET", "/forex/" + encode(lower(base)) + "/" + encode(lower(quote)),
std::move(params));
}

std::string FxMacroDataClient::cot(const std::string& currency,
QueryParams params) const {
return send("GET", "/cot/" + encode(lower(currency)), std::move(params));
}

std::string FxMacroDataClient::commodity(const std::string& indicator,
QueryParams params) const {
return send("GET", "/commodities/" + encode(indicator), std::move(params));
}

std::string FxMacroDataClient::commoditiesLatest(QueryParams params) const {
return send("GET", "/commodities/latest", std::move(params));
}

std::string FxMacroDataClient::curves(const std::string& currency,
QueryParams params) const {
return send("GET", "/curves/" + encode(lower(currency)), std::move(params));
}

std::string FxMacroDataClient::curveProxies(const std::string& currency,
QueryParams params) const {
return send("GET", "/curve_proxies/" + encode(lower(currency)), std::move(params));
}

std::string FxMacroDataClient::forwardCurves(const std::string& currency,
QueryParams params) const {
return send("GET", "/forward_curves/" + encode(lower(currency)), std::move(params));
}

std::string FxMacroDataClient::rateDifferentials(const std::string& base,
const std::string& quote,
QueryParams params) const {
return send("GET", "/rate_differentials/" + encode(lower(base)) + "/" + encode(lower(quote)),
std::move(params));
}

std::string FxMacroDataClient::forwardDifferentials(const std::string& base,
const std::string& quote,
QueryParams params) const {
return send("GET", "/forward_differentials/" + encode(lower(base)) + "/" + encode(lower(quote)),
std::move(params));
}

std::string FxMacroDataClient::marketSessions(QueryParams params) const {
return send("GET", "/market_sessions", std::move(params));
}

std::string FxMacroDataClient::riskSentiment(QueryParams params) const {
return send("GET", "/risk_sentiment", std::move(params));
}

std::string FxMacroDataClient::news(const std::string& currency,
QueryParams params) const {
return send("GET", "/news/" + encode(lower(currency)), std::move(params));
}

std::string FxMacroDataClient::pressReleases(const std::string& currency,
QueryParams params) const {
return send("GET", "/press-releases/" + encode(lower(currency)), std::move(params));
}

std::string FxMacroDataClient::graphql(const std::string& query,
const std::string& variables_json) const {
return send("POST", "/graphql", {},
"{\"query\":\"" + query + "\",\"variables\":" + variables_json + "}");
}

std::string FxMacroDataClient::request(const std::string& path,
QueryParams params,
std::string method,
std::string body) const {
return send(std::move(method), path, std::move(params), body);
}

} // namespace StarQuant
77 changes: 77 additions & 0 deletions cppsrc/StarQuant/Common/fxmacrodata.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
/*****************************************************************************
* Copyright [2026]
*
* Licensed under the Apache License, Version 2.0 (the "License");
*****************************************************************************/
#ifndef CPPSRC_STARQUANT_COMMON_FXMACRODATA_H_
#define CPPSRC_STARQUANT_COMMON_FXMACRODATA_H_

#include <functional>
#include <string>
#include <utility>
#include <vector>

namespace StarQuant {

class FxMacroDataClient {
public:
using QueryParams = std::vector<std::pair<std::string, std::string>>;
using Transport = std::function<std::string(const std::string& method,
const std::string& url,
const std::string& body)>;

explicit FxMacroDataClient(std::string api_key = "",
std::string base_url = "https://api.fxmacrodata.com/v1",
Transport transport = nullptr);

std::string dataCatalogue(const std::string& currency, QueryParams params = {}) const;
std::string announcements(const std::string& currency,
const std::string& indicator,
QueryParams params = {}) const;
std::string latestAnnouncements(const std::string& currency, QueryParams params = {}) const;
std::string announcementChanges(QueryParams params = {}) const;
std::string calendar(const std::string& currency, QueryParams params = {}) const;
std::string predictions(const std::string& currency,
const std::string& indicator,
QueryParams params = {}) const;
std::string forex(const std::string& base, const std::string& quote,
QueryParams params = {}) const;
std::string cot(const std::string& currency, QueryParams params = {}) const;
std::string commodity(const std::string& indicator, QueryParams params = {}) const;
std::string commoditiesLatest(QueryParams params = {}) const;
std::string curves(const std::string& currency, QueryParams params = {}) const;
std::string curveProxies(const std::string& currency, QueryParams params = {}) const;
std::string forwardCurves(const std::string& currency, QueryParams params = {}) const;
std::string rateDifferentials(const std::string& base,
const std::string& quote,
QueryParams params = {}) const;
std::string forwardDifferentials(const std::string& base,
const std::string& quote,
QueryParams params = {}) const;
std::string marketSessions(QueryParams params = {}) const;
std::string riskSentiment(QueryParams params = {}) const;
std::string news(const std::string& currency, QueryParams params = {}) const;
std::string pressReleases(const std::string& currency, QueryParams params = {}) const;
std::string graphql(const std::string& query,
const std::string& variables_json = "{}") const;
std::string request(const std::string& path,
QueryParams params = {},
std::string method = "GET",
std::string body = "") const;

std::string buildUrl(const std::string& path, QueryParams params = {}) const;

private:
std::string api_key_;
std::string base_url_;
Transport transport_;

std::string send(const std::string& method,
const std::string& path,
QueryParams params,
const std::string& body = "") const;
};

} // namespace StarQuant

#endif // CPPSRC_STARQUANT_COMMON_FXMACRODATA_H_