feat: Add real-time price tracking and P/L calculations using yfinance
This commit is contained in:
parent
8ea233ff7c
commit
1416d1b912
@ -14,3 +14,6 @@ pytest
|
||||
# Time zone handling
|
||||
pytz
|
||||
tzdata
|
||||
|
||||
# Real-time data
|
||||
yfinance
|
||||
|
||||
@ -3,6 +3,7 @@ from dataclasses import dataclass
|
||||
from typing import Optional
|
||||
import pytz
|
||||
from zoneinfo import ZoneInfo
|
||||
import yfinance as yf
|
||||
from db.db_connection import create_client
|
||||
from trading.position_calculator import PositionCalculator
|
||||
from utils.data_utils import get_user_input
|
||||
@ -401,6 +402,31 @@ def get_open_trades():
|
||||
'exit_date', 'exit_reason', 'notes', 'created_at']
|
||||
return [dict(zip(columns, row)) for row in result]
|
||||
|
||||
def get_current_prices(tickers: list) -> dict:
|
||||
"""Get current prices for multiple tickers using yfinance"""
|
||||
try:
|
||||
# Create a space-separated string of tickers
|
||||
ticker_str = " ".join(tickers)
|
||||
# Get data for all tickers at once
|
||||
data = yf.download(ticker_str, period="1d", interval="1m", group_by='ticker')
|
||||
|
||||
prices = {}
|
||||
if len(tickers) == 1:
|
||||
# Handle single ticker case
|
||||
ticker = tickers[0]
|
||||
if not data.empty:
|
||||
prices[ticker] = data['Close'].iloc[-1]
|
||||
else:
|
||||
# Handle multiple tickers
|
||||
for ticker in tickers:
|
||||
if (ticker, 'Close') in
|
||||
prices[ticker] = data[ticker]['Close'].iloc[-1]
|
||||
|
||||
return prices
|
||||
except Exception as e:
|
||||
print(f"Error fetching current prices: {e}")
|
||||
return {}
|
||||
|
||||
def get_trade_history(limit: int = 50):
|
||||
with create_client() as client:
|
||||
query = f"""
|
||||
@ -608,26 +634,57 @@ def journal_menu():
|
||||
if not open_trades:
|
||||
print("No open trades found.")
|
||||
else:
|
||||
# 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)
|
||||
|
||||
print("\n=== Open Trades Summary ===")
|
||||
total_portfolio_value = 0
|
||||
total_paper_pl = 0
|
||||
|
||||
for summary in open_summary:
|
||||
ticker = summary['ticker']
|
||||
avg_entry = summary['avg_entry_price']
|
||||
stop_loss = avg_entry * 0.93 # 7% stop loss
|
||||
total_value = avg_entry * summary['total_shares']
|
||||
max_loss = (avg_entry - stop_loss) * summary['total_shares']
|
||||
current_price = current_prices.get(ticker)
|
||||
|
||||
print(f"\n{summary['ticker']} Summary:")
|
||||
print(f"Total Shares: {summary['total_shares']}")
|
||||
stop_loss = avg_entry * 0.93 # 7% stop loss
|
||||
total_shares = summary['total_shares']
|
||||
position_value = avg_entry * total_shares
|
||||
max_loss = (avg_entry - stop_loss) * total_shares
|
||||
|
||||
print(f"\n{ticker} Summary:")
|
||||
print(f"Total Shares: {total_shares}")
|
||||
print(f"Average Entry: ${avg_entry:.2f}")
|
||||
print(f"Total Position Value: ${total_value:.2f}")
|
||||
print(f"Total Position Value: ${position_value:.2f}")
|
||||
print(f"Combined Stop Loss (7%): ${stop_loss:.2f}")
|
||||
print(f"Maximum Loss at Stop: ${max_loss:.2f}")
|
||||
|
||||
if current_price:
|
||||
current_value = current_price * total_shares
|
||||
paper_pl = (current_price - avg_entry) * total_shares
|
||||
pl_percentage = (paper_pl / position_value) * 100
|
||||
total_portfolio_value += current_value
|
||||
total_paper_pl += paper_pl
|
||||
|
||||
print(f"Current Price: ${current_price:.2f}")
|
||||
print(f"Current Value: ${current_value:.2f}")
|
||||
print(f"Paper P/L: ${paper_pl:.2f} ({pl_percentage:.2f}%)")
|
||||
|
||||
print(f"Number of Orders: {summary['num_orders']}")
|
||||
print(f"Position Duration: {summary['last_entry'] - summary['first_entry']}")
|
||||
print("-" * 50)
|
||||
|
||||
if total_portfolio_value > 0:
|
||||
print(f"\nTotal Portfolio Value: ${total_portfolio_value:.2f}")
|
||||
print(f"Total Paper P/L: ${total_paper_pl:.2f}")
|
||||
print(f"Overall P/L %: {(total_paper_pl / (total_portfolio_value - total_paper_pl)) * 100:.2f}%")
|
||||
|
||||
print("\n=== Individual Trades ===")
|
||||
for trade in open_trades:
|
||||
print(f"\nTicker: {trade['ticker']}")
|
||||
ticker = trade['ticker']
|
||||
current_price = current_prices.get(ticker)
|
||||
|
||||
print(f"\nTicker: {ticker}")
|
||||
print(f"Position ID: {trade['position_id']}")
|
||||
print(f"Entry Date: {trade['entry_date']}")
|
||||
print(f"Shares: {trade['shares']}")
|
||||
@ -636,6 +693,13 @@ def journal_menu():
|
||||
print(f"Stop Loss: ${trade['stop_loss']}")
|
||||
print(f"Strategy: {trade['strategy']}")
|
||||
print(f"Order Type: {trade['order_type']}")
|
||||
|
||||
if current_price:
|
||||
paper_pl = (current_price - trade['entry_price']) * trade['shares']
|
||||
pl_percentage = (paper_pl / (trade['entry_price'] * trade['shares'])) * 100
|
||||
print(f"Current Price: ${current_price:.2f}")
|
||||
print(f"Paper P/L: ${paper_pl:.2f} ({pl_percentage:.2f}%)")
|
||||
|
||||
if trade['entry_reason']:
|
||||
print(f"Entry Reason: {trade['entry_reason']}")
|
||||
if trade['notes']:
|
||||
|
||||
Loading…
Reference in New Issue
Block a user