aboutsummarylogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.SRCINFO2
-rw-r--r--PKGBUILD2
-rw-r--r--api.c113
-rw-r--r--api.h60
-rw-r--r--portfolio.c33
-rw-r--r--tick.12
6 files changed, 183 insertions, 29 deletions
diff --git a/.SRCINFO b/.SRCINFO
index f6cad1408103..6b54836d9e52 100644
--- a/.SRCINFO
+++ b/.SRCINFO
@@ -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
diff --git a/PKGBUILD b/PKGBUILD
index f60f2c5e7bd0..a7308bc3317f 100644
--- a/PKGBUILD
+++ b/PKGBUILD
@@ -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")
diff --git a/api.c b/api.c
index 620ef83f0acd..7c6afbd8a559 100644
--- a/api.c
+++ b/api.c
@@ -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
diff --git a/api.h b/api.h
index 268568fafd21..006fae482486 100644
--- a/api.h
+++ b/api.h
@@ -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;
}
diff --git a/tick.1 b/tick.1
index 0c5e2def2c13..f21e8ea014e7 100644
--- a/tick.1
+++ b/tick.1
@@ -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.