@@ -11,11 +11,18 @@ import yfinance as yf
1111import sys
1212from PyQt6.QtWidgets import QApplication, QWidget, QVBoxLayout, QHBoxLayout, QLabel, QLineEdit, QPushButton, QTextEdit
1313from PyQt6.QtGui import QFont, QColor, QPalette
14- from PyQt6.QtCore import Qt, QTimer, QThread, pyqtSignal
14+ from PyQt6.QtCore import Qt, QTimer, QThread, pyqtSignal, QEventLoop
1515
1616class StockUpdateThread(QThread):
1717 update_signal = pyqtSignal(dict)
1818
19+
20+ def has_content_changed(self, component_name, new_content):
21+ if self.previous_results[component_name] != new_content:
22+ self.previous_results[component_name] = new_content
23+ return True
24+ return False
25+
1926 def __init__(self, stock_number, ja_tokenizer, ja_model, en_tokenizer, en_model):
2027 super().__init__()
2128 self.stock_number = stock_number
@@ -179,7 +186,18 @@ class MAGIStockAnalysis(QWidget):
179186 self.en_model = AutoModelForSequenceClassification.from_pretrained("distilbert-base-uncased-finetuned-sst-2-english")
180187 self.flicker_timers = {}
181188 self.update_thread = None
189+ self.previous_results = {
190+ 'casper': '',
191+ 'balthasar': '',
192+ 'melchior': ''
193+ }
182194
195+ def has_content_changed(self, component_name, new_content):
196+ if self.previous_results[component_name] != new_content:
197+ self.previous_results[component_name] = new_content
198+ return True
199+ return False
200+
183201 def initUI(self):
184202 self.setWindowTitle('MAGI Stock Analysis System')
185203 self.setGeometry(100, 100, 1200, 800)
@@ -238,7 +256,7 @@ class MAGIStockAnalysis(QWidget):
238256 if component not in self.flicker_timers:
239257 timer = QTimer(self)
240258 timer.timeout.connect(lambda: self.flicker_effect(component))
241- timer.start(500 ) # Flicker every 500ms
259+ timer.start(100 ) # Flicker every 100ms
242260 self.flicker_timers[component] = timer
243261
244262 def stop_flicker(self, component):
@@ -250,7 +268,7 @@ class MAGIStockAnalysis(QWidget):
250268 def flicker_effect(self, component):
251269 current_style = component.styleSheet()
252270 if "background-color: #001a1a" in current_style:
253- component.setStyleSheet("border: 2px solid #ff8c00; background-color: #003a3a ;")
271+ component.setStyleSheet("border: 2px solid #ff8c00; background-color: #005a5a ;") # Brighter color
254272 else:
255273 component.setStyleSheet("border: 2px solid #ff8c00; background-color: #001a1a;")
256274
@@ -282,47 +300,67 @@ class MAGIStockAnalysis(QWidget):
282300 self.update_thread.start()
283301
284302 def update_display(self, data, purchase_price):
285- current_price = data['current_price']
286- nikkei_sentiment = data['nikkei_sentiment']
287- yahoo_sentiment = data['yahoo_sentiment']
288- stock_data = data['stock_data']
289- psr, pbr = data['psr'], data['pbr']
290-
291- overall_sentiment = (nikkei_sentiment + yahoo_sentiment) / 2 if nikkei_sentiment and yahoo_sentiment else None
292- overall_sentiment_text = self.sentiment_to_text(overall_sentiment) if overall_sentiment else "Insufficient data"
293-
294- matched_pattern = self.identify_pattern(stock_data) if stock_data else "Unable to retrieve stock data"
295- psr_score, pbr_score, psr_comment, pbr_comment = self.evaluate_psr_pbr(psr, pbr)
296- recommendation = self.get_action_recommendation(overall_sentiment_text, matched_pattern, stock_data, psr, pbr, purchase_price)
297-
298- # Update MAGI components with results
299- self.casper.findChild(QTextEdit).setText(
300- f"Nikkei Sentiment: {self.sentiment_to_text(nikkei_sentiment)}\n"
301- f"Yahoo Sentiment: {self.sentiment_to_text(yahoo_sentiment)}\n"
302- f"Overall Sentiment: {overall_sentiment_text}"
303- )
304- self.balthasar.findChild(QTextEdit).setText(
305- f"30-Day Pattern: {matched_pattern}\n"
306- f"Recommended Action: {recommendation}"
307- )
308-
309- current_price_text = f"¥{current_price:.2f}" if current_price is not None else "N/A"
310- purchase_price_text = f"¥{purchase_price:.2f}" if purchase_price is not None else "N/A"
311- psr_text = f"{psr:.2f}" if psr is not None else "N/A"
312- pbr_text = f"{pbr:.2f}" if pbr is not None else "N/A"
313-
314- self.melchior.findChild(QTextEdit).setText(
315- f"Current Price: {current_price_text}\n"
316- f"Purchase Price: {purchase_price_text}\n"
317- f"Price Difference: {self.calculate_price_difference(current_price, purchase_price)}\n"
318- f"PSR: {psr_text} - {psr_comment}\n"
319- f"PBR: {pbr_text} - {pbr_comment}"
320- )
303+ try:
304+ current_price = data['current_price']
305+ nikkei_sentiment = data['nikkei_sentiment']
306+ yahoo_sentiment = data['yahoo_sentiment']
307+ stock_data = data['stock_data']
308+ psr, pbr = data['psr'], data['pbr']
309+
310+ overall_sentiment = (nikkei_sentiment + yahoo_sentiment) / 2 if nikkei_sentiment and yahoo_sentiment else None
311+ overall_sentiment_text = self.sentiment_to_text(overall_sentiment) if overall_sentiment else "Insufficient data"
312+
313+ matched_pattern = self.identify_pattern(stock_data) if stock_data else "Unable to retrieve stock data"
314+ psr_score, pbr_score, psr_comment, pbr_comment = self.evaluate_psr_pbr(psr, pbr)
315+ recommendation = self.get_action_recommendation(overall_sentiment_text, matched_pattern, stock_data, psr, pbr, purchase_price)
316+
317+ # Update CASPER
318+ casper_content = (
319+ f"Nikkei Sentiment: {self.sentiment_to_text(nikkei_sentiment)}\n"
320+ f"Yahoo Sentiment: {self.sentiment_to_text(yahoo_sentiment)}\n"
321+ f"Overall Sentiment: {overall_sentiment_text}"
322+ )
323+ if self.has_content_changed('casper', casper_content):
324+ self.update_component_with_flicker(self.casper, casper_content)
325+ else:
326+ self.casper.findChild(QTextEdit).setText(casper_content)
327+
328+ # Update BALTHASAR
329+ balthasar_content = (
330+ f"30-Day Pattern: {matched_pattern}\n"
331+ f"Recommended Action: {recommendation}"
332+ )
333+ if self.has_content_changed('balthasar', balthasar_content):
334+ self.update_component_with_flicker(self.balthasar, balthasar_content)
335+ else:
336+ self.balthasar.findChild(QTextEdit).setText(balthasar_content)
321337
322- # Stop flickering
323- for component in [self.casper, self.balthasar, self.melchior]:
324- self.stop_flicker(component)
338+ # Update MELCHIOR
339+ current_price_text = f"¥{current_price:.2f}" if current_price is not None else "N/A"
340+ purchase_price_text = f"¥{purchase_price:.2f}" if purchase_price is not None else "N/A"
341+ psr_text = f"{psr:.2f}" if psr is not None else "N/A"
342+ pbr_text = f"{pbr:.2f}" if pbr is not None else "N/A"
343+
344+ melchior_content = (
345+ f"Current Price: {current_price_text}\n"
346+ f"Purchase Price: {purchase_price_text}\n"
347+ f"Price Difference: {self.calculate_price_difference(current_price, purchase_price)}\n"
348+ f"PSR: {psr_text} - {psr_comment}\n"
349+ f"PBR: {pbr_text} - {pbr_comment}"
350+ )
351+ if self.has_content_changed('melchior', melchior_content):
352+ self.update_component_with_flicker(self.melchior, melchior_content)
353+ else:
354+ self.melchior.findChild(QTextEdit).setText(melchior_content)
355+
356+ except Exception as e:
357+ print(f"Error in update_display: {e}")
358+ self.show_error(f"An error occurred while updating the display: {e}")
325359
360+ def update_component_with_flicker(self, component, new_text):
361+ self.start_flicker(component)
362+ component.findChild(QTextEdit).setText(new_text)
363+ QTimer.singleShot(500, lambda: self.stop_flicker(component))
326364
327365 def show_error(self, message):
328366 for component in [self.casper, self.balthasar, self.melchior]:
0 commit comments