From c5d7a96e38013c97dac6d8289142227ed8be8ea0 Mon Sep 17 00:00:00 2001 From: "Bobby (aider)" Date: Wed, 12 Feb 2025 17:33:51 -0800 Subject: [PATCH] refactor: Move trading plan page to dedicated module --- src/pages/trading/trading_plan_page.py | 483 +++++++++++++++++++++++ src/streamlit_app.py | 513 +------------------------ 2 files changed, 485 insertions(+), 511 deletions(-) create mode 100644 src/pages/trading/trading_plan_page.py diff --git a/src/pages/trading/trading_plan_page.py b/src/pages/trading/trading_plan_page.py new file mode 100644 index 0000000..a5c6813 --- /dev/null +++ b/src/pages/trading/trading_plan_page.py @@ -0,0 +1,483 @@ +import streamlit as st +from db.db_connection import create_client +from trading.trading_plan import ( + delete_trading_plan, + TradingPlan, PlanStatus, Timeframe, MarketFocus, TradeFrequency, + 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 +) + +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}") + + 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) + + 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}") + + 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") + + 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") + + 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") + + 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") + + 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") + + 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") + + 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: + 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") + + 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") + + 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") + + 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") + + 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") + + 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: + 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)}") + + 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)}") + + st.subheader("Trade Management") + + plan_trades = get_plan_trades(plan.id) + + 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}") + + if st.button("Unlink Trade", key=f"unlink_trade_{trade['id']}"): + try: + 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']}) + + 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)}") + + if st.button("Unlink All Trades", key=f"unlink_all_trades_{plan.id}"): + try: + if unlink_trades_from_plan(plan.id): + 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)}") + + 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!") + + 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") diff --git a/src/streamlit_app.py b/src/streamlit_app.py index 2455dbd..4a82f65 100644 --- a/src/streamlit_app.py +++ b/src/streamlit_app.py @@ -6,25 +6,16 @@ from db.db_connection import create_client from pages.journal.trading_journal_page import trading_journal_page, format_datetime from pages.screener.technical_scanner_page import technical_scanner_page from pages.trading.trading_system_page import trading_system_page +from pages.trading.trading_plan_page import trading_plan_page from trading.journal import ( create_trades_table, get_open_trades, get_trade_history, 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 + create_trading_plan_table, ) -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 pages.screener.canslim_screener_page import canslim_screener_page, load_scanner_reports -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""" @@ -37,506 +28,6 @@ def init_session_state(): -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")