import streamlit as st import pandas as pd from datetime import datetime import pytz from db.db_connection import create_client from trading.journal import ( create_trades_table, get_open_trades, get_trade_history, add_trade, update_trade, delete_trade, TradeEntry, get_open_trades_summary, get_current_prices, generate_position_id, get_position_summary, get_latest_portfolio_value, update_portfolio_value ) from trading.trading_plan import ( delete_trading_plan, TradingPlan, PlanStatus, Timeframe, MarketFocus, TradeFrequency, create_trading_plan_table, save_trading_plan, get_trading_plan, get_all_trading_plans, update_trading_plan, get_plan_trades, link_trades_to_plan, calculate_plan_metrics, unlink_trades_from_plan ) from trading.position_calculator import PositionCalculator from pages.rules.strategy_guide_page import strategy_guide_page from screener.scanner_controller import run_technical_scanner from screener.canslim_controller import run_canslim_screener from trading.portfolio import Portfolio, Position from trading.position_calculator import PositionCalculator import plotly.graph_objects as go from plotly.subplots import make_subplots def init_session_state(): """Initialize session state variables""" if 'page' not in st.session_state: st.session_state.page = 'Trading Journal' def load_scanner_reports(): """Load and return available scanner reports""" import os import pandas as pd from datetime import datetime reports = [] reports_dir = "reports" if os.path.exists(reports_dir): for file in os.listdir(reports_dir): if file.endswith(".csv"): file_path = os.path.join(reports_dir, file) # Get file creation time created = datetime.fromtimestamp(os.path.getctime(file_path)) reports.append({ 'name': file, 'path': file_path, 'created': created }) # Sort by creation time, newest first return sorted(reports, key=lambda x: x['created'], reverse=True) def format_datetime(dt): """Format datetime for display""" if dt: return dt.strftime('%Y-%m-%d %H:%M') return '' def plot_trade_history(trades): """Create a P/L chart using Plotly""" if not trades: return None # Prepare data dates = [] pnl = [] cumulative_pnl = 0 for trade in trades: if trade['exit_price']: trade_pnl = (trade['exit_price'] - trade['entry_price']) * trade['shares'] cumulative_pnl += trade_pnl dates.append(trade['exit_date']) pnl.append(cumulative_pnl) if not dates: return None # Create figure fig = go.Figure() fig.add_trace( go.Scatter(x=dates, y=pnl, mode='lines+markers', name='Cumulative P/L', line=dict(color='blue'), hovertemplate='Date: %{x}
P/L: $%{y:.2f}') ) fig.update_layout( title='Cumulative Profit/Loss Over Time', xaxis_title='Date', yaxis_title='Cumulative P/L ($)', hovermode='x unified' ) return fig def trading_journal_page(): st.header("Trading Journal") # Tabs for different journal functions tab1, tab2, tab3, tab4 = st.tabs(["Open Positions", "Add Trade", "Update Trade", "Trade History"]) with tab1: st.subheader("Open Positions") open_trades = get_open_trades() open_summary = get_open_trades_summary() if open_summary: # Get current prices unique_tickers = list(set(summary['ticker'] for summary in open_summary)) current_prices = get_current_prices(unique_tickers) total_portfolio_value = 0 total_paper_pl = 0 for summary in open_summary: with st.expander(f"{summary['ticker']} Summary"): ticker = summary['ticker'] avg_entry = summary['avg_entry_price'] current_price = current_prices.get(ticker) total_shares = summary['total_shares'] position_value = avg_entry * total_shares col1, col2 = st.columns(2) with col1: st.metric("Total Shares", f"{total_shares:,}") st.metric("Average Entry", f"${avg_entry:.2f}") st.metric("Position Value", f"${position_value:.2f}") with col2: if current_price: current_value = current_price * total_shares paper_pl = (current_price - avg_entry) * total_shares pl_percentage = (paper_pl / position_value) * 100 st.metric("Current Price", f"${current_price:.2f}") st.metric("Paper P/L", f"${paper_pl:.2f}", f"{pl_percentage:.2f}%") total_portfolio_value += current_value total_paper_pl += paper_pl if total_portfolio_value > 0: st.markdown("---") st.subheader("Portfolio Summary") col1, col2 = st.columns(2) with col1: st.metric("Total Portfolio Value", f"${total_portfolio_value:.2f}") with col2: st.metric("Total P/L", f"${total_paper_pl:.2f}", f"{(total_paper_pl / (total_portfolio_value - total_paper_pl)) * 100:.2f}%") with tab2: st.subheader("Add New Trade") ticker = st.text_input("Ticker Symbol").upper() # Add direction selection direction = st.selectbox( "Direction", ["Buy", "Sell"], key="trade_direction" ) if ticker: # Show existing positions for this ticker existing_positions = get_position_summary(ticker) if existing_positions: st.write(f"Existing {ticker} Positions:") for pos in existing_positions: st.write(f"Position ID: {pos['position_id']}") st.write(f"Total Shares: {pos['total_shares']}") st.write(f"Average Entry: ${pos['avg_entry_price']:.2f}") if direction == "Sell": position_id = st.selectbox( "Select Position to Exit", options=[pos['position_id'] for pos in existing_positions], key="position_select" ) else: # Buy add_to_existing = st.checkbox("Add to existing position") if add_to_existing: position_id = st.selectbox( "Select Position ID", options=[pos['position_id'] for pos in existing_positions], key="position_select" ) else: position_id = generate_position_id(ticker) else: if direction == "Sell": st.error("No existing positions found for this ticker") st.stop() position_id = generate_position_id(ticker) col1, col2 = st.columns(2) with col1: shares = st.number_input("Number of Shares", min_value=1, step=1) if direction == "Buy": entry_price = st.number_input("Entry Price", min_value=0.01, step=0.01) else: entry_price = st.number_input("Exit Price", min_value=0.01, step=0.01) with col2: if direction == "Buy": target_price = st.number_input("Target Price", min_value=0.01, step=0.01) stop_loss = st.number_input("Stop Loss", min_value=0.01, step=0.01) strategy = st.text_input("Strategy") else: exit_reason = st.text_area("Exit Reason", key="exit_reason") order_type = st.selectbox("Order Type", ["Market", "Limit"], key="add_trade_order_type") entry_date = st.date_input("Entry Date") entry_time = st.time_input("Entry Time") if direction == "Buy": followed_rules = st.checkbox("Followed Trading Rules") entry_reason = st.text_area("Entry Reason", key="add_trade_reason") notes = st.text_area("Notes", key="add_trade_notes") if st.button("Add Trade"): try: entry_datetime = datetime.combine(entry_date, entry_time) entry_datetime = pytz.timezone('US/Pacific').localize(entry_datetime) trade = TradeEntry( ticker=ticker, entry_date=entry_datetime, shares=shares, entry_price=entry_price, target_price=target_price if direction == "Buy" else None, stop_loss=stop_loss if direction == "Buy" else None, strategy=strategy if direction == "Buy" else None, order_type=order_type, position_id=position_id, followed_rules=followed_rules if direction == "Buy" else None, entry_reason=entry_reason if direction == "Buy" else None, exit_reason=exit_reason if direction == "Sell" else None, notes=notes, direction=direction.lower() ) add_trade(trade) st.success("Trade added successfully!") st.query_params(rerun=True) except Exception as e: st.error(f"Error adding trade: {str(e)}") with tab3: st.subheader("Update Trade") open_trades = get_open_trades() if open_trades: trade_id = st.selectbox( "Select Trade to Update", options=[t['id'] for t in open_trades], format_func=lambda x: f"{next(t['ticker'] for t in open_trades if t['id'] == x)} - {x}", key="trade_select" ) trade = next(t for t in open_trades if t['id'] == trade_id) col1, col2 = st.columns(2) with col1: new_shares = st.number_input("Shares", value=trade['shares']) new_entry = st.number_input("Entry Price", value=float(trade['entry_price'])) new_target = st.number_input("Target Price", value=float(trade['target_price'])) with col2: new_stop = st.number_input("Stop Loss", value=float(trade['stop_loss'])) new_strategy = st.text_input("Strategy", value=trade['strategy']) new_order_type = st.selectbox("Order Type", ["Market", "Limit"], index=0 if trade['order_type'] == "Market" else 1, key="update_trade_order_type") # Add date and time fields entry_date = st.date_input( "Entry Date", value=trade['entry_date'].date(), key="update_entry_date" ) entry_time = st.time_input( "Entry Time", value=trade['entry_date'].time(), key="update_entry_time" ) new_notes = st.text_area("Notes", value=trade['notes'] if trade['notes'] else "", key="update_trade_notes") if st.button("Update Trade"): try: # Combine date and time into datetime entry_datetime = datetime.combine(entry_date, entry_time) entry_datetime = pytz.timezone('US/Pacific').localize(entry_datetime) updates = { 'entry_date': entry_datetime, 'shares': new_shares, 'entry_price': new_entry, 'target_price': new_target, 'stop_loss': new_stop, 'strategy': new_strategy, 'order_type': new_order_type, 'notes': new_notes } update_trade(trade_id, updates) st.success("Trade updated successfully!") st.query_params(rerun=True) except Exception as e: st.error(f"Error updating trade: {str(e)}") else: st.info("No open trades to update") with tab4: st.subheader("Trade History") history = get_trade_history() if history: # Add P/L chart fig = plot_trade_history(history) if fig: st.plotly_chart(fig, use_container_width=True) for trade in history: with st.expander(f"{trade['ticker']} - {format_datetime(trade['entry_date'])}"): profit_loss = (trade['exit_price'] - trade['entry_price']) * trade['shares'] if trade['exit_price'] else None col1, col2 = st.columns(2) with col1: st.metric("Entry Price", f"${trade['entry_price']:.2f}") st.metric("Shares", trade['shares']) if profit_loss: st.metric("P/L", f"${profit_loss:.2f}") with col2: if trade['exit_price']: st.metric("Exit Price", f"${trade['exit_price']:.2f}") st.metric("Exit Date", format_datetime(trade['exit_date'])) st.text(f"Strategy: {trade['strategy']}") if trade['notes']: st.text(f"Notes: {trade['notes']}") else: st.info("No trade history found") def technical_scanner_page(): st.header("Technical Scanner") # Create tabs for scanner and reports scanner_tab, reports_tab = st.tabs(["Run Scanner", "View Reports"]) with scanner_tab: scanner_type = st.selectbox( "Select Scanner", ["SunnyBands", "ATR-EMA", "ATR-EMA v2"], key="tech_scanner_type" ) # Add interval selection interval = st.selectbox( "Select Time Interval", ["Daily", "5 minute", "15 minute", "30 minute", "1 hour"], key="interval_select" ) # Convert interval to format expected by scanner interval_map = { "Daily": "1d", "5 minute": "5m", "15 minute": "15m", "30 minute": "30m", "1 hour": "1h" } selected_interval = interval_map[interval] # Date range selection date_col1, date_col2 = st.columns(2) with date_col1: start_date = st.date_input("Start Date") with date_col2: end_date = st.date_input("End Date") col1, col2 = st.columns(2) with col1: min_price = st.number_input("Minimum Price", value=5.0, step=0.1) max_price = st.number_input("Maximum Price", value=100.0, step=0.1) with col2: min_volume = st.number_input("Minimum Volume", value=500000, step=100000) portfolio_size = st.number_input("Portfolio Size", value=100000.0, step=1000.0) if st.button("Run Scanner"): with st.spinner("Running scanner..."): try: signals = run_technical_scanner( scanner_choice=scanner_type.lower().replace(" ", "_"), start_date=start_date.strftime("%Y-%m-%d"), end_date=end_date.strftime("%Y-%m-%d"), min_price=min_price, max_price=max_price, min_volume=min_volume, portfolio_size=portfolio_size, interval=selected_interval ) if signals: st.success(f"Found {len(signals)} signals") for signal in signals: with st.expander(f"{signal['ticker']} - ${signal['entry_price']:.2f}"): col1, col2 = st.columns(2) with col1: st.metric("Entry Price", f"${signal['entry_price']:.2f}") st.metric("Target", f"${signal['target_price']:.2f}") st.metric("Stop Loss", f"${signal['stop_loss']:.2f}") with col2: st.metric("Shares", signal['shares']) st.metric("Position Size", f"${signal['position_size']:.2f}") st.metric("Risk Amount", f"${abs(signal['risk_amount']):.2f}") else: st.info("No signals found") except Exception as e: st.error(f"Error running scanner: {str(e)}") with reports_tab: st.subheader("Scanner Reports") reports = load_scanner_reports() if reports: # Create a selectbox to choose the report selected_report = st.selectbox( "Select Report", options=reports, format_func=lambda x: f"{x['name']} ({x['created'].strftime('%Y-%m-%d %H:%M')})", key="tech_scanner_report" ) if selected_report: try: # Load and display the CSV df = pd.read_csv(selected_report['path']) # Add download button st.download_button( label="Download Report", data=df.to_csv(index=False), file_name=selected_report['name'], mime='text/csv' ) # Display the dataframe st.dataframe(df) except Exception as e: st.error(f"Error loading report: {str(e)}") else: st.info("No scanner reports found") def canslim_screener_page(): st.header("CANSLIM Screener") # Create tabs for scanner and reports scanner_tab, reports_tab = st.tabs(["Run Scanner", "View Reports"]) with scanner_tab: # Date range selection col1, col2 = st.columns(2) with col1: start_date = st.date_input("Start Date") with col2: end_date = st.date_input("End Date") # CANSLIM criteria selection st.subheader("Select Screening Criteria") c_criteria = st.expander("Current Quarterly Earnings (C)") with c_criteria: eps_threshold = st.slider("EPS Growth Threshold (%)", 0, 100, 25) sales_threshold = st.slider("Sales Growth Threshold (%)", 0, 100, 25) roe_threshold = st.slider("ROE Threshold (%)", 0, 50, 17) a_criteria = st.expander("Annual Earnings Growth (A)") with a_criteria: annual_eps_threshold = st.slider("Annual EPS Growth Threshold (%)", 0, 100, 25) l_criteria = st.expander("Industry Leadership (L)") with l_criteria: use_l = st.checkbox("Check Industry Leadership", value=True) l_threshold = st.slider("Industry Leadership Score Threshold", 0.0, 1.0, 0.7) i_criteria = st.expander("Institutional Sponsorship (I)") with i_criteria: use_i = st.checkbox("Check Institutional Sponsorship", value=True) i_threshold = st.slider("Institutional Sponsorship Score Threshold", 0.0, 1.0, 0.7) if st.button("Run CANSLIM Screener"): with st.spinner("Running CANSLIM screener..."): try: # Prepare selected screeners dictionary selected_screeners = { "C": { "EPS_Score": eps_threshold / 100, "Sales_Score": sales_threshold / 100, "ROE_Score": roe_threshold / 100 }, "A": { "Annual_EPS_Score": annual_eps_threshold / 100 } } if use_l: selected_screeners["L"] = {"L_Score": l_threshold} if use_i: selected_screeners["I"] = {"I_Score": i_threshold} # Convert dates to strings for the screener start_str = start_date.strftime("%Y-%m-%d") end_str = end_date.strftime("%Y-%m-%d") # Run the screener st.session_state.screener_params = { "start_date": start_str, "end_date": end_str, "selected_screeners": selected_screeners } # Modify run_canslim_screener to accept parameters run_canslim_screener() st.success("Screening complete! Check the Reports tab for results.") except Exception as e: st.error(f"Error running CANSLIM screener: {str(e)}") with reports_tab: st.subheader("CANSLIM Reports") # Use the same report loading function but look in a CANSLIM-specific directory reports = load_scanner_reports() # You might want to modify this to look in a CANSLIM directory if reports: # Create a selectbox to choose the report selected_report = st.selectbox( "Select Report", options=reports, format_func=lambda x: f"{x['name']} ({x['created'].strftime('%Y-%m-%d %H:%M')})", key="canslim_scanner_report" ) if selected_report: try: # Load and display the CSV df = pd.read_csv(selected_report['path']) # Add download button st.download_button( label="Download Report", data=df.to_csv(index=False), file_name=selected_report['name'], mime='text/csv' ) # Display the dataframe st.dataframe(df) except Exception as e: st.error(f"Error loading report: {str(e)}") else: st.info("No CANSLIM reports found") def trading_system_page(): st.header("Trading System") # Create tabs calc_tab, portfolio_tab, value_tab = st.tabs(["Position Calculator", "Portfolio Management", "Portfolio Value"]) with calc_tab: st.subheader("Position Calculator") # Get latest portfolio value for default account size portfolio_data = get_latest_portfolio_value() default_account_size = portfolio_data['total_value'] if portfolio_data else 100000.0 col1, col2 = st.columns(2) with col1: account_size = st.number_input("Account Size ($)", min_value=0.0, value=default_account_size, step=1000.0) risk_percentage = st.number_input("Risk Percentage (%)", min_value=0.1, max_value=100.0, value=1.0, step=0.1) stop_loss_percentage = st.number_input("Stop Loss Percentage (%)", min_value=0.1, max_value=100.0, value=7.0, step=0.1) with col2: entry_price = st.number_input("Entry Price ($)", min_value=0.01, step=0.01) target_price = st.number_input("Target Price ($)", min_value=0.01, step=0.01) if st.button("Calculate Position"): try: 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) col1, col2 = st.columns(2) with col1: 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: st.metric("Potential Profit", f"${position['potential_profit']:,.2f}") st.metric("Risk/Reward Ratio", f"{position['risk_reward_ratio']:.2f}") except Exception as e: st.error(f"Error calculating position: {str(e)}") with portfolio_tab: st.subheader("Portfolio Management") # Initialize portfolio if not in session state if 'portfolio' not in st.session_state: st.session_state.portfolio = Portfolio() # Load existing open trades into portfolio open_trades = get_open_trades() for trade in open_trades: position = Position( symbol=trade['ticker'], entry_date=trade['entry_date'], entry_price=trade['entry_price'], shares=trade['shares'], stop_loss=trade['stop_loss'], target_price=trade['target_price'] ) st.session_state.portfolio.add_position(position) # Add position form with st.expander("Add New Position"): col1, col2 = st.columns(2) with col1: symbol = st.text_input("Symbol").upper() shares = st.number_input("Number of Shares", min_value=1, step=1) entry_price = st.number_input("Entry Price ($)", min_value=0.01, step=0.01, key="port_entry_price") with col2: target_price = st.number_input("Target Price ($)", min_value=0.01, step=0.01, key="port_target_price") stop_loss = st.number_input("Stop Loss ($)", min_value=0.01, step=0.01) if st.button("Add Position"): try: position = Position( symbol=symbol, entry_date=datetime.now(), entry_price=entry_price, shares=shares, stop_loss=stop_loss, target_price=target_price ) st.session_state.portfolio.add_position(position) st.success(f"Added position: {symbol}") except Exception as e: st.error(f"Error adding position: {str(e)}") # Display current portfolio positions = st.session_state.portfolio.get_position_summary() if positions: st.subheader("Current Positions") # Add a counter to make unique keys for i, pos in enumerate(positions): with st.expander(f"{pos['symbol']} Position - {format_datetime(pos['entry_date'])}"): col1, col2 = st.columns(2) with col1: st.metric("Entry Price", f"${pos['entry_price']:.2f}") st.metric("Shares", pos['shares']) st.metric("Current Value", f"${pos['current_value']:.2f}") with col2: st.metric("Stop Loss", f"${pos['stop_loss']:.2f}") st.metric("Target", f"${pos['target_price']:.2f}") st.metric("Risk/Reward", f"{pos['risk_reward_ratio']:.2f}") if st.button(f"Remove {pos['symbol']}", key=f"remove_{pos['symbol']}_{i}"): st.session_state.portfolio.remove_position(pos['symbol']) st.rerun() else: st.info("No positions in portfolio") with value_tab: st.subheader("Portfolio Value Management") # Get latest portfolio value portfolio_data = get_latest_portfolio_value() if portfolio_data: st.metric("Current Portfolio Value", f"${portfolio_data['total_value']:,.2f}") st.metric("Cash Balance", f"${portfolio_data['cash_balance']:,.2f}") st.text(f"Last Updated: {portfolio_data['date']}") else: st.info("No portfolio value data found") # Update portfolio value form with st.expander("Update Portfolio Value"): new_value = st.number_input("New Portfolio Value ($)", min_value=0.0, step=100.0) new_cash = st.number_input("New Cash Balance ($)", min_value=0.0, step=100.0) notes = st.text_area("Notes (optional)", key="portfolio_value_notes") if st.button("Update Values"): try: update_portfolio_value(new_value, new_cash, notes) st.success("Portfolio value updated successfully!") st.set_query_params(rerun=True) except Exception as e: st.error(f"Error updating portfolio value: {str(e)}") def trading_plan_page(): st.header("Trading Plans") # Create tabs for different plan operations list_tab, add_tab, edit_tab = st.tabs(["View Plans", "Add Plan", "Edit Plan"]) with list_tab: st.subheader("Trading Plans") plans = get_all_trading_plans() if plans: for plan in plans: with st.expander(f"{plan.plan_name} ({plan.status.value})"): col1, col2 = st.columns(2) with col1: st.markdown("### Basic Information") st.write(f"**Plan Name:** {plan.plan_name}") st.write(f"**Status:** {plan.status.value}") st.write(f"**Author:** {plan.plan_author}") st.write(f"**Version:** {plan.strategy_version}") st.write(f"**Created:** {plan.created_at}") st.write(f"**Updated:** {plan.updated_at}") st.markdown("### Market Details") st.write(f"**Timeframe:** {plan.timeframe.value}") st.write(f"**Market:** {plan.market_focus.value}") st.write(f"**Frequency:** {plan.trade_frequency.value}") if plan.sector_focus: st.write(f"**Sector Focus:** {plan.sector_focus}") with col2: st.markdown("### Risk Parameters") st.write(f"**Stop Loss:** {plan.stop_loss}%") st.write(f"**Profit Target:** {plan.profit_target}%") st.write(f"**Risk/Reward Ratio:** {plan.risk_reward_ratio}") st.write(f"**Position Size:** {plan.position_sizing}%") st.write(f"**Risk per Trade:** {plan.total_risk_per_trade}%") st.write(f"**Max Portfolio Risk:** {plan.max_portfolio_risk}%") st.write(f"**Max Drawdown:** {plan.maximum_drawdown}%") st.write(f"**Max Trades/Day:** {plan.max_trades_per_day}") st.write(f"**Max Trades/Week:** {plan.max_trades_per_week}") st.markdown("### Performance Metrics") if any([plan.win_rate, plan.average_return_per_trade, plan.profit_factor]): col3, col4 = st.columns(2) with col3: if plan.win_rate: st.write(f"**Win Rate:** {plan.win_rate}%") if plan.average_return_per_trade: st.write(f"**Avg Return/Trade:** {plan.average_return_per_trade}%") with col4: if plan.profit_factor: st.write(f"**Profit Factor:** {plan.profit_factor}") # Add Linked Trades section st.markdown("### Linked Trades") plan_trades = get_plan_trades(plan.id) if plan_trades: total_pl = 0 winning_trades = 0 total_trades = len(plan_trades) # Display trade statistics first st.markdown("#### Trade Statistics") col1, col2 = st.columns(2) with col1: st.write(f"**Total Trades:** {total_trades}") st.write(f"**Winning Trades:** {winning_trades}") if total_trades > 0: st.write(f"**Win Rate:** {(winning_trades/total_trades)*100:.2f}%") with col2: st.write(f"**Total P/L:** ${total_pl:.2f}") if total_trades > 0: st.write(f"**Average P/L per Trade:** ${total_pl/total_trades:.2f}") # Display trades in a table format instead of nested expanders st.markdown("#### Individual Trades") for trade in plan_trades: st.markdown("---") cols = st.columns(3) with cols[0]: st.write(f"**{trade['ticker']} - {trade['entry_date']}**") st.write(f"**Direction:** {trade['direction']}") if trade['strategy']: st.write(f"**Strategy:** {trade['strategy']}") with cols[1]: st.write(f"**Entry:** ${trade['entry_price']:.2f}") st.write(f"**Shares:** {trade['shares']}") with cols[2]: if trade['exit_price']: pl = (trade['exit_price'] - trade['entry_price']) * trade['shares'] total_pl += pl if pl > 0: winning_trades += 1 st.write(f"**Exit:** ${trade['exit_price']:.2f}") st.write(f"**P/L:** ${pl:.2f}") st.write(f"**Exit Date:** {trade['exit_date']}") else: st.write("**Status:** Open") else: st.info("No trades linked to this plan") st.markdown("### Strategy Details") st.write("**Entry Criteria:**") st.write(plan.entry_criteria) st.write("**Exit Criteria:**") st.write(plan.exit_criteria) st.write("**Entry Confirmation:**") st.write(plan.entry_confirmation) st.write("**Market Conditions:**") st.write(plan.market_conditions) st.write("**Technical Indicators:**") st.write(plan.indicators_used) st.markdown("### Risk Management") st.write("**Drawdown Adjustments:**") st.write(plan.adjustments_for_drawdown) st.write("**Risk Controls:**") st.write(plan.risk_controls) if plan.fundamental_criteria: st.markdown("### Fundamental Analysis") st.write(plan.fundamental_criteria) if plan.options_strategy_details: st.markdown("### Options Strategy") st.write(plan.options_strategy_details) if plan.improvements_needed: st.markdown("### Areas for Improvement") st.write(plan.improvements_needed) if plan.trade_review_notes: st.markdown("### Trade Review Notes") st.write(plan.trade_review_notes) if plan.future_testing_ideas: st.markdown("### Future Testing Ideas") st.write(plan.future_testing_ideas) if plan.historical_backtest_results: st.markdown("### Historical Backtest Results") st.write(plan.historical_backtest_results) if plan.real_trade_performance: st.markdown("### Real Trading Performance") st.write(plan.real_trade_performance) else: st.info("No trading plans found") with add_tab: st.subheader("Create New Trading Plan") # Basic Info col1, col2 = st.columns(2) with col1: plan_name = st.text_input("Plan Name", key="add_plan_name") status = st.selectbox("Status", [s.value for s in PlanStatus], key="add_status") timeframe = st.selectbox("Timeframe", [t.value for t in Timeframe], key="add_timeframe") market_focus = st.selectbox("Market Focus", [m.value for m in MarketFocus], key="add_market_focus") with col2: trade_frequency = st.selectbox("Trade Frequency", [f.value for f in TradeFrequency], key="add_trade_frequency") plan_author = st.text_input("Author", key="add_plan_author") strategy_version = st.number_input("Version", min_value=1, value=1, key="add_strategy_version") # Risk Parameters st.subheader("Risk Parameters") col1, col2 = st.columns(2) with col1: stop_loss = st.number_input("Stop Loss %", min_value=0.1, value=7.0, key="add_stop_loss") profit_target = st.number_input("Profit Target %", min_value=0.1, value=21.0, key="add_profit_target") risk_reward_ratio = profit_target / stop_loss if stop_loss > 0 else 0 st.write(f"Risk:Reward Ratio: {risk_reward_ratio:.2f}") with col2: position_sizing = st.number_input("Position Size %", min_value=0.1, value=5.0, key="add_position_sizing") total_risk_per_trade = st.number_input("Risk per Trade %", min_value=0.1, value=1.0, key="add_total_risk_per_trade") max_portfolio_risk = st.number_input("Max Portfolio Risk %", min_value=0.1, value=5.0, key="add_max_portfolio_risk") # Trade Rules st.subheader("Trade Rules") col1, col2 = st.columns(2) with col1: max_trades_per_day = st.number_input("Max Trades per Day", min_value=1, value=3, key="add_max_trades_per_day") max_trades_per_week = st.number_input("Max Trades per Week", min_value=1, value=15, key="add_max_trades_per_week") maximum_drawdown = st.number_input("Maximum Drawdown %", min_value=0.1, value=20.0, key="add_maximum_drawdown") # Strategy Details st.subheader("Strategy Details") entry_criteria = st.text_area("Entry Criteria", key="add_entry_criteria") exit_criteria = st.text_area("Exit Criteria", key="add_exit_criteria") entry_confirmation = st.text_area("Entry Confirmation", key="add_entry_confirmation") market_conditions = st.text_area("Market Conditions", key="add_market_conditions") indicators_used = st.text_area("Technical Indicators", key="add_indicators_used") # Risk Management st.subheader("Risk Management") adjustments_for_drawdown = st.text_area("Drawdown Adjustments", key="add_adjustments_for_drawdown") risk_controls = st.text_area("Risk Controls", key="add_risk_controls") # Optional Fields st.subheader("Additional Information") col1, col2 = st.columns(2) with col1: sector_focus = st.text_input("Sector Focus (optional)", key="add_sector_focus") fundamental_criteria = st.text_area("Fundamental Criteria (optional)", key="add_fundamental_criteria") with col2: options_strategy_details = st.text_area("Options Strategy Details (optional)", key="add_options_strategy_details") improvements_needed = st.text_area("Improvements Needed (optional)", key="add_improvements_needed") if st.button("Create Trading Plan", key="create_plan_button"): try: plan = TradingPlan( plan_name=plan_name, status=PlanStatus(status), timeframe=Timeframe(timeframe), market_focus=MarketFocus(market_focus), trade_frequency=TradeFrequency(trade_frequency), entry_criteria=entry_criteria, exit_criteria=exit_criteria, stop_loss=stop_loss, profit_target=profit_target, risk_reward_ratio=risk_reward_ratio, entry_confirmation=entry_confirmation, position_sizing=position_sizing, maximum_drawdown=maximum_drawdown, max_trades_per_day=max_trades_per_day, max_trades_per_week=max_trades_per_week, total_risk_per_trade=total_risk_per_trade, max_portfolio_risk=max_portfolio_risk, adjustments_for_drawdown=adjustments_for_drawdown, risk_controls=risk_controls, market_conditions=market_conditions, indicators_used=indicators_used, plan_author=plan_author, strategy_version=strategy_version, sector_focus=sector_focus, fundamental_criteria=fundamental_criteria, options_strategy_details=options_strategy_details, improvements_needed=improvements_needed ) save_trading_plan(plan) st.success("Trading plan created successfully!") st.query_params.update(rerun=True) except Exception as e: st.error(f"Error creating trading plan: {str(e)}") with edit_tab: st.subheader("Edit Trading Plan") plans = get_all_trading_plans() if plans: selected_plan_id = st.selectbox( "Select Plan to Edit", options=[plan.id for plan in plans], format_func=lambda x: next(p.plan_name for p in plans if p.id == x), key="edit_plan_select" ) if selected_plan_id: plan = get_trading_plan(selected_plan_id) if plan: # Basic Info col1, col2 = st.columns(2) with col1: plan_name = st.text_input("Plan Name", value=plan.plan_name, key="edit_plan_name") status = st.selectbox("Status", [s.value for s in PlanStatus], index=[s.value for s in PlanStatus].index(plan.status.value), key="edit_status") timeframe = st.selectbox("Timeframe", [t.value for t in Timeframe], index=[t.value for t in Timeframe].index(plan.timeframe.value), key="edit_timeframe") market_focus = st.selectbox("Market Focus", [m.value for m in MarketFocus], index=[m.value for m in MarketFocus].index(plan.market_focus.value), key="edit_market_focus") with col2: trade_frequency = st.selectbox("Trade Frequency", [f.value for f in TradeFrequency], index=[f.value for f in TradeFrequency].index(plan.trade_frequency.value), key="edit_trade_frequency") plan_author = st.text_input("Author", value=plan.plan_author, key="edit_plan_author") strategy_version = st.number_input("Version", min_value=1, value=plan.strategy_version, key="edit_strategy_version") # Risk Parameters st.subheader("Risk Parameters") col1, col2 = st.columns(2) with col1: stop_loss = st.number_input("Stop Loss %", min_value=0.1, value=plan.stop_loss, key="edit_stop_loss") profit_target = st.number_input("Profit Target %", min_value=0.1, value=plan.profit_target, key="edit_profit_target") risk_reward_ratio = profit_target / stop_loss if stop_loss > 0 else 0 st.write(f"Risk:Reward Ratio: {risk_reward_ratio:.2f}") with col2: position_sizing = st.number_input("Position Size %", min_value=0.1, value=plan.position_sizing, key="edit_position_sizing") total_risk_per_trade = st.number_input("Risk per Trade %", min_value=0.1, value=plan.total_risk_per_trade, key="edit_total_risk_per_trade") max_portfolio_risk = st.number_input("Max Portfolio Risk %", min_value=0.1, value=plan.max_portfolio_risk, key="edit_max_portfolio_risk") # Trade Rules st.subheader("Trade Rules") col1, col2 = st.columns(2) with col1: max_trades_per_day = st.number_input("Max Trades per Day", min_value=1, value=plan.max_trades_per_day, key="edit_max_trades_per_day") max_trades_per_week = st.number_input("Max Trades per Week", min_value=1, value=plan.max_trades_per_week, key="edit_max_trades_per_week") maximum_drawdown = st.number_input("Maximum Drawdown %", min_value=0.1, value=plan.maximum_drawdown, key="edit_maximum_drawdown") # Strategy Details st.subheader("Strategy Details") entry_criteria = st.text_area("Entry Criteria", value=plan.entry_criteria, key="edit_entry_criteria") exit_criteria = st.text_area("Exit Criteria", value=plan.exit_criteria, key="edit_exit_criteria") entry_confirmation = st.text_area("Entry Confirmation", value=plan.entry_confirmation, key="edit_entry_confirmation") market_conditions = st.text_area("Market Conditions", value=plan.market_conditions, key="edit_market_conditions") indicators_used = st.text_area("Technical Indicators", value=plan.indicators_used, key="edit_indicators_used") # Risk Management st.subheader("Risk Management") adjustments_for_drawdown = st.text_area("Drawdown Adjustments", value=plan.adjustments_for_drawdown, key="edit_adjustments_for_drawdown") risk_controls = st.text_area("Risk Controls", value=plan.risk_controls, key="edit_risk_controls") # Optional Fields st.subheader("Additional Information") col1, col2 = st.columns(2) with col1: sector_focus = st.text_input("Sector Focus (optional)", value=plan.sector_focus, key="edit_sector_focus") fundamental_criteria = st.text_area("Fundamental Criteria (optional)", value=plan.fundamental_criteria, key="edit_fundamental_criteria") with col2: options_strategy_details = st.text_area("Options Strategy Details (optional)", value=plan.options_strategy_details, key="edit_options_strategy_details") improvements_needed = st.text_area("Improvements Needed (optional)", value=plan.improvements_needed, key="edit_improvements_needed") if st.button("Update Plan", key="update_plan_button"): try: # Update the plan with new values plan.plan_name = plan_name plan.status = PlanStatus(status) plan.timeframe = Timeframe(timeframe) plan.market_focus = MarketFocus(market_focus) plan.trade_frequency = TradeFrequency(trade_frequency) plan.plan_author = plan_author plan.strategy_version = strategy_version plan.stop_loss = stop_loss plan.profit_target = profit_target plan.position_sizing = position_sizing plan.total_risk_per_trade = total_risk_per_trade plan.max_portfolio_risk = max_portfolio_risk plan.max_trades_per_day = max_trades_per_day plan.max_trades_per_week = max_trades_per_week plan.maximum_drawdown = maximum_drawdown plan.entry_criteria = entry_criteria plan.exit_criteria = exit_criteria plan.entry_confirmation = entry_confirmation plan.market_conditions = market_conditions plan.indicators_used = indicators_used plan.adjustments_for_drawdown = adjustments_for_drawdown plan.risk_controls = risk_controls plan.sector_focus = sector_focus plan.fundamental_criteria = fundamental_criteria plan.options_strategy_details = options_strategy_details plan.improvements_needed = improvements_needed update_trading_plan(plan) st.success("Plan updated successfully!") st.query_params.update(rerun=True) except Exception as e: st.error(f"Error updating plan: {str(e)}") # Delete button (at the same level as the update button) if st.button("Delete Plan", key="delete_plan_button"): try: delete_trading_plan(plan.id) st.success("Plan deleted successfully!") st.query_params.update(rerun=True) except Exception as e: st.error(f"Error deleting plan: {str(e)}") # Add Trade Management section st.subheader("Trade Management") # Get current trades for this plan plan_trades = get_plan_trades(plan.id) # Display current trades if plan_trades: st.write("Current Trades:") for trade in plan_trades: with st.expander(f"{trade['ticker']} - {trade['entry_date']}"): col1, col2 = st.columns(2) with col1: st.write(f"Entry: ${trade['entry_price']:.2f}") st.write(f"Shares: {trade['shares']}") with col2: if trade['exit_price']: pl = (trade['exit_price'] - trade['entry_price']) * trade['shares'] st.write(f"Exit: ${trade['exit_price']:.2f}") st.write(f"P/L: ${pl:.2f}") # Add unlink button for each trade if st.button("Unlink Trade", key=f"unlink_trade_{trade['id']}"): try: # Update the single trade query = """ ALTER TABLE stock_db.trades UPDATE plan_id = NULL WHERE id = %(trade_id)s """ with create_client() as client: client.command(query, {'trade_id': trade['id']}) # Recalculate metrics metrics = calculate_plan_metrics(plan.id) plan.win_rate = metrics['win_rate'] plan.average_return_per_trade = metrics['average_return'] plan.profit_factor = metrics['profit_factor'] update_trading_plan(plan) st.success(f"Trade unlinked successfully!") st.query_params.update(rerun=True) except Exception as e: st.error(f"Error unlinking trade: {str(e)}") # Add button to unlink all trades if st.button("Unlink All Trades", key=f"unlink_all_trades_{plan.id}"): try: if unlink_trades_from_plan(plan.id): # Reset metrics plan.win_rate = None plan.average_return_per_trade = None plan.profit_factor = None update_trading_plan(plan) st.success("All trades unlinked successfully!") st.query_params.update(rerun=True) else: st.error("Error unlinking trades") except Exception as e: st.error(f"Error unlinking trades: {str(e)}") # Get available trades with create_client() as client: query = """ SELECT id, ticker, entry_date, entry_price, shares, exit_price, exit_date, direction, strategy, CASE WHEN exit_price IS NOT NULL THEN (exit_price - entry_price) * shares ELSE NULL END as profit_loss FROM stock_db.trades WHERE plan_id IS NULL ORDER BY entry_date DESC """ result = client.query(query) available_trades = [dict(zip( ['id', 'ticker', 'entry_date', 'entry_price', 'shares', 'exit_price', 'exit_date', 'direction', 'strategy', 'profit_loss'], row )) for row in result.result_rows] if available_trades: st.write("Link Existing Trades:") selected_trades = st.multiselect( "Select trades to link to this plan", options=[t['id'] for t in available_trades], format_func=lambda x: next( f"{t['ticker']} - {t['entry_date']} - ${t['entry_price']:.2f} " f"({t['direction']}) - {t['strategy']} " f"{'[Closed]' if t['exit_price'] else '[Open]'} " f"{'P/L: $' + format(t['profit_loss'], '.2f') if t['profit_loss'] is not None else ''}" for t in available_trades if t['id'] == x ), key=f"link_trades_{plan.id}" ) if selected_trades and st.button("Link Selected Trades", key=f"link_trades_button_{plan.id}"): if link_trades_to_plan(plan.id, selected_trades): st.success("Trades linked successfully!") # Calculate and update metrics metrics = calculate_plan_metrics(plan.id) plan.win_rate = metrics['win_rate'] plan.average_return_per_trade = metrics['average_return'] plan.profit_factor = metrics['profit_factor'] update_trading_plan(plan) st.query_params.update(rerun=True) else: st.error("Error linking trades") else: st.info("No plans available to edit") def main(): st.set_page_config(page_title="Trading System", layout="wide") init_session_state() # Sidebar navigation st.sidebar.title("Navigation") st.session_state.page = st.sidebar.radio( "Go to", ["Strategy Guide", "Trading Journal", "Technical Scanner", "CANSLIM Screener", "Trading System", "Trading Plans"] ) # Create necessary tables create_trades_table() create_trading_plan_table() # Display selected page if st.session_state.page == "Strategy Guide": strategy_guide_page() elif st.session_state.page == "Trading Journal": trading_journal_page() elif st.session_state.page == "Technical Scanner": technical_scanner_page() elif st.session_state.page == "CANSLIM Screener": canslim_screener_page() elif st.session_state.page == "Trading System": trading_system_page() elif st.session_state.page == "Trading Plans": trading_plan_page() if __name__ == "__main__": main()