feat: Add watchlist feature with database tables and UI integration
This commit is contained in:
parent
f81e82d171
commit
c00893360e
36
src/migrations/add_watchlist_tables.py
Normal file
36
src/migrations/add_watchlist_tables.py
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
from db.db_connection import create_client
|
||||||
|
|
||||||
|
def create_watchlist_tables():
|
||||||
|
with create_client() as client:
|
||||||
|
cursor = client.cursor()
|
||||||
|
|
||||||
|
# Create watchlists table
|
||||||
|
cursor.execute("""
|
||||||
|
CREATE TABLE IF NOT EXISTS watchlists (
|
||||||
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
|
name TEXT NOT NULL UNIQUE,
|
||||||
|
strategy TEXT,
|
||||||
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||||
|
)
|
||||||
|
""")
|
||||||
|
|
||||||
|
# Create watchlist items table
|
||||||
|
cursor.execute("""
|
||||||
|
CREATE TABLE IF NOT EXISTS watchlist_items (
|
||||||
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
|
watchlist_id INTEGER,
|
||||||
|
ticker TEXT NOT NULL,
|
||||||
|
entry_price REAL,
|
||||||
|
target_price REAL,
|
||||||
|
stop_loss REAL,
|
||||||
|
notes TEXT,
|
||||||
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
FOREIGN KEY (watchlist_id) REFERENCES watchlists(id),
|
||||||
|
UNIQUE(watchlist_id, ticker)
|
||||||
|
)
|
||||||
|
""")
|
||||||
|
|
||||||
|
client.commit()
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
create_watchlist_tables()
|
||||||
@ -5,10 +5,19 @@ from utils.data_utils import get_current_prices
|
|||||||
from pages.analysis.monte_carlo_page import MonteCarloSimulator
|
from pages.analysis.monte_carlo_page import MonteCarloSimulator
|
||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta
|
||||||
from utils.common_utils import get_stock_data
|
from utils.common_utils import get_stock_data
|
||||||
|
from trading.watchlist import (
|
||||||
|
create_watchlist, get_watchlists, add_to_watchlist,
|
||||||
|
remove_from_watchlist, get_watchlist_items, WatchlistItem
|
||||||
|
)
|
||||||
|
|
||||||
def trading_system_page():
|
def trading_system_page():
|
||||||
st.header("Trading System")
|
st.header("Trading System")
|
||||||
st.subheader("Position Calculator")
|
|
||||||
|
# Create tabs
|
||||||
|
tab1, tab2 = st.tabs(["Position Calculator", "Watch Lists"])
|
||||||
|
|
||||||
|
with tab1:
|
||||||
|
st.subheader("Position Calculator")
|
||||||
|
|
||||||
# Get latest portfolio value and open trades for total portfolio calculation
|
# Get latest portfolio value and open trades for total portfolio calculation
|
||||||
portfolio_data = get_latest_portfolio_value()
|
portfolio_data = get_latest_portfolio_value()
|
||||||
@ -173,6 +182,85 @@ def trading_system_page():
|
|||||||
with col3:
|
with col3:
|
||||||
st.metric("Days Projected", f"{days_out}")
|
st.metric("Days Projected", f"{days_out}")
|
||||||
st.metric("Confidence Level", f"{confidence_level}%")
|
st.metric("Confidence Level", f"{confidence_level}%")
|
||||||
|
|
||||||
|
# Add to watchlist option
|
||||||
|
if st.button("Add to Watch List"):
|
||||||
|
watchlists = get_watchlists()
|
||||||
|
if not watchlists:
|
||||||
|
st.warning("No watch lists available. Create one in the Watch Lists tab.")
|
||||||
|
else:
|
||||||
|
selected_list = st.selectbox(
|
||||||
|
"Select Watch List",
|
||||||
|
options=[(w['id'], w['name']) for w in watchlists],
|
||||||
|
format_func=lambda x: x[1]
|
||||||
|
)
|
||||||
|
|
||||||
|
notes = st.text_area("Notes")
|
||||||
|
|
||||||
|
if st.button("Confirm Add to Watch List"):
|
||||||
|
item = WatchlistItem(
|
||||||
|
ticker=ticker,
|
||||||
|
entry_price=entry_price,
|
||||||
|
target_price=target_price,
|
||||||
|
stop_loss=position['stop_loss'],
|
||||||
|
notes=notes
|
||||||
|
)
|
||||||
|
if add_to_watchlist(selected_list[0], item):
|
||||||
|
st.success(f"Added {ticker} to watch list!")
|
||||||
|
else:
|
||||||
|
st.error("Failed to add to watch list")
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
st.error(f"Error calculating position: {str(e)}")
|
st.error(f"Error calculating position: {str(e)}")
|
||||||
|
|
||||||
|
with tab2:
|
||||||
|
st.subheader("Watch Lists")
|
||||||
|
|
||||||
|
# Create new watch list
|
||||||
|
with st.expander("Create New Watch List"):
|
||||||
|
new_list_name = st.text_input("Watch List Name")
|
||||||
|
strategy = st.selectbox(
|
||||||
|
"Strategy",
|
||||||
|
options=["SunnyBand", "Heikin Ashi", "Three ATR EMA", "Other"],
|
||||||
|
index=3
|
||||||
|
)
|
||||||
|
if st.button("Create Watch List"):
|
||||||
|
if new_list_name:
|
||||||
|
create_watchlist(new_list_name, strategy)
|
||||||
|
st.success(f"Created watch list: {new_list_name}")
|
||||||
|
else:
|
||||||
|
st.error("Please enter a watch list name")
|
||||||
|
|
||||||
|
# Display watch lists
|
||||||
|
watchlists = get_watchlists()
|
||||||
|
if watchlists:
|
||||||
|
selected_watchlist = st.selectbox(
|
||||||
|
"Select Watch List to View",
|
||||||
|
options=[(w['id'], w['name']) for w in watchlists],
|
||||||
|
format_func=lambda x: x[1]
|
||||||
|
)
|
||||||
|
|
||||||
|
items = get_watchlist_items(selected_watchlist[0])
|
||||||
|
if items:
|
||||||
|
for item in items:
|
||||||
|
with st.container():
|
||||||
|
col1, col2, col3, col4, col5 = st.columns([2, 2, 2, 2, 1])
|
||||||
|
with col1:
|
||||||
|
st.write(f"**{item.ticker}**")
|
||||||
|
with col2:
|
||||||
|
st.write(f"Entry: ${item.entry_price:.2f}")
|
||||||
|
with col3:
|
||||||
|
st.write(f"Target: ${item.target_price:.2f}")
|
||||||
|
with col4:
|
||||||
|
st.write(f"Stop: ${item.stop_loss:.2f}")
|
||||||
|
with col5:
|
||||||
|
if st.button("Remove", key=f"remove_{item.id}"):
|
||||||
|
if remove_from_watchlist(item.id):
|
||||||
|
st.rerun()
|
||||||
|
if item.notes:
|
||||||
|
st.info(item.notes)
|
||||||
|
st.divider()
|
||||||
|
else:
|
||||||
|
st.info("No items in this watch list")
|
||||||
|
else:
|
||||||
|
st.info("No watch lists created yet")
|
||||||
|
|||||||
71
src/trading/watchlist.py
Normal file
71
src/trading/watchlist.py
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
from dataclasses import dataclass
|
||||||
|
from datetime import datetime
|
||||||
|
from typing import List, Optional
|
||||||
|
from db.db_connection import create_client
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class WatchlistItem:
|
||||||
|
ticker: str
|
||||||
|
entry_price: float
|
||||||
|
target_price: float
|
||||||
|
stop_loss: float
|
||||||
|
notes: Optional[str] = None
|
||||||
|
watchlist_id: Optional[int] = None
|
||||||
|
id: Optional[int] = None
|
||||||
|
created_at: Optional[datetime] = None
|
||||||
|
|
||||||
|
def create_watchlist(name: str, strategy: Optional[str] = None) -> int:
|
||||||
|
with create_client() as client:
|
||||||
|
cursor = client.cursor()
|
||||||
|
cursor.execute(
|
||||||
|
"INSERT INTO watchlists (name, strategy) VALUES (?, ?)",
|
||||||
|
(name, strategy)
|
||||||
|
)
|
||||||
|
return cursor.lastrowid
|
||||||
|
|
||||||
|
def get_watchlists() -> List[dict]:
|
||||||
|
with create_client() as client:
|
||||||
|
cursor = client.cursor()
|
||||||
|
cursor.execute("SELECT * FROM watchlists ORDER BY name")
|
||||||
|
return [dict(row) for row in cursor.fetchall()]
|
||||||
|
|
||||||
|
def add_to_watchlist(watchlist_id: int, item: WatchlistItem) -> bool:
|
||||||
|
with create_client() as client:
|
||||||
|
cursor = client.cursor()
|
||||||
|
try:
|
||||||
|
cursor.execute("""
|
||||||
|
INSERT INTO watchlist_items
|
||||||
|
(watchlist_id, ticker, entry_price, target_price, stop_loss, notes)
|
||||||
|
VALUES (?, ?, ?, ?, ?, ?)
|
||||||
|
""", (watchlist_id, item.ticker, item.entry_price, item.target_price,
|
||||||
|
item.stop_loss, item.notes))
|
||||||
|
client.commit()
|
||||||
|
return True
|
||||||
|
except Exception:
|
||||||
|
return False
|
||||||
|
|
||||||
|
def remove_from_watchlist(item_id: int) -> bool:
|
||||||
|
with create_client() as client:
|
||||||
|
cursor = client.cursor()
|
||||||
|
cursor.execute("DELETE FROM watchlist_items WHERE id = ?", (item_id,))
|
||||||
|
return cursor.rowcount > 0
|
||||||
|
|
||||||
|
def get_watchlist_items(watchlist_id: Optional[int] = None) -> List[WatchlistItem]:
|
||||||
|
with create_client() as client:
|
||||||
|
cursor = client.cursor()
|
||||||
|
if watchlist_id:
|
||||||
|
cursor.execute("""
|
||||||
|
SELECT i.*, w.name as watchlist_name, w.strategy
|
||||||
|
FROM watchlist_items i
|
||||||
|
JOIN watchlists w ON w.id = i.watchlist_id
|
||||||
|
WHERE watchlist_id = ?
|
||||||
|
ORDER BY i.created_at DESC
|
||||||
|
""", (watchlist_id,))
|
||||||
|
else:
|
||||||
|
cursor.execute("""
|
||||||
|
SELECT i.*, w.name as watchlist_name, w.strategy
|
||||||
|
FROM watchlist_items i
|
||||||
|
JOIN watchlists w ON w.id = i.watchlist_id
|
||||||
|
ORDER BY i.created_at DESC
|
||||||
|
""")
|
||||||
|
return [WatchlistItem(**row) for row in cursor.fetchall()]
|
||||||
Loading…
Reference in New Issue
Block a user