First commit to gitea

This commit is contained in:
hoguchi live 2022-05-07 16:49:43 +02:00
parent a464435f9b
commit 2af145e9eb
107 changed files with 6555 additions and 624 deletions

View File

@ -0,0 +1,11 @@
#include "api.h"
class nsfq_proxy_api {
public:
private:
/* HTTP wrapper to interface with the server. */
/* Websocket used to interface with the server. */
websocket_endpoint ws_endpoint;
}

View File

@ -1,5 +1,5 @@
#ifndef _MY_SSL_H_ #ifndef _API_H_
#define _MY_SSL_H_ #define _API_H_
#include <iostream> #include <iostream>
#include <string> #include <string>
@ -16,8 +16,7 @@
#include "../parser/parser.h" #include "../parser/parser.h"
#include "../common/common.h" #include "../common/common.h"
#include "../safe_queue/safe_queue.h" #include "../safe_queue/safe_queue.h"
#include "../my_ssl/my_ssl.h"
int connect_ws(std::string);
#endif #endif

View File

@ -0,0 +1,9 @@
#include "client.h"
namespace proxy {
client::client(void) {
m_q = SafeQueue<std::string>;
m_endpoint =
}
}

View File

@ -0,0 +1,24 @@
#ifndef _CLIENT_H_
#define _CLIENT_H_
#include "../common/common.h"
#include "../ws/ssl_ws.h"
namespace proxy {
/**
NASFAQ proxy client.
*/
class client {
public:
client(void);
~client(void);
void init(void);
private:
SafeQueue<std::string> q;
ws::websocket_endpoint endpoint;
}
}
#endif

View File

@ -1,14 +1,73 @@
#include "common.h" #include "common.h"
std::ostream& operator<< (std::ostream& stream, MSG_TYPE const & type) { /***********************************************************************************
WEBSOCKET MESSAGE STRUCTURES FUNCTIONS
***********************************************************************************/
/**
Displays websocket message types.
*/
std::ostream& operator<< (std::ostream& stream, WS_MSG const & type) {
std::string ret; std::string ret;
switch(type) { switch(type) {
case COIN_PRICE_UPDATE: ret = "COIN_PRICE_UPDATE"; break; #define X(a) case a: ret = #a; break;
case HISTORY_UPDATE: ret = "HISTORY_UPDATE"; break; #include "ws_msg.def"
case BROKER_FEE_UPDATE: ret = "BROKER_FEE_UPDATE"; break; #undef X
case TODAY_PRICES_UPDATE: ret = "TODAY_PRICES_UPDATE"; break; default: ret = "Unknown type";
default: ret = "Unknown type: ";
} }
stream << ret; stream << ret;
return stream; return stream;
} }
/**
Pretty prints COIN_PRICE events.
*/
template<>
std::ostream& operator<< (std::ostream& stream, ws_msg_parsed<WS_EVENT_COIN_PRICE_UPDATE> const & op) {
stream << "WS_EVENT_COIN_PRICE_UPDATE:"
<< " Coin: " << op.coin
<< " Price: " << op.price
<< " SaleValue: " << op.saleValue
<< " inCirculation: " << op.inCirculation;
return stream;
}
/**
Pretty prints WS_EVENT_TRANSACTION events.
*/
template<>
std::ostream& operator<< (std::ostream& stream, ws_msg_parsed<WS_EVENT_TRANSACTION> const & op) {
stream << "WS_EVENT_TRANSACTION:"
<< " Coin: " << op.coin
<< " Type: " << op.type
<< " UserID: " << op.userid
<< " Quantity: " << op.quantity
<< " Timestamp: " << op.timestamp
<< " Completed: " << op.completed
<< " Price: " << op.price;
return stream;
}
/**
Pretty prints the transactions held in the WS_EVENT_HISTORY_UPDATE vector.
*/
template<>
std::ostream& operator<< (std::ostream& stream, ws_msg_parsed<WS_EVENT_HISTORY_UPDATE> const & op) {
stream << "WS_EVENT_HISTORY_UPDATE:\n";
for(auto & element : op.transaction_list) {
stream << "\t" << element << std::endl;
}
return stream;
}
/***********************************************************************************
INGAME MESSAGE STRUCTURES FUNCTIONS
***********************************************************************************/
std::ostream& operator<< (std::ostream& stream, const cycle_t& op) {
stream << "CYCLE: " << std::endl;
for(auto const& element : op) {
stream << element.first << " : " << element.second << std::endl;
}
return stream;
}

View File

@ -7,43 +7,125 @@
#include <iostream> #include <iostream>
#include <string> #include <string>
#include <stdlib.h> #include <stdlib.h>
#include <pthread.h>
#include <time.h>
#include <tuple>
#include <nlohmann/json.hpp> #include <nlohmann/json.hpp>
#include "../common/common.h" //#include "../safe_queue/safe_queue.h"
#include "../safe_queue/safe_queue.h"
/***********************************************************************************
enum MSG_TYPE WEBSOCKET MESSAGE STRUCTURES
{ COIN_PRICE_UPDATE ***********************************************************************************/
, HISTORY_UPDATE /**
, BROKER_FEE_UPDATE Types of messages going through the websocket.
, TODAY_PRICES_UPDATE X-macros: https://stackoverflow.com/questions/201593/is-there-a-simple-way-to-convert-c-enum-to-string
*/
enum WS_MSG {
#define X(a) a,
#include "ws_msg.def"
#undef X
}; };
std::ostream& operator<< (std::ostream&, const MSG_TYPE&); ///**
// Mapping from WS_MSG enum to its name.
//*/
//std::map<WS_MSG, std::string> WS_MSG_map {
// #define X(a) {a, "#a"},
// #include "ws_msg.def"
// #undef X
//};
/**
Structure holding websocket raw data and their type.
Used to fill the queue uniformly
*/
typedef struct raw_msg_t { typedef struct raw_msg_t {
enum MSG_TYPE type; enum WS_MSG type;
std::string data; std::string data;
} raw_message_t ; } raw_message_t ;
/** /**
Placeholder for pre-parsed outputs of the socket. Placeholder for parsed outputs of the websocket.
These structures are c++ formated and should contain the entirety of the represented data.
Specialized below.
*/ */
template <MSG_TYPE E> template <WS_MSG E>
struct pparsed; struct ws_msg_parsed;
/** /**
coinPriceUpdate structure coinPriceUpdate structure
*/ */
template <> template <>
struct pparsed<COIN_PRICE_UPDATE> { struct ws_msg_parsed<WS_EVENT_COIN_PRICE_UPDATE> {
std::string coin; std::string coin;
float price; float price;
float saleValue; float saleValue;
uint inCirculation; uint inCirculation;
}; };
/**
Auxiliary type for WS_EVENT_HISTORY_UPDATE.
This holds individual transactions as handed by the websocket in a list.
*/
template <>
struct ws_msg_parsed<WS_EVENT_TRANSACTION> {
std::string coin;
uint type;
std::string userid;
int quantity;
long timestamp;
bool completed;
float price;
};
/**
historyUpdate structure holding transactions.
*/
template<>
struct ws_msg_parsed<WS_EVENT_HISTORY_UPDATE> {
std::vector<ws_msg_parsed<WS_EVENT_TRANSACTION>> transaction_list;
};
/***********************************************************************************
WEBSOCKET MESSAGE STRUCTURES FUNCTIONS
***********************************************************************************/
std::ostream& operator<< (std::ostream&, const WS_MSG&);
/***********************************************************************************
IN-GAME MESSAGE STRUCTURES
***********************************************************************************/
/**
Types of in-game messages.
*/
enum IG_MSG
{ TRANSACTION
, IG_UNKNOWN_TYPE
};
/***********************************************************************************
INGAME MESSAGE STRUCTURES FUNCTIONS
***********************************************************************************/
template<WS_MSG E>
std::ostream& operator<< (std::ostream&, ws_msg_parsed<E> const &);
/**
Cycle representation.
*/
typedef std::map<std::string, int> cycle_t;
std::ostream& operator<< (std::ostream&, const cycle_t&);
/**
User representation
*/
typedef struct user_t{
std::string userid;
std::string username;
std::string icon;
float networth;
} user_t;
#endif #endif

View File

@ -0,0 +1,13 @@
X(WS_EVENT_COIN_PRICE_UPDATE)
X(WS_EVENT_TRANSACTION)
X(WS_EVENT_HISTORY_UPDATE)
X(WS_EVENT_BROKER_FEE_UPDATE)
X(WS_EVENT_TODAY_PRICES_UPDATE)
X(WS_EVENT_LEADERBOARD_UPDATE)
X(WS_EVENT_FLOOR_UPDATE)
X(WS_EVENT_AUCTION_UPDATE)
X(WS_EVENT_BENCHMARK_UPDATE)
X(WS_EVENT_SUPERCHAT_UPDATE)
X(WS_EVENT_GACHA_UPDATE)
X(WS_EVENT_ADD_MESSAGE_GLOBAL)
X(WS_EVENT_UNKNOWN)

View File

@ -1,171 +1,171 @@
#include "http_connector.h" #include "http_connector.h"
static size_t WriteCallback(void *contents, size_t size, size_t nmemb, void *userp) namespace nsfq_http {
{ namespace http_connector {
/**
Make curl return strings instead of curl objects.
*/
static size_t WriteCallback(void *contents, size_t size, size_t nmemb, void *userp)
{
((std::string*)userp)->append((char*)contents, size * nmemb); ((std::string*)userp)->append((char*)contents, size * nmemb);
return size * nmemb; return size * nmemb;
} }
//class http_connection { connector::connector() {
//public: m_hdl = curl_easy_init();
// http_connection(int id, CURL *hdl, std::string uri) m_uri = "";
// : m_id(id) m_response = "N/A";
// ; m_hdl(hdl) m_read_buffer = "";
// ; m_uri(uri)
// ; m_response("N/A") /* Basic buffers and functions. */
// {} curl_easy_setopt(m_hdl, CURLOPT_WRITEFUNCTION, WriteCallback);
// curl_easy_setopt(m_hdl, CURLOPT_WRITEDATA, &m_read_buffer);
//private: curl_easy_getinfo(m_hdl, CURLINFO_RESPONSE_CODE, &m_http_code);
// int m_id;
// CURL *m_hdl; /* Header definition. TODO: cookie should be handled safely? */
// std::string m_uri; m_slist1 = NULL;
// CURLcode m_status; m_slist1 = curl_slist_append(m_slist1 , "Cookie: holosesh=s%3AxmS8xBlQk4kH_rXQOaNjHk_3OuaBDsfA.M0yi%2BZmkiq%2BAmJBRj%2FNg9S%2BaSQpsfHRJcEeYVHLiKXg");
// std::string m_response; m_slist1 = curl_slist_append(m_slist1, "referer : https://nasfaq.biz/market");
// std::vector<std::string> m_payloads; curl_easy_setopt(m_hdl, CURLOPT_HTTPHEADER, m_slist1);
//} }
//
//class http_endpoint { connector::~connector() {
//public: curl_easy_cleanup(m_hdl);
// http_endpoint() { }
//
// } void connector::set_uri(std::string uri) {
//private: /* TODO: check for url sanity. */
//} m_uri = uri;
curl_easy_setopt(m_hdl, CURLOPT_URL, m_uri.c_str());
std::string get_sid() }
{
CURL *curl; int connector::perform_request() {
CURLcode res; m_result = curl_easy_perform(m_hdl);
static const char *POLLING_URL_0 = "https://nasfaq.biz/socket/?EIO=4&transport=polling&t=Ny7z439"; if (m_result == CURLE_OK) {
static const char *POLLING_URL_1 = "https://nasfaq.biz/socket/?user=314d0bda-d7f0-4636-aed7-5ea02743604b&EIO=4&transport=polling&t=Ny7z472"; return 0;
static const char *POLLING_URL_2 = "https://nasfaq.biz/socket/?user=314d0bda-d7f0-4636-aed7-5ea02743604b&EIO=4&transport=polling&t=Ny7z4Bn&sid="; }else {
static const char *POLLING_URL_3 = "https://nasfaq.biz/socket/?user=314d0bda-d7f0-4636-aed7-5ea02743604b&EIO=4&transport=polling&t=Ny7z4Bp&sid="; return -1;
static const char *POLLING_URL_4 = "https://nasfaq.biz/socket/?user=314d0bda-d7f0-4636-aed7-5ea02743604b&EIO=4&transport=polling&t=Ny7z4EU&sid="; }
}
long http_code = 0;
std::string sid_final = ""; void connector::clear_buffer() {
std::string readBuffer = ""; m_read_buffer = "";
}
curl = curl_easy_init();
void connector::get(std::string url) {
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback); clear_buffer();
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &readBuffer); set_uri(url);
curl_easy_getinfo (curl, CURLINFO_RESPONSE_CODE, &http_code); curl_easy_setopt(m_hdl, CURLOPT_CUSTOMREQUEST, "GET");
/* Header */ if(perform_request() == -1) {
struct curl_slist *slist1; std::cout << "> Error occured during GET with url " << m_uri
slist1 = NULL; << " CURLcode: " << curl_easy_strerror(m_result)
slist1 = curl_slist_append(slist1 , "Cookie: holosesh=s%3AxmS8xBlQk4kH_rXQOaNjHk_3OuaBDsfA.M0yi%2BZmkiq%2BAmJBRj%2FNg9S%2BaSQpsfHRJcEeYVHLiKXg"); << " HTTP response: " << m_http_code << std::endl;
slist1 =curl_slist_append(slist1, "referer : https://nasfaq.biz/market"); };
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, slist1); }
if(curl) { void connector::post(std::string url, std::string payload) {
clear_buffer();
/************** ZEROTH STAGE ********/ set_uri(url);
readBuffer = ""; curl_easy_setopt(m_hdl, CURLOPT_CUSTOMREQUEST, "POST");
curl_easy_setopt(curl, CURLOPT_URL, POLLING_URL_0); curl_easy_setopt(m_hdl, CURLOPT_POSTFIELDS, payload.c_str());
res = curl_easy_perform(curl);
if(perform_request() == -1) {
/* Check for result */ std::cout << "> Error occured during POST with url " << m_uri
if ( res != CURLE_ABORTED_BY_CALLBACK) { << " Payload: " << payload
std::cout << "Zeroth stage ok" << std::endl; << " CURLcode: " << curl_easy_strerror(m_result)
}else { << " HTTP response: " << m_http_code << std::endl;
std::cout << "Failure" << std::endl; };
return ""; }
}
std::string connector::get_buffer() const {
return m_read_buffer;
/************** FIRST STAGE ********/ }
readBuffer = "";
curl_easy_setopt(curl, CURLOPT_URL, POLLING_URL_1); //class http_connector {
//public:
/* Perform the request, res will get the return code */ // http_connector() {
res = curl_easy_perform(curl); // m_hdl = curl_easy_init();
// m_uri = "";
/* Check for result */ // m_response = "N/A";
if (res != CURLE_ABORTED_BY_CALLBACK) { // m_read_buffer = "";
std::cout << "First stage ok" << std::endl; //
}else { // /* Basic buffers and functions. */
std::cout << "Failure" << std::endl; // curl_easy_setopt(m_hdl, CURLOPT_WRITEFUNCTION, WriteCallback);
return ""; // curl_easy_setopt(m_hdl, CURLOPT_WRITEDATA, &m_read_buffer);
} // curl_easy_getinfo(m_hdl, CURLINFO_RESPONSE_CODE, &m_http_code);
//
/* Get sid */ // /* Header definition. TODO: cookie should be handled safely? */
nlohmann::json r = nlohmann::json::parse(readBuffer.substr(1)); // m_slist1 = NULL;
sid_final = r["sid"]; // m_slist1 = curl_slist_append(m_slist1 , "Cookie: holosesh=s%3AxmS8xBlQk4kH_rXQOaNjHk_3OuaBDsfA.M0yi%2BZmkiq%2BAmJBRj%2FNg9S%2BaSQpsfHRJcEeYVHLiKXg");
// m_slist1 = curl_slist_append(m_slist1, "referer : https://nasfaq.biz/market");
// curl_easy_setopt(m_hdl, CURLOPT_HTTPHEADER, m_slist1);
/************** SECOND STAGE ********/ // }
readBuffer = ""; //
std::string polling_url_2 = POLLING_URL_2 + sid_final; // ~http_connector() {
// curl_easy_cleanup(m_hdl);
curl_easy_setopt(curl, CURLOPT_URL, polling_url_2.c_str()); // }
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, "40"); //
curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "POST"); // void set_uri(std::string uri) {
// /* TODO: check for url sanity. */
/* Perform the request, res will get the return code */ // m_uri = uri;
res = curl_easy_perform(curl); // curl_easy_setopt(m_hdl, CURLOPT_URL, m_uri.c_str());
// }
/* Check for result */ //
if (res != CURLE_ABORTED_BY_CALLBACK && readBuffer == "ok") { // int perform_request() {
std::cout << "Second stage ok" << std::endl; // m_result = curl_easy_perform(m_hdl);
}else { //
std::cout << "Failure" << std::endl; // if (m_result == CURLE_OK) {
return ""; // return 0;
} // }else {
// return -1;
/************** THIRD STAGE ********/ // }
readBuffer = ""; // }
//
// Format next url // void clear_buffer() {
std::string polling_url_3 = POLLING_URL_3 + sid_final; // m_read_buffer = "";
// }
curl_easy_setopt(curl, CURLOPT_URL, polling_url_3.c_str()); //
curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "GET"); // void get(std::string url) {
// clear_buffer();
/* Perform the request, res will get the return code */ // set_uri(url);
res = curl_easy_perform(curl); // curl_easy_setopt(m_hdl, CURLOPT_CUSTOMREQUEST, "GET");
//
// if(perform_request() == -1) {
/* Check for result */ // std::cout << "> Error occured during GET with url " << m_uri
if (res != CURLE_ABORTED_BY_CALLBACK) { // << " CURLcode: " << curl_easy_strerror(m_result)
nlohmann::json r2 = nlohmann::json::parse(readBuffer.substr(2)); // << " HTTP response: " << m_http_code << std::endl;
std::cout << "Third stage ok" << std::endl; // };
}else { // }
std::cout << "Failure" << std::endl; //
return ""; // void post(std::string url, std::string payload) {
} // clear_buffer();
// set_uri(url);
// curl_easy_setopt(m_hdl, CURLOPT_CUSTOMREQUEST, "POST");
/************** FOURTH STAGE ********/ // curl_easy_setopt(m_hdl, CURLOPT_POSTFIELDS, payload.c_str());
readBuffer = ""; //
std::string polling_url_4 = POLLING_URL_4 + sid_final; // if(perform_request() == -1) {
// std::cout << "> Error occured during POST with url " << m_uri
curl_easy_setopt(curl, CURLOPT_URL, polling_url_4.c_str()); // << " Payload: " << payload
curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "GET"); // << " CURLcode: " << curl_easy_strerror(m_result)
// << " HTTP response: " << m_http_code << std::endl;
/* Perform the request, res will get the return code */ // };
res = curl_easy_perform(curl); // }
//
/* Check for result */ // std::string get_buffer() const {
if ( res != CURLE_ABORTED_BY_CALLBACK) { // return m_read_buffer;
std::cout << "Fourth stage ok" << std::endl; // }
}else { //private:
std::cout << "Failure" << std::endl; // int m_id;
return ""; // std::string m_uri;
} // struct curl_slist *m_slist1;
// CURL *m_hdl;
// CURLcode m_result;
// long m_http_code;
/* Check for errors */ // std::string m_response;
if(res != CURLE_OK) // std::string m_read_buffer;
fprintf(stderr, "curl_easy_perform() failed: %s\n", //};
curl_easy_strerror(res)); }
/* always cleanup */
curl_easy_cleanup(curl);
}
return sid_final;
} }

View File

@ -7,6 +7,34 @@
#include <curl/curl.h> #include <curl/curl.h>
#include <nlohmann/json.hpp> #include <nlohmann/json.hpp>
std::string get_sid(); /**
Some of these functions such as perform_request should be private
*/
namespace nsfq_http {
namespace http_connector {
class connector {
public:
connector();
~connector();
void set_uri(std::string);
int perform_request();
void clear_buffer();
void get(std::string);
void post(std::string, std::string);
std::string get_buffer() const;
private:
int m_id;
std::string m_uri;
struct curl_slist *m_slist1;
CURL *m_hdl;
CURLcode m_result;
long m_http_code;
std::string m_response;
std::string m_read_buffer;
};
}
}
#endif #endif

View File

@ -0,0 +1,28 @@
#include "users.h"
namespace users {
std::vector<user_t> get_users() {
nlohmann::json j;
user_t user_tmp;
std::vector<user_t> rop;
static const char *LEADERBOARD_URL = "https://nasfaq.biz/api/getLeaderboard?leaderboard";
nsfq_http::http_connector::connector c;
/* Start handshake, first result is discarded. */
c.get(LEADERBOARD_URL);
j = nlohmann::json::parse(c.get_buffer())["leaderboard"]["leaderboard"];
for(auto const & element:j) {
user_tmp.userid = element["userid"];
user_tmp.username = element["username"];
user_tmp.icon = element["icon"];
user_tmp.networth = element["networth"];
rop.push_back(user_tmp);
}
return rop;
}
}

View File

@ -0,0 +1,19 @@
#ifndef _USERS_H_
#define _USERS_H_
#include <iostream>
#include <stdio.h>
#include <string.h>
//#include <curl/curl.h>
//#include <nlohmann/json.hpp>
#include "../http/http_connector.h"
#include "../common/common.h"
namespace users {
std::vector<user_t> get_users();
}
#endif

View File

@ -1,29 +1,33 @@
#include "parser.h" #include "parser.h"
MSG_TYPE msg_type_detect(std::string op) {
MSG_TYPE ret;
if (op.substr(2, 15) == "coinPriceUpdate") { namespace parser {
ret = COIN_PRICE_UPDATE;
} else if (op.substr(2, 13) == "historyUpdate") { WS_MSG msg_type_detect(std::string op) {
ret = HISTORY_UPDATE; WS_MSG ret;
} else if (op.substr(2, 17) == "todayPricesUpdate") {
ret = TODAY_PRICES_UPDATE; if (op.substr(0, 30).find("coinPriceUpdate") != std::string::npos) {
} else if (op.substr(2, 15) == "brokerFeeUpdate") { ret = WS_EVENT_COIN_PRICE_UPDATE;
ret = BROKER_FEE_UPDATE; } else if (op.substr(0, 30).find("historyUpdate") != std::string::npos) {
ret = WS_EVENT_HISTORY_UPDATE;
} else if (op.substr(0, 30).find("todayPricespdate") != std::string::npos) {
ret = WS_EVENT_TODAY_PRICES_UPDATE;
} else if (op.substr(0, 30).find("brokerFeeUpdate") != std::string::npos) {
ret = WS_EVENT_BROKER_FEE_UPDATE;
} else {
ret = WS_EVENT_UNKNOWN;
} }
return ret; return ret;
} }
template <MSG_TYPE E> template <WS_MSG E>
pparsed<E> parse(raw_msg_t rmsg) {}; ws_msg_parsed<E> parse(std::string rmsg) {};
template <> template <>
pparsed<COIN_PRICE_UPDATE> parse<COIN_PRICE_UPDATE>(raw_msg_t rmsg) { ws_msg_parsed<WS_EVENT_COIN_PRICE_UPDATE> raw_msg_parse<WS_EVENT_COIN_PRICE_UPDATE>(std::string rmsg) {
std::string payload = rmsg.data; nlohmann::json jparsed = nlohmann::json::parse(rmsg); /* Check for errors and emptiness needed */
nlohmann::json jparsed = nlohmann::json::parse(payload.substr(21, payload.length()-21-1)); /* Check for errors and emptiness needed */
pparsed<COIN_PRICE_UPDATE> rop; ws_msg_parsed<WS_EVENT_COIN_PRICE_UPDATE> rop;
rop.coin = jparsed["coin"]; rop.coin = jparsed["coin"];
rop.price = (jparsed["info"])["price"]; rop.price = (jparsed["info"])["price"];
rop.saleValue = (jparsed["info"])["saleValue"]; rop.saleValue = (jparsed["info"])["saleValue"];
@ -32,28 +36,141 @@ pparsed<COIN_PRICE_UPDATE> parse<COIN_PRICE_UPDATE>(raw_msg_t rmsg) {
return rop; return rop;
} }
/****************************************************************
Helper functions should go in common or something more general
****************************************************************/
//class parser { /*
//public: See https://stackoverflow.com/questions/2896600/how-to-replace-all-occurrences-of-a-character-in-string
// parser (SafeQueue<raw_msg_t> queue) */
// : m_queue(queue); static inline void replace_all(std::string& str, const std::string& from, const std::string& to) {
// {} size_t start_pos = 0;
// while((start_pos = str.find(from, start_pos)) != std::string::npos) {
// void parse() { str.replace(start_pos, from.length(), to);
// std::string raw_data; start_pos += to.length(); // Handles case where 'to' is a substring of 'from'
// }
// msg_type type; }
// std::string data;
// /*
// while(1) { Splits a string "{...}, ..., {...}" in an array ["{...}", ..., "{...}"].
// raw_data = m_queue.dequeue(); ONLY HANDLES DICTIONARIES OF DEPTH 1.
// type = msg_type_detect(raw_data); */
// std::vector<std::string> tokenize_json_array(std::string op, std::string token = "}") {
// data = m_queue. int start = 0;
// sleep(0.5); int end = op.find("}");
// } std::vector<std::string> ret;
// }
//private: while( end != -1 ) {
// SafeQueue<raw_msg_t> m_queue; ret.push_back(op.substr(start, end - start + 1));
//} start = end + token.size() + 1; // + 1 accounts for the ",".
// end = op.find(token, start);
}
return ret;
}
template <>
ws_msg_parsed<WS_EVENT_TRANSACTION> raw_msg_parse<WS_EVENT_TRANSACTION>(std::string rmsg) {
nlohmann::json jparsed = nlohmann::json::parse(rmsg); /* Check for errors and emptiness needed */
ws_msg_parsed<WS_EVENT_TRANSACTION> rop;
rop.coin = jparsed["coin"];
rop.type = jparsed["type"];
rop.userid = jparsed["userid"];
rop.quantity = jparsed["quantity"];
rop.timestamp = jparsed["timestamp"];
rop.completed = jparsed["completed"];
rop.timestamp = jparsed["timestamp"];
rop.price = jparsed["price"];
return rop;
}
template<>
ws_msg_parsed<WS_EVENT_HISTORY_UPDATE> raw_msg_parse<WS_EVENT_HISTORY_UPDATE>(std::string rmsg) {
std::vector<std::string> raw_vect;
ws_msg_parsed<WS_EVENT_HISTORY_UPDATE> rop;
/* Replace \" by " */
replace_all(rmsg, "\\\"", "\"");
/* Extract array */
raw_vect = tokenize_json_array(rmsg);
/* Create the output array by parsing each transaction elements */
for(auto & raw_tr : raw_vect) {
rop.transaction_list.push_back(raw_msg_parse<WS_EVENT_TRANSACTION>(raw_tr));
}
return rop;
}
parser::parser(ws::connection_metadata::ptr metadata, pqxx::connection* C)
: m_metadata(metadata)
, m_process_queue_state(false)
, m_connection(C)
{}
parser::~parser() {
}
void parser::process_queue() {
WS_MSG type;
std::string raw_data;
std::string parsed_msg;
m_process_queue_state = true;
while(m_process_queue_state) {
raw_data = m_metadata->pop_message();
type = msg_type_detect(raw_data);
/* POSTGRESQL STUFF GOES HERE */
if (type == WS_EVENT_COIN_PRICE_UPDATE) {
/* 18 = 3 + 15 */
raw_data = raw_data.substr(18, raw_data.length()-18);
ws_msg_parsed<WS_EVENT_COIN_PRICE_UPDATE> parsed_msg = raw_msg_parse<WS_EVENT_COIN_PRICE_UPDATE>(raw_data);
std::cout << parsed_msg << std::endl;
db::push_coin_price(m_connection, parsed_msg);
} else if (type == WS_EVENT_HISTORY_UPDATE) {
raw_data = raw_data.substr(18, raw_data.length()-18);
ws_msg_parsed<WS_EVENT_HISTORY_UPDATE> parsed_msg = raw_msg_parse<WS_EVENT_HISTORY_UPDATE>(raw_data);
std::cout << parsed_msg << std::endl;
db::push_history(m_connection, parsed_msg);
//std::cout << "\x1B[31mTexting\033[0m\t\t" << std::endl;
}
}
}
void* parser::process_queue_helper(void* arg)
{
parser* p = reinterpret_cast<parser*>(arg);
p->process_queue();
return 0;
}
void parser::process_queue_start() {
int rc = pthread_create(&m_process_queue_thread, NULL, process_queue_helper, this);
if (rc) {
std::cout << "Error:unable to create thread," << rc << std::endl;
exit(-1);
}
}
void parser::process_queue_thread_join()
{
pthread_join(m_process_queue_thread, 0);
}
void parser::process_queue_stop() {
m_process_queue_state = false;
}
}

View File

@ -6,11 +6,46 @@
#include <stdlib.h> #include <stdlib.h>
#include <nlohmann/json.hpp> #include <nlohmann/json.hpp>
#include "../sql/db_handle.h"
#include "../common/common.h" #include "../common/common.h"
#include "../safe_queue/safe_queue.h" #include "../ws/ssl_ws.h"
MSG_TYPE msg_type_detect(std::string); namespace parser {
WS_MSG msg_type_detect(std::string);
template <WS_MSG E>
ws_msg_parsed<E> raw_msg_parse(std::string);
template <>
ws_msg_parsed<WS_EVENT_COIN_PRICE_UPDATE> raw_msg_parse<WS_EVENT_COIN_PRICE_UPDATE>(std::string);
template<>
ws_msg_parsed<WS_EVENT_TRANSACTION> raw_msg_parse<WS_EVENT_TRANSACTION>(std::string);
template<>
ws_msg_parsed<WS_EVENT_HISTORY_UPDATE> raw_msg_parse<WS_EVENT_HISTORY_UPDATE>(std::string);
class parser {
public:
parser(ws::connection_metadata::ptr, pqxx::connection*);
~parser(void);
void process_queue();
void process_queue_start();
void process_queue_stop();
void process_queue_thread_join();
private:
ws::connection_metadata::ptr m_metadata;
bool m_process_queue_state;
pthread_t m_process_queue_thread;
pqxx::connection* m_connection;
static void* process_queue_helper(void*);
};
}
#endif #endif

View File

@ -1,2 +1,50 @@
#include "safe_queue.h" #include "safe_queue.h"
template <typename T>
TestQueue<T>::TestQueue(void)
: q()
{}
template <typename T>
TestQueue<T>::~TestQueue(void)
{}
template <typename T>
SafeQueue<T>::SafeQueue(void)
: q()
, m()
, c()
{}
template <typename T>
SafeQueue<T>::~SafeQueue(void)
{}
// Add an element to the queue.
template <typename T>
void SafeQueue<T>::enqueue(T t)
{
std::lock_guard<std::mutex> lock(m);
q.push(t);
c.notify_one();
}
// Get the "front"-element.
// If the queue is empty, wait till a element is avaiable.
template <typename T>
T SafeQueue<T>::dequeue(void) {
std::unique_lock<std::mutex> lock(m);
while(q.empty())
{
// release lock as long as the wait and reaquire it afterwards.
c.wait(lock);
}
T val = q.front();
q.pop();
return val;
}
template <typename T>
bool SafeQueue<T>::empty(void) {
return q.empty();
}

View File

@ -1,47 +1,32 @@
#ifndef SAFE_QUEUE #ifndef _SAFE_QUEUE_H_
#define SAFE_QUEUE #define _SAFE_QUEUE_H_
#include <queue> #include <queue>
#include <mutex> #include <mutex>
#include <condition_variable> #include <condition_variable>
// A threadsafe-queue.
template <class T>
class TestQueue
{
public:
TestQueue();
~TestQueue();
private:
std::queue<T> q;
};
// A threadsafe-queue. // A threadsafe-queue.
template <class T> template <class T>
class SafeQueue class SafeQueue
{ {
public: public:
SafeQueue(void) SafeQueue(void);
: q() ~SafeQueue(void);
, m()
, c()
{}
~SafeQueue(void)
{}
// Add an element to the queue.
void enqueue(T t)
{
std::lock_guard<std::mutex> lock(m);
q.push(t);
c.notify_one();
}
// Get the "front"-element.
// If the queue is empty, wait till a element is avaiable.
T dequeue(void)
{
std::unique_lock<std::mutex> lock(m);
while(q.empty())
{
// release lock as long as the wait and reaquire it afterwards.
c.wait(lock);
}
T val = q.front();
q.pop();
return val;
}
void enqueue(T);
T dequeue(void);
bool empty(void);
private: private:
std::queue<T> q; std::queue<T> q;
mutable std::mutex m; mutable std::mutex m;

View File

@ -0,0 +1,285 @@
#include "db_handle.h"
namespace db {
namespace query {
/* Query templates for HISTORY. */
//TODO: Move these definitions to .h file.
const std::string query_template_transaction = "INSERT INTO HISTORY(COIN, TYPE, USERID, QUANTITY, TIMESTAMP, COMPLETED, PRICE) "\
"VALUES('{}', {}, '{}', {}, {}, {}, {});";
const std::string query_template_history_ts = "SELECT * FROM HISTORY WHERE TIMESTAMP <= {} AND TIMESTAMP > {};";
const std::string query_template_userid_ts = "SELECT DISTINCT USERID FROM HISTORY WHERE TIMESTAMP <= {} AND TIMESTAMP > {};";
const std::string query_template_slope_ts_top = "SELECT PRICE, TIMESTAMP FROM HISTORY "\
"WHERE COIN = '{}' AND TIMESTAMP <= {} AND TIMESTAMP > {} "\
"ORDER BY TIMESTAMP ASC "\
"LIMIT 1;";
const std::string query_template_transactions_userid_ts = "SELECT * FROM HISTORY WHERE USERID = '{}' AND TIMESTAMP <= {} AND TIMESTAMP > {};";
const std::string query_template_slope_ts_bot = "SELECT PRICE, TIMESTAMP FROM HISTORY "\
"WHERE COIN = '{}' AND TIMESTAMP <= {} AND TIMESTAMP > {} "\
"ORDER BY TIMESTAMP DESC "\
"LIMIT 1;";
const std::string query_template_last_n_spaced_prices = "select PRICE, TIMESTAMP FROM last_n_spaced_prices('{}', {}, {});";
const std::string query_template_user = "INSERT INTO USERS(USERID, USERNAME, ICON, NETWORTH) "\
"VALUES('{}', E'{}', '{}', {}) "
"ON CONFLICT (USERID) DO UPDATE SET "\
"NETWORTH = {};";
const std::string query_template_userid_to_username = "select USERNAME FROM USERS WHERE USERID = '{}'";
/********************************************************************************
GLOBAL QUERIES
********************************************************************************/
std::string make_push_query_transaction( ws_msg_parsed<WS_EVENT_TRANSACTION> op ) {
return fmt::format(query_template_transaction,
op.coin,
op.type,
op.userid,
op.quantity,
op.timestamp,
op.completed,
op.price);
}
std::string make_pull_query_history_ts( long ts_high, long ts_low ) {
return fmt::format(query_template_history_ts, ts_high, ts_low);
}
std::string make_pull_query_userid_list_ts( long ts_high, long ts_low ) {
return fmt::format(query_template_userid_ts, ts_high, ts_low);
}
std::string make_pull_query_transactions_userid_ts( std::string userid, long ts_high, long ts_low ) {
return fmt::format(query_template_transactions_userid_ts, userid, ts_high, ts_low);
}
std::string make_pull_query_top_price_cycle_ts( std::string coin, long ts_high, long ts_low ) {
return fmt::format(query_template_slope_ts_top, coin, ts_high, ts_low);
}
std::string make_pull_query_bot_price_cycle_ts( std::string coin, long ts_high, long ts_low ) {
return fmt::format(query_template_slope_ts_bot, coin, ts_high, ts_low);
}
/* Query templates for COIN PRICE. */
const std::string query_template_coin_price = "INSERT INTO COINPRICE(COIN, PRICE, SALEVALUE, INCIRCULATION, LASTUPDATE) "\
"VALUES('{}', {}, {}, {}, {}) "\
"ON CONFLICT (COIN) DO UPDATE SET "\
"PRICE = {}, SALEVALUE = {}, INCIRCULATION = {}, LASTUPDATE = {};";
std::string make_push_query_coin_price( ws_msg_parsed<WS_EVENT_COIN_PRICE_UPDATE> op ) {
return fmt::format(query_template_coin_price,
op.coin,
op.price,
op.saleValue,
op.inCirculation,
std::time(NULL)*1000,
op.price,
op.saleValue,
op.inCirculation,
std::time(NULL)*1000);
}
/* Query templates for math functions. */
std::string make_pull_query_last_n_spaced_prices( std::string coin, int nb_cycles, int delta) {
return fmt::format(query_template_last_n_spaced_prices,
coin,
nb_cycles,
delta);
}
std::string make_push_query_user(user_t user){
return fmt::format(query_template_user,
user.userid,
user.username,
user.icon,
user.networth,
user.networth);
}
std::string make_pull_query_userid_to_username(std::string userid) {
return fmt::format(query_template_userid_to_username,
userid);
}
}
/********************************************************************************
HISTORY
********************************************************************************/
/* Add transactions contained in history update to the database. */
void push_history( pqxx::connection* C, ws_msg_parsed<WS_EVENT_HISTORY_UPDATE> op ) {
std::string query;
for(auto& element : op.transaction_list){
query += query::make_push_query_transaction(element);
}
/* Create a transactional object. */
pqxx::work W(*C);
/* Execute SQL query */
W.exec( query );
W.commit();
}
/* Returns the last cycle in form of a ws_msg_parsed<WS_EVENT_HISTORY_UPDATE> struct. */
ws_msg_parsed<WS_EVENT_HISTORY_UPDATE> pull_last_cycle(pqxx::connection* C) {
std::string query;
long ts_high, ts_low;
ws_msg_parsed<WS_EVENT_TRANSACTION> tmp;
ws_msg_parsed<WS_EVENT_HISTORY_UPDATE> rop;
ts_high = time(NULL)*1000;
ts_low = ts_high - 600*1000;
query = query::make_pull_query_history_ts(ts_high, ts_low);
/* Create a non-transactional object. */
pqxx::nontransaction N(*C);
/* Execute SQL query */
pqxx::result R( N.exec( query ));
/* Parse result. */
for (pqxx::result::const_iterator c = R.begin(); c != R.end(); ++c) {
tmp.coin = c[1].as<std::string>();
tmp.type = c[2].as<int>();
tmp.userid = c[3].as<std::string>();
tmp.quantity = c[4].as<int>();
tmp.timestamp = c[5].as<long>();
tmp.completed = c[6].as<bool>();
tmp.price = c[7].as<float>();
rop.transaction_list.push_back(tmp);
}
return rop;
}
/* Fetches unique user ids having transactions between ts_low and ts_high. */
std::vector<std::string> pull_userid_list_ts( pqxx::connection *C, long ts_high, long ts_low ) {
std::string query;
std::vector<std::string> rop;
query = query::make_pull_query_userid_list_ts(ts_high, ts_low);
/* Create a non-transactional object. */
pqxx::nontransaction N(*C);
/* Execute SQL query */
pqxx::result R( N.exec( query ));
/* Parse result. */
for (pqxx::result::const_iterator c = R.begin(); c != R.end(); ++c) {
rop.push_back(c[0].as<std::string>());
}
return rop;
}
/* Fetches all transactions by userid during period ts_low to ts_high. */
ws_msg_parsed<WS_EVENT_HISTORY_UPDATE> pull_transactions_userid_ts( pqxx::connection *C, std::string userid, long ts_high, long ts_low) {
std::string query;
ws_msg_parsed<WS_EVENT_TRANSACTION> tmp;
ws_msg_parsed<WS_EVENT_HISTORY_UPDATE> rop;
query = query::make_pull_query_transactions_userid_ts(userid, ts_high, ts_low);
/* Create a non-transactional object. */
pqxx::nontransaction N(*C);
/* Execute SQL query */
pqxx::result R( N.exec( query ));
/* Parse result. */
for (pqxx::result::const_iterator c = R.begin(); c != R.end(); ++c) {
tmp.coin = c[1].as<std::string>();
tmp.type = c[2].as<int>();
tmp.userid = c[3].as<std::string>();
tmp.quantity = c[4].as<int>();
tmp.timestamp = c[5].as<long>();
tmp.completed = c[6].as<bool>();
tmp.price = c[7].as<float>();
rop.transaction_list.push_back(tmp);
}
return rop;
}
/* Fetches last cycle's transactions for userid. */
ws_msg_parsed<WS_EVENT_HISTORY_UPDATE> pull_last_cycle_userid( pqxx::connection *C, std::string userid) {
long ts_high, ts_low;
ts_high = time(NULL)*1000;
ts_low = ts_high - 600*1000;
return pull_transactions_userid_ts(C, userid, ts_high, ts_low);
}
/********************************************************************************
COIN PRICE
********************************************************************************/
void push_coin_price( pqxx::connection* C, ws_msg_parsed<WS_EVENT_COIN_PRICE_UPDATE> op) {
std::string query;
query = query::make_push_query_coin_price(op);
/* Create a transactional object. */
pqxx::work W(*C);
/* Execute SQL query */
W.exec( query );
W.commit();
}
/********************************************************************************
USERS
********************************************************************************/
// TODO: goes into common or algo
void ReplaceAll(std::string &str, const std::string& from, const std::string& to) {
size_t start_pos = 0;
while((start_pos = str.find(from, start_pos)) != std::string::npos) {
str.replace(start_pos, from.length(), to);
start_pos += to.length(); // Handles case where 'to' is a substring of 'from'
}
}
void push_users( pqxx::connection* C, std::vector<user_t> op){
std::string query;
std::string tmp;
for(auto& user : op){
tmp = user.username;
ReplaceAll(tmp, "'", "\\'");
user.username = tmp;
query += query::make_push_query_user(user);
}
/* Create a transactional object. */
pqxx::work W(*C);
/* Execute SQL query */
W.exec( query );
W.commit();
}
std::string userid_to_username(pqxx::connection* C, std::string userid){
std::string query;
query = query::make_pull_query_userid_to_username(userid);
/* Create a non-transactional object. */
pqxx::nontransaction N(*C);
/* Execute SQL query */
pqxx::result R( N.exec( query ));
return (R.begin())[0].as<std::string>();
}
}

View File

@ -0,0 +1,50 @@
#ifndef _DB_HANDLE_H_
#define _DB_HANDLE_H_
#include <iostream>
#include <pqxx/pqxx>
#include <fmt/core.h>
#include <algorithm>
#include "../common/common.h"
/* DB API to store and fetch data. */
namespace db {
namespace query {
std::string make_pull_query_last_n_spaced_prices(std::string, int, int);
}
/********************************************************************************
HISTORY
********************************************************************************/
void push_history( pqxx::connection*, ws_msg_parsed<WS_EVENT_HISTORY_UPDATE> );
ws_msg_parsed<WS_EVENT_HISTORY_UPDATE> pull_last_cycle( pqxx::connection*);
std::vector<std::string> pull_userid_list_ts( pqxx::connection *, long, long);
ws_msg_parsed<WS_EVENT_HISTORY_UPDATE> pull_transactions_userid_ts( pqxx::connection *, std::string, long, long);
ws_msg_parsed<WS_EVENT_HISTORY_UPDATE> pull_last_cycle_userid( pqxx::connection *, std::string);
float pull_last_cycle_slope(pqxx::connection*, std::string);
/********************************************************************************
COIN PRICE
********************************************************************************/
void push_coin_price( pqxx::connection*, ws_msg_parsed<WS_EVENT_COIN_PRICE_UPDATE> );
/********************************************************************************
COIN PRICE
********************************************************************************/
std::string userid_to_username(pqxx::connection*, std::string userid);
/********************************************************************************
USERS
********************************************************************************/
void push_users( pqxx::connection*, std::vector<user_t> );
std::string userid_to_username(pqxx::connection*, std::string userid);
}
#endif

View File

@ -0,0 +1,157 @@
#include "db_init.h"
namespace db {
int create_table_history(pqxx::connection& C) {
std::string query;
try {
/* Create a transactional object. */
pqxx::work W(C);
/* Create sql query for history table creation */
query = "CREATE TABLE IF NOT EXISTS HISTORY(" \
"ID SERIAL PRIMARY KEY NOT NULL," \
"COIN CHAR(32) NOT NULL,"\
"TYPE INT,"\
"USERID CHAR(128) NOT NULL,"\
"QUANTITY INT,"\
"TIMESTAMP BIGINT NOT NULL,"\
"COMPLETED BOOLEAN,"\
"PRICE REAL);";
/* Execute SQL query */
W.exec( query );
W.commit();
} catch (const std::exception &e) {
std::cerr << e.what() << std::endl;
return 1;
}
return 0;
}
int create_table_coin_price(pqxx::connection& C) {
std::string query;
try {
/* Create a transactional object. */
pqxx::work W(C);
/* Create sql query for history table creation */
query = "CREATE TABLE IF NOT EXISTS COINPRICE(" \
"COIN CHAR(32) PRIMARY KEY,"\
"PRICE REAL," \
"SALEVALUE REAL," \
"INCIRCULATION INT, "\
"LASTUPDATE BIGINT);";
/* Execute SQL query */
W.exec( query );
W.commit();
} catch (const std::exception &e) {
std::cerr << e.what() << std::endl;
return 1;
}
return 0;
}
int create_last_n_anchor_prices_function(pqxx::connection& C) {
std::string query;
try {
/* Create a transactional object. */
pqxx::work W(C);
/* Create sql query for spaced prices function, delta is in seconds*/
query = "CREATE OR REPLACE FUNCTION last_n_spaced_prices(var_coin CHAR(32), var_n INT, var_delta INT) RETURNS SETOF HISTORY AS $$" \
"DECLARE "\
" row HISTORY%ROWTYPE; "\
" cur_date BIGINT = 9223372036854775806; "\
" nb_dates INT = 0; "\
" nb_dates_max INT = var_n; "\
"BEGIN "\
" FOR row IN "\
" SELECT * "\
" FROM HISTORY "\
" WHERE HISTORY.COIN = var_coin "\
" ORDER BY TIMESTAMP DESC "\
" LOOP "\
" IF nb_dates = nb_dates_max "\
" THEN "\
" EXIT; "\
" END IF; "\
" "\
" IF row.TIMESTAMP <= cur_date - var_delta*1000 OR cur_date IS NULL "\
" THEN "\
" cur_date := row.TIMESTAMP; "\
" nb_dates := nb_dates + 1; "\
" RETURN NEXT row; "\
" END IF; "\
" END LOOP; "\
"END; "\
"$$ LANGUAGE plpgsql; ";
/* Execute SQL query */
W.exec( query );
W.commit();
} catch (const std::exception &e) {
std::cerr << e.what() << std::endl;
return 1;
}
return 0;
}
int create_table_users(pqxx::connection& C) {
std::string query;
try {
/* Create a transactional object. */
pqxx::work W(C);
/* Create sql query for history table creation */
query = "CREATE TABLE IF NOT EXISTS USERS(" \
"USERID CHAR(128) PRIMARY KEY,"\
"USERNAME TEXT NOT NULL,"\
"ICON CHAR(32) NOT NULL,"\
"NETWORTH REAL);";
/* Execute SQL query */
W.exec( query );
W.commit();
} catch (const std::exception &e) {
std::cerr << e.what() << std::endl;
return 1;
}
return 0;
}
int populate() {
try {
pqxx::connection C("dbname = nasfaq user = steaky \
hostaddr = 127.0.0.1 port = 5432");
if (C.is_open()) {
std::cout << "Opened database successfully: " << C.dbname() << std::endl;
} else {
std::cout << "Can't open database" << std::endl;
return 1;
}
/* Create tables. */
create_table_history(C);
create_table_coin_price(C);
create_table_users(C);
/* Create functions. */
create_last_n_anchor_prices_function(C);
} catch (const std::exception &e) {
std::cerr << e.what() << std::endl;
return 1;
}
return 0;
}
}

View File

@ -0,0 +1,19 @@
#ifndef _DB_INIT_H_
#define _DB_INIT_H_
#include <iostream>
#include <pqxx/pqxx>
#include <fmt/core.h>
#include <ctime>
#include "../http/users.h"
namespace db {
int create_table_history(pqxx::connection&);
int create_table_coin_price(pqxx::connection&);
int create_table_users(pqxx::connection&);
int populate();
}
#endif

BIN
nasfaq/connections/test/graph Executable file

Binary file not shown.

View File

@ -0,0 +1,11 @@
#include <graphviz/gvc.h>
#include <graphviz/cgraph.h>
#include "../common/common.h"
#include "../../maths/graph.h"
int main(void) {
test();
return 1;
}

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,4 @@
g++ ../common/common.cpp \
../../maths/graph.cpp \
graph.cpp \
-L/usr/lib -lgvc -lcgraph -lfmt -lpqxx -lpq -o graph && ./graph

View File

@ -1,3 +0,0 @@
clang++ ../http/http_connector.cpp \
./main_http.cpp \
-o main_http -lcurl && ./main_http

Binary file not shown.

View File

@ -1,11 +1,95 @@
#include "../http/http_connector.h"
#include "../ws/my_ssl.h"
#include "../safe_queue/safe_queue.h"
#include "../parser/parser.h"
#include "../common/common.h" #include "../common/common.h"
#include "../http/http_connector.h"
#include "../http/users.h"
#include "../ws/http_handshake.h"
#include "../safe_queue/safe_queue.h"
#include "../ws/ssl_ws.h"
#include "../sql/db_init.h"
#include "../sql/db_handle.h"
#include "../parser/parser.h"
int connect_ws() {
bool done = false;
std::string input;
ws::websocket_endpoint endpoint;
/* Get session id */
std::string sid = ws::http_handshake::get_sid();
/* Start connection */
std::string uri = "wss://nasfaq.biz/socket/?user=314d0bda-d7f0-4636-aed7-5ea02743604b&EIO=4&transport=websocket&sid=" + sid;
int id = endpoint.connect(uri);
if(id != -1) {
std::cout << ">Created nasfaq websocket connection" << std::endl;
} else {
return -1;
}
sleep(1);
/* Display connection metadata */
ws::connection_metadata::ptr metadata = endpoint.get_metadata(id);
if (metadata) {
std::cout << *metadata << std::endl;
} else {
std::cout << ">Unknown connection id " << id << std::endl;
}
/* Populate database if needed. */
db::populate();
/* Open up database connection. */
pqxx::connection C("dbname = nasfaq user = steaky \
hostaddr = 127.0.0.1 port = 5432");
if (C.is_open()) {
std::cout << "Opened database successfully: " << C.dbname() << std::endl;
} else {
std::cout << "Can't open database" << std::endl;
return 1;
}
/* Update users. */
db::push_users(&C, users::get_users());
/* Set up parser */
parser::parser p(metadata, &C);
/* Loop and print data through parser*/
while(!done) {
input = std::cin.get();
if(input == "q" || input == "quit") {
done = true;
} else if (input == "p") {
std::cout << "PROCESSING QUEUE " << std::endl;
p.process_queue_start();
} else if (input == "s") {
std::cout << "STOPPING QUEUE PROCESSING" << std::endl;
p.process_queue_stop();
} else if (input == "t") {
std::cout << "TEST" << std::endl;
auto ret = db::pull_last_cycle(&C);
std::cout << ret << std::endl;
}
}
/* Close websocket */
std::stringstream ss(input);
std::string cmd;
int close_code = websocketpp::close::status::normal;
std::string reason;
ss >> cmd >> id >> close_code;
std::getline(ss, reason);
endpoint.close(id, close_code, reason);
return 0;
}
int main(void) { int main(void) {
std::string sid = get_sid(); connect_ws();
connect_ws(sid); return 1;
} }

Binary file not shown.

View File

@ -1,6 +0,0 @@
#include "../http/http_connector.h"
int main(void) {
get_sid();
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,60 @@
from pyvis.network import Network
import matplotlib.pyplot as plt
import networkx as nx
import pyvis
import json
THRESHOLD = 10
def make_net(N, json_path):
with open(json_path, 'r') as f:
data = json.load(f)
weighted_edges = []
for parent, element in data.items():
for child, weight in element.items():
if parent == child: pass
elif weight > THRESHOLD: pass
else:
weighted_edges.append((parent, child, round(weight, 1)))
# Add edges
N.add_weighted_edges_from(weighted_edges)
def nudge(pos, x_shift, y_shift):
return {n:(x + x_shift, y + y_shift) for n,(x,y) in pos.items()}
net = nx.Graph()
make_net(net, "graph.json")
pos = nx.circular_layout(net)
nx.draw_networkx(
net, pos, edge_color='black', width=1, linewidths=1,
node_size=100, node_color='pink', alpha=0.9,
with_labels = False)
#labels={node: node for node in net.nodes()}
edge_labels = dict([((n1, n2), net[n1][n2]['weight'])
for n1, n2 in net.edges])
#nx.draw_networkx_edge_labels(
# net, pos,
# edge_labels=edge_labels,
# font_color='red'
#)
pretty_net = Network(height='750px', width='100%', bgcolor='#222222', font_color='white')
pretty_net.barnes_hut()
pretty_net.from_nx(net)
pretty_net.show_buttons(filter_=['physics'])
pretty_net.show("graph.html")
#plt.axis('off')
#plt.show()

View File

@ -1,7 +1,11 @@
clang++ ../common/common.cpp \ g++ ../safe_queue/safe_queue.cpp \
../parser/parser.cpp \ ../common/common.cpp \
../safe_queue/safe_queue.cpp \
../http/http_connector.cpp \ ../http/http_connector.cpp \
../ws/my_ssl.cpp \ ../http/users.cpp \
../ws/ssl_ws.cpp \
../sql/db_init.cpp \
../sql/db_handle.cpp \
../parser/parser.cpp \
../ws/http_handshake.cpp \
./main.cpp \ ./main.cpp \
-o main -lcurl -lcrypto -lssl -lboost_system -lboost_random -lboost_thread -lpthread && ./main -o main -lpqxx -lpq -lfmt -lcurl -lcrypto -lssl -lboost_system -lboost_random -lboost_thread -lpthread && ./main

BIN
nasfaq/connections/test/sql Executable file

Binary file not shown.

View File

@ -0,0 +1,62 @@
#include "../common/common.h"
#include "../sql/db_init.h"
#include "../sql/db_handle.h"
#include "../../maths/maths.h"
#include "../../maths/graph.h"
int connect_db() {
bool done = false;
std::string input;
/* Populate database if needed. */
db::populate();
/* Open up database connection. */
pqxx::connection C("dbname = nasfaq user = steaky \
hostaddr = 127.0.0.1 port = 5432");
if (C.is_open()) {
std::cout << "Opened database successfully: " << C.dbname() << std::endl;
} else {
std::cout << "Can't open database" << std::endl;
return 1;
}
/* Loop and print data through parser*/
while(!done) {
input = std::cin.get();
if(input == "q" || input == "quit") {
done = true;
} else if (input == "t") {
std::string coin = "miko";
//float s = db::pull_last_cycle_slope(&C, coin);
float ws = optimizer::get_last_n_weighted_slope(&C, coin, 2, 600);
std::cout << "slope: " << ws << std::endl;
} else if (input == "d") {
long ts_low, ts_high;
float threshold;
std::vector<std::string> userids;
std::map<std::string, std::map<std::string, float>> result;
ts_high = time(NULL)*1000;
ts_low = ts_high - 600*1000;
threshold = 10;
userids = db::pull_userid_list_ts(&C, ts_high, ts_low);
result = norm::diff_map(&C, userids, ts_high, ts_low, threshold);
//make_graph_from_map(result);
norm::diff_save_json(&C, result);
}
}
return 0;
}
int main(void) {
connect_db();
return 1;
}

View File

@ -0,0 +1,7 @@
g++ ../common/common.cpp \
../sql/db_init.cpp \
../sql/db_handle.cpp \
../../maths/maths.cpp \
../../maths/graph.cpp \
sql.cpp \
-L/usr/lib -lgvc -lcgraph -lfmt -lpqxx -lpq -o sql && ./sql

View File

@ -0,0 +1,35 @@
#include "http_handshake.h"
namespace ws {
namespace http_handshake {
std::string get_sid() {
static const char *POLLING_URL_0 = "https://nasfaq.biz/socket/?EIO=4&transport=polling&t=Ny7z439";
static const char *POLLING_URL_1 = "https://nasfaq.biz/socket/?user=314d0bda-d7f0-4636-aed7-5ea02743604b&EIO=4&transport=polling&t=Ny7z472";
static const char *POLLING_URL_2 = "https://nasfaq.biz/socket/?user=314d0bda-d7f0-4636-aed7-5ea02743604b&EIO=4&transport=polling&t=Ny7z4Bn&sid=";
static const char *POLLING_URL_3 = "https://nasfaq.biz/socket/?user=314d0bda-d7f0-4636-aed7-5ea02743604b&EIO=4&transport=polling&t=Ny7z4Bp&sid=";
static const char *POLLING_URL_4 = "https://nasfaq.biz/socket/?user=314d0bda-d7f0-4636-aed7-5ea02743604b&EIO=4&transport=polling&t=Ny7z4EU&sid=";
nlohmann::json json_ret;
std::string sid;
nsfq_http::http_connector::connector c;
/* Start handshake, first result is discarded. */
c.get(POLLING_URL_0);
c.get(POLLING_URL_1);
/* Get session id for websocket. */
json_ret = nlohmann::json::parse(c.get_buffer().substr(1));
sid = json_ret["sid"];
/* Post "40" acknowledgement with sid. */
c.post(POLLING_URL_2 + sid, "40");
/* Continue handshake (might be unneeded). See XHR trace. */
//c.get(POLLING_URL_3 + sid);
//c.get(POLLING_URL_4 + sid);
return sid;
}
}
}

View File

@ -0,0 +1,19 @@
#ifndef _HTTP_HANDSHAKE_H_
#define _HTTP_HANDSHAKE_H_
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <curl/curl.h>
#include <nlohmann/json.hpp>
#include "../http/http_connector.h"
namespace ws {
namespace http_handshake {
std::string get_sid();
}
}
#endif

View File

@ -1,334 +0,0 @@
#include "my_ssl.h"
typedef websocketpp::client<websocketpp::config::asio_tls_client> client;
typedef std::shared_ptr<boost::asio::ssl::context> context_ptr;
class connection_metadata {
public:
typedef websocketpp::lib::shared_ptr<connection_metadata> ptr;
connection_metadata(client *endpoint, int id, websocketpp::connection_hdl hdl, std::string uri)
: m_id(id)
, m_hdl(hdl)
, m_status("Connecting")
, m_uri(uri)
, m_server("N/A")
, m_endpoint(endpoint) // I really hate this, maybe the whole send function altogether should be in this class?
{}
void on_open(client *c, websocketpp::connection_hdl hdl) {
websocketpp::lib::error_code ec;
m_status = "Open";
client::connection_ptr con = c->get_con_from_hdl(hdl);
m_server = con->get_response_header("Server");
sleep(1); /* How to wait for status? */
m_endpoint->send(m_hdl, "2probe", websocketpp::frame::opcode::text, ec);
if (ec) {
std::cout << "> Error sending 2probe: " << ec.message() << std::endl;
return;
}
sleep(1); /* How to wait for status? */
m_endpoint->send(m_hdl, "5", websocketpp::frame::opcode::text, ec);
if (ec) {
std::cout << "> Error sending 5: " << ec.message() << std::endl;
return;
}
}
void on_fail(client *c, websocketpp::connection_hdl hdl) {
m_status = "Failed";
client::connection_ptr con = c->get_con_from_hdl(hdl);
m_server = con->get_response_header("Server");
m_error_reason = con->get_ec().message();
}
void on_close(client *c, websocketpp::connection_hdl hdl) {
m_status = "Closed";
client::connection_ptr con = c->get_con_from_hdl(hdl);
std::stringstream s;
s << "close code: " << con->get_remote_close_code() << " ("
<< websocketpp::close::status::get_string(con->get_remote_close_code())
<< "), close reason: " << con->get_remote_close_reason();
m_error_reason = s.str();
}
void on_message(websocketpp::connection_hdl hdl, client::message_ptr msg) {
if (msg->get_opcode() == websocketpp::frame::opcode::text) {
std::string payload = msg->get_payload();
if (payload == "2") {
websocketpp::lib::error_code ec;
m_endpoint->send(m_hdl, "3", websocketpp::frame::opcode::text, ec);
if (ec) {
std::cout << "> Error sending pong 3: " << ec.message() << std::endl;
return;
}
} else if (payload.substr(0, 2) == "42") {
/* Add message to a raw struct and pass to parser */
raw_message_t rmsg; /* should be cached somewhere? */
rmsg.type = msg_type_detect(payload.substr(2, 20)); /* Get message type, this should be out of this loop and encompassing the pongs and probes */
rmsg.data = payload.substr(3, payload.length() - 1); /* Should use regex */
std::cout << "Got payload of type: " << rmsg.type << std::endl;
//nlohmann::json jres = nlohmann::json::parse(payload.substr(21, payload.length()-21-1));
m_messages.push_back(payload);
}
}
}
websocketpp::connection_hdl get_hdl() const {
return m_hdl;
}
int get_id() const {
return m_id;
}
std::string get_status() const {
return m_status;
}
friend std::ostream & operator<< (std::ostream & out, connection_metadata const & data);
void record_sent_message(std::string message) {
m_messages.push_back(">> " + message);
}
private:
int m_id;
websocketpp::connection_hdl m_hdl;
std::string m_status;
std::string m_uri;
std::string m_server;
std::string m_error_reason;
std::vector<std::string> m_messages;
client *m_endpoint;
};
std::ostream & operator<< (std::ostream & out, connection_metadata const & data) {
out
<< "> URI: " << data.m_uri << "\n"
<< "> Status: " << data.m_status << "\n"
<< "> Remote Server: " << (data.m_server.empty() ? "None Specified" : data.m_server) << "\n"
<< "> Error/close reason: " << (data.m_error_reason.empty() ? "N/A" : data.m_error_reason);
std::vector<std::string>::const_iterator it;
for (it = data.m_messages.begin(); it != data.m_messages.end(); ++it) {
out << *it << "\n";
}
return out;
}
static context_ptr on_tls_init() {
// establishes a SSL connection
context_ptr ctx = std::make_shared<boost::asio::ssl::context>(boost::asio::ssl::context::sslv23);
try {
ctx->set_options(boost::asio::ssl::context::default_workarounds |
boost::asio::ssl::context::no_sslv2 |
boost::asio::ssl::context::no_sslv3 |
boost::asio::ssl::context::single_dh_use);
} catch (std::exception &e) {
std::cout << "Error in context pointer: " << e.what() << std::endl;
}
return ctx;
}
class websocket_endpoint {
public:
websocket_endpoint() {
m_endpoint.clear_access_channels(websocketpp::log::alevel::all);
m_endpoint.clear_error_channels(websocketpp::log::elevel::all);
m_endpoint.init_asio();
m_endpoint.set_tls_init_handler(bind(&on_tls_init));
m_endpoint.start_perpetual();
m_thread.reset(new websocketpp::lib::thread(&client::run, &m_endpoint));
}
~websocket_endpoint() {
m_endpoint.stop_perpetual();
for (con_list::const_iterator it = m_connection_list.begin(); it != m_connection_list.end(); ++it) {
if (it->second->get_status() != "Open") {
// Close only open connections
continue;
}
std::cout << "> Closing connection " << it->second->get_id() << std::endl;
websocketpp::lib::error_code ec;
m_endpoint.close(it->second->get_hdl(), websocketpp::close::status::going_away, "", ec);
if (ec) {
std::cout << "> Error closing connection " << it->second->get_id() << ": "
<< ec.message() << std::endl;
}
}
}
int connect(std::string const &uri) {
websocketpp::lib::error_code ec;
client::connection_ptr con = m_endpoint.get_connection(uri, ec);
con->append_header("Cookie", "holosesh=s%3AxmS8xBlQk4kH_rXQOaNjHk_3OuaBDsfA.M0yi%2BZmkiq%2BAmJBRj%2FNg9S%2BaSQpsfHRJcEeYVHLiKXg");
if(ec) {
std::cout << ">Connect initialization error: " << ec.message() << std::endl;
return -1;
}
int new_id = m_next_id++;
connection_metadata::ptr metadata_ptr(new connection_metadata(&m_endpoint, new_id, con->get_handle(), uri));
m_connection_list[new_id] = metadata_ptr;
con->set_open_handler(websocketpp::lib::bind(
&connection_metadata::on_open,
metadata_ptr,
&m_endpoint,
websocketpp::lib::placeholders::_1
));
con->set_fail_handler(websocketpp::lib::bind(
&connection_metadata::on_fail,
metadata_ptr,
&m_endpoint,
websocketpp::lib::placeholders::_1
));
con->set_message_handler(websocketpp::lib::bind(
&connection_metadata::on_message,
metadata_ptr,
websocketpp::lib::placeholders::_1,
websocketpp::lib::placeholders::_2
));
m_endpoint.connect(con);
return new_id;
}
void close(int id, websocketpp::close::status::value code, std::string reason) {
websocketpp::lib::error_code ec;
con_list::iterator metadata_it = m_connection_list.find(id);
if (metadata_it == m_connection_list.end()) {
std::cout << "> No connection found with id " << id << std::endl;
return;
}
m_endpoint.close(metadata_it->second->get_hdl(), code, "", ec);
if (ec) {
std::cout << "> Error initiating close: " << ec.message() << std::endl;
}
}
void send(int id, std::string message) {
websocketpp::lib::error_code ec;
con_list::iterator metadata_it = m_connection_list.find(id);
if (metadata_it == m_connection_list.end()) {
std::cout << "> No connection found with id " << id << std::endl;
return;
}
m_endpoint.send(metadata_it->second->get_hdl(), message, websocketpp::frame::opcode::text, ec);
if (ec) {
std::cout << "> Error sending message: " << ec.message() << std::endl;
return;
}
metadata_it->second->record_sent_message(message);
}
connection_metadata::ptr get_metadata(int id) const {
con_list::const_iterator metadata_it = m_connection_list.find(id);
if(metadata_it == m_connection_list.end()) {
return connection_metadata::ptr();
} else {
return metadata_it->second;
}
}
private:
typedef std::map<int, connection_metadata::ptr> con_list;
client m_endpoint;
websocketpp::lib::shared_ptr<websocketpp::lib::thread> m_thread;
con_list m_connection_list;
int m_next_id;
};
int connect_ws(std::string sid) {
bool done = false;
std::string input;
websocket_endpoint endpoint;
while(!done) {
std::cout << "Enter command: ";
std::getline(std::cin, input);
if(input == "quit" || input == "q" ) done = true;
else if(input == "help") {
std::cout
<< "\nCommand List:\n"
<< "help: Display this help text\n"
<< "quit: Exit the program\n"
<< std::endl;
} else if (input.substr(0, 3) == "nsf") {
std::string uri = "wss://nasfaq.biz/socket/?user=314d0bda-d7f0-4636-aed7-5ea02743604b&EIO=4&transport=websocket&sid=" + sid;
int id = endpoint.connect(uri);
if(id != -1) {
std::cout << ">Created nsf connection with id " << id << std::endl;
}
} else if (input.substr(0, 7) == "connect") {
int id = endpoint.connect(input.substr(8));
if(id != -1) {
std::cout << ">Created connection with id " << id << std::endl;
}
} else if (input.substr(0,4) == "show") {
int id = atoi(input.substr(5).c_str());
connection_metadata::ptr metadata = endpoint.get_metadata(id);
if (metadata) {
std::cout << *metadata << std::endl;
} else {
std::cout << ">Unknown connection id " << id << std::endl;
}
} else if (input.substr(0, 5) == "close") {
std::stringstream ss(input);
std::string cmd;
int id;
int close_code = websocketpp::close::status::normal;
std::string reason;
ss >> cmd >> id >> close_code;
std::getline(ss, reason);
endpoint.close(id, close_code, reason);
} else if (input.substr(0,4) == "send") {
std::stringstream ss(input);
std::string cmd;
int id;
std::string message = "";
ss >> cmd >> id;
std::getline(ss,message);
endpoint.send(id, message);
} else {
std::cout << "Unrecognized command" << std::endl;
}
}
return 0;
}

View File

@ -0,0 +1,273 @@
#include "ssl_ws.h"
// TODO: rewrite this in the header
namespace ws {
connection_metadata::connection_metadata(client *endpoint, int id, websocketpp::connection_hdl hdl, std::string uri)
: m_id(id)
, m_hdl(hdl)
, m_status("Connecting")
, m_uri(uri)
, m_server("N/A")
, m_endpoint(endpoint) // I really hate this, maybe the whole send function altogether should be in this class?
{}
void connection_metadata::on_open(client *c, websocketpp::connection_hdl hdl) {
websocketpp::lib::error_code ec;
m_status = "Open";
client::connection_ptr con = c->get_con_from_hdl(hdl);
m_server = con->get_response_header("Server");
sleep(1); /* How to wait for status? */
m_endpoint->send(m_hdl, "2probe", websocketpp::frame::opcode::text, ec);
if (ec) {
std::cout << "> Error sending 2probe: " << ec.message() << std::endl;
return;
}
sleep(1); /* How to wait for status? */
m_endpoint->send(m_hdl, "5", websocketpp::frame::opcode::text, ec);
if (ec) {
std::cout << "> Error sending 5: " << ec.message() << std::endl;
return;
}
}
void connection_metadata::on_fail(client *c, websocketpp::connection_hdl hdl) {
m_status = "Failed";
client::connection_ptr con = c->get_con_from_hdl(hdl);
m_server = con->get_response_header("Server");
m_error_reason = con->get_ec().message();
}
void connection_metadata::on_close(client *c, websocketpp::connection_hdl hdl) {
m_status = "Closed";
client::connection_ptr con = c->get_con_from_hdl(hdl);
std::stringstream s;
s << "close code: " << con->get_remote_close_code() << " ("
<< websocketpp::close::status::get_string(con->get_remote_close_code())
<< "), close reason: " << con->get_remote_close_reason();
m_error_reason = s.str();
}
void connection_metadata::on_message(websocketpp::connection_hdl hdl, client::message_ptr msg) {
if (msg->get_opcode() == websocketpp::frame::opcode::text) {
std::string payload = msg->get_payload();
if (payload == "2") {
websocketpp::lib::error_code ec;
m_endpoint->send(m_hdl, "3", websocketpp::frame::opcode::text, ec);
if (ec) {
std::cout << "> Error sending pong 3: " << ec.message() << std::endl;
return;
}
} else if (payload.substr(0, 2) == "42") {
std::string payload_format = payload.substr(3, payload.length() - 4);
push_message(payload_format);
}
}
}
websocketpp::connection_hdl connection_metadata::get_hdl() const {
return m_hdl;
}
int connection_metadata::get_id() const {
return m_id;
}
std::string connection_metadata::get_status() const {
return m_status;
}
/**
Should it use the cdt variable?
If it doesn't lock this thread up maybe, otherwise it should be defined externally.
Isn't the connection in another thread anyways?
*/
bool connection_metadata::msg_queue_empty(void) {
return m_msg_q.empty();
}
std::string connection_metadata::pop_message(void) {
std::unique_lock<std::mutex> lock(m_msg_q_mutex);
while(m_msg_q.empty())
{
// release lock as long as the wait and reaquire it afterwards.
m_msg_q_cdt.wait(lock);
}
std::string ret = m_msg_q.front();
m_msg_q.pop();
return ret;
}
void connection_metadata::push_message(std::string msg) {
std::lock_guard<std::mutex> lock(m_msg_q_mutex);
m_msg_q.push(msg);
m_msg_q_cdt.notify_one();
}
std::ostream & operator<< (std::ostream & out, connection_metadata const & data) {
out
<< "> URI: " << data.m_uri << "\n"
<< "> Status: " << data.m_status << "\n"
<< "> Remote Server: " << (data.m_server.empty() ? "None Specified" : data.m_server) << "\n"
<< "> Error/close reason: " << (data.m_error_reason.empty() ? "N/A" : data.m_error_reason);
return out;
}
/*******************************************************************************************
Connection endpoint
*******************************************************************************************/
/**
TLS initialization.
*/
static context_ptr on_tls_init() {
// establishes a SSL connection
context_ptr ctx = std::make_shared<boost::asio::ssl::context>(boost::asio::ssl::context::sslv23);
try {
ctx->set_options(boost::asio::ssl::context::default_workarounds |
boost::asio::ssl::context::no_sslv2 |
boost::asio::ssl::context::no_sslv3 |
boost::asio::ssl::context::single_dh_use);
} catch (std::exception &e) {
std::cout << "Error in context pointer: " << e.what() << std::endl;
}
return ctx;
}
websocket_endpoint::websocket_endpoint() {
m_endpoint.clear_access_channels(websocketpp::log::alevel::all);
m_endpoint.clear_error_channels(websocketpp::log::elevel::all);
m_endpoint.init_asio();
m_endpoint.set_tls_init_handler(bind(&on_tls_init));
m_endpoint.start_perpetual();
m_thread.reset(new websocketpp::lib::thread(&client::run, &m_endpoint));
}
websocket_endpoint::~websocket_endpoint() {
m_endpoint.stop_perpetual();
for (con_list::const_iterator it = m_connection_list.begin(); it != m_connection_list.end(); ++it) {
if (it->second->get_status() != "Open") {
// Close only open connections
continue;
}
std::cout << "> Closing connection " << it->second->get_id() << std::endl;
websocketpp::lib::error_code ec;
m_endpoint.close(it->second->get_hdl(), websocketpp::close::status::going_away, "", ec);
if (ec) {
std::cout << "> Error closing connection " << it->second->get_id() << ": "
<< ec.message() << std::endl;
}
}
}
int websocket_endpoint::connect(std::string const &uri) {
websocketpp::lib::error_code ec;
client::connection_ptr con = m_endpoint.get_connection(uri, ec);
con->append_header("Cookie", "holosesh=s%3AxmS8xBlQk4kH_rXQOaNjHk_3OuaBDsfA.M0yi%2BZmkiq%2BAmJBRj%2FNg9S%2BaSQpsfHRJcEeYVHLiKXg");
if(ec) {
std::cout << ">Connect initialization error: " << ec.message() << std::endl;
return -1;
}
int new_id = m_next_id++;
connection_metadata::ptr metadata_ptr(new connection_metadata(&m_endpoint, new_id, con->get_handle(), uri));
m_connection_list[new_id] = metadata_ptr;
con->set_open_handler(websocketpp::lib::bind(
&connection_metadata::on_open,
metadata_ptr,
&m_endpoint,
websocketpp::lib::placeholders::_1
));
con->set_fail_handler(websocketpp::lib::bind(
&connection_metadata::on_fail,
metadata_ptr,
&m_endpoint,
websocketpp::lib::placeholders::_1
));
con->set_message_handler(websocketpp::lib::bind(
&connection_metadata::on_message,
metadata_ptr,
websocketpp::lib::placeholders::_1,
websocketpp::lib::placeholders::_2
));
m_endpoint.connect(con);
return new_id;
}
void websocket_endpoint::close(int id, websocketpp::close::status::value code, std::string reason) {
websocketpp::lib::error_code ec;
con_list::iterator metadata_it = m_connection_list.find(id);
if (metadata_it == m_connection_list.end()) {
std::cout << "> No connection found with id " << id << std::endl;
return;
}
m_endpoint.close(metadata_it->second->get_hdl(), code, "", ec);
if (ec) {
std::cout << "> Error initiating close: " << ec.message() << std::endl;
}
}
void websocket_endpoint::send(int id, std::string message) {
websocketpp::lib::error_code ec;
con_list::iterator metadata_it = m_connection_list.find(id);
if (metadata_it == m_connection_list.end()) {
std::cout << "> No connection found with id " << id << std::endl;
return;
}
m_endpoint.send(metadata_it->second->get_hdl(), message, websocketpp::frame::opcode::text, ec);
if (ec) {
std::cout << "> Error sending message: " << ec.message() << std::endl;
return;
}
// metadata_it->second->record_sent_message(message);
}
connection_metadata::ptr websocket_endpoint::get_metadata(int id) const {
con_list::const_iterator metadata_it = m_connection_list.find(id);
if(metadata_it == m_connection_list.end()) {
return connection_metadata::ptr();
} else {
return metadata_it->second;
}
}
std::string websocket_endpoint::get_queue_front(int id) const {
con_list::const_iterator metadata_it = m_connection_list.find(id);
if(metadata_it == m_connection_list.end()) {
return "";
} else {
return metadata_it->second->pop_message();
}
}
}

View File

@ -0,0 +1,82 @@
#ifndef _SSL_WS_H_
#define _SSL_WS_H_
#include <iostream>
#include <string>
#include <stdlib.h>
//#include "../parser/parser.h"
#include "../common/common.h"
#include "../safe_queue/safe_queue.h"
#include <websocketpp/config/asio_client.hpp>
#include <websocketpp/client.hpp>
#include <websocketpp/common/thread.hpp>
#include <websocketpp/common/memory.hpp>
#include <nlohmann/json.hpp>
namespace ws {
typedef websocketpp::client<websocketpp::config::asio_tls_client> client;
typedef std::shared_ptr<boost::asio::ssl::context> context_ptr;
class connection_metadata {
public:
typedef websocketpp::lib::shared_ptr<connection_metadata> ptr;
connection_metadata(client*, int, websocketpp::connection_hdl, std::string);
void on_open(client *, websocketpp::connection_hdl);
void on_fail(client *, websocketpp::connection_hdl);
void on_close(client *, websocketpp::connection_hdl);
void on_message(websocketpp::connection_hdl, client::message_ptr);
websocketpp::connection_hdl get_hdl() const;
int get_id() const;
std::string get_status() const;
friend std::ostream & operator<< (std::ostream &, connection_metadata const &);
bool msg_queue_empty(void);
std::string pop_message(void);
private:
int m_id;
websocketpp::connection_hdl m_hdl;
std::string m_status;
std::string m_uri;
std::string m_server;
std::string m_error_reason;
//std::vector<std::string> m_messages;
client *m_endpoint;
std::queue<std::string> m_msg_q;
mutable std::mutex m_msg_q_mutex;
std::condition_variable m_msg_q_cdt;
void push_message(std::string);
};
class websocket_endpoint {
public:
websocket_endpoint();
~websocket_endpoint();
int connect(std::string const &);
void close(int, websocketpp::close::status::value, std::string);
void send(int, std::string);
connection_metadata::ptr get_metadata(int) const;
std::string get_queue_front(int) const;
private:
typedef std::map<int, connection_metadata::ptr> con_list;
client m_endpoint;
websocketpp::lib::shared_ptr<websocketpp::lib::thread> m_thread;
con_list m_connection_list;
int m_next_id;
};
}
#endif

55
nasfaq/maths/graph.cpp Normal file
View File

@ -0,0 +1,55 @@
#include "graph.h"
//template <typename T>
void make_graph_from_map(std::map<std::string, std::map<std::string, float>> op) {
#ifndef NO_LAYOUT_OR_RENDERING
// set up a graphviz context - but only once even for multiple graphs
GVC_t *gvc = gvContext();
#endif
// Create a simple digraph
Agraph_t *g = agopen("g", Agundirected, 0);
// Placeholders
Agnode_t *parent;
Agnode_t *child;
char float_buffer[64];
// Add vertices and edges
for (auto& userid1_map:op) {
parent = agnode(g, (char *)(userid1_map.first).c_str(), 1);
agsafeset(parent, "label", (char *)(userid1_map.first).c_str(), "");
std::cout << "Parent: " << userid1_map.first << std::endl;
for (auto& element:userid1_map.second) {
child = agnode(g, (char *)(element.first).c_str(), 1);
agsafeset(parent, "label", (char *)(element.first).c_str(), "");
//std::cout << " Child: " << element.first << " Dist: " << element.second << std::endl;
Agedge_t *e = agedge(g, parent, child, 0, 1);
// Convert float to char*
snprintf(float_buffer, sizeof(float_buffer), "%f", element.second);
agsafeset(e, "label", float_buffer, "");
}
}
// Set an attribute - in this case one that affects the visible rendering
//agsafeset(n, "color", "red", "");
#ifdef NO_LAYOUT_OR_RENDERING
// Just write the graph without layout
agwrite(g, savefile);
#else
// Use the directed graph layout engine
gvLayout(gvc, g, "dot");
// Output in .dot format
FILE *fptr = fopen("graph.dot", "w");
gvRender(gvc, g, "dot", fptr);
fclose(fptr);
gvFreeLayout(gvc, g);
#endif
agclose(g);
}

18
nasfaq/maths/graph.h Normal file
View File

@ -0,0 +1,18 @@
#ifndef _GRAPH_H_
#define _GRAPH_H_
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <fstream>
#include "../connections/common/common.h"
#include <graphviz/gvc.h>
#include <graphviz/cgraph.h>
//template <typename T>
void make_graph_from_map(std::map<std::string, std::map<std::string, float>>);
#endif

199
nasfaq/maths/maths.cpp Normal file
View File

@ -0,0 +1,199 @@
#include "maths.h"
namespace query {
const std::string query_template_slope_ts_bot = "SELECT PRICE, TIMESTAMP FROM HISTORY "\
"WHERE COIN = '{}' AND TIMESTAMP <= {} AND TIMESTAMP > {} "\
"ORDER BY TIMESTAMP DESC "\
"LIMIT 1;";
const std::string query_template_last_n_spaced_prices = "select PRICE, TIMESTAMP FROM last_n_spaced_prices('{}', {}, {});";
}
namespace norm {
float norm(cycle_t c) {
float rop = 0;
for (auto const & element : c) {
rop += pow(element.second, 2);
}
return sqrt(rop);
}
/* Should balance with weights. */
cycle_t history_to_cycle(ws_msg_parsed<WS_EVENT_HISTORY_UPDATE> op) {
cycle_t rop;
for(auto const& element : op.transaction_list) {
rop[element.coin] = element.quantity * pow((-1), element.type);
}
return rop;
}
cycle_t diff_vector(cycle_t op1, cycle_t op2) {
cycle_t rop;
rop = op1;
for(auto const& element : op2) {
if (op1.count(element.first)) {
rop[element.first] -= element.second;
} else {
rop[element.first] = -element.second;
}
}
return rop;
}
int cycle_size(cycle_t op) {
int rop = 0;
for (auto const & element : op) {
rop += std::abs(element.second);
}
return rop;
}
std::map<std::string, float> diff_all(pqxx::connection *C, cycle_t base_cycle, std::map<std::string, cycle_t> cycles, std::vector<std::string> userid_list, std::string userid, long ts_high, long ts_low, float threshold) {
std::map<std::string, float> result;
cycle_t tmp1, tmp2;
float tmp_res;
for(auto const& id : userid_list) {
tmp2 = cycles.find(id)->second;
if (cycle_size(tmp2) >= 10) {
tmp_res = norm(diff_vector(tmp1, tmp2));
if (tmp_res < threshold) {
result[id] = tmp_res;
std::cout << "Difference between " << userid << " and " << id << " : " << result[id] << std::endl;
}
}
}
return result;
}
std::map<std::string, std::map<std::string, float>> diff_map(pqxx::connection *C, std::vector<std::string> userids, long ts_high, long ts_low, float threshold){
std::map<std::string, std::map<std::string, float>> result;
std::map<std::string, cycle_t> cycles;
std::map<std::string, float> tmp;
/* Prepare cycles from db. */
for(auto const& id : userids) {
cycles.insert( std::pair<std::string, cycle_t>(id, history_to_cycle(db::pull_last_cycle_userid(C, id))) );
}
for (auto& userid:userids) {
tmp = norm::diff_all(C, cycles[userid], cycles, userids, userid, ts_high, ts_low, threshold);
result.insert( std::pair<std::string, std::map<std::string, float>>( userid, tmp ));
}
return result;
}
void diff_save_json( pqxx::connection *C, std::map<std::string, std::map<std::string, float>> op) {
json j;
std::string parent, child;
for (auto& userid1_map:op) {
parent = db::userid_to_username(C, userid1_map.first);
for (auto& element:userid1_map.second) {
child = db::userid_to_username(C, element.first);
j[parent][child] = element.second;
}
}
std::ofstream o("graph.json");
o << std::setw(4) << j << std::endl;
}
}
namespace optimizer{
std::tuple<long, long> get_last_nth_cycle_ts(int n) {
long ts_now, ts_top, ts_bot;
ts_now = time(NULL);
ts_top = (ts_now - ts_now % 600) - n * 600; // floor (top) - n cycles
ts_bot = ts_top - (n+1) * 600;
return std::make_tuple(ts_top * 1000, ts_bot * 1000);
}
///* Returns slope over last cycle. */
//float pull_last_cycle_slope(pqxx::connection* C, std::string coin) {
// std::string query;
// float price_top, price_bot, delta_p;
// float ts_top, ts_bot, delta_t;
// float slope;
// pqxx::nontransaction N(*C);
// pqxx::result::const_iterator c;
// pqxx::result R;
// auto [ts_high, ts_low] = optimizer::get_last_nth_cycle_ts(1);
// //ts_high = time(NULL)*1000;
// //ts_low = ts_high - 600*1000;
// query = db::query::make_pull_query_top_price_cycle_ts(coin, ts_high, ts_low);
// R = N.exec( query );
// c = R.begin();
// price_top = c[0].as<float>();
// ts_top = c[1].as<float>();
// query = db::query::make_pull_query_bot_price_cycle_ts(coin, ts_high, ts_low);
// R = N.exec( query );
// c = R.begin();
// price_bot = c[0].as<float>();
// ts_bot = c[1].as<float>();
// slope = (price_top - price_bot) / ( (ts_top - ts_bot) ) * 1000 * 600;
// std::cout << "pt: " << price_top << " pb: " << price_bot << std::endl;
// std::cout << "tt: " << ts_top << " tb: " << ts_bot << std::endl;
// return slope;
//}
float get_last_n_weighted_slope(pqxx::connection* C, std::string coin, int nb_cycles, int delta = 600) {
std::string query;
float wma, tmp_slope, price_top, price_bot;
double ts_top, ts_bot;
int weight, denum;
query = db::query::make_pull_query_last_n_spaced_prices(coin, nb_cycles, delta);
/* Create a non-transactional object. */
pqxx::nontransaction N(*C);
/* Execute SQL query */
pqxx::result R( N.exec( query ));
/* Parse result. */
price_top = R[0][0].as<float>();
price_bot = R[1][0].as<float>();
ts_top = R[0][1].as<double>();
ts_bot = R[1][1].as<double>();
tmp_slope = (price_top - price_bot) / (ts_top - ts_bot);
weight = nb_cycles;
wma = weight * tmp_slope;
denum = weight;
for (pqxx::result::const_iterator c = R.begin() + 1; c != R.end(); ++c) {
price_bot = price_top;
ts_bot = ts_top;
price_top = c[0].as<float>();
ts_top = c[1].as<double>();
weight--;
tmp_slope = (price_top - price_bot) / (ts_top - ts_bot);
wma += weight * tmp_slope;
denum += weight;
}
return wma / denum * 1000 * 600;
}
}

28
nasfaq/maths/maths.h Normal file
View File

@ -0,0 +1,28 @@
#ifndef _MATHS_H_
#define _MATHS_H_
#include <cmath>
#include <fstream>
#include <tuple>
#include <nlohmann/json.hpp>
using json = nlohmann::json;
#include "../connections/common/common.h"
#include "../connections/sql/db_handle.h"
namespace norm {
float norm(cycle_t);
cycle_t history_to_cycle(ws_msg_parsed<WS_EVENT_HISTORY_UPDATE>);
cycle_t diff_vector(cycle_t, cycle_t);
std::map<std::string, float> diff_all(pqxx::connection *C, cycle_t base_cycle, std::map<std::string, cycle_t> cycles, std::vector<std::string> userid_list, std::string userid, long ts_high, long ts_low, float threshold);
std::map<std::string, std::map<std::string, float>> diff_map(pqxx::connection *C, std::vector<std::string> userid_list, long, long, float);
void diff_save_json( pqxx::connection *, std::map<std::string, std::map<std::string, float>>);
}
namespace optimizer{
std::tuple<long, long> get_last_nth_cycle_ts(int);
float get_last_n_weighted_slope(pqxx::connection*, std::string, int, int);
}
#endif

View File

@ -0,0 +1,7 @@
import json
USERID = "314d0bda-d7f0-4636-aed7-5ea02743604b"
URL_API = "https://nasfaq.biz/api/"
COINS = ['aki', 'amelia', 'aqua', 'ayame', 'azki', 'botan', 'calliope', 'choco', 'civia', 'coco', 'flare', 'fubuki', 'gura', 'haato', 'himemoriluna', 'hololive', 'inanis', 'iofi', 'kanata', 'kiara', 'korone', 'lamy', 'marine', 'matsuri', 'mel', 'melfissa', 'miko', 'mio', 'moona', 'nana', 'nene', 'noel', 'okayu', 'ollie', 'pekora', 'polka', 'reine', 'risu', 'roboco', 'rushia', 'shion', 'sora', 'subaru', 'suisei', 'towa', 'ui', 'watame', 'laplus', 'lui', 'koyori', 'chloe', 'iroha', 'irys', 'sana', 'fauna', 'kronii', 'mumei', 'baelz']

View File

@ -0,0 +1,47 @@
import psycopg2
from common import *
def get_db_connection():
return psycopg2.connect(database="nasfaq", user = "steaky", host = "127.0.0.1", port = "5432")
def fetch_wma_slope_all(cursor):
slope_dict = {}
nb_cycles = 2
delta = 600
for coin in COINS:
tmp = 0
weight = nb_cycles
wma = 0
denum = 0
query = "select PRICE, TIMESTAMP FROM last_n_spaced_prices('{}', {}, {});".format(coin, nb_cycles, delta)
cursor.execute(query)
rows = cursor.fetchall()
price_top = float(rows[0][0])
price_bot = float(rows[1][0])
ts_top = int(rows[0][1])
ts_bot = int(rows[1][1])
tmp = (price_top - price_bot) / (ts_top - ts_bot)
wma = weight * tmp
denum = weight
for row in rows[1::]:
price_bot = price_top
price_top = row[0]
ts_bot = ts_top
ts_top = row[1]
weight -= 1
tmp = (price_top - price_bot) / (ts_top - ts_bot)
wma += weight * tmp
denum += weight
slope_dict[coin] = wma / denum * 1000 * 600
return slope_dict

View File

@ -0,0 +1,24 @@
from common import *
import requests
def fetch_marketInfo_all():
url = URL_API + "getMarketInfo?all"
r = requests.get(url)
return r.json()['coinInfo']['data']
def fetch_coin_qty_all():
rop = {}
url = URL_API + "getUserWallet?userid=" + USERID
r = requests.get(url)
for key, item in r.json()['wallet']['coins'].items():
rop[key] = item['amt']
return rop
def fetch_balance():
url = URL_API + "getUserWallet?userid=" + USERID
r = requests.get(url)
return r.json()['wallet']['balance']

View File

@ -0,0 +1,46 @@
import random
from common import *
from optimizer import *
from db_handle import *
from http_handle import *
if __name__ == '__main__':
C = get_db_connection()
cur = C.cursor()
user_balance = fetch_balance()
coin_qty = fetch_coin_qty_all()
coin_prices = fetch_marketInfo_all()
wma_coins = fetch_wma_slope_all(cur)
#wma_coins = {coin:20 for coin in coin_prices.keys() }
# Cut down for test
u = 0
max_u = 10
smp_prices = {}
smp_wma = {}
#coins = ["lamy", "towa", "luna", "marine", "subaru", "aqua", "hololive"]
for key in coin_prices.keys():
if u > max_u: break
else:
try:
a = wma_coins[key]
if abs(a) > 10:
smp_prices[key] = coin_prices[key]
smp_wma[key] = wma_coins[key]
u += 1
except KeyError:
pass
print("Coins prices: ")
print(smp_prices)
print("Coins wma: ")
print(smp_wma)
M = 10
nb_cycles = 144
sol = optimize(smp_wma, smp_prices, nb_cycles, M)
print(sol)

View File

@ -0,0 +1,138 @@
#import numpy as np
#import itertools
#import json
#import math
#import collections
from common import *
import matplotlib
import matplotlib.pyplot as plt
from scipy.optimize import minimize
from gekko import GEKKO
"""
Gekko function.
Function to minimize
"""
def to_optimize(x, S, a, nb_cycles, M, m):
local_gain = 0
t = m.if2(a, -1, 1) # type of trade
tax = m.if2(a, 0.035, 0.045) # type of tax
for i in range(1, M):
mult = m.if2( x[0] - t*i, 0, x[0] - t*i)
delta = x[i+1] - x[i]
local_gain += t*mult*delta*( (S+a*nb_cycles) - (S+a*(x[i] + x[i+1] + 1)/2)*(1+t*tax*mult))
return -local_gain # We minimize the opposite function
"""
GEKKO optimizer
"""
def optimize(wma_coins, coin_prices, nb_cycles, M):
nb_rows, nb_cols = len(wma_coins.keys()), M
# Transform dict to lists
coin_prices_list = [coin_prices[coin]["price"] for coin in coin_prices.keys()]
wma_coins_list = [wma_coins[coin] for coin in coin_prices.keys()]
m = GEKKO(remote=False)
x = m.Array(m.Var, (nb_rows, nb_cols + 1), lb=0, ub=144, integer=True) # Lower bound is 0: no order, upper bound is 10: hyper-multicoining
# Set multicoin bounds
for i in range(nb_rows):
x[i][0].value = 0
x[i][0].lower = -10
x[i][0].upper = 10
# constraints on cycles
for i in range(nb_rows):
for j in range(1, nb_cols):
m.Equation(x[i][j] <= x[i][j+1])
# EQUATIONS
for i in range(nb_rows):
m.Obj(to_optimize(x[i], coin_prices_list[i], wma_coins_list[i], nb_cycles, M, m))
m.options.SOLVER=3
m.options.IMODE = 3
m.options.COLDSTART=1
#m.solver_options = ['maximum_iterations 10000']
#m.Minimize(to_optimize(x, nb_rows, nb_cols, coin_prices_list, wma_coins_list, nb_cycles, m))
m.solve(disp=True)
return x
#def save_result(res):
#
# print(res)
# d = dict()
# for i in range(len(L)):
# d[L[i]] = round(int(res[i].value[0]))
#
#
# with open(PATH_OUT, "w") as f:
# json.dump(d, f)
def display_strategy(x):
s = {}
m = -1
index = 0
toprint = ""
for i in range(len(x)):
if x[i] != m:
toprint = "[Change@" + str(i) + "\t:x" + str(int(x[i])) + "]"
m = x[i]
s[i] = x[i]
print(toprint)
return s
def plot_results(x, s):
fig, ax = plt.subplots()
M = len(x)
X = [i for i in range(M)]
# Naive Strategies to plot
n_strats = [i for i in range(1, 5)]
# Plot the straight strategies
for n in n_strats:
xx = [n for _ in range(M)]
Y = [to_optimize_(xx, m) for m in X]
ax.scatter(X, Y, marker = "+", label = "Constant x{}".format(n))
# Plot optimized strategy
Y = [to_optimize_(x, m) for m in X]
ax.scatter(X, Y, marker = "^", label = "Optimized")
for cycle, n in s.items():
ax.annotate("x{}".format(int(n)), textcoords = "offset pixels", xytext = (0, 10), xy = (X[cycle], Y[cycle]))
# Display parameters
textstr = '\n'.join((
r'Coin price at adjustment: {}'.format(S),
r'Tax baseline: {}'.format(T),
r'Slope extrapolation: {}'.format(a),
r'Number of cycles: {}'.format(M)))
props = dict(boxstyle='round', facecolor='white', alpha=0.5)
# place a text box in upper left in axes coords
ax.text(0.12, 0.98, textstr, transform=ax.transAxes, fontsize=14,
verticalalignment='top', bbox=props)
#ax.set_yscale("log")
#ax.set_xscale("log")
ax.legend(loc="upper left")
ax.set_xlabel("Cycle")
ax.set_ylabel("Profit")
ax.set_title("Profit using naive and optimized strategies")
ax.grid(True)
plt.show()

View File

@ -0,0 +1,38 @@
#include "optimizer.h"
namespace operations_research {
void BasicExample() {
// Create the linear solver with the GLOP backend.
std::unique_ptr<MPSolver> solver(MPSolver::CreateSolver("SCIP"));
if (!solver) {
LOG(WARNING) << "SCIP solver unavailable.";
return;
}
// Create the variables x and y.
MPVariable* const x = solver->MakeIntVar(0.0, 1, "x");
MPVariable* const y = solver->MakeIntVar(0.0, 2, "y");
LOG(INFO) << "Number of variables = " << solver->NumVariables();
// Create a linear constraint, 0 <= x + y <= 2.
MPConstraint* const ct = solver->MakeRowConstraint(0.0, 2.0, "ct");
ct->SetCoefficient(x, 1);
ct->SetCoefficient(y, 1);
LOG(INFO) << "Number of constraints = " << solver->NumConstraints();
// Create the objective function, 3 * x + y.
MPObjective* const objective = solver->MutableObjective();
objective->SetCoefficient(x, 3);
objective->SetCoefficient(y, 1);
objective->SetMaximization();
solver->Solve();
LOG(INFO) << "Solution:" << std::endl;
LOG(INFO) << "Objective value = " << objective->Value();
LOG(INFO) << "x = " << x->solution_value();
LOG(INFO) << "y = " << y->solution_value();
}
} // namespace operations_research

View File

@ -0,0 +1,11 @@
#ifndef _OPTIMIZER_H_
#define _OPTIMIZER_H_
#include "ortools/linear_solver/linear_solver.h"
namespace operations_research {
void BasicExample();
}
#endif

View File

@ -0,0 +1,7 @@
import json
USERID = "314d0bda-d7f0-4636-aed7-5ea02743604b"
URL_API = "https://nasfaq.biz/api/"
COINS = ['aki', 'amelia', 'aqua', 'ayame', 'azki', 'botan', 'calliope', 'choco', 'civia', 'coco', 'flare', 'fubuki', 'gura', 'haato', 'himemoriluna', 'hololive', 'inanis', 'iofi', 'kanata', 'kiara', 'korone', 'lamy', 'marine', 'matsuri', 'mel', 'melfissa', 'miko', 'mio', 'moona', 'nana', 'nene', 'noel', 'okayu', 'ollie', 'pekora', 'polka', 'reine', 'risu', 'roboco', 'rushia', 'shion', 'sora', 'subaru', 'suisei', 'towa', 'ui', 'watame', 'laplus', 'lui', 'koyori', 'chloe', 'iroha', 'irys', 'sana', 'fauna', 'kronii', 'mumei', 'baelz']

View File

@ -0,0 +1,47 @@
import psycopg2
from common import *
def get_db_connection():
return psycopg2.connect(database="nasfaq", user = "steaky", host = "127.0.0.1", port = "5432")
def fetch_wma_slope_all(cursor):
slope_dict = {}
nb_cycles = 2
delta = 600
for coin in COINS:
tmp = 0
weight = nb_cycles
wma = 0
denum = 0
query = "select PRICE, TIMESTAMP FROM last_n_spaced_prices('{}', {}, {});".format(coin, nb_cycles, delta)
cursor.execute(query)
rows = cursor.fetchall()
price_top = float(rows[0][0])
price_bot = float(rows[1][0])
ts_top = int(rows[0][1])
ts_bot = int(rows[1][1])
tmp = (price_top - price_bot) / (ts_top - ts_bot)
wma = weight * tmp
denum = weight
for row in rows[1::]:
price_bot = price_top
price_top = row[0]
ts_bot = ts_top
ts_top = row[1]
weight -= 1
tmp = (price_top - price_bot) / (ts_top - ts_bot)
wma += weight * tmp
denum += weight
slope_dict[coin] = wma / denum * 1000 * 600
return slope_dict

View File

@ -0,0 +1,24 @@
from common import *
import requests
def fetch_marketInfo_all():
url = URL_API + "getMarketInfo?all"
r = requests.get(url)
return r.json()['coinInfo']['data']
def fetch_coin_qty_all():
rop = {}
url = URL_API + "getUserWallet?userid=" + USERID
r = requests.get(url)
for key, item in r.json()['wallet']['coins'].items():
rop[key] = item['amt']
return rop
def fetch_balance():
url = URL_API + "getUserWallet?userid=" + USERID
r = requests.get(url)
return r.json()['wallet']['balance']

View File

@ -0,0 +1,42 @@
from common import *
from optimizer import *
from db_handle import *
from http_handle import *
if __name__ == '__main__':
C = get_db_connection()
cur = C.cursor()
user_balance = fetch_balance()
coin_qty = fetch_coin_qty_all()
coin_prices = fetch_marketInfo_all()
wma_coins = fetch_wma_slope_all(cur)
#wma_coins = {coin:20 for coin in coin_prices.keys() }
# Cut down for test
u = 0
max_u = 10
smp_prices = {}
smp_wma = {}
#coins = ["lamy", "towa", "luna", "marine", "subaru", "aqua", "hololive"]
for key in coin_prices.keys():
if u > max_u: break
else:
try:
a = wma_coins[key]
if abs(a) > 10:
smp_prices[key] = coin_prices[key]
smp_wma[key] = wma_coins[key]
u += 1
except KeyError:
pass
print("Coins prices: ")
print(smp_prices)
print("Coins wma: ")
print(smp_wma)
M = 144
sol = optimize_all(smp_wma, smp_prices, M)
save_strategy_all(sol, smp_wma, smp_prices, M)

View File

@ -0,0 +1,164 @@
#import numpy as np
#import itertools
#import json
#import math
#import collections
import matplotlib
import matplotlib.pyplot as plt
from scipy.optimize import minimize
from gekko import GEKKO
"""
Global Parameters
S: Stock price at adjustment
T: Tax baseline
a: Slope
M: Number of cycles (maximum of 24*6 = 144)
"""
"""
Function to minimize
This one is for python
"""
def to_optimize_(x, S, a, M, m):
res = 0
t = -1 if a<0 else 1
tax = 0.035 if a <0 else 0.045
for i in range(m): #Ineffective when plotting (O(m^2))
res += t*x[i]*( a*(M - (i+1)) - x[i]*tax*t*(S + a*i))
return res # We minimize the opposite function
"""
Gekko function.
Function to minimize
"""
def to_optimize(x, S, a, M, m):
res = 0
t = m.if2(a, -1, 1) # type of trade
tax = m.if2(a, 0.035, 0.045) # type of tax
for i in range(M):
res += t*x[i]*( a*(M - (i+1)) - x[i]*t*tax*(S + a*i))
return -res # We minimize the opposite function
"""
GEKKO optimizer
"""
def optimize_all(wma, prices, M):
result = {}
for coin in prices.keys():
try:
m = GEKKO(remote=False)
x = m.Array(m.Var, M, lb=0, ub=10, integer=True)
m.options.SOLVER=1
m.options.IMODE = 3
m.options.COLDSTART=1
m.solver_options = ['maximum_iterations 10000']
m.Minimize(to_optimize(x, prices[coin]["price"] , wma[coin], M, m))
m.solve(disp=True)
result[coin] = [y.value[0] for y in x]
except Exception as e:
pass
return result
#def save_result(res):
#
# print(res)
# d = dict()
# for i in range(len(L)):
# d[L[i]] = round(int(res[i].value[0]))
#
#
# with open(PATH_OUT, "w") as f:
# json.dump(d, f)
def display_strategy(x):
s = {}
m = -1
index = 0
toprint = ""
for i in range(len(x)):
if x[i] != m:
toprint = "[Change@" + str(i) + "\t:x" + str(int(x[i])) + "]"
m = x[i]
s[i] = x[i]
print(toprint)
return s
def plot_results(x, S, T, a, M, s, coin, save_path = None):
fig, ax = plt.subplots(figsize=(20, 10))
M = len(x)
X = [i for i in range(M)]
# Naive Strategies to plot
n_strats = [i for i in range(1, 5)]
# Plot the straight strategies
for n in n_strats:
xx = [n for _ in range(M)]
Y = [to_optimize_(xx, S, a, M, m) for m in X]
ax.scatter(X, Y, marker = "+", label = "Constant x{}".format(n))
# Plot optimized strategy
Y = [to_optimize_(x, S, a, M, m) for m in X]
ax.scatter(X, Y, marker = "^", label = "Optimized")
for cycle, n in s.items():
ax.annotate("x{}".format(int(n)), textcoords = "offset pixels", xytext = (0, 10), xy = (X[cycle], Y[cycle]))
# Display parameters
textstr = '\n'.join((
r'Coin price: {}'.format(S),
r'Tax baseline: {}'.format(T),
r'Slope extrapolation: {}'.format(round(a, 2)),
r'Number of cycles: {}'.format(M)))
props = dict(boxstyle='round', facecolor='white', alpha=0.5)
# place a text box in upper left in axes coords
ax.text(0.12, 0.98, textstr, transform=ax.transAxes, fontsize=14,
verticalalignment='top', bbox=props)
#ax.set_yscale("log")
#ax.set_xscale("log")
ax.legend(loc="upper left")
ax.set_xlabel("Cycle")
ax.set_ylabel("Profit")
ax.set_title("[{}] Profit for naive and optimized strategies".format(coin))
ax.grid(True)
if save_path != None:
plt.savefig(save_path, dpi=200)
else:
plt.show()
def save_strategy_all(x, wma, prices, M):
for coin in x.keys():
try:
T = 0.045 if wma[coin] > 0 else 0.035
s = display_strategy(x[coin])
plot_results(x[coin], prices[coin]["price"], T, wma[coin], M, s, coin, save_path = "res/" + str(coin) + ".png")
except e:
pass
#def main():
# #x = [3 for _ in range(M)]
# #res = to_optimize(x, 0)
# #print(res)
# res = optimize()
# res_ = [x.value[0] for x in res]
# print("Net profit with strategy x: ", to_optimize_(res_, M))
# print("Strategy vector:")
# s = display_strategy(res_)
# plot_results(res_, s)
#
#if __name__ == "__main__":
# main()

View File

@ -0,0 +1,147 @@
#import numpy as np
#import itertools
#import json
#import math
#import collections
import matplotlib
import matplotlib.pyplot as plt
from scipy.optimize import minimize
from gekko import GEKKO
"""
Global Parameters
S: Stock price at adjustment
T: Tax baseline
a: Slope
M: Number of cycles (maximum of 24*6 = 144)
"""
S = 11360
T = 0.045
a = 20
M = 144
"""
Function to minimize
This one is for python
"""
def to_optimize_(x, m):
global S, T, M
res = 0
for i in range(m): #Ineffective when plotting (O(m^2))
res += x[i]*( a*(M - (i+1)) - x[i]*T*(S + a*i))
return res # We minimize the opposite function
"""
Gekko function.
Function to minimize
"""
def to_optimize(x, m):
global S, T
res = 0
for i in range(M):
res += x[i]*( a*(M - (i+1)) - x[i]*T*(S + a*i))
return -res # We minimize the opposite function
"""
GEKKO optimizer
"""
def optimize():
global L, T
m = GEKKO(remote=False)
x = m.Array(m.Var, M, lb=0, ub=10, integer=True) # Lower bound is 0: no order, upper bound is 10: hyper-multicoining
m.options.SOLVER=1
m.options.IMODE = 3
m.options.COLDSTART=1
m.solver_options = ['maximum_iterations 10000']
m.Minimize(to_optimize(x, m))
m.solve(disp=True)
return x
#def save_result(res):
#
# print(res)
# d = dict()
# for i in range(len(L)):
# d[L[i]] = round(int(res[i].value[0]))
#
#
# with open(PATH_OUT, "w") as f:
# json.dump(d, f)
def display_strategy(x):
s = {}
m = -1
index = 0
toprint = ""
for i in range(len(x)):
if x[i] != m:
toprint = "[Change@" + str(i) + "\t:x" + str(int(x[i])) + "]"
m = x[i]
s[i] = x[i]
print(toprint)
return s
def plot_results(x, s):
fig, ax = plt.subplots()
M = len(x)
X = [i for i in range(M)]
# Naive Strategies to plot
n_strats = [i for i in range(1, 5)]
# Plot the straight strategies
for n in n_strats:
xx = [n for _ in range(M)]
Y = [to_optimize_(xx, m) for m in X]
ax.scatter(X, Y, marker = "+", label = "Constant x{}".format(n))
# Plot optimized strategy
Y = [to_optimize_(x, m) for m in X]
ax.scatter(X, Y, marker = "^", label = "Optimized")
for cycle, n in s.items():
ax.annotate("x{}".format(int(n)), textcoords = "offset pixels", xytext = (0, 10), xy = (X[cycle], Y[cycle]))
# Display parameters
textstr = '\n'.join((
r'Coin price at adjustment: {}'.format(S),
r'Tax baseline: {}'.format(T),
r'Slope extrapolation: {}'.format(a),
r'Number of cycles: {}'.format(M)))
props = dict(boxstyle='round', facecolor='white', alpha=0.5)
# place a text box in upper left in axes coords
ax.text(0.12, 0.98, textstr, transform=ax.transAxes, fontsize=14,
verticalalignment='top', bbox=props)
#ax.set_yscale("log")
#ax.set_xscale("log")
ax.legend(loc="upper left")
ax.set_xlabel("Cycle")
ax.set_ylabel("Profit")
ax.set_title("Profit using naive and optimized strategies")
ax.grid(True)
plt.show()
def main():
#x = [3 for _ in range(M)]
#res = to_optimize(x, 0)
#print(res)
res = optimize()
res_ = [x.value[0] for x in res]
print("Net profit with strategy x: ", to_optimize_(res_, M))
print("Strategy vector:")
s = display_strategy(res_)
plot_results(res_, s)
if __name__ == "__main__":
main()

View File

@ -0,0 +1,51 @@
import json
import math
import matplotlib.pyplot as plt
font = {'family' : 'normal',
'size' : 18}
plt.rc('font', **font)
DIR = "./files/"
FILENAME = "timings.json"
EXTENSION_DEGREE = [1, 1, 1, 1, 1, 1, 1, 1, 1,
3, 3,
4, 4,
5, 5, 5,
7, 7, 7,
8,
9, 9]
with open(DIR+FILENAME) as f:
timings = json.load(f)
x = [int(l) for l in timings.keys()]
y = [timings[str(l)] for l in x]
x_rad = x[0:3]
y_rad = y[0:3]
x_velu = x[3:]
y_velu = y[3:]
fig, ax = plt.subplots()
ax.scatter(x_rad, y_rad, marker = "2", label = "Radical isogeny")
ax.scatter(x_velu, y_velu, marker = "^", label = "Sqrt-Velu")
ax.set_yscale("log")
ax.set_xscale("log")
for i, txt in enumerate(x_rad):
ax.annotate(" " + str(txt) + " [{}] {}".format(EXTENSION_DEGREE[:3][i], math.floor(math.log(x_rad[i])/math.log(2))), (x_rad[i], y_rad[i]))
for i, txt in enumerate(x_velu):
ax.annotate(" " + str(txt) + " [{}] {}".format(EXTENSION_DEGREE[3:][i], math.floor(math.log(x_velu[i])/math.log(2))), (x_velu[i], y_velu[i]))
ax.legend(loc="upper left")
ax.set_xlabel("l (log)")
ax.set_ylabel("Average step time in seconds (log)")
ax.set_title("Timings for the l-primes")
ax.grid(True)
plt.show()

Binary file not shown.

After

Width:  |  Height:  |  Size: 190 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 191 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 177 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 173 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 211 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 192 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 208 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 214 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 195 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 178 KiB

Binary file not shown.

@ -1 +0,0 @@
Subproject commit 1088642db8abbcf9f034bab61f2496864235c042

BIN
nasfaq/tests/optimizer Executable file

Binary file not shown.

3
nasfaq/tests/optimizer.sh Executable file
View File

@ -0,0 +1,3 @@
g++ ../maths/optimizer/optimizer.cpp \
optimizer_main.cpp \
-lortools -o optimizer && ./optimizer

View File

@ -0,0 +1,8 @@
#include "../maths/optimizer/optimizer.h"
int main() {
operations_research::BasicExample();
return EXIT_SUCCESS;
return 1;
}

Some files were not shown because too many files have changed in this diff Show More