summaryrefslogtreecommitdiff
path: root/stonks.c
diff options
context:
space:
mode:
authorDavid Vazgenovich Shakaryan <dvshakaryan@gmail.com>2021-05-31 06:11:22 -0700
committerDavid Vazgenovich Shakaryan <dvshakaryan@gmail.com>2021-05-31 06:11:22 -0700
commit18bde7391efb9c6bd6ea7846891ab5d16276a809 (patch)
tree237cc152edbdf934ed32e4c8c54c5ce97535e57f /stonks.c
downloadstonks-master.tar.gz
stonks-master.tar.xz
initial importHEADmaster
A bit messy and missing error handling in some places.
Diffstat (limited to 'stonks.c')
-rw-r--r--stonks.c172
1 files changed, 172 insertions, 0 deletions
diff --git a/stonks.c b/stonks.c
new file mode 100644
index 0000000..77b7296
--- /dev/null
+++ b/stonks.c
@@ -0,0 +1,172 @@
+#include "assets.h"
+#include "json_curl.h"
+#include "output.h"
+#include "quotes.h"
+#include "tda.h"
+#include "yahoo.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <lauxlib.h>
+#include <lua.h>
+#include <lualib.h>
+
+#define ASSETS_MAX 100
+
+int load_assets_stock(struct asset **assets, lua_State *L)
+{
+ lua_getglobal(L, "stock");
+ lua_pushnil(L);
+
+ int n = 0;
+ while (lua_next(L, -2)) {
+ struct asset *asset = calloc(1, sizeof(*asset));
+ asset->symbol = strdup(lua_tostring(L, -2));
+ asset->amt = lua_tonumber(L, -1);
+ asset->type = STOCK;
+ assets[n++] = asset;
+
+ lua_pop(L, 1);
+ }
+
+ lua_pop(L, 1);
+ return n;
+}
+
+int load_assets_crypto(struct asset **assets, lua_State *L)
+{
+ lua_getglobal(L, "crypto");
+ lua_pushnil(L);
+
+ int n = 0;
+ while (lua_next(L, -2)) {
+ struct asset *asset = calloc(1, sizeof(*asset));
+ asset->symbol = strdup(lua_tostring(L, -2));
+ asset->amt = lua_tonumber(L, -1);
+ asset->type = CRYPTO;
+ assets[n++] = asset;
+
+ lua_pop(L, 1);
+ }
+
+ lua_pop(L, 1);
+ return n;
+}
+
+static int read_token(const char *path, char *buf, size_t bufsize)
+{
+ FILE *f = fopen(path, "r");
+ if (!f) return 0;
+
+ int ret = 0;
+ if (fgets(buf, bufsize, f)) {
+ ret = 1;
+ char *nl = strchr(buf, '\n');
+ if (nl) *nl = '\0';
+ }
+
+ fclose(f);
+ return ret;
+}
+
+static int write_token(const char *path, char *buf)
+{
+ FILE *f = fopen(path, "w");
+ if (!f) return 0;
+
+ int ret = 0;
+ if (fputs(buf, f) != EOF && fputc('\n', f) != EOF)
+ ret = 1;
+
+ fclose(f);
+ return ret;
+}
+
+int load_tda(struct asset **assets, lua_State *L, struct tda_session **sessptr)
+{
+ int ret = -1;
+ struct tda_session *sess = NULL;
+
+ size_t token_size = 2048;
+ char *token = malloc(token_size);
+ if (!token) goto out;
+
+ lua_getglobal(L, "tda");
+ lua_getfield(L, -1, "account_id");
+ const char *account_id = lua_tostring(L, -1);
+ lua_getfield(L, -2, "client_id");
+ const char *client_id = lua_tostring(L, -1);
+ lua_getfield(L, -3, "token_path");
+ const char *token_path = lua_tostring(L, -1);
+
+ if (read_token(token_path, token, token_size) &&
+ (sess = tda_init(client_id, account_id, token))) {
+ if (write_token(token_path, sess->refresh_token)) {
+ ret = tda_load_assets(sess, assets);
+ } else {
+ tda_cleanup(sess);
+ sess = NULL;
+ }
+ }
+
+ lua_pop(L, 4);
+ free(token);
+out:
+ *sessptr = sess;
+ return ret;
+}
+
+int main()
+{
+ lua_State *L = luaL_newstate();
+ luaL_openlibs(L);
+ luaL_dofile(L, "config.lua");
+ lua_pushcfunction(L, push_field_lua);
+ lua_setglobal(L, "get_asset_field");
+
+ if (curl_global_init(CURL_GLOBAL_DEFAULT) != 0)
+ return 1;
+
+ struct tda_session *tda;
+ struct asset **assets = calloc(ASSETS_MAX, sizeof(*assets));
+ int n_assets = load_tda(assets, L, &tda);
+ n_assets += load_assets_stock(assets + n_assets, L);
+ n_assets += load_assets_crypto(assets + n_assets, L);
+
+ struct quote **quotes;
+ char *symbols;
+ int n_quotes;
+
+ yahoo_get_quote_symbols(assets, n_assets, &symbols);
+ n_quotes = yahoo_get_quotes(symbols, &quotes);
+ free(symbols);
+ add_quotes_to_assets(assets, n_assets, quotes, n_quotes);
+
+ for (int i = 0; i < n_quotes; ++i)
+ quote_free(quotes[i]);
+ free(quotes);
+
+ tda_get_quote_symbols(assets, n_assets, &symbols);
+ n_quotes = tda_get_quotes(tda, symbols, &quotes);
+ free(symbols);
+ add_quotes_to_assets(assets, n_assets, quotes, n_quotes);
+
+ for (int i = 0; i < n_quotes; ++i)
+ quote_free(quotes[i]);
+ free(quotes);
+
+ qsort(assets, n_assets, sizeof(*assets), asset_cmp);
+ n_assets += add_totals(assets, n_assets);
+ output(assets, n_assets, L);
+
+ for (int i = 0; i < n_assets; ++i)
+ asset_free(assets[i]);
+ free(assets);
+
+ tda_cleanup(tda);
+ curl_global_cleanup();
+ lua_close(L);
+ return 0;
+}