Riy777 commited on
Commit
172cf4d
·
1 Parent(s): 909d04f

Create titan_engine.py

Browse files
Files changed (1) hide show
  1. ml_engine/titan_engine.py +152 -0
ml_engine/titan_engine.py ADDED
@@ -0,0 +1,152 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # ml_engine/titan_engine.py
2
+ # (V1.0 - Titan Inference Engine)
3
+
4
+ import os
5
+ import joblib
6
+ import numpy as np
7
+ import pandas as pd
8
+ import pandas_ta as ta
9
+ import xgboost as xgb
10
+ import json
11
+
12
+ class TitanEngine:
13
+ def __init__(self, model_dir="ml_models/layer2"):
14
+ self.model_path = os.path.join(model_dir, "Titan_XGB_V1.json")
15
+ self.features_path = os.path.join(model_dir, "Titan_Features.pkl")
16
+ self.model = None
17
+ self.feature_names = None
18
+ self.initialized = False
19
+
20
+ async def initialize(self):
21
+ """تحميل النموذج وقائمة الميزات من القرص"""
22
+ print(f"🛡️ [Titan] جاري تهيئة المحرك من {self.model_path}...")
23
+ try:
24
+ if os.path.exists(self.model_path) and os.path.exists(self.features_path):
25
+ # تحميل نموذج XGBoost
26
+ self.model = xgb.Booster()
27
+ self.model.load_model(self.model_path)
28
+
29
+ # تحميل قائمة الميزات لضمان الترتيب الصحيح
30
+ self.feature_names = joblib.load(self.features_path)
31
+
32
+ self.initialized = True
33
+ print(f"✅ [Titan] تم التحميل بنجاح. جاهز بـ {len(self.feature_names)} ميزة.")
34
+ else:
35
+ print(f"❌ [Titan] ملفات النموذج مفقودة!")
36
+ except Exception as e:
37
+ print(f"❌ [Titan] خطأ فادح أثناء التهيئة: {e}")
38
+
39
+ def apply_inverted_pyramid(self, df, tf):
40
+ """نفس منطق هندسة الميزات المستخدم في التدريب تماماً"""
41
+ df = df.copy().sort_values('timestamp').reset_index(drop=True)
42
+ # تعيين الفهرس للسهولة في pandas_ta
43
+ df = df.set_index(pd.DatetimeIndex(pd.to_datetime(df['timestamp'], unit='ms')))
44
+
45
+ # --- المستوى 1: دقيق (5m, 15m) ---
46
+ if tf in ['5m', '15m']:
47
+ df['RSI'] = ta.rsi(df['close'], length=14)
48
+ df['MACD'] = ta.macd(df['close']).iloc[:, 0]
49
+ df['MACD_h'] = ta.macd(df['close']).iloc[:, 1]
50
+ df['CCI'] = ta.cci(df['high'], df['low'], df['close'], length=20)
51
+ df['ADX'] = ta.adx(df['high'], df['low'], df['close'], length=14).iloc[:, 0]
52
+ for p in [9, 21, 50, 200]:
53
+ ema = ta.ema(df['close'], length=p)
54
+ df[f'EMA_{p}_dist'] = (df['close'] / ema) - 1
55
+ bb = ta.bbands(df['close'], length=20, std=2.0)
56
+ df['BB_w'] = (bb.iloc[:, 2] - bb.iloc[:, 0]) / bb.iloc[:, 1]
57
+ df['BB_p'] = (df['close'] - bb.iloc[:, 0]) / (bb.iloc[:, 2] - bb.iloc[:, 0])
58
+ df['MFI'] = ta.mfi(df['high'], df['low'], df['close'], df['volume'], length=14)
59
+ vwap = ta.vwap(df['high'], df['low'], df['close'], df['volume'])
60
+ df['VWAP_dist'] = (df['close'] / vwap) - 1
61
+
62
+ # --- المستوى 2: تكتيكي (1h, 4h) ---
63
+ elif tf in ['1h', '4h']:
64
+ df['RSI'] = ta.rsi(df['close'], length=14)
65
+ df['MACD_h'] = ta.macd(df['close']).iloc[:, 1]
66
+ df['EMA_50_dist'] = (df['close'] / ta.ema(df['close'], length=50)) - 1
67
+ df['EMA_200_dist'] = (df['close'] / ta.ema(df['close'], length=200)) - 1
68
+ df['ATR_pct'] = ta.atr(df['high'], df['low'], df['close'], length=14) / df['close']
69
+
70
+ # --- المستوى 3: استراتيجي (1d) ---
71
+ elif tf == '1d':
72
+ df['RSI'] = ta.rsi(df['close'], length=14)
73
+ df['EMA_200_dist'] = (df['close'] / ta.ema(df['close'], length=200)) - 1
74
+ adx = ta.adx(df['high'], df['low'], df['close'])
75
+ if adx is not None and not adx.empty:
76
+ df['Trend_Strong'] = np.where(adx.iloc[:, 0] > 25, 1, 0)
77
+ else:
78
+ df['Trend_Strong'] = 0
79
+
80
+ return df.reset_index(drop=True)
81
+
82
+ def predict(self, ohlcv_data: dict) -> dict:
83
+ """
84
+ استقبال البيانات الخام (Dictionary of DataFrames/Lists)،
85
+ تجهيزها، ثم استدعاء النموذج للتنبؤ.
86
+ """
87
+ if not self.initialized or not self.model:
88
+ return {'score': 0.0, 'error': 'Titan not initialized'}
89
+
90
+ try:
91
+ # 1. تجهيز البيانات لكل إطار
92
+ processed_tfs = {}
93
+ for tf, data in ohlcv_data.items():
94
+ if not data: continue
95
+ # تحويل القوائم إلى DataFrame إذا لزم الأمر
96
+ if isinstance(data, list):
97
+ df = pd.DataFrame(data, columns=['timestamp', 'open', 'high', 'low', 'close', 'volume'])
98
+ else:
99
+ df = data.copy()
100
+
101
+ # تطبيق المؤشرات حسب الإطار
102
+ df = self.apply_inverted_pyramid(df, tf)
103
+ processed_tfs[tf] = df
104
+
105
+ # 2. الدمج (Alignment) للحصول على آخر ��قطة (Latest Snapshot)
106
+ if '5m' not in processed_tfs:
107
+ return {'score': 0.0, 'error': 'Missing 5m base timeframe'}
108
+
109
+ # نأخذ آخر صف فقط من الـ 5m كأساس
110
+ latest_5m = processed_tfs['5m'].iloc[-1:].copy()
111
+ latest_ts = latest_5m['timestamp'].iloc[0]
112
+
113
+ base_row = latest_5m.add_prefix('5m_').rename(columns={'5m_timestamp': 'timestamp'})
114
+
115
+ # دمج باقي الأطر (نأخذ آخر شمعة أغلقت قبل أو مع شمعة الـ 5m الحالية)
116
+ for tf, df in processed_tfs.items():
117
+ if tf == '5m': continue
118
+ # العثور على الشمعة المناسبة زمنياً
119
+ relevant_row = df[df['timestamp'] <= latest_ts].iloc[-1:].copy()
120
+ if relevant_row.empty: continue
121
+
122
+ # تجهيز الأعمدة للدمج
123
+ cols = [c for c in relevant_row.columns if c not in ['timestamp','open','high','low','close','volume']]
124
+ for col in cols:
125
+ base_row[f"{tf}_{col}"] = relevant_row[col].values[0]
126
+
127
+ # 3. تجهيز شعاع الإدخال (Feature Vector)
128
+ # التأكد من وجود كل الميزات المطلوبة بالترتيب الصحيح
129
+ input_data = []
130
+ for feat in self.feature_names:
131
+ val = base_row.get(feat, np.nan)
132
+ # إذا كانت القيمة مصفوفة أو سلسلة بانداز، نأخذ القيمة الأولى
133
+ if isinstance(val, (pd.Series, np.ndarray)):
134
+ val = val.iloc[0] if len(val) > 0 else np.nan
135
+ input_data.append(val)
136
+
137
+ # 4. التنبؤ
138
+ # تحويل إلى DMatrix (تنسيق XGBoost السريع)
139
+ dtest = xgb.DMatrix([input_data], feature_names=self.feature_names)
140
+ prediction = self.model.predict(dtest)[0] # إرجاع الاحتمالية الأولى
141
+
142
+ return {
143
+ 'score': float(prediction),
144
+ 'timestamp': int(latest_ts),
145
+ 'status': 'OK'
146
+ }
147
+
148
+ except Exception as e:
149
+ # print(f"⚠️ [Titan Error] {e}")
150
+ import traceback
151
+ traceback.print_exc()
152
+ return {'score': 0.0, 'error': str(e)}