Skip to content

Commit 410112b

Browse files
committed
Modified code files
1 parent 1daacd4 commit 410112b

18 files changed

Lines changed: 1288 additions & 236 deletions

File tree

.streamlit/config.toml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
[theme]
2+
base="dark"
3+
backgroundColor="#F5F5F5" # "#E3F2FD"
4+
secondaryBackgroundColor="#F0F2F6"
5+
textColor="#333333"
6+
font="sans serif"

pyproject.toml

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,20 +7,23 @@ authors = [
77
{ name = "Dimeji Salau", email = "dimejisalau@protonmail.com" }
88
]
99
requires-python = ">=3.12"
10+
1011
dependencies = [
1112
"asyncio>=3.4.3",
1213
"duckdb>=1.1.3",
13-
"fastapi>=0.115.4",
1414
"httpx>=0.27.2",
15+
"pandas>=2.2.3",
16+
"plotly>=5.24.1",
1517
"polars>=1.12.0",
16-
"pyarrow>=18.0.0",
1718
"pydantic>=2.9.2",
1819
"python-dotenv>=1.0.1",
1920
"pyyaml>=6.0.2",
2021
"streamlit>=1.40.1",
21-
"uvicorn>=0.32.0",
2222
]
2323

24+
[tool.hatch.build.targets.wheel]
25+
packages = ["src/stock_valuation_app"]
26+
2427
[project.scripts]
2528
stock-valuation-app = "stock_valuation_app:main"
2629

@@ -36,5 +39,8 @@ dev = [
3639
"ruff>=0.7.3",
3740
]
3841

39-
[tool.setuptools]
40-
package-dir = {"" = "src"}
42+
[tool.pytest.ini.options]
43+
pythonpath = "src/stock_valuation_app"
44+
45+
# [tool.setuptools]
46+
# package-dir = {"" = "src"}

src/main.py

Whitespace-only changes.

src/models/stock_data.py

Lines changed: 0 additions & 87 deletions
This file was deleted.

src/services/stock_analysis.py

Lines changed: 0 additions & 50 deletions
This file was deleted.
Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@
33
from dataclasses import dataclass, field
44
from typing import Any
55
import httpx
6-
import utils
7-
from models.stock_data import CombinedModel
6+
import stock_valuation_app.utils as utils
7+
from stock_valuation_app.models.stock_models import CombinedModel
88

99

1010
def get_endpoint(url: str) -> str:
@@ -28,7 +28,16 @@ class FMPClient:
2828
"""A client for interacting with the Financial Modeling Prep API."""
2929
base_url: str = field(default_factory=get_base_url)
3030
api_key: str = field(default_factory=get_api_key)
31-
metric_types: list[str] = field(default_factory=lambda: ["profile", "rating", "ratios", "key-metrics", "financial-growth",])
31+
metric_types: list[str] = field(
32+
default_factory=lambda: [
33+
"profile",
34+
"rating",
35+
"quote",
36+
"key-metrics-ttm",
37+
"key-metrics",
38+
"financial-growth",
39+
]
40+
) #
3241

3342
async def get_data(self, client: httpx.Client, url: str) -> dict[str, Any]:
3443
"""Call API endpoint asynchronously"""
@@ -40,7 +49,7 @@ async def fetch_data(self, ticker: str) -> dict[str, list[dict[str, Any]]]:
4049
"""Extracts data asynchronously from multiple FMP endpoints"""
4150
urls = []
4251
for metric in self.metric_types:
43-
if metric in ["profile", "rating"]:
52+
if metric in ["profile", "quote", "rating", "key-metrics-ttm"]:
4453
endpoint = f"{self.base_url}/{metric}/{ticker}?apikey={self.api_key}"
4554
else:
4655
endpoint = f"{self.base_url}/{metric}/{ticker}?period=annual&apikey={self.api_key}"
@@ -54,7 +63,11 @@ async def fetch_data(self, ticker: str) -> dict[str, list[dict[str, Any]]]:
5463
results = await asyncio.gather(*tasks)
5564

5665
# Rename some metric types to match with fields defined in the CombinedModel
57-
replace_metric_types = {"key-metrics": "key_metrics", "financial-growth": "growth",}
66+
replace_metric_types = {
67+
"rating": "ratings",
68+
"key-metrics": "key_metrics",
69+
"key-metrics-ttm": "key_metrics_ttm",
70+
"financial-growth": "growth",} #
5871
new_metric_types = [replace_metric_types.get(item, item) for item in self.metric_types]
5972

6073
# Create combined records dict for validation

src/stock_valuation_app/main.py

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
import streamlit as st
2+
3+
4+
def display_stock_price(label, stock_price):
5+
html_content = f"""
6+
<style>
7+
.stock-box {{
8+
background-color: #f0f0f0;
9+
border-radius: 5px;
10+
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
11+
padding: 10px;
12+
margin-bottom: 10px;
13+
width: 180px;
14+
border: 1px solid #e0e0e0;
15+
text-align: center;
16+
}}
17+
.stock-label {{
18+
font-weight: bold;
19+
font-size: 16px;
20+
color: #2c3e50;
21+
margin-bottom: 10px;
22+
}}
23+
.price-header {{
24+
font-size: 12px;
25+
color: #7f8c8d;
26+
margin-bottom: 5px;
27+
font-weight: 300;
28+
}}
29+
.price-value {{
30+
font-size: 24px;
31+
font-weight: bold;
32+
color: #2ecc71;
33+
}}
34+
</style>
35+
<div class="stock-box">
36+
<div class="stock-label">{label}</div>
37+
<div class="price-header">Stock Price</div>
38+
<div class="price-value">${stock_price}</div>
39+
</div>
40+
"""
41+
st.html(html_content)
42+
43+
44+
# Streamlit app
45+
def main():
46+
st.title("Stock Price Display")
47+
display_stock_price("AAPL", 150.25)
48+
49+
50+
if __name__ == "__main__":
51+
main()
File renamed without changes.
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
from typing import Optional
2+
from pydantic import BaseModel, Field
3+
4+
5+
class CompanyProfile(BaseModel):
6+
symbol: str
7+
beta: float
8+
range: str
9+
company_name: str = Field(..., alias="companyName")
10+
sector: Optional[str] = None
11+
industry: Optional[str] = None
12+
description: Optional[str] = None
13+
image: Optional[str] = None
14+
15+
16+
class Quote(BaseModel):
17+
symbol: str
18+
price: float
19+
change_percent: Optional[float] = Field(..., alias="changesPercentage")
20+
year_high: float = Field(..., alias="yearHigh")
21+
year_low: float = Field(..., alias="yearLow")
22+
market_cap: float = Field(..., alias="marketCap")
23+
vol_avg: int = Field(..., alias="avgVolume")
24+
eps: float
25+
pe: float
26+
earning_date: str = Field(..., alias="earningsAnnouncement")
27+
shares_outstanding: int = Field(..., alias="sharesOutstanding")
28+
29+
30+
31+
class Ratings(BaseModel):
32+
symbol: str
33+
date: str
34+
rating: str
35+
score: int = Field(..., alias="ratingScore")
36+
recommendation: str = Field(..., alias="ratingRecommendation")
37+
dcf_score: int = Field(..., alias="ratingDetailsDCFScore")
38+
dcf_rec: str = Field(..., alias="ratingDetailsDCFRecommendation")
39+
roe_score: int = Field(..., alias="ratingDetailsROEScore")
40+
roe_rec: str = Field(..., alias="ratingDetailsROERecommendation")
41+
roa_score: int = Field(..., alias="ratingDetailsROAScore")
42+
roa_rec: str = Field(..., alias="ratingDetailsROARecommendation")
43+
de_score: int = Field(..., alias="ratingDetailsDEScore")
44+
de_rec: str = Field(..., alias="ratingDetailsDERecommendation")
45+
pe_score: int = Field(..., alias="ratingDetailsPEScore")
46+
pe_rec: str = Field(..., alias="ratingDetailsPERecommendation")
47+
pb_score: int = Field(..., alias="ratingDetailsPBScore")
48+
pb_rec: str = Field(..., alias="ratingDetailsPBRecommendation")
49+
50+
51+
class KeyMetricsTTM(BaseModel):
52+
rev_per_share_ttm: float = Field(..., alias="revenuePerShareTTM")
53+
net_income_per_share_ttm: float = Field(..., alias="netIncomePerShareTTM")
54+
fcf_per_share_ttm: float = Field(..., alias="freeCashFlowPerShareTTM")
55+
pe_ratio_ttm: float = Field(..., alias="peRatioTTM")
56+
ev_over_ebitda_ttm: float = Field(..., alias="enterpriseValueOverEBITDATTM")
57+
ev_to_fcf_ttm: float = Field(..., alias="evToFreeCashFlowTTM")
58+
fcf_yield_ttm: float = Field(..., alias="freeCashFlowYieldTTM")
59+
pts_ratio_ttm: float = Field(..., alias="priceToSalesRatioTTM")
60+
ptb_ratio_ttm: float = Field(..., alias="ptbRatioTTM")
61+
pfcf_ratio_ttm: float = Field(..., alias="pfcfRatioTTM")
62+
dvd_yield_pct_ttm: float = Field(..., alias="dividendYieldPercentageTTM")
63+
dvd_per_share_ttm: float = Field(..., alias="dividendPerShareTTM")
64+
payout_ratio_ttm: float = Field(..., alias="payoutRatioTTM")
65+
66+
67+
class KeyMetrics(BaseModel):
68+
symbol: str
69+
date: str
70+
rev_per_share: float = Field(..., alias="revenuePerShare")
71+
fcf_per_share: float = Field(..., alias="freeCashFlowPerShare")
72+
pe_ratio: float = Field(..., alias="peRatio")
73+
ev_over_ebitda: float = Field(..., alias="enterpriseValueOverEBITDA")
74+
ev_to_fcf: float = Field(..., alias="evToFreeCashFlow")
75+
fcf_yield: float = Field(..., alias="freeCashFlowYield")
76+
77+
78+
class Growth(BaseModel):
79+
symbol: str
80+
date: str
81+
rev_growth: float = Field(..., alias="revenueGrowth")
82+
eps_growth: float = Field(..., alias="epsdilutedGrowth")
83+
dps_growth: float = Field(..., alias="dividendsperShareGrowth")
84+
fcf_growth: float = Field(..., alias="freeCashFlowGrowth")
85+
debt_growth: float = Field(..., alias="debtGrowth")
86+
fiveY_rev_growth_per_share: float = Field(..., alias="fiveYRevenueGrowthPerShare")
87+
fiveY_ni_growth_per_share: float = Field(..., alias="fiveYNetIncomeGrowthPerShare")
88+
fiveY_dps_growth_per_share: float = Field(..., alias="fiveYDividendperShareGrowthPerShare")
89+
fiveY_opcf_growth_per_share: float = Field(..., alias="fiveYOperatingCFGrowthPerShare")
90+
91+
92+
93+
class CombinedModel(BaseModel):
94+
profile: list[CompanyProfile]
95+
quote: list[Quote]
96+
ratings: list[Ratings]
97+
key_metrics_ttm: list[KeyMetricsTTM]
98+
key_metrics: list[KeyMetrics]
99+
growth: list[Growth]
100+

0 commit comments

Comments
 (0)