* [RFC PATCH 0/9] Introducing GNU/Weeb Arbitrage Opportunity Notification Bot
@ 2024-09-10 21:44 Alviro Iskandar Setiawan
2024-09-10 21:44 ` [RFC PATCH 2/9] gwarnt: Create initial P2P ad data structure Alviro Iskandar Setiawan
` (8 more replies)
0 siblings, 9 replies; 10+ messages in thread
From: Alviro Iskandar Setiawan @ 2024-09-10 21:44 UTC (permalink / raw)
To: Ammar Faizi, Michael William Jonathan
Cc: Alviro Iskandar Setiawan, Ravel Kevin Ethan,
GNU/Weeb Mailing List
Hi,
Following the chief's approval of the concept to develop a bot for
identifying arbitrage opportunities between two exchanges, I am excited
to introduce the initial version of the GNU/Weeb Arbitrage Opportunity
Notification Bot.
This bot efficiently scans multiple exchanges for a given currency pair,
detecting profitable arbitrage opportunities in real-time. Additionally,
it can automatically send these alerts to a designated Telegram chat.
Currently, the bot onlu supports Binance and OKX exchanges. However,
it is designed to be easily extensible to support additional exchanges.
I believe this tool would be a valuable addition to the GNU/Weeb group
and would streamline the process of identifying arbitrage possibilities.
Please consider integrating this bot (@FreezingNightBot) into the group
for the benefit of our community.
Thank you for your consideration!
The following changes since commit acd5fc366c900e29d88ffac8ccac96dfe87df23d:
Initial commit (2024-09-11 02:28:37 +0700)
are available in the Git repository at:
https://github.com/alviroiskandar/gwarnt.git master
for you to fetch changes up to 315cd5c14d3fbc8a7cbf5b49038ed61674ed537e:
gwarnt: Add Telegram bot usage to the README file (2024-09-11 04:07:44 +0700)
Signed-off-by: Alviro Iskandar Setiawan <[email protected]>
----------------------------------------------------------------
Alviro Iskandar Setiawan (9):
gwarnt: Create initial P2P ad data structure
gwarnt: p2p: Add P2P Binance
gwarnt: p2p: Add P2P OKX
gwarnt: Create function to find arbitrage opportunities
gwarnt: p2p/binance: Fix invalid page
gwarnt: Create the initial example
gwarnt: Add README file
gwarnt: Add Telegram bot
gwarnt: Add Telegram bot usage to the README file
Makefile | 7 +-
README | 21 ++++
src/gwarnt/arbitrage.cpp | 27 ++++
src/gwarnt/arbitrage.hpp | 21 ++++
src/gwarnt/entry.cpp | 248 +++++++++++++++++++++++++++++++++++++
src/gwarnt/net.cpp | 2 +
src/gwarnt/p2p/binance.cpp | 142 +++++++++++++++++++++
src/gwarnt/p2p/binance.hpp | 42 +++++++
src/gwarnt/p2p/okx.cpp | 101 +++++++++++++++
src/gwarnt/p2p/okx.hpp | 35 ++++++
src/gwarnt/p2p_ad.cpp | 31 +++++
src/gwarnt/p2p_ad.hpp | 31 +++++
src/gwarnt/tgbot.cpp | 75 +++++++++++
src/gwarnt/tgbot.hpp | 46 +++++++
14 files changed, 828 insertions(+), 1 deletion(-)
create mode 100644 README
create mode 100644 src/gwarnt/arbitrage.cpp
create mode 100644 src/gwarnt/arbitrage.hpp
create mode 100644 src/gwarnt/p2p/binance.cpp
create mode 100644 src/gwarnt/p2p/binance.hpp
create mode 100644 src/gwarnt/p2p/okx.cpp
create mode 100644 src/gwarnt/p2p/okx.hpp
create mode 100644 src/gwarnt/p2p_ad.cpp
create mode 100644 src/gwarnt/p2p_ad.hpp
create mode 100644 src/gwarnt/tgbot.cpp
create mode 100644 src/gwarnt/tgbot.hpp
--
Alviro Iskandar Setiawan
^ permalink raw reply [flat|nested] 10+ messages in thread
* [RFC PATCH 2/9] gwarnt: Create initial P2P ad data structure
2024-09-10 21:44 [RFC PATCH 0/9] Introducing GNU/Weeb Arbitrage Opportunity Notification Bot Alviro Iskandar Setiawan
@ 2024-09-10 21:44 ` Alviro Iskandar Setiawan
2024-09-10 21:44 ` [RFC PATCH 3/9] gwarnt: p2p: Add P2P Binance Alviro Iskandar Setiawan
` (7 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Alviro Iskandar Setiawan @ 2024-09-10 21:44 UTC (permalink / raw)
To: Ammar Faizi, Michael William Jonathan
Cc: Alviro Iskandar Setiawan, Ravel Kevin Ethan,
GNU/Weeb Mailing List
Create an abstraction to make P2P ad uniform across multiple
crypto currency exchanges.
Signed-off-by: Alviro Iskandar Setiawan <[email protected]>
---
Makefile | 3 ++-
src/gwarnt/p2p_ad.cpp | 31 +++++++++++++++++++++++++++++++
src/gwarnt/p2p_ad.hpp | 31 +++++++++++++++++++++++++++++++
3 files changed, 64 insertions(+), 1 deletion(-)
create mode 100644 src/gwarnt/p2p_ad.cpp
create mode 100644 src/gwarnt/p2p_ad.hpp
diff --git a/Makefile b/Makefile
index ba50192..7dbfb71 100644
--- a/Makefile
+++ b/Makefile
@@ -13,7 +13,8 @@ C_SOURCES :=
CXX_SOURCES := \
src/gwarnt/entry.cpp \
src/gwarnt/helpers.cpp \
- src/gwarnt/net.cpp
+ src/gwarnt/net.cpp \
+ src/gwarnt/p2p_ad.cpp
C_OBJECTS := $(C_SOURCES:.c=.o)
CXX_OBJECTS := $(CXX_SOURCES:.cpp=.o)
diff --git a/src/gwarnt/p2p_ad.cpp b/src/gwarnt/p2p_ad.cpp
new file mode 100644
index 0000000..7e8e0e5
--- /dev/null
+++ b/src/gwarnt/p2p_ad.cpp
@@ -0,0 +1,31 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+#include <gwarnt/p2p_ad.hpp>
+#include <cstddef>
+
+namespace gwarnt {
+
+std::string p2p_ad::dump(void) const
+{
+ std::string ret = "";
+ size_t i = 0;
+
+ ret += "ad_id: " + ad_id_ + "\n";
+ ret += "merchant_name: " + merchant_name_ + "\n";
+ ret += "fiat: " + fiat_ + "\n";
+ ret += "crypto: " + crypto_ + "\n";
+ ret += "trade_type: " + trade_type_ + "\n";
+ ret += "exchange: " + exchange_ + "\n";
+ ret += "price: " + std::to_string(price_) + "\n";
+ ret += "min_amount: " + std::to_string(min_amount_) + "\n";
+ ret += "max_amount: " + std::to_string(max_amount_) + "\n";
+ ret += "tradable_amount: " + std::to_string(tradable_amount_) + "\n";
+
+ ret += "methods: ";
+ for (const auto &m : methods_)
+ ret += (i++ > 0 ? ", " : "") + m;
+
+ return ret;
+}
+
+} /* namespace gwarnt */
diff --git a/src/gwarnt/p2p_ad.hpp b/src/gwarnt/p2p_ad.hpp
new file mode 100644
index 0000000..85799b2
--- /dev/null
+++ b/src/gwarnt/p2p_ad.hpp
@@ -0,0 +1,31 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+#ifndef GWARNT__P2PDS_HPP
+#define GWARNT__P2PDS_HPP
+
+#include <vector>
+#include <string>
+
+namespace gwarnt {
+
+struct p2p_ad {
+ std::string ad_id_;
+ std::string merchant_name_;
+ std::string fiat_;
+ std::string crypto_;
+ std::string trade_type_;
+ std::string exchange_;
+
+ double price_;
+ double min_amount_;
+ double max_amount_;
+ double tradable_amount_;
+
+ std::vector<std::string> methods_;
+
+ std::string dump(void) const;
+};
+
+} /* namespace gwarnt */
+
+#endif /* #ifndef GWARNT__P2PDS_HPP */
--
Alviro Iskandar Setiawan
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [RFC PATCH 3/9] gwarnt: p2p: Add P2P Binance
2024-09-10 21:44 [RFC PATCH 0/9] Introducing GNU/Weeb Arbitrage Opportunity Notification Bot Alviro Iskandar Setiawan
2024-09-10 21:44 ` [RFC PATCH 2/9] gwarnt: Create initial P2P ad data structure Alviro Iskandar Setiawan
@ 2024-09-10 21:44 ` Alviro Iskandar Setiawan
2024-09-10 21:44 ` [RFC PATCH 4/9] gwarnt: p2p: Add P2P OKX Alviro Iskandar Setiawan
` (6 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Alviro Iskandar Setiawan @ 2024-09-10 21:44 UTC (permalink / raw)
To: Ammar Faizi, Michael William Jonathan
Cc: Alviro Iskandar Setiawan, Ravel Kevin Ethan,
GNU/Weeb Mailing List
Add an interface to collect P2P ads from Binance.
Signed-off-by: Alviro Iskandar Setiawan <[email protected]>
---
Makefile | 3 +-
src/gwarnt/p2p/binance.cpp | 142 +++++++++++++++++++++++++++++++++++++
src/gwarnt/p2p/binance.hpp | 42 +++++++++++
3 files changed, 186 insertions(+), 1 deletion(-)
create mode 100644 src/gwarnt/p2p/binance.cpp
create mode 100644 src/gwarnt/p2p/binance.hpp
diff --git a/Makefile b/Makefile
index 7dbfb71..732d1b7 100644
--- a/Makefile
+++ b/Makefile
@@ -14,7 +14,8 @@ CXX_SOURCES := \
src/gwarnt/entry.cpp \
src/gwarnt/helpers.cpp \
src/gwarnt/net.cpp \
- src/gwarnt/p2p_ad.cpp
+ src/gwarnt/p2p_ad.cpp \
+ src/gwarnt/p2p/binance.cpp
C_OBJECTS := $(C_SOURCES:.c=.o)
CXX_OBJECTS := $(CXX_SOURCES:.cpp=.o)
diff --git a/src/gwarnt/p2p/binance.cpp b/src/gwarnt/p2p/binance.cpp
new file mode 100644
index 0000000..541a5de
--- /dev/null
+++ b/src/gwarnt/p2p/binance.cpp
@@ -0,0 +1,142 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+#include <gwarnt/p2p/binance.hpp>
+#include <gwarnt/helpers.hpp>
+#include <gwarnt/json.hpp>
+#include <exception>
+
+using json = nlohmann::json;
+
+namespace gwarnt {
+namespace p2p {
+
+binance::binance(void)
+{
+ net_.add_header("Content-Type", "application/json");
+ net_.add_header("x-passthrough-token", "");
+}
+
+binance::~binance(void) = default;
+
+void binance::set_fiat(const std::string &fiat)
+{
+ fiat_ = fiat;
+}
+
+void binance::set_crypto(const std::string &crypto)
+{
+ crypto_ = crypto;
+}
+
+void binance::set_trade_type(const std::string &trade_type)
+{
+ trade_type_ = trade_type;
+}
+
+std::vector<gwarnt::p2p_ad> binance::get_data(void)
+{
+ return get_data(fiat_, crypto_, trade_type_);
+}
+
+std::vector<gwarnt::p2p_ad> binance::get_data(const std::string &fiat,
+ const std::string &crypto,
+ const std::string &trade_type,
+ uint64_t page)
+{
+ std::vector<gwarnt::p2p_ad> ads;
+
+ if (page == ~0ull) {
+ std::vector<gwarnt::p2p_ad> tmp;
+ size_t i;
+
+ for (i = 1; i <= 5; i++) {
+ tmp = __get_data(fiat, crypto, trade_type, page);
+ ads.insert(ads.end(), tmp.begin(), tmp.end());
+ }
+ } else {
+ ads = __get_data(fiat, crypto, trade_type, page);
+ }
+
+ return ads;
+}
+
+std::vector<gwarnt::p2p_ad> binance::__get_data(const std::string &fiat,
+ const std::string &crypto,
+ const std::string &trade_type,
+ uint64_t page)
+{
+ std::vector<gwarnt::p2p_ad> ads;
+ std::string type;
+ json j;
+
+ type = trade_type;
+ strtoupper(type);
+ if (type == "BUY")
+ type = "BUY";
+ else if (type == "SELL")
+ type = "SELL";
+ else
+ throw std::runtime_error("Invalid trade type: " + trade_type);
+
+ j["fiat"] = fiat;
+ j["page"] = page;
+ j["rows"] = 20;
+ j["tradeType"] = type;
+ j["asset"] = crypto;
+ j["countries"] = json::array();
+ j["proMerchantAds"] = false;
+ j["shieldMerchantAds"] = false;
+ j["filterType"] = "all";
+ j["periods"] = json::array();
+ j["additionalKycVerifyFilter"] = 0;
+ j["publisherType"] = "merchant";
+ j["payTypes"] = json::array();
+ j["classifies"] = json::array();
+ j["classifies"].push_back("mass");
+ j["classifies"].push_back("profession");
+ j["classifies"].push_back("fiat_trade");
+
+ net_.set_url("https://p2p.binance.com/bapi/c2c/v2/friendly/c2c/adv/search");
+ net_.set_method("POST");
+ net_.set_data(j.dump());
+ net_.set_curl_opt(CURLOPT_ACCEPT_ENCODING, "gzip");
+ net_.exec();
+
+ const std::string &res = net_.get_resp();
+ j = json::parse(res);
+
+ for (const auto &i : j["data"]) {
+ try {
+ const auto &adv = i["adv"];
+ gwarnt::p2p_ad p;
+
+ p.ad_id_ = adv["advNo"];
+ p.merchant_name_ = i["advertiser"]["nickName"];
+ p.fiat_ = adv["fiatUnit"];
+ p.crypto_ = adv["asset"];
+ p.trade_type_ = adv["tradeType"];
+ p.price_ = strtod(adv["price"].get<std::string>().c_str(), nullptr);
+ p.min_amount_ = strtod(adv["minSingleTransAmount"].get<std::string>().c_str(), nullptr);
+ p.max_amount_ = strtod(adv["maxSingleTransAmount"].get<std::string>().c_str(), nullptr);
+ p.tradable_amount_ = strtod(adv["tradableQuantity"].get<std::string>().c_str(), nullptr);
+ p.exchange_ = "binance";
+
+ for (auto &j : adv["tradeMethods"]) {
+ try {
+ p.methods_.push_back(j["tradeMethodName"]);
+ } catch (...) {
+ p.methods_.push_back("p:"+j["identifier"].get<std::string>());
+ }
+ }
+
+ ads.push_back(p);
+ } catch (std::exception &e) {
+ printf("gwarnt::p2p::binance::__get_data: %s\n", e.what());
+ }
+ }
+
+ return ads;
+}
+
+} /* namespace gwarnt */
+} /* namespace p2p */
diff --git a/src/gwarnt/p2p/binance.hpp b/src/gwarnt/p2p/binance.hpp
new file mode 100644
index 0000000..1b73dbe
--- /dev/null
+++ b/src/gwarnt/p2p/binance.hpp
@@ -0,0 +1,42 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+#ifndef GWARNT__P2P__BINANCE_HPP
+#define GWARNT__P2P__BINANCE_HPP
+
+#include <gwarnt/net.hpp>
+#include <gwarnt/p2p_ad.hpp>
+
+namespace gwarnt {
+namespace p2p {
+
+class binance {
+public:
+ binance(void);
+ ~binance(void);
+
+ void set_fiat(const std::string &fiat);
+ void set_crypto(const std::string &crypto);
+ void set_trade_type(const std::string &trade_type);
+ std::vector<gwarnt::p2p_ad> get_data(void);
+ std::vector<gwarnt::p2p_ad> get_data(const std::string &fiat,
+ const std::string &crypto,
+ const std::string &trade_type,
+ uint64_t page = ~0ull);
+
+private:
+ std::vector<gwarnt::p2p_ad> __get_data(const std::string &fiat,
+ const std::string &crypto,
+ const std::string &trade_type,
+ uint64_t page);
+
+
+ gwarnt::net net_;
+ std::string fiat_;
+ std::string crypto_;
+ std::string trade_type_;
+};
+
+} /* namespace p2p */
+} /* namespace gwarnt */
+
+#endif /* GWARNT__P2P__BINANCE_HPP */
--
Alviro Iskandar Setiawan
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [RFC PATCH 4/9] gwarnt: p2p: Add P2P OKX
2024-09-10 21:44 [RFC PATCH 0/9] Introducing GNU/Weeb Arbitrage Opportunity Notification Bot Alviro Iskandar Setiawan
2024-09-10 21:44 ` [RFC PATCH 2/9] gwarnt: Create initial P2P ad data structure Alviro Iskandar Setiawan
2024-09-10 21:44 ` [RFC PATCH 3/9] gwarnt: p2p: Add P2P Binance Alviro Iskandar Setiawan
@ 2024-09-10 21:44 ` Alviro Iskandar Setiawan
2024-09-10 21:44 ` [RFC PATCH 5/9] gwarnt: Create function to find arbitrage opportunities Alviro Iskandar Setiawan
` (5 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Alviro Iskandar Setiawan @ 2024-09-10 21:44 UTC (permalink / raw)
To: Ammar Faizi, Michael William Jonathan
Cc: Alviro Iskandar Setiawan, Ravel Kevin Ethan,
GNU/Weeb Mailing List
Add an interface to collect P2P ads from OKX.
Signed-off-by: Alviro Iskandar Setiawan <[email protected]>
---
Makefile | 3 +-
src/gwarnt/p2p/okx.cpp | 101 +++++++++++++++++++++++++++++++++++++++++
src/gwarnt/p2p/okx.hpp | 35 ++++++++++++++
3 files changed, 138 insertions(+), 1 deletion(-)
create mode 100644 src/gwarnt/p2p/okx.cpp
create mode 100644 src/gwarnt/p2p/okx.hpp
diff --git a/Makefile b/Makefile
index 732d1b7..6aa0b32 100644
--- a/Makefile
+++ b/Makefile
@@ -15,7 +15,8 @@ CXX_SOURCES := \
src/gwarnt/helpers.cpp \
src/gwarnt/net.cpp \
src/gwarnt/p2p_ad.cpp \
- src/gwarnt/p2p/binance.cpp
+ src/gwarnt/p2p/binance.cpp \
+ src/gwarnt/p2p/okx.cpp
C_OBJECTS := $(C_SOURCES:.c=.o)
CXX_OBJECTS := $(CXX_SOURCES:.cpp=.o)
diff --git a/src/gwarnt/p2p/okx.cpp b/src/gwarnt/p2p/okx.cpp
new file mode 100644
index 0000000..f37ace4
--- /dev/null
+++ b/src/gwarnt/p2p/okx.cpp
@@ -0,0 +1,101 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+#include <gwarnt/p2p/okx.hpp>
+#include <gwarnt/helpers.hpp>
+#include <gwarnt/json.hpp>
+#include <exception>
+
+using json = nlohmann::json;
+
+namespace gwarnt {
+namespace p2p {
+
+okx::okx(void)
+{
+ net_.add_header("Content-Type", "application/json");
+}
+
+okx::~okx(void) = default;
+
+void okx::set_fiat(const std::string &fiat)
+{
+ fiat_ = fiat;
+}
+
+void okx::set_crypto(const std::string &crypto)
+{
+ crypto_ = crypto;
+}
+
+void okx::set_trade_type(const std::string &trade_type)
+{
+ trade_type_ = trade_type;
+}
+
+std::vector<gwarnt::p2p_ad> okx::get_data(void)
+{
+ return get_data(fiat_, crypto_, trade_type_);
+}
+
+std::vector<gwarnt::p2p_ad> okx::get_data(const std::string &fiat,
+ const std::string &crypto,
+ const std::string &trade_type)
+{
+ std::vector<gwarnt::p2p_ad> ads;
+ std::string type;
+ std::string url;
+ std::string p;
+ json *jent;
+ json j;
+
+ type = trade_type;
+ strtoupper(type);
+ if (type != "BUY" && type != "SELL")
+ throw std::runtime_error("Invalid trade type: " + trade_type);
+
+ p = "side=" + trade_type + "&fiatCurrency=" + fiat + "&cryptoCurrency=" + crypto;
+ url = "https://www.okx.com/v3/c2c/tradingOrders/getMarketplaceAdsPrelogin?&paymentMethod=all&userType=all&hideOverseasVerificationAds=false&sortType=price_asc&limit=1000¤tPage=1&numberPerPage=1000&"
+ + p;
+
+ net_.set_method("GET");
+ net_.set_url(url);
+ net_.set_curl_opt(CURLOPT_ACCEPT_ENCODING, "gzip");
+ net_.exec();
+
+ const std::string &res = net_.get_resp();
+ j = json::parse(res);
+
+ if (type == "SELL")
+ jent = &j["data"]["sell"];
+ else
+ jent = &j["data"]["buy"];
+
+ for (const auto &q : *jent) {
+ try {
+ gwarnt::p2p_ad p;
+
+ p.ad_id_ = q["id"];
+ p.merchant_name_ = q["nickName"];
+ p.trade_type_ = type;
+ p.fiat_ = fiat;
+ p.crypto_ = crypto;
+ p.price_ = strtod(q["price"].get<std::string>().c_str(), nullptr);
+ p.min_amount_ = strtod(q["quoteMinAmountPerOrder"].get<std::string>().c_str(), nullptr);
+ p.max_amount_ = strtod(q["quoteMaxAmountPerOrder"].get<std::string>().c_str(), nullptr);
+ p.tradable_amount_ = strtod(q["availableAmount"].get<std::string>().c_str(), nullptr);
+ p.exchange_ = "okx";
+
+ for (auto &r : q["paymentMethods"])
+ p.methods_.push_back(r);
+
+ ads.push_back(p);
+ } catch (const std::exception &e) {
+ printf("gwarnt::p2p::okx::get_data: %s\n", e.what());
+ }
+ }
+
+ return ads;
+}
+
+} /* namespace gwarnt */
+} /* namespace p2p */
diff --git a/src/gwarnt/p2p/okx.hpp b/src/gwarnt/p2p/okx.hpp
new file mode 100644
index 0000000..3422ac5
--- /dev/null
+++ b/src/gwarnt/p2p/okx.hpp
@@ -0,0 +1,35 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+#ifndef GWARNT__P2P__OKX_HPP
+#define GWARNT__P2P__OKX_HPP
+
+#include <gwarnt/net.hpp>
+#include <gwarnt/p2p_ad.hpp>
+
+namespace gwarnt {
+namespace p2p {
+
+class okx {
+public:
+ okx(void);
+ ~okx(void);
+
+ void set_fiat(const std::string &fiat);
+ void set_crypto(const std::string &crypto);
+ void set_trade_type(const std::string &trade_type);
+ std::vector<gwarnt::p2p_ad> get_data(void);
+ std::vector<gwarnt::p2p_ad> get_data(const std::string &fiat,
+ const std::string &crypto,
+ const std::string &trade_type);
+
+private:
+ gwarnt::net net_;
+ std::string fiat_;
+ std::string crypto_;
+ std::string trade_type_;
+};
+
+} /* namespace p2p */
+} /* namespace gwarnt */
+
+#endif /* GWARNT__P2P__OKX_HPP */
--
Alviro Iskandar Setiawan
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [RFC PATCH 5/9] gwarnt: Create function to find arbitrage opportunities
2024-09-10 21:44 [RFC PATCH 0/9] Introducing GNU/Weeb Arbitrage Opportunity Notification Bot Alviro Iskandar Setiawan
` (2 preceding siblings ...)
2024-09-10 21:44 ` [RFC PATCH 4/9] gwarnt: p2p: Add P2P OKX Alviro Iskandar Setiawan
@ 2024-09-10 21:44 ` Alviro Iskandar Setiawan
2024-09-10 21:44 ` [RFC PATCH 6/9] gwarnt: p2p/binance: Fix invalid page Alviro Iskandar Setiawan
` (4 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Alviro Iskandar Setiawan @ 2024-09-10 21:44 UTC (permalink / raw)
To: Ammar Faizi, Michael William Jonathan
Cc: Alviro Iskandar Setiawan, Ravel Kevin Ethan,
GNU/Weeb Mailing List
After collecting buy and sell ads from two different exchanges, find
the arbitrage opportunities.
Signed-off-by: Alviro Iskandar Setiawan <[email protected]>
---
Makefile | 1 +
src/gwarnt/arbitrage.cpp | 27 +++++++++++++++++++++++++++
src/gwarnt/arbitrage.hpp | 21 +++++++++++++++++++++
3 files changed, 49 insertions(+)
create mode 100644 src/gwarnt/arbitrage.cpp
create mode 100644 src/gwarnt/arbitrage.hpp
diff --git a/Makefile b/Makefile
index 6aa0b32..f775bfc 100644
--- a/Makefile
+++ b/Makefile
@@ -11,6 +11,7 @@ DEPFLAGS = -MT "$@" -MMD -MP -MF $(@:%.o=%.d)
C_SOURCES :=
CXX_SOURCES := \
+ src/gwarnt/arbitrage.cpp \
src/gwarnt/entry.cpp \
src/gwarnt/helpers.cpp \
src/gwarnt/net.cpp \
diff --git a/src/gwarnt/arbitrage.cpp b/src/gwarnt/arbitrage.cpp
new file mode 100644
index 0000000..ec7c771
--- /dev/null
+++ b/src/gwarnt/arbitrage.cpp
@@ -0,0 +1,27 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+#include <gwarnt/arbitrage.hpp>
+
+namespace gwarnt {
+
+std::vector<struct arb_opp> find_arbitrage_opps(const std::vector<p2p_ad> &sell,
+ const std::vector<p2p_ad> &buy)
+{
+ std::vector<struct arb_opp> ret;
+
+ for (const auto &i : buy) {
+ for (const auto &j : sell) {
+ if (j.price_ < i.price_) {
+ struct arb_opp opp;
+
+ opp.buy = i;
+ opp.sell = j;
+ ret.push_back(opp);
+ }
+ }
+ }
+
+ return ret;
+}
+
+} /* namespace gwarnt */
diff --git a/src/gwarnt/arbitrage.hpp b/src/gwarnt/arbitrage.hpp
new file mode 100644
index 0000000..0b0338e
--- /dev/null
+++ b/src/gwarnt/arbitrage.hpp
@@ -0,0 +1,21 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+#ifndef GWARNT__ARBITRAGE_HPP
+#define GWARNT__ARBITRAGE_HPP
+
+#include <gwarnt/p2p_ad.hpp>
+
+namespace gwarnt {
+
+// Arbitrage opportunity
+struct arb_opp {
+ p2p_ad buy;
+ p2p_ad sell;
+};
+
+std::vector<struct arb_opp> find_arbitrage_opps(const std::vector<p2p_ad> &sell,
+ const std::vector<p2p_ad> &buy);
+
+} /* namespace gwarnt */
+
+#endif /* GWARNT__ARBITRAGE_HPP */
--
Alviro Iskandar Setiawan
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [RFC PATCH 6/9] gwarnt: p2p/binance: Fix invalid page
2024-09-10 21:44 [RFC PATCH 0/9] Introducing GNU/Weeb Arbitrage Opportunity Notification Bot Alviro Iskandar Setiawan
` (3 preceding siblings ...)
2024-09-10 21:44 ` [RFC PATCH 5/9] gwarnt: Create function to find arbitrage opportunities Alviro Iskandar Setiawan
@ 2024-09-10 21:44 ` Alviro Iskandar Setiawan
2024-09-10 21:44 ` [RFC PATCH 7/9] gwarnt: Create the initial example Alviro Iskandar Setiawan
` (3 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Alviro Iskandar Setiawan @ 2024-09-10 21:44 UTC (permalink / raw)
To: Ammar Faizi, Michael William Jonathan
Cc: Alviro Iskandar Setiawan, Ravel Kevin Ethan,
GNU/Weeb Mailing List
The page passed to __get_data was wrong, it should take from the
iteration variable instead of 'page' argument which is always ~0ull in
value. While in there, also fix the inverted search as Binance will show
SELL ads when the filter is BUY and vice versa.
Signed-off-by: Alviro Iskandar Setiawan <[email protected]>
---
src/gwarnt/p2p/binance.cpp | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/src/gwarnt/p2p/binance.cpp b/src/gwarnt/p2p/binance.cpp
index 541a5de..81d23fe 100644
--- a/src/gwarnt/p2p/binance.cpp
+++ b/src/gwarnt/p2p/binance.cpp
@@ -50,7 +50,7 @@ std::vector<gwarnt::p2p_ad> binance::get_data(const std::string &fiat,
size_t i;
for (i = 1; i <= 5; i++) {
- tmp = __get_data(fiat, crypto, trade_type, page);
+ tmp = __get_data(fiat, crypto, trade_type, i);
ads.insert(ads.end(), tmp.begin(), tmp.end());
}
} else {
@@ -72,9 +72,9 @@ std::vector<gwarnt::p2p_ad> binance::__get_data(const std::string &fiat,
type = trade_type;
strtoupper(type);
if (type == "BUY")
- type = "BUY";
- else if (type == "SELL")
type = "SELL";
+ else if (type == "SELL")
+ type = "BUY";
else
throw std::runtime_error("Invalid trade type: " + trade_type);
--
Alviro Iskandar Setiawan
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [RFC PATCH 7/9] gwarnt: Create the initial example
2024-09-10 21:44 [RFC PATCH 0/9] Introducing GNU/Weeb Arbitrage Opportunity Notification Bot Alviro Iskandar Setiawan
` (4 preceding siblings ...)
2024-09-10 21:44 ` [RFC PATCH 6/9] gwarnt: p2p/binance: Fix invalid page Alviro Iskandar Setiawan
@ 2024-09-10 21:44 ` Alviro Iskandar Setiawan
2024-09-10 21:44 ` [RFC PATCH 8/9] gwarnt: Add README file Alviro Iskandar Setiawan
` (2 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Alviro Iskandar Setiawan @ 2024-09-10 21:44 UTC (permalink / raw)
To: Ammar Faizi, Michael William Jonathan
Cc: Alviro Iskandar Setiawan, Ravel Kevin Ethan,
GNU/Weeb Mailing List
Initial example to show the usage.
Signed-off-by: Alviro Iskandar Setiawan <[email protected]>
---
src/gwarnt/entry.cpp | 42 ++++++++++++++++++++++++++++++++++++++++++
1 file changed, 42 insertions(+)
diff --git a/src/gwarnt/entry.cpp b/src/gwarnt/entry.cpp
index 4a74df9..044234e 100644
--- a/src/gwarnt/entry.cpp
+++ b/src/gwarnt/entry.cpp
@@ -1,6 +1,48 @@
// SPDX-License-Identifier: GPL-2.0-only
+#include <unistd.h>
+#include <iostream>
+#include <gwarnt/p2p/okx.hpp>
+#include <gwarnt/p2p/binance.hpp>
+#include <gwarnt/arbitrage.hpp>
+
int main(void)
{
+ std::vector<gwarnt::p2p_ad> buy_bnc, sell_bnc;
+ std::vector<gwarnt::p2p_ad> buy_okx, sell_okx;
+ std::vector<gwarnt::arb_opp> opportunities;
+ gwarnt::p2p::binance bnc;
+ gwarnt::p2p::okx okx;
+
+ while (1) {
+ printf("Fetching data ...\n");
+ buy_bnc = bnc.get_data("IDR", "USDT", "BUY");
+ sell_bnc = bnc.get_data("IDR", "USDT", "SELL");
+
+ buy_okx = okx.get_data("IDR", "USDT", "BUY");
+ sell_okx = okx.get_data("IDR", "USDT", "SELL");
+ printf("Binance: %lu buy, %lu sell\n", buy_bnc.size(), sell_bnc.size());
+ printf("OKX: %lu buy, %lu sell\n", buy_okx.size(), sell_okx.size());
+
+ opportunities = gwarnt::find_arbitrage_opps(sell_okx, buy_bnc);
+ for (const auto &i : opportunities) {
+ std::cout << i.sell.dump() << std::endl;
+ std::cout << "====================" << std::endl;
+ std::cout << i.buy.dump() << std::endl;
+ std::cout << "----------------------------------------------" << std::endl;
+ }
+
+ opportunities = gwarnt::find_arbitrage_opps(sell_bnc, buy_okx);
+ for (const auto &i : opportunities) {
+ std::cout << i.sell.dump() << std::endl;
+ std::cout << "====================" << std::endl;
+ std::cout << i.buy.dump() << std::endl;
+ std::cout << "----------------------------------------------" << std::endl;
+ }
+
+ printf("Sleeping...\n");
+ sleep(5);
+ }
+
return 0;
}
--
Alviro Iskandar Setiawan
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [RFC PATCH 8/9] gwarnt: Add README file
2024-09-10 21:44 [RFC PATCH 0/9] Introducing GNU/Weeb Arbitrage Opportunity Notification Bot Alviro Iskandar Setiawan
` (5 preceding siblings ...)
2024-09-10 21:44 ` [RFC PATCH 7/9] gwarnt: Create the initial example Alviro Iskandar Setiawan
@ 2024-09-10 21:44 ` Alviro Iskandar Setiawan
2024-09-10 21:44 ` [RFC PATCH 9/9] gwarnt: Add Telegram bot Alviro Iskandar Setiawan
2024-09-10 22:21 ` [RFC PATCH 0/9] Introducing GNU/Weeb Arbitrage Opportunity Notification Bot Ammar Faizi
8 siblings, 0 replies; 10+ messages in thread
From: Alviro Iskandar Setiawan @ 2024-09-10 21:44 UTC (permalink / raw)
To: Ammar Faizi, Michael William Jonathan
Cc: Alviro Iskandar Setiawan, Ravel Kevin Ethan,
GNU/Weeb Mailing List
Signed-off-by: Alviro Iskandar Setiawan <[email protected]>
---
README | 19 +++++++++++++++++++
1 file changed, 19 insertions(+)
create mode 100644 README
diff --git a/README b/README
new file mode 100644
index 0000000..23786c8
--- /dev/null
+++ b/README
@@ -0,0 +1,19 @@
+gwarnt
+------
+
+GNU/Weeb Arbitrage Opportunity Notification. Find the arbitrage
+opportunities across two different exchanges for a given currency pair.
+
+## Installation
+
+ sudo apt-get install -y git libcurl4-openssl-dev gcc g++ make;
+ git clone https://github.com/alviroiskandar/gwarnt.git;
+ cd gwarnt;
+ make -j$(nproc);
+
+## Run
+
+ ./gwarnt
+
+--
+Alviro Iskandar Setiawan
--
Alviro Iskandar Setiawan
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [RFC PATCH 9/9] gwarnt: Add Telegram bot
2024-09-10 21:44 [RFC PATCH 0/9] Introducing GNU/Weeb Arbitrage Opportunity Notification Bot Alviro Iskandar Setiawan
` (6 preceding siblings ...)
2024-09-10 21:44 ` [RFC PATCH 8/9] gwarnt: Add README file Alviro Iskandar Setiawan
@ 2024-09-10 21:44 ` Alviro Iskandar Setiawan
2024-09-10 22:21 ` [RFC PATCH 0/9] Introducing GNU/Weeb Arbitrage Opportunity Notification Bot Ammar Faizi
8 siblings, 0 replies; 10+ messages in thread
From: Alviro Iskandar Setiawan @ 2024-09-10 21:44 UTC (permalink / raw)
To: Ammar Faizi, Michael William Jonathan
Cc: Alviro Iskandar Setiawan, Ravel Kevin Ethan,
GNU/Weeb Mailing List
Send a notification to Telegram using bot if arbitrage opportunities
detected.
Signed-off-by: Alviro Iskandar Setiawan <[email protected]>
---
Makefile | 1 +
src/gwarnt/entry.cpp | 258 ++++++++++++++++++++++++++++++++++++++-----
src/gwarnt/net.cpp | 2 +
src/gwarnt/tgbot.cpp | 75 +++++++++++++
src/gwarnt/tgbot.hpp | 46 ++++++++
5 files changed, 356 insertions(+), 26 deletions(-)
create mode 100644 src/gwarnt/tgbot.cpp
create mode 100644 src/gwarnt/tgbot.hpp
diff --git a/Makefile b/Makefile
index f775bfc..8de277b 100644
--- a/Makefile
+++ b/Makefile
@@ -16,6 +16,7 @@ CXX_SOURCES := \
src/gwarnt/helpers.cpp \
src/gwarnt/net.cpp \
src/gwarnt/p2p_ad.cpp \
+ src/gwarnt/tgbot.cpp \
src/gwarnt/p2p/binance.cpp \
src/gwarnt/p2p/okx.cpp
diff --git a/src/gwarnt/entry.cpp b/src/gwarnt/entry.cpp
index 044234e..9510c3c 100644
--- a/src/gwarnt/entry.cpp
+++ b/src/gwarnt/entry.cpp
@@ -1,47 +1,253 @@
// SPDX-License-Identifier: GPL-2.0-only
#include <unistd.h>
+#include <ctime>
+#include <cstdlib>
+#include <sstream>
#include <iostream>
+#include <unordered_map>
+
+#include <gwarnt/tgbot.hpp>
#include <gwarnt/p2p/okx.hpp>
#include <gwarnt/p2p/binance.hpp>
#include <gwarnt/arbitrage.hpp>
+#include <gwarnt/helpers.hpp>
-int main(void)
+template <typename T>
+std::string to_string_wp(const T a_value, const int n = 2)
+{
+ std::ostringstream out;
+ out.precision(n);
+ out << std::fixed << a_value;
+ return std::move(out).str();
+}
+
+class gwarnt_bot {
+public:
+ inline void set_token(const std::string &token) { tg_.set_token(token); }
+ inline void set_chat_id(const std::string &chat_id) { chat_id_ = chat_id; }
+
+ void init_get_me(void);
+ void broadcast_opp(const gwarnt::arb_opp &opp);
+ void garbage_collect(void);
+
+private:
+ static constexpr time_t BROADCAST_INTERVAL = 300;
+ gwarnt::tgbot tg_;
+ std::string chat_id_;
+ std::unordered_map<std::string, time_t> broadcast_map_;
+
+ bool opp_need_broadcast(const gwarnt::arb_opp &opp);
+ void insert_broadcast_map(const gwarnt::arb_opp &opp);
+ std::string get_opp_hash(const gwarnt::arb_opp &opp);
+};
+
+inline
+void gwarnt_bot::init_get_me(void)
+{
+ auto j = tg_.get_me();
+ auto username = j["result"]["username"].get<std::string>();
+
+ printf("========================================\n");
+ printf("Bot username : %s\n", username.c_str());
+ printf("Target Chat ID : %s\n", chat_id_.c_str());
+ printf("========================================\n");
+}
+
+inline
+std::string gwarnt_bot::get_opp_hash(const gwarnt::arb_opp &opp)
+{
+ std::string hash = "";
+
+ hash += opp.buy.ad_id_;
+ hash += opp.sell.ad_id_;
+ hash += to_string_wp(opp.buy.price_);
+ hash += to_string_wp(opp.sell.price_);
+
+ return hash;
+}
+
+inline
+void gwarnt_bot::garbage_collect(void)
+{
+ auto it = broadcast_map_.begin();
+
+ while (it != broadcast_map_.end()) {
+ if (time(NULL) - it->second > BROADCAST_INTERVAL)
+ it = broadcast_map_.erase(it);
+ else
+ ++it;
+ }
+}
+
+inline
+bool gwarnt_bot::opp_need_broadcast(const gwarnt::arb_opp &opp)
+{
+ std::string hash = get_opp_hash(opp);
+ auto it = broadcast_map_.find(hash);
+
+ if (it == broadcast_map_.end())
+ return false;
+
+ if (time(NULL) - it->second > BROADCAST_INTERVAL) {
+ broadcast_map_.erase(it);
+ return false;
+ }
+
+ return true;
+}
+
+inline
+void gwarnt_bot::insert_broadcast_map(const gwarnt::arb_opp &opp)
+{
+ std::string hash = get_opp_hash(opp);
+ broadcast_map_[hash] = time(NULL);
+ printf("Inserted hash %s\n", hash.c_str());
+}
+
+static std::string merge_vec_str(const std::vector<std::string> &vec)
+{
+ std::string ret = "";
+ size_t i = 0;
+
+ for (const auto &s : vec)
+ ret += (++i > 1 ? ", " : "") + s;
+
+ return ret;
+}
+
+inline
+void gwarnt_bot::broadcast_opp(const gwarnt::arb_opp &opp)
+{
+ double min_avail;
+ double est_profit;
+
+ if (opp_need_broadcast(opp))
+ return;
+
+ std::string msg = "Arbitrage opportunity detected!\n\n";
+ const auto &b = opp.buy;
+ const auto &s = opp.sell;
+
+ msg += "Buy on " + s.exchange_ + "\n";
+ msg += "m: " + s.ad_id_ + " (" + s.merchant_name_ + ")\n";
+ msg += "price: " + to_string_wp(b.price_, 2) + "\n";
+ msg += "min_buy: " + to_string_wp(s.min_amount_, 2) + " " + s.fiat_ + "\n";
+ msg += "max_buy: " + to_string_wp(s.max_amount_, 2) + " " + s.fiat_ + "\n";
+ msg += "available: " + to_string_wp(s.tradable_amount_, 2) + " " + s.crypto_ + "\n";
+ msg += "methods: " + merge_vec_str(s.methods_) + "\n";
+
+ msg += "\n";
+
+ msg += "Sell on " + b.exchange_ + "\n";
+ msg += "m: " + b.ad_id_ + " (" + b.merchant_name_ + ")\n";
+ msg += "price: " + to_string_wp(s.price_, 2) + "\n";
+ msg += "min_sell: " + to_string_wp(b.min_amount_, 2) + " " + b.fiat_ + "\n";
+ msg += "max_sell: " + to_string_wp(b.max_amount_, 2) + " " + b.fiat_ + "\n";
+ msg += "available: " + to_string_wp(b.tradable_amount_, 2) + " " + b.crypto_ + "\n";
+ msg += "methods: " + merge_vec_str(b.methods_) + "\n";
+
+ msg += "------------------------------------------\n";
+
+ if (b.tradable_amount_ < s.tradable_amount_)
+ min_avail = b.tradable_amount_;
+ else
+ min_avail = s.tradable_amount_;
+
+ est_profit = s.price_ - b.price_;
+ msg += "est_profit_per_unit: " + to_string_wp(est_profit, 2) + " " + s.fiat_ + "\n";
+ msg += "maximum_extractable_value: " + to_string_wp(min_avail * est_profit, 2) + " " + s.fiat_ + "\n";
+
+ tg_.send_message(chat_id_, msg);
+ insert_broadcast_map(opp);
+ sleep(3);
+}
+
+static int broadcast_opp(gwarnt_bot *bot, const gwarnt::arb_opp &opp)
+{
+ bot->broadcast_opp(opp);
+ return 0;
+}
+
+static int broadcast_opps(gwarnt_bot *bot,
+ const std::vector<gwarnt::arb_opp> &opps)
+{
+ std::string msg;
+ gwarnt::tgbot::json j;
+
+ if (opps.size() == 0)
+ return 0;
+
+ for (const auto &opp : opps)
+ broadcast_opp(bot, opp);
+
+ return 0;
+}
+
+static void run(gwarnt_bot *bot, gwarnt::p2p::binance *bnc,
+ gwarnt::p2p::okx *okx)
{
std::vector<gwarnt::p2p_ad> buy_bnc, sell_bnc;
std::vector<gwarnt::p2p_ad> buy_okx, sell_okx;
- std::vector<gwarnt::arb_opp> opportunities;
+ std::vector<gwarnt::arb_opp> opps;
+
+ printf("Fetching data...\n");
+
+ buy_bnc = bnc->get_data("IDR", "USDT", "BUY");
+ sell_bnc = bnc->get_data("IDR", "USDT", "SELL");
+ buy_okx = okx->get_data("IDR", "USDT", "BUY");
+ sell_okx = okx->get_data("IDR", "USDT", "SELL");
+
+ printf("Binance : %lu buy, %lu sell\n", buy_bnc.size(), sell_bnc.size());
+ printf("OKX : %lu buy, %lu sell\n", buy_okx.size(), sell_okx.size());
+
+ opps = gwarnt::find_arbitrage_opps(sell_okx, buy_bnc);
+ printf("Opp1 : %zu\n", opps.size());
+ broadcast_opps(bot, opps);
+
+ opps = gwarnt::find_arbitrage_opps(sell_bnc, buy_okx);
+ printf("Opp2 : %zu\n", opps.size());
+ broadcast_opps(bot, opps);
+}
+
+int main(void)
+{
gwarnt::p2p::binance bnc;
gwarnt::p2p::okx okx;
+ const char *tmp;
+ gwarnt_bot bot;
+ unsigned u = 5;
+
+ tmp = std::getenv("TG_BOT_TOKEN");
+ if (!tmp) {
+ printf("Please set TG_BOT_TOKEN environment variable!\n");
+ return 1;
+ }
+ bot.set_token(tmp);
+
+ tmp = std::getenv("TG_CHAT_ID");
+ if (!tmp) {
+ printf("Please set TG_CHAT_ID environment variable!\n");
+ return 1;
+ }
+ bot.set_chat_id(tmp);
+ bot.init_get_me();
while (1) {
- printf("Fetching data ...\n");
- buy_bnc = bnc.get_data("IDR", "USDT", "BUY");
- sell_bnc = bnc.get_data("IDR", "USDT", "SELL");
-
- buy_okx = okx.get_data("IDR", "USDT", "BUY");
- sell_okx = okx.get_data("IDR", "USDT", "SELL");
- printf("Binance: %lu buy, %lu sell\n", buy_bnc.size(), sell_bnc.size());
- printf("OKX: %lu buy, %lu sell\n", buy_okx.size(), sell_okx.size());
-
- opportunities = gwarnt::find_arbitrage_opps(sell_okx, buy_bnc);
- for (const auto &i : opportunities) {
- std::cout << i.sell.dump() << std::endl;
- std::cout << "====================" << std::endl;
- std::cout << i.buy.dump() << std::endl;
- std::cout << "----------------------------------------------" << std::endl;
- }
- opportunities = gwarnt::find_arbitrage_opps(sell_bnc, buy_okx);
- for (const auto &i : opportunities) {
- std::cout << i.sell.dump() << std::endl;
- std::cout << "====================" << std::endl;
- std::cout << i.buy.dump() << std::endl;
- std::cout << "----------------------------------------------" << std::endl;
+ try {
+ run(&bot, &bnc, &okx);
+ u = 5;
+ } catch (std::exception &e) {
+ printf("Exception: %s\n", e.what());
+
+ // Double the sleep time if exception occurs.
+ u *= 2;
}
- printf("Sleeping...\n");
- sleep(5);
+ bot.garbage_collect();
+ printf("Sleeping for %u seconds...\n", u);
+ sleep(u);
}
return 0;
diff --git a/src/gwarnt/net.cpp b/src/gwarnt/net.cpp
index 8aa78f4..da38047 100644
--- a/src/gwarnt/net.cpp
+++ b/src/gwarnt/net.cpp
@@ -129,6 +129,8 @@ void net::exec(void)
curl_easy_setopt(ch_, CURLOPT_PROXY, proxy_.c_str());
curl_easy_setopt(ch_, CURLOPT_WRITEFUNCTION, &curl_write_callback);
curl_easy_setopt(ch_, CURLOPT_WRITEDATA, &resp_);
+ curl_easy_setopt(ch_, CURLOPT_TIMEOUT, 30L);
+ curl_easy_setopt(ch_, CURLOPT_CONNECTTIMEOUT, 10L);
resp_.clear();
res = curl_easy_perform(ch_);
diff --git a/src/gwarnt/tgbot.cpp b/src/gwarnt/tgbot.cpp
new file mode 100644
index 0000000..2c39c37
--- /dev/null
+++ b/src/gwarnt/tgbot.cpp
@@ -0,0 +1,75 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+#include <gwarnt/tgbot.hpp>
+
+using json = nlohmann::json;
+
+namespace gwarnt {
+
+tgbot::tgbot(const std::string &token):
+ token_(token)
+{
+ init();
+}
+
+tgbot::tgbot(void)
+{
+ init();
+}
+
+inline void tgbot::init(void)
+{
+ net_.add_header("Content-Type", "application/json");
+}
+
+tgbot::~tgbot(void) = default;
+
+json tgbot::send_message(const std::string &chat_id, const std::string &text,
+ tgbot_send_msg_t parse_mode)
+{
+ json j;
+
+ j["chat_id"] = chat_id;
+ j["text"] = text;
+
+ switch (parse_mode) {
+ case SEND_MSG_HTML:
+ j["parse_mode"] = "HTML";
+ break;
+ case SEND_MSG_MARKDOWN:
+ j["parse_mode"] = "Markdown";
+ break;
+ default:
+ break;
+ }
+
+ return exec_post("sendMessage", j);
+}
+
+json tgbot::get_me(void)
+{
+ return exec_get("getMe");
+}
+
+json tgbot::exec_post(const std::string &method, const json &data)
+{
+ std::string url = "https://api.telegram.org/bot" + token_ + "/" + method;
+
+ net_.set_url(url);
+ net_.set_data(data.dump());
+ net_.set_method("POST");
+ net_.exec();
+ return json::parse(net_.get_resp());
+}
+
+json tgbot::exec_get(const std::string &method)
+{
+ std::string url = "https://api.telegram.org/bot" + token_ + "/" + method;
+
+ net_.set_url(url);
+ net_.set_method("GET");
+ net_.exec();
+ return json::parse(net_.get_resp());
+}
+
+} /* namespace gwarnt */
diff --git a/src/gwarnt/tgbot.hpp b/src/gwarnt/tgbot.hpp
new file mode 100644
index 0000000..73cae79
--- /dev/null
+++ b/src/gwarnt/tgbot.hpp
@@ -0,0 +1,46 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+#ifndef GWARNT__TGBOT_HPP
+#define GWARNT__TGBOT_HPP
+
+#include <gwarnt/net.hpp>
+#include <gwarnt/json.hpp>
+
+#include <string>
+
+namespace gwarnt {
+
+typedef enum tgbot_send_msg {
+ SEND_MSG_PLAIN,
+ SEND_MSG_HTML,
+ SEND_MSG_MARKDOWN,
+} tgbot_send_msg_t;
+
+class tgbot {
+public:
+ using json = nlohmann::json;
+
+ tgbot(const std::string &token);
+ tgbot(void);
+ ~tgbot(void);
+
+ json send_message(const std::string &chat_id, const std::string &text,
+ tgbot_send_msg_t parse_mode = SEND_MSG_PLAIN);
+
+ json get_me(void);
+
+ void set_token(const std::string &token) { token_ = token; }
+
+private:
+ json exec_post(const std::string &method, const json &data);
+ json exec_get(const std::string &method);
+ void init(void);
+
+ net net_;
+
+ std::string token_;
+};
+
+} /* namespace gwarnt */
+
+#endif /* #ifndef GWARNT__TGBOT_HPP */
--
Alviro Iskandar Setiawan
^ permalink raw reply related [flat|nested] 10+ messages in thread
* Re: [RFC PATCH 0/9] Introducing GNU/Weeb Arbitrage Opportunity Notification Bot
2024-09-10 21:44 [RFC PATCH 0/9] Introducing GNU/Weeb Arbitrage Opportunity Notification Bot Alviro Iskandar Setiawan
` (7 preceding siblings ...)
2024-09-10 21:44 ` [RFC PATCH 9/9] gwarnt: Add Telegram bot Alviro Iskandar Setiawan
@ 2024-09-10 22:21 ` Ammar Faizi
8 siblings, 0 replies; 10+ messages in thread
From: Ammar Faizi @ 2024-09-10 22:21 UTC (permalink / raw)
To: Alviro Iskandar Setiawan
Cc: Michael William Jonathan, Ravel Kevin Ethan,
GNU/Weeb Mailing List
On 9/11/24 4:44 AM, Alviro Iskandar Setiawan wrote:
> I believe this tool would be a valuable addition to the GNU/Weeb group
> and would streamline the process of identifying arbitrage possibilities.
> Please consider integrating this bot (@FreezingNightBot) into the group
> for the benefit of our community.
>
> Thank you for your consideration!
Thanks for developing the bot!
Let's give it a whirl and see how useful it is.
--
Ammar Faizi
^ permalink raw reply [flat|nested] 10+ messages in thread
end of thread, other threads:[~2024-09-10 22:21 UTC | newest]
Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-09-10 21:44 [RFC PATCH 0/9] Introducing GNU/Weeb Arbitrage Opportunity Notification Bot Alviro Iskandar Setiawan
2024-09-10 21:44 ` [RFC PATCH 2/9] gwarnt: Create initial P2P ad data structure Alviro Iskandar Setiawan
2024-09-10 21:44 ` [RFC PATCH 3/9] gwarnt: p2p: Add P2P Binance Alviro Iskandar Setiawan
2024-09-10 21:44 ` [RFC PATCH 4/9] gwarnt: p2p: Add P2P OKX Alviro Iskandar Setiawan
2024-09-10 21:44 ` [RFC PATCH 5/9] gwarnt: Create function to find arbitrage opportunities Alviro Iskandar Setiawan
2024-09-10 21:44 ` [RFC PATCH 6/9] gwarnt: p2p/binance: Fix invalid page Alviro Iskandar Setiawan
2024-09-10 21:44 ` [RFC PATCH 7/9] gwarnt: Create the initial example Alviro Iskandar Setiawan
2024-09-10 21:44 ` [RFC PATCH 8/9] gwarnt: Add README file Alviro Iskandar Setiawan
2024-09-10 21:44 ` [RFC PATCH 9/9] gwarnt: Add Telegram bot Alviro Iskandar Setiawan
2024-09-10 22:21 ` [RFC PATCH 0/9] Introducing GNU/Weeb Arbitrage Opportunity Notification Bot Ammar Faizi
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox