Skip to content

Instantly share code, notes, and snippets.

@msnorth
Created December 6, 2013 18:41
Show Gist options
  • Save msnorth/040e9a69ed1e22aad1ac to your computer and use it in GitHub Desktop.
Save msnorth/040e9a69ed1e22aad1ac to your computer and use it in GitHub Desktop.
A BitCoin arbitrage bot using a parallelized Bellman-Ford graph algorithm
#include<iostream>
#include <fstream>
#include <stdlib.h> /* atol */
#include <list>
#include <stack>
#include <limits.h>
#include <omp.h>
#include <curl/curl.h>
#include <sstream>
#include <math.h>
#include <jsoncpp/json.h>
using namespace std;
class list_node {
int v;
double weight;
public:
list_node(int _v, double _w) {
v = _v;
weight = _w;
}
int get_vertex() {
return v;
}
double get_weight() {
return weight;
}
};
class graph {
int V; // No. of vertices'
// Pointer to an array containing adjacency lists
list<list_node> *adj;
public:
graph(int V); // Constructor
// function to add an edge to graph
void add_edge(int u, int v, double weight);
int bellman_ford(int src, double* dist, int* pre);
};
graph::graph(int V) {
this->V = V;
adj = new list<list_node>[V];
}
void graph::add_edge(int u, int v, double weight) {
list_node node(v, weight);
adj[u].push_back(node);
}
int graph::bellman_ford(int src, double* dist, int* pre) {
for (int i = 0; i < V; i++) {
dist[i] = INT_MAX;
pre[i] = -1;
}
dist[src] = 0;
int relaxed = 0;
clock_t startTime1 = clock();
#define CHUNKSIZE 1 /*defines the chunk size as 1 contiguous iteration*/
/*forks off the threads*/
#pragma omp parallel private(i)
{
/*Starts the work sharing construct*/
#pragma omp for schedule(dynamic, CHUNKSIZE)
clock_t startTime2 = clock();
list<list_node>::iterator i;
for (int u = 0; u < V - 1; u++) {
relaxed = 0;
if (dist[u] != INT_MAX) {
for (i = adj[u].begin(); i != adj[u].end(); ++i) {
if (dist[i->get_vertex()] > dist[u] + i->get_weight()) {
dist[i->get_vertex()] = dist[u] + i->get_weight();
pre[i->get_vertex()] = u;
relaxed = 1;
}
}
}
}
cout << float( clock() - startTime2) /
(float) CLOCKS_PER_SEC << " iteraton seconds." << endl;
}
cout << float( clock() - startTime1) /
(float) CLOCKS_PER_SEC << " seconds." << endl;
cout << "Vertex\t\tDistance\t\tPred" << endl;
for (int i = 0; i < V; i++) {
cout << i << "\t\t" << dist[i];
cout << "\t\t" << pre[i] << "\t\t";
cout << endl;
}
return relaxed;
}
//function prototypes
//for libcurl
size_t write_data(char *ptr, size_t size, size_t nmemb, void *userdata);
int main() {
//set up currencies
string coin[16];
coin[0] = "BTC";
coin[1] = "ANC";
coin[2] = "DGC";
coin[3] = "DVC";
coin[4] = "FRC";
coin[5] = "FTC";
coin[6] = "I0C";
coin[7] = "IXC";
coin[8] = "LTC";
coin[9] = "NMC";
coin[10] = "NVC";
coin[11] = "PPC";
coin[12] = "TRC";
coin[13] = "WDC";
coin[14] = "XPM";
coin[15] = "USD";
int V = 16;
//1-(the fees incurred by a trade)
double discount = 0.995;
std::ostringstream stream;
//set up curl
CURL *curl;
CURLcode res;
curl = curl_easy_init();
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &stream);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_data);
curl_easy_setopt(curl, CURLOPT_URL, "https://vircurex.com/api/get_info_for_currency.json");
/* Perform the request, res will get the return code */
res = curl_easy_perform(curl);
/* Check for errors */
if (res != CURLE_OK) {
fprintf(stderr, "curl_easy_perform() failed: %s\n",
curl_easy_strerror(res));
cout << "error" << endl;
return 1;
}
/* always cleanup */
curl_easy_cleanup(curl);
std::string output = stream.str();
Json::Value root;
Json::Reader reader;
bool parsedSuccess = reader.parse(output, root, false);
if (not parsedSuccess) {
// Report failures and their locations
// in the document.
cout << output << endl;
cout << "Failed to parse JSON" << endl << reader.getFormatedErrorMessages() << endl;
return 1;
}
//# of currencies
graph g(V);
for (int i = 0; i < V; i++) {
const Json::Value currency1 = root[coin[i]];
for (int j = 0; j < V; j++) {
if (j != i) {
const Json::Value currency2 = currency1[coin[j]];
double exchange = atof(currency2["highest_bid"].asCString());
double volume = atof(currency2["volume"].asCString());
/*only trade coins that are currently being traded and not worthless*/
if (exchange * discount * volume > 0) {
// cout << "exchange " << i << " to " << j << " is: " << exchange * discount << endl;
g.add_edge(i, j, -log(exchange * discount));
}
}
}
}
//clear stream
stream.str(std::string());
int s = 0;
double dist[V];
int pre[V];
cout << "Following are shortest distances from source " << coin[s] << " \n";
int relaxed = g.bellman_ford(s, dist, pre);
if (relaxed) {
//get negative cycle from src
for (int u = 0; u < V; u++) {
if (dist[u] < 0) {
cout << "profit: " << exp(dist[u]) << " path: ";
int k = u;
cout << coin[s] << "->";
do {
cout << coin[k] << "->";
k = pre[k];
} while (k != s);
cout << coin[k] << endl;
}
}
}
return 0;
}
size_t write_data(char *ptr, size_t size, size_t nmemb, void *userdata) {
std::ostringstream *stream = (std::ostringstream*)userdata;
size_t count = size * nmemb;
stream->write(ptr, count);
return count;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment