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
|
# Time zone handling
|
||||||
pytz
|
pytz
|
||||||
tzdata
|
tzdata
|
||||||
|
|
||||||
|
# Real-time data
|
||||||
|
yfinance
|
||||||
|
|||||||
@ -3,6 +3,7 @@ from dataclasses import dataclass
|
|||||||
from typing import Optional
|
from typing import Optional
|
||||||
import pytz
|
import pytz
|
||||||
from zoneinfo import ZoneInfo
|
from zoneinfo import ZoneInfo
|
||||||
|
import yfinance as yf
|
||||||
from db.db_connection import create_client
|
from db.db_connection import create_client
|
||||||
from trading.position_calculator import PositionCalculator
|
from trading.position_calculator import PositionCalculator
|
||||||
from utils.data_utils import get_user_input
|
from utils.data_utils import get_user_input
|
||||||
@ -401,6 +402,31 @@ def get_open_trades():
|
|||||||
'exit_date', 'exit_reason', 'notes', 'created_at']
|
'exit_date', 'exit_reason', 'notes', 'created_at']
|
||||||
return [dict(zip(columns, row)) for row in result]
|
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):
|
def get_trade_history(limit: int = 50):
|
||||||
with create_client() as client:
|
with create_client() as client:
|
||||||
query = f"""
|
query = f"""
|
||||||
@ -608,26 +634,57 @@ def journal_menu():
|
|||||||
if not open_trades:
|
if not open_trades:
|
||||||
print("No open trades found.")
|
print("No open trades found.")
|
||||||
else:
|
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 ===")
|
print("\n=== Open Trades Summary ===")
|
||||||
|
total_portfolio_value = 0
|
||||||
|
total_paper_pl = 0
|
||||||
|
|
||||||
for summary in open_summary:
|
for summary in open_summary:
|
||||||
|
ticker = summary['ticker']
|
||||||
avg_entry = summary['avg_entry_price']
|
avg_entry = summary['avg_entry_price']
|
||||||
stop_loss = avg_entry * 0.93 # 7% stop loss
|
current_price = current_prices.get(ticker)
|
||||||
total_value = avg_entry * summary['total_shares']
|
|
||||||
max_loss = (avg_entry - stop_loss) * summary['total_shares']
|
|
||||||
|
|
||||||
print(f"\n{summary['ticker']} Summary:")
|
stop_loss = avg_entry * 0.93 # 7% stop loss
|
||||||
print(f"Total Shares: {summary['total_shares']}")
|
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"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"Combined Stop Loss (7%): ${stop_loss:.2f}")
|
||||||
print(f"Maximum Loss at Stop: ${max_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"Number of Orders: {summary['num_orders']}")
|
||||||
print(f"Position Duration: {summary['last_entry'] - summary['first_entry']}")
|
print(f"Position Duration: {summary['last_entry'] - summary['first_entry']}")
|
||||||
print("-" * 50)
|
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 ===")
|
print("\n=== Individual Trades ===")
|
||||||
for trade in open_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"Position ID: {trade['position_id']}")
|
||||||
print(f"Entry Date: {trade['entry_date']}")
|
print(f"Entry Date: {trade['entry_date']}")
|
||||||
print(f"Shares: {trade['shares']}")
|
print(f"Shares: {trade['shares']}")
|
||||||
@ -636,6 +693,13 @@ def journal_menu():
|
|||||||
print(f"Stop Loss: ${trade['stop_loss']}")
|
print(f"Stop Loss: ${trade['stop_loss']}")
|
||||||
print(f"Strategy: {trade['strategy']}")
|
print(f"Strategy: {trade['strategy']}")
|
||||||
print(f"Order Type: {trade['order_type']}")
|
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']:
|
if trade['entry_reason']:
|
||||||
print(f"Entry Reason: {trade['entry_reason']}")
|
print(f"Entry Reason: {trade['entry_reason']}")
|
||||||
if trade['notes']:
|
if trade['notes']:
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user