- def get_random_key(self):
- return random.choice(secrets.alphavantage_keys)
-
- def periodic_render(self, key):
- now = datetime.datetime.now()
- if (
- now.hour < (9 - 3)
- or now.hour >= (17 - 3)
- or datetime.datetime.today().weekday() > 4
- ):
- self.debug_print("The stock market is closed so not re-rendering")
- return True
-
- if self.thread is None or not self.thread.is_alive():
- self.debug_print("Spinning up a background thread...")
- self.thread = Thread(target=self.thread_internal_render, args=())
- self.thread.start()
- return True
-
- def thread_internal_render(self):
- symbols_finished = 0
- f = file_writer.file_writer("stock_3_86400.html")
- f.write("<H1>Stock Quotes</H1><HR>")
- f.write("<TABLE WIDTH=99%>")
- for symbol in self.symbols:
- # print "---------- Working on %s\n" % symbol
-
- # https://www.alphavantage.co/query?function=TIME_SERIES_INTRADAY&symbol=MSFT&interval=5min&apikey=<key>
-
- # https://www.alphavantage.co/query?function=GLOBAL_QUOTE&symbol=MSFT&apikey=<key>
-
- attempts = 0
- cooked = ""
- while True:
- key = self.get_random_key()
- url = self.prefix + "function=GLOBAL_QUOTE&symbol=%s&apikey=%s" % (
- symbol,
- key,
+ @staticmethod
+ def get_ticker_name(ticker: yf.ticker.Ticker) -> str:
+ """Get friendly name of a ticker."""
+ info = ticker.get_info()
+ if "shortName" in info:
+ return info["shortName"]
+ return ticker
+
+ @staticmethod
+ def get_price(ticker: yf.ticker.Ticker) -> Optional[float]:
+ """Get most recent price of a ticker."""
+ keys = [
+ "bid",
+ "ask",
+ "regularMarketPrice",
+ "lastMarket",
+ "open",
+ "previousClose",
+ ]
+ info = ticker.get_info()
+ for key in keys:
+ if key in info and info[key] is not None and info[key] != 0.0:
+ print(f"Price: picked {key}, ${info[key]}.")
+ return float(info[key])
+ return None
+
+ @staticmethod
+ def get_change_and_delta(
+ ticker: yf.ticker.Ticker, price: float
+ ) -> Tuple[float, float]:
+ """Given the current price, look up opening price and compute delta."""
+ keys = [
+ "previousClose",
+ "open",
+ ]
+ info = ticker.get_info()
+ for key in keys:
+ if key in info and info[key] is not None:
+ print(f"Change: picked {key}, ${info[key]}.")
+ old_price = float(info[key])
+ delta = price - old_price
+ return (delta / old_price * 100.0, delta)
+ return (0.0, 0.0)
+
+ def periodic_render(self, key: str) -> bool:
+ """Write an up-to-date stock page."""
+ with file_writer.file_writer("stock_3_86400.html") as f:
+ f.write("<H1>Stock Quotes</H1><HR>")
+ f.write("<TABLE WIDTH=99%>")
+ symbols_finished = 0
+ for symbol in self.symbols:
+ ticker = yf.Ticker(symbol)
+ # print(ticker.get_info())
+ if ticker is None:
+ self.debug_print(f"Unknown symbol {symbol} -- ignored.")
+ continue
+ name = stock_quote_renderer.get_ticker_name(ticker)
+ price = stock_quote_renderer.get_price(ticker)
+ if price is None:
+ self.debug_print(f"No price information for {symbol} -- skipped.")
+ continue
+ (percent_change, delta) = stock_quote_renderer.get_change_and_delta(
+ ticker, price