The AlphaVantage stock script now uses a cache file that is built slowly while waiting 15 seconds per API call, because the free AlphaVantage API keys are rate limited and only the first stock symbol was being returned.
This commit is contained in:
parent
f78d5d4778
commit
579509fe87
1 changed files with 88 additions and 4 deletions
|
|
@ -1,9 +1,16 @@
|
||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import time
|
||||||
import requests
|
import requests
|
||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta
|
||||||
import argparse
|
import argparse
|
||||||
|
|
||||||
|
CACHE_FILE = os.path.expanduser("~/.cache/mgconky/stocks_alphavantage.txt")
|
||||||
|
API_DELAY_SECONDS = 15
|
||||||
|
USE_CACHE = True
|
||||||
|
|
||||||
def fetch_intraday_data(api_key, symbol, interval="1min"):
|
def fetch_intraday_data(api_key, symbol, interval="1min"):
|
||||||
"""Fetch current and historical intraday price using TIME_SERIES_INTRADAY."""
|
"""Fetch current and historical intraday price using TIME_SERIES_INTRADAY."""
|
||||||
url = "https://www.alphavantage.co/query"
|
url = "https://www.alphavantage.co/query"
|
||||||
|
|
@ -99,6 +106,7 @@ def fetch_historical_data(api_key, symbol, range_in_days):
|
||||||
print(f"Error: Failed to fetch historical data for {symbol} - {e}")
|
print(f"Error: Failed to fetch historical data for {symbol} - {e}")
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
# Parse command-line arguments
|
# Parse command-line arguments
|
||||||
parser = argparse.ArgumentParser(description="Fetch stock data from Alpha Vantage.")
|
parser = argparse.ArgumentParser(description="Fetch stock data from Alpha Vantage.")
|
||||||
|
|
@ -126,9 +134,15 @@ def main():
|
||||||
line_tab3_offset = "${alignr}" # Could also replace this with goto 120 if you don't like the right alignment
|
line_tab3_offset = "${alignr}" # Could also replace this with goto 120 if you don't like the right alignment
|
||||||
|
|
||||||
# Iterate symbols
|
# Iterate symbols
|
||||||
for symbol in symbols:
|
had_success = False
|
||||||
|
for i, symbol in enumerate(symbols):
|
||||||
fetched_data = fetch_intraday_data(args.api_key, symbol) if args.range_in_days < 1 else fetch_historical_data(args.api_key, symbol, args.range_in_days)
|
fetched_data = fetch_intraday_data(args.api_key, symbol) if args.range_in_days < 1 else fetch_historical_data(args.api_key, symbol, args.range_in_days)
|
||||||
if fetched_data:
|
if (
|
||||||
|
isinstance(fetched_data, dict)
|
||||||
|
and "current_price" in fetched_data
|
||||||
|
and isinstance(fetched_data["current_price"], (int, float))
|
||||||
|
):
|
||||||
|
had_success = True
|
||||||
current_price = fetched_data["current_price"]
|
current_price = fetched_data["current_price"]
|
||||||
compare_price = fetched_data["compare_price"]
|
compare_price = fetched_data["compare_price"]
|
||||||
price_difference = current_price - compare_price
|
price_difference = current_price - compare_price
|
||||||
|
|
@ -146,11 +160,81 @@ def main():
|
||||||
else:
|
else:
|
||||||
output.append(f"{symbol}: Error fetching data")
|
output.append(f"{symbol}: Error fetching data")
|
||||||
|
|
||||||
|
# --- Rate limit protection for Alpha Vantage ---
|
||||||
|
if i < len(symbols) - 1:
|
||||||
|
time.sleep(API_DELAY_SECONDS) # wait 15 seconds between queries
|
||||||
|
|
||||||
# Join all parts of the output and print it
|
# Join all parts of the output and print it
|
||||||
header_label = f"Intraday" if args.range_in_days < 1 else f"{args.range_in_days} Day"
|
header_label = f"Intraday" if args.range_in_days < 1 else f"{args.range_in_days} Day"
|
||||||
header_line = f"{line_tab1_offset}{color_header}Ticker{line_tab2_offset}Price ($$){line_tab3_offset}{header_label}{color_label}"
|
header_line = f"{line_tab1_offset}{color_header}Ticker{line_tab2_offset}Price ($$){line_tab3_offset}{header_label}{color_label}"
|
||||||
return header_line + "\n" + f"{line_tab1_offset}{color_header}${{voffset -5}}${{hr 1}}" + "\n" + "\n".join(output)
|
final_output = (
|
||||||
|
header_line
|
||||||
|
+ "\n"
|
||||||
|
+ f"{line_tab1_offset}{color_header}${{voffset -5}}${{hr 1}}"
|
||||||
|
+ "\n"
|
||||||
|
+ "\n".join(output)
|
||||||
|
)
|
||||||
|
|
||||||
|
if had_success:
|
||||||
|
if USE_CACHE:
|
||||||
|
# Save results to cache file
|
||||||
|
os.makedirs(os.path.dirname(CACHE_FILE), exist_ok=True)
|
||||||
|
tmp_file = CACHE_FILE + ".tmp"
|
||||||
|
with open(tmp_file, "w") as f:
|
||||||
|
f.write(final_output)
|
||||||
|
os.replace(tmp_file, CACHE_FILE)
|
||||||
|
else:
|
||||||
|
# Direct output mode (no cache)
|
||||||
|
return final_output
|
||||||
|
else:
|
||||||
|
# No valid data was returned
|
||||||
|
# Do NOT overwrite cache
|
||||||
|
# Do NOT return anything in cache mode
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
print(main())
|
|
||||||
|
# The free alpha vantage plan may require you to rate limit.
|
||||||
|
# Conky will not wait for rate limited output.
|
||||||
|
# We must instead return the previous results
|
||||||
|
# (from when this script was last called)
|
||||||
|
# Set RATE_LIMIT to false if you have the paid plan.
|
||||||
|
if USE_CACHE:
|
||||||
|
|
||||||
|
# Fork immediately so the process Conky launched can exit right away.
|
||||||
|
pid = os.fork()
|
||||||
|
if pid > 0:
|
||||||
|
# PARENT PROCESS (this is the process Conky launched)
|
||||||
|
|
||||||
|
# Return contents of cache file (from early query to Conky)
|
||||||
|
if os.path.exists(CACHE_FILE):
|
||||||
|
try:
|
||||||
|
with open(CACHE_FILE, "r") as f:
|
||||||
|
print(f.read(), end="")
|
||||||
|
sys.stdout.flush()
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
|
# Parent exits immediately ---> Conky renders output
|
||||||
|
sys.exit(0)
|
||||||
|
|
||||||
|
else:
|
||||||
|
# CHILD PROCESS (background updater, not waited on by Conky)
|
||||||
|
|
||||||
|
# Detach from the parent session so Conky does not wait on this process
|
||||||
|
os.setsid()
|
||||||
|
|
||||||
|
# Perform new query
|
||||||
|
main()
|
||||||
|
sys.exit(0)
|
||||||
|
|
||||||
|
else:
|
||||||
|
|
||||||
|
# Return the results to Conky
|
||||||
|
result = main()
|
||||||
|
if result is not None:
|
||||||
|
print(result)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue