diff options
-rw-r--r-- | .SRCINFO | 2 | ||||
-rw-r--r-- | PKGBUILD | 2 | ||||
-rw-r--r-- | api.c | 113 | ||||
-rw-r--r-- | api.h | 60 | ||||
-rw-r--r-- | portfolio.c | 33 | ||||
-rw-r--r-- | tick.1 | 2 |
6 files changed, 183 insertions, 29 deletions
@@ -1,6 +1,6 @@ pkgbase = tick pkgdesc = Command line stock and cryptocurrency portfolio tracker. - pkgver = 1.3.0 + pkgver = 1.4.0 pkgrel = 1 url = https://github.com/aokellermann/tick arch = x86_64 @@ -1,7 +1,7 @@ # Maintainer: Antony Kellermann <aokellermann@gmail.com> pkgname=tick -pkgver=1.3.0 +pkgver=1.4.0 pkgrel=1 pkgdesc="Command line stock and cryptocurrency portfolio tracker." arch=("x86_64") @@ -62,6 +62,19 @@ double api_get_current_price(char* ticker_name_string) { return -1; } +double api_get_1d_price(char* ticker_name_string){ + double val = iex_get_1d_price(ticker_name_string); + if (val != -1) + return val; + val = alphavantage_get_1d_price(ticker_name_string); + if (val != -1) + return val; + val = coinmarketcap_get_1d_price(ticker_name_string); + if (val != -1) + return val; + return -1; +} + double iex_get_current_price(char* ticker_name_string) { size_t ticker_name_len = strlen(ticker_name_string); char* iex_api_string = calloc(64, sizeof(char)); @@ -87,7 +100,7 @@ double alphavantage_get_current_price(char* ticker_name_string) { size_t av_len = strlen(alphavantage_api_string); memcpy(&alphavantage_api_string[av_len], ticker_name_string, 10); String* pString = api_curl_data(alphavantage_api_string); - if (pString->data[0] == '{'){ + if (pString->data[0] == '{') { api_string_destroy(&pString); memset(alphavantage_api_string, '\0', 160); av_str = "https://www.alphavantage.co/query?function=TIME_SERIES_DAILY&apikey=DFUMLJ1ILOM2G7IH&datatype=csv&symbol="; @@ -96,7 +109,7 @@ double alphavantage_get_current_price(char* ticker_name_string) { memcpy(&alphavantage_api_string[av_len], ticker_name_string, 10); pString = api_curl_data(alphavantage_api_string); } - if (pString->data[0] == '{'){ + if (pString->data[0] == '{') { free(alphavantage_api_string); api_string_destroy(&pString); return -1; @@ -105,7 +118,7 @@ double alphavantage_get_current_price(char* ticker_name_string) { for (int j = 0; j < 9; i++, j++) while (pString->data[i] != ',') i++; - char* price_string = (char*)calloc(16, 1); + char* price_string = (char*) calloc(16, 1); for (int j = 0; pString->data[i] != ','; i++, j++) price_string[j] = pString->data[i]; free(alphavantage_api_string); @@ -121,7 +134,7 @@ double coinmarketcap_get_current_price(char* ticker_name_string) { memcpy(coinmarketcap_api_string, cmc_str, 40); memcpy(&coinmarketcap_api_string[40], ticker_name_string, 20); String* pString = api_curl_data(coinmarketcap_api_string); - if (pString->data[0] == '{'){ + if (pString->data[0] == '{') { free(coinmarketcap_api_string); api_string_destroy(&pString); return -1; @@ -130,7 +143,7 @@ double coinmarketcap_get_current_price(char* ticker_name_string) { for (int j = 0; j < 19; i++, j++) while (pString->data[i] != '"') i++; - char* price_string = (char*)calloc(16, 1); + char* price_string = (char*) calloc(16, 1); for (int j = 0; pString->data[i] != '"'; i++, j++) price_string[j] = pString->data[i]; free(coinmarketcap_api_string); @@ -140,10 +153,96 @@ double coinmarketcap_get_current_price(char* ticker_name_string) { return ret; } +double iex_get_1d_price(char* ticker_name_string) { + size_t ticker_name_len = strlen(ticker_name_string); + char* iex_api_string = calloc(64, sizeof(char)); + memcpy(iex_api_string, "https://api.iextrading.com/1.0/stock/", 37); + memcpy(&iex_api_string[37], ticker_name_string, ticker_name_len); + memcpy(&iex_api_string[37 + ticker_name_len], "/previous?format=csv", 21); + + String* pString = api_curl_data(iex_api_string); + free(iex_api_string); + + if (strcmp(pString->data, "Unknown symbol") == 0) { + api_string_destroy(&pString); + return -1; + } + int i = 0; + for (int j = 0; j < 15; i++, j++) + while (pString->data[i] != ',') + i++; + char* price_string = (char*) calloc(16, 1); + for (int j = 0; pString->data[i] != ','; i++, j++) + price_string[j] = pString->data[i]; + double ret = strtod(price_string, NULL); + free(price_string); + api_string_destroy(&pString); + return ret; +} + +double alphavantage_get_1d_price(char* ticker_name_string){ + size_t ticker_name_len = strlen(ticker_name_string); + char* alphavantage_api_string = calloc(128, sizeof(char)); + memcpy(alphavantage_api_string, "https://www.alphavantage.co/query?function=TIME_SERIES_DAILY&apikey=DFUMLJ1ILOM2G7IH&datatype=csv&symbol=", 128); + size_t prefix = strlen(alphavantage_api_string); + memcpy(&alphavantage_api_string[prefix], ticker_name_string, ticker_name_len); + String* pString = api_curl_data(alphavantage_api_string); + if (pString->data[0] == '{') { + free(alphavantage_api_string); + api_string_destroy(&pString); + return -1; + } + int i = 0; + for (int j = 0; j < 14; i++, j++) + while (pString->data[i] != ',') + i++; + char* price_string = (char*) calloc(16, 1); + for (int j = 0; pString->data[i] != ','; i++, j++) + price_string[j] = pString->data[i]; + double ret = strtod(price_string, NULL); + free(alphavantage_api_string); + free(price_string); + api_string_destroy(&pString); + return ret; +} + +double coinmarketcap_get_1d_price(char* ticker_name_string){ + char* cmc_str = "https://api.coinmarketcap.com/v1/ticker/"; + char* coinmarketcap_api_string = calloc(64, sizeof(char)); + memcpy(coinmarketcap_api_string, cmc_str, 40); + memcpy(&coinmarketcap_api_string[40], ticker_name_string, 20); + String* pString = api_curl_data(coinmarketcap_api_string); + if (pString->data[0] == '{') { + free(coinmarketcap_api_string); + api_string_destroy(&pString); + return -1; + } + int i = 0; + for (int j = 0; j < 19; i++, j++) + while (pString->data[i] != '"') + i++; + char* price_string = (char*) calloc(16, 1); + for (int j = 0; pString->data[i] != '"'; i++, j++) + price_string[j] = pString->data[i]; + char* percent_string = (char*) calloc(16, 1); + i = 0; + for (int j = 0; j < 51; i++, j++) + while (pString->data[i] != '"') + i++; + for (int j = 0; pString->data[i] != '"'; i++, j++) + percent_string[j] = pString->data[i]; + free(coinmarketcap_api_string); + double current_price = strtod(price_string, NULL); + double percent_change = strtod(percent_string, NULL); + free(price_string); + free(percent_string); + api_string_destroy(&pString); + return current_price - (current_price * (percent_change/100)); +} + void api_string_destroy(String** phString) { String* pString = *phString; free(pString->data); free(*phString); *phString = NULL; -} - +}
\ No newline at end of file @@ -1,7 +1,8 @@ /** - * API data is taken from IEX Trading and Alpha Vantage + * API data is taken from IEX Trading, Alpha Vantage, and Coinmarketcap. * https://iextrading.com/developer/docs/ * https://www.alphavantage.co/documentation/ + * https://coinmarketcap.com/api/ */ #ifndef IEX_H @@ -35,13 +36,21 @@ String* api_string_init(void); String* api_curl_data(char* url); /** - * Returns current price of a stock + * Returns current price of a stock or cryptocurrency. * @param ticker_name_string symbol * @return current price of stock */ double api_get_current_price(char* ticker_name_string); /** + * If it is a listed security, returns the close price of the previous day. + * If it is a cryptocurrency, returns the price 24 hours ago + * @param ticker_name_string symbol + * @return one day ago's price + */ +double api_get_1d_price(char* ticker_name_string); + +/** * writefunction for cURL HTTP GET * stolen from a nice man on stackoverflow */ @@ -50,27 +59,60 @@ size_t api_string_writefunc(void* ptr, size_t size, size_t nmemb, String* hStrin /** * Returns current price of a stock with data from IEX. * Tested for NASDAQ, NYSE, and NYSEARCA listed stocks/ETFs. - * Fast -- should take less than one second per call + * Fast -- should take less than one second per call. * @param ticker_name_string symbol * @return current price of stock */ double iex_get_current_price(char* ticker_name_string); /** - * Returns current price of a stock. - * If the symbol is not on IEX, Alpha Vantage will be used + * Returns current price of a mutual fund or over-the-counter stock with data from Alpha Vantage. * Tested for MUTF and OTCMKTS listed securities. - * Dreadfully slow -- may take up to ten seconds per call + * Dreadfully slow -- may take up to ten seconds per call. * @param ticker_name_string symbol - * @return current price of stock + * @return current price of security */ double alphavantage_get_current_price(char* ticker_name_string); - +/** + * Returns current price of a cryptocurrency with data from Coinmarketcap. + * All cryptocurrencies listed on Coinmarketcap will work. + * Fast -- should take less than one second per call. + * @param ticker_name_string symbol + * @return current price of cryptocurrency + */ double coinmarketcap_get_current_price(char* ticker_name_string); /** - * Destroys STRING object and frees memory + * Returns previous close price of a stock with data from IEX. + * Tested for NASDAQ, NYSE, and NYSEARCA listed stocks/ETFs. + * Fast -- should take less than one second per call. + * @param ticker_name_string symbol + * @return current price of stock + */ +double iex_get_1d_price(char* ticker_name_string); + +/** + * Returns previous close price of a mutual fund or over-the-counter stock with data from Alpha Vantage. + * Tested for MUTF and OTCMKTS listed securities. + * Dreadfully slow -- may take up to ten seconds per call. + * @param ticker_name_string symbol + * @return current price of security + */ +double alphavantage_get_1d_price(char* ticker_name_string); + +/** + * Returns price 24 hours ago of a cryptocurrency with data from Coinmarketcap. + * If the symbol is not on IEX, Alpha Vantage will be used + * Tested for MUTF and OTCMKTS listed securities. + * Fast -- should take less than one second per call. + * @param ticker_name_string symbol + * @return current price of cryptocurrency + */ +double coinmarketcap_get_1d_price(char* ticker_name_string); + +/** + * Destroys String object and frees memory * @param phString the String to destroy */ void api_string_destroy(String** phString); diff --git a/portfolio.c b/portfolio.c index 5b580a839a80..487a1e828eb6 100644 --- a/portfolio.c +++ b/portfolio.c @@ -62,7 +62,7 @@ void portfolio_modify(char* ticker_name_string, double quantity_shares, double u free(end); fclose(fp); } else { - if (api_get_current_price(ticker_name_string) == -1 && strcmp("USD$", ticker_name_string) != 0) { + if (strlen(ticker_name_string) > 16 || (api_get_current_price(ticker_name_string) == -1 && strcmp("USD$", ticker_name_string) != 0)) { printf("Invalid symbol.\n"); return; } @@ -102,7 +102,7 @@ void portfolio_print_all(FILE* fp) { char* str = (char*) calloc(64, sizeof(char)); char* ticker_name_string = (char*) calloc(32, sizeof(char)); double* data; - double total_owned = 0, total_spent = 0; + double total_owned = 0, total_spent = 0, total_gain_1d = 0; int i; char c; while (fgets(str, 63, fp) != NULL) { @@ -115,32 +115,45 @@ void portfolio_print_all(FILE* fp) { if (data != NULL) { total_owned += data[0]; total_spent += data[1]; + total_gain_1d += data[2]; } memset(str, '\0', 64); memset(ticker_name_string, '\0', 32); free(data); } - printf("\nTotals: Value: $%8.2lf. Expenditure: $%8.2lf. Profit: %6.2lf (%4.2lf%%)\n", - total_owned, total_spent, total_owned - total_spent, (100 * (total_owned - total_spent)) / total_spent); + printf("\nTotals: Value: $%8.2lf. Expenditure: $%8.2lf. Profit: %6.2lf (%4.2lf%%) 1d: %6.2lf (%4.2lf%%)\n", + total_owned, total_spent, total_owned - total_spent, (100 * (total_owned - total_spent)) / total_spent, + total_gain_1d, 100 * total_gain_1d / total_spent); free(str); free(ticker_name_string); } double* portfolio_print_stock(char* ticker_name_string, FILE* fp) { - double* a = malloc(sizeof(double) * 2); + /** + * Values in USD + * a[0] -- current balance + * a[1] -- amount spent + * a[2] -- 1d gain + */ + double* a = malloc(sizeof(double) * 3); a[0] = portfolio_get_quantity_shares(ticker_name_string, fp); a[1] = portfolio_get_usd_spent(ticker_name_string, fp); + a[2] = 0; if (a[0] == 0 && a[1] == 0) { free(a); a = NULL; } else { - double ticker_price_usd = 1; + double ticker_current_price_usd = 1, ticker_1d_price_usd, ticker_1d_percent_change = 0; if (strcmp(ticker_name_string, "USD$") != 0) { - ticker_price_usd = api_get_current_price(ticker_name_string); - a[0] *= ticker_price_usd; + ticker_current_price_usd = api_get_current_price(ticker_name_string); + ticker_1d_price_usd = api_get_1d_price(ticker_name_string); + a[2] = ((ticker_current_price_usd - ticker_1d_price_usd) * a[0]); + ticker_1d_percent_change = 100 * (ticker_current_price_usd / ticker_1d_price_usd - 1); + a[0] *= ticker_current_price_usd; } - printf("%8.2lf %5s. Value: $%8.2lf. Expenditure: $%8.2lf. Profit: %6.2lf (%4.2lf%%)\n", - a[0] / ticker_price_usd, ticker_name_string, a[0], a[1], a[0] - a[1], (100 * (a[0] - a[1])) / a[1]); + printf("%8.2lf %6s. Value: $%8.2lf. Expenditure: $%8.2lf. Profit: %8.2lf (%6.2lf%%). 1d: %8.2lf (%6.2lf%%).\n", + a[0] / ticker_current_price_usd, ticker_name_string, a[0], a[1], a[0] - a[1], (100 * (a[0] - a[1])) / a[1], + a[2], ticker_1d_percent_change); } return a; } @@ -1,4 +1,4 @@ -.TH TICK "1" "January 2018" "Tick 1.3.0" "User Commands" +.TH TICK "1" "January 2018" "Tick 1.4.0" "User Commands" .SH NAME Tick - Command line stock and cryptocurrency portfolio tracker. |