aboutsummarylogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--api.c48
-rw-r--r--api.h14
-rw-r--r--graph.c58
-rw-r--r--graph.h16
-rw-r--r--main.c12
5 files changed, 141 insertions, 7 deletions
diff --git a/api.c b/api.c
index 236864f149b7..1531b009341c 100644
--- a/api.c
+++ b/api.c
@@ -171,11 +171,45 @@ double* coinmarketcap_get_price(const char* ticker_name_string) {
return ret;
}
+double* api_get_hist_5y(const char* ticker_name_string){
+ double* val;
+ val = iex_get_hist_5y(ticker_name_string); //First tries IEX for intraday prices
+ if (val != NULL)
+ return val;
+ return NULL; //Invalid symbol
+}
+
+double* iex_get_hist_5y(const char* ticker_name_string) {
+ char iex_api_string[64];
+ sprintf(iex_api_string, "https://api.iextrading.com/1.0/stock/%s/chart/5y", ticker_name_string);
+ String* pString = api_curl_data(iex_api_string, NULL);
+ if (strcmp(pString->data, "Unknown symbol") == 0) { //Invalid symbol
+ string_destroy(&pString);
+ return NULL;
+ }
+ Json* jobj = json_tokener_parse(pString->data);
+ size_t len = json_object_array_length(jobj);
+ double* ret = malloc(sizeof(double) * (len + 1));
+ ret[len] = '\0';
+ if (ret == NULL) {
+ fprintf(stderr, "malloc() failed\n");
+ exit(EXIT_FAILURE);
+ }
+ Json* temp;
+ for (int i = 0; i < (int)len; i++) {
+ temp = json_object_array_get_idx(jobj, (size_t) i);
+ ret[i] = json_object_get_double(json_object_object_get(temp, "close"));
+ }
+ json_object_put(jobj);
+ string_destroy(&pString);
+ return ret;
+}
+
void news_print_top_three(const char* ticker_name_string) {
char* url_encoded_string = calloc(128, 1);
if (url_encoded_string == NULL) {
fprintf(stderr, "malloc() failed\n");
- return;
+ exit(EXIT_FAILURE);
}
for (int i = 0, j = 0; i < 128; i++, j++) { //Replace underscores and spaces with url encoded '%20's
if (ticker_name_string[i] == '_' || ticker_name_string[i] == ' ') {
@@ -248,15 +282,15 @@ void api_print_info(const char* ticker_name_string) {
if (strcmp(ticker_info->symbol, "") != 0)
printf("Symbol: %s\n", ticker_info->symbol);
if (ticker_info->price != EMPTY)
- printf("Price: $%lf\n", ticker_info->price);
+ printf("Price: $%.2lf\n", ticker_info->price);
if (ticker_info->change_1d != EMPTY)
- printf("Percent change 24h: %lf%%\n", ticker_info->change_1d);
+ printf("Percent change 24h: %.2lf%%\n", ticker_info->change_1d);
if (ticker_info->change_7d != EMPTY)
- printf("Percent change 7d: %lf%%\n", ticker_info->change_7d);
+ printf("Percent change 7d: %.2lf%%\n", ticker_info->change_7d);
if (ticker_info->change_30d != EMPTY)
- printf("Percent change 30d: %lf%%\n", ticker_info->change_30d);
+ printf("Percent change 30d: %.2lf%%\n", ticker_info->change_30d);
if (ticker_info->div_yield != EMPTY)
- printf("Dividend yield: %lf%%\n", ticker_info->div_yield);
+ printf("Dividend yield: %.2lf%%\n", ticker_info->div_yield);
if (ticker_info->marketcap != EMPTY)
printf("Market Cap: $%ld\n", ticker_info->marketcap);
if (ticker_info->volume_1d != EMPTY)
@@ -293,7 +327,7 @@ Info* iex_get_info(const char* ticker_name_string) {
struct tm* ts = localtime(&now);
mktime(ts);
int after_close = ts->tm_hour > 16 && ts->tm_wday != 0 && ts->tm_wday != 6;
- Json* d_30 = json_object_array_get_idx(jobj, (size_t)after_close);
+ Json* d_30 = json_object_array_get_idx(jobj, (size_t) after_close);
Json* d_7 = json_object_array_get_idx(jobj, json_object_array_length(jobj) - 6 + after_close);
Json* d_1 = json_object_array_get_idx(jobj, json_object_array_length(jobj) - 2 + after_close);
ticker_info->change_30d = 100 / ticker_info->price *
diff --git a/api.h b/api.h
index 20262330e670..2242e2fc82bf 100644
--- a/api.h
+++ b/api.h
@@ -89,6 +89,20 @@ double* morningstar_get_price(const char* ticker_name_string);
double* coinmarketcap_get_price(const char* ticker_name_string);
/**
+ * Returns an array of doubles containing the close price each day in the past 5 years
+ * @param ticker_name_string symbol
+ * @return double array of close prices
+ */
+double* api_get_hist_5y(const char* ticker_name_string);
+
+/**
+ * Returns an array of doubles containing the close price each day in the past 5 years
+ * @param ticker_name_string symbol of stock or etf
+ * @return double array of close prices
+ */
+double* iex_get_hist_5y(const char* ticker_name_string);
+
+/**
* Prints the top three news articles by popularity pertaining to the given string, ticker_name_string. Spaces and
* underscores will be url-encoded (replaced by "%20"). News API will be used for data.
* @param ticker_name_string the string to query
diff --git a/graph.c b/graph.c
new file mode 100644
index 000000000000..ffbafd40bd26
--- /dev/null
+++ b/graph.c
@@ -0,0 +1,58 @@
+#include "graph.h"
+
+void graph_print(const double* points, struct tm* start_time) {
+ struct winsize w;
+ ioctl(STDOUT_FILENO, TIOCGWINSZ, &w);
+ int cols = w.ws_col - 10; // 10 offset per side to give space for graph labels
+ int lines = w.ws_row - ROWS_SPACING;
+ lines -= lines % ROWS_SPACING; // Round down to multiple of 5
+ if (cols < 10 || lines < 10) {
+ puts("Terminal not large enough.\n");
+ return;
+ }
+
+ double max = points[0], min = points[0];
+ int data_length = 0;
+ for (int i = 1; points[i] != '\0'; i++) { // Find max and min values for graph upper/lower bounds
+ if (points[i] > max)
+ max = points[i];
+ if (points[i] < min)
+ min = points[i];
+ data_length++;
+ }
+ double line_diff = (max - min) / lines, dat; // Each lines includes data point up to line_diff below
+
+ for (int i = lines; i >= 0; i--) {
+ if (i % ROWS_SPACING == 0) // Print y-axis price labels with width 10
+ printf("%9.2lf ", (max - ((lines - i) * line_diff)));
+ else printf(" ");
+ for (int j = 0; j < cols; j++) {
+ dat = points[(int) ((double) j * data_length / cols)];
+ if (dat <= (max - ((lines - i) * line_diff)) && dat > (min + ((i - 1) * line_diff)))
+ putchar('*');
+ else if (i % ROWS_SPACING == 0 && j % COLS_SPACING == 0)
+ putchar('+');
+ else if (i % ROWS_SPACING == 0)
+ putchar('-');
+ else if (j % COLS_SPACING == 0)
+ putchar('|');
+ else putchar(' ');
+ }
+ putchar('\n');
+ }
+
+ printf(" ");
+ char time_string[16];
+ int x = data_length / (COLS_SPACING - 1);
+ struct tm copy = *start_time;
+ for (int i = 0; i < cols; i++) {
+ if (i % (2 * COLS_SPACING) == 0 && cols - i > 10) { // Print x-axis date labels every two
+ if (i != 0)
+ copy.tm_mday += 2 * x;
+ mktime(&copy);
+ strftime(time_string, 16, "%m/%d/%Y", &copy);
+ printf("%s ", time_string); // Width 2 * COLS_SPACING
+ }
+ }
+ putchar('\n');
+} \ No newline at end of file
diff --git a/graph.h b/graph.h
new file mode 100644
index 000000000000..291e7d90fa15
--- /dev/null
+++ b/graph.h
@@ -0,0 +1,16 @@
+#ifndef GRAPH_H
+#define GRAPH_H
+
+#define ROWS_SPACING 5
+#define COLS_SPACING 12
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <ncurses.h>
+#include <sys/ioctl.h>
+#include <unistd.h>
+#include "api.h"
+
+void graph_print(const double* points, struct tm* start_time);
+
+#endif \ No newline at end of file
diff --git a/main.c b/main.c
index e4a30c84c3a6..5099f45ac97d 100644
--- a/main.c
+++ b/main.c
@@ -1,4 +1,5 @@
#include "portfolio.h"
+#include "graph.h"
int main(int argc, char* argv[]) {
if (argc < 2) {
@@ -50,6 +51,17 @@ int main(int argc, char* argv[]) {
// Info
else if (strcmp(cmd, "info") == 0 && argc == 3)
api_print_info(sym);
+ else if (strcmp(cmd, "graph") == 0 && argc == 3) {
+ double* data = api_get_hist_5y(sym);
+ if (data != NULL) {
+ time_t now = time(NULL);
+ struct tm* ts = localtime(&now);
+ ts->tm_year -= 5; // Lowerbound date is 14 days earlier
+ graph_print(data, ts);
+ free(data);
+ }
+ else printf("Invalid symbol.\n");
+ }
// Check
else if (strcmp(cmd, "check") == 0) {