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