Toymakerftw
commited on
Commit
·
f4079e2
1
Parent(s):
3994932
test
Browse files
app.py
CHANGED
|
@@ -125,47 +125,46 @@ def resolve_ticker_symbol(query: str) -> str:
|
|
| 125 |
Convert company names/partial symbols to valid Yahoo Finance tickers.
|
| 126 |
Example: "Kalyan Jewellers" → "KALYANKJIL.NS"
|
| 127 |
"""
|
| 128 |
-
exchanges = ["NSE", "BSE"]
|
| 129 |
-
exchange_suffixes = {
|
| 130 |
-
"NSE": ".NS",
|
| 131 |
-
"BSE": ".BO",
|
| 132 |
-
}
|
| 133 |
-
|
| 134 |
url = "https://query2.finance.yahoo.com/v1/finance/search"
|
| 135 |
headers = {"User-Agent": "Mozilla/5.0"} # Avoid blocking
|
| 136 |
-
params = {"q": query, "quotesCount": 5, "country": "India"}
|
| 137 |
|
| 138 |
response = requests.get(url, headers=headers, params=params)
|
| 139 |
data = response.json()
|
| 140 |
|
| 141 |
-
if data.get("quotes"):
|
| 142 |
-
# Extract symbols and names
|
| 143 |
-
tickers = [quote["symbol"] for quote in data["quotes"]]
|
| 144 |
-
names = [quote["longname"] or quote["shortname"] for quote in data["quotes"]]
|
| 145 |
-
|
| 146 |
-
# Fuzzy match the query with company names
|
| 147 |
-
best_match = process.extractOne(query, names)
|
| 148 |
-
if best_match:
|
| 149 |
-
index = names.index(best_match[0])
|
| 150 |
-
resolved_ticker = tickers[index]
|
| 151 |
-
|
| 152 |
-
# Ensure the exchange suffix is only added if not already present
|
| 153 |
-
for exchange in exchanges:
|
| 154 |
-
if not resolved_ticker.endswith(exchange_suffixes[exchange]):
|
| 155 |
-
resolved_ticker += exchange_suffixes[exchange]
|
| 156 |
-
break
|
| 157 |
-
return resolved_ticker
|
| 158 |
-
else:
|
| 159 |
-
# Default to first result
|
| 160 |
-
resolved_ticker = tickers[0]
|
| 161 |
-
for exchange in exchanges:
|
| 162 |
-
if not resolved_ticker.endswith(exchange_suffixes[exchange]):
|
| 163 |
-
resolved_ticker += exchange_suffixes[exchange]
|
| 164 |
-
break
|
| 165 |
-
return resolved_ticker
|
| 166 |
-
else:
|
| 167 |
raise ValueError(f"No ticker found for: {query}")
|
| 168 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 169 |
def fetch_articles(query):
|
| 170 |
try:
|
| 171 |
logging.info(f"Fetching articles for query: '{query}'")
|
|
@@ -190,53 +189,41 @@ def analyze_article_sentiment(article):
|
|
| 190 |
return article
|
| 191 |
|
| 192 |
def fetch_yfinance_data(ticker):
|
| 193 |
-
"""Enhanced Yahoo Finance data fetching with technical analysis
|
| 194 |
-
|
| 195 |
-
|
| 196 |
-
|
| 197 |
-
"
|
| 198 |
-
|
| 199 |
-
|
| 200 |
-
|
| 201 |
-
|
| 202 |
-
|
| 203 |
-
|
| 204 |
-
|
| 205 |
-
|
| 206 |
-
|
| 207 |
-
|
| 208 |
-
|
| 209 |
-
|
| 210 |
-
|
| 211 |
-
|
| 212 |
-
|
| 213 |
-
|
| 214 |
-
|
| 215 |
-
|
| 216 |
-
current_price
|
| 217 |
-
|
| 218 |
-
|
| 219 |
-
|
| 220 |
-
|
| 221 |
-
|
| 222 |
-
|
| 223 |
-
|
| 224 |
-
return {
|
| 225 |
-
'current_price': current_price,
|
| 226 |
-
'price_change': price_change,
|
| 227 |
-
'percent_change': percent_change,
|
| 228 |
-
'chart': chart,
|
| 229 |
-
'technical_indicators': ta_data,
|
| 230 |
-
'fundamentals': stock.info
|
| 231 |
-
}
|
| 232 |
-
|
| 233 |
-
except Exception as e:
|
| 234 |
-
logging.error(f"Error fetching Yahoo Finance data for {ticker}{exchange_suffixes[exchange]}: {str(e)}")
|
| 235 |
-
continue
|
| 236 |
-
|
| 237 |
-
logging.error(f"Failed to fetch data for {ticker} from all exchanges")
|
| 238 |
-
return {"error": f"Failed to fetch data for {ticker} from all exchanges"}
|
| 239 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 240 |
def time_weighted_sentiment(articles):
|
| 241 |
"""Apply time-based weighting to sentiment scores"""
|
| 242 |
now = datetime.now()
|
|
|
|
| 125 |
Convert company names/partial symbols to valid Yahoo Finance tickers.
|
| 126 |
Example: "Kalyan Jewellers" → "KALYANKJIL.NS"
|
| 127 |
"""
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 128 |
url = "https://query2.finance.yahoo.com/v1/finance/search"
|
| 129 |
headers = {"User-Agent": "Mozilla/5.0"} # Avoid blocking
|
| 130 |
+
params = {"q": query, "quotesCount": 5, "country": "India"}
|
| 131 |
|
| 132 |
response = requests.get(url, headers=headers, params=params)
|
| 133 |
data = response.json()
|
| 134 |
|
| 135 |
+
if not data.get("quotes"):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 136 |
raise ValueError(f"No ticker found for: {query}")
|
| 137 |
|
| 138 |
+
# Extract quotes data
|
| 139 |
+
quotes = data["quotes"]
|
| 140 |
+
tickers = [quote["symbol"] for quote in quotes]
|
| 141 |
+
names = [quote.get("longname") or quote.get("shortname", "") for quote in quotes]
|
| 142 |
+
|
| 143 |
+
# Fuzzy match the query with company names
|
| 144 |
+
best_match, score = process.extractOne(query, names)
|
| 145 |
+
if not best_match:
|
| 146 |
+
raise ValueError(f"No matching ticker found for: {query}")
|
| 147 |
+
|
| 148 |
+
index = names.index(best_match)
|
| 149 |
+
best_quote = quotes[index]
|
| 150 |
+
resolved_ticker = best_quote["symbol"]
|
| 151 |
+
exchange_code = best_quote.get("exchange", "").upper()
|
| 152 |
+
|
| 153 |
+
# Map exchange codes to suffixes
|
| 154 |
+
exchange_suffix_map = {
|
| 155 |
+
"NSI": ".NS", # NSE
|
| 156 |
+
"BOM": ".BO", # BSE
|
| 157 |
+
"BSE": ".BO",
|
| 158 |
+
"NSE": ".NS",
|
| 159 |
+
}
|
| 160 |
+
suffix = exchange_suffix_map.get(exchange_code, ".NS") # Default to NSE
|
| 161 |
+
|
| 162 |
+
# Append suffix only if not already present
|
| 163 |
+
if not resolved_ticker.endswith(suffix):
|
| 164 |
+
resolved_ticker += suffix
|
| 165 |
+
|
| 166 |
+
return resolved_ticker
|
| 167 |
+
|
| 168 |
def fetch_articles(query):
|
| 169 |
try:
|
| 170 |
logging.info(f"Fetching articles for query: '{query}'")
|
|
|
|
| 189 |
return article
|
| 190 |
|
| 191 |
def fetch_yfinance_data(ticker):
|
| 192 |
+
"""Enhanced Yahoo Finance data fetching with technical analysis"""
|
| 193 |
+
try:
|
| 194 |
+
logging.info(f"Fetching Yahoo Finance data for: {ticker}")
|
| 195 |
+
stock = yf.Ticker(ticker)
|
| 196 |
+
history = stock.history(period="1y", interval="1d")
|
| 197 |
+
|
| 198 |
+
if history.empty:
|
| 199 |
+
logging.error(f"No data found for {ticker}")
|
| 200 |
+
return {"error": f"No data found for {ticker}"}
|
| 201 |
+
|
| 202 |
+
# Calculate technical indicators
|
| 203 |
+
ta_data = calculate_technical_indicators(history)
|
| 204 |
+
|
| 205 |
+
# Current price data
|
| 206 |
+
current_price = history['Close'].iloc[-1]
|
| 207 |
+
prev_close = history['Close'].iloc[-2] if len(history) > 1 else 0
|
| 208 |
+
price_change = current_price - prev_close
|
| 209 |
+
percent_change = (price_change / prev_close) * 100 if prev_close != 0 else 0
|
| 210 |
+
|
| 211 |
+
# Generate price chart
|
| 212 |
+
chart = generate_price_chart(history[-120:]) # Last 120 days
|
| 213 |
+
|
| 214 |
+
return {
|
| 215 |
+
'current_price': current_price,
|
| 216 |
+
'price_change': price_change,
|
| 217 |
+
'percent_change': percent_change,
|
| 218 |
+
'chart': chart,
|
| 219 |
+
'technical_indicators': ta_data,
|
| 220 |
+
'fundamentals': stock.info
|
| 221 |
+
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 222 |
|
| 223 |
+
except Exception as e:
|
| 224 |
+
logging.error(f"Error fetching Yahoo Finance data for {ticker}: {str(e)}")
|
| 225 |
+
return {"error": f"Failed to fetch data for {ticker}: {str(e)}"}
|
| 226 |
+
|
| 227 |
def time_weighted_sentiment(articles):
|
| 228 |
"""Apply time-based weighting to sentiment scores"""
|
| 229 |
now = datetime.now()
|