diff options
-rw-r--r-- | api.c | 248 | ||||
-rw-r--r-- | api.h | 77 | ||||
-rw-r--r-- | portfolio.c | 25 |
3 files changed, 75 insertions, 275 deletions
@@ -3,7 +3,7 @@ Info* api_info_init(void) { Info* pInfo = malloc(sizeof(Info)); pointer_alloc_check(pInfo); - *pInfo = (Info) { + *pInfo = (Info) { // Set every string to NULL and every value to EMPTY .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, @@ -46,71 +46,6 @@ String* api_curl_data(const char* url) { return pString; } -double* api_get_current_price(const char* symbol) { - double* val; - if (strlen(symbol) > 5) { // If symbol length is greater than 5, then it must be a crypto - val = coinmarketcap_get_price(symbol); - return val; - } - - val = iex_get_price(symbol); // First tries IEX for intraday prices - if (val != NULL) - return val; - - val = morningstar_get_price(symbol); // Secondly tries Morningstar for market open/close data - if (val != NULL) - return val; - - val = coinmarketcap_get_price(symbol); // Thirdly tries Coinmarketcap for real-time crypto data - if (val != NULL) - return val; - - return NULL; // Invalid symbol -} - -double* iex_get_price(const char* symbol) { - 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) - return NULL; - - if (strcmp(pString->data, "Unknown symbol") == 0) { // Invalid symbol - string_destroy(&pString); - return NULL; - } - - Json* jobj = json_tokener_parse(pString->data); - double* api_data = malloc(sizeof(double) * 3); - pointer_alloc_check(api_data); - // First API call can only give intraday and previous close - api_data[0] = json_object_get_double(json_object_object_get(jobj, "latestPrice")); // Intraday - api_data[1] = json_object_get_double(json_object_object_get(jobj, "previousClose")); // Previous close - json_object_put(jobj); - string_destroy(&pString); - - // Second API call gives 7D price - sprintf(iex_api_string, "https://api.iextrading.com/1.0/stock/%s/chart", symbol); - pString = api_curl_data(iex_api_string); - if (pString == NULL) { - free(api_data); - return NULL; - } - - if (strcmp(pString->data, "Unknown symbol") == 0) { // May happen as a result of an unpredictable API - free(api_data); - string_destroy(&pString); - return NULL; - } - - jobj = json_tokener_parse(pString->data); - api_data[2] = json_object_get_double( - json_object_object_get(json_object_array_get_idx(jobj, json_object_array_length(jobj) - 5), "close")); - json_object_put(jobj); - string_destroy(&pString); - return api_data; -} - void* iex_store_company(void* vpInfo) { Info* symbol_info = vpInfo; char iex_api_string[URL_MAX_LENGTH]; @@ -159,7 +94,7 @@ void* iex_store_quote(void* vpInfo) { symbol_info->intraday_time = json_object_get_int64(json_object_object_get(jobj, "closeTime")); 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")); + symbol_info->pe_ratio = json_object_get_double(json_object_object_get(jobj, "peRatio")); json_object_put(jobj); string_destroy(&pString); return NULL; @@ -317,150 +252,20 @@ void* coinmarketcap_store_info(void* vpInfo) { string_destroy(&pString); return NULL; } - Info* ticker_info = api_info_init(); Json* jobj = json_tokener_parse(pString->data); Json* data = json_object_array_get_idx(jobj, 0); - strcpy(ticker_info->name, json_object_get_string(json_object_object_get(data, "name"))); - strcpy(ticker_info->symbol, json_object_get_string(json_object_object_get(data, "symbol"))); - ticker_info->price = strtod(json_object_get_string(json_object_object_get(data, "price_usd")), NULL); - ticker_info->change_1d = strtod(json_object_get_string(json_object_object_get(data, "percent_change_24h")), NULL); - ticker_info->change_7d = strtod(json_object_get_string(json_object_object_get(data, "percent_change_7d")), NULL); - ticker_info->marketcap = strtol(json_object_get_string(json_object_object_get(data, "market_cap_usd")), NULL, 10); - ticker_info->volume_1d = strtol(json_object_get_string(json_object_object_get(data, "24h_volume_usd")), NULL, 10); + strcpy(symbol_info->name, json_object_get_string(json_object_object_get(data, "name"))); + strcpy(symbol_info->symbol, json_object_get_string(json_object_object_get(data, "symbol"))); + symbol_info->price = strtod(json_object_get_string(json_object_object_get(data, "price_usd")), NULL); + symbol_info->change_1d = strtod(json_object_get_string(json_object_object_get(data, "percent_change_24h")), NULL); + symbol_info->change_7d = strtod(json_object_get_string(json_object_object_get(data, "percent_change_7d")), NULL); + symbol_info->marketcap = strtol(json_object_get_string(json_object_object_get(data, "market_cap_usd")), NULL, 10); + symbol_info->volume_1d = strtol(json_object_get_string(json_object_object_get(data, "24h_volume_usd")), NULL, 10); json_object_put(jobj); string_destroy(&pString); return NULL; } -double* morningstar_get_price(const char* symbol) { - 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, DATE_MAX_LENGTH, "%Y-%m-%d", ts); - ts->tm_mday -= 12; // Get info from past 12 days - mktime(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", - symbol, yesterday_str, today_str); - String* pString = api_curl_data(morningstar_api_string); - if (pString == NULL) - return NULL; - - if (strcmp("null", pString->data) == 0) { // Invalid symbol - string_destroy(&pString); - return NULL; - } - - Json* jobj = json_tokener_parse(pString->data); - double* api_data = malloc(sizeof(double) * 3); - pointer_alloc_check(api_data); - Json* datapoints = json_object_object_get( - json_object_array_get_idx(json_object_object_get(jobj, "PriceDataList"), 0), "Datapoints"); - size_t size = json_object_array_length(datapoints); - api_data[0] = json_object_get_double(json_object_array_get_idx(json_object_array_get_idx(datapoints, size - 1), 0)); - api_data[1] = json_object_get_double(json_object_array_get_idx(json_object_array_get_idx(datapoints, size - 2), 0)); - api_data[2] = json_object_get_double(json_object_array_get_idx(json_object_array_get_idx(datapoints, size - 5), 0)); - json_object_put(jobj); - string_destroy(&pString); - return api_data; -} - -double* coinmarketcap_get_price(const char* symbol) { - 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) - return NULL; - - if (pString->data[0] == '{') { // Invalid symbol - string_destroy(&pString); - return NULL; - } - - Json* jobj = json_tokener_parse(pString->data); - double* api_data = malloc(sizeof(double) * 3); - pointer_alloc_check(api_data); - Json* idx = json_object_array_get_idx(jobj, 0); - api_data[0] = strtod(json_object_get_string(json_object_object_get(idx, "price_usd")), NULL); - api_data[1] = api_data[0] - ((strtod(json_object_get_string( - json_object_object_get(idx, "percent_change_24h")), NULL) / 100) * api_data[0]); - api_data[2] = api_data[0] - ((strtod(json_object_get_string( - json_object_object_get(idx, "percent_change_7d")), NULL) / 100) * api_data[0]); - json_object_put(jobj); - string_destroy(&pString); - return api_data; -} - -double* api_get_hist_5y(const char* symbol) { - if (strlen(symbol) > 5) // Cryptocurrency - return NULL; - double* val = iex_get_hist_5y(symbol); // First tries IEX - if (val != NULL) - return val; - return morningstar_get_hist_5y(symbol); // Secondly tries Morningstar -} - -double* iex_get_hist_5y(const char* symbol) { - 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) - return 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* api_data = calloc(len + 1, sizeof(double)); - pointer_alloc_check(api_data); - for (size_t i = 0; i < len; i++) - api_data[i] = json_object_get_double(json_object_object_get(json_object_array_get_idx(jobj, i), "close")); - json_object_put(jobj); - string_destroy(&pString); - return api_data; -} - -double* morningstar_get_hist_5y(const char* symbol) { - 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, DATE_MAX_LENGTH, "%Y-%m-%d", ts); - ts->tm_year -= 5; //get info from past 5 years - mktime(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", - symbol, yesterday_str, today_str); - String* pString = api_curl_data(morningstar_api_string); - if (pString == NULL) - return NULL; - - if (strcmp("null", pString->data) == 0) { // Invalid symbol - string_destroy(&pString); - return NULL; - } - - Json* jobj = json_tokener_parse(pString->data); - Json* datapoints = json_object_object_get( - json_object_array_get_idx(json_object_object_get(jobj, "PriceDataList"), 0), "Datapoints"); - size_t len = json_object_array_length(datapoints); - double* api_data = calloc(len + 1, sizeof(double)); // Must calloc() because some data points don't exist - pointer_alloc_check(api_data); - for (int i = 0; i < (int) len; i++) - api_data[i] = json_object_get_double( - json_object_array_get_idx(json_object_array_get_idx(datapoints, (size_t) i), 0)); - json_object_put(jobj); - string_destroy(&pString); - return api_data; -} - Info* iex_get_info(const char* symbol) { Info* symbol_info = api_info_init(); strcpy(symbol_info->symbol, symbol); @@ -504,6 +309,41 @@ Info* coinmarketcap_get_info(const char* symbol) { return symbol_info; } +Info* api_get_check_info(const char* symbol) { + if (strlen(symbol) > 5) // If symbol length is greater than 5, then it must be a crypto + return coinmarketcap_get_info(symbol); + + Info* symbol_info = api_info_init(); + strcpy(symbol_info->symbol, symbol); + pthread_t threads[2]; + void* (*funcs[2])(void*) = {iex_store_quote, iex_store_chart}; + for (int i = 0; i < 2; i++) + if (pthread_create(&threads[i], NULL, funcs[i], symbol_info)) + EXIT_MSG("Error creating thread!") + + for (int i = 0; i < 2; i++) + if (pthread_join(threads[i], NULL)) + EXIT_MSG("Error joining thread!") + + if (symbol_info->price != EMPTY) + return symbol_info; + + api_info_destroy(&symbol_info); + return morningstar_get_info(symbol); +} + +Info* api_get_info(const char* symbol) { + if (strlen(symbol) > 5) + return coinmarketcap_get_info(symbol); + + Info* symbol_info = iex_get_info(symbol); + if (symbol_info != NULL) + return symbol_info; + + return morningstar_get_info(symbol); + +} + void api_info_destroy(Info** phInfo) { free((*phInfo)->points); free(*phInfo); @@ -76,29 +76,6 @@ size_t api_string_writefunc(void* ptr, size_t size, size_t nmemb, String* pStrin */ String* api_curl_data(const char* url); -/** - * Returns a double* containing the current price and yesterday's price of a stock or cryptocurrency. - * [0] = current intraday price - * [1] = last close price - * [2] = close price 5 trading days previously - * The function will first query IEX. If no response, it will query Morningstar. If no response, it will query - * Coinmarketcap. If Coinmarketcap returns NULL, the function returns NULL. - * 1. IEX -- NASDAQ/NYSE/NYSEARCA - * 2. Morningstar -- MUTF/OTCMKTS - * 3. Coinmarketcap -- CRYPTO - * @param symbol security symbol or name to get prices of - * @return price data or NULL if invalid symbol - */ -double* api_get_current_price(const char* symbol); - -/** - * Returns current and yesterday's price of a stock with data from IEX. - * Tested for NASDAQ, NYSE, and NYSEARCA listed stocks/ETFs. - * @param symbol symbol - * @return price data as defined by api_get_current_price or NULL if invalid symbol - */ -double* iex_get_price(const char* symbol); - void* iex_store_company(void* vpInfo); void* iex_store_quote(void* vpInfo); @@ -114,43 +91,6 @@ void* morningstar_store_info(void* vpInfo); void* coinmarketcap_store_info(void* vpInfo); /** - * Returns current and yesterday's price of a mutual fund with data from Morningstar - * Tested for MUTF and OTCMKTS listed securities. - * @param symbol symbol - * @return price data as defined by api_get_current_price or NULL if invalid symbol - */ -double* morningstar_get_price(const char* symbol); - -/** - * Returns current and yesterday's price of a cryptocurrency with data from Coinmarketcap. - * All cryptocurrencies listed on Coinmarketcap will work. - * @param symbol symbol - * @return price data as defined by api_get_current_price or NULL if invalid symbol - */ -double* coinmarketcap_get_price(const char* symbol); - -/** - * Returns an array of doubles containing the close price each day in the past 5 years - * @param symbol symbol - * @return double array of close prices - */ -double* api_get_hist_5y(const char* symbol); - -/** - * Returns an array of doubles containing the close price each day in the past 5 years - * @param symbol symbol of stock or etf - * @return double array of close prices - */ -double* iex_get_hist_5y(const char* symbol); - -/** - * Returns an array of doubles containing the close price each day in the past 5 years - * @param symbol symbol of mutf/otcmkts - * @return double array of close prices - */ -double* morningstar_get_hist_5y(const char* symbol); - -/** * Returns a pointer to an Info object containing info pertaining * to the given symbol with data from IEX. * @param symbol stock/etf symbol @@ -174,6 +114,23 @@ Info* morningstar_get_info(const char* symbol); Info* coinmarketcap_get_info(const char* symbol); /** + * Returns a double* containing the current price and yesterday's price of a stock or cryptocurrency. + * [0] = current intraday price + * [1] = last close price + * [2] = close price 5 trading days previously + * The function will first query IEX. If no response, it will query Morningstar. If no response, it will query + * Coinmarketcap. If Coinmarketcap returns NULL, the function returns NULL. + * 1. IEX -- NASDAQ/NYSE/NYSEARCA + * 2. Morningstar -- MUTF/OTCMKTS + * 3. Coinmarketcap -- CRYPTO + * @param symbol security symbol or name to get prices of + * @return price data or NULL if invalid symbol + */ +Info* api_get_check_info(const char* symbol); + +Info* api_get_info(const char* symbol); + +/** * Destroys Info object and frees memory. Sets the pointer to the Info to NULL * @param phInfo the Info to destroy */ diff --git a/portfolio.c b/portfolio.c index 4cbcd510cbc8..8ab0062084a9 100644 --- a/portfolio.c +++ b/portfolio.c @@ -85,10 +85,10 @@ void portfolio_modify(const char* symbol, double quantity_shares, double usd_spe GOTO_CLEAN_MSG("You don't have any of this security to remove") if (strcmp("USD$", symbol) != 0) { // Check that the symbol is valid, except if it's USD - double* data = api_get_current_price(symbol); + Info* data = api_get_check_info(symbol); if (data == NULL) // If NULL response from APIs, it's invalid GOTO_CLEAN_MSG("Invalid symbol.") - else free(data); + else api_info_destroy(&data); } Json* new_object = json_object_new_object(); // Creates new array index and adds values to it @@ -185,16 +185,19 @@ SDA* portfolio_get_data_array(void) { void* portfolio_store_api_data(void* vsec_data) { SD* sec_data = vsec_data; if (strcmp(sec_data->symbol, "USD$") != 0) { - double* ticker_data = api_get_current_price(sec_data->symbol); - sec_data->current_value = sec_data->amount * ticker_data[0]; + Info* symbol_info = api_get_check_info(sec_data->symbol); + double price_data[3] = { + symbol_info->price, symbol_info->price - symbol_info->price * symbol_info->change_1d / 100, + symbol_info->price - symbol_info->price * symbol_info->change_7d / 100 + }; + sec_data->current_value = sec_data->amount * price_data[0]; sec_data->total_profit = sec_data->current_value - sec_data->total_spent; - sec_data->total_profit_percent = 100 * ((ticker_data[0] / (sec_data->total_spent / sec_data->amount)) - 1); - sec_data->total_profit_percent = 100 * ((ticker_data[0] / (sec_data->total_spent / sec_data->amount)) - 1); - sec_data->one_day_profit = sec_data->current_value - (sec_data->amount * ticker_data[1]); - sec_data->one_day_profit_percent = 100 * ((ticker_data[0] / ticker_data[1]) - 1); - sec_data->seven_day_profit = sec_data->current_value - (sec_data->amount * ticker_data[2]); - sec_data->seven_day_profit_percent = 100 * ((ticker_data[0] / ticker_data[2]) - 1); - free(ticker_data); + sec_data->total_profit_percent = 100 * ((price_data[0] / (sec_data->total_spent / sec_data->amount)) - 1); + sec_data->one_day_profit = sec_data->current_value - (sec_data->amount * price_data[1]); + sec_data->one_day_profit_percent = 100 * ((price_data[0] / price_data[1]) - 1); + sec_data->seven_day_profit = sec_data->current_value - (sec_data->amount * price_data[2]); + sec_data->seven_day_profit_percent = 100 * ((price_data[0] / price_data[2]) - 1); + api_info_destroy(&symbol_info); } else { sec_data->current_value = sec_data->amount; sec_data->total_profit = sec_data->current_value - sec_data->total_spent; |