Riy777 commited on
Commit
7c3e1f5
·
verified ·
1 Parent(s): 0749e35

Update r2.py

Browse files
Files changed (1) hide show
  1. r2.py +120 -205
r2.py CHANGED
@@ -1,4 +1,4 @@
1
- # r2.py (V11.0 - GEM-Architect: Full Stack Restoration & Accounting Fix)
2
  import os
3
  import traceback
4
  import json
@@ -17,21 +17,18 @@ R2_ACCESS_KEY_ID = os.getenv("R2_ACCESS_KEY_ID")
17
  R2_SECRET_ACCESS_KEY = os.getenv("R2_SECRET_ACCESS_KEY")
18
  BUCKET_NAME = "trading"
19
 
20
- # الرصيد الافتراضي عند إنشاء محفظة جديدة (تم تحديثه ليكون منطقياً للمحاكاة)
21
- INITIAL_CAPITAL = 100.0
22
 
23
- # 📁 مفاتيح الملفات في R2 (File Keys)
24
- # 1. التعلم العميق للحيتان
25
  WHALE_LEARNING_PENDING_KEY = "learning_whale_pending_records.json"
26
  WHALE_LEARNING_COMPLETED_KEY = "learning_whale_completed_records.json"
27
  WHALE_LEARNING_CONFIG_KEY = "learning_whale_optimal_config.json"
28
 
29
- # 2. المحاسبة والتاريخ
30
  PORTFOLIO_STATE_KEY = "portfolio_state.json"
31
  OPEN_TRADES_KEY = "open_trades.json"
32
  CLOSED_TRADES_KEY = "closed_trades_history.json"
33
 
34
- # 3. النظام والمرشحين
35
  CANDIDATES_KEY = "Candidates.json"
36
  CONTRACTS_DB_KEY = "contracts.json"
37
  SYSTEM_LOGS_KEY = "system_logs.json"
@@ -53,7 +50,6 @@ class R2Service:
53
  self.lock_acquired = False
54
  self.BUCKET_NAME = BUCKET_NAME
55
 
56
- # منع تكرار طباعة التحذيرات
57
  self._open_trades_warning_printed = False
58
  self._portfolio_warning_printed = False
59
  self._contracts_warning_printed = False
@@ -61,6 +57,49 @@ class R2Service:
61
  except Exception as e:
62
  raise RuntimeError(f"Failed to initialize S3 client: {e}")
63
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
64
  # ==============================================================================
65
  # 🔒 إدارة القفل (Lock Mechanism)
66
  # ==============================================================================
@@ -83,7 +122,6 @@ class R2Service:
83
  except Exception as e:
84
  print(f"❌ Failed to acquire lock: {e}")
85
  time.sleep(1)
86
- print(f"❌ Failed to acquire lock after {max_retries} attempts.")
87
  return False
88
 
89
  def release_lock(self):
@@ -100,7 +138,6 @@ class R2Service:
100
  # 📊 إدارة المرشحين (Candidates)
101
  # ==============================================================================
102
  async def save_candidates_async(self, candidates):
103
- """حفظ بيانات المرشحين العشرة في ملف منفصل في R2"""
104
  try:
105
  data = {
106
  "timestamp": datetime.now().isoformat(),
@@ -112,29 +149,16 @@ class R2Service:
112
  Bucket=BUCKET_NAME, Key=CANDIDATES_KEY, Body=data_json, ContentType="application/json"
113
  )
114
  print(f"✅ تم حفظ {len(candidates)} مرشح في ملف Candidates في R2")
115
-
116
- # عرض معلومات المرشحين المحفوظين
117
- print("📊 المرشحون المحفوظون:")
118
- for i, candidate in enumerate(candidates):
119
- symbol = candidate.get('symbol', 'Unknown')
120
- score = candidate.get('enhanced_final_score', 0)
121
- strategy = candidate.get('target_strategy', 'GENERIC')
122
- print(f" {i+1}. {symbol}: {score:.3f} - {strategy}")
123
-
124
  except Exception as e:
125
  print(f"❌ فشل حفظ المرشحين في R2: {e}")
126
 
127
  async def load_candidates_async(self):
128
- """تحميل بيانات المرشحين من R2"""
129
  try:
130
  response = self.s3_client.get_object(Bucket=BUCKET_NAME, Key=CANDIDATES_KEY)
131
  data = json.loads(response['Body'].read())
132
- candidates = data.get('candidates', [])
133
- print(f"✅ تم تحميل {len(candidates)} مرشح من R2")
134
- return candidates
135
  except ClientError as e:
136
  if e.response['Error']['Code'] == 'NoSuchKey':
137
- print("⚠️ لا يوجد ملف مرشحين سابق")
138
  return []
139
  else:
140
  raise
@@ -143,16 +167,12 @@ class R2Service:
143
  # 📝 السجلات والتعلم (Logs & Debugging)
144
  # ==============================================================================
145
  async def save_llm_prompts_async(self, symbol, prompt_type, prompt_content, analysis_data=None):
146
- """حفظ الـ Prompts المرسلة إلى النموذج الضخم"""
147
  try:
148
  try:
149
  response = self.s3_client.get_object(Bucket=BUCKET_NAME, Key=LLM_PROMPTS_KEY)
150
  existing_data = json.loads(response['Body'].read())
151
- except ClientError as e:
152
- if e.response['Error']['Code'] == 'NoSuchKey':
153
- existing_data = {"prompts": []}
154
- else:
155
- raise
156
 
157
  new_prompt = {
158
  "timestamp": datetime.now().isoformat(),
@@ -163,7 +183,6 @@ class R2Service:
163
  }
164
 
165
  existing_data["prompts"].append(new_prompt)
166
- # الاحتفاظ بآخر 2000 سجل فقط
167
  if len(existing_data["prompts"]) > 2000:
168
  existing_data["prompts"] = existing_data["prompts"][-2000:]
169
 
@@ -171,20 +190,16 @@ class R2Service:
171
  self.s3_client.put_object(
172
  Bucket=BUCKET_NAME, Key=LLM_PROMPTS_KEY, Body=data_json, ContentType="application/json"
173
  )
174
- print(f"✅ تم حفظ prompt لـ {symbol} ({prompt_type}) في R2")
175
- except Exception as e:
176
- print(f"❌ فشل حفظ prompt لـ {symbol}: {e}")
177
 
178
  async def save_system_logs_async(self, log_data):
179
  try:
180
  try:
181
  response = self.s3_client.get_object(Bucket=BUCKET_NAME, Key=SYSTEM_LOGS_KEY)
182
  existing_logs = json.loads(response['Body'].read())
183
- except ClientError as e:
184
- if e.response['Error']['Code'] == 'NoSuchKey':
185
- existing_logs = {"logs": []}
186
- else:
187
- raise
188
 
189
  log_entry = {
190
  "timestamp": datetime.now().isoformat(),
@@ -199,12 +214,11 @@ class R2Service:
199
  self.s3_client.put_object(
200
  Bucket=BUCKET_NAME, Key=SYSTEM_LOGS_KEY, Body=data_json, ContentType="application/json"
201
  )
202
- print(f"✅ System log saved: {log_data.get('cycle_started', log_data.get('cycle_completed', 'event'))}")
203
- except Exception as e:
204
- print(f"❌ Failed to save system logs: {e}")
205
 
206
  # ==============================================================================
207
- # 🧠 بيانات التعلم العام (General Learning Data)
208
  # ==============================================================================
209
  async def save_learning_data_async(self, learning_data):
210
  try:
@@ -216,41 +230,39 @@ class R2Service:
216
  self.s3_client.put_object(
217
  Bucket=BUCKET_NAME, Key=LEARNING_DATA_KEY, Body=data_json, ContentType="application/json"
218
  )
219
- print("✅ Learning data saved to R2")
220
- except Exception as e:
221
- print(f"❌ Failed to save learning data: {e}")
222
 
223
  async def load_learning_data_async(self):
224
  try:
225
  response = self.s3_client.get_object(Bucket=BUCKET_NAME, Key=LEARNING_DATA_KEY)
226
- data = json.loads(response['Body'].read())
227
- print("✅ Learning data loaded from R2")
228
- return data
229
- except ClientError as e:
230
- if e.response['Error']['Code'] == 'NoSuchKey':
231
- print("⚠️ No learning data found. Starting fresh.")
232
- return {}
233
- else:
234
- raise
235
 
236
  # ==============================================================================
237
- # 💰 إدارة المحفظة (Accounting & Portfolio) - [معدل للمحاسبة]
238
  # ==============================================================================
239
  async def get_portfolio_state_async(self):
240
  try:
241
  response = self.s3_client.get_object(Bucket=BUCKET_NAME, Key=PORTFOLIO_STATE_KEY)
242
  state = json.loads(response['Body'].read())
 
 
 
 
 
 
243
  if hasattr(self, '_portfolio_warning_printed'):
244
  delattr(self, '_portfolio_warning_printed')
245
- print(f"💰 Portfolio state loaded: Current Capital ${state.get('current_capital_usd', 0):.2f}")
246
  return state
247
  except ClientError as e:
248
  if e.response['Error']['Code'] == 'NoSuchKey':
249
  if not hasattr(self, '_portfolio_warning_printed'):
250
- print(f"⚠️ No portfolio state file found. Initializing with ${INITIAL_CAPITAL:.2f}")
251
  self._portfolio_warning_printed = True
252
 
253
- # تهيئة محفظة جديدة نظيفة
254
  initial_state = {
255
  "current_capital_usd": INITIAL_CAPITAL,
256
  "invested_capital_usd": 0.0,
@@ -275,7 +287,7 @@ class R2Service:
275
  self.s3_client.put_object(
276
  Bucket=BUCKET_NAME, Key=PORTFOLIO_STATE_KEY, Body=data_json, ContentType="application/json"
277
  )
278
- print(f"💾 Portfolio state saved: Current Capital ${state.get('current_capital_usd', 0):.2f}")
279
  except Exception as e:
280
  print(f"❌ Failed to save portfolio state: {e}")
281
  raise
@@ -286,18 +298,9 @@ class R2Service:
286
  async def get_open_trades_async(self):
287
  try:
288
  response = self.s3_client.get_object(Bucket=BUCKET_NAME, Key=OPEN_TRADES_KEY)
289
- trades = json.loads(response['Body'].read())
290
- if hasattr(self, '_open_trades_warning_printed'):
291
- delattr(self, '_open_trades_warning_printed')
292
- return trades
293
- except ClientError as e:
294
- if e.response['Error']['Code'] == 'NoSuchKey':
295
- if not hasattr(self, '_open_trades_warning_printed'):
296
- print("⚠️ No open trades file found. Starting with an empty list.")
297
- self._open_trades_warning_printed = True
298
- return []
299
- else:
300
- raise
301
 
302
  async def save_open_trades_async(self, trades):
303
  try:
@@ -305,29 +308,18 @@ class R2Service:
305
  self.s3_client.put_object(
306
  Bucket=BUCKET_NAME, Key=OPEN_TRADES_KEY, Body=data_json, ContentType="application/json"
307
  )
308
- print(f"✅ Open trades saved to R2. Total open trades: {len(trades)}")
309
  except Exception as e:
310
  print(f"❌ Failed to save open trades: {e}")
311
- raise
312
 
313
- # 🔴 [جديد] أرشفة الصفقات المغلقة 🔴
314
  async def append_to_closed_trades_history(self, trade_data: Dict[str, Any]):
315
- """إضافة صفقة مغلقة إلى السجل التاريخي الدائم"""
316
  try:
317
- # 1. تحميل السجل القديم
318
  try:
319
  response = self.s3_client.get_object(Bucket=BUCKET_NAME, Key=CLOSED_TRADES_KEY)
320
  history = json.loads(response['Body'].read())
321
- except ClientError as e:
322
- if e.response['Error']['Code'] == 'NoSuchKey':
323
- history = []
324
- else:
325
- raise
326
 
327
- # 2. إضافة الصفقة الجديدة
328
  history.append(trade_data)
329
-
330
- # 3. حفظ السجل (نحتفظ بآخر 1000 صفقة فقط)
331
  if len(history) > 1000:
332
  history = history[-1000:]
333
 
@@ -335,13 +327,12 @@ class R2Service:
335
  self.s3_client.put_object(
336
  Bucket=BUCKET_NAME, Key=CLOSED_TRADES_KEY, Body=data_json, ContentType="application/json"
337
  )
338
- print(f"📜 [R2 History] تم أرشفة الصفقة {trade_data.get('symbol')} في السجل التاريخي.")
339
 
340
  except Exception as e:
341
- print(f"❌ [R2 Error] فشل حفظ الصفقة في السجل التاريخي: {e}")
342
 
343
  async def get_closed_trades_history(self):
344
- """جلب سجل الصفقات التاريخية"""
345
  try:
346
  response = self.s3_client.get_object(Bucket=BUCKET_NAME, Key=CLOSED_TRADES_KEY)
347
  return json.loads(response['Body'].read())
@@ -349,24 +340,14 @@ class R2Service:
349
  return []
350
 
351
  # ==============================================================================
352
- # 📜 قاعدة بيانات العقود (Contracts DB)
353
  # ==============================================================================
354
  async def load_contracts_db_async(self):
355
  try:
356
  response = self.s3_client.get_object(Bucket=BUCKET_NAME, Key=CONTRACTS_DB_KEY)
357
- contracts_db = json.loads(response['Body'].read())
358
- if hasattr(self, '_contracts_warning_printed'):
359
- delattr(self, '_contracts_warning_printed')
360
- print(f"💾 Contracts database loaded from R2. Total entries: {len(contracts_db)}")
361
- return contracts_db
362
- except ClientError as e:
363
- if e.response['Error']['Code'] == 'NoSuchKey':
364
- if not hasattr(self, '_contracts_warning_printed'):
365
- print("⚠️ No existing contracts database found. Initializing new one.")
366
- self._contracts_warning_printed = True
367
- return {}
368
- else:
369
- raise
370
 
371
  async def save_contracts_db_async(self, data):
372
  try:
@@ -374,13 +355,11 @@ class R2Service:
374
  self.s3_client.put_object(
375
  Bucket=BUCKET_NAME, Key=CONTRACTS_DB_KEY, Body=data_json, ContentType="application/json"
376
  )
377
- print(f"✅ Contracts database saved to R2 successfully. Total entries: {len(data)}")
378
- except Exception as e:
379
- print(f"❌ Failed to save contracts database to R2: {e}")
380
- raise
381
 
382
  # ==============================================================================
383
- # 🛠️ أدوات مساعدة (Utilities)
384
  # ==============================================================================
385
  async def get_trade_by_symbol_async(self, symbol):
386
  try:
@@ -389,8 +368,7 @@ class R2Service:
389
  if trade['symbol'] == symbol and trade['status'] == 'OPEN':
390
  return trade
391
  return None
392
- except Exception as e:
393
- print(f"❌ Failed to get trade by symbol {symbol}: {e}")
394
  return None
395
 
396
  async def update_trade_monitoring_status_async(self, symbol, is_monitored):
@@ -404,149 +382,86 @@ class R2Service:
404
  break
405
  if updated:
406
  await self.save_open_trades_async(open_trades)
407
- status = "ENABLED" if is_monitored else "DISABLED"
408
- print(f"✅ Real-time monitoring {status} for {symbol}")
409
- else:
410
- print(f"⚠️ Trade {symbol} not found for monitoring status update")
411
- return updated
412
- except Exception as e:
413
- print(f"❌ Failed to update monitoring status for {symbol}: {e}")
414
  return False
415
 
416
  async def get_monitored_trades_async(self):
417
  try:
418
  open_trades = await self.get_open_trades_async()
419
- monitored_trades = [trade for trade in open_trades if trade.get('is_monitored', False)]
420
- return monitored_trades
421
- except Exception as e:
422
- print(f"❌ Failed to get monitored trades: {e}")
423
  return []
424
 
425
  async def save_analysis_audit_log_async(self, audit_data):
426
- """حفظ سجل تدقيق دورة التحليل (يحتفظ بآخر 50 دورة)"""
427
  try:
428
- # 1. جلب السجل الحالي (إن وجد)
429
  try:
430
  response = self.s3_client.get_object(Bucket=BUCKET_NAME, Key=ANALYSIS_AUDIT_KEY)
431
- existing_log_data = json.loads(response['Body'].read())
432
- if isinstance(existing_log_data, list):
433
- history = existing_log_data
434
- else:
435
- history = []
436
- except ClientError as e:
437
- if e.response['Error']['Code'] == 'NoSuchKey':
438
- history = []
439
- else:
440
- raise
441
 
442
- # 2. إضافة الدورة الحالية
443
  history.append(audit_data)
444
-
445
- # 3. الحفاظ على آخر 50 سجل فقط
446
  if len(history) > 50:
447
  history = history[-50:]
448
 
449
- # 4. حفظ الملف المحدث
450
  data_json = json.dumps(history, indent=2, ensure_ascii=False).encode('utf-8')
451
  self.s3_client.put_object(
452
  Bucket=BUCKET_NAME, Key=ANALYSIS_AUDIT_KEY, Body=data_json, ContentType="application/json"
453
  )
454
- print(f"📊 تم حفظ سجل تدقيق التحليل بنجاح في R2 (إجمالي {len(history)} سجلات)")
455
-
456
- except Exception as e:
457
- print(f"❌ فشل حفظ سجل تدقيق التحليل في R2: {e}")
458
 
459
  # ==============================================================================
460
- # 🐋 تعلم الحيتان (Whale Learning) - V10.2
461
  # ==============================================================================
462
-
463
  async def _load_json_file_from_r2(self, key: str, default: Any = []) -> Any:
464
- """دالة مساعدة لتحميل ملف JSON بأمان."""
465
  try:
466
  response = self.s3_client.get_object(Bucket=self.BUCKET_NAME, Key=key)
467
  return json.loads(response['Body'].read())
468
- except ClientError as e:
469
- if e.response['Error']['Code'] == 'NoSuchKey':
470
- print(f"ℹ️ [R2Service] لم يتم العثور على ملف '{key}'. سيتم استخدام القيمة الافتراضية.")
471
- return default
472
- else:
473
- print(f"❌ [R2Service] خطأ ClientError أثناء تحميل '{key}': {e}")
474
- raise
475
- except Exception as e:
476
- print(f"❌ [R2Service] خطأ عام أثناء تحميل '{key}': {e}")
477
  return default
478
 
479
  async def _save_json_file_to_r2(self, key: str, data: Any):
480
- """دالة مساعدة لحفظ ملف JSON بأمان."""
481
  try:
482
  data_json = json.dumps(data, indent=2, ensure_ascii=False).encode('utf-8')
483
- self.s3_client.put_object(
484
- Bucket=self.BUCKET_NAME, Key=key, Body=data_json, ContentType="application/json"
485
- )
486
- except Exception as e:
487
- print(f"❌ [R2Service] فشل حفظ الملف '{key}' إلى R2: {e}")
488
- traceback.print_exc()
489
 
490
  async def save_whale_learning_record_async(self, record: Dict[str, Any]):
491
- """يحفظ سجلاً 'معلقاً' جديداً في ملف PENDING."""
492
  try:
493
- pending_records = await self._load_json_file_from_r2(WHALE_LEARNING_PENDING_KEY, default=[])
494
- pending_records.append(record)
495
- await self._save_json_file_to_r2(WHALE_LEARNING_PENDING_KEY, pending_records)
496
- print(f"✅ [R2Service] تم حفظ سجل تعلم الحيتان (PENDING) لـ {record['symbol']}.")
497
- except Exception as e:
498
- print(f"❌ [R2Service] فشل في save_whale_learning_record_async: {e}")
499
 
500
  async def get_pending_whale_learning_records_async(self) -> List[Dict[str, Any]]:
501
- """يجلب جميع السجلات 'المعلقة' من ملف PENDING."""
502
- try:
503
- return await self._load_json_file_from_r2(WHALE_LEARNING_PENDING_KEY, default=[])
504
- except Exception as e:
505
- print(f"❌ [R2Service] فشل في get_pending_whale_learning_records_async: {e}")
506
- return []
507
 
508
  async def update_completed_whale_learning_record_async(self, completed_record: Dict[str, Any]):
509
- """يحفظ السجل 'المكتمل' في ملف COMPLETED ويزيله من PENDING."""
510
  try:
511
  record_id = completed_record.get("record_id")
512
- if not record_id:
513
- print("❌ [R2Service] لا يمكن تحديث سجل مكتمل بدون record_id.")
514
- return
515
-
516
- # 1. الحفظ في ملف المكتمل (يحتفظ بآخر 5000 سجل مكتمل)
517
- completed_records = await self._load_json_file_from_r2(WHALE_LEARNING_COMPLETED_KEY, default=[])
518
- completed_records.append(completed_record)
519
- if len(completed_records) > 5000:
520
- completed_records = completed_records[-5000:]
521
- await self._save_json_file_to_r2(WHALE_LEARNING_COMPLETED_KEY, completed_records)
522
-
523
- # 2. الإزالة من ملف المعلق
524
- pending_records = await self._load_json_file_from_r2(WHALE_LEARNING_PENDING_KEY, default=[])
525
- updated_pending_records = [
526
- rec for rec in pending_records if rec.get("record_id") != record_id
527
- ]
528
- await self._save_json_file_to_r2(WHALE_LEARNING_PENDING_KEY, updated_pending_records)
529
-
530
- print(f"✅ [R2Service] تم نقل سجل تعلم الحيتان (COMPLETED) لـ {completed_record['symbol']} (ID: {record_id}).")
531
 
532
- except Exception as e:
533
- print(f"❌ [R2Service] فشل في update_completed_whale_learning_record_async: {e}")
534
-
535
  async def get_all_completed_whale_records_async(self) -> List[Dict[str, Any]]:
536
- """يجلب جميع السجلات المكتملة."""
537
- try:
538
- return await self._load_json_file_from_r2(WHALE_LEARNING_COMPLETED_KEY, default=[])
539
- except Exception as e:
540
- print(f"❌ [R2Service] فشل في get_all_completed_whale_records_async: {e}")
541
- return []
542
 
543
  async def save_whale_learning_config_async(self, config: Dict[str, Any]):
544
- """يحفظ ملف الإعدادات (الأوزان) الذي نتج عن التعلم."""
545
  await self._save_json_file_to_r2(WHALE_LEARNING_CONFIG_KEY, config)
546
- print(f"✅ [R2Service] تم حفظ إعدادات تعلم الحيتان المثلى.")
547
 
548
  async def load_whale_learning_config_async(self) -> Dict[str, Any]:
549
- """يجلب ملف الإعدادات (الأوزان)."""
550
  return await self._load_json_file_from_r2(WHALE_LEARNING_CONFIG_KEY, default={})
551
 
552
- print("✅ Full R2 Service Loaded - Accounting & History Modules Ready")
 
1
+ # r2.py (V12.1 - GEM-Architect: Full Code with Reset Function)
2
  import os
3
  import traceback
4
  import json
 
17
  R2_SECRET_ACCESS_KEY = os.getenv("R2_SECRET_ACCESS_KEY")
18
  BUCKET_NAME = "trading"
19
 
20
+ # 🔴 الرصيد الافتراضي (تم تعديله ليكون 10 دولار)
21
+ INITIAL_CAPITAL = 10.0
22
 
23
+ # 📁 مفاتيح الملفات في R2
 
24
  WHALE_LEARNING_PENDING_KEY = "learning_whale_pending_records.json"
25
  WHALE_LEARNING_COMPLETED_KEY = "learning_whale_completed_records.json"
26
  WHALE_LEARNING_CONFIG_KEY = "learning_whale_optimal_config.json"
27
 
 
28
  PORTFOLIO_STATE_KEY = "portfolio_state.json"
29
  OPEN_TRADES_KEY = "open_trades.json"
30
  CLOSED_TRADES_KEY = "closed_trades_history.json"
31
 
 
32
  CANDIDATES_KEY = "Candidates.json"
33
  CONTRACTS_DB_KEY = "contracts.json"
34
  SYSTEM_LOGS_KEY = "system_logs.json"
 
50
  self.lock_acquired = False
51
  self.BUCKET_NAME = BUCKET_NAME
52
 
 
53
  self._open_trades_warning_printed = False
54
  self._portfolio_warning_printed = False
55
  self._contracts_warning_printed = False
 
57
  except Exception as e:
58
  raise RuntimeError(f"Failed to initialize S3 client: {e}")
59
 
60
+ # ==============================================================================
61
+ # 🔴 [هام جداً] دالة التصفير الشامل (هذه هي الدالة المفقودة)
62
+ # ==============================================================================
63
+ async def reset_all_stats_async(self):
64
+ """تصفير المحفظة والسجلات التاريخية والعودة لنقطة الصفر"""
65
+ try:
66
+ print("🔄 [R2 Reset] بدء عملية التصفير...")
67
+
68
+ # 1. إعادة تعيين المحفظة للقيمة الأولية
69
+ initial_state = {
70
+ "current_capital_usd": INITIAL_CAPITAL,
71
+ "invested_capital_usd": 0.0,
72
+ "initial_capital_usd": INITIAL_CAPITAL, # تثبيت القيمة الأولية
73
+ "total_trades": 0,
74
+ "winning_trades": 0,
75
+ "losing_trades": 0,
76
+ "total_profit_usd": 0.0,
77
+ "total_loss_usd": 0.0,
78
+ "win_rate": 0.0,
79
+ "last_update": datetime.now().isoformat()
80
+ }
81
+ await self.save_portfolio_state_async(initial_state)
82
+
83
+ # 2. مسح سجل الصفقات المغلقة (History)
84
+ empty_list_json = json.dumps([], indent=2).encode('utf-8')
85
+ self.s3_client.put_object(
86
+ Bucket=BUCKET_NAME, Key=CLOSED_TRADES_KEY, Body=empty_list_json, ContentType="application/json"
87
+ )
88
+
89
+ # 3. مسح السجلات (Logs)
90
+ empty_logs_json = json.dumps({"logs": []}, indent=2).encode('utf-8')
91
+ self.s3_client.put_object(
92
+ Bucket=BUCKET_NAME, Key=SYSTEM_LOGS_KEY, Body=empty_logs_json, ContentType="application/json"
93
+ )
94
+
95
+ print("✅ [R2 Reset] تم تصفير جميع البيانات والمحفظة بنجاح.")
96
+ return True
97
+
98
+ except Exception as e:
99
+ print(f"❌ [R2 Reset Error] فشل التصفير: {e}")
100
+ traceback.print_exc()
101
+ return False
102
+
103
  # ==============================================================================
104
  # 🔒 إدارة القفل (Lock Mechanism)
105
  # ==============================================================================
 
122
  except Exception as e:
123
  print(f"❌ Failed to acquire lock: {e}")
124
  time.sleep(1)
 
125
  return False
126
 
127
  def release_lock(self):
 
138
  # 📊 إدارة المرشحين (Candidates)
139
  # ==============================================================================
140
  async def save_candidates_async(self, candidates):
 
141
  try:
142
  data = {
143
  "timestamp": datetime.now().isoformat(),
 
149
  Bucket=BUCKET_NAME, Key=CANDIDATES_KEY, Body=data_json, ContentType="application/json"
150
  )
151
  print(f"✅ تم حفظ {len(candidates)} مرشح في ملف Candidates في R2")
 
 
 
 
 
 
 
 
 
152
  except Exception as e:
153
  print(f"❌ فشل حفظ المرشحين في R2: {e}")
154
 
155
  async def load_candidates_async(self):
 
156
  try:
157
  response = self.s3_client.get_object(Bucket=BUCKET_NAME, Key=CANDIDATES_KEY)
158
  data = json.loads(response['Body'].read())
159
+ return data.get('candidates', [])
 
 
160
  except ClientError as e:
161
  if e.response['Error']['Code'] == 'NoSuchKey':
 
162
  return []
163
  else:
164
  raise
 
167
  # 📝 السجلات والتعلم (Logs & Debugging)
168
  # ==============================================================================
169
  async def save_llm_prompts_async(self, symbol, prompt_type, prompt_content, analysis_data=None):
 
170
  try:
171
  try:
172
  response = self.s3_client.get_object(Bucket=BUCKET_NAME, Key=LLM_PROMPTS_KEY)
173
  existing_data = json.loads(response['Body'].read())
174
+ except ClientError:
175
+ existing_data = {"prompts": []}
 
 
 
176
 
177
  new_prompt = {
178
  "timestamp": datetime.now().isoformat(),
 
183
  }
184
 
185
  existing_data["prompts"].append(new_prompt)
 
186
  if len(existing_data["prompts"]) > 2000:
187
  existing_data["prompts"] = existing_data["prompts"][-2000:]
188
 
 
190
  self.s3_client.put_object(
191
  Bucket=BUCKET_NAME, Key=LLM_PROMPTS_KEY, Body=data_json, ContentType="application/json"
192
  )
193
+ except Exception:
194
+ pass
 
195
 
196
  async def save_system_logs_async(self, log_data):
197
  try:
198
  try:
199
  response = self.s3_client.get_object(Bucket=BUCKET_NAME, Key=SYSTEM_LOGS_KEY)
200
  existing_logs = json.loads(response['Body'].read())
201
+ except ClientError:
202
+ existing_logs = {"logs": []}
 
 
 
203
 
204
  log_entry = {
205
  "timestamp": datetime.now().isoformat(),
 
214
  self.s3_client.put_object(
215
  Bucket=BUCKET_NAME, Key=SYSTEM_LOGS_KEY, Body=data_json, ContentType="application/json"
216
  )
217
+ except Exception:
218
+ pass
 
219
 
220
  # ==============================================================================
221
+ # 🧠 بيانات التعلم العام
222
  # ==============================================================================
223
  async def save_learning_data_async(self, learning_data):
224
  try:
 
230
  self.s3_client.put_object(
231
  Bucket=BUCKET_NAME, Key=LEARNING_DATA_KEY, Body=data_json, ContentType="application/json"
232
  )
233
+ except Exception:
234
+ pass
 
235
 
236
  async def load_learning_data_async(self):
237
  try:
238
  response = self.s3_client.get_object(Bucket=BUCKET_NAME, Key=LEARNING_DATA_KEY)
239
+ return json.loads(response['Body'].read())
240
+ except ClientError:
241
+ return {}
 
 
 
 
 
 
242
 
243
  # ==============================================================================
244
+ # 💰 إدارة المحفظة (Accounting & Portfolio)
245
  # ==============================================================================
246
  async def get_portfolio_state_async(self):
247
  try:
248
  response = self.s3_client.get_object(Bucket=BUCKET_NAME, Key=PORTFOLIO_STATE_KEY)
249
  state = json.loads(response['Body'].read())
250
+
251
+ # إصلاح البيانات القديمة إن وجدت
252
+ if 'losing_trades' not in state: state['losing_trades'] = 0
253
+ if 'total_loss_usd' not in state: state['total_loss_usd'] = 0.0
254
+ if 'initial_capital_usd' not in state: state['initial_capital_usd'] = INITIAL_CAPITAL
255
+
256
  if hasattr(self, '_portfolio_warning_printed'):
257
  delattr(self, '_portfolio_warning_printed')
258
+ print(f"💰 Portfolio loaded: Current Capital ${state.get('current_capital_usd', 0):.2f}")
259
  return state
260
  except ClientError as e:
261
  if e.response['Error']['Code'] == 'NoSuchKey':
262
  if not hasattr(self, '_portfolio_warning_printed'):
263
+ print(f"⚠️ No portfolio state found. Initializing with ${INITIAL_CAPITAL}")
264
  self._portfolio_warning_printed = True
265
 
 
266
  initial_state = {
267
  "current_capital_usd": INITIAL_CAPITAL,
268
  "invested_capital_usd": 0.0,
 
287
  self.s3_client.put_object(
288
  Bucket=BUCKET_NAME, Key=PORTFOLIO_STATE_KEY, Body=data_json, ContentType="application/json"
289
  )
290
+ print(f"💾 Portfolio saved: ${state.get('current_capital_usd', 0):.2f}")
291
  except Exception as e:
292
  print(f"❌ Failed to save portfolio state: {e}")
293
  raise
 
298
  async def get_open_trades_async(self):
299
  try:
300
  response = self.s3_client.get_object(Bucket=BUCKET_NAME, Key=OPEN_TRADES_KEY)
301
+ return json.loads(response['Body'].read())
302
+ except ClientError:
303
+ return []
 
 
 
 
 
 
 
 
 
304
 
305
  async def save_open_trades_async(self, trades):
306
  try:
 
308
  self.s3_client.put_object(
309
  Bucket=BUCKET_NAME, Key=OPEN_TRADES_KEY, Body=data_json, ContentType="application/json"
310
  )
 
311
  except Exception as e:
312
  print(f"❌ Failed to save open trades: {e}")
 
313
 
 
314
  async def append_to_closed_trades_history(self, trade_data: Dict[str, Any]):
 
315
  try:
 
316
  try:
317
  response = self.s3_client.get_object(Bucket=BUCKET_NAME, Key=CLOSED_TRADES_KEY)
318
  history = json.loads(response['Body'].read())
319
+ except ClientError:
320
+ history = []
 
 
 
321
 
 
322
  history.append(trade_data)
 
 
323
  if len(history) > 1000:
324
  history = history[-1000:]
325
 
 
327
  self.s3_client.put_object(
328
  Bucket=BUCKET_NAME, Key=CLOSED_TRADES_KEY, Body=data_json, ContentType="application/json"
329
  )
330
+ print(f"📜 History archived for {trade_data.get('symbol')}")
331
 
332
  except Exception as e:
333
+ print(f"❌ Failed to archive trade: {e}")
334
 
335
  async def get_closed_trades_history(self):
 
336
  try:
337
  response = self.s3_client.get_object(Bucket=BUCKET_NAME, Key=CLOSED_TRADES_KEY)
338
  return json.loads(response['Body'].read())
 
340
  return []
341
 
342
  # ==============================================================================
343
+ # 📜 قاعدة بيانات العقود
344
  # ==============================================================================
345
  async def load_contracts_db_async(self):
346
  try:
347
  response = self.s3_client.get_object(Bucket=BUCKET_NAME, Key=CONTRACTS_DB_KEY)
348
+ return json.loads(response['Body'].read())
349
+ except ClientError:
350
+ return {}
 
 
 
 
 
 
 
 
 
 
351
 
352
  async def save_contracts_db_async(self, data):
353
  try:
 
355
  self.s3_client.put_object(
356
  Bucket=BUCKET_NAME, Key=CONTRACTS_DB_KEY, Body=data_json, ContentType="application/json"
357
  )
358
+ except Exception:
359
+ pass
 
 
360
 
361
  # ==============================================================================
362
+ # 🛠️ أدوات مساعدة
363
  # ==============================================================================
364
  async def get_trade_by_symbol_async(self, symbol):
365
  try:
 
368
  if trade['symbol'] == symbol and trade['status'] == 'OPEN':
369
  return trade
370
  return None
371
+ except Exception:
 
372
  return None
373
 
374
  async def update_trade_monitoring_status_async(self, symbol, is_monitored):
 
382
  break
383
  if updated:
384
  await self.save_open_trades_async(open_trades)
385
+ return True
386
+ return False
387
+ except Exception:
 
 
 
 
388
  return False
389
 
390
  async def get_monitored_trades_async(self):
391
  try:
392
  open_trades = await self.get_open_trades_async()
393
+ return [trade for trade in open_trades if trade.get('is_monitored', False)]
394
+ except Exception:
 
 
395
  return []
396
 
397
  async def save_analysis_audit_log_async(self, audit_data):
 
398
  try:
 
399
  try:
400
  response = self.s3_client.get_object(Bucket=BUCKET_NAME, Key=ANALYSIS_AUDIT_KEY)
401
+ history = json.loads(response['Body'].read())
402
+ except ClientError:
403
+ history = []
 
 
 
 
 
 
 
404
 
 
405
  history.append(audit_data)
 
 
406
  if len(history) > 50:
407
  history = history[-50:]
408
 
 
409
  data_json = json.dumps(history, indent=2, ensure_ascii=False).encode('utf-8')
410
  self.s3_client.put_object(
411
  Bucket=BUCKET_NAME, Key=ANALYSIS_AUDIT_KEY, Body=data_json, ContentType="application/json"
412
  )
413
+ except Exception:
414
+ pass
 
 
415
 
416
  # ==============================================================================
417
+ # 🐋 تعلم الحيتان (Whale Learning)
418
  # ==============================================================================
 
419
  async def _load_json_file_from_r2(self, key: str, default: Any = []) -> Any:
 
420
  try:
421
  response = self.s3_client.get_object(Bucket=self.BUCKET_NAME, Key=key)
422
  return json.loads(response['Body'].read())
423
+ except Exception:
 
 
 
 
 
 
 
 
424
  return default
425
 
426
  async def _save_json_file_to_r2(self, key: str, data: Any):
 
427
  try:
428
  data_json = json.dumps(data, indent=2, ensure_ascii=False).encode('utf-8')
429
+ self.s3_client.put_object(Bucket=self.BUCKET_NAME, Key=key, Body=data_json, ContentType="application/json")
430
+ except Exception:
431
+ pass
 
 
 
432
 
433
  async def save_whale_learning_record_async(self, record: Dict[str, Any]):
 
434
  try:
435
+ pending = await self._load_json_file_from_r2(WHALE_LEARNING_PENDING_KEY, default=[])
436
+ pending.append(record)
437
+ await self._save_json_file_to_r2(WHALE_LEARNING_PENDING_KEY, pending)
438
+ except Exception: pass
 
 
439
 
440
  async def get_pending_whale_learning_records_async(self) -> List[Dict[str, Any]]:
441
+ return await self._load_json_file_from_r2(WHALE_LEARNING_PENDING_KEY, default=[])
 
 
 
 
 
442
 
443
  async def update_completed_whale_learning_record_async(self, completed_record: Dict[str, Any]):
 
444
  try:
445
  record_id = completed_record.get("record_id")
446
+ if not record_id: return
447
+
448
+ completed = await self._load_json_file_from_r2(WHALE_LEARNING_COMPLETED_KEY, default=[])
449
+ completed.append(completed_record)
450
+ if len(completed) > 5000: completed = completed[-5000:]
451
+ await self._save_json_file_to_r2(WHALE_LEARNING_COMPLETED_KEY, completed)
452
+
453
+ pending = await self._load_json_file_from_r2(WHALE_LEARNING_PENDING_KEY, default=[])
454
+ updated_pending = [r for r in pending if r.get("record_id") != record_id]
455
+ await self._save_json_file_to_r2(WHALE_LEARNING_PENDING_KEY, updated_pending)
456
+ except Exception: pass
 
 
 
 
 
 
 
 
457
 
 
 
 
458
  async def get_all_completed_whale_records_async(self) -> List[Dict[str, Any]]:
459
+ return await self._load_json_file_from_r2(WHALE_LEARNING_COMPLETED_KEY, default=[])
 
 
 
 
 
460
 
461
  async def save_whale_learning_config_async(self, config: Dict[str, Any]):
 
462
  await self._save_json_file_to_r2(WHALE_LEARNING_CONFIG_KEY, config)
 
463
 
464
  async def load_whale_learning_config_async(self) -> Dict[str, Any]:
 
465
  return await self._load_json_file_from_r2(WHALE_LEARNING_CONFIG_KEY, default={})
466
 
467
+ print("✅ Full R2 Service Loaded - Accounting, History & Reset Ready")