321 lines
15 KiB
Python
321 lines
15 KiB
Python
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")
|