Add real-time market caps
parent
722d294915
commit
d50aa17a83
|
@ -41,15 +41,13 @@ def colorcode(name):
|
||||||
return _colors[name if name else 'gray']
|
return _colors[name if name else 'gray']
|
||||||
|
|
||||||
|
|
||||||
# border size
|
_bs = 3 # border size
|
||||||
_bs = 3
|
|
||||||
_color = [0.13]*3 # nice shade of gray
|
_color = [0.13]*3 # nice shade of gray
|
||||||
|
|
||||||
_kv = (f'''
|
_kv = (f'''
|
||||||
#:kivy 1.10.0
|
#:kivy 1.10.0
|
||||||
|
|
||||||
<Cell>
|
<Cell>
|
||||||
font_size: 20
|
font_size: 18
|
||||||
text_size: self.size
|
text_size: self.size
|
||||||
size: self.texture_size
|
size: self.texture_size
|
||||||
color: {colorcode('gray')}
|
color: {colorcode('gray')}
|
||||||
|
@ -62,7 +60,7 @@ _kv = (f'''
|
||||||
outline_color: [0.1]*4
|
outline_color: [0.1]*4
|
||||||
|
|
||||||
<HeaderCell>
|
<HeaderCell>
|
||||||
font_size: 21
|
font_size: 20
|
||||||
background_color: [0]*4
|
background_color: [0]*4
|
||||||
canvas.before:
|
canvas.before:
|
||||||
Color:
|
Color:
|
||||||
|
@ -91,17 +89,19 @@ _kv = (f'''
|
||||||
''')
|
''')
|
||||||
|
|
||||||
|
|
||||||
# Questrade key conversion
|
# Questrade key conversion / column order
|
||||||
_qt_keys = {
|
_qt_keys = {
|
||||||
# 'symbol': 'symbol', # done manually in qtconvert
|
'symbol': 'symbol', # done manually in qtconvert
|
||||||
|
'%': '%',
|
||||||
'lastTradePrice': 'last',
|
'lastTradePrice': 'last',
|
||||||
'askPrice': 'ask',
|
'askPrice': 'ask',
|
||||||
'bidPrice': 'bid',
|
'bidPrice': 'bid',
|
||||||
'lastTradeSize': 'size',
|
'lastTradeSize': 'size',
|
||||||
'bidSize': 'bsize',
|
'bidSize': 'bsize',
|
||||||
'askSize': 'asize',
|
'askSize': 'asize',
|
||||||
'volume': ('vol', humanize),
|
|
||||||
'VWAP': ('VWAP', partial(round, ndigits=3)),
|
'VWAP': ('VWAP', partial(round, ndigits=3)),
|
||||||
|
'volume': ('vol', humanize),
|
||||||
|
'mktcap': ('mktcap', humanize),
|
||||||
'openPrice': 'open',
|
'openPrice': 'open',
|
||||||
'lowPrice': 'low',
|
'lowPrice': 'low',
|
||||||
'highPrice': 'high',
|
'highPrice': 'high',
|
||||||
|
@ -127,19 +127,25 @@ def qtconvert(
|
||||||
and the second is the same but with all values converted to a
|
and the second is the same but with all values converted to a
|
||||||
"display-friendly" string format.
|
"display-friendly" string format.
|
||||||
"""
|
"""
|
||||||
|
last = quote['lastTradePrice']
|
||||||
|
symbol = quote['symbol']
|
||||||
if symbol_data: # we can only compute % change from symbols data
|
if symbol_data: # we can only compute % change from symbols data
|
||||||
previous = symbol_data[quote['symbol']]['prevDayClosePrice']
|
previous = symbol_data[symbol]['prevDayClosePrice']
|
||||||
change = percent_change(previous, quote['lastTradePrice'])
|
change = percent_change(previous, last)
|
||||||
|
share_count = symbol_data[symbol].get('outstandingShares', None)
|
||||||
|
mktcap = share_count * last if share_count else 'NA'
|
||||||
else:
|
else:
|
||||||
change = 0
|
change = 0
|
||||||
new = {
|
computed = {
|
||||||
'symbol': quote['symbol'],
|
'symbol': quote['symbol'],
|
||||||
'%': round(change, 3)
|
'%': round(change, 3),
|
||||||
|
'mktcap': mktcap,
|
||||||
}
|
}
|
||||||
displayable = new.copy()
|
new = {}
|
||||||
|
displayable = {}
|
||||||
|
|
||||||
for key, new_key in keymap.items():
|
for key, new_key in keymap.items():
|
||||||
display_value = value = quote[key]
|
display_value = value = quote.get(key) or computed.get(key)
|
||||||
|
|
||||||
# API servers can return `None` vals when markets are closed (weekend)
|
# API servers can return `None` vals when markets are closed (weekend)
|
||||||
value = 0 if value is None else value
|
value = 0 if value is None else value
|
||||||
|
@ -263,7 +269,6 @@ class Row(GridLayout):
|
||||||
'last': ['bid', 'ask'],
|
'last': ['bid', 'ask'],
|
||||||
'size': ['bsize', 'asize']
|
'size': ['bsize', 'asize']
|
||||||
}
|
}
|
||||||
# import pdb; pdb.set_trace()
|
|
||||||
ba_cells = {}
|
ba_cells = {}
|
||||||
layouts = {}
|
layouts = {}
|
||||||
for key, children in bidasks.items():
|
for key, children in bidasks.items():
|
||||||
|
@ -309,6 +314,23 @@ class Row(GridLayout):
|
||||||
self.add_widget(cell)
|
self.add_widget(cell)
|
||||||
return cell
|
return cell
|
||||||
|
|
||||||
|
def update(self, record, displayable):
|
||||||
|
# color changed field values
|
||||||
|
for key, val in record.items():
|
||||||
|
# logic for cell text coloring: up-green, down-red
|
||||||
|
if self._last_record[key] < val:
|
||||||
|
color = colorcode('forestgreen')
|
||||||
|
elif self._last_record[key] > val:
|
||||||
|
color = colorcode('red2')
|
||||||
|
else:
|
||||||
|
color = colorcode('gray')
|
||||||
|
|
||||||
|
cell = self.get_cell(key)
|
||||||
|
cell.text = str(displayable[key])
|
||||||
|
cell.color = color
|
||||||
|
|
||||||
|
self._last_record = record
|
||||||
|
|
||||||
|
|
||||||
class TickerTable(GridLayout):
|
class TickerTable(GridLayout):
|
||||||
"""A grid for displaying ticker quote records as a table.
|
"""A grid for displaying ticker quote records as a table.
|
||||||
|
@ -392,9 +414,10 @@ async def update_quotes(
|
||||||
for quote in first_quotes:
|
for quote in first_quotes:
|
||||||
sym = quote['symbol']
|
sym = quote['symbol']
|
||||||
row = grid.symbols2rows[sym]
|
row = grid.symbols2rows[sym]
|
||||||
data, displayable = qtconvert(quote, symbol_data=symbol_data)
|
record, displayable = qtconvert(quote, symbol_data=symbol_data)
|
||||||
color_row(row, data)
|
row.update(record, displayable)
|
||||||
cache[sym] = (data, row)
|
color_row(row, record)
|
||||||
|
cache[sym] = (record, row)
|
||||||
|
|
||||||
grid.render_rows(cache)
|
grid.render_rows(cache)
|
||||||
|
|
||||||
|
@ -403,26 +426,11 @@ async def update_quotes(
|
||||||
log.debug("Waiting on quotes")
|
log.debug("Waiting on quotes")
|
||||||
quotes = await queue.get() # new quotes data only
|
quotes = await queue.get() # new quotes data only
|
||||||
for quote in quotes:
|
for quote in quotes:
|
||||||
data, displayable = qtconvert(quote, symbol_data=symbol_data)
|
record, displayable = qtconvert(quote, symbol_data=symbol_data)
|
||||||
row = grid.symbols2rows[data['symbol']]
|
row = grid.symbols2rows[record['symbol']]
|
||||||
cache[data['symbol']] = (data, row)
|
cache[record['symbol']] = (record, row)
|
||||||
|
row.update(record, displayable)
|
||||||
# color changed field values
|
color_row(row, record)
|
||||||
for key, val in data.items():
|
|
||||||
# logic for cell text coloring: up-green, down-red
|
|
||||||
if row._last_record[key] < val:
|
|
||||||
color = colorcode('forestgreen')
|
|
||||||
elif row._last_record[key] > val:
|
|
||||||
color = colorcode('red2')
|
|
||||||
else:
|
|
||||||
color = colorcode('gray')
|
|
||||||
|
|
||||||
cell = row.get_cell(key)
|
|
||||||
cell.text = str(displayable[key])
|
|
||||||
cell.color = color
|
|
||||||
|
|
||||||
color_row(row, data)
|
|
||||||
row._last_record = data
|
|
||||||
|
|
||||||
grid.render_rows(cache)
|
grid.render_rows(cache)
|
||||||
|
|
||||||
|
@ -458,7 +466,7 @@ async def _async_main(name, watchlists, brokermod):
|
||||||
return
|
return
|
||||||
|
|
||||||
first_quotes = [
|
first_quotes = [
|
||||||
qtconvert(quote, symbol_data=sd)[1] for quote in pkts]
|
qtconvert(quote, symbol_data=sd)[0] for quote in pkts]
|
||||||
|
|
||||||
# build out UI
|
# build out UI
|
||||||
Builder.load_string(_kv)
|
Builder.load_string(_kv)
|
||||||
|
|
Loading…
Reference in New Issue