diff --git a/.DS_Store b/.DS_Store index 1b9a277..baf4f10 100644 Binary files a/.DS_Store and b/.DS_Store differ diff --git a/backend/.DS_Store b/backend/.DS_Store index 375798d..2622bc1 100644 Binary files a/backend/.DS_Store and b/backend/.DS_Store differ diff --git a/backend/myapp/__pycache__/graph_all_holdings_day.cpython-38.pyc b/backend/myapp/__pycache__/graph_all_holdings_day.cpython-38.pyc new file mode 100644 index 0000000..ecb0f20 Binary files /dev/null and b/backend/myapp/__pycache__/graph_all_holdings_day.cpython-38.pyc differ diff --git a/backend/myapp/__pycache__/graph_stock_holdings_day.cpython-38.pyc b/backend/myapp/__pycache__/graph_stock_holdings_day.cpython-38.pyc index 96d856c..915c1cb 100644 Binary files a/backend/myapp/__pycache__/graph_stock_holdings_day.cpython-38.pyc and b/backend/myapp/__pycache__/graph_stock_holdings_day.cpython-38.pyc differ diff --git a/backend/myapp/__pycache__/urls.cpython-38.pyc b/backend/myapp/__pycache__/urls.cpython-38.pyc index 165cfff..4fc1b37 100644 Binary files a/backend/myapp/__pycache__/urls.cpython-38.pyc and b/backend/myapp/__pycache__/urls.cpython-38.pyc differ diff --git a/backend/myapp/graph_all_holdings_day.py b/backend/myapp/graph_all_holdings_day.py new file mode 100644 index 0000000..2c684cb --- /dev/null +++ b/backend/myapp/graph_all_holdings_day.py @@ -0,0 +1,89 @@ +import json +from django.http import JsonResponse +from django.conf import settings +from pathlib import Path +import yfinance as yf +import pytz +from datetime import datetime, timedelta +from collections import defaultdict + +# Your timezone, for example, 'UTC' +timezone = pytz.timezone('EST') + +def get_current_shares_held(ticker): + if not ticker: + return JsonResponse({"error": "Ticker symbol is required."}, status=400) + + # Define the path to the JSON file + json_file_path = Path(settings.BASE_DIR) / 'data' / 'investments_data.json' + + # Open the JSON file and load its content + with open(json_file_path, 'r') as file: + transactions_data = json.load(file) + + transactions = [t for t in transactions_data if t['Ticker Symbol'] == ticker] + + if not transactions: + return JsonResponse({"error": "No transactions found for given ticker."}, status=404) + + current_shares = 0.0 + + # Calculate the current number of shares held + for transaction in transactions: + shares = float(transaction["No. of Shares"]) + if transaction["Transaction Type"] == "BUY": + current_shares += shares + elif transaction["Transaction Type"] == "SELL": + current_shares -= shares + + return current_shares + +def get_all_holdings_day(request): + json_file_path = Path(settings.BASE_DIR) / 'data' / 'investments_data.json' + + with open(json_file_path, 'r') as file: + transactions_data = json.load(file) + + # Get a list of unique tickers + tickers = set(t['Ticker Symbol'] for t in transactions_data) + + # Aggregated data for all stocks + aggregated_data = defaultdict(lambda: {"total_value": 0, "value_paid": 0}) + + # Store previous day's closing value + total_value_paid = 0 + + for ticker in tickers: + shares_held = get_current_shares_held(ticker) + + if shares_held <= 0: + continue + + stock = yf.Ticker(ticker) + today = datetime.now(tz=timezone).date() + + # Find most recent market day with data + for i in range(7): + check_day = today - timedelta(days=i) + day_data = stock.history(period='1d', interval='1m', start=check_day, end=check_day + timedelta(days=1)) + prev_day_data = stock.history(period="2d", interval="1d") + if not day_data.empty and len(prev_day_data) >= 2: + previous_close = prev_day_data['Close'].iloc[-2] + total_value_paid += previous_close * shares_held + break + + if day_data.empty or len(prev_day_data) < 2: + continue # Skip if no data available + + for time, row in day_data.iterrows(): + # Add the value of this stock to the aggregated data + aggregated_data[time]["total_value"] += row['Close'] * shares_held + aggregated_data[time]["value_paid"] = total_value_paid + + # Convert aggregated data to a list format suitable for JsonResponse + historical_values = [{"date": time.tz_convert(timezone).strftime('%Y-%m-%d %H:%M:%S'), + "total_value": data["total_value"], + "value_paid": data["value_paid"]} + for time, data in aggregated_data.items()] + + return JsonResponse(historical_values, safe=False) \ No newline at end of file diff --git a/backend/myapp/graph_stock_holdings_day.py b/backend/myapp/graph_stock_holdings_day.py index fbabe2d..7d8e8e7 100644 --- a/backend/myapp/graph_stock_holdings_day.py +++ b/backend/myapp/graph_stock_holdings_day.py @@ -42,22 +42,26 @@ def get_stock_history_day(request, ticker): return JsonResponse({"error": "Ticker symbol is required."}, status=400) stock = yf.Ticker(ticker) - # Get today's date and yesterday's date in the specified timezone today = datetime.now(tz=timezone).date() - yesterday = today - timedelta(days=1) - # Fetch today's data - today_data = stock.history(period='1d', interval='1m', start=today, end=today + timedelta(days=1)) + # Initialize variable to hold historical prices + historical_prices = None - if today_data.empty: # If today's data is empty, assume the market is closed - # Fetch previous day's data - historical_prices = stock.history(period='1d', interval='1m', start=yesterday, end=today) - else: - historical_prices = today_data + # Loop to find the most recent market day with data + for i in range(7): # Check up to a week back + check_day = today - timedelta(days=i) + day_data = stock.history(period='1d', interval='1m', start=check_day, end=check_day + timedelta(days=1)) + + if not day_data.empty: + historical_prices = day_data + break + + if historical_prices is None: + return JsonResponse({"error": "No recent market data available."}, status=404) shares_held = get_current_shares_held(ticker) - current_open_time = today_data.index[0] - + current_open_time = historical_prices.index[0] + # Fetch the previous day's closing price previous_day_data = stock.history(period="2d", interval="1d") if len(previous_day_data) < 2: @@ -78,8 +82,8 @@ def get_stock_history_day(request, ticker): # Add rest of the historical values historical_values.extend([{ "date": date.tz_convert(timezone).strftime('%Y-%m-%d %H:%M:%S'), - "value": row['Close'] * shares_held, # Current value of shares held - "value_paid": previous_close_paid # Value based on previous day's close + "value": row['Close'] * shares_held, + "value_paid": previous_close_paid } for date, row in historical_prices.iterrows()]) - return JsonResponse(historical_values, safe=False) + return JsonResponse(historical_values, safe=False) \ No newline at end of file diff --git a/backend/myapp/urls.py b/backend/myapp/urls.py index cb8b9aa..293e756 100644 --- a/backend/myapp/urls.py +++ b/backend/myapp/urls.py @@ -3,6 +3,7 @@ from .current_stock_holdings_day import get_stock_holdings_day from .graph_stock_holdings import get_stock_history from .graph_stock_holdings_day import get_stock_history_day +from .graph_all_holdings_day import get_all_holdings_day from .historic_stock_holdings import get_historic_stock_holdings from .graph_all_holdings import get_portfolio_value @@ -11,6 +12,7 @@ path('stock_holdings_day/', get_stock_holdings_day, name='stock_holdings_day'), path('graph_stock//', get_stock_history, name='graph_stock'), path('graph_stock_day//', get_stock_history_day, name='graph_stock_day'), + path('graph_all_day/', get_all_holdings_day, name='graph_all_day'), path('historic_holdings/', get_historic_stock_holdings, name='all_holdings'), path('graph_portfolio//', get_portfolio_value, name='graph_portfolio'), ] \ No newline at end of file diff --git a/frontend/src/AllGraphingDay.js b/frontend/src/AllGraphingDay.js new file mode 100644 index 0000000..8ee2ff7 --- /dev/null +++ b/frontend/src/AllGraphingDay.js @@ -0,0 +1,88 @@ +import React, { useState, useEffect } from 'react'; +import { Line } from 'react-chartjs-2'; +import 'chart.js/auto'; +import 'chartjs-adapter-date-fns'; + +function AllGraphDay({ ticker, timeFrame }) { + const [stockData, setStockData] = useState([]); + + useEffect(() => { + // Ensure the ticker value is included in the fetch URL + fetch(`http://localhost:8000/api/graph_all_day/`) + .then(response => response.json()) + .then(data => setStockData(data)) + .catch(error => console.error('Error fetching data:', error)); + }, [ticker]); + + const chartData = { + labels: stockData.map(data => data.date), + datasets: [ + { + // Dataset for stock value + label: 'Stock Value', + data: stockData.map(data => data.value), + fill: false, + backgroundColor: 'rgba(75, 192, 192 0.1)', + borderColor: 'rgb(75, 245, 192)', + borderWidth: 0.8, + tension: 0.1, + pointRadius: 0, + hoverRadius: 0, + }, + { + // Dataset for cumulative investment + label: 'Cumulative Investment', + data: stockData.map(data => data.value_paid), + fill: false, + + borderColor: 'rgb(245, 245, 245)', + borderWidth: 0.75, + tension: 0.1, + pointRadius: 0, + hoverRadius: 0, + }, + ] + }; + + const chartOptions = { + responsive: true, + plugins: { + legend: { + display: false + }, + tooltip: { + mode: 'index', + intersect: false + }, + }, + scales: { + y: { + beginAtZero: false + }, + x: { + type: 'time', + time: { + unit: 'month', + displayFormats: { + month: 'dd-MM-yy-HH:mm' + } + }, + ticks: { + display: false + } + } + }, + animation: { + duration: 1000 // Animation duration in milliseconds + } + }; + + + return ( +
+ +
+ ); +} + +export default AllGraphDay; diff --git a/frontend/src/App.css b/frontend/src/App.css index 65700b1..28dc9ad 100644 --- a/frontend/src/App.css +++ b/frontend/src/App.css @@ -171,7 +171,7 @@ h1 { .stock-details { display: flex; flex-direction: column; - align-items: flex-start; + align-items: center; color: #909090; gap: 5px; /* Added space between info lines */ } diff --git a/frontend/src/App.js b/frontend/src/App.js index 93a9285..655792b 100644 --- a/frontend/src/App.js +++ b/frontend/src/App.js @@ -4,6 +4,7 @@ import homeImage from './resources/menu-con.jpg'; import StockHoldings from './StockHoldings'; import StockGraphAll from './StockGraphingAll'; import StockGraphDay from './StockGraphingDay'; +import AllGraphingDay from './AllGraphingDay'; import HistoricHoldings from './HistoricHoldings'; import TimeFrameFlip from './TimeFrameFlip'; @@ -72,12 +73,13 @@ function App() {
-

{selectedStock ? `${selectedStock.name}` : 'Overall Portfolio'}

-
- +

{selectedStock ? `${selectedStock.name}` : 'Overall Portfolio'}

- {selectedStock && ( -
+ +
+ {!selectedStock && timeFrame === 'Day' && } + {selectedStock && ( +

Current Value: ${selectedStock.value_held.toFixed(2)} diff --git a/frontend/src/StockHoldings.js b/frontend/src/StockHoldings.js index 86e4730..925acfa 100644 --- a/frontend/src/StockHoldings.js +++ b/frontend/src/StockHoldings.js @@ -87,7 +87,7 @@ function StockHoldings({ onStockSelect, timeFrame }) {

Current Stock Holdings

{holdings.map((stock, index) => ( -