Spaces:
Build error
Build error
Download src/vision/pattern_detector.py from leovean/Forex-AI-Analyst: direct link, hf CLI and curl.
- Browser
- Download file 4.48 kB
-
https://huggingface.co/spaces/leovean/Forex-AI-Analyst/resolve/main/src/vision/pattern_detector.py
- Command line
-
hf download hf://spaces/leovean/Forex-AI-Analyst/src/vision/pattern_detector.py
-
curl -L -o pattern_detector.py https://huggingface.co/spaces/leovean/Forex-AI-Analyst/resolve/main/src/vision/pattern_detector.py
4.48 kB
| import cv2 | |
| import numpy as np | |
| import os | |
| from ultralytics import YOLO | |
| from typing import List, Dict, Any | |
| from PIL import Image | |
| from huggingface_hub import hf_hub_download | |
| class PatternDetector: | |
| def __init__(self, model_path: str = "foduucom/stockmarket-pattern-detection-yolov8"): | |
| if "/" in model_path and not os.path.exists(model_path): | |
| print(f"⬇️ Downloading model from Hugging Face: {model_path}") | |
| try: | |
| local_model_path = hf_hub_download( | |
| repo_id=model_path, | |
| filename="model.pt", | |
| cache_dir="./models" | |
| ) | |
| print(f"✅ Model downloaded to: {local_model_path}") | |
| except Exception as e: | |
| print(f"❌ Failed to download model: {e}") | |
| print("⚠️ Falling back to default YOLOv8n model.") | |
| local_model_path = "yolov8n.pt" | |
| else: | |
| local_model_path = model_path | |
| self.model = YOLO(local_model_path) | |
| self.supported_patterns = [ | |
| 'Head and shoulders bottom', 'Head and shoulders top', | |
| 'M_Head', 'W_Bottom', 'Triangle', 'Flag', 'Pennant', | |
| 'Double Top', 'Double Bottom', 'Cup and Handle' | |
| ] | |
| def detect_patterns(self, image: np.ndarray, conf_threshold: float = 0.3) -> List[Dict[str, Any]]: | |
| if isinstance(image, Image.Image): | |
| image = np.array(image) | |
| image = cv2.cvtColor(image, cv2.COLOR_RGB2BGR) | |
| results = self.model(image, conf=conf_threshold) | |
| detections = [] | |
| for result in results: | |
| boxes = result.boxes | |
| if boxes is not None: | |
| for box in boxes: | |
| x1, y1, x2, y2 = box.xyxy[0].tolist() | |
| conf = float(box.conf[0]) | |
| cls_id = int(box.cls[0]) | |
| pattern_name = self.model.names[cls_id] | |
| detections.append({ | |
| 'pattern': pattern_name, | |
| 'confidence': conf, | |
| 'bbox': (int(x1), int(y1), int(x2), int(y2)), | |
| 'center': ((x1 + x2) / 2, (y1 + y2) / 2) | |
| }) | |
| return detections | |
| def analyze_pattern_sentiment(self, detections: List[Dict]) -> Dict[str, Any]: | |
| bullish_patterns = ['W_Bottom', 'Double Bottom', 'Cup and Handle', 'Head and shoulders bottom'] | |
| bearish_patterns = ['M_Head', 'Double Top', 'Head and shoulders top'] | |
| bullish_score = 0 | |
| bearish_score = 0 | |
| for det in detections: | |
| pattern = det['pattern'] | |
| conf = det['confidence'] | |
| if pattern in bullish_patterns: | |
| bullish_score += conf | |
| elif pattern in bearish_patterns: | |
| bearish_score += conf | |
| total = bullish_score + bearish_score | |
| sentiment = "NEUTRAL" | |
| strength = 0.0 | |
| if total > 0: | |
| if bullish_score > bearish_score: | |
| sentiment = "BULLISH" | |
| strength = bullish_score / total | |
| else: | |
| sentiment = "BEARISH" | |
| strength = bearish_score / total | |
| return { | |
| 'sentiment': sentiment, | |
| 'strength': strength, | |
| 'bullish_score': bullish_score, | |
| 'bearish_score': bearish_score, | |
| 'patterns_found': [d['pattern'] for d in detections], | |
| 'highest_confidence_pattern': max(detections, key=lambda x: x['confidence']) if detections else None | |
| } | |
| def draw_detections(self, image: np.ndarray, detections: List[Dict]) -> np.ndarray: | |
| img_copy = image.copy() | |
| for det in detections: | |
| x1, y1, x2, y2 = det['bbox'] | |
| label = f"{det['pattern']}: {det['confidence']:.2f}" | |
| bullish_patterns = ['W_Bottom', 'Double Bottom', 'Cup and Handle'] | |
| bearish_patterns = ['M_Head', 'Double Top'] | |
| if det['pattern'] in bullish_patterns: | |
| color = (0, 255, 0) | |
| elif det['pattern'] in bearish_patterns: | |
| color = (0, 0, 255) | |
| else: | |
| color = (255, 255, 0) | |
| cv2.rectangle(img_copy, (x1, y1), (x2, y2), color, 2) | |
| cv2.putText(img_copy, label, (x1, y1 - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.5, color, 2) | |
| return img_copy |