Spaces:
Paused
Paused
Update ml_engine/processor.py
Browse files- ml_engine/processor.py +126 -268
ml_engine/processor.py
CHANGED
|
@@ -1,307 +1,165 @@
|
|
| 1 |
-
# ml_engine/processor.py (
|
| 2 |
import pandas as pd
|
| 3 |
import numpy as np
|
| 4 |
-
from datetime import datetime
|
| 5 |
import asyncio
|
| 6 |
import json
|
| 7 |
-
import
|
| 8 |
|
| 9 |
-
#
|
| 10 |
from .indicators import AdvancedTechnicalAnalyzer
|
| 11 |
from .monte_carlo import MonteCarloAnalyzer
|
| 12 |
-
|
| 13 |
from .strategies import MultiStrategyEngine
|
| 14 |
|
| 15 |
class MLProcessor:
|
| 16 |
-
def __init__(self, market_context, data_manager, learning_hub):
|
| 17 |
self.market_context = market_context
|
| 18 |
self.data_manager = data_manager
|
| 19 |
-
self.learning_hub = learning_hub
|
| 20 |
|
| 21 |
self.technical_analyzer = AdvancedTechnicalAnalyzer()
|
| 22 |
-
|
| 23 |
-
self.strategy_engine = MultiStrategyEngine(data_manager, learning_hub)
|
| 24 |
self.monte_carlo_analyzer = MonteCarloAnalyzer()
|
| 25 |
|
| 26 |
-
#
|
| 27 |
-
# (استخدام محرك V8 الرئيسي المحمل مسبقاً من DataManager)
|
| 28 |
-
# (هذا يحل مشكلة "النموذج/المقياس غير محمل")
|
| 29 |
if self.data_manager and self.data_manager.pattern_analyzer:
|
| 30 |
-
self.
|
| 31 |
-
print("✅ [MLProcessor V6.4] تم ربط محرك الأنماط V8 (الرئيسي).")
|
| 32 |
else:
|
| 33 |
-
|
| 34 |
-
|
| 35 |
-
# 🔴 --- END OF CHANGE --- 🔴
|
| 36 |
-
|
| 37 |
-
self.whale_data_semaphore = asyncio.Semaphore(2)
|
| 38 |
|
| 39 |
async def process_and_score_symbol_enhanced(self, raw_data, preloaded_whale_data: dict = None):
|
| 40 |
"""
|
| 41 |
-
|
| 42 |
"""
|
| 43 |
try:
|
| 44 |
-
|
| 45 |
-
|
| 46 |
-
|
| 47 |
-
symbol = raw_data['symbol']
|
| 48 |
-
|
| 49 |
-
base_analysis = await self.process_and_score_symbol(raw_data)
|
| 50 |
-
if not base_analysis:
|
| 51 |
-
return None
|
| 52 |
|
| 53 |
-
|
| 54 |
-
# Calculate Indicators
|
| 55 |
-
advanced_indicators = {}
|
| 56 |
-
ohlcv_available = raw_data.get('ohlcv', {})
|
| 57 |
-
for timeframe, candles in ohlcv_available.items():
|
| 58 |
-
if candles and len(candles) >= 20:
|
| 59 |
-
dataframe = self._create_dataframe(candles)
|
| 60 |
-
indicators = self.technical_analyzer.calculate_all_indicators(dataframe, timeframe)
|
| 61 |
-
advanced_indicators[timeframe] = indicators
|
| 62 |
-
base_analysis['advanced_indicators'] = advanced_indicators
|
| 63 |
-
|
| 64 |
-
# Monte Carlo (Phase 1)
|
| 65 |
-
monte_carlo_results = await self.monte_carlo_analyzer.generate_1h_price_distribution(ohlcv_available)
|
| 66 |
-
|
| 67 |
-
if monte_carlo_results:
|
| 68 |
-
base_analysis['monte_carlo_distribution'] = monte_carlo_results
|
| 69 |
-
base_analysis['monte_carlo_probability'] = monte_carlo_results.get('probability_of_gain', 0)
|
| 70 |
-
base_analysis['monte_carlo_details'] = self.monte_carlo_analyzer.simulation_results
|
| 71 |
-
else:
|
| 72 |
-
base_analysis['monte_carlo_distribution'] = None
|
| 73 |
-
base_analysis['monte_carlo_probability'] = 0
|
| 74 |
-
base_analysis['monte_carlo_details'] = self.monte_carlo_analyzer.simulation_results
|
| 75 |
-
|
| 76 |
-
# Pattern Analysis
|
| 77 |
-
# (This call will now use the *correctly loaded* V8 engine)
|
| 78 |
-
pattern_analysis = await self.pattern_analyzer.detect_chart_patterns(ohlcv_available)
|
| 79 |
-
base_analysis['pattern_analysis'] = pattern_analysis
|
| 80 |
-
|
| 81 |
-
# Whale Data
|
| 82 |
-
if preloaded_whale_data:
|
| 83 |
-
base_analysis['whale_data'] = preloaded_whale_data.get(symbol, {'data_available': False, 'reason': 'Not preloaded'})
|
| 84 |
-
else:
|
| 85 |
-
base_analysis['whale_data'] = {'data_available': False, 'reason': 'Preloading disabled'}
|
| 86 |
-
|
| 87 |
-
# 🔴 (This call now uses the Learning Hub via strategy_engine)
|
| 88 |
-
strategy_scores, base_scores = await self.strategy_engine.evaluate_all_strategies(base_analysis, self.market_context)
|
| 89 |
-
base_analysis['strategy_scores'] = strategy_scores
|
| 90 |
-
base_analysis['base_strategy_scores'] = base_scores
|
| 91 |
-
|
| 92 |
-
if base_scores:
|
| 93 |
-
best_strategy = max(base_scores.items(), key=lambda x: x[1])
|
| 94 |
-
best_strategy_name = best_strategy[0]
|
| 95 |
-
best_strategy_score = best_strategy[1]
|
| 96 |
-
base_analysis['recommended_strategy'] = best_strategy_name
|
| 97 |
-
base_analysis['strategy_confidence'] = best_strategy_score
|
| 98 |
-
base_analysis['target_strategy'] = best_strategy_name if best_strategy_score > 0.3 else 'GENERIC'
|
| 99 |
-
|
| 100 |
-
# 🔴 (V6.6) استدعاء الدالة المحدثة (بدون درجة الأخبار هنا، لأنها تضاف لاحقاً)
|
| 101 |
-
enhanced_score = self._calculate_enhanced_final_score(base_analysis)
|
| 102 |
-
base_analysis['enhanced_final_score'] = enhanced_score
|
| 103 |
-
|
| 104 |
-
return base_analysis
|
| 105 |
-
|
| 106 |
-
except Exception as strategy_error:
|
| 107 |
-
print(f"❌ Error in advanced analysis for {symbol}: {strategy_error}")
|
| 108 |
-
return base_analysis
|
| 109 |
-
|
| 110 |
-
except Exception as error:
|
| 111 |
-
print(f"❌ Fatal error in enhanced processing for {raw_data.get('symbol', 'unknown')}: {error}")
|
| 112 |
-
return None
|
| 113 |
-
|
| 114 |
-
def _create_dataframe(self, candles):
|
| 115 |
-
# (This function remains unchanged)
|
| 116 |
-
try:
|
| 117 |
-
if not candles: return pd.DataFrame()
|
| 118 |
-
df = pd.DataFrame(candles, columns=['timestamp', 'open', 'high', 'low', 'close', 'volume'])
|
| 119 |
-
df[['open', 'high', 'low', 'close', 'volume']] = df[['open', 'high', 'low', 'close', 'volume']].astype(float)
|
| 120 |
-
df['timestamp'] = pd.to_datetime(df['timestamp'], unit='ms')
|
| 121 |
-
df.set_index('timestamp', inplace=True)
|
| 122 |
-
df.sort_index(inplace=True)
|
| 123 |
-
return df
|
| 124 |
-
except Exception as e:
|
| 125 |
-
print(f"❌ Error creating DataFrame: {e}")
|
| 126 |
-
return pd.DataFrame()
|
| 127 |
|
| 128 |
-
|
| 129 |
-
|
| 130 |
-
|
| 131 |
-
|
| 132 |
-
|
| 133 |
-
|
| 134 |
-
|
| 135 |
-
|
| 136 |
-
# (جديد V6.6) جلب درجة الأخبار الإحصائية (الربح/الخسارة الفعلي)
|
| 137 |
-
# (هذه القيمة ستكون 0.0 لمعظم العمليات، إلا عند إعادة حساب Top 10)
|
| 138 |
-
# (القيمة هي PnL%، مثلاً: 1.1% أو -0.5%)
|
| 139 |
-
statistical_pnl = analysis.get('statistical_news_pnl', 0.0)
|
| 140 |
-
|
| 141 |
-
# (تطبيع PnL% إلى درجة من 0 إلى 1)
|
| 142 |
-
# نفترض أن أقصى تأثير هو -3% إلى +3%
|
| 143 |
-
clamped_pnl = max(min(statistical_pnl, 3.0), -3.0)
|
| 144 |
-
# (-3% -> 0.0)
|
| 145 |
-
# (0% -> 0.5)
|
| 146 |
-
# (+3% -> 1.0)
|
| 147 |
-
normalized_news_score = (clamped_pnl + 3.0) / 6.0
|
| 148 |
-
|
| 149 |
-
# --- 1. حساب درجة مونت كارلو (كما في V6.2) ---
|
| 150 |
-
mc_distribution = analysis.get('monte_carlo_distribution')
|
| 151 |
-
monte_carlo_score = 0
|
| 152 |
-
|
| 153 |
-
if mc_distribution:
|
| 154 |
-
prob_gain = mc_distribution.get('probability_of_gain', 0)
|
| 155 |
-
var_95_value = mc_distribution.get('risk_metrics', {}).get('VaR_95_value', 0)
|
| 156 |
-
current_price = analysis.get('current_price', 1)
|
| 157 |
-
|
| 158 |
-
if current_price > 0:
|
| 159 |
-
normalized_var = var_95_value / current_price
|
| 160 |
-
risk_penalty = 1.0
|
| 161 |
-
if normalized_var > 0.05: risk_penalty = 0.5
|
| 162 |
-
elif normalized_var > 0.03: risk_penalty = 0.8
|
| 163 |
-
|
| 164 |
-
normalized_prob_score = max(0.0, (prob_gain - 0.5) * 2)
|
| 165 |
-
monte_carlo_score = normalized_prob_score * risk_penalty
|
| 166 |
-
else:
|
| 167 |
-
monte_carlo_score = 0
|
| 168 |
-
|
| 169 |
-
# --- 2. حساب درجة الحيتان (كما في V6.2) ---
|
| 170 |
-
whale_confidence = 0
|
| 171 |
-
whale_data = analysis.get('whale_data')
|
| 172 |
-
if whale_data and whale_data.get('data_available'):
|
| 173 |
-
signal = whale_data.get('trading_signal', {})
|
| 174 |
-
if signal.get('action') != 'HOLD' and signal.get('confidence', 0) >= 0.5:
|
| 175 |
-
whale_confidence = signal.get('confidence', 0)
|
| 176 |
|
| 177 |
-
#
|
| 178 |
-
|
| 179 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 180 |
|
| 181 |
-
|
| 182 |
-
|
| 183 |
-
|
| 184 |
-
if pattern_confidence > 0: components.append(pattern_confidence); weights.append(0.20)
|
| 185 |
-
if strategy_confidence > 0: components.append(strategy_confidence); weights.append(0.15)
|
| 186 |
-
if whale_confidence > 0: components.append(whale_confidence); weights.append(0.20)
|
| 187 |
|
| 188 |
-
#
|
| 189 |
-
|
| 190 |
-
|
|
|
|
|
|
|
| 191 |
|
|
|
|
|
|
|
|
|
|
| 192 |
|
| 193 |
-
|
| 194 |
-
total_weight = sum(weights)
|
| 195 |
-
if total_weight == 0: return 0
|
| 196 |
-
enhanced_score = sum(comp * weight for comp, weight in zip(components, weights)) / total_weight
|
| 197 |
-
|
| 198 |
-
# --- 4. ( V6.3) تطبيق 'عامل جزاء الإرهاق' ---
|
| 199 |
-
exhaustion_penalty_factor = 1.0
|
| 200 |
-
|
| 201 |
-
# (جلب البيانات المطلوبة من القاموس)
|
| 202 |
-
price_change_24h = analysis.get('price_change_24h', 0)
|
| 203 |
-
rsi_1d = analysis.get('advanced_indicators', {}).get('1d', {}).get('rsi', 50)
|
| 204 |
-
rsi_4h = analysis.get('advanced_indicators', {}).get('4h', {}).get('rsi', 50)
|
| 205 |
-
|
| 206 |
-
if price_change_24h > 60 and (rsi_1d > 80 or rsi_4h > 80):
|
| 207 |
-
exhaustion_penalty_factor = 0.4 # (عقوبة قاسية - 60%)
|
| 208 |
-
elif price_change_24h > 40 and (rsi_1d > 75 or rsi_4h > 75):
|
| 209 |
-
exhaustion_penalty_factor = 0.6 # (عقوبة متوسطة - 40%)
|
| 210 |
-
|
| 211 |
-
if exhaustion_penalty_factor < 1.0:
|
| 212 |
-
# (اختياري: للطباعة التشخيصية)
|
| 213 |
-
# print(f" ⚠️ [Processor] {analysis.get('symbol')} Exhaustion Penalty Applied! Score {enhanced_score:.2f} * {exhaustion_penalty_factor} (24h: {price_change_24h:+.1f}%, RSI 1D: {rsi_1d:.1f})")
|
| 214 |
-
pass
|
| 215 |
|
| 216 |
-
final_penalized_score = enhanced_score * exhaustion_penalty_factor
|
| 217 |
-
|
| 218 |
-
return min(max(final_penalized_score, 0.0), 1.0)
|
| 219 |
-
|
| 220 |
except Exception as e:
|
| 221 |
-
print(f"❌
|
| 222 |
-
|
| 223 |
-
# 🔴 --- END OF CHANGE --- 🔴
|
| 224 |
-
|
| 225 |
-
async def process_and_score_symbol(self, raw_data):
|
| 226 |
-
"""(محدث V6.3) إضافة price_change_24h إلى القاموس"""
|
| 227 |
-
try:
|
| 228 |
-
symbol = raw_data['symbol']
|
| 229 |
-
ohlcv_data = raw_data.get('ohlcv')
|
| 230 |
-
if not ohlcv_data: return None
|
| 231 |
-
current_price = raw_data.get('current_price', 0)
|
| 232 |
-
layer1_score = raw_data.get('layer1_score', 0)
|
| 233 |
-
reasons = raw_data.get('reasons_for_candidacy', [])
|
| 234 |
-
final_score = layer1_score
|
| 235 |
-
successful_timeframes = raw_data.get('successful_timeframes', 0)
|
| 236 |
-
|
| 237 |
-
# 🔴 --- START OF CHANGE (V6.3) --- 🔴
|
| 238 |
-
price_change_24h = raw_data.get('price_change_24h', 0)
|
| 239 |
-
# 🔴 --- END OF CHANGE --- 🔴
|
| 240 |
-
|
| 241 |
-
return {
|
| 242 |
-
'symbol': symbol, 'current_price': current_price, 'final_score': final_score,
|
| 243 |
-
'enhanced_final_score': final_score, 'reasons_for_candidacy': reasons,
|
| 244 |
-
'layer1_score': layer1_score, 'ohlcv': ohlcv_data,
|
| 245 |
-
'successful_timeframes': successful_timeframes,
|
| 246 |
-
'price_change_24h': price_change_24h # (إضافة الحقل هنا)
|
| 247 |
-
}
|
| 248 |
-
except Exception as error:
|
| 249 |
-
print(f"❌ Error in basic symbol processing {raw_data.get('symbol', 'unknown')}: {error}")
|
| 250 |
return None
|
| 251 |
|
| 252 |
-
def
|
| 253 |
-
|
| 254 |
-
|
| 255 |
-
|
| 256 |
-
|
| 257 |
-
|
| 258 |
-
|
| 259 |
-
|
| 260 |
-
|
| 261 |
-
|
| 262 |
-
print(f" {i+1}. {symbol}: 📊 {score:.3f} | TFs: {timeframes}/6")
|
| 263 |
-
if mc_dist:
|
| 264 |
-
mc_pi_90 = mc_dist.get('prediction_interval_90', [0,0]); mc_var = mc_dist.get('risk_metrics', {}).get('VaR_95_value', 0)
|
| 265 |
-
print(f" 🎯 MonteCarlo: 90% PI [{mc_pi_90[0]:.4f} - {mc_pi_90[1]:.4f}] | VaR: ${mc_var:.4f}")
|
| 266 |
-
print(f" 🎯 Strategy: {strategy} | Pattern: {pattern}")
|
| 267 |
-
whale_data = c.get('whale_data')
|
| 268 |
-
if whale_data and whale_data.get('data_available'):
|
| 269 |
-
signal = whale_data.get('trading_signal', {}); print(f" 🐋 Whale: {signal.get('action', 'HOLD')} (Conf: {signal.get('confidence', 0):.2f})")
|
| 270 |
-
# (V6.6) طباعة درجة الأخبار الإحصائية إن وجدت
|
| 271 |
-
if 'statistical_news_pnl' in c:
|
| 272 |
-
print(f" 📰 News (Learned PnL): {c['statistical_news_pnl']:.2f}%")
|
| 273 |
-
return top_candidates
|
| 274 |
|
| 275 |
-
async def
|
| 276 |
-
|
| 277 |
-
|
| 278 |
-
tasks_results = []
|
| 279 |
-
async def process_symbol_with_semaphore(symbol_data):
|
| 280 |
-
async with semaphore:
|
| 281 |
-
try:
|
| 282 |
-
return await self.process_and_score_symbol_enhanced(symbol_data, preloaded_whale_data)
|
| 283 |
-
except Exception as e:
|
| 284 |
-
return e
|
| 285 |
try:
|
| 286 |
-
|
| 287 |
-
|
| 288 |
-
|
| 289 |
-
|
| 290 |
-
|
| 291 |
-
|
| 292 |
-
|
| 293 |
-
|
| 294 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 295 |
|
| 296 |
-
def
|
| 297 |
-
|
| 298 |
-
|
| 299 |
-
|
| 300 |
-
|
| 301 |
-
|
|
|
|
| 302 |
try:
|
| 303 |
-
|
| 304 |
-
|
| 305 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 306 |
|
| 307 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# ml_engine/processor.py (V11.0 - XGBoost Multi-TF Integrated & New Scoring)
|
| 2 |
import pandas as pd
|
| 3 |
import numpy as np
|
|
|
|
| 4 |
import asyncio
|
| 5 |
import json
|
| 6 |
+
import traceback
|
| 7 |
|
| 8 |
+
# استيراد المحركات من نفس المجلد
|
| 9 |
from .indicators import AdvancedTechnicalAnalyzer
|
| 10 |
from .monte_carlo import MonteCarloAnalyzer
|
| 11 |
+
# لا نحتاج لاستيراد ChartPatternAnalyzer هنا لأنه سيأتي جاهزاً من DataManager
|
| 12 |
from .strategies import MultiStrategyEngine
|
| 13 |
|
| 14 |
class MLProcessor:
|
| 15 |
+
def __init__(self, market_context, data_manager, learning_hub):
|
| 16 |
self.market_context = market_context
|
| 17 |
self.data_manager = data_manager
|
| 18 |
+
self.learning_hub = learning_hub
|
| 19 |
|
| 20 |
self.technical_analyzer = AdvancedTechnicalAnalyzer()
|
| 21 |
+
self.strategy_engine = MultiStrategyEngine(data_manager, learning_hub)
|
|
|
|
| 22 |
self.monte_carlo_analyzer = MonteCarloAnalyzer()
|
| 23 |
|
| 24 |
+
# استخدام محرك الأنماط المركزي المجهز في DataManager
|
|
|
|
|
|
|
| 25 |
if self.data_manager and self.data_manager.pattern_analyzer:
|
| 26 |
+
self.pattern_engine = self.data_manager.pattern_analyzer
|
|
|
|
| 27 |
else:
|
| 28 |
+
self.pattern_engine = None
|
| 29 |
+
print("⚠️ [MLProcessor] تحذير: محرك الأنماط غير متوفر من DataManager.")
|
|
|
|
|
|
|
|
|
|
| 30 |
|
| 31 |
async def process_and_score_symbol_enhanced(self, raw_data, preloaded_whale_data: dict = None):
|
| 32 |
"""
|
| 33 |
+
المعالجة المركزية للعملة: تجمع الأنماط (4 أطر)، المؤشرات، ومونت كارلو المتقدمة.
|
| 34 |
"""
|
| 35 |
try:
|
| 36 |
+
symbol = raw_data.get('symbol')
|
| 37 |
+
ohlcv_data = raw_data.get('ohlcv') # يجب أن يحتوي على {'15m': [], '1h': [], ...}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 38 |
|
| 39 |
+
if not symbol or not ohlcv_data: return None
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 40 |
|
| 41 |
+
# 1. تجهيز الهيكل الأساسي للنتيجة
|
| 42 |
+
analysis_result = {
|
| 43 |
+
'symbol': symbol,
|
| 44 |
+
'current_price': raw_data.get('current_price', 0.0),
|
| 45 |
+
'layer1_score': raw_data.get('layer1_score', 0.0),
|
| 46 |
+
'ohlcv': ohlcv_data, # نحتفظ بالبيانات الخام للرجوع إليها
|
| 47 |
+
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 48 |
|
| 49 |
+
# 2. تشغيل التحليلات المتقدمة بالتوازي لسرعة الأداء
|
| 50 |
+
# (أنماط XGBoost، مؤشرات فنية، مونت كارلو المتقدمة)
|
| 51 |
+
tasks = [
|
| 52 |
+
self._run_xgboost_patterns(ohlcv_data),
|
| 53 |
+
self._run_advanced_indicators(ohlcv_data),
|
| 54 |
+
self._run_advanced_monte_carlo(ohlcv_data)
|
| 55 |
+
]
|
| 56 |
+
patterns, indicators, mc_results = await asyncio.gather(*tasks)
|
| 57 |
|
| 58 |
+
analysis_result['pattern_analysis'] = patterns
|
| 59 |
+
analysis_result['advanced_indicators'] = indicators
|
| 60 |
+
analysis_result['monte_carlo_distribution'] = mc_results
|
|
|
|
|
|
|
|
|
|
| 61 |
|
| 62 |
+
# 3. دمج بيانات الحيتان (إذا توفرت مسبقاً)
|
| 63 |
+
if preloaded_whale_data and symbol in preloaded_whale_data:
|
| 64 |
+
analysis_result['whale_data'] = preloaded_whale_data[symbol]
|
| 65 |
+
else:
|
| 66 |
+
analysis_result['whale_data'] = {'data_available': False}
|
| 67 |
|
| 68 |
+
# 4. حساب الدرجة النهائية الموزونة (V11.0 New Weights)
|
| 69 |
+
final_score = self._calculate_final_weighted_score(analysis_result)
|
| 70 |
+
analysis_result['enhanced_final_score'] = final_score
|
| 71 |
|
| 72 |
+
return analysis_result
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 73 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 74 |
except Exception as e:
|
| 75 |
+
print(f"❌ [Processor] خطأ فادح في معالجة {symbol}: {e}")
|
| 76 |
+
traceback.print_exc()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 77 |
return None
|
| 78 |
|
| 79 |
+
async def _run_xgboost_patterns(self, ohlcv_data):
|
| 80 |
+
"""تشغيل محرك الأنماط الجديد على كافة الأطر الزمنية المتاحة"""
|
| 81 |
+
if not self.pattern_engine or not self.pattern_engine.initialized:
|
| 82 |
+
return {'pattern_confidence': 0.0, 'details': {}}
|
| 83 |
+
try:
|
| 84 |
+
# المحرك الجديد يعيد نتيجة مجمعة جاهزة
|
| 85 |
+
return await self.pattern_engine.detect_chart_patterns(ohlcv_data)
|
| 86 |
+
except Exception as e:
|
| 87 |
+
print(f"⚠️ خطأ في تحليل الأنماط: {e}")
|
| 88 |
+
return {'pattern_confidence': 0.0, 'details': {'error': str(e)}}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 89 |
|
| 90 |
+
async def _run_advanced_indicators(self, ohlcv_data):
|
| 91 |
+
"""حساب المؤشرات الفنية المتقدمة لأهم الأطر الزمنية"""
|
| 92 |
+
indicators = {}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 93 |
try:
|
| 94 |
+
# نركز على 1h و 4h للتحليل الفني العام
|
| 95 |
+
for tf in ['1h', '4h']:
|
| 96 |
+
if tf in ohlcv_data and len(ohlcv_data[tf]) >= 50:
|
| 97 |
+
df = self._create_dataframe(ohlcv_data[tf])
|
| 98 |
+
indicators[tf] = self.technical_analyzer.calculate_all_indicators(df, tf)
|
| 99 |
+
except Exception: pass
|
| 100 |
+
return indicators
|
| 101 |
+
|
| 102 |
+
async def _run_advanced_monte_carlo(self, ohlcv_data):
|
| 103 |
+
"""تشغيل محاكاة مونت كارلو المتقدمة (GARCH+LGBM) على إطار الساعة"""
|
| 104 |
+
try:
|
| 105 |
+
# نستخدم النسخة المتقدمة (المرحلة 2+3) بدلاً من البسيطة
|
| 106 |
+
return await self.monte_carlo_analyzer.generate_1h_distribution_advanced(ohlcv_data)
|
| 107 |
+
except Exception: return None
|
| 108 |
|
| 109 |
+
def _calculate_final_weighted_score(self, analysis):
|
| 110 |
+
"""
|
| 111 |
+
(V11.0) حساب الدرجة النهائية بالأوزان الجديدة:
|
| 112 |
+
- التحليل الفني: 85% (أنماط 40%، مؤشرات 30%، مونت كارلو 30% من الـ 85%)
|
| 113 |
+
- الحيتان: 10%
|
| 114 |
+
- الأخبار: 5%
|
| 115 |
+
"""
|
| 116 |
try:
|
| 117 |
+
# 1. المكون الفني (Total Technical Score)
|
| 118 |
+
pattern_score = analysis.get('pattern_analysis', {}).get('pattern_confidence', 0.0)
|
| 119 |
+
|
| 120 |
+
# حساب درجة المؤشرات (متوسط بسيط لبعض المؤشرات الرئيسية كمثال)
|
| 121 |
+
inds = analysis.get('advanced_indicators', {}).get('1h', {})
|
| 122 |
+
rsi = inds.get('rsi', 50)
|
| 123 |
+
macd = inds.get('macd_hist', 0)
|
| 124 |
+
ind_score = 0.5
|
| 125 |
+
if rsi > 50: ind_score += 0.1
|
| 126 |
+
if macd > 0: ind_score += 0.1
|
| 127 |
+
# (يمكن تعقيد هذا الجزء أكثر لاحقاً)
|
| 128 |
+
|
| 129 |
+
# درجة مونت كارلو
|
| 130 |
+
mc_prob = analysis.get('monte_carlo_distribution', {}).get('probability_of_gain', 0.5)
|
| 131 |
+
mc_score = max(0.0, min(1.0, (mc_prob - 0.5) * 2.0)) # تطبيع إلى 0-1
|
| 132 |
+
|
| 133 |
+
# دمج المكون الفني (85% من الإجمالي)
|
| 134 |
+
technical_sub_score = (pattern_score * 0.40) + (ind_score * 0.30) + (mc_score * 0.30)
|
| 135 |
+
weighted_technical = technical_sub_score * 0.85
|
| 136 |
+
|
| 137 |
+
# 2. مكون الحيتان (10%)
|
| 138 |
+
whale_score = 0.0
|
| 139 |
+
whale_data = analysis.get('whale_data', {})
|
| 140 |
+
if whale_data.get('data_available'):
|
| 141 |
+
# نفترض وجود درجة ثقة جاهزة من 0 لـ 1
|
| 142 |
+
whale_score = whale_data.get('confidence_score', 0.5)
|
| 143 |
+
weighted_whale = whale_score * 0.10
|
| 144 |
+
|
| 145 |
+
# 3. مكون الأخبار (5%)
|
| 146 |
+
news_score = 0.5 # محايد افتراضياً
|
| 147 |
+
# (سيتم تحديث هذا الجزء لاحقاً عند توفر تحليل الأخبار الحقيقي)
|
| 148 |
+
weighted_news = news_score * 0.05
|
| 149 |
+
|
| 150 |
+
# الدرجة النهائية
|
| 151 |
+
return weighted_technical + weighted_whale + weighted_news
|
| 152 |
+
|
| 153 |
+
except Exception as e:
|
| 154 |
+
# print(f"⚠️ خطأ في حساب الدرجة النهائية: {e}")
|
| 155 |
+
return analysis.get('layer1_score', 0.0) * 0.85 # عودة للدرجة الأولية
|
| 156 |
|
| 157 |
+
def _create_dataframe(self, candles):
|
| 158 |
+
if not candles: return pd.DataFrame()
|
| 159 |
+
df = pd.DataFrame(candles, columns=['ts', 'open', 'high', 'low', 'close', 'volume'])
|
| 160 |
+
df[['open', 'high', 'low', 'close', 'volume']] = df[['open', 'high', 'low', 'close', 'volume']].astype(float)
|
| 161 |
+
df['ts'] = pd.to_datetime(df['ts'], unit='ms')
|
| 162 |
+
df.set_index('ts', inplace=True)
|
| 163 |
+
return df
|
| 164 |
+
|
| 165 |
+
print("✅ ML Processor loaded - V11.0 (XGBoost Multi-TF & New Weights)")
|