refactor: Move trading journal functionality to separate module
This commit is contained in:
parent
417dbbc596
commit
bf034d9ada
1
src/pages/journal/__init__.py
Normal file
1
src/pages/journal/__init__.py
Normal file
@ -0,0 +1 @@
|
|||||||
|
# Trading journal package
|
||||||
308
src/pages/journal/trading_journal_page.py
Normal file
308
src/pages/journal/trading_journal_page.py
Normal file
@ -0,0 +1,308 @@
|
|||||||
|
import streamlit as st
|
||||||
|
import plotly.graph_objects as go
|
||||||
|
from datetime import datetime
|
||||||
|
import pytz
|
||||||
|
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
|
||||||
|
)
|
||||||
|
|
||||||
|
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}<br>P/L: $%{y:.2f}<extra></extra>')
|
||||||
|
)
|
||||||
|
|
||||||
|
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")
|
||||||
@ -3,12 +3,7 @@ import pandas as pd
|
|||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
import pytz
|
import pytz
|
||||||
from db.db_connection import create_client
|
from db.db_connection import create_client
|
||||||
from trading.journal import (
|
from pages.journal.trading_journal_page import trading_journal_page
|
||||||
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 (
|
from trading.trading_plan import (
|
||||||
delete_trading_plan,
|
delete_trading_plan,
|
||||||
TradingPlan, PlanStatus, Timeframe, MarketFocus, TradeFrequency,
|
TradingPlan, PlanStatus, Timeframe, MarketFocus, TradeFrequency,
|
||||||
@ -54,303 +49,6 @@ def load_scanner_reports():
|
|||||||
# Sort by creation time, newest first
|
# Sort by creation time, newest first
|
||||||
return sorted(reports, key=lambda x: x['created'], reverse=True)
|
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}<br>P/L: $%{y:.2f}<extra></extra>')
|
|
||||||
)
|
|
||||||
|
|
||||||
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():
|
def technical_scanner_page():
|
||||||
st.header("Technical Scanner")
|
st.header("Technical Scanner")
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user