229 lines
5.8 KiB
C++
229 lines
5.8 KiB
C++
#include "maths.h"
|
|
|
|
#define DIFF_ALL_MIN_CYCLE_SIZE 0
|
|
|
|
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,
|
|
long ts_high,
|
|
long ts_low,
|
|
float threshold){
|
|
|
|
std::map<std::string, float> result;
|
|
std::string tmp_uid;
|
|
cycle_t tmp_c;
|
|
float tmp_f;
|
|
|
|
for(std::map<std::string,cycle_t>::iterator iter = cycles.begin(); iter != cycles.end(); ++iter) {
|
|
tmp_uid = iter->first;
|
|
tmp_c = iter->second;
|
|
tmp_f = norm(diff_vector(base_cycle, tmp_c));
|
|
|
|
if(tmp_f && tmp_f < threshold){
|
|
result.insert(std::pair<std::string, float>(tmp_uid, tmp_f));
|
|
}
|
|
}
|
|
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;
|
|
cycle_t tmp_c;
|
|
int c_size;
|
|
unsigned int pos;
|
|
std::string userid;
|
|
|
|
/* Prepare cycles from db. */
|
|
pos = 0;
|
|
for(auto const& userid:userids) {
|
|
tmp_c = history_to_cycle(db::pull_last_cycle_userid(C, userid));
|
|
c_size = cycle_size(tmp_c);
|
|
|
|
/* Only keep players with large cycles */
|
|
if (c_size >= DIFF_ALL_MIN_CYCLE_SIZE) {
|
|
cycles.insert(std::pair<std::string, cycle_t>(userid, tmp_c));
|
|
}
|
|
pos++;
|
|
}
|
|
|
|
/* Compute norms and diffs */
|
|
for(std::map<std::string,cycle_t>::iterator iter = cycles.begin(); iter != cycles.end(); ++iter) {
|
|
userid = iter->first;
|
|
tmp = norm::diff_all(C, cycles[userid], cycles, 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;
|
|
}
|
|
}
|