Implemented add ticker feature. TODO - implement remvoe ticker feature.

This commit is contained in:
George 2024-10-05 11:23:52 -07:00
parent 3ca078f990
commit 1b8612e504

View File

@ -36,6 +36,7 @@ from dotenv import load_dotenv
import psycopg2 import psycopg2
import os import os
import sys import sys
from sec_cik_mapper import StockMapper
pd.options.mode.chained_assignment = None # default='warn' pd.options.mode.chained_assignment = None # default='warn'
load_dotenv() load_dotenv()
@ -81,6 +82,28 @@ def get_watchlist(username : str):
return df return df
def insert_ticker(username : str, tick : str, name : str):
if username:
table_name = f"{username + '_watch_list'}"
else: # username is None, use default table
table_name = "stock_watch_list"
QUERY1 = f'''CREATE TABLE IF NOT EXISTS {table_name}
(
tick character varying(5) NOT NULL,
description text,
PRIMARY KEY (tick)
);'''
QUERY2 = f"INSERT INTO {table_name} SELECT 'SPY', 'SPDR S&P 500 ETF Trust' WHERE NOT EXISTS (SELECT NULL FROM {table_name});"
QUERY3 = f"INSERT INTO {table_name} VALUES ('{tick}', '{name}') ON CONFLICT DO NOTHING;"
with connect_db() as conn:
with conn.cursor() as curs:
curs.execute(QUERY1)
curs.execute(QUERY2)
curs.execute(QUERY3)
def hash_password(password): def hash_password(password):
# Encode the password as bytes # Encode the password as bytes
password_bytes = password.encode('utf-8') password_bytes = password.encode('utf-8')
@ -622,13 +645,19 @@ def fetch_stk_data(sym, sd):
app.layout = [ app.layout = [
html.Div([ html.Div([
html.Button('Load', id="reload-button", n_clicks=0, html.Button('Load', id="reload-button", n_clicks=0,
style={'font-size': '12px', 'width': '120px', 'display': 'inline-block', 'margin-bottom': '10px', 'margin-right': '5px', 'height':'36px', 'verticalAlign': 'top'}), style={'font-size': '12px', 'width': '80px', 'display': 'inline-block', 'margin-bottom': '10px', 'margin-right': '5px', 'height':'36px', 'verticalAlign': 'top'}),
# html.Label('Add ticker:', style={'width': '80px', 'display': 'inline-block', 'height':'36px', 'textAlign': 'center', 'adjust': 'right', 'margin-bottom': '10px', 'margin-right': '5px', 'verticalAlign': 'top'}),
html.Div([
html.Label('Add ticker:'),
dcc.Input(id='input-ticker', type='text', maxLength=5, debounce=True, style={'height':'31px', 'width':'50px'}),
], style={'width': '150px', 'text-align': 'center'}),
html.Button('Remove', id="remove-button", n_clicks=0,
style={'font-size': '12px', 'width': '80px', 'display': 'inline-block', 'margin-bottom': '10px', 'margin-right': '5px', 'height':'36px', 'verticalAlign': 'top'}),
html.Div([ html.Div([
# dcc.Dropdown({'SPY - SPDR S&P 500 ETF Trust'}, 'SPY - SPDR S&P 500 ETF Trust', id='symbols_dropdown_list',),
dcc.Dropdown(id='symbols_dropdown_list',), dcc.Dropdown(id='symbols_dropdown_list',),
], style={'width': '330px', 'text-align': 'center'}), ], style={'width': '330px', 'text-align': 'center'}),
html.Button('Auto Play', id="start-button", n_clicks=0, html.Button('Auto Play', id="start-button", n_clicks=0,
style={'font-size': '12px', 'width': '120px', 'display': 'inline-block', 'margin-bottom': '10px', 'margin-right': '5px', 'height':'36px', 'verticalAlign': 'top'}), style={'font-size': '12px', 'width': '80px', 'display': 'inline-block', 'margin-bottom': '10px', 'margin-right': '5px', 'height':'36px', 'verticalAlign': 'top'}),
], style={'display':'flex', 'justify-content':'center'}), ], style={'display':'flex', 'justify-content':'center'}),
dcc.Graph( dcc.Graph(
@ -644,6 +673,8 @@ app.layout = [
max_intervals=1, max_intervals=1,
disabled=True, disabled=True,
), ),
dcc.Store(id="signaling"),
] ]
app.clientside_callback( app.clientside_callback(
@ -662,6 +693,19 @@ app.clientside_callback(
Input("start-button", "id") Input("start-button", "id")
) )
# tiker input callback
@callback(Output('signaling', component_property='data'),
Input('input-ticker', component_property='value'))
def update_tickers(ticker):
if ticker:
long_name = StockMapper().ticker_to_company_name.get(ticker)
if long_name:
insert_ticker(auth.username, ticker.upper(), long_name)
return True
return no_update
# start / stop button callback # start / stop button callback
@callback(Output('interval-component', 'disabled'), @callback(Output('interval-component', 'disabled'),
Output("start-button", "children"), Output("start-button", "children"),
@ -681,10 +725,11 @@ def start_cycle(n, value):
@callback(Output('symbols_dropdown_list', 'options'), @callback(Output('symbols_dropdown_list', 'options'),
Output('interval-component', 'n_intervals'), Output('interval-component', 'n_intervals'),
Output('interval-component', 'max_intervals'), Output('interval-component', 'max_intervals'),
Input("reload-button", "n_clicks"),) Input("reload-button", "n_clicks"),
Input("signaling", "data"))
def reload_syms(n): def reload_syms(n, s):
if n: if n or s:
watchlist = get_watchlist(auth.username) watchlist = get_watchlist(auth.username)
symbols = (watchlist.iloc[:, 0] + " - " + watchlist.iloc[:, 1]).tolist() symbols = (watchlist.iloc[:, 0] + " - " + watchlist.iloc[:, 1]).tolist()
return symbols, 0, 2*len(symbols) return symbols, 0, 2*len(symbols)