|
|
|
|
|
import numpy as np |
|
|
import pandas as pd |
|
|
from arch import arch_model |
|
|
import lightgbm as lgb |
|
|
import traceback |
|
|
import json |
|
|
|
|
|
|
|
|
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 = {} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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 = (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) |
|
|
|
|
|
|
|
|
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)) |
|
|
|
|
|
|
|
|
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") |