diff options
author | Antony Kellermann | 2018-05-27 23:15:55 -0400 |
---|---|---|
committer | Antony Kellermann | 2018-05-27 23:15:55 -0400 |
commit | b776fc7eeba23d11198c9fa16c8a0797c1010e99 (patch) | |
tree | 5ab31f1a695de7b9a81e5af2c97a50bb5c851630 | |
parent | b84d32092615a3d0ec8f5fed98b035207f95807b (diff) | |
download | aur-b776fc7eeba23d11198c9fa16c8a0797c1010e99.tar.gz |
Added functions to store additional Info data
-rw-r--r-- | api.c | 257 | ||||
-rw-r--r-- | api.h | 53 |
2 files changed, 237 insertions, 73 deletions
@@ -3,15 +3,15 @@ Info* api_info_init(void) { Info* pInfo = malloc(sizeof(Info)); pointer_alloc_check(pInfo); - pInfo->name[0] = '\0'; - pInfo->symbol[0] = '\0'; - pInfo->price = EMPTY; - pInfo->change_1d = EMPTY; - pInfo->change_7d = EMPTY; - pInfo->change_30d = EMPTY; - pInfo->div_yield = EMPTY; - pInfo->marketcap = EMPTY; - pInfo->volume_1d = EMPTY; + *pInfo = (Info) { + .symbol[0] = '\0', .name[0] = '\0', .industry[0] = '\0', .website[0] = '\0', .description[0] = '\0', + .ceo[0] = '\0', .issue_type[0] = '\0', .sector[0] = '\0', .intraday_time = EMPTY, .price = EMPTY, + .marketcap = EMPTY, .volume_1d = EMPTY, .pe_ratio = EMPTY, .div_yield = EMPTY, .revenue = EMPTY, + .gross_profit = EMPTY, .cash = EMPTY, .debt = EMPTY, .eps = {EMPTY, EMPTY, EMPTY, EMPTY}, + .fiscal_period[0][0] = '\0', .fiscal_period[1][0] = '\0', .fiscal_period[2][0] = '\0', + .fiscal_period[3][0] = '\0', .eps_year_ago = {EMPTY, EMPTY, EMPTY, EMPTY}, .change_1d = EMPTY, + .change_7d = EMPTY, .change_30d = EMPTY + }; return pInfo; } @@ -69,7 +69,7 @@ double* api_get_current_price(const char* symbol) { } double* iex_get_price(const char* symbol) { - char iex_api_string[80]; + char iex_api_string[URL_MAX_LENGTH]; sprintf(iex_api_string, "https://api.iextrading.com/1.0/stock/%s/quote", symbol); String* pString = api_curl_data(iex_api_string); if (pString == NULL) @@ -111,14 +111,164 @@ double* iex_get_price(const char* symbol) { return api_data; } +void* iex_store_company(void* vpInfo) { + Info* symbol_info = vpInfo; + symbol_info->symbol[0] = '\0'; + char iex_api_string[URL_MAX_LENGTH]; + sprintf(iex_api_string, "https://api.iextrading.com/1.0/stock/%s/company", symbol_info->symbol); + String* pString = api_curl_data(iex_api_string); // API CALL 1 -- Company + if (pString == NULL) + return NULL; + + Json* jobj = json_tokener_parse(pString->data); + if (jobj == NULL) { // Invalid symbol + string_destroy(&pString); + return NULL; + } + + strcpy(symbol_info->symbol, json_object_get_string(json_object_object_get(jobj, "symbol"))); + strcpy(symbol_info->name, json_object_get_string(json_object_object_get(jobj, "companyName"))); + strcpy(symbol_info->industry, json_object_get_string(json_object_object_get(jobj, "industry"))); + strcpy(symbol_info->website, json_object_get_string(json_object_object_get(jobj, "website"))); + strcpy(symbol_info->description, json_object_get_string(json_object_object_get(jobj, "description"))); + strcpy(symbol_info->ceo, json_object_get_string(json_object_object_get(jobj, "CEO"))); + strcpy(symbol_info->issue_type, json_object_get_string(json_object_object_get(jobj, "issueType"))); + strcpy(symbol_info->sector, json_object_get_string(json_object_object_get(jobj, "sector"))); + json_object_put(jobj); + string_destroy(&pString); + return NULL; +} + +void* iex_store_quote(void* vpInfo) { + Info* symbol_info = vpInfo; + if (symbol_info->symbol[0] == '\0') + return NULL; + + char iex_api_string[URL_MAX_LENGTH]; + sprintf(iex_api_string, "https://api.iextrading.com/1.0/stock/%s/quote", symbol_info->symbol); + String* pString = api_curl_data(iex_api_string); // API CALL 2 -- Quote + if (pString == NULL) + return NULL; + + Json* jobj = json_tokener_parse(pString->data); + if (jobj == NULL) { // Invalid symbol + string_destroy(&pString); + return NULL; + } + + symbol_info->price = json_object_get_double(json_object_object_get(jobj, "latestPrice")); + symbol_info->intraday_time = json_object_get_int64(json_object_object_get(jobj, "latestUpdate")); + symbol_info->marketcap = json_object_get_int64(json_object_object_get(jobj, "marketCap")); + symbol_info->volume_1d = json_object_get_int64(json_object_object_get(jobj, "latestVolume")); + symbol_info->pe_ratio = json_object_get_int64(json_object_object_get(jobj, "peRatio")); + json_object_put(jobj); + string_destroy(&pString); + return NULL; +} + +void* iex_store_stats(void* vpInfo) { + Info* symbol_info = vpInfo; + if (symbol_info->symbol[0] == '\0') + return NULL; + + char iex_api_string[URL_MAX_LENGTH]; + sprintf(iex_api_string, "https://api.iextrading.com/1.0/stock/%s/stats", symbol_info->symbol); + String* pString = api_curl_data(iex_api_string); // API CALL 3 -- Stats + if (pString == NULL) + return NULL; + + Json* jobj = json_tokener_parse(pString->data); + if (jobj == NULL) { // Invalid symbol + string_destroy(&pString); + return NULL; + } + + symbol_info->div_yield = json_object_get_double(json_object_object_get(jobj, "dividentYield")); + symbol_info->revenue = json_object_get_int64(json_object_object_get(jobj, "revenue")); + symbol_info->gross_profit = json_object_get_int64(json_object_object_get(jobj, "grossProfit")); + symbol_info->cash = json_object_get_int64(json_object_object_get(jobj, "cash")); + symbol_info->debt = json_object_get_int64(json_object_object_get(jobj, "debt")); + json_object_put(jobj); + string_destroy(&pString); + return NULL; +} + +void* iex_store_earnings(void* vpInfo) { + Info* symbol_info = vpInfo; + if (symbol_info->symbol[0] == '\0') + return NULL; + + char iex_api_string[URL_MAX_LENGTH]; + sprintf(iex_api_string, "https://api.iextrading.com/1.0/stock/%s/earnings", symbol_info->symbol); + String* pString = api_curl_data(iex_api_string); // API CALL 4 -- Earnings + if (pString == NULL) + return NULL; + + Json* jobj = json_tokener_parse(pString->data); + if (jobj == NULL) { // Invalid symbol + string_destroy(&pString); + return NULL; + } + + Json* idx; + size_t len = json_object_array_length(json_object_object_get(jobj, "earnings")); + for (size_t i = 0; i < len; i++) { + idx = json_object_array_get_idx(json_object_object_get(jobj, "earnings"), i); + symbol_info->eps[i] = json_object_get_double(json_object_object_get(idx, "actualEPS")); + symbol_info->eps_year_ago[i] = json_object_get_double(json_object_object_get(idx, "yearAgo")); + strcpy(symbol_info->fiscal_period[i], json_object_get_string(json_object_object_get(idx, "fiscalPeriod"))); + } + json_object_put(jobj); + string_destroy(&pString); + return NULL; +} + +void* iex_store_chart(void* vpInfo) { + Info* symbol_info = vpInfo; + if (symbol_info->symbol[0] == '\0') + return NULL; + + char iex_api_string[URL_MAX_LENGTH]; + sprintf(iex_api_string, "https://api.iextrading.com/1.0/stock/%s/chart/5y", symbol_info->symbol); + String* pString = api_curl_data(iex_api_string); + if (pString == NULL) + return NULL; + + Json* jobj = json_tokener_parse(pString->data); + if (jobj == NULL) { // Invalid symbol + string_destroy(&pString); + return NULL; + } + + size_t len = json_object_array_length(jobj); + symbol_info->points = calloc(len + 1, sizeof(double)); + pointer_alloc_check(symbol_info->points); + for (size_t i = 0; i < len; i++) + symbol_info->points[i] = json_object_get_double( + json_object_object_get(json_object_array_get_idx(jobj, i), "close")); + + len = 0; + while (symbol_info->points[len] != '\0') + len++; + time_t now = time(NULL); + struct tm* ts = localtime(&now); + mktime(ts); + int after_close = ts->tm_hour > 16 && ts->tm_wday != 0 && ts->tm_wday != 6; + double coef = 100 / symbol_info->price; + symbol_info->change_1d = coef * (symbol_info->price - symbol_info->points[len - 2 + after_close]); + symbol_info->change_7d = coef * (symbol_info->price - symbol_info->points[len - 6 + after_close]); + symbol_info->change_30d = coef * (symbol_info->price - symbol_info->points[len - 22 + after_close]); + return NULL; +} + double* morningstar_get_price(const char* symbol) { - char today_str[16], yesterday_str[16], morningstar_api_string[256]; + char today_str[DATE_MAX_LENGTH], yesterday_str[DATE_MAX_LENGTH], morningstar_api_string[URL_MAX_LENGTH]; time_t now = time(NULL); struct tm* ts = localtime(&now); - strftime(today_str, 16, "%Y-%m-%d", ts); + strftime(today_str, DATE_MAX_LENGTH, "%Y-%m-%d", ts); ts->tm_mday -= 12; // Get info from past 12 days mktime(ts); - strftime(yesterday_str, 16, "%Y-%m-%d", ts); + strftime(yesterday_str, DATE_MAX_LENGTH, "%Y-%m-%d", ts); sprintf(morningstar_api_string, "http://globalquote.morningstar.com/globalcomponent/RealtimeHistoricalStockData.ashx?showVol=true&dtype=his" "&f=d&curry=USD&isD=true&isS=true&hasF=true&ProdCode=DIRECT&ticker=%s&range=%s|%s", @@ -147,7 +297,7 @@ double* morningstar_get_price(const char* symbol) { } double* coinmarketcap_get_price(const char* symbol) { - char coinmarketcap_api_string[64]; + char coinmarketcap_api_string[URL_MAX_LENGTH]; sprintf(coinmarketcap_api_string, "https://api.coinmarketcap.com/v1/ticker/%s", symbol); String* pString = api_curl_data(coinmarketcap_api_string); if (pString == NULL) @@ -182,7 +332,7 @@ double* api_get_hist_5y(const char* symbol) { } double* iex_get_hist_5y(const char* symbol) { - char iex_api_string[64]; + char iex_api_string[URL_MAX_LENGTH]; sprintf(iex_api_string, "https://api.iextrading.com/1.0/stock/%s/chart/5y", symbol); String* pString = api_curl_data(iex_api_string); if (pString == NULL) @@ -205,14 +355,14 @@ double* iex_get_hist_5y(const char* symbol) { } double* morningstar_get_hist_5y(const char* symbol) { - char today_str[16], yesterday_str[16], morningstar_api_string[256]; + char today_str[DATE_MAX_LENGTH], yesterday_str[DATE_MAX_LENGTH], morningstar_api_string[URL_MAX_LENGTH]; time_t now = time(NULL); struct tm* ts = localtime(&now); mktime(ts); - strftime(today_str, 16, "%Y-%m-%d", ts); + strftime(today_str, DATE_MAX_LENGTH, "%Y-%m-%d", ts); ts->tm_year -= 5; //get info from past 5 years mktime(ts); - strftime(yesterday_str, 16, "%Y-%m-%d", ts); + strftime(yesterday_str, DATE_MAX_LENGTH, "%Y-%m-%d", ts); sprintf(morningstar_api_string, "http://globalquote.morningstar.com/globalcomponent/RealtimeHistoricalStockData.ashx?showVol=true&dtype=his" "&f=d&curry=USD&isD=true&isS=true&hasF=true&ProdCode=DIRECT&ticker=%s&range=%s|%s", @@ -329,60 +479,36 @@ void api_print_info(const char* ticker_name_string) { api_info_destroy(&ticker_info); } -Info* iex_get_info(const char* ticker_name_string) { - char iex_api_string[128]; - sprintf(iex_api_string, "https://api.iextrading.com/1.0/stock/%s/quote", ticker_name_string); - String* pString = api_curl_data(iex_api_string); // API CALL 1 -- name, symbol, price, mcap, volume - if (strcmp(pString->data, "Unknown symbol") == 0) { //Invalid symbol - string_destroy(&pString); - return NULL; - } - Info* ticker_info = api_info_init(); - Json* jobj = json_tokener_parse(pString->data); - strcpy(ticker_info->name, json_object_get_string(json_object_object_get(jobj, "companyName"))); - strcpy(ticker_info->symbol, json_object_get_string(json_object_object_get(jobj, "symbol"))); - ticker_info->price = json_object_get_double(json_object_object_get(jobj, "latestPrice")); - ticker_info->marketcap = json_object_get_int64(json_object_object_get(jobj, "marketCap")); - ticker_info->volume_1d = json_object_get_int64(json_object_object_get(jobj, "latestVolume")); - json_object_put(jobj); - string_destroy(&pString); - - sprintf(iex_api_string, "https://api.iextrading.com/1.0/stock/%s/stats/dividendYield", ticker_name_string); - pString = api_curl_data(iex_api_string); // API CALL 2 -- dividend - if (strcmp("0", pString->data) != 0) - ticker_info->div_yield = strtod(pString->data, NULL); - string_destroy(&pString); - - sprintf(iex_api_string, "https://api.iextrading.com/1.0/stock/%s/chart", ticker_name_string); - pString = api_curl_data(iex_api_string); // API CALL 3 -- historical - jobj = json_tokener_parse(pString->data); - time_t now = time(NULL); - 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_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 * - (ticker_info->price - json_object_get_double(json_object_object_get(d_30, "close"))); - ticker_info->change_7d = 100 / ticker_info->price * - (ticker_info->price - json_object_get_double(json_object_object_get(d_7, "close"))); - ticker_info->change_1d = 100 / ticker_info->price * - (ticker_info->price - json_object_get_double(json_object_object_get(d_1, "close"))); - json_object_put(jobj); - string_destroy(&pString); - return ticker_info; +Info* iex_get_info(const char* symbol) { + Info* symbol_info = api_info_init(); + strcpy(symbol_info->symbol, symbol); + pthread_t threads[5]; + void* (*funcs[5]) (void*) = { + iex_store_company, iex_store_quote, iex_store_stats, iex_store_earnings, iex_store_chart + }; + for (int i = 0; i < 5; i++) + if (pthread_create(&threads[i], NULL, funcs[i], symbol_info)) + EXIT_MSG("Error creating thread!"); + + for (int i = 0; i < 5; i++) + if (pthread_join(threads[i], NULL)) + EXIT_MSG("Error joining thread!"); + + if (symbol_info->symbol[0] == '\0') + api_info_destroy(&symbol_info); + + return symbol_info; } Info* morningstar_get_info(const char* ticker_name_string) { - char today_char[16], yesterday_char[16], morningstar_api_string[512]; + char today_char[DATE_MAX_LENGTH], yesterday_char[DATE_MAX_LENGTH], morningstar_api_string[URL_MAX_LENGTH]; time_t now = time(NULL); struct tm* ts = localtime(&now); mktime(ts); - strftime(today_char, 16, "%Y-%m-%d", ts); + strftime(today_char, DATE_MAX_LENGTH, "%Y-%m-%d", ts); ts->tm_mday -= 30; // Get info from past 30 days mktime(ts); - strftime(yesterday_char, 16, "%Y-%m-%d", ts); + strftime(yesterday_char, DATE_MAX_LENGTH, "%Y-%m-%d", ts); sprintf(morningstar_api_string, "http://globalquote.morningstar.com/globalcomponent/RealtimeHistoricalStockData.ashx?showVol=true&dtype=his" "&f=d&curry=USD&isD=true&isS=true&hasF=true&ProdCode=DIRECT&ticker=%s&range=%s|%s", @@ -417,7 +543,7 @@ Info* morningstar_get_info(const char* ticker_name_string) { } Info* coinmarketcap_get_info(const char* ticker_name_string) { - char coinmarketcap_api_string[64]; + char coinmarketcap_api_string[URL_MAX_LENGTH]; sprintf(coinmarketcap_api_string, "https://api.coinmarketcap.com/v1/ticker/%s", ticker_name_string); String* pString = api_curl_data(coinmarketcap_api_string); if (pString->data[0] == '{') { // Invalid symbol @@ -440,6 +566,7 @@ Info* coinmarketcap_get_info(const char* ticker_name_string) { } void api_info_destroy(Info** phInfo) { + free((*phInfo)->points); free(*phInfo); *phInfo = NULL; }
\ No newline at end of file @@ -1,32 +1,59 @@ /** - * API data is taken from IEX Trading, Morningstar, Coinmarketcap, and News API. + * API data is taken from IEX Trading, Morningstar, Coinmarketcap. * https://iextrading.com/developer/docs/ * http://www.morningstar.com/ * https://coinmarketcap.com/api/ - * https://newsapi.org/docs */ #ifndef API_H #define API_H +#define QUARTERS 4 #define DATE_MAX_LENGTH 16 #define SYMBOL_MAX_LENGTH 32 #define URL_MAX_LENGTH 2048 +#define INFO_TEXT_MAX 2048 #define EMPTY (-999) #include <stddef.h> #include <curl/curl.h> #include <json-c/json_tokener.h> +#include <pthread.h> #include "string-tick.h" typedef struct info { - char name[SYMBOL_MAX_LENGTH]; // Name of security (ex. Apple Inc.) + /* Company */ char symbol[SYMBOL_MAX_LENGTH]; // Symbol of security (ex. AAPL) + char name[INFO_TEXT_MAX]; // Name of security (ex. Apple Inc.) + char industry[INFO_TEXT_MAX]; + char website[URL_MAX_LENGTH]; + char description[INFO_TEXT_MAX]; // Description of company + char ceo[INFO_TEXT_MAX]; + char issue_type[3]; + char sector[INFO_TEXT_MAX]; + + /* Quote */ + int64_t intraday_time; // unix time double price; // Current price of security in USD (ex. 174.54) - double change_1d, change_7d, change_30d; // Percent change in the past x days (ex. -7.49) + int64_t marketcap; // Market cap in USD (ex. 890489000000) + int64_t volume_1d; // Volume in shares of security (ex. 33812360) + double pe_ratio; + + /* Stats */ double div_yield; // Percent dividend yield (ex. 1.46) - long marketcap; // Market cap in USD (ex. 890489000000) - long volume_1d; // Volume in shares of security (ex. 33812360) + int64_t revenue; + int64_t gross_profit; + int64_t cash; + int64_t debt; + + /* Earnings */ + double eps[QUARTERS]; + char fiscal_period[QUARTERS][DATE_MAX_LENGTH]; + double eps_year_ago[QUARTERS]; + + /* Chart */ + double change_1d, change_7d, change_30d; // Percent change in the past x days (ex. -7.49) + double* points; // 5y } Info; /** @@ -72,6 +99,16 @@ double* api_get_current_price(const char* symbol); */ double* iex_get_price(const char* symbol); +void* iex_store_company(void* vpInfo); + +void* iex_store_quote(void* vpInfo); + +void* iex_store_stats(void* vpInfo); + +void* iex_store_earnings(void* vpInfo); + +void* iex_store_chart(void* vpInfo); + /** * Returns current and yesterday's price of a mutual fund with data from Morningstar * Tested for MUTF and OTCMKTS listed securities. @@ -125,10 +162,10 @@ void api_print_info(const char* ticker_name_string); /** * Returns a pointer to an Info object containing info pertaining * to the given symbol with data from IEX. - * @param ticker_name_string stock/etf symbol + * @param symbol stock/etf symbol * @return Info object */ -Info* iex_get_info(const char* ticker_name_string); +Info* iex_get_info(const char* symbol); /** * Returns a pointer to an Info object containing info pertaining |