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(): # Initialize session state if 'prefill_watchlist' not in st.session_state: st.session_state.prefill_watchlist = None 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("Save to Watch List") if st.button("Prepare for Watch List", key="prepare_watchlist"): st.session_state.prefill_watchlist = { 'ticker': ticker, 'entry_price': float(entry_price), 'target_price': float(target_price), 'stop_loss': float(position['stop_loss']), 'shares': recommended_shares } st.success("Details saved! Switch to Watch Lists tab to complete adding to your watch list.") 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") # Add new item section with st.expander("Add New Item", expanded=bool(st.session_state.prefill_watchlist)): watchlists = get_watchlists() if watchlists: selected_list = st.selectbox( "Select Watch List", options=[(w['id'], w['name']) for w in watchlists], format_func=lambda x: x[1] ) # Use prefilled data if available prefill = st.session_state.prefill_watchlist or {} # Debug output to verify prefill data if prefill: st.write("Debug - Prefill ", prefill) col1, col2 = st.columns(2) with col1: ticker = st.text_input("Ticker", value=str(prefill.get('ticker', ''))) entry_price = st.number_input("Entry Price", value=float(prefill.get('entry_price') or 0.0), min_value=0.0, step=0.01, format="%.2f") shares = st.number_input("Shares", value=int(prefill.get('shares') or 0), min_value=0, step=1) with col2: target_price = st.number_input("Target Price", value=float(prefill.get('target_price') or 0.0), min_value=0.0, step=0.01, format="%.2f") stop_loss = st.number_input("Stop Loss", value=float(prefill.get('stop_loss') or 0.0), min_value=0.0, step=0.01, format="%.2f") shares = st.number_input("Shares", value=prefill.get('shares', 0), min_value=0, step=1) with col2: target_price = st.number_input("Target Price", value=prefill.get('target_price', 0.0), min_value=0.0, step=0.01, format="%.2f") stop_loss = st.number_input("Stop Loss", value=prefill.get('stop_loss', 0.0), min_value=0.0, step=0.01, format="%.2f") notes = st.text_area("Notes") if st.button("Add to Watch List"): try: ensure_tables_exist() item = WatchlistItem( ticker=ticker, entry_price=entry_price, target_price=target_price, stop_loss=stop_loss, shares=shares, notes=notes ) success = add_to_watchlist(selected_list[0], item) if success: st.success(f"Added {ticker} to watchlist!") # Clear the prefill data st.session_state.prefill_watchlist = None time.sleep(1) st.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") else: st.warning("Please create a watch list first") # Display watch lists st.subheader("Current 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], key="view_watchlist" # Add a unique key to avoid conflicts ) items = get_watchlist_items(selected_watchlist[0]) if items: for item in items: with st.container(): col1, col2, col3, col4, col5, col6 = st.columns([2, 2, 2, 2, 1, 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: st.write(f"Shares: {item.shares:,}") with col6: 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")