First commit to gitea
11
nasfaq/connections/api/api.cpp
Normal 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;
|
||||||
|
}
|
@ -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
|
||||||
|
|
9
nasfaq/connections/client/client.cpp
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
#include "client.h"
|
||||||
|
|
||||||
|
namespace proxy {
|
||||||
|
client::client(void) {
|
||||||
|
m_q = SafeQueue<std::string>;
|
||||||
|
m_endpoint =
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
24
nasfaq/connections/client/client.h
Normal 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
|
||||||
|
|
@ -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;
|
||||||
|
}
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
13
nasfaq/connections/common/ws_msg.def
Normal 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)
|
@ -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;
|
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
28
nasfaq/connections/http/users.cpp
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
19
nasfaq/connections/http/users.h
Normal 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
|
||||||
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
@ -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();
|
||||||
|
}
|
||||||
|
@ -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;
|
||||||
|
285
nasfaq/connections/sql/db_handle.cpp
Normal 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>();
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
50
nasfaq/connections/sql/db_handle.h
Normal 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
|
||||||
|
|
157
nasfaq/connections/sql/db_init.cpp
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
19
nasfaq/connections/sql/db_init.h
Normal 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
11
nasfaq/connections/test/graph.cpp
Normal 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;
|
||||||
|
}
|
227
nasfaq/connections/test/graph.html
Normal file
3335
nasfaq/connections/test/graph.json
Normal file
4
nasfaq/connections/test/graph_run.sh
Executable 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
|
@ -1,3 +0,0 @@
|
|||||||
clang++ ../http/http_connector.cpp \
|
|
||||||
./main_http.cpp \
|
|
||||||
-o main_http -lcurl && ./main_http
|
|
@ -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;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,6 +0,0 @@
|
|||||||
#include "../http/http_connector.h"
|
|
||||||
|
|
||||||
int main(void) {
|
|
||||||
get_sid();
|
|
||||||
|
|
||||||
}
|
|
BIN
nasfaq/connections/test/output-[00.02.150-00.06.266].webm
Normal file
BIN
nasfaq/connections/test/output.mp4
Normal file
BIN
nasfaq/connections/test/output_2.mp4
Normal file
BIN
nasfaq/connections/test/output_trim.mp4
Normal file
60
nasfaq/connections/test/parseGraph.py
Normal 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()
|
@ -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
62
nasfaq/connections/test/sql.cpp
Normal 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;
|
||||||
|
}
|
7
nasfaq/connections/test/sql_run.sh
Executable 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
|
35
nasfaq/connections/ws/http_handshake.cpp
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
19
nasfaq/connections/ws/http_handshake.h
Normal 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
|
||||||
|
|
@ -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;
|
|
||||||
}
|
|
273
nasfaq/connections/ws/ssl_ws.cpp
Normal 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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
82
nasfaq/connections/ws/ssl_ws.h
Normal 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
@ -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
@ -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
@ -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
@ -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
|
||||||
|
|
BIN
nasfaq/maths/optimizer/__pycache__/common.cpython-310.pyc
Normal file
BIN
nasfaq/maths/optimizer/__pycache__/db_handle.cpython-310.pyc
Normal file
BIN
nasfaq/maths/optimizer/__pycache__/http_handle.cpython-310.pyc
Normal file
BIN
nasfaq/maths/optimizer/__pycache__/optimizer.cpython-310.pyc
Normal file
7
nasfaq/maths/optimizer/common.py
Normal 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']
|
47
nasfaq/maths/optimizer/db_handle.py
Normal 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
|
24
nasfaq/maths/optimizer/http_handle.py
Normal 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']
|
46
nasfaq/maths/optimizer/main.py
Normal 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)
|
138
nasfaq/maths/optimizer/optimizer.py
Normal 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()
|
38
nasfaq/maths/optimizer/trash/optimizer.cpp
Normal 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
|
11
nasfaq/maths/optimizer/trash/optimizer.h
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
#ifndef _OPTIMIZER_H_
|
||||||
|
#define _OPTIMIZER_H_
|
||||||
|
|
||||||
|
#include "ortools/linear_solver/linear_solver.h"
|
||||||
|
|
||||||
|
namespace operations_research {
|
||||||
|
void BasicExample();
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
BIN
nasfaq/maths/strategy/__pycache__/common.cpython-310.pyc
Normal file
BIN
nasfaq/maths/strategy/__pycache__/db_handle.cpython-310.pyc
Normal file
BIN
nasfaq/maths/strategy/__pycache__/http_handle.cpython-310.pyc
Normal file
BIN
nasfaq/maths/strategy/__pycache__/optimizer.cpython-310.pyc
Normal file
7
nasfaq/maths/strategy/common.py
Normal 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']
|
47
nasfaq/maths/strategy/db_handle.py
Normal 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
|
24
nasfaq/maths/strategy/http_handle.py
Normal 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']
|
42
nasfaq/maths/strategy/main.py
Normal 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)
|
164
nasfaq/maths/strategy/optimizer.py
Normal 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()
|
147
nasfaq/maths/strategy/original.py
Normal 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()
|
51
nasfaq/maths/strategy/plot.py
Normal 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()
|
BIN
nasfaq/maths/strategy/res/aki.png
Normal file
After Width: | Height: | Size: 190 KiB |
BIN
nasfaq/maths/strategy/res/aqua.png
Normal file
After Width: | Height: | Size: 191 KiB |
BIN
nasfaq/maths/strategy/res/baelz.png
Normal file
After Width: | Height: | Size: 177 KiB |
BIN
nasfaq/maths/strategy/res/botan.png
Normal file
After Width: | Height: | Size: 173 KiB |
BIN
nasfaq/maths/strategy/res/calliope.png
Normal file
After Width: | Height: | Size: 211 KiB |
BIN
nasfaq/maths/strategy/res/chloe.png
Normal file
After Width: | Height: | Size: 192 KiB |
BIN
nasfaq/maths/strategy/res/choco.png
Normal file
After Width: | Height: | Size: 208 KiB |
BIN
nasfaq/maths/strategy/res/coco.png
Normal file
After Width: | Height: | Size: 214 KiB |
BIN
nasfaq/maths/strategy/res/gura.png
Normal file
After Width: | Height: | Size: 195 KiB |
BIN
nasfaq/maths/strategy/res/haato.png
Normal file
After Width: | Height: | Size: 178 KiB |
BIN
nasfaq/maths/strategy/res/res.pdf
Normal file
@ -1 +0,0 @@
|
|||||||
Subproject commit 1088642db8abbcf9f034bab61f2496864235c042
|
|
BIN
nasfaq/tests/optimizer
Executable file
3
nasfaq/tests/optimizer.sh
Executable file
@ -0,0 +1,3 @@
|
|||||||
|
g++ ../maths/optimizer/optimizer.cpp \
|
||||||
|
optimizer_main.cpp \
|
||||||
|
-lortools -o optimizer && ./optimizer
|
8
nasfaq/tests/optimizer_main.cpp
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
#include "../maths/optimizer/optimizer.h"
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
operations_research::BasicExample();
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|