import logging import streamlit as st from trading.journal import get_latest_portfolio_value, get_open_trades_summary from trading.position_calculator import PositionCalculator from utils.data_utils import get_current_prices from pages.analysis.monte_carlo_page import MonteCarloSimulator from datetime import datetime, timedelta import time 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, ensure_tables_exist ) from db.db_connection import create_client # Configure logging logger = logging.getLogger(__name__) def trading_system_page(): st.header("Trading System") # 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 portfolio_data = get_latest_portfolio_value() cash_balance = portfolio_data['cash_balance'] if portfolio_data else 0 # Calculate total portfolio value including open positions open_summary = get_open_trades_summary() total_position_value = 0 total_paper_pl = 0 if open_summary: # Get current prices for all open positions unique_tickers = list(set(summary['ticker'] for summary in open_summary)) current_prices = get_current_prices(unique_tickers) # Calculate total invested value and paper P/L for summary in open_summary: ticker = summary['ticker'] current_price = current_prices.get(ticker, 0) shares = summary['total_shares'] avg_entry = summary['avg_entry_price'] position_value = current_price * shares if current_price else avg_entry * shares total_position_value += position_value total_paper_pl += (current_price - avg_entry) * shares if current_price else 0 total_portfolio_value = cash_balance + total_position_value # Display portfolio information col1, col2, col3 = st.columns(3) with col1: st.info(f"Available Cash: ${cash_balance:,.2f}") with col2: st.info(f"Positions Value: ${total_position_value:,.2f}") with col3: st.info(f"Total Portfolio Value: ${total_portfolio_value:,.2f}") col1, col2 = st.columns(2) with col1: account_size = st.number_input("Account Size ($)", min_value=0.0, value=total_portfolio_value, step=1000.0) risk_percentage = st.number_input("Risk Percentage (%)", min_value=0.1, max_value=100.0, value=1.0, step=0.1) use_monte_carlo = st.checkbox("Use Monte Carlo for Analysis", value=True) if use_monte_carlo: days_out = st.number_input("Days to Project", min_value=1, max_value=30, value=5, help="Number of days to project for target price") confidence_level = st.slider("Confidence Level (%)", min_value=80, max_value=99, value=95) with col2: ticker = st.text_input("Ticker Symbol", value="").upper() entry_price = st.number_input("Entry Price ($)", min_value=0.01, step=0.01) if not use_monte_carlo: target_price = st.number_input("Target Price ($)", min_value=0.01, step=0.01) if st.button("Calculate Position"): try: if not ticker: st.error("Please enter a ticker symbol") return # Get historical data for Monte Carlo simulation if use_monte_carlo: with st.spinner("Calculating optimal stop loss..."): df = get_stock_data( ticker, datetime.now() - timedelta(days=30), # Last 30 days of data datetime.now(), '1m' # Minute data for more accurate simulation ) if df.empty: st.error("No data available for the selected ticker") return # Initialize Monte Carlo simulator # Initialize Monte Carlo simulator simulator = MonteCarloSimulator(df, num_simulations=1000, time_horizon=days_out) # Calculate stop loss and target prices stop_loss_price = simulator.calculate_stop_loss(risk_percentage) target_price = simulator.calculate_target_price(confidence_level) # Calculate stop loss percentage stop_loss_percentage = abs((stop_loss_price - entry_price) / entry_price * 100) else: stop_loss_percentage = 7.0 # Default value if not using Monte Carlo calculator = PositionCalculator( account_size=account_size, risk_percentage=risk_percentage, stop_loss_percentage=stop_loss_percentage ) position = calculator.calculate_position_size(entry_price, target_price) # Calculate maximum shares possible with available cash max_shares_by_cash = int(cash_balance / entry_price) if entry_price > 0 else 0 # Adjust shares based on available cash recommended_shares = min(position['shares'], max_shares_by_cash) col1, col2 = st.columns(2) with col1: if recommended_shares < position['shares']: st.warning( f"Position size limited by available cash.\n" f"Ideal shares: {position['shares']:,}\n" f"Maximum affordable shares: {recommended_shares:,}" ) position_value = recommended_shares * entry_price risk_amount = position['risk_amount'] * (recommended_shares / position['shares']) st.metric("Recommended Shares", f"{recommended_shares:,}") st.metric("Position Value", f"${position_value:,.2f}") st.metric("Risk Amount", f"${risk_amount:,.2f}") else: st.metric("Number of Shares", f"{position['shares']:,}") st.metric("Position Value", f"${position['position_value']:,.2f}") st.metric("Risk Amount", f"${position['risk_amount']:,.2f}") with col2: st.metric("Stop Loss Price", f"${position['stop_loss']:.2f}") st.metric("Potential Loss", f"${position['potential_loss']:,.2f}") if 'potential_profit' in position: potential_profit = (target_price - entry_price) * recommended_shares risk_reward = abs(potential_profit / (position['stop_loss'] - entry_price) / recommended_shares) if recommended_shares > 0 else 0 st.metric("Potential Profit", f"${potential_profit:,.2f}") st.metric("Risk/Reward Ratio", f"{risk_reward:.2f}") # Show percentage of cash being used if recommended_shares > 0: cash_usage = (recommended_shares * entry_price / cash_balance) * 100 portfolio_usage = (recommended_shares * entry_price / total_portfolio_value) * 100 st.info( f"This position would use:\n" f"- {cash_usage:.1f}% of available cash\n" f"- {portfolio_usage:.1f}% of total portfolio" ) # Add Monte Carlo metrics if used if use_monte_carlo: st.subheader("Monte Carlo Analysis") col1, col2, col3 = st.columns(3) with col1: st.metric("Stop Loss Price", f"${stop_loss_price:.2f}") st.metric("Stop Loss %", f"{stop_loss_percentage:.2f}%") with col2: st.metric("Target Price", f"${target_price:.2f}") st.metric("Target %", f"{((target_price - entry_price) / entry_price * 100):.2f}%") with col3: st.metric("Days Projected", f"{days_out}") st.metric("Confidence Level", f"{confidence_level}%") # Add to watchlist option st.divider() st.subheader("Add to Watch List") watchlists = get_watchlists() if not watchlists: st.warning("No watch lists available. Create one in the Watch Lists tab.") else: # Create three columns for better layout col1, col2, col3 = st.columns([2, 2, 1]) with col1: selected_list = st.selectbox( "Select Watch List", options=[(w['id'], w['name']) for w in watchlists], format_func=lambda x: x[1] ) with col2: notes = st.text_area("Notes", key="watchlist_notes") with col3: # Move Debug button outside of conditional if st.button("Debug DB", key="debug_db"): try: with create_client() as client: st.write("=== Watchlists Table ===") watchlists_result = client.query("SELECT * FROM stock_db.watchlists") st.write(watchlists_result.result_rows) st.write("=== Watchlist Items Table ===") items_result = client.query("SELECT * FROM stock_db.watchlist_items") st.write(items_result.result_rows) except Exception as e: st.error(f"Debug query error: {e}") # Move Add to Watch List button outside of columns if st.button("Add to Watch List", key="add_to_watchlist"): try: # Ensure tables exist ensure_tables_exist() # Create watchlist item item = WatchlistItem( ticker=ticker, entry_price=float(entry_price), target_price=float(target_price), stop_loss=float(position['stop_loss']), notes=str(notes) if notes else '' ) # Show debug information st.write("Adding item to watchlist:", { "watchlist_id": selected_list[0], "ticker": item.ticker, "entry_price": item.entry_price, "target_price": item.target_price, "stop_loss": item.stop_loss, "notes": item.notes }) # Add to watchlist success = add_to_watchlist(selected_list[0], item) if success: st.success(f"Added {ticker} to watchlist!") time.sleep(2) st.experimental_rerun() else: st.error("Failed to add to watchlist") except Exception as e: st.error(f"Error: {str(e)}") logger.exception("Error adding to watchlist") except Exception as 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")