Spaces:
Running
Running
| # ml_engine/monte_carlo.py (V10.2 - Fix: 1H Horizon with "Any Gain" Target) | |
| import numpy as np | |
| import pandas as pd | |
| from arch import arch_model | |
| import lightgbm as lgb | |
| import traceback | |
| import json | |
| # محاولة استيراد pandas_ta | |
| try: | |
| import pandas_ta as ta | |
| except ImportError: | |
| ta = None | |
| def _sanitize_results_for_json(results_dict): | |
| if isinstance(results_dict, dict): | |
| return {k: _sanitize_results_for_json(v) for k, v in results_dict.items()} | |
| elif isinstance(results_dict, list): | |
| return [_sanitize_results_for_json(v) for v in results_dict] | |
| elif isinstance(results_dict, np.ndarray): | |
| return results_dict.tolist() | |
| elif isinstance(results_dict, (np.float64, np.float32)): | |
| return float(results_dict) | |
| elif isinstance(results_dict, (np.int64, np.int32)): | |
| return int(results_dict) | |
| else: | |
| return results_dict | |
| class MonteCarloAnalyzer: | |
| def __init__(self): | |
| self.simulation_results = {} | |
| # ================================================================== | |
| # 🔴 الدالة المبسطة للرانكر (تم تعديل الهدف V10.2) | |
| # ================================================================== | |
| def generate_1h_price_distribution_simple(self, closes_np: np.ndarray) -> dict: | |
| """ | |
| (V10.2) محاكاة سريعة لساعة واحدة قادمة. | |
| الهدف: حساب احتمالية أن يكون الإغلاق القادم أعلى من السعر الحالي (أي ربح > 0). | |
| """ | |
| try: | |
| if len(closes_np) < 30: | |
| return {'mc_prob_gain': 0.5, 'mc_var_95_pct': 0.0, 'error': True} | |
| current_price = closes_np[-1] | |
| if current_price <= 0: | |
| return {'mc_prob_gain': 0.5, 'mc_var_95_pct': 0.0, 'error': True} | |
| # حساب العوائد اللوغاريتمية | |
| log_returns = np.log(closes_np[1:] / closes_np[:-1]) | |
| log_returns = log_returns[~np.isnan(log_returns) & ~np.isinf(log_returns)] | |
| if len(log_returns) < 20: | |
| return {'mc_prob_gain': 0.5, 'mc_var_95_pct': 0.0, 'error': True} | |
| mean_return = np.mean(log_returns) | |
| std_return = np.std(log_returns) | |
| if std_return < 1e-6: # انعدام تقلب شبه كامل | |
| return {'mc_prob_gain': 0.5, 'mc_var_95_pct': 0.0, 'error': True} | |
| # إعدادات المحاكاة (لساعة واحدة فقط) | |
| num_simulations = 1000 | |
| t_df = 10 | |
| # Drift & Diffusion لساعة واحدة | |
| drift = (mean_return - 0.5 * std_return**2) | |
| diffusion = std_return * np.random.standard_t(df=t_df, size=num_simulations) | |
| simulated_log_returns = drift + diffusion | |
| simulated_prices_1h = current_price * np.exp(simulated_log_returns) | |
| # 🔴 التعديل الجوهري: احتمالية "أي ربح" بدلاً من ربح محدد | |
| # هل السعر المتوقع بعد ساعة > السعر الحالي؟ | |
| probability_of_gain = np.mean(simulated_prices_1h > current_price) | |
| # حساب المخاطرة (VaR 95%) | |
| var95_price = np.percentile(simulated_prices_1h, 5) | |
| var95_pct = (current_price - var95_price) / current_price | |
| return { | |
| 'mc_prob_gain': float(probability_of_gain), | |
| 'mc_var_95_pct': float(var95_pct), | |
| 'error': False | |
| } | |
| except Exception: | |
| return {'mc_prob_gain': 0.5, 'mc_var_95_pct': 0.0, 'error': True} | |
| # ... (الدوال المتقدمة تبقى كما هي أو يمكن تحديثها لاحقاً بنفس المنطق) ... | |
| async def generate_1h_distribution_advanced(self, ohlcv_data, target_profit_percent=0.005): | |
| # (سأترك هذه كما هي حالياً لأنها تستخدم في مراحل متقدمة قد تحتاج هدفاً محدداً، | |
| # لكن يمكننا تعديلها أيضاً إذا أردت توحيد المعايير) | |
| try: | |
| if not ohlcv_data or '1h' not in ohlcv_data or len(ohlcv_data['1h']) < 50: return None | |
| candles = ohlcv_data['1h'] | |
| df = pd.DataFrame(candles, columns=['ts', 'o', 'h', 'l', 'c', 'v']) | |
| df[['o', 'h', 'l', 'c', 'v']] = df[['o', 'h', 'l', 'c', 'v']].astype(float) | |
| current_price = df['c'].iloc[-1] | |
| df['log_ret'] = np.log(df['c'] / df['c'].shift(1)).fillna(0) | |
| rets = df['log_ret'].replace([np.inf, -np.inf], 0) | |
| vol_est = np.std(rets.iloc[-30:]) | |
| try: | |
| am = arch_model(rets * 100, vol='Garch', p=1, q=1, dist='t', rescale=False) | |
| res = am.fit(disp='off'); vol_est = np.sqrt(res.forecast(horizon=1).variance.iloc[-1,0])/100 | |
| except: pass | |
| drift = (np.mean(rets.iloc[-30:]) - 0.5 * vol_est**2) | |
| sim_prices = current_price * np.exp(drift + vol_est * np.random.standard_t(df=10, size=5000)) | |
| # هنا أيضاً يمكن تخفيف الهدف إذا أردت، لكن سأبقيه 0.5% للمرحلة المتقدمة | |
| prob_gain = np.mean(sim_prices >= current_price * (1 + target_profit_percent)) | |
| var95 = current_price - np.percentile(sim_prices, 5) | |
| return _sanitize_results_for_json({ | |
| 'probability_of_gain': prob_gain, | |
| 'risk_metrics': {'VaR_95_value': var95}, | |
| 'simulation_model': 'Advanced_GARCH_1h' | |
| }) | |
| except Exception: return None | |
| print("✅ ML Module: Monte Carlo V10.2 (Any Gain Target) loaded") |