7b34455eb610283946eeb37a9db571449b9e3c22
[kiosk.git] / stock_renderer.py
1 from bs4 import BeautifulSoup
2 from threading import Thread
3 import datetime
4 import file_writer
5 import json
6 import re
7 import renderer
8 import random
9 import secrets
10 import time
11 import urllib.request, urllib.error, urllib.parse
12
13
14 class stock_quote_renderer(renderer.debuggable_abstaining_renderer):
15     # format exchange:symbol
16     def __init__(self, name_to_timeout_dict, symbols):
17         super(stock_quote_renderer, self).__init__(name_to_timeout_dict, False)
18         self.symbols = symbols
19         self.prefix = "https://www.alphavantage.co/query?"
20         self.thread = None
21
22     def debug_prefix(self):
23         return "stock"
24
25     def get_random_key(self):
26         return random.choice(secrets.alphavantage_keys)
27
28     def periodic_render(self, key):
29         now = datetime.datetime.now()
30         if (
31             now.hour < (9 - 3)
32             or now.hour >= (17 - 3)
33             or datetime.datetime.today().weekday() > 4
34         ):
35             self.debug_print("The stock market is closed so not re-rendering")
36             return True
37
38         if self.thread is None or not self.thread.is_alive():
39             self.debug_print("Spinning up a background thread...")
40             self.thread = Thread(target=self.thread_internal_render, args=())
41             self.thread.start()
42         return True
43
44     def thread_internal_render(self):
45         symbols_finished = 0
46         f = file_writer.file_writer("stock_3_86400.html")
47         f.write("<H1>Stock Quotes</H1><HR>")
48         f.write("<TABLE WIDTH=99%>")
49         for symbol in self.symbols:
50             #            print "---------- Working on %s\n" % symbol
51
52             # https://www.alphavantage.co/query?function=TIME_SERIES_INTRADAY&symbol=MSFT&interval=5min&apikey=<key>
53
54             # https://www.alphavantage.co/query?function=GLOBAL_QUOTE&symbol=MSFT&apikey=<key>
55
56             attempts = 0
57             cooked = ""
58             while True:
59                 key = self.get_random_key()
60                 url = self.prefix + "function=GLOBAL_QUOTE&symbol=%s&apikey=%s" % (
61                     symbol,
62                     key,
63                 )
64                 raw = urllib.request.urlopen(url).read()
65                 cooked = json.loads(raw)
66                 if "Global Quote" not in cooked:
67                     #                    print "%s\n" % cooked
68                     print(
69                         "Failure %d, sleep %d sec...\n" % (attempts + 1, 2 ** attempts)
70                     )
71                     time.sleep(2 ** attempts)
72                     attempts += 1
73                     if attempts > 10:  # we'll wait up to 512 seconds per symbol
74                         break
75                 else:
76                     break
77
78             # These fuckers...
79             if "Global Quote" not in cooked:
80                 print("Can't get data for symbol %s: %s\n" % (symbol, raw))
81                 continue
82             cooked = cooked["Global Quote"]
83
84             # {
85             #   u'Global Quote':
86             #     {
87             #       u'01. symbol': u'MSFT',
88             #       u'02. open': u'151.2900',
89             #       u'03. high': u'151.8900',
90             #       u'04. low': u'150.7650',
91             #       u'05. price': u'151.1300',
92             #       u'06. volume': u'16443559',
93             #       u'07. latest trading day': u'2019-12-10',
94             #       u'08. previous close': u'151.3600',
95             #       u'09. change': u'-0.2300'
96             #       u'10. change percent': u'-0.1520%',
97             #     }
98             # }
99
100             price = "?????"
101             if "05. price" in cooked:
102                 price = cooked["05. price"]
103                 price = price[:-2]
104
105             percent_change = "?????"
106             if "10. change percent" in cooked:
107                 percent_change = cooked["10. change percent"]
108                 if not "-" in percent_change:
109                     percent_change = "+" + percent_change
110
111             change = "?????"
112             cell_color = "#bbbbbb"
113             if "09. change" in cooked:
114                 change = cooked["09. change"]
115                 if "-" in change:
116                     cell_color = "#b00000"
117                 else:
118                     cell_color = "#009000"
119                 change = change[:-2]
120
121             if symbols_finished % 4 == 0:
122                 if symbols_finished > 0:
123                     f.write("</TR>")
124                 f.write("<TR>")
125             symbols_finished += 1
126
127             f.write(
128                 """
129 <TD WIDTH=20%% HEIGHT=150 BGCOLOR="%s">
130   <!-- Container -->
131   <DIV style="position:relative;
132               height:150px;">
133     <!-- Symbol -->
134     <DIV style="position:absolute;
135                 bottom:50;
136                 right:-20;
137                 -webkit-transform:rotate(-90deg);
138                 font-size:28pt;
139                 font-family: helvetica, arial, sans-serif;
140                 font-weight:900;
141                 -webkit-text-stroke: 2px black;
142                 color: #ddd">
143       %s
144     </DIV>
145     <!-- Current price, Change today and percent change today -->
146     <DIV style="position:absolute;
147                 left:10;
148                 top:20;
149                 font-size:23pt;
150                 font-family: helvetica, arial, sans-serif;
151                 width:70%%">
152             $%s<BR>
153             <I>(%s)</I><BR>
154             <B>$%s</B>
155     </DIV>
156   </DIV>
157 </TD>"""
158                 % (cell_color, symbol, price, percent_change, change)
159             )
160         f.write("</TR></TABLE>")
161         f.close()
162         return True
163
164
165 # x = stock_quote_renderer({}, ["MSFT", "GOOG", "GOOGL", "OPTAX", "VNQ"])
166 # x.periodic_render(None)
167 # x.periodic_render(None)