From e36720ad0dba3f9d42157c7fcf923f31129ef606 Mon Sep 17 00:00:00 2001 From: psyes9 Date: Mon, 18 Dec 2023 13:22:36 +0000 Subject: [PATCH] python cache alterations made to reduce fetch --- .DS_Store | Bin 6148 -> 8196 bytes backend/.DS_Store | Bin 6148 -> 8196 bytes .../graph_all_holdings_day.cpython-38.pyc | Bin 0 -> 2873 bytes .../graph_stock_holdings_day.cpython-38.pyc | Bin 2498 -> 2579 bytes backend/myapp/__pycache__/urls.cpython-38.pyc | Bin 973 -> 1085 bytes backend/myapp/graph_all_holdings_day.py | 89 ++++++++++++++++++ backend/myapp/graph_stock_holdings_day.py | 32 ++++--- backend/myapp/urls.py | 2 + frontend/src/AllGraphingDay.js | 88 +++++++++++++++++ frontend/src/App.css | 2 +- frontend/src/App.js | 12 ++- frontend/src/StockHoldings.js | 2 +- 12 files changed, 206 insertions(+), 21 deletions(-) create mode 100644 backend/myapp/__pycache__/graph_all_holdings_day.cpython-38.pyc create mode 100644 backend/myapp/graph_all_holdings_day.py create mode 100644 frontend/src/AllGraphingDay.js diff --git a/.DS_Store b/.DS_Store index 1b9a277942b2957f601d0c3658e8321b375a78e0..baf4f105702e963fb77b8412794fc40854d8bc99 100644 GIT binary patch delta 517 zcmZoMXmOBWU|?W$DortDU;r^WfEYvza8E20o2aMAD7-OXH}hr%jz7$c**Q2SHn1=X zPv&9qo?OSeXR`=v6(ghM?hIob&hI}BI1?1&3V)U%w=F;N}pWM<~q5LO?%B)zyZkCOQhn=H|6J3e|>&hL)4>uvmc9 z2$TgE<>ln(r2{oH0`s-Squz347m)cKo^xV z=mOmeaa$J9b?K=37}f*Tu9>`(%~qHj=!ay6BA_mizG8+9hWyD3*~FFCAeo9q4bWA^ zlZ#o8E8~zu_R!|fY$A*k8{P>rgWbp=!40HcLBYRSkmEb^WPTCP$^JYX96+CgVuoRI SJkM0Q|Np^?aTrgc)vp27H+^OR delta 151 zcmZp1XfcprU|?W$DortDU=RQ@Ie-{Mvv5r;6q~50$jH4hU^g=(_hcRc@5$!ELW~@f zCkRIKb8^NDNLE)HnV1;rD43c~{wXLk`GT;@W?{i9#>w}E%qGtfG1|-_Cdjy$or6P= m8E7C72yg=lSCH8o3%@f@=9lpV*~GvEu@&SHhRyLjbC?0nbsUKR diff --git a/backend/.DS_Store b/backend/.DS_Store index 375798d006a0fd6f4409a6ab50ff7d205984aa2a..2622bc1e0304e3002580347fc543c6743e195c73 100644 GIT binary patch delta 580 zcmbVKJxc>Y5S_ifc&9nyi9u5MiG?60Bxn#T6G6mI(M~Yrl5oUa?vm_9g&;|h%2dZ9 zHg>jxm^6ae+uHaK`~enXsk5g=4A{7^J8x#^y?G1Uj<-`003aLnd;&l~6}O0b(5p^( zu{jdD+j$^eS&_T)JGoX=)oaNl#5HMs{NAWoMdrriFGQkpU`SCFekdJ;)ZvUCX*3ea zm8IF`RsJMRl5_ql&5#Zc&o_h zsR5$yzpRQzi#{sjcpG2LaI_1j;Qk&=I{o|strKXXoVR<#z+k1_DM#2+hC?rD0UhWER1xllKZ4O%4^-+APK)%Cec8;}5$aGem&^ lH;{G(Id5a(cjn3bGL9hkGXPCv0ntnl4}irs$Mei#1^|G5CL90& 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 0000000000000000000000000000000000000000..ecb0f200aecf4b86235ce871bd4ce74bfc16620d GIT binary patch literal 2873 zcmai0OK%&=5$^7JaQGA@(+}A~!i!=P!AiRhf+UV2Y1~i)d=}JPUas6CLcpn$Ix-YX-vBKW-%SJE~7YhVrT4jT|0JTZ|rw{JEn1| z8`v}DZW-QQTp3rom2tIOwflZt8`ryaN<{gr!As|~+u#8&zarfQUg1@EH#yxVo!SN5 zO}0AJ)PAngvP*tX2Gp7qWX@yqlICvas@Te{fZS>!m)CMHb03p0 z9_79+Wj?Pj<9~6~SSEbofXTmPURL@Z$-P5;x!QzPjjP`;Ry_b}am#o@%2dwo?nM0q zA=_#?-b>?lq}oy(9z{~{wdfQK2S9wKLw%%-3wVWZZbr$mP)S++cmuhTVHC~g~%&@f&4b`vVer;8h z3n1oAZ~eIvQmqR;3KKPs^l1IDPzO4ltUnc@Ou)zO&!&2mChc$-M#=gMv8N&}*7riN zGvVvwX*ijz4`nzR^};yrjnbH7V1O;twaL^}HsVO>emb6P-a+Mk=zPLRjm*A16uQ?x zk`iq1sZl6}>WxIq*EZs`AI54E2Jg?#?r)`SEkVbyuOo=U_8>hRahrI~}yQt@v4U=SoC-XF3ta`Q-WM#@&AM^l2xM2(v_-CB~x(KKb$X zliuT>Ju_}P5s7iFYuq>ux$y?@(r~7Q|7_q+ZxF?zH-T(0E)LD&yu#MGrZ&H18rQ8i z)wx}W6RWfJlSIeMn|Rgj|ASf`HdPxsLS5Q)mYf=Gu_Xp$<~jkb!LNdi$yNBzwdg|O z$VQ(+Qxm{XL(1(lNH_`!$85qm5NXb3!ntSOemvoSoU@gc39vo1a9PaA!StSD&%FDXCU(O2^#0stfHG) zl~+&b9g^3w^8O;P@p@LvYP!iAxPBW__QcKWcCQJ$izh5^WcB?eb*gV<4X|hFz>}w0 zgWp&t`z_vDCiz0x1I3-xFg?2{;q_3QfQFP| zA8}~o3#*fB{E3iJ%1sa@T1e2zc)-aL$`de}VGntS$&cW?d?d-wVA^x72e}W*Za3DH&u9#CUgGhN7yL;GS#WD_j zGe~rcB_PA51LGHEN_uubNngkx;{FeC>H$*^g+xeAX$04$atc*;Jke9*#K^`GlnL-5 zxKO4ql<{CRR+hs%H%tlZE)-Vz4V3sz?AlgTQ72S)Ash~+7{WITx76Hi&P8ewqL$jL zbCn6>B<&vmK+-+Xt-EwUO2ni{Do(5L<(y7M8HC#nGO1vI(YxC<&9kkRO8_ z<4&e}X1!SWtJ+WFSQLf2aJls>79M-?oR#x=KTi2kEH*Jq6=Gjhtr`WxXp`2Q3JX^L E4OY+KtpET3 literal 0 HcmV?d00001 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 96d856ccebda1625393148d1651ec4400d6a5752..915c1cbbb29ad4b224ff06e0caf8747313400937 100644 GIT binary patch delta 646 zcmYLF&ubGw6n<|ryF0tdrfCz~Mk8HB52045XrWC6!D4S7TD%mbta)piq(3KvwqceY zBDOt5!~rjQNRA%Gzd+Ca0|x&A{|5zUb8+B(^WHb_d-KhFFX~e8Gzfe!3+=PG_a$hu zV%}7qiHwPE9RU=+$CCcY=FbQcCS7v+xDLc+NAINY&5}jCv6v-%zUPi6G==olJN6eaD zkqWl0yHvHr?X+IfS!Yq#oDbQ1X}O%jef`T>!WHeiHQdsV-3=`2w{E4dmL9Gc7~3K` zXvX@hyL5duC2J|^#3wR7pfPXBSct<{-D+O{bt{YG>D^XW9*R~Y+S@rYTihLEYujt= z#*NO7dCoRBU=kVWM?Ap?`WwHwP&Xq185S%b3mKNlVIC`%V;INcSkQm?4cycV-bVN^ Zy__AL%AT-IDx4H1UT>w@rhenq{{aJ_o4x=5 delta 580 zcmYLF&1w`u5bo;fndzRN&1PrZABhlxf=i6}vjKksUW6P(gNT=0WUz1-VZqumB*6=mgu?asPGCKa%bqQe1Y~T}#F`b)lr{_?JD9gADuQQAw|(jaTNk zzuJ(lvrBJam&$cFbj3Ul)_vKu*y!M6eAAKFTYrB5u3p zrqllkH-cNPx?`^LW-l#6Ie7hMFj6wJZ0V2G;q(2{SBKWdt{B_KKsp#z%roq(zUlMK zyypdMnMho0_3Ru026YhU(`WDK-rOMJJhjz?Q GvGo@Rd4zTV diff --git a/backend/myapp/__pycache__/urls.cpython-38.pyc b/backend/myapp/__pycache__/urls.cpython-38.pyc index 165cfffa7c04fa71ffddcd498a8df8551b377dc1..4fc1b37988ee9283faba489a3ba770a3ba86f29d 100644 GIT binary patch delta 343 zcmX@hzL!Hgl$V!_0SJUd>r=loGcY^`agYHwkmCTv#d{`dhu5btrEuo(lNFf47zHPnGj&Uf!3E)(j3|&9h4&KxkuOr7 delta 208 zcmdnXah6>>l$V!_0SG>vsYoqjW?*;>;vfT%tOF1iFPW$v9+b+M!kNmP!j;0^%M4`m zq_U>)LfL$&>?!RpiXfCNl**kV3}uU?@}`J_*y(Ihd?{kV44UE--xN58MixLYm;uCXn;xqDdQZn<>i;FlXFJu;G;{{3=@lM{w QoX8>tWKLFOk!1V@0Bij*RsaA1 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) => ( -