Deepvest/ProfilingAI
0
1# src/analysis/ml_analyzer.py2 3import numpy as np4import pandas as pd5from typing import Dict, List, Optional, Any6from datetime import datetime7from sklearn.ensemble import RandomForestClassifier, GradientBoostingRegressor8from sklearn.preprocessing import StandardScaler9import torch10import torch.nn as nn11import logging12 13from transformers import AutoTokenizer, AutoModelForSequenceClassification14from ..core.types import MLAnalyzerProtocol15 16class AlternativeDataAnalyzer:17 """Analyze alternative data sources for market insights"""18 19 def __init__(self):20 self.social_sentiment_model = RandomForestClassifier(n_estimators=100)21 self.web_traffic_model = RandomForestClassifier(n_estimators=50)22 23 def analyze_social_sentiment(self, social_data: List[Dict]) -> float:24 """Analyze social media sentiment"""25 features = self._extract_social_features(social_data)26 return float(self.social_sentiment_model.predict(features)[0])27 28 def analyze_web_traffic(self, traffic_data: pd.DataFrame) -> Dict[str, float]:29 """Analyze web traffic patterns"""30 features = self._prepare_traffic_features(traffic_data)31 predictions = self.web_traffic_model.predict(features)32 return {33 'growth_score': float(np.mean(predictions)),34 'trend_strength': float(np.std(predictions))35 }36 37 38class MarketImpactPredictor:39 """Predicts market impact of trades using machine learning"""40 41 def __init__(self):42 self.impact_model = GradientBoostingRegressor(43 n_estimators=100,44 learning_rate=0.1,45 max_depth=3,46 random_state=4247 )48 self.scaler = StandardScaler()49 self.feature_columns = [50 'trade_size_norm',51 'volume_profile',52 'volatility',53 'bid_ask_spread',54 'market_regime',55 'time_of_day'56 ]57 58 def predict_trade_impact(self,59 trade_size: float,60 market_data: pd.DataFrame,61 market_conditions: Optional[Dict] = None) -> Dict[str, float]:62 """63 Predict market impact of a trade64 65 Args:66 trade_size: Size of the trade67 market_data: Market data (prices, volumes, etc.)68 market_conditions: Additional market condition indicators69 70 Returns:71 Dictionary with impact predictions and metrics72 """73 try:74 # Extract features75 features = self._extract_impact_features(76 trade_size, 77 market_data, 78 market_conditions79 )80 81 # Scale features82 scaled_features = self.scaler.transform(features)83 84 # Predict impact85 base_impact = float(self.impact_model.predict(scaled_features)[0])86 87 # Adjust for market conditions88 adjusted_impact = self._adjust_for_market_conditions(89 base_impact,90 market_conditions91 )92 93 # Calculate confidence and risk metrics94 confidence = self._calculate_prediction_confidence(features)95 risk_metrics = self._calculate_impact_risk_metrics(96 adjusted_impact,97 market_data98 )99 100 return {101 'predicted_impact': adjusted_impact,102 'base_impact': base_impact,103 'confidence': confidence,104 'risk_metrics': risk_metrics,105 'recommended_sizing': self._calculate_recommended_sizing(106 trade_size,107 adjusted_impact,108 market_data109 )110 }111 112 except Exception as e:113 print(f"Error predicting market impact: {e}")114 return {115 'predicted_impact': self._calculate_simple_impact(116 trade_size, 117 market_data118 ),119 'confidence': 0.0,120 'risk_metrics': {}121 }122 123 def _extract_impact_features(self,124 trade_size: float,125 market_data: pd.DataFrame,126 market_conditions: Optional[Dict]) -> np.ndarray:127 """Extract features for impact prediction"""128 try:129 features = []130 131 # Normalize trade size by average daily volume132 avg_volume = market_data['volume'].mean()133 trade_size_norm = trade_size / avg_volume if avg_volume > 0 else 0134 features.append(trade_size_norm)135 136 # Volume profile137 volume_profile = self._calculate_volume_profile(market_data)138 features.append(volume_profile)139 140 # Market volatility141 volatility = market_data['close'].pct_change().std()142 features.append(volatility)143 144 # Bid-ask spread145 spread = self._calculate_bid_ask_spread(market_data)146 features.append(spread)147 148 # Market regime indicator149 regime_indicator = self._get_regime_indicator(market_conditions)150 features.append(regime_indicator)151 152 # Time of day effect153 time_feature = self._calculate_time_feature(market_data)154 features.append(time_feature)155 156 return np.array(features).reshape(1, -1)157 158 except Exception as e:159 print(f"Error extracting impact features: {e}")160 return np.zeros((1, len(self.feature_columns)))161 162 def _adjust_for_market_conditions(self,163 base_impact: float,164 market_conditions: Optional[Dict]) -> float:165 """Adjust impact prediction based on market conditions"""166 try:167 if not market_conditions:168 return base_impact169 170 # Volatility adjustment171 volatility_factor = market_conditions.get('volatility', 1.0)172 173 # Liquidity adjustment174 liquidity_factor = 1 / market_conditions.get('liquidity', 1.0)175 176 # Regime adjustment177 regime_factor = self._get_regime_factor(market_conditions)178 179 # Combined adjustment180 adjustment = (volatility_factor * liquidity_factor * regime_factor)181 182 return base_impact * adjustment183 184 except Exception as e:185 print(f"Error adjusting for market conditions: {e}")186 return base_impact187 188 def _calculate_prediction_confidence(self, features: np.ndarray) -> float:189 """Calculate confidence score for impact prediction"""190 try:191 # Base confidence192 confidence = 0.8193 194 # Adjust based on feature quality195 for i, feature in enumerate(features[0]):196 if np.isnan(feature) or np.isinf(feature):197 confidence *= 0.8198 199 # Adjust based on feature values200 trade_size_norm = features[0][0]201 if trade_size_norm > 0.1: # Large trades202 confidence *= 0.9203 204 return float(confidence)205 206 except Exception as e:207 print(f"Error calculating prediction confidence: {e}")208 return 0.5209 210 def _calculate_impact_risk_metrics(self,211 impact: float,212 market_data: pd.DataFrame) -> Dict[str, float]:213 """Calculate risk metrics for impact prediction"""214 try:215 metrics = {}216 217 # Calculate VaR of impact218 metrics['impact_var_95'] = impact * 1.645 # Assuming normal distribution219 220 # Calculate potential slippage221 metrics['max_slippage'] = impact * 2222 223 # Timing risk224 metrics['timing_risk'] = self._calculate_timing_risk(market_data)225 226 return metrics227 228 except Exception as e:229 print(f"Error calculating impact risk metrics: {e}")230 return {}231 232 def _calculate_simple_impact(self,233 trade_size: float,234 market_data: pd.DataFrame) -> float:235 """Calculate simple market impact estimate"""236 try:237 avg_volume = market_data['volume'].mean()238 participation_rate = trade_size / avg_volume if avg_volume > 0 else 0239 240 # Square root model241 return 0.1 * np.sqrt(participation_rate)242 243 except Exception as e:244 print(f"Error calculating simple impact: {e}")245 return 0.01 # Default 1 bp impact246 247 def _calculate_recommended_sizing(self,248 trade_size: float,249 predicted_impact: float,250 market_data: pd.DataFrame) -> Dict[str, float]:251 """Calculate recommended trade sizing"""252 try:253 avg_volume = market_data['volume'].mean()254 255 # Calculate different size recommendations256 aggressive = min(trade_size, avg_volume * 0.1)257 normal = min(trade_size, avg_volume * 0.05)258 passive = min(trade_size, avg_volume * 0.02)259 260 return {261 'aggressive_size': float(aggressive),262 'normal_size': float(normal),263 'passive_size': float(passive),264 'optimal_size': float(normal) # Could be adjusted based on urgency265 }266 267 except Exception as e:268 print(f"Error calculating recommended sizing: {e}")269 return {'optimal_size': trade_size * 0.05}270 271 @staticmethod272 def _calculate_volume_profile(market_data: pd.DataFrame) -> float:273 """Calculate volume profile metric"""274 try:275 recent_volume = market_data['volume'].tail(20).mean()276 hist_volume = market_data['volume'].mean()277 return recent_volume / hist_volume if hist_volume > 0 else 1.0278 except:279 return 1.0280 281 @staticmethod282 def _calculate_bid_ask_spread(market_data: pd.DataFrame) -> float:283 """Calculate average bid-ask spread"""284 try:285 if 'bid' in market_data and 'ask' in market_data:286 spread = (market_data['ask'] - market_data['bid']) / market_data['ask']287 return float(spread.mean())288 return 0.001 # Default 10 bp spread289 except:290 return 0.001291 292 @staticmethod293 def _get_regime_indicator(market_conditions: Optional[Dict]) -> float:294 """Get numerical indicator for market regime"""295 try:296 if not market_conditions:297 return 0.0298 regime = market_conditions.get('regime', 'normal')299 regime_map = {300 'crisis': -1.0,301 'stress': -0.5,302 'normal': 0.0,303 'calm': 0.5,304 'highly_liquid': 1.0305 }306 return regime_map.get(regime, 0.0)307 except:308 return 0.0309 310 @staticmethod311 def _calculate_time_feature(market_data: pd.DataFrame) -> float:312 """Calculate time of day feature"""313 try:314 if isinstance(market_data.index, pd.DatetimeIndex):315 hour = market_data.index[-1].hour316 # Normalize to 0-1 range, with peak at market open/close317 return np.sin(np.pi * hour / 12)318 return 0.0319 except:320 return 0.0321 322 @staticmethod323 def _get_regime_factor(market_conditions: Optional[Dict]) -> float:324 """Get adjustment factor for market regime"""325 try:326 if not market_conditions:327 return 1.0328 regime = market_conditions.get('regime', 'normal')329 regime_factors = {330 'crisis': 2.0,331 'stress': 1.5,332 'normal': 1.0,333 'calm': 0.8,334 'highly_liquid': 0.5335 }336 return regime_factors.get(regime, 1.0)337 except:338 return 1.0339 340 @staticmethod341 def _calculate_timing_risk(market_data: pd.DataFrame) -> float:342 """Calculate timing risk metric"""343 try:344 returns = market_data['close'].pct_change()345 volatility = returns.std()346 return float(volatility * np.sqrt(252))347 except:348 return 0.2 # Default 20% annualized vol349 350class SentimentAnalyzer:351 """Advanced sentiment analyzer for market and news data"""352 353 def __init__(self):354 self.sentiment_model = None355 self.text_vectorizer = None356 self.market_indicators = [357 'price_momentum',358 'volume_change',359 'volatility',360 'rsi',361 'macd',362 'social_sentiment'363 ]364 365 def analyze_sentiment(self,366 market_data: pd.DataFrame,367 news_data: Optional[List[str]] = None,368 social_data: Optional[Dict[str, Any]] = None) -> Dict[str, float]:369 """370 Analyze overall market sentiment using multiple data sources.371 372 Args:373 market_data: Market price and volume data374 news_data: List of news articles/headlines375 social_data: Social media sentiment data376 377 Returns:378 Dictionary of sentiment scores379 """380 try:381 # Market technical sentiment382 market_sentiment = self._analyze_market_sentiment(market_data)383 384 # News sentiment385 news_sentiment = self._analyze_news_sentiment(news_data) if news_data else 0.5386 387 # Social media sentiment388 social_sentiment = self._analyze_social_sentiment(social_data) if social_data else 0.5389 390 # Combine all sentiment signals391 composite_sentiment = self._calculate_composite_sentiment(392 market_sentiment,393 news_sentiment,394 social_sentiment395 )396 397 return {398 'composite_sentiment': composite_sentiment,399 'market_sentiment': market_sentiment,400 'news_sentiment': news_sentiment,401 'social_sentiment': social_sentiment,402 'sentiment_indicators': self._calculate_sentiment_indicators(market_data),403 'confidence_score': self._calculate_confidence_score(market_data)404 }405 406 except Exception as e:407 print(f"Error in sentiment analysis: {e}")408 return {409 'composite_sentiment': 0.5,410 'market_sentiment': 0.5,411 'news_sentiment': 0.5,412 'social_sentiment': 0.5,413 'sentiment_indicators': {},414 'confidence_score': 0.0415 }416 417 def _analyze_market_sentiment(self, market_data: pd.DataFrame) -> float:418 """Analyze sentiment from market data"""419 try:420 if market_data.empty:421 return 0.5422 423 sentiment_scores = []424 425 # Price momentum426 returns = market_data['close'].pct_change()427 momentum = returns.rolling(window=20).mean().iloc[-1]428 sentiment_scores.append(self._normalize_score(momentum, -0.02, 0.02))429 430 # Volume trend431 volume_change = market_data['volume'].pct_change()432 vol_trend = volume_change.rolling(window=20).mean().iloc[-1]433 sentiment_scores.append(self._normalize_score(vol_trend, -0.1, 0.1))434 435 # RSI436 rsi = self._calculate_rsi(market_data)437 sentiment_scores.append(self._normalize_score(rsi, 30, 70))438 439 # Weighted average440 weights = [0.5, 0.3, 0.2]441 return sum(score * weight for score, weight 442 in zip(sentiment_scores, weights))443 444 except Exception as e:445 print(f"Error in market sentiment analysis: {e}")446 return 0.5447 448 def _analyze_news_sentiment(self, news_data: List[str]) -> float:449 """Analyze sentiment from news articles"""450 try:451 if not news_data:452 return 0.5453 454 # Simple keyword-based sentiment (placeholder)455 positive_words = {'growth', 'profit', 'success', 'gain', 'rally'}456 negative_words = {'loss', 'risk', 'decline', 'crash', 'fear'}457 458 total_score = 0459 for text in news_data:460 words = set(text.lower().split())461 positive_count = len(words.intersection(positive_words))462 negative_count = len(words.intersection(negative_words))463 464 if positive_count + negative_count > 0:465 score = positive_count / (positive_count + negative_count)466 else:467 score = 0.5468 469 total_score += score470 471 return total_score / len(news_data)472 473 except Exception as e:474 print(f"Error in news sentiment analysis: {e}")475 return 0.5476 477 def _analyze_social_sentiment(self, social_data: Dict[str, Any]) -> float:478 """Analyze sentiment from social media data"""479 try:480 if not social_data:481 return 0.5482 483 sentiment_scores = []484 485 # Process different social media sources486 for source, data in social_data.items():487 if source == 'twitter':488 score = self._analyze_twitter_sentiment(data)489 elif source == 'reddit':490 score = self._analyze_reddit_sentiment(data)491 else:492 score = 0.5493 494 sentiment_scores.append(score)495 496 return np.mean(sentiment_scores) if sentiment_scores else 0.5497 498 except Exception as e:499 print(f"Error in social sentiment analysis: {e}")500 return 0.5501 502 def _calculate_composite_sentiment(self,503 market_sentiment: float,504 news_sentiment: float,505 social_sentiment: float) -> float:506 """Calculate weighted composite sentiment"""507 weights = {508 'market': 0.5,509 'news': 0.3,510 'social': 0.2511 }512 513 composite = (514 weights['market'] * market_sentiment +515 weights['news'] * news_sentiment +516 weights['social'] * social_sentiment517 )518 519 return min(max(composite, 0), 1) # Ensure between 0 and 1520 521 def _calculate_sentiment_indicators(self, market_data: pd.DataFrame) -> Dict[str, float]:522 """Calculate various sentiment indicators"""523 try:524 indicators = {}525 526 for indicator in self.market_indicators:527 if indicator == 'price_momentum':528 value = self._calculate_momentum(market_data)529 elif indicator == 'volume_change':530 value = self._calculate_volume_change(market_data)531 elif indicator == 'volatility':532 value = self._calculate_volatility(market_data)533 else:534 value = 0.0535 536 indicators[indicator] = value537 538 return indicators539 540 except Exception as e:541 print(f"Error calculating sentiment indicators: {e}")542 return {}543 544 @staticmethod545 def _normalize_score(value: float, min_val: float, max_val: float) -> float:546 """Normalize a value to a 0-1 range"""547 try:548 return min(max((value - min_val) / (max_val - min_val), 0), 1)549 except:550 return 0.5551 552 @staticmethod553 def _calculate_rsi(data: pd.DataFrame, periods: int = 14) -> float:554 """Calculate RSI indicator"""555 try:556 delta = data['close'].diff()557 gain = (delta.where(delta > 0, 0)).rolling(window=periods).mean()558 loss = (-delta.where(delta < 0, 0)).rolling(window=periods).mean()559 rs = gain / loss560 return float(100 - (100 / (1 + rs.iloc[-1])))561 except:562 return 50.0563 564 def _calculate_confidence_score(self, market_data: pd.DataFrame) -> float:565 """Calculate confidence score for sentiment analysis"""566 try:567 # Volatility-based confidence568 volatility = self._calculate_volatility(market_data)569 volume = self._calculate_volume_change(market_data)570 571 # Lower confidence in high volatility periods572 confidence = 1 - min(volatility, 0.5)573 574 # Higher confidence with higher volume575 volume_factor = min(max(volume, 0), 1)576 confidence *= (0.7 + 0.3 * volume_factor)577 578 return float(confidence)579 580 except Exception as e:581 print(f"Error calculating confidence score: {e}")582 return 0.0583 584 @staticmethod585 def _calculate_momentum(data: pd.DataFrame, window: int = 20) -> float:586 """Calculate price momentum"""587 try:588 returns = data['close'].pct_change()589 return float(returns.rolling(window=window).mean().iloc[-1])590 except:591 return 0.0592 593 @staticmethod594 def _calculate_volume_change(data: pd.DataFrame, window: int = 20) -> float:595 """Calculate volume trend"""596 try:597 volume_change = data['volume'].pct_change()598 return float(volume_change.rolling(window=window).mean().iloc[-1])599 except:600 return 0.0601 602 @staticmethod603 def _calculate_volatility(data: pd.DataFrame, window: int = 20) -> float:604 """Calculate price volatility"""605 try:606 returns = data['close'].pct_change()607 return float(returns.rolling(window=window).std().iloc[-1])608 except:609 return 0.0610 611class MarketRegimeClassifier:612 """Classifier for market regimes using machine learning"""613 614 def __init__(self):615 self.model = GaussianMixture(n_components=3, random_state=42)616 self.scaler = StandardScaler()617 self.regimes = ['bear', 'neutral', 'bull']618 619 def extract_features(self, market_data: pd.DataFrame) -> np.ndarray:620 """Extract relevant features for regime classification"""621 features = []622 623 # Price-based features624 returns = market_data['close'].pct_change()625 features.extend([626 returns.mean(), # Mean return627 returns.std(), # Volatility628 returns.skew(), # Asymmetry629 returns.kurt(), # Kurtosis630 self._calculate_momentum(market_data), # Momentum631 self._calculate_rsi(market_data), # RSI632 self._calculate_volatility_regime(returns) # Volatility regime633 ])634 635 return np.array(features).reshape(1, -1)636 637 def predict_regime(self, market_data: pd.DataFrame) -> str:638 """Predict current market regime"""639 features = self.extract_features(market_data)640 scaled_features = self.scaler.transform(features)641 regime_idx = self.model.predict(scaled_features)[0]642 return self.regimes[regime_idx]643 644 def _calculate_momentum(self, data: pd.DataFrame, window: int = 63) -> float:645 """Calculate price momentum"""646 returns = data['close'].pct_change()647 return returns.rolling(window=window).mean().iloc[-1]648 649 def _calculate_rsi(self, data: pd.DataFrame, periods: int = 14) -> float:650 """Calculate RSI indicator"""651 delta = data['close'].pct_change()652 gain = (delta.where(delta > 0, 0)).rolling(window=periods).mean()653 loss = (-delta.where(delta < 0, 0)).rolling(window=periods).mean()654 rs = gain / loss655 return 100 - (100 / (1 + rs.iloc[-1]))656 657 def _calculate_volatility_regime(self, returns: pd.Series, window: int = 21) -> float:658 """Calculate volatility regime indicator"""659 vol = returns.rolling(window=window).std() * np.sqrt(252)660 return vol.iloc[-1]661 662class MLEnhancedAnalyzer:663 """Enhanced market analyzer with machine learning capabilities"""664 def _setup_logger(self) -> logging.Logger:665 """Configuration du système de logging"""666 logger = logging.getLogger('Deepvest')667 logger.setLevel(logging.INFO)668 handler = logging.StreamHandler()669 formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')670 handler.setFormatter(formatter)671 logger.addHandler(handler)672 return logger673 674 def __init__(self):675 self.regime_classifier = MarketRegimeClassifier()676 self.sentiment_analyzer = self._initialize_sentiment_model()677 678 def _initialize_sentiment_model(self):679 return GaussianMixture(n_components=2, random_state=42)680 681 def predict_market_regime(self, market_data: pd.DataFrame) -> str:682 """Predict market regime"""683 return self.regime_classifier.predict_regime(market_data)684 685 def analyze_market_sentiment(self, 686 market_data: pd.DataFrame, 687 news_data: Optional[List[str]] = None) -> float:688 """Analyze market sentiment"""689 market_features = self._extract_market_features(market_data)690 sentiment_score = self.sentiment_analyzer.predict_proba(market_features)691 if news_data:692 news_sentiment = self._analyze_news_sentiment(news_data)693 sentiment_score = 0.7 * sentiment_score + 0.3 * news_sentiment694 return float(sentiment_score.mean())695 696 def _extract_market_features(self, market_data: pd.DataFrame) -> np.ndarray:697 """Extract features for sentiment analysis"""698 if market_data.empty:699 return np.array([[0]])700 701 features = []702 returns = market_data['close'].pct_change().dropna()703 704 # Basic features705 features.extend([706 returns.mean(),707 returns.std(),708 returns.skew(),709 returns.kurt()710 ])711 712 # Technical features713 features.extend([714 self._calculate_macd(market_data),715 self._calculate_rsi(market_data),716 self._calculate_bollinger_bands(market_data)717 ])718 719 return np.array(features).reshape(1, -1)720 721 @staticmethod722 def _calculate_macd(data: pd.DataFrame) -> float:723 """Calculate MACD indicator"""724 if 'close' not in data.columns or len(data) < 26:725 return 0.0726 exp1 = data['close'].ewm(span=12, adjust=False).mean()727 exp2 = data['close'].ewm(span=26, adjust=False).mean()728 macd = exp1 - exp2729 return float(macd.iloc[-1])730 731 @staticmethod732 def _calculate_bollinger_bands(data: pd.DataFrame) -> float:733 """Calculate Bollinger Bands position"""734 if 'close' not in data.columns or len(data) < 20:735 return 0.0736 ma = data['close'].rolling(window=20).mean()737 std = data['close'].rolling(window=20).std()738 upper = ma + (std * 2)739 lower = ma - (std * 2)740 position = (data['close'] - lower) / (upper - lower)741 return float(position.iloc[-1])742 743 def _analyze_news_sentiment(self, news_data: List[str]) -> float:744 """Simple sentiment analysis of news data"""745 # Placeholder - would normally use NLP model746 return 0.5747 748class MLEnhancedAnalyzer(MLAnalyzerProtocol):749 """ML-enhanced market analysis implementation"""750 751 def __init__(self):752 # Modèles pour différentes tâches d'analyse753 self.regime_classifier = RandomForestClassifier(n_estimators=100, random_state=42)754 self.risk_predictor = GradientBoostingRegressor(n_estimators=100, random_state=42)755 self.scaler = StandardScaler()756 757 # Modèle de sentiment758 self.sentiment_tokenizer = AutoTokenizer.from_pretrained("nickmuchi/finbert-tone-finetuned-finance-text-classification")759 self.sentiment_model = AutoModelForSequenceClassification.from_pretrained("nickmuchi/finbert-tone-finetuned-finance-text-classification")760 761 async def analyze_market_conditions(self,762 market_data: pd.DataFrame,763 news_data: Optional[List[str]] = None,764 alternative_data: Optional[Dict] = None) -> Dict[str, Any]:765 """Analyse complète des conditions de marché utilisant ML"""766 try:767 # Préparer les features768 features = self._prepare_features(market_data)769 scaled_features = self.scaler.transform(features)770 771 # Analyse du régime de marché772 regime = self._predict_market_regime(scaled_features)773 774 # Analyse des risques775 risk_metrics = self._analyze_risk_factors(market_data)776 777 # Analyse technique778 technical_metrics = self._analyze_technical_factors(market_data)779 780 # Analyse du sentiment si des données sont disponibles781 sentiment = {}782 if news_data:783 sentiment = await self._analyze_sentiment(news_data)784 785 # Analyse des données alternatives si disponibles786 alt_insights = {}787 if alternative_data:788 alt_insights = self._analyze_alternative_data(alternative_data)789 790 return {791 'regime': regime,792 'risk_metrics': risk_metrics,793 'technical_metrics': technical_metrics,794 'sentiment': sentiment,795 'alternative_insights': alt_insights,796 'timestamp': datetime.now()797 }798 799 except Exception as e:800 print(f"Error in ML market analysis: {str(e)}")801 return self._get_default_analysis()802 803 def _prepare_features(self, market_data: pd.DataFrame) -> np.ndarray:804 """Prépare les features pour l'analyse ML"""805 try:806 # Calculer les rendements si nécessaire807 if 'returns' not in market_data.columns:808 returns = market_data.pct_change().dropna()809 else:810 returns = market_data['returns'].dropna()811 812 features = []813 814 # Features basées sur les rendements815 features.extend([816 returns.mean(),817 returns.std(),818 returns.skew(),819 returns.kurtosis(),820 (returns < 0).mean()821 ])822 823 # Features basées sur le volume si disponible824 if 'volume' in market_data.columns:825 volume = market_data['volume']826 features.extend([827 volume.mean(),828 volume.std() / volume.mean(),829 (volume.pct_change() > 0).mean()830 ])831 832 # Features techniques si disponibles833 if 'close' in market_data.columns:834 close_prices = market_data['close']835 features.extend(self._calculate_technical_features(close_prices))836 837 return np.array(features).reshape(1, -1)838 839 except Exception as e:840 print(f"Error preparing features: {str(e)}")841 return np.zeros((1, 10)) # Features par défaut842 843 def _predict_market_regime(self, features: np.ndarray) -> str:844 """Prédit le régime de marché actuel"""845 try:846 prediction = self.regime_classifier.predict(features)[0]847 regimes = ['BULL_MARKET', 'BEAR_MARKET', 'HIGH_VOLATILITY', 'LOW_VOLATILITY']848 return regimes[prediction] if isinstance(prediction, (int, np.integer)) else 'LOW_VOLATILITY'849 except Exception as e:850 print(f"Error predicting regime: {str(e)}")851 return 'LOW_VOLATILITY'852 853 def _analyze_risk_factors(self, market_data: pd.DataFrame) -> Dict[str, float]:854 """Analyse des facteurs de risque"""855 try:856 returns = market_data.pct_change().dropna()857 858 risk_metrics = {859 'volatility': float(returns.std() * np.sqrt(252)),860 'tail_risk': self._calculate_tail_risk(returns),861 'var_95': float(np.percentile(returns, 5)),862 'skewness': float(returns.skew()),863 'kurtosis': float(returns.kurtosis())864 }865 866 return risk_metrics867 868 except Exception as e:869 print(f"Error analyzing risk factors: {str(e)}")870 return {871 'volatility': 0.15,872 'tail_risk': 0.05,873 'var_95': -0.02,874 'skewness': 0.0,875 'kurtosis': 3.0876 }877 878 async def _analyze_sentiment(self, news_data: List[str]) -> Dict[str, float]:879 """Analyse du sentiment des nouvelles"""880 try:881 sentiments = []882 for text in news_data:883 # Tokenization et préparation884 inputs = self.sentiment_tokenizer(text, return_tensors="pt", padding=True, truncation=True)885 886 # Analyse avec le modèle887 with torch.no_grad():888 outputs = self.sentiment_model(**inputs)889 logits = outputs.logits890 probs = torch.softmax(logits, dim=1)891 sentiments.append(probs.tolist()[0])892 893 # Agrégation des sentiments894 avg_sentiment = np.mean(sentiments, axis=0)895 return {896 'positive': float(avg_sentiment[2]), # Indice 2 pour le sentiment positif897 'neutral': float(avg_sentiment[1]), # Indice 1 pour le sentiment neutre898 'negative': float(avg_sentiment[0]) # Indice 0 pour le sentiment négatif899 }900 901 except Exception as e:902 print(f"Error analyzing sentiment: {str(e)}")903 return {'positive': 0.33, 'neutral': 0.34, 'negative': 0.33}904 905 def _analyze_technical_factors(self, market_data: pd.DataFrame) -> Dict[str, float]:906 """Analyse des facteurs techniques"""907 try:908 close_prices = market_data['close']909 910 return {911 'rsi': self._calculate_rsi(close_prices),912 'macd': self._calculate_macd(close_prices),913 'momentum': self._calculate_momentum(close_prices),914 'trend_strength': self._calculate_trend_strength(close_prices)915 }916 917 except Exception as e:918 print(f"Error analyzing technical factors: {str(e)}")919 return {920 'rsi': 50.0,921 'macd': 0.0,922 'momentum': 0.0,923 'trend_strength': 0.0924 }925 926 def _analyze_alternative_data(self, alternative_data: Dict) -> Dict[str, Any]:927 """Analyse des données alternatives"""928 insights = {}929 930 try:931 # Analyse des données sociales si disponibles932 if 'social_media' in alternative_data:933 insights['social'] = self._analyze_social_data(alternative_data['social_media'])934 935 # Analyse des données de trafic web si disponibles936 if 'web_traffic' in alternative_data:937 insights['traffic'] = self._analyze_web_traffic(alternative_data['web_traffic'])938 939 # Analyse des données satellite si disponibles940 if 'satellite' in alternative_data:941 insights['satellite'] = self._analyze_satellite_data(alternative_data['satellite'])942 943 except Exception as e:944 print(f"Error analyzing alternative data: {str(e)}")945 946 return insights947 948 @staticmethod949 def _calculate_rsi(prices: pd.Series, periods: int = 14) -> float:950 """Calcul du RSI"""951 try:952 delta = prices.diff()953 gain = (delta.where(delta > 0, 0)).rolling(window=periods).mean()954 loss = (-delta.where(delta < 0, 0)).rolling(window=periods).mean()955 rs = gain / loss956 return float(100 - (100 / (1 + rs.iloc[-1])))957 except Exception:958 return 50.0959 960 @staticmethod961 def _calculate_macd(prices: pd.Series) -> float:962 """Calcul du MACD"""963 try:964 exp1 = prices.ewm(span=12, adjust=False).mean()965 exp2 = prices.ewm(span=26, adjust=False).mean()966 macd = exp1 - exp2967 signal = macd.ewm(span=9, adjust=False).mean()968 return float(macd.iloc[-1] - signal.iloc[-1])969 except Exception:970 return 0.0971 972 @staticmethod973 def _get_default_analysis() -> Dict[str, Any]:974 """Retourne une analyse par défaut en cas d'erreur"""975 return {976 'regime': 'LOW_VOLATILITY',977 'risk_metrics': {978 'volatility': 0.15,979 'tail_risk': 0.05,980 'var_95': -0.02981 },982 'technical_metrics': {983 'rsi': 50.0,984 'macd': 0.0,985 'momentum': 0.0986 },987 'sentiment': {988 'positive': 0.33,989 'neutral': 0.34,990 'negative': 0.33991 },992 'alternative_insights': {},993 'timestamp': datetime.now()994 }