diff options
-rw-r--r-- | api.c | 48 | ||||
-rw-r--r-- | api.h | 14 | ||||
-rw-r--r-- | graph.c | 58 | ||||
-rw-r--r-- | graph.h | 16 | ||||
-rw-r--r-- | main.c | 12 |
5 files changed, 141 insertions, 7 deletions
@@ -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 * @@ -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(©); + strftime(time_string, 16, "%m/%d/%Y", ©); + 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 @@ -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) { |