@@ -11,32 +11,20 @@ from langdetect import detect
1111def get_stock_codes_and_names():
1212 url = "https://site2.sbisec.co.jp/ETGate/?OutSide=on&_ControlID=WPLETmgR001Control&_PageID=WPLETmgR001Mdtl20&_DataStoreID=DSWPLETmgR001Control&_ActionID=DefaultAID&getFlg=on&burl=search_market&cat1=market&cat2=none&dir=info&file=market_meigara_400.html"
1313
14- print(f"Fetching URL: {url}")
1514 response = requests.get(url)
16-
17- print(f"Response status code: {response.status_code}")
18-
1915 if response.status_code != 200:
2016 print(f"Failed to fetch the webpage. Status code: {response.status_code}")
2117 return []
2218
2319 soup = BeautifulSoup(response.content, 'html.parser')
24-
2520 stock_table = soup.find('table', {'class': 'md-l-table-type01'})
26-
2721 if stock_table is None:
28- print("Could not find table with class 'md-l-table-type01'")
2922 all_tables = soup.find_all('table')
30- print(f"Number of tables found: {len(all_tables)}")
31-
3223 for table in all_tables:
3324 if table.find('tr'):
3425 stock_table = table
35- print(f"Using table with classes: {stock_table.get('class', 'No class')}")
3626 break
37-
3827 if stock_table is None:
39- print("Could not find any suitable table")
4028 return []
4129
4230 stock_data = []
@@ -46,20 +34,14 @@ def get_stock_codes_and_names():
4634 stock_code = cells[0].text.strip()
4735 company_name = cells[1].text.strip()
4836 stock_data.append((stock_code, company_name))
49-
50- print(f"Found {len(stock_data)} stocks")
5137 return stock_data
5238
5339def scrape_nikkei_news(stock_number):
5440 url = f"https://www.nikkei.com/nkd/company/news/?scode={stock_number}&ba=1"
5541 response = requests.get(url)
5642 soup = BeautifulSoup(response.content, 'html.parser')
5743 news_items = soup.find_all('a', href=lambda href: href and "/nkd/company/article/" in href)
58- news_data = []
59- for item in news_items:
60- title = item.text.strip()
61- url = "https://www.nikkei.com" + item['href']
62- news_data.append({"title": title, "url": url})
44+ news_data = [{"title": item.text.strip(), "url": "https://www.nikkei.com" + item['href']} for item in news_items]
6345 return news_data
6446
6547def scrape_yahoo_finance_news(stock_number):
@@ -83,12 +65,8 @@ def analyze_sentiment(text, ja_tokenizer, ja_model, en_tokenizer, en_model):
8365 except:
8466 lang = 'ja' # Default to Japanese if detection fails
8567
86- if lang == 'ja':
87- tokenizer = ja_tokenizer
88- model = ja_model
89- else:
90- tokenizer = en_tokenizer
91- model = en_model
68+ tokenizer = ja_tokenizer if lang == 'ja' else en_tokenizer
69+ model = ja_model if lang == 'ja' else en_model
9270
9371 inputs = tokenizer(text, return_tensors="pt", truncation=True, max_length=512)
9472 outputs = model(**inputs)
@@ -121,13 +99,11 @@ def get_stock_data(stock_number):
12199 try:
122100 df = yf.download(ticker, start=start_date, end=end_date)
123101 if df.empty:
124- print("No data found for the specified stock number.")
125102 return None
126103
127104 df = df.reset_index()
128105 df['Date'] = pd.to_datetime(df['Date'])
129106 stock_data = [(row['Date'], row['Close']) for _, row in df.iterrows()]
130-
131107 stock_data.sort(key=lambda x: x[0], reverse=True)
132108 return stock_data[:30]
133109
@@ -155,7 +131,10 @@ def calculate_stock_trend(stock_data):
155131 else:
156132 return "Neutral"
157133
158- def get_action_recommendation(public_opinion, stock_trend, current_price):
134+ def get_action_recommendation(public_opinion, stock_trend, stock_price_data):
135+ if not stock_price_data:
136+ return "Insufficient data for recommendation"
137+
159138 opinion_score = {
160139 "Very Positive": 2, "Positive": 1, "Neutral": 0, "Negative": -1, "Very Negative": -2
161140 }
@@ -165,11 +144,20 @@ def get_action_recommendation(public_opinion, stock_trend, current_price):
165144
166145 total_score = opinion_score[public_opinion] + trend_score[stock_trend]
167146
147+ # Calculate average price and standard deviation
148+ prices = [price for _, price in stock_price_data]
149+ avg_price = np.mean(prices)
150+ std_dev = np.std(prices)
151+
152+ current_price = stock_price_data[0][1] # Most recent price
153+
168154 if total_score >= 2:
169- target_price = current_price * 1.05 # 5% above current price
155+ # Buy recommendation: Set target slightly below current price
156+ target_price = max(current_price * 0.98, avg_price - 0.5 * std_dev)
170157 return f"Buy (Target: ¥{target_price:.2f})"
171158 elif total_score <= -2:
172- target_price = current_price * 1.05 # 5% above current price for selling
159+ # Sell recommendation: Set target slightly above current price
160+ target_price = min(current_price * 1.02, avg_price + 0.5 * std_dev)
173161 return f"Sell (Target: ¥{target_price:.2f})"
174162 else:
175163 return "Hold"
@@ -237,22 +225,21 @@ def interactive_results_display(stock_analysis):
237225 print("Invalid input. Please type 'continue', '#<rank>', '#buy', '#sell', '#hold', or 'exit'.")
238226
239227def main():
240- print("Fetching stock codes and company names from the website...")
241228 stock_data = get_stock_codes_and_names()
242- print(f"Found {len(stock_data)} stocks.")
243-
229+ if not stock_data:
230+ print("Failed to retrieve stock data. Please check your internet connection and try again.")
231+ return
232+
244233 ja_tokenizer = AutoTokenizer.from_pretrained("jarvisx17/japanese-sentiment-analysis")
245234 ja_model = AutoModelForSequenceClassification.from_pretrained("jarvisx17/japanese-sentiment-analysis")
246235
247236 en_tokenizer = AutoTokenizer.from_pretrained("distilbert-base-uncased-finetuned-sst-2-english")
248237 en_model = AutoModelForSequenceClassification.from_pretrained("distilbert-base-uncased-finetuned-sst-2-english")
249-
238+
250239 stock_analysis = []
251-
240+
252241 for stock_number, company_name in stock_data:
253242 try:
254- print(f"Analyzing {company_name} ({stock_number})...")
255-
256243 nikkei_news_data = scrape_nikkei_news(stock_number)
257244 yahoo_finance_news_data = scrape_yahoo_finance_news(stock_number)
258245
@@ -269,28 +256,26 @@ def main():
269256 current_stock_price = stock_price_data[0][1] if stock_price_data else None
270257 stock_trend = calculate_stock_trend(stock_price_data)
271258
272- action = get_action_recommendation(overall_sentiment, stock_trend, current_stock_price ) if current_stock_price else "N/A "
259+ action = get_action_recommendation(overall_sentiment, stock_trend, stock_price_data ) if stock_price_data else "Insufficient data "
273260
274261 stock_analysis.append({
275- "company_name": company_name,
276- "stock_number": stock_number,
277- "current_stock_price": current_stock_price,
278- "nikkei_sentiment": nikkei_overall_sentiment,
279- "yahoo_sentiment": yahoo_finance_overall_sentiment,
280- "overall_sentiment": overall_sentiment,
281- "overall_sentiment_value": overall_sentiment_value,
282- "stock_trend": stock_trend,
283- "action": action,
284- "nikkei_news": [{"title": news['title'], "url": news['url']} for news in nikkei_news_data],
285- "yahoo_news": [{"title": news['title'], "url": news['url']} for news in yahoo_finance_news_data]
262+ 'stock_number': stock_number,
263+ 'company_name': company_name,
264+ 'current_stock_price': current_stock_price,
265+ 'nikkei_sentiment': nikkei_overall_sentiment,
266+ 'yahoo_sentiment': yahoo_finance_overall_sentiment,
267+ 'overall_sentiment': overall_sentiment,
268+ 'stock_trend': stock_trend,
269+ 'action': action,
270+ 'nikkei_news': nikkei_news_data,
271+ 'yahoo_news': yahoo_finance_news_data
286272 })
273+
274+ print(f"Processed {company_name} ({stock_number})")
275+
287276 except Exception as e:
288- print(f"Error analyzing {stock_number}: {e}")
289-
290- # Sort stocks based on overall sentiment value (higher is better)
291- stock_analysis.sort(key=lambda x: x["overall_sentiment_value"], reverse=True)
292-
293- print("\nStock Analysis Results (Sorted from Best to Worst):")
277+ print(f"Error processing {company_name} ({stock_number}): {str(e)}")
278+
294279 interactive_results_display(stock_analysis)
295280
296281if __name__ == '__main__':
0 commit comments