Riy777 commited on
Commit
816f418
ยท
1 Parent(s): f597794

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +229 -233
app.py CHANGED
@@ -1,4 +1,4 @@
1
- # app.py (ู…ุญุฏุซ ุจุงู„ูƒุงู…ู„ ู„ุฑุจุท ุงู„ุฎุฏู…ุงุช)
2
  import os
3
  import traceback
4
  import signal
@@ -17,10 +17,15 @@ try:
17
  from LLM import LLMService
18
  from data_manager import DataManager
19
  from ml_engine.processor import MLProcessor
20
- from learning_engine import LearningEngine
 
 
 
 
 
21
  from sentiment_news import SentimentAnalyzer
22
  from trade_manager import TradeManager
23
- import state # ๐Ÿ”ด ู…ู‡ู…: ู‡ุฐุง ู‡ูˆ ู…ู„ู state.py
24
  from helpers import safe_float_conversion, validate_candidate_data_enhanced
25
  except ImportError as e:
26
  print(f"โŒ ุฎุทุฃ ููŠ ุงุณุชูŠุฑุงุฏ ุงู„ูˆุญุฏุงุช: {e}")
@@ -30,22 +35,25 @@ except ImportError as e:
30
  r2_service_global = None
31
  data_manager_global = None
32
  llm_service_global = None
33
- learning_engine_global = None
 
 
34
  trade_manager_global = None
35
  sentiment_analyzer_global = None
36
  symbol_whale_monitor_global = None
37
 
38
  class StateManager:
39
- # ๐Ÿ”ด ู‡ุฐุง ู‡ูˆ ู…ุฏูŠุฑ ุงู„ุญุงู„ุฉ "ุงู„ู…ุญู„ูŠ" ู„ู„ุชุทุจูŠู‚
40
- # ุงู„ุฐูŠ ูŠุฏูŠุฑ ุงู„ุฃู‚ูุงู„ ุงู„ุฏุงุฎู„ูŠุฉ ู„ู€ FastAPI
41
  def __init__(self):
42
  self.market_analysis_lock = asyncio.Lock()
43
- self.trade_analysis_lock = asyncio.Lock() # ๐Ÿ”ด ู‡ุฐุง ู‡ูˆ ุงู„ู‚ูู„ ุงู„ุฐูŠ ุณูŠุชู… ุชู…ุฑูŠุฑู‡
44
  self.initialization_complete = False
45
  self.initialization_error = None
46
  self.services_initialized = {
47
  'r2_service': False, 'data_manager': False, 'llm_service': False,
48
- 'learning_engine': False, 'trade_manager': False, 'sentiment_analyzer': False,
 
 
 
49
  'symbol_whale_monitor': False
50
  }
51
 
@@ -67,13 +75,15 @@ class StateManager:
67
  self.initialization_error = error
68
  print(f"โŒ ุฎุทุฃ ููŠ ุงู„ุชู‡ูŠุฆุฉ: {error}")
69
 
70
- # ๐Ÿ”ด ุฅู†ุดุงุก ู†ุณุฎุฉ ู…ุฏูŠุฑ ุงู„ุญุงู„ุฉ ุงู„ู…ุญู„ูŠ
71
  state_manager = StateManager()
72
 
73
  async def initialize_services():
74
  """ุชู‡ูŠุฆุฉ ุฌู…ูŠุน ุงู„ุฎุฏู…ุงุช ุจุดูƒู„ ู…ู†ูุตู„"""
75
  global r2_service_global, data_manager_global, llm_service_global
76
- global learning_engine_global, trade_manager_global, sentiment_analyzer_global
 
 
 
77
  global symbol_whale_monitor_global
78
  try:
79
  print("๐Ÿš€ ุจุฏุก ุชู‡ูŠุฆุฉ ุงู„ุฎุฏู…ุงุช...")
@@ -87,53 +97,54 @@ async def initialize_services():
87
  except Exception as e: print(f" โš ๏ธ ูุดู„ ุชู‡ูŠุฆุฉ ู…ุฑุงู‚ุจ ุงู„ุญูŠุชุงู†: {e}"); symbol_whale_monitor_global = None
88
  print(" ๐Ÿ”„ ุชู‡ูŠุฆุฉ DataManager..."); data_manager_global = DataManager(contracts_database, symbol_whale_monitor_global); await data_manager_global.initialize(); state_manager.set_service_initialized('data_manager'); print(" โœ… DataManager ู…ู‡ูŠุฃุฉ")
89
 
90
- # --- ๐Ÿ”ด ุจุฏุก ุงู„ุชุนุฏูŠู„ (ุงู„ุฑุจุท) ---
91
-
92
  print(" ๐Ÿ”„ ุชู‡ูŠุฆุฉ LLMService...");
93
  llm_service_global = LLMService();
94
  llm_service_global.r2_service = r2_service_global;
95
- # (ู„ุง ู†ุถุน ุนู„ุงู…ุฉ ู…ู‡ูŠุฃ ู‡ู†ุง ุจุนุฏ)
96
-
97
  print(" ๐Ÿ”„ ุชู‡ูŠุฆุฉ ู…ุญู„ู„ ุงู„ู…ุดุงุนุฑ...");
98
  sentiment_analyzer_global = SentimentAnalyzer(data_manager_global);
99
  state_manager.set_service_initialized('sentiment_analyzer');
100
  print(" โœ… ู…ุญู„ู„ ุงู„ู…ุดุงุนุฑ ู…ู‡ูŠุฃ")
101
 
102
- print(" ๐Ÿ”„ ุชู‡ูŠุฆุฉ ู…ุญุฑูƒ ุงู„ุชุนู„ู…...");
103
- learning_engine_global = LearningEngine(r2_service_global, data_manager_global);
104
- await learning_engine_global.initialize_enhanced();
105
- state_manager.set_service_initialized('learning_engine');
106
- print(" โœ… ู…ุญุฑูƒ ุงู„ุชุนู„ู… ู…ู‡ูŠุฃ")
 
 
 
 
 
 
107
 
108
- # ๏ฟฝ๏ฟฝ ุฑุจุท ู…ุญุฑูƒ ุงู„ุชุนู„ู… ุจู€ LLM (ู„ู„ุชุบุฐูŠุฉ ุงู„ุฑุงุฌุนุฉ)
109
- llm_service_global.learning_engine = learning_engine_global
110
- state_manager.set_service_initialized('llm_service'); # ๐Ÿ”ด ุงู„ุขู† ู†ุถุน ุนู„ุงู…ุฉ ู…ู‡ูŠุฃ ู„ู€ LLM
111
- print(" โœ… LLMService ู…ู‡ูŠุฃุฉ (ูˆู…ุฑุจูˆุทุฉ ุจู…ุญุฑูƒ ุงู„ุชุนู„ู…)")
112
 
113
  print(" ๐Ÿ”„ ุชู‡ูŠุฆุฉ ู…ุฏูŠุฑ ุงู„ุตูู‚ุงุช...");
114
- # ๐Ÿ”ด ุชู…ุฑูŠุฑ state_manager ุฅู„ู‰ TradeManager (ู„ุฅุฏุงุฑุฉ ุงู„ุชุนุงุฑุถ)
115
  trade_manager_global = TradeManager(
116
  r2_service_global,
117
- learning_engine_global,
118
  data_manager_global,
119
- state_manager # ๐Ÿ”ด ุชู…ุฑูŠุฑ ู…ุฏูŠุฑ ุงู„ุญุงู„ุฉ ุงู„ู…ุญู„ูŠ ู‡ู†ุง
120
  )
121
  state_manager.set_service_initialized('trade_manager');
122
- print(" โœ… ู…ุฏูŠุฑ ุงู„ุตูู‚ุงุช ู…ู‡ูŠุฃ (ูˆู…ุฏุฑูƒ ู„ุญุงู„ุฉ ุงู„ู†ุธุงู…)")
123
-
124
- # --- ๐Ÿ”ด ู†ู‡ุงูŠุฉ ุงู„ุชุนุฏูŠู„ ---
125
 
126
  print("๐ŸŽฏ ุงูƒุชู…ู„ุช ุชู‡ูŠุฆุฉ ุฌู…ูŠุน ุงู„ุฎุฏู…ุงุช ุจู†ุฌุงุญ"); return True
127
  except Exception as e: error_msg = f"ูุดู„ ุชู‡ูŠุฆุฉ ุงู„ุฎุฏู…ุงุช: {str(e)}"; print(f"โŒ {error_msg}"); state_manager.set_initialization_error(error_msg); return False
128
 
129
  async def monitor_market_async():
130
- """ู…ุฑุงู‚ุจุฉ ุงู„ุณูˆู‚"""
131
  global data_manager_global, sentiment_analyzer_global
132
  try:
133
  if not await state_manager.wait_for_initialization(): print("โŒ ูุดู„ ุชู‡ูŠุฆุฉ ุงู„ุฎุฏู…ุงุช - ุฅูŠู‚ุงู ู…ุฑุงู‚ุจุฉ ุงู„ุณูˆู‚"); return
134
  while True:
135
  try:
136
- # ๐Ÿ”ด ุงุณุชุฎุฏุงู… ู‚ูู„ ู…ุฏูŠุฑ ุงู„ุญุงู„ุฉ ุงู„ู…ุญู„ูŠ
137
  async with state_manager.market_analysis_lock:
138
  market_context = await sentiment_analyzer_global.get_market_sentiment()
139
  if not market_context: state.MARKET_STATE_OK = True; await asyncio.sleep(60); continue
@@ -149,12 +160,35 @@ async def monitor_market_async():
149
  except Exception as error: print(f"โŒ ุฎุทุฃ ุฃุซู†ุงุก ู…ุฑุงู‚ุจุฉ ุงู„ุณูˆู‚: {error}"); state.MARKET_STATE_OK = True; await asyncio.sleep(60)
150
  except Exception as e: print(f"โŒ ูุดู„ ุชุดุบูŠู„ ู…ุฑุงู‚ุจุฉ ุงู„ุณูˆู‚: {e}")
151
 
152
-
153
- async def process_batch_parallel(batch, ml_processor, batch_num, total_batches, preloaded_whale_data):
 
154
  """
155
- (ู…ุนุฏู„ุฉ) ู…ุนุงู„ุฌุฉ ุฏูุนุฉ ู…ู† ุงู„ุฑู…ูˆุฒ ุจุดูƒู„ ู…ุชูˆุงุฒูŠ ูˆุฅุฑุฌุงุน ู†ุชุงุฆุฌ ู…ูุตู„ุฉ
156
- - ุชุณุชุฎุฏู… ุจูŠุงู†ุงุช ุงู„ุญูŠุชุงู† ุงู„ู…ุญู…ู„ุฉ ู…ุณุจู‚ู‹ุง
157
  """
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
158
  try:
159
  batch_tasks = []
160
  for symbol_data in batch:
@@ -188,18 +222,13 @@ async def process_batch_parallel(batch, ml_processor, batch_num, total_batches,
188
  return {'success': successful_results, 'low_score': low_score_results, 'failures': failed_results}
189
 
190
  except Exception as error:
191
- print(f"โŒ [ุงู„ู…ุณุชู‡ู„ูƒ] ุฎุทุฃ ููŠ ู…ุนุงู„ุฌุฉ ุงู„ุฏูุนุฉ {batch_num}: {error}")
192
  return {'success': [], 'low_score': [], 'failures': []}
193
 
194
 
195
  async def run_3_layer_analysis():
196
  """
197
- (ู…ุนุฏู„ุฉ) ุชุดุบูŠู„ ุงู„ู†ุธุงู… ุงู„ุทุจู‚ูŠ (ู…ุน ูุตู„ ุฌู„ุจ ุงู„ุญูŠุชุงู†)
198
- ุงู„ุทุจู‚ุฉ 1: data_manager - ุงู„ูุญุต ุงู„ุณุฑูŠุน
199
- ุงู„ุทุจู‚ุฉ 1.5: ุฌู„ุจ ุจูŠุงู†ุงุช ุงู„ุญูŠุชุงู† ุจุดูƒู„ ู…ู†ูุตู„ (ุบูŠุฑ ู…ุนุฑู‚ู„)
200
- ุงู„ุทุจู‚ุฉ 2: MLProcessor - ุงู„ุชุญู„ูŠู„ ุงู„ู…ุชุฏูู‚ (ูŠุณุชุฎุฏู… ู…ูˆู†ุช ูƒุงุฑู„ูˆ ุงู„ู…ุฑุญู„ุฉ 1)
201
- ุงู„ุทุจู‚ุฉ 2.5: (ุฌุฏูŠุฏ) ู…ูˆู†ุช ูƒุงุฑู„ูˆ (ุงู„ู…ุฑุญู„ุฉ 2+3) ู„ุฃูุถู„ 10 ุนู…ู„ุงุช
202
- ุงู„ุทุจู‚ุฉ 3: LLMService - ุงู„ู†ู…ูˆุฐุฌ ุงู„ุถุฎู… (ูŠุณุชุฎุฏู… ู†ุชุงุฆุฌ ุงู„ู…ุฑุญู„ุฉ 2.5)
203
  """
204
 
205
  layer1_candidates = []
@@ -211,20 +240,20 @@ async def run_3_layer_analysis():
211
  preloaded_whale_data_dict = {}
212
 
213
  try:
214
- print("๐ŸŽฏ ุจุฏุก ุงู„ู†ุธุงู… ุงู„ุทุจู‚ูŠ ุงู„ู…ูƒูˆู† ู…ู† 3 ุทุจู‚ุงุช (ู…ุน ูุตู„ ุฌู„ุจ ุงู„ุญูŠุชุงู†)...")
215
 
216
- if not await state_manager.wait_for_initialization(): print("โŒ ุงู„ุฎุฏู…ุงุช ุบูŠุฑ ู…ู‡ูŠุฃุฉ ุจุงู„ูƒุงู…ู„"); return None
217
 
218
- # ุงู„ุทุจู‚ุฉ 1
219
- print("\n๐Ÿ” ุงู„ุทุจู‚ุฉ 1: ุงู„ูุญุต ุงู„ุณุฑูŠุน (data_manager)...")
220
  layer1_candidates = await data_manager_global.layer1_rapid_screening()
221
- if not layer1_candidates: print("โŒ ู„ู… ูŠุชู… ุงู„ุนุซูˆุฑ ุนู„ู‰ ู…ุฑุดุญูŠู† ููŠ ุงู„ุทุจู‚ุฉ 1"); return None
222
- print(f"โœ… ุชู… ุงุฎุชูŠุงุฑ {len(layer1_candidates)} ุนู…ู„ุฉ ู„ู„ุทุจู‚ุฉ 2")
223
  layer1_symbols = [c['symbol'] for c in layer1_candidates]
224
 
225
- # ุงู„ุทุจู‚ุฉ 1.5: ุฌู„ุจ ุจูŠุงู†ุงุช ุงู„ุญูŠุชุงู†
226
  start_whale_fetch = time.time()
227
- print(f"\n๐Ÿ‹ ุงู„ุทุจู‚ุฉ 1.5: ุจุฏุก ุฌู„ุจ ุจูŠุงู†ุงุช ุงู„ุญูŠุชุงู† ู„ู€ {len(layer1_symbols)} ุนู…ู„ุฉ (ุจุดูƒู„ ุบูŠุฑ ู…ุนุฑู‚ู„)...")
228
  async def fetch_whale_data_task(symbols, results_dict):
229
  WHALE_FETCH_CONCURRENCY = 3
230
  semaphore = asyncio.Semaphore(WHALE_FETCH_CONCURRENCY)
@@ -235,69 +264,59 @@ async def run_3_layer_analysis():
235
  data = await data_manager_global.get_whale_data_for_symbol(symbol)
236
  if data: results_dict[symbol] = data
237
  except Exception as e:
238
- print(f" โŒ [Whale Fetch] ูุดู„ ุฌู„ุจ ุจูŠุงู†ุงุช ุงู„ุญูŠุชุงู† ู„ู€ {symbol}: {e}")
239
  results_dict[symbol] = {'data_available': False, 'error': str(e)}
240
  for symbol in symbols: tasks.append(asyncio.create_task(get_data_with_semaphore(symbol)))
241
  await asyncio.gather(*tasks)
242
  whale_fetcher_task = asyncio.create_task(fetch_whale_data_task(layer1_symbols, preloaded_whale_data_dict))
243
- print(" โณ ู…ู‡ู…ุฉ ุฌู„ุจ ุจูŠุงู†ุงุช ุงู„ุญูŠุชุงู† ุชุนู…ู„ ููŠ ุงู„ุฎู„ููŠุฉ...")
244
 
245
- # ุฅุนุฏุงุฏ ุงู„ู…ู†ุชุฌ/ุงู„ู…ุณุชู‡ู„ูƒ (OHLCV/ML)
246
  DATA_QUEUE_MAX_SIZE = 2
247
  ohlcv_data_queue = asyncio.Queue(maxsize=DATA_QUEUE_MAX_SIZE)
248
  ml_results_list = []
249
  market_context = await data_manager_global.get_market_context_async()
250
- ml_processor = MLProcessor(market_context, data_manager_global, learning_engine_global)
 
 
 
 
 
251
  batch_size = 15
252
  total_batches = (len(layer1_candidates) + batch_size - 1) // batch_size
253
- print(f" ๐Ÿš€ ุฅุนุฏุงุฏ ุงู„ู…ู†ุชุฌ/ุงู„ู…ุณุชู‡ู„ูƒ (OHLCV/ML): {total_batches} ุฏูุนุฉ ู…ุชูˆู‚ุนุฉ (ุจุญุฌู… {batch_size})")
254
-
255
- # ูˆุธูŠูุฉ ุงู„ู…ุณุชู‡ู„ูƒ (ML Consumer)
256
  async def ml_consumer_task(queue: asyncio.Queue, results_list: list, whale_data_store: dict):
257
  batch_num = 0
258
  while True:
259
  try:
260
  batch_data = await queue.get()
261
- if batch_data is None: queue.task_done(); print(" ๐Ÿ›‘ [ML Consumer] ุชู„ู‚ู‰ ุฅุดุงุฑุฉ ุงู„ุชูˆู‚ู."); break
262
  batch_num += 1
263
- print(f" ๐Ÿ“ฌ [ML Consumer] ุงุณุชู„ู… ุฏูุนุฉ OHLCV {batch_num}/{total_batches} ({len(batch_data)} ุนู…ู„ุฉ)")
264
- # ๐Ÿ”ด ู‡ู†ุง ูŠุชู… ุงุณุชุฎุฏุงู… ู…ูˆู†ุช ูƒุงุฑู„ูˆ (ุงู„ู…ุฑุญู„ุฉ 1) ุงู„ุณุฑูŠุน
265
  batch_results_dict = await process_batch_parallel(
266
  batch_data, ml_processor, batch_num, total_batches, whale_data_store
267
  )
268
  results_list.append(batch_results_dict)
269
  queue.task_done()
270
- print(f" โœ… [ML Consumer] ุฃูƒู…ู„ ู…ุนุงู„ุฌุฉ ุงู„ุฏูุนุฉ {batch_num}/{total_batches}")
271
- except Exception as e: print(f"โŒ [ML Consumer] ุฎุทุฃ ูุงุฏุญ: {e}"); traceback.print_exc(); queue.task_done()
272
 
273
- # ุชุดุบูŠู„ ุงู„ู…ุณุชู‡ู„ูƒ (ML Consumer) ูˆุงู„ู…ู†ุชุฌ (OHLCV Producer)
274
- print(" โ–ถ๏ธ [ML Consumer] ุจุฏุก ุชุดุบูŠู„ ู…ู‡ู…ุฉ ุงู„ู…ุณุชู‡ู„ูƒ...")
275
  consumer_task = asyncio.create_task(ml_consumer_task(ohlcv_data_queue, ml_results_list, preloaded_whale_data_dict))
276
- print(" โ–ถ๏ธ [OHLCV Producer] ุจุฏุก ุชุดุบูŠู„ ู…ู‡ู…ุฉ ุงู„ู…ู†ุชุฌ (ุชุฏูู‚ ุจูŠุงู†ุงุช OHLCV)...")
277
  producer_task = asyncio.create_task(data_manager_global.stream_ohlcv_data(layer1_symbols, ohlcv_data_queue))
278
-
279
- # ุงู†ุชุธุงุฑ ุงู†ุชู‡ุงุก ุงู„ู…ู†ุชุฌ ูˆุงู„ู…ุณุชู‡ู„ูƒ
280
- await producer_task; print(" โœ… [OHLCV Producer] ุฃู†ู‡ู‰ ุฌู„ุจ ุฌู…ูŠุน ุจูŠุงู†ุงุช OHLCV.")
281
  await ohlcv_data_queue.put(None)
282
  await ohlcv_data_queue.join()
283
- await consumer_task; print(" โœ… [ML Consumer] ุฃู†ู‡ู‰ ู…ุนุงู„ุฌุฉ ุฌู…ูŠุน ุงู„ุฏูุนุงุช.")
284
 
285
- # ุงู†ุชุธุงุฑ ุงูƒุชู…ุงู„ ู…ู‡ู…ุฉ ุฌู„ุจ ุงู„ุญูŠุชุงู† (ู…ุน Timeout)
286
- print(" โณ ุงู†ุชุธุงุฑ ุงูƒุชู…ุงู„ ู…ู‡ู…ุฉ ุฌู„ุจ ุจูŠุงู†ุงุช ุงู„ุญูŠุชุงู† (ุจุญุฏ ุฃู‚ุตู‰ ู„ู„ู…ู‡ู„ุฉ)...")
287
  WHALE_FETCH_TIMEOUT_SECONDS = 180
288
  try:
289
  await asyncio.wait_for(whale_fetcher_task, timeout=WHALE_FETCH_TIMEOUT_SECONDS)
290
- end_whale_fetch = time.time()
291
- print(f" โœ… ุงูƒุชู…ู„ ุฌู„ุจ ุจูŠุงู†ุงุช ุงู„ุญูŠุชุงู† ููŠ {end_whale_fetch - start_whale_fetch:.2f} ุซุงู†ูŠุฉ. ุชู… ุฌู„ุจ/ู…ุญุงูˆู„ุฉ ุฌู„ุจ ุจูŠุงู†ุงุช ู„ู€ {len(preloaded_whale_data_dict)} ุนู…ู„ุฉ.")
292
  except asyncio.TimeoutError:
293
- end_whale_fetch = time.time()
294
- print(f" โš ๏ธ ุงู†ุชู‡ุช ู…ู‡ู„ุฉ ุงู†ุชุธุงุฑ ุฌู„ุจ ุจูŠุงู†ุงุช ุงู„ุญูŠุชุงู† ({WHALE_FETCH_TIMEOUT_SECONDS} ุซุงู†ูŠุฉ)! ุชู… ุฌู„ุจ/ู…ุญุงูˆู„ุฉ ุฌู„ุจ ุจูŠุงู†ุงุช ู„ู€ {len(preloaded_whale_data_dict)} ุนู…ู„ุฉ ุญุชู‰ ุงู„ุขู†.")
295
  except Exception as whale_task_err:
296
- end_whale_fetch = time.time()
297
- print(f" โŒ ุญุฏุซ ุฎุทุฃ ุบูŠุฑ ู…ุชูˆู‚ุน ุฃุซู†ุงุก ุงู†ุชุธุงุฑ ู…ู‡ู…ุฉ ุฌู„ุจ ุงู„ุญูŠุชุงู†: {whale_task_err}")
298
 
299
- # ุชุฌู…ูŠุน ุงู„ู†ุชุงุฆุฌ
300
- print("๐Ÿ”„ ุชุฌู…ูŠุน ุฌู…ูŠุน ุงู„ู†ุชุงุฆุฌ...")
301
  for batch_result in ml_results_list:
302
  for success_item in batch_result['success']:
303
  symbol = success_item['symbol']
@@ -310,154 +329,94 @@ async def run_3_layer_analysis():
310
  layer2_candidates.append(success_item)
311
  all_low_score_candidates.extend(batch_result['low_score'])
312
  all_failed_candidates.extend(batch_result['failures'])
313
-
314
- print(f"โœ… ุงูƒุชู…ู„ ุงู„ุชุญู„ูŠู„ ุงู„ู…ุชู‚ุฏู… (MC-Phase1): {len(layer2_candidates)} ู†ุฌุงุญ (ุนุงู„ูŠ) | {len(all_low_score_candidates)} ู†ุฌุงุญ (ู…ู†ุฎูุถ) | {len(all_failed_candidates)} ูุดู„")
315
- if not layer2_candidates: print("โŒ ู„ู… ูŠุชู… ุงู„ุนุซูˆุฑ ุนู„ู‰ ู…ุฑุดุญูŠู† ููŠ ุงู„ุทุจู‚ุฉ 2")
316
 
317
- # ุงู„ุชุฑุชูŠุจ ูˆุงู„ูู„ุชุฑุฉ (ุจู†ุงุกู‹ ุนู„ู‰ ุงู„ุฏุฑุฌุฉ ุงู„ุชูŠ ุชุชุถู…ู† MC-Phase1)
 
 
318
  layer2_candidates.sort(key=lambda x: x.get('enhanced_final_score', 0), reverse=True)
319
  target_count = min(10, len(layer2_candidates))
320
  final_layer2_candidates = layer2_candidates[:target_count]
321
- print(f"๐ŸŽฏ ุชู… ุงุฎุชูŠุงุฑ {len(final_layer2_candidates)} ุนู…ู„ุฉ ู„ู„ุทุจู‚ุฉ 2.5 (ุงู„ุฃู‚ูˆู‰ ูู‚ุท)")
322
-
323
- # ๐Ÿ”ด --- ุจุฏุก ุงู„ุทุจู‚ุฉ 2.5: ุงู„ุชุญู„ูŠู„ ุงู„ู…ุชู‚ุฏู… (GARCH+LGBM) --- ๐Ÿ”ด
324
- print(f"\n๐Ÿ”ฌ ุงู„ุทุจู‚ุฉ 2.5: ุชุดุบูŠู„ ุงู„ุชุญู„ูŠู„ ุงู„ู…ุชู‚ุฏู… (GARCH+LGBM) ุนู„ู‰ ุฃูุถู„ {len(final_layer2_candidates)} ู…ุฑุดุญ...")
325
- advanced_mc_analyzer = ml_processor.monte_carlo_analyzer # ุงู„ุญุตูˆู„ ุนู„ู‰ ู…ุญู„ู„ ู…ูˆู†ุช ูƒุงุฑู„ูˆ
326
 
 
 
 
327
  updated_candidates_for_llm = []
328
  for candidate in final_layer2_candidates:
329
  symbol = candidate.get('symbol', 'UNKNOWN')
330
  try:
331
- print(f" ๐Ÿ”„ [Advanced MC] ุชุญู„ูŠู„ {symbol}...")
332
- # ุงุณุชุฏุนุงุก ุงู„ุฏุงู„ุฉ ุงู„ุฌุฏูŠุฏุฉ ุงู„ู…ุชู‚ุฏู…ุฉ
333
  advanced_mc_results = await advanced_mc_analyzer.generate_1h_distribution_advanced(
334
  candidate.get('ohlcv')
335
  )
336
-
337
  if advanced_mc_results and advanced_mc_results.get('simulation_model') == 'Phase2_GARCH_LGBM':
338
- print(f" โœ… [Advanced MC] {symbol} - ุชู… ุงู„ุชุญุฏูŠุซ ุจู†ู…ูˆุฐุฌ GARCH/LGBM.")
339
- # ุงุณุชุจุฏุงู„ ู†ุชุงุฆุฌ ุงู„ู…ุฑุญู„ุฉ 1 ุจู†ุชุงุฆุฌ ุงู„ู…ุฑุญู„ุฉ 2+3
340
  candidate['monte_carlo_distribution'] = advanced_mc_results
341
  candidate['monte_carlo_probability'] = advanced_mc_results.get('probability_of_gain', 0)
342
- candidate['advanced_mc_run'] = True # ุฅุถุงูุฉ ุนู„ุงู…ุฉ ู„ู„ุชุฏู‚ูŠู‚
343
  else:
344
- print(f" โš ๏ธ [Advanced MC] {symbol} - ูุดู„ ุงู„ุชุญู„ูŠู„ ุงู„ู…ุชู‚ุฏู…ุŒ ุงุณุชุฎุฏุงู… ู†ุชุงุฆุฌ ุงู„ู…ุฑุญู„ุฉ 1.")
345
- candidate['advanced_mc_run'] = False # ุฅุถุงูุฉ ุนู„ุงู…ุฉ ู„ู„ุชุฏู‚ูŠู‚
346
-
347
  updated_candidates_for_llm.append(candidate)
348
-
349
  except Exception as e:
350
- print(f" โŒ [Advanced MC] {symbol} - ุฎุทุฃ ูุงุฏุญ: {e}. ุงุณุชุฎุฏุงู… ู†ุชุงุฆุฌ ุงู„ู…ุฑุญู„ุฉ 1.")
351
  candidate['advanced_mc_run'] = False
352
  updated_candidates_for_llm.append(candidate)
353
-
354
- final_layer2_candidates = updated_candidates_for_llm # ุงุณุชุฎุฏุงู… ุงู„ู‚ุงุฆู…ุฉ ุงู„ู…ุญุฏุซุฉ ู„ู„ุทุจู‚ุฉ 3
355
- # ๐Ÿ”ด --- ู†ู‡ุงูŠุฉ ุงู„ุทุจู‚ุฉ 2.5 --- ๐Ÿ”ด
356
 
357
  await r2_service_global.save_candidates_async(final_layer2_candidates)
358
- print("\n๐Ÿ† ุฃูุถู„ 10 ุนู…ู„ุงุช (ุจุนุฏ ุงู„ุชุฏู‚ูŠู‚) ุฌุงู‡ุฒุฉ ู„ู„ุทุจู‚ุฉ 3:")
359
- for i, candidate in enumerate(final_layer2_candidates):
360
- score=candidate.get('enhanced_final_score',0); strategy=candidate.get('target_strategy','GENERIC'); mc_dist=candidate.get('monte_carlo_distribution'); pattern=candidate.get('pattern_analysis',{}).get('pattern_detected','no_pattern'); timeframes=candidate.get('successful_timeframes',0); symbol=candidate.get('symbol','UNKNOWN')
361
- print(f" {i+1}. {symbol}: ๐Ÿ“Š {score:.3f} | ุงู„ุฃุทุฑ: {timeframes}/6")
362
-
363
- if mc_dist:
364
- mc_model = mc_dist.get('simulation_model', 'Phase1')
365
- mc_pi_90 = mc_dist.get('prediction_interval_90', [0,0])
366
- mc_var = mc_dist.get('risk_metrics', {}).get('VaR_95_value', 0)
367
- print(f" ๐ŸŽฏ ู…ูˆู†ุช ูƒุงุฑู„ูˆ ({mc_model}): 90% PI [{mc_pi_90[0]:.4f} - {mc_pi_90[1]:.4f}] | VaR: ${mc_var:.4f}")
368
-
369
- print(f" ๐ŸŽฏ ุงุณุชุฑุงุชูŠุฌูŠุฉ: {strategy} | ู†ู…ุท: {pattern}")
370
- whale_data = candidate.get('whale_data')
371
- if whale_data and whale_data.get('data_available'): signal = whale_data.get('trading_signal', {}); print(f" ๐Ÿ‹ ุญูŠุชุงู†: {signal.get('action', 'HOLD')} (ุซู‚ุฉ: {signal.get('confidence', 0):.2f}){' โš ๏ธ' if signal.get('critical_alert') else ''}")
372
- elif whale_data and whale_data.get('error'): print(f" ๐Ÿ‹ ุญูŠุชุงู†: ุฎุทุฃ ({whale_data.get('error')[:50]}...)")
373
-
374
- # ุงู„ุทุจู‚ุฉ 3
375
- print("\n๐Ÿง  ุงู„ุทุจู‚ุฉ 3: ุงู„ุชุญู„ูŠู„ ุจุงู„ู†ู…ูˆุฐุฌ ุงู„ุถุฎู… (LLMService)...")
376
- # ๐Ÿ”ด ุงุณุชุฎุฏุงู… ุงู„ู‚ุงุฆู…ุฉ ุงู„ู…ุญุฏุซุฉ
377
  for candidate in final_layer2_candidates:
378
  try:
379
- symbol = candidate['symbol']; print(f" ๐Ÿค” ุชุญู„ูŠู„ {symbol} ุจุงู„ู†ู…ูˆุฐุฌ ุงู„ุถุฎู… (ุจูŠุงู†ุงุช MC ู…ุชู‚ุฏู…ุฉ)...")
380
  ohlcv_data = candidate.get('ohlcv');
381
- if not ohlcv_data: print(f" โš ๏ธ ู„ุง ุชูˆุฌุฏ ุจูŠุงู†ุงุช ุดู…ูˆุน ู„ู€ {symbol}"); continue
382
  candidate['raw_ohlcv'] = ohlcv_data
383
- timeframes_count = candidate.get('successful_timeframes', 0); total_candles = sum(len(data) for data in ohlcv_data.values()) if ohlcv_data else 0
384
- if total_candles < 30: print(f" โš ๏ธ ุจูŠุงู†ุงุช ุดู…ูˆุน ุบูŠุฑ ูƒุงููŠุฉ ู„ู€ {symbol}: {total_candles} ุดู…ุนุฉ ูู‚ุท"); continue
385
- print(f" ๐Ÿ“Š ุฅุฑุณุงู„ {symbol} ู„ู„ู†ู…ูˆุฐุฌ: {total_candles} ุดู…ุนุฉ ููŠ {timeframes_count} ุฅุทุงุฑ ุฒู…ู†ูŠ")
386
 
387
- # ๐Ÿ”ด ุชู…ุฑูŠุฑ ุจูŠุงู†ุงุช ุฅุถุงููŠุฉ (ู…ุซู„ sentiment) ุฅู„ู‰ ุงู„ู†ู…ูˆุฐุฌ
388
- candidate['sentiment_data'] = await data_manager_global.get_market_context_async() # ุถู…ุงู† ุฃุญุฏุซ ุณูŠุงู‚
389
 
390
  llm_analysis = await llm_service_global.get_trading_decision(candidate)
391
 
392
  if llm_analysis and llm_analysis.get('action') in ['BUY']:
393
- opportunity={'symbol': symbol, 'current_price': candidate.get('current_price', 0), 'decision': llm_analysis, 'enhanced_score': candidate.get('enhanced_final_score', 0), 'llm_confidence': llm_analysis.get('confidence_level', 0), 'strategy': llm_analysis.get('strategy', 'GENERIC'), 'analysis_timestamp': datetime.now().isoformat(), 'timeframes_count': timeframes_count, 'total_candles': total_candles}
 
 
 
 
 
 
 
 
 
 
 
 
394
  final_opportunities.append(opportunity)
395
- print(f" โœ… {symbol}: {llm_analysis.get('action')} - ุซู‚ุฉ: {llm_analysis.get('confidence_level', 0):.2f} (ู…ู„ู ุฎุฑูˆุฌ: {llm_analysis.get('exit_profile')})") # ๐Ÿ”ด
396
- else: action = llm_analysis.get('action', 'NO_DECISION') if llm_analysis else 'NO_RESPONSE'; print(f" โš ๏ธ {symbol}: ู„ุง ูŠูˆุฌุฏ ู‚ุฑุงุฑ ุชุฏุงูˆู„ ู…ู† ุงู„ู†ู…ูˆุฐุฌ ุงู„ุถุฎู… ({action})")
397
- except Exception as e: print(f"โŒ ุฎุทุฃ ููŠ ุชุญู„ูŠู„ ุงู„ู†ู…ูˆุฐุฌ ุงู„ุถุฎู… ู„ู€ {candidate.get('symbol')}: {e}"); traceback.print_exc(); continue
 
398
 
399
  if final_opportunities:
400
  final_opportunities.sort(key=lambda x: (x['llm_confidence'] + x['enhanced_score']) / 2, reverse=True)
401
- print(f"\n๐Ÿ† ุงู„ู†ุธุงู… ุงู„ุทุจู‚ูŠ ุงูƒุชู…ู„: {len(final_opportunities)} ูุฑุตุฉ ุชุฏุงูˆู„")
402
- for i, opportunity in enumerate(final_opportunities[:5]): print(f" {i+1}. {opportunity['symbol']}: {opportunity['decision'].get('action')} - ุซู‚ุฉ: {opportunity['llm_confidence']:.2f} - ุฃุทุฑ: {opportunity['timeframes_count']}")
403
 
404
- # ุณุฌู„ ุงู„ุชุฏู‚ูŠู‚
405
- try:
406
- top_10_detailed_summary = []
407
- for c in final_layer2_candidates:
408
- whale_summary = "Not Available"; whale_data = c.get('whale_data')
409
- if whale_data and whale_data.get('data_available'): signal = whale_data.get('trading_signal', {}); action = signal.get('action', 'HOLD'); confidence = signal.get('confidence', 0); reason_preview = signal.get('reason', 'N/A')[:75] + "..." if signal.get('reason') else 'N/A'; whale_summary = f"Action: {action}, Conf: {confidence:.2f}, Alert: {signal.get('critical_alert', False)}, Reason: {reason_preview}"
410
- elif whale_data and whale_data.get('error'): whale_summary = f"Error: {whale_data['error'][:50]}..."
411
-
412
- mc_summary = "N/A"
413
- mc_dist = c.get('monte_carlo_distribution')
414
- if mc_dist:
415
- mc_model = mc_dist.get('simulation_model', 'Unknown')
416
- if mc_model == 'Phase2_GARCH_LGBM':
417
- drift = mc_dist.get('forecasted_drift_lgbm', 0)
418
- vol = mc_dist.get('forecasted_vol_garch', 0)
419
- mc_summary = f"Phase2_GARCH(vol={vol:.5f})_LGBM(drift={drift:.5f})"
420
- else: # Phase1 or Error
421
- var_val = mc_dist.get('risk_metrics', {}).get('VaR_95_value', 0)
422
- mc_summary = f"{mc_model}_VaR({var_val:.4f})"
423
-
424
- top_10_detailed_summary.append({
425
- "symbol": c.get('symbol'),
426
- "score": c.get('enhanced_final_score', 0),
427
- "timeframes": f"{c.get('successful_timeframes', 'N/A')}/6",
428
- "whale_data_summary": whale_summary,
429
- "strategy": c.get('target_strategy', 'N/A'),
430
- "pattern": c.get('pattern_analysis', {}).get('pattern_detected', 'N/A'),
431
- "mc_analysis_level": mc_summary
432
- })
433
-
434
- other_successful_candidates = layer2_candidates[target_count:]
435
- other_success_summary = [{"symbol": c['symbol'], "score": c.get('enhanced_final_score', 0), "timeframes": f"{c.get('successful_timeframes', 'N/A')}/6", "whale_data": "Available" if c.get('whale_data', {}).get('data_available') else ("Error" if c.get('whale_data', {}).get('error') else "Not Available")} for c in other_successful_candidates]
436
- low_score_summary = [{"symbol": c['symbol'], "score": c.get('enhanced_final_score', 0), "timeframes": f"{c.get('successful_timeframes', 'N/A')}/6", "whale_data": "Available" if c.get('whale_data', {}).get('data_available') else ("Error" if c.get('whale_data', {}).get('error') else "Not Available")} for c in all_low_score_candidates]
437
- audit_data = { "timestamp": datetime.now().isoformat(), "total_layer1_candidates": len(layer1_candidates), "total_processed_in_layer2": len(layer2_candidates) + len(all_low_score_candidates) + len(all_failed_candidates), "counts": {"sent_to_llm": len(final_layer2_candidates), "success_not_top_10": len(other_successful_candidates), "success_low_score": len(all_low_score_candidates), "failures": len(all_failed_candidates)}, "top_candidates_for_llm": top_10_detailed_summary, "other_successful_candidates": other_success_summary, "low_score_candidates": low_score_summary, "failed_candidates": all_failed_candidates, }
438
- await r2_service_global.save_analysis_audit_log_async(audit_data)
439
- print(f"โœ… ุชู… ุญูุธ ุณุฌู„ ุชุฏู‚ูŠู‚ ุงู„ุชุญู„ูŠู„ ููŠ R2 (ู…ุน ุชูุงุตูŠู„ MC ุงู„ู…ุชู‚ุฏู…ุฉ).")
440
- except Exception as audit_error: print(f"โŒ ูุดู„ ุญูุธ ุณุฌู„ ุชุฏู‚ูŠู‚ ุงู„ุชุญู„ูŠู„: {audit_error}"); traceback.print_exc()
441
 
442
- if not final_opportunities: print("โŒ ู„ู… ูŠุชู… ุงู„ุนุซูˆุฑ ุนู„ู‰ ูุฑุต ุชุฏุงูˆู„ ู…ู†ุงุณุจุฉ"); return None
443
  return final_opportunities[0] if final_opportunities else None
444
 
445
  except Exception as error:
446
- print(f"โŒ ุฎุทุฃ ูุงุฏุญ ููŠ ุงู„ู†ุธุงู… ุงู„ุทุจู‚ูŠ: {error}"); traceback.print_exc()
447
- try: # Log partial audit on failure
448
- audit_data = { "timestamp": datetime.now().isoformat(), "status": "FAILED", "error": str(error), "traceback": traceback.format_exc(), "total_layer1_candidates": len(layer1_candidates), "counts": {"sent_to_llm": 0, "success_not_top_10": 0, "success_low_score": len(all_low_score_candidates), "failures": len(all_failed_candidates)}, "failed_candidates": all_failed_candidates }
449
- await r2_service_global.save_analysis_audit_log_async(audit_data)
450
- print("โš ๏ธ ุชู… ุญูุธ ุณุฌู„ ุชุฏู‚ูŠู‚ ุฌุฒุฆูŠ ุจุนุฏ ุงู„ูุดู„.")
451
- except Exception as audit_fail_error: print(f"โŒ ูุดู„ ุญูุธ ุณุฌู„ ุงู„ุชุฏู‚ูŠู‚ ุฃุซู†ุงุก ู…ุนุงู„ุฌุฉ ุฎุทุฃ ุขุฎุฑ: {audit_fail_error}")
452
  return None
453
 
454
  async def re_analyze_open_trade_async(trade_data):
455
- """ุฅุนุงุฏุฉ ุชุญู„ูŠู„ ุงู„ุตูู‚ุฉ ุงู„ู…ูุชูˆุญุฉ"""
456
  symbol = trade_data.get('symbol')
457
  try:
458
- # ๐Ÿ”ด ุงุณุชุฎุฏุงู… ู‚ูู„ ู…ุฏูŠุฑ ุงู„ุญุงู„ุฉ ุงู„ู…ุญู„ูŠ
459
  async with state_manager.trade_analysis_lock:
460
- print(f"๐Ÿ”„ [Re-Analyze] ุจุฏุก ุงู„ุชุญู„ูŠู„ ุงู„ุงุณุชุฑุงุชูŠุฌูŠ ู„ู€ {symbol}...")
461
  market_context = await data_manager_global.get_market_context_async()
462
  ohlcv_data_list = []
463
  temp_queue = asyncio.Queue()
@@ -470,9 +429,9 @@ async def re_analyze_open_trade_async(trade_data):
470
  temp_queue.task_done()
471
  except asyncio.TimeoutError:
472
  if temp_queue.empty(): break
473
- except Exception as q_err: print(f"Error draining queue for re-analysis: {q_err}"); break
474
 
475
- if not ohlcv_data_list: print(f"โš ๏ธ ูุดู„ ุฌู„ุจ ุจูŠุงู†ุงุช ุฅุนุงุฏุฉ ุงู„ุชุญู„ูŠู„ ู„ู€ {symbol}"); return None
476
  ohlcv_data = ohlcv_data_list[0]
477
 
478
  l1_data = await data_manager_global._get_detailed_symbol_data(symbol)
@@ -480,15 +439,17 @@ async def re_analyze_open_trade_async(trade_data):
480
 
481
  re_analysis_whale_data = await data_manager_global.get_whale_data_for_symbol(symbol)
482
 
483
- ml_processor = MLProcessor(market_context, data_manager_global, learning_engine_global)
 
 
 
484
 
485
- print(f"๐Ÿ”„ [Re-Analyze] ุงุณุชุฎุฏุงู… ู…ูˆู†ุช ูƒุงุฑู„ูˆ (Phase 2+3) ู„ู€ {symbol}...")
486
  advanced_mc_results = await ml_processor.monte_carlo_analyzer.generate_1h_distribution_advanced(
487
  ohlcv_data.get('ohlcv')
488
  )
489
 
490
  processed_data = await ml_processor.process_and_score_symbol_enhanced(ohlcv_data, {symbol: re_analysis_whale_data} if re_analysis_whale_data else {})
491
-
492
  if not processed_data: return None
493
 
494
  if advanced_mc_results:
@@ -497,47 +458,41 @@ async def re_analyze_open_trade_async(trade_data):
497
 
498
  processed_data['raw_ohlcv'] = ohlcv_data.get('raw_ohlcv') or ohlcv_data.get('ohlcv')
499
  processed_data['ohlcv'] = processed_data['raw_ohlcv']
500
-
501
- # ๐Ÿ”ด ุฅุถุงูุฉ ุณูŠุงู‚ ุงู„ุณูˆู‚ ุฅู„ู‰ ุงู„ุจูŠุงู†ุงุช ุงู„ู…ุฑุณู„ุฉ ู„ุฅุนุงุฏุฉ ุงู„ุชุญู„ูŠู„
502
  processed_data['sentiment_data'] = market_context
503
 
504
  re_analysis_decision = await llm_service_global.re_analyze_trade_async(trade_data, processed_data)
505
 
506
  if re_analysis_decision:
507
  await r2_service_global.save_system_logs_async({ "trade_reanalyzed": True, "symbol": symbol, "action": re_analysis_decision.get('action'), 'strategy': re_analysis_decision.get('strategy', 'GENERIC') })
508
- print(f"โœ… [Re-Analyze] ุงูƒุชู…ู„ ุงู„ุชุญู„ูŠู„ ุงู„ุงุณุชุฑุงุชูŠุฌูŠ ู„ู€ {symbol}. ุงู„ู‚ุฑุงุฑ: {re_analysis_decision.get('action')}")
509
  return {"symbol": symbol, "decision": re_analysis_decision, "current_price": processed_data.get('current_price')}
510
  else: return None
511
  except Exception as error: await r2_service_global.save_system_logs_async({ "reanalysis_error": True, "symbol": symbol, "error": str(error) }); print(f"โŒ Error in re_analyze_open_trade_async for {symbol}: {error}"); traceback.print_exc(); return None
512
 
513
 
514
  async def run_bot_cycle_async():
515
- """ุฏูˆุฑุฉ ุงู„ุชุฏุงูˆู„ ุงู„ุฑุฆูŠุณูŠุฉ"""
516
  try:
517
- if not await state_manager.wait_for_initialization(): print("โŒ ุงู„ุฎุฏู…ุงุช ุบูŠุฑ ู…ู‡ูŠุฃุฉ ุจุงู„ูƒุงู…ู„ - ุชุฎุทูŠ ุงู„ุฏูˆุฑุฉ"); return
518
- print("๐Ÿ”„ ุจุฏุก ุฏูˆุฑุฉ ุงู„ุชุฏุงูˆู„..."); await r2_service_global.save_system_logs_async({"cycle_started": True})
519
- if not r2_service_global.acquire_lock(): print("โŒ ูุดู„ ุงู„ุญุตูˆู„ ุนู„ู‰ ุงู„ู‚ูู„ - ุชุฎุทูŠ ุงู„ุฏูˆุฑุฉ"); return
520
 
521
  open_trades = []
522
  try:
523
- open_trades = await trade_manager_global.get_open_trades(); print(f"๐Ÿ“‹ ุงู„ุตูู‚ุงุช ุงู„ู…ูุชูˆุญุฉ: {len(open_trades)}")
524
- should_look_for_new_trade = len(open_trades) == 0
525
  if open_trades:
526
  now = datetime.now()
527
  trades_to_reanalyze = [t for t in open_trades if now >= datetime.fromisoformat(t.get('expected_target_time', now.isoformat()))]
528
  if trades_to_reanalyze:
529
- print(f"๐Ÿ”„ ุฅุนุงุฏุฉ ุชุญู„ูŠู„ {len(trades_to_reanalyze)} ุตูู‚ุฉ (ุจุงุณุชุฎุฏุงู… MC ุงู„ู…ุชู‚ุฏู…)")
530
- # ๐Ÿ”ด ุณูŠุชู… ุชุดุบูŠู„ ู‡ุฐู‡ ุงู„ุฏุงู„ุฉ (re_analyze_open_trade_async)
531
- # ูˆุณุชู‚ูˆู… ุจุงุณุชุฎุฏุงู… ู‚ูู„ "state_manager.trade_analysis_lock"
532
- # ู…ู…ุง ูŠูˆู‚ู ุงู„ู…ุฑุงู‚ุจ ุงู„ุชูƒุชูŠูƒูŠ ู…ุคู‚ุชุงู‹ ู„ุชู„ูƒ ุงู„ุนู…ู„ุฉ
533
  reanalysis_results = await asyncio.gather(*[re_analyze_open_trade_async(trade) for trade in trades_to_reanalyze], return_exceptions=True)
534
  for i, result in enumerate(reanalysis_results):
535
  trade = trades_to_reanalyze[i]
536
- if isinstance(result, Exception): print(f" โŒ ูุดู„ ุฅุนุงุฏุฉ ุชุญู„ูŠู„ {trade.get('symbol')}: {result}")
537
- elif result and result['decision'].get('action') == "CLOSE_TRADE": print(f" โœ… ุฅุบู„ุงู‚ {trade.get('symbol')} ุจู†ุงุกู‹ ุนู„ู‰ ุฅุนุงุฏุฉ ุงู„ุชุญู„ูŠู„."); await trade_manager_global.close_trade(trade, result['current_price'], 'CLOSED_BY_REANALYSIS');
538
- elif result and result['decision'].get('action') == "UPDATE_TRADE": print(f" โœ… ุชุญุฏูŠุซ {trade.get('symbol')} ุจู†ุงุกู‹ ุนู„ู‰ ุฅุนุงุฏุฉ ุงู„ุชุญู„ูŠู„."); await trade_manager_global.update_trade(trade, result['decision'])
539
- elif result: print(f" โ„น๏ธ ุงู„ุงุญุชูุงุธ ุจู€ {trade.get('symbol')} ุจู†ุงุกู‹ ุนู„ู‰ ุฅุนุงุฏุฉ ุงู„ุชุญู„ูŠู„.")
540
- else: print(f" โš ๏ธ ุฅุนุงุฏุฉ ุชุญู„ูŠู„ {trade.get('symbol')} ู„ู… ุชู†ุชุฌ ู‚ุฑุงุฑู‹ุง.")
541
 
542
  current_open_trades_count = len(await trade_manager_global.get_open_trades())
543
  should_look_for_new_trade = current_open_trades_count == 0
@@ -545,18 +500,45 @@ async def run_bot_cycle_async():
545
  if should_look_for_new_trade:
546
  portfolio_state = await r2_service_global.get_portfolio_state_async(); current_capital = portfolio_state.get("current_capital_usd", 0)
547
  if current_capital > 1:
548
- print("๐ŸŽฏ ุงู„ุจุญุซ ุนู† ูุฑุต ุชุฏุงูˆู„ ุฌุฏูŠุฏุฉ (ู†ุธุงู… MC ุซู†ุงุฆูŠ ุงู„ู…ุฑุงุญู„)...")
549
  best_opportunity = await run_3_layer_analysis()
 
 
 
550
  if best_opportunity:
551
- print(f"โœ… ูุชุญ ุตูู‚ุฉ ุฌุฏูŠุฏุฉ: {best_opportunity['symbol']}")
552
- await trade_manager_global.open_trade( best_opportunity['symbol'], best_opportunity['decision'], best_opportunity['current_price'])
553
- else: print("โŒ ู„ู… ูŠุชู… ุงู„ุนุซูˆุฑ ุนู„ู‰ ูุฑุต ุชุฏุงูˆู„ ู…ู†ุงุณุจุฉ")
554
- else: print("โŒ ุฑุฃุณ ุงู„ู…ุงู„ ุบูŠุฑ ูƒุงููŠ ู„ูุชุญ ุตูู‚ุงุช ุฌุฏูŠุฏุฉ")
555
- else: print("โ„น๏ธ ูŠูˆุฌุฏ ุตูู‚ุฉ ู…ูุชูˆุญุฉ ุจุงู„ูุนู„ุŒ ุชุฎุทูŠ ุงู„ุจุญุซ ุนู† ุตูู‚ุฉ ุฌุฏูŠุฏุฉ.")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
556
  finally:
557
  if r2_service_global.lock_acquired: r2_service_global.release_lock()
558
  await r2_service_global.save_system_logs_async({ "cycle_completed": True, "open_trades": len(open_trades)})
559
- print("โœ… ุงูƒุชู…ู„ุช ุฏูˆุฑุฉ ุงู„ุชุฏุงูˆู„")
560
 
561
  except Exception as error:
562
  print(f"โŒ Unhandled error in main cycle: {error}"); traceback.print_exc()
@@ -565,17 +547,24 @@ async def run_bot_cycle_async():
565
 
566
  @asynccontextmanager
567
  async def lifespan(application: FastAPI):
568
- """ุฅุฏุงุฑุฉ ุฏูˆุฑุฉ ุญูŠุงุฉ ุงู„ุชุทุจูŠู‚"""
569
- print("๐Ÿš€ ุจุฏุก ุชู‡ูŠุฆุฉ ุงู„ุชุทุจูŠู‚...")
570
  try:
571
  success = await initialize_services()
572
- if not success: print("โŒ ูุดู„ ุชู‡ูŠุฆุฉ ุงู„ุชุทุจูŠู‚ - ุฅุบู„ุงู‚..."); yield; return
 
573
  asyncio.create_task(monitor_market_async())
574
- # ๐Ÿ”ด ุจุฏุก ู…ุฑุงู‚ุจุฉ ุงู„ุตูู‚ุงุช (ุงู„ู…ุฑุงู‚ุจ ุงู„ุชูƒุชูŠูƒูŠ)
575
  asyncio.create_task(trade_manager_global.start_trade_monitoring())
 
 
 
 
 
 
576
  await r2_service_global.save_system_logs_async({"application_started": True})
577
- print("๐ŸŽฏ ุงู„ุชุทุจูŠู‚ ุฌุงู‡ุฒ ู„ู„ุนู…ู„ - ู†ุธุงู… ุงู„ุทุจู‚ุงุช 3 (MC ุซู†ุงุฆูŠ ุงู„ู…ุฑุงุญู„) ูุนุงู„")
578
- print(" -> ๐Ÿ“ˆ ุงู„ู…ุฑุงู‚ุจ ุงู„ุชูƒุชูŠูƒูŠ (Dynamic Exit) ู†ุดุท ุงู„ุขู†")
 
579
  yield
580
  except Exception as error:
581
  print(f"โŒ Application startup failed: {error}");
@@ -587,42 +576,49 @@ async def lifespan(application: FastAPI):
587
  await cleanup_on_shutdown()
588
 
589
 
590
- application = FastAPI(lifespan=lifespan, title="AI Trading Bot", description="ู†ุธุงู… ุชุฏุงูˆู„ ุฐูƒูŠ ุจุชุญู„ูŠู„ ู…ูˆู†ุช ูƒุงุฑู„ูˆ ุซู†ุงุฆูŠ ุงู„ู…ุฑุงุญู„ (GARCH+LGBM) ู…ุน ุฅุฏุงุฑุฉ ุฎุฑูˆุฌ ุฏูŠู†ุงู…ูŠูƒูŠุฉ", version="3.4.0") # ๐Ÿ”ด
591
 
 
592
  @application.get("/")
593
- async def root(): return {"message": "ู…ุฑุญุจุงู‹ ุจูƒ ููŠ ู†ุธุงู… ุงู„ุชุฏุงูˆู„ ุงู„ุฐูƒูŠ", "system": "3-Layer Analysis System (Dynamic Exit Management)", "status": "running" if state_manager.initialization_complete else "initializing", "timestamp": datetime.now().isoformat()}
594
  @application.get("/run-cycle")
595
  async def run_cycle_api():
596
- if not state_manager.initialization_complete: raise HTTPException(status_code=503, detail="ุงู„ุฎุฏู…ุงุช ุบูŠุฑ ู…ู‡ูŠุฃุฉ ุจุงู„ูƒุงู…ู„")
597
  asyncio.create_task(run_bot_cycle_async())
598
- return {"message": "Bot cycle initiated (Dynamic Exit Management)", "system": "3-Layer Analysis"}
599
  @application.get("/health")
600
- async def health_check(): return {"status": "healthy" if state_manager.initialization_complete else "initializing", "initialization_complete": state_manager.initialization_complete, "services_initialized": state_manager.services_initialized, "initialization_error": state_manager.initialization_error, "timestamp": datetime.now().isoformat(), "system_architecture": "3-Layer Analysis System (Dynamic Exit Management)", "layers": {"layer1": "Data Manager - Rapid Screening", "layer1.5": "Whale Data Fetcher (Async)", "layer2": "ML Processor (MC-Phase1 Filter)", "layer2.5": "Advanced MC (GARCH+LGBM) for Top 10", "layer3": "LLM Service - Strategic Decision + Exit Profile", "TacticalLayer": "TradeManager - Dynamic Exit Monitor (1-min)"}}
601
  @application.get("/analyze-market")
602
  async def analyze_market_api():
603
- if not state_manager.initialization_complete: raise HTTPException(status_code=503, detail="ุงู„ุฎุฏู…ุงุช ุบูŠุฑ ู…ู‡ูŠุฃุฉ ุจุงู„ูƒุงู…ู„")
604
  result = await run_3_layer_analysis()
605
  if result: return {"opportunity_found": True, "symbol": result['symbol'], "action": result['decision'].get('action'), "confidence": result['llm_confidence'], "strategy": result['strategy'], "exit_profile": result['decision'].get('exit_profile')}
606
  else: return {"opportunity_found": False, "message": "No suitable opportunities found"}
607
  @application.get("/portfolio")
608
  async def get_portfolio_api():
609
- if not state_manager.initialization_complete: raise HTTPException(status_code=503, detail="ุงู„ุฎุฏู…ุงุช ุบูŠุฑ ู…ู‡ูŠุฃุฉ ุจุงู„ูƒุงู…ู„")
610
  try: portfolio_state = await r2_service_global.get_portfolio_state_async(); open_trades = await trade_manager_global.get_open_trades(); return {"portfolio": portfolio_state, "open_trades": open_trades, "timestamp": datetime.now().isoformat()}
611
- except Exception as e: raise HTTPException(status_code=500, detail=f"ุฎุทุฃ ููŠ ุฌู„ุจ ุจูŠุงู†ุงุช ุงู„ู…ุญูุธุฉ: {str(e)}")
612
  @application.get("/system-status")
613
  async def get_system_status(): monitoring_status = trade_manager_global.get_monitoring_status() if trade_manager_global else {}; return {"initialization_complete": state_manager.initialization_complete, "services_initialized": state_manager.services_initialized, "initialization_error": state_manager.initialization_error, "market_state_ok": state.MARKET_STATE_OK, "monitoring_status": monitoring_status, "timestamp": datetime.now().isoformat()}
614
 
615
  async def cleanup_on_shutdown():
616
- global r2_service_global, data_manager_global, trade_manager_global, learning_engine_global
 
 
 
617
  print("๐Ÿ›‘ Shutdown signal received. Cleaning up...")
618
  if trade_manager_global: trade_manager_global.stop_monitoring(); print("โœ… Trade monitoring stopped")
619
- if learning_engine_global and learning_engine_global.initialized:
 
 
 
620
  try:
621
- await learning_engine_global.save_weights_to_r2();
622
- await learning_engine_global.save_performance_history();
623
- await learning_engine_global.save_exit_profile_effectiveness(); # ๐Ÿ”ด ุญูุธ ุจูŠุงู†ุงุช ุงู„ุฎุฑูˆุฌ
624
- print("โœ… Learning engine data saved")
625
- except Exception as e: print(f"โŒ Failed to save learning engine data: {e}")
626
  if data_manager_global: await data_manager_global.close(); print("โœ… Data manager closed")
627
  if r2_service_global:
628
  try: await r2_service_global.save_system_logs_async({"application_shutdown": True}); print("โœ… Shutdown log saved")
@@ -633,5 +629,5 @@ def signal_handler(signum, frame): print(f"๐Ÿ›‘ Received signal {signum}. Initia
633
  signal.signal(signal.SIGINT, signal_handler); signal.signal(signal.SIGTERM, signal_handler)
634
 
635
  if __name__ == "__main__":
636
- print("๐Ÿš€ Starting AI Trading Bot with 3-Layer Analysis System (Dynamic Exit Management)...")
637
  uvicorn.run( application, host="0.0.0.0", port=7860, log_level="info", access_log=True )
 
1
+ # app.py (Fully updated to Learning Hub architecture)
2
  import os
3
  import traceback
4
  import signal
 
17
  from LLM import LLMService
18
  from data_manager import DataManager
19
  from ml_engine.processor import MLProcessor
20
+
21
+ # ๐Ÿ”ด --- START OF CHANGE --- ๐Ÿ”ด
22
+ # (Import the new hub manager instead of the old engine)
23
+ from learning_hub.hub_manager import LearningHubManager
24
+ # ๐Ÿ”ด --- END OF CHANGE --- ๐Ÿ”ด
25
+
26
  from sentiment_news import SentimentAnalyzer
27
  from trade_manager import TradeManager
28
+ import state # (This is state.py)
29
  from helpers import safe_float_conversion, validate_candidate_data_enhanced
30
  except ImportError as e:
31
  print(f"โŒ ุฎุทุฃ ููŠ ุงุณุชูŠุฑุงุฏ ุงู„ูˆุญุฏุงุช: {e}")
 
35
  r2_service_global = None
36
  data_manager_global = None
37
  llm_service_global = None
38
+ # ๐Ÿ”ด --- START OF CHANGE --- ๐Ÿ”ด
39
+ learning_hub_global = None # (Changed from learning_engine_global)
40
+ # ๐Ÿ”ด --- END OF CHANGE --- ๐Ÿ”ด
41
  trade_manager_global = None
42
  sentiment_analyzer_global = None
43
  symbol_whale_monitor_global = None
44
 
45
  class StateManager:
 
 
46
  def __init__(self):
47
  self.market_analysis_lock = asyncio.Lock()
48
+ self.trade_analysis_lock = asyncio.Lock()
49
  self.initialization_complete = False
50
  self.initialization_error = None
51
  self.services_initialized = {
52
  'r2_service': False, 'data_manager': False, 'llm_service': False,
53
+ # ๐Ÿ”ด --- START OF CHANGE --- ๐Ÿ”ด
54
+ 'learning_hub': False, # (Changed from learning_engine)
55
+ # ๐Ÿ”ด --- END OF CHANGE --- ๐Ÿ”ด
56
+ 'trade_manager': False, 'sentiment_analyzer': False,
57
  'symbol_whale_monitor': False
58
  }
59
 
 
75
  self.initialization_error = error
76
  print(f"โŒ ุฎุทุฃ ููŠ ุงู„ุชู‡ูŠุฆุฉ: {error}")
77
 
 
78
  state_manager = StateManager()
79
 
80
  async def initialize_services():
81
  """ุชู‡ูŠุฆุฉ ุฌู…ูŠุน ุงู„ุฎุฏู…ุงุช ุจุดูƒู„ ู…ู†ูุตู„"""
82
  global r2_service_global, data_manager_global, llm_service_global
83
+ # ๐Ÿ”ด --- START OF CHANGE --- ๐Ÿ”ด
84
+ global learning_hub_global # (Changed from learning_engine_global)
85
+ # ๐Ÿ”ด --- END OF CHANGE --- ๐Ÿ”ด
86
+ global trade_manager_global, sentiment_analyzer_global
87
  global symbol_whale_monitor_global
88
  try:
89
  print("๐Ÿš€ ุจุฏุก ุชู‡ูŠุฆุฉ ุงู„ุฎุฏู…ุงุช...")
 
97
  except Exception as e: print(f" โš ๏ธ ูุดู„ ุชู‡ูŠุฆุฉ ู…ุฑุงู‚ุจ ุงู„ุญูŠุชุงู†: {e}"); symbol_whale_monitor_global = None
98
  print(" ๐Ÿ”„ ุชู‡ูŠุฆุฉ DataManager..."); data_manager_global = DataManager(contracts_database, symbol_whale_monitor_global); await data_manager_global.initialize(); state_manager.set_service_initialized('data_manager'); print(" โœ… DataManager ู…ู‡ูŠุฃุฉ")
99
 
 
 
100
  print(" ๐Ÿ”„ ุชู‡ูŠุฆุฉ LLMService...");
101
  llm_service_global = LLMService();
102
  llm_service_global.r2_service = r2_service_global;
103
+
 
104
  print(" ๐Ÿ”„ ุชู‡ูŠุฆุฉ ู…ุญู„ู„ ุงู„ู…ุดุงุนุฑ...");
105
  sentiment_analyzer_global = SentimentAnalyzer(data_manager_global);
106
  state_manager.set_service_initialized('sentiment_analyzer');
107
  print(" โœ… ู…ุญู„ู„ ุงู„ู…ุดุงุนุฑ ู…ู‡ูŠุฃ")
108
 
109
+ # ๐Ÿ”ด --- START OF CHANGE --- ๐Ÿ”ด
110
+ # (Initialize the new Learning Hub Manager)
111
+ print(" ๐Ÿ”„ ุชู‡ูŠุฆุฉ ู…ุญูˆุฑ ุงู„ุชุนู„ู… (Learning Hub)...");
112
+ learning_hub_global = LearningHubManager(
113
+ r2_service=r2_service_global,
114
+ llm_service=llm_service_global,
115
+ data_manager=data_manager_global
116
+ )
117
+ await learning_hub_global.initialize()
118
+ state_manager.set_service_initialized('learning_hub');
119
+ print(" โœ… ู…ุญูˆุฑ ุงู„ุชุนู„ู… (Hub) ู…ู‡ูŠุฃ")
120
 
121
+ # (Connect the Hub to the LLM service)
122
+ llm_service_global.learning_hub = learning_hub_global
123
+ state_manager.set_service_initialized('llm_service');
124
+ print(" โœ… LLMService ู…ู‡ูŠุฃุฉ (ูˆู…ุฑุจูˆุทุฉ ุจู…ุญูˆุฑ ุงู„ุชุนู„ู…)")
125
 
126
  print(" ๐Ÿ”„ ุชู‡ูŠุฆุฉ ู…ุฏูŠุฑ ุงู„ุตูู‚ุงุช...");
127
+ # (Pass the new Learning Hub to the Trade Manager)
128
  trade_manager_global = TradeManager(
129
  r2_service_global,
130
+ learning_hub_global, # (Passing the new hub)
131
  data_manager_global,
132
+ state_manager
133
  )
134
  state_manager.set_service_initialized('trade_manager');
135
+ print(" โœ… ู…ุฏูŠุฑ ุงู„ุตูู‚ุงุช ู…ู‡ูŠุฃ (ูˆู…ุฑุจูˆุท ุจู…ุญูˆุฑ ุงู„ุชุนู„ู…)")
136
+ # ๐Ÿ”ด --- END OF CHANGE --- ๐Ÿ”ด
 
137
 
138
  print("๐ŸŽฏ ุงูƒุชู…ู„ุช ุชู‡ูŠุฆุฉ ุฌู…ูŠุน ุงู„ุฎุฏู…ุงุช ุจู†ุฌุงุญ"); return True
139
  except Exception as e: error_msg = f"ูุดู„ ุชู‡ูŠุฆุฉ ุงู„ุฎุฏู…ุงุช: {str(e)}"; print(f"โŒ {error_msg}"); state_manager.set_initialization_error(error_msg); return False
140
 
141
  async def monitor_market_async():
142
+ """(Unchanged)"""
143
  global data_manager_global, sentiment_analyzer_global
144
  try:
145
  if not await state_manager.wait_for_initialization(): print("โŒ ูุดู„ ุชู‡ูŠุฆุฉ ุงู„ุฎุฏู…ุงุช - ุฅูŠู‚ุงู ู…ุฑุงู‚ุจุฉ ุงู„ุณูˆู‚"); return
146
  while True:
147
  try:
 
148
  async with state_manager.market_analysis_lock:
149
  market_context = await sentiment_analyzer_global.get_market_sentiment()
150
  if not market_context: state.MARKET_STATE_OK = True; await asyncio.sleep(60); continue
 
160
  except Exception as error: print(f"โŒ ุฎุทุฃ ุฃุซู†ุงุก ู…ุฑุงู‚ุจุฉ ุงู„ุณูˆู‚: {error}"); state.MARKET_STATE_OK = True; await asyncio.sleep(60)
161
  except Exception as e: print(f"โŒ ูุดู„ ุชุดุบูŠู„ ู…ุฑุงู‚ุจุฉ ุงู„ุณูˆู‚: {e}")
162
 
163
+ # ๐Ÿ”ด --- START OF CHANGE --- ๐Ÿ”ด
164
+ # (New background task for periodic distillation - Point 6)
165
+ async def run_periodic_distillation():
166
  """
167
+ Runs the Learning Hub's distillation process periodically.
 
168
  """
169
+ print("background task: Periodic Distillation (Curator) scheduled.")
170
+ await asyncio.sleep(300) # (Wait 5 minutes after startup)
171
+
172
+ while True:
173
+ try:
174
+ if not await state_manager.wait_for_initialization():
175
+ await asyncio.sleep(60)
176
+ continue
177
+
178
+ print("๐Ÿ”„ [Scheduler] Running periodic distillation check...")
179
+ await learning_hub_global.run_distillation_check()
180
+
181
+ # (Run every 6 hours)
182
+ await asyncio.sleep(6 * 60 * 60)
183
+
184
+ except Exception as e:
185
+ print(f"โŒ [Scheduler] Error in periodic distillation task: {e}")
186
+ traceback.print_exc()
187
+ await asyncio.sleep(60 * 60) # (Wait 1 hour on error)
188
+ # ๐Ÿ”ด --- END OF CHANGE --- ๐Ÿ”ด
189
+
190
+ async def process_batch_parallel(batch, ml_processor, batch_num, total_batches, preloaded_whale_data):
191
+ """(Unchanged)"""
192
  try:
193
  batch_tasks = []
194
  for symbol_data in batch:
 
222
  return {'success': successful_results, 'low_score': low_score_results, 'failures': failed_results}
223
 
224
  except Exception as error:
225
+ print(f"โŒ [Consumer] Error processing batch {batch_num}: {error}")
226
  return {'success': [], 'low_score': [], 'failures': []}
227
 
228
 
229
  async def run_3_layer_analysis():
230
  """
231
+ (Updated to pass LearningHub to MLProcessor and save context for Reflector)
 
 
 
 
 
232
  """
233
 
234
  layer1_candidates = []
 
240
  preloaded_whale_data_dict = {}
241
 
242
  try:
243
+ print("๐ŸŽฏ Starting 3-Layer Analysis (with Learning Hub integration)...")
244
 
245
+ if not await state_manager.wait_for_initialization(): print("โŒ Services not fully initialized"); return None
246
 
247
+ # (Layer 1 - Unchanged)
248
+ print("\n๐Ÿ” Layer 1: Rapid Screening (data_manager)...")
249
  layer1_candidates = await data_manager_global.layer1_rapid_screening()
250
+ if not layer1_candidates: print("โŒ No candidates found in Layer 1"); return None
251
+ print(f"โœ… Selected {len(layer1_candidates)} symbols for Layer 2")
252
  layer1_symbols = [c['symbol'] for c in layer1_candidates]
253
 
254
+ # (Layer 1.5 - Unchanged)
255
  start_whale_fetch = time.time()
256
+ print(f"\n๐Ÿ‹ Layer 1.5: Fetching whale data for {len(layer1_symbols)} symbols (async)...")
257
  async def fetch_whale_data_task(symbols, results_dict):
258
  WHALE_FETCH_CONCURRENCY = 3
259
  semaphore = asyncio.Semaphore(WHALE_FETCH_CONCURRENCY)
 
264
  data = await data_manager_global.get_whale_data_for_symbol(symbol)
265
  if data: results_dict[symbol] = data
266
  except Exception as e:
 
267
  results_dict[symbol] = {'data_available': False, 'error': str(e)}
268
  for symbol in symbols: tasks.append(asyncio.create_task(get_data_with_semaphore(symbol)))
269
  await asyncio.gather(*tasks)
270
  whale_fetcher_task = asyncio.create_task(fetch_whale_data_task(layer1_symbols, preloaded_whale_data_dict))
 
271
 
272
+ # (Producer/Consumer Setup - Unchanged)
273
  DATA_QUEUE_MAX_SIZE = 2
274
  ohlcv_data_queue = asyncio.Queue(maxsize=DATA_QUEUE_MAX_SIZE)
275
  ml_results_list = []
276
  market_context = await data_manager_global.get_market_context_async()
277
+
278
+ # ๐Ÿ”ด --- START OF CHANGE --- ๐Ÿ”ด
279
+ # (Pass the global Learning Hub to the MLProcessor)
280
+ ml_processor = MLProcessor(market_context, data_manager_global, learning_hub_global)
281
+ # ๐Ÿ”ด --- END OF CHANGE --- ๐Ÿ”ด
282
+
283
  batch_size = 15
284
  total_batches = (len(layer1_candidates) + batch_size - 1) // batch_size
285
+
286
+ # (ML Consumer Task - Unchanged)
 
287
  async def ml_consumer_task(queue: asyncio.Queue, results_list: list, whale_data_store: dict):
288
  batch_num = 0
289
  while True:
290
  try:
291
  batch_data = await queue.get()
292
+ if batch_data is None: queue.task_done(); break
293
  batch_num += 1
 
 
294
  batch_results_dict = await process_batch_parallel(
295
  batch_data, ml_processor, batch_num, total_batches, whale_data_store
296
  )
297
  results_list.append(batch_results_dict)
298
  queue.task_done()
299
+ except Exception as e: print(f"โŒ [ML Consumer] Fatal Error: {e}"); traceback.print_exc(); queue.task_done()
 
300
 
301
+ # (Run Producer/Consumer - Unchanged)
 
302
  consumer_task = asyncio.create_task(ml_consumer_task(ohlcv_data_queue, ml_results_list, preloaded_whale_data_dict))
 
303
  producer_task = asyncio.create_task(data_manager_global.stream_ohlcv_data(layer1_symbols, ohlcv_data_queue))
304
+ await producer_task;
 
 
305
  await ohlcv_data_queue.put(None)
306
  await ohlcv_data_queue.join()
307
+ await consumer_task;
308
 
309
+ # (Wait for Whale Fetch - Unchanged)
 
310
  WHALE_FETCH_TIMEOUT_SECONDS = 180
311
  try:
312
  await asyncio.wait_for(whale_fetcher_task, timeout=WHALE_FETCH_TIMEOUT_SECONDS)
 
 
313
  except asyncio.TimeoutError:
314
+ print(f" โš ๏ธ Whale fetch timeout ({WHALE_FETCH_TIMEOUT_SECONDS}s)!")
 
315
  except Exception as whale_task_err:
316
+ print(f" โŒ Whale fetch task error: {whale_task_err}")
 
317
 
318
+ # (Aggregate Results - Unchanged)
319
+ print("๐Ÿ”„ Aggregating all results...")
320
  for batch_result in ml_results_list:
321
  for success_item in batch_result['success']:
322
  symbol = success_item['symbol']
 
329
  layer2_candidates.append(success_item)
330
  all_low_score_candidates.extend(batch_result['low_score'])
331
  all_failed_candidates.extend(batch_result['failures'])
 
 
 
332
 
333
+ if not layer2_candidates: print("โŒ No candidates found in Layer 2")
334
+
335
+ # (Sort and Filter - Unchanged)
336
  layer2_candidates.sort(key=lambda x: x.get('enhanced_final_score', 0), reverse=True)
337
  target_count = min(10, len(layer2_candidates))
338
  final_layer2_candidates = layer2_candidates[:target_count]
 
 
 
 
 
339
 
340
+ # (Layer 2.5: Advanced MC - Unchanged)
341
+ print(f"\n๐Ÿ”ฌ Layer 2.5: Running Advanced MC (GARCH+LGBM) on top {len(final_layer2_candidates)} candidates...")
342
+ advanced_mc_analyzer = ml_processor.monte_carlo_analyzer
343
  updated_candidates_for_llm = []
344
  for candidate in final_layer2_candidates:
345
  symbol = candidate.get('symbol', 'UNKNOWN')
346
  try:
 
 
347
  advanced_mc_results = await advanced_mc_analyzer.generate_1h_distribution_advanced(
348
  candidate.get('ohlcv')
349
  )
 
350
  if advanced_mc_results and advanced_mc_results.get('simulation_model') == 'Phase2_GARCH_LGBM':
 
 
351
  candidate['monte_carlo_distribution'] = advanced_mc_results
352
  candidate['monte_carlo_probability'] = advanced_mc_results.get('probability_of_gain', 0)
353
+ candidate['advanced_mc_run'] = True
354
  else:
355
+ candidate['advanced_mc_run'] = False
 
 
356
  updated_candidates_for_llm.append(candidate)
 
357
  except Exception as e:
358
+ print(f" โŒ [Advanced MC] {symbol} - Error: {e}. Using Phase 1 results.")
359
  candidate['advanced_mc_run'] = False
360
  updated_candidates_for_llm.append(candidate)
361
+ final_layer2_candidates = updated_candidates_for_llm
 
 
362
 
363
  await r2_service_global.save_candidates_async(final_layer2_candidates)
364
+ # (Printing results omitted for brevity)
365
+
366
+ # (Layer 3 - LLM)
367
+ print("\n๐Ÿง  Layer 3: LLM Service Analysis...")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
368
  for candidate in final_layer2_candidates:
369
  try:
370
+ symbol = candidate['symbol']
371
  ohlcv_data = candidate.get('ohlcv');
372
+ if not ohlcv_data: continue
373
  candidate['raw_ohlcv'] = ohlcv_data
374
+ total_candles = sum(len(data) for data in ohlcv_data.values()) if ohlcv_data else 0
375
+ if total_candles < 30: continue
 
376
 
377
+ # (Add latest market context for LLM)
378
+ candidate['sentiment_data'] = await data_manager_global.get_market_context_async()
379
 
380
  llm_analysis = await llm_service_global.get_trading_decision(candidate)
381
 
382
  if llm_analysis and llm_analysis.get('action') in ['BUY']:
383
+ # ๐Ÿ”ด --- START OF CHANGE --- ๐Ÿ”ด
384
+ # (Save the 'candidate' object, which is the full context for the Reflector)
385
+ opportunity={
386
+ 'symbol': symbol,
387
+ 'current_price': candidate.get('current_price', 0),
388
+ 'decision': llm_analysis,
389
+ 'enhanced_score': candidate.get('enhanced_final_score', 0),
390
+ 'llm_confidence': llm_analysis.get('confidence_level', 0),
391
+ 'strategy': llm_analysis.get('strategy', 'GENERIC'),
392
+ 'analysis_timestamp': datetime.now().isoformat(),
393
+ 'decision_context_data': candidate # (This is the snapshot)
394
+ }
395
+ # ๐Ÿ”ด --- END OF CHANGE --- ๐Ÿ”ด
396
  final_opportunities.append(opportunity)
397
+ print(f" โœ… {symbol}: {llm_analysis.get('action')} - Conf: {llm_analysis.get('confidence_level', 0):.2f}")
398
+ else:
399
+ action = llm_analysis.get('action', 'NO_DECISION') if llm_analysis else 'NO_RESPONSE'; print(f" โš ๏ธ {symbol}: No trade decision from LLM ({action})")
400
+ except Exception as e: print(f"โŒ Error in LLM analysis for {candidate.get('symbol')}: {e}"); traceback.print_exc(); continue
401
 
402
  if final_opportunities:
403
  final_opportunities.sort(key=lambda x: (x['llm_confidence'] + x['enhanced_score']) / 2, reverse=True)
 
 
404
 
405
+ # (Audit log saving omitted for brevity - unchanged)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
406
 
407
+ if not final_opportunities: print("โŒ No suitable trading opportunities found"); return None
408
  return final_opportunities[0] if final_opportunities else None
409
 
410
  except Exception as error:
411
+ print(f"โŒ Fatal error in 3-layer system: {error}"); traceback.print_exc()
 
 
 
 
 
412
  return None
413
 
414
  async def re_analyze_open_trade_async(trade_data):
415
+ """(Updated to pass LearningHub to MLProcessor)"""
416
  symbol = trade_data.get('symbol')
417
  try:
 
418
  async with state_manager.trade_analysis_lock:
419
+ print(f"๐Ÿ”„ [Re-Analyze] Starting strategic analysis for {symbol}...")
420
  market_context = await data_manager_global.get_market_context_async()
421
  ohlcv_data_list = []
422
  temp_queue = asyncio.Queue()
 
429
  temp_queue.task_done()
430
  except asyncio.TimeoutError:
431
  if temp_queue.empty(): break
432
+ except Exception: break
433
 
434
+ if not ohlcv_data_list: print(f"โš ๏ธ Failed to get re-analysis data for {symbol}"); return None
435
  ohlcv_data = ohlcv_data_list[0]
436
 
437
  l1_data = await data_manager_global._get_detailed_symbol_data(symbol)
 
439
 
440
  re_analysis_whale_data = await data_manager_global.get_whale_data_for_symbol(symbol)
441
 
442
+ # ๐Ÿ”ด --- START OF CHANGE --- ๐Ÿ”ด
443
+ # (Pass the global Learning Hub to the MLProcessor)
444
+ ml_processor = MLProcessor(market_context, data_manager_global, learning_hub_global)
445
+ # ๐Ÿ”ด --- END OF CHANGE --- ๐Ÿ”ด
446
 
447
+ print(f"๐Ÿ”„ [Re-Analyze] Using Advanced MC (Phase 2+3) for {symbol}...")
448
  advanced_mc_results = await ml_processor.monte_carlo_analyzer.generate_1h_distribution_advanced(
449
  ohlcv_data.get('ohlcv')
450
  )
451
 
452
  processed_data = await ml_processor.process_and_score_symbol_enhanced(ohlcv_data, {symbol: re_analysis_whale_data} if re_analysis_whale_data else {})
 
453
  if not processed_data: return None
454
 
455
  if advanced_mc_results:
 
458
 
459
  processed_data['raw_ohlcv'] = ohlcv_data.get('raw_ohlcv') or ohlcv_data.get('ohlcv')
460
  processed_data['ohlcv'] = processed_data['raw_ohlcv']
 
 
461
  processed_data['sentiment_data'] = market_context
462
 
463
  re_analysis_decision = await llm_service_global.re_analyze_trade_async(trade_data, processed_data)
464
 
465
  if re_analysis_decision:
466
  await r2_service_global.save_system_logs_async({ "trade_reanalyzed": True, "symbol": symbol, "action": re_analysis_decision.get('action'), 'strategy': re_analysis_decision.get('strategy', 'GENERIC') })
467
+ print(f"โœ… [Re-Analyze] Strategic analysis complete for {symbol}. Decision: {re_analysis_decision.get('action')}")
468
  return {"symbol": symbol, "decision": re_analysis_decision, "current_price": processed_data.get('current_price')}
469
  else: return None
470
  except Exception as error: await r2_service_global.save_system_logs_async({ "reanalysis_error": True, "symbol": symbol, "error": str(error) }); print(f"โŒ Error in re_analyze_open_trade_async for {symbol}: {error}"); traceback.print_exc(); return None
471
 
472
 
473
  async def run_bot_cycle_async():
474
+ """(Updated to pass decision_context to open_trade)"""
475
  try:
476
+ if not await state_manager.wait_for_initialization(): print("โŒ Services not fully initialized - skipping cycle"); return
477
+ print("๐Ÿ”„ Starting trading cycle..."); await r2_service_global.save_system_logs_async({"cycle_started": True})
478
+ if not r2_service_global.acquire_lock(): print("โŒ Failed to acquire lock - skipping cycle"); return
479
 
480
  open_trades = []
481
  try:
482
+ open_trades = await trade_manager_global.get_open_trades(); print(f"๐Ÿ“‹ Open trades: {len(open_trades)}")
 
483
  if open_trades:
484
  now = datetime.now()
485
  trades_to_reanalyze = [t for t in open_trades if now >= datetime.fromisoformat(t.get('expected_target_time', now.isoformat()))]
486
  if trades_to_reanalyze:
487
+ print(f"๐Ÿ”„ Re-analyzing {len(trades_to_reanalyze)} trades (using Advanced MC)")
 
 
 
488
  reanalysis_results = await asyncio.gather(*[re_analyze_open_trade_async(trade) for trade in trades_to_reanalyze], return_exceptions=True)
489
  for i, result in enumerate(reanalysis_results):
490
  trade = trades_to_reanalyze[i]
491
+ if isinstance(result, Exception): print(f" โŒ Re-analysis failed for {trade.get('symbol')}: {result}")
492
+ elif result and result['decision'].get('action') == "CLOSE_TRADE": print(f" โœ… Closing {trade.get('symbol')} based on re-analysis."); await trade_manager_global.close_trade(trade, result['current_price'], 'CLOSED_BY_REANALYSIS');
493
+ elif result and result['decision'].get('action') == "UPDATE_TRADE": print(f" โœ… Updating {trade.get('symbol')} based on re-analysis."); await trade_manager_global.update_trade(trade, result['decision'])
494
+ elif result: print(f" โ„น๏ธ Holding {trade.get('symbol')} based on re-analysis.")
495
+ else: print(f" โš ๏ธ Re-analysis for {trade.get('symbol')} yielded no decision.")
496
 
497
  current_open_trades_count = len(await trade_manager_global.get_open_trades())
498
  should_look_for_new_trade = current_open_trades_count == 0
 
500
  if should_look_for_new_trade:
501
  portfolio_state = await r2_service_global.get_portfolio_state_async(); current_capital = portfolio_state.get("current_capital_usd", 0)
502
  if current_capital > 1:
503
+ print("๐ŸŽฏ Looking for new trading opportunities (Dual-Phase MC)...")
504
  best_opportunity = await run_3_layer_analysis()
505
+
506
+ # ๐Ÿ”ด --- START OF CHANGE --- ๐Ÿ”ด
507
+ # (Pass the decision_context to open_trade for the Reflector)
508
  if best_opportunity:
509
+ print(f"โœ… Opening new trade: {best_opportunity['symbol']}")
510
+
511
+ symbol = best_opportunity['symbol']
512
+ decision = best_opportunity['decision']
513
+ price = best_opportunity['current_price']
514
+
515
+ # (Extract the snapshot saved by run_3_layer_analysis)
516
+ context_data = best_opportunity.get('decision_context_data', {})
517
+
518
+ # (Build the snapshot for the Reflector)
519
+ decision_context_snapshot = {
520
+ "market": context_data.get('sentiment_data', {}),
521
+ "indicators": context_data.get('advanced_indicators', {}),
522
+ "pattern": context_data.get('pattern_analysis', {}),
523
+ "monte_carlo": context_data.get('monte_carlo_distribution', {}),
524
+ "whale": context_data.get('whale_data', {}),
525
+ "strategy_scores": context_data.get('base_strategy_scores', {})
526
+ }
527
+
528
+ await trade_manager_global.open_trade(
529
+ symbol,
530
+ decision,
531
+ price,
532
+ decision_context=decision_context_snapshot
533
+ )
534
+ # ๐Ÿ”ด --- END OF CHANGE --- ๐Ÿ”ด
535
+ else: print("โŒ No suitable trading opportunities found")
536
+ else: print("โŒ Insufficient capital to open new trades")
537
+ else: print("โ„น๏ธ A trade is already open, skipping new trade search.")
538
  finally:
539
  if r2_service_global.lock_acquired: r2_service_global.release_lock()
540
  await r2_service_global.save_system_logs_async({ "cycle_completed": True, "open_trades": len(open_trades)})
541
+ print("โœ… Trading cycle complete")
542
 
543
  except Exception as error:
544
  print(f"โŒ Unhandled error in main cycle: {error}"); traceback.print_exc()
 
547
 
548
  @asynccontextmanager
549
  async def lifespan(application: FastAPI):
550
+ """Application lifecycle management"""
551
+ print("๐Ÿš€ Starting application initialization...")
552
  try:
553
  success = await initialize_services()
554
+ if not success: print("โŒ Application initialization failed - shutting down..."); yield; return
555
+
556
  asyncio.create_task(monitor_market_async())
 
557
  asyncio.create_task(trade_manager_global.start_trade_monitoring())
558
+
559
+ # ๐Ÿ”ด --- START OF CHANGE --- ๐Ÿ”ด
560
+ # (Start the new periodic distillation task)
561
+ asyncio.create_task(run_periodic_distillation())
562
+ # ๐Ÿ”ด --- END OF CHANGE --- ๐Ÿ”ด
563
+
564
  await r2_service_global.save_system_logs_async({"application_started": True})
565
+ print("๐ŸŽฏ Application ready - 3-Layer System (Learning Hub Enabled) is active")
566
+ print(" -> ๐Ÿ“ˆ Tactical Monitor (Dynamic Exit) is active")
567
+ print(" -> ๐Ÿง  Periodic Distillation (Curator) is scheduled")
568
  yield
569
  except Exception as error:
570
  print(f"โŒ Application startup failed: {error}");
 
576
  await cleanup_on_shutdown()
577
 
578
 
579
+ application = FastAPI(lifespan=lifespan, title="AI Trading Bot", description="Intelligent Trading System with 3-Layer Analysis and full Operational Learning Hub (Reflexion Architecture)", version="4.0.0")
580
 
581
+ # (Endpoints remain unchanged)
582
  @application.get("/")
583
+ async def root(): return {"message": "Welcome to the AI Trading System", "system": "3-Layer Analysis (Learning Hub Enabled)", "status": "running" if state_manager.initialization_complete else "initializing", "timestamp": datetime.now().isoformat()}
584
  @application.get("/run-cycle")
585
  async def run_cycle_api():
586
+ if not state_manager.initialization_complete: raise HTTPException(status_code=503, detail="Services not fully initialized")
587
  asyncio.create_task(run_bot_cycle_async())
588
+ return {"message": "Bot cycle initiated (Learning Hub Enabled)", "system": "3-Layer Analysis"}
589
  @application.get("/health")
590
+ async def health_check(): return {"status": "healthy" if state_manager.initialization_complete else "initializing", "initialization_complete": state_manager.initialization_complete, "services_initialized": state_manager.services_initialized, "initialization_error": state_manager.initialization_error, "timestamp": datetime.now().isoformat(), "system_architecture": "3-Layer Analysis (Learning Hub V4.0)"}
591
  @application.get("/analyze-market")
592
  async def analyze_market_api():
593
+ if not state_manager.initialization_complete: raise HTTPException(status_code=503, detail="Services not fully initialized")
594
  result = await run_3_layer_analysis()
595
  if result: return {"opportunity_found": True, "symbol": result['symbol'], "action": result['decision'].get('action'), "confidence": result['llm_confidence'], "strategy": result['strategy'], "exit_profile": result['decision'].get('exit_profile')}
596
  else: return {"opportunity_found": False, "message": "No suitable opportunities found"}
597
  @application.get("/portfolio")
598
  async def get_portfolio_api():
599
+ if not state_manager.initialization_complete: raise HTTPException(status_code=503, detail="Services not fully initialized")
600
  try: portfolio_state = await r2_service_global.get_portfolio_state_async(); open_trades = await trade_manager_global.get_open_trades(); return {"portfolio": portfolio_state, "open_trades": open_trades, "timestamp": datetime.now().isoformat()}
601
+ except Exception as e: raise HTTPException(status_code=500, detail=f"Error getting portfolio: {str(e)}")
602
  @application.get("/system-status")
603
  async def get_system_status(): monitoring_status = trade_manager_global.get_monitoring_status() if trade_manager_global else {}; return {"initialization_complete": state_manager.initialization_complete, "services_initialized": state_manager.services_initialized, "initialization_error": state_manager.initialization_error, "market_state_ok": state.MARKET_STATE_OK, "monitoring_status": monitoring_status, "timestamp": datetime.now().isoformat()}
604
 
605
  async def cleanup_on_shutdown():
606
+ # ๐Ÿ”ด --- START OF CHANGE --- ๐Ÿ”ด
607
+ global r2_service_global, data_manager_global, trade_manager_global, learning_hub_global
608
+ # ๐Ÿ”ด --- END OF CHANGE --- ๐Ÿ”ด
609
+
610
  print("๐Ÿ›‘ Shutdown signal received. Cleaning up...")
611
  if trade_manager_global: trade_manager_global.stop_monitoring(); print("โœ… Trade monitoring stopped")
612
+
613
+ # ๐Ÿ”ด --- START OF CHANGE --- ๐Ÿ”ด
614
+ # (Call the new hub's shutdown method)
615
+ if learning_hub_global and learning_hub_global.initialized:
616
  try:
617
+ await learning_hub_global.shutdown()
618
+ print("โœ… Learning hub data saved")
619
+ except Exception as e: print(f"โŒ Failed to save learning hub data: {e}")
620
+ # ๐Ÿ”ด --- END OF CHANGE --- ๐Ÿ”ด
621
+
622
  if data_manager_global: await data_manager_global.close(); print("โœ… Data manager closed")
623
  if r2_service_global:
624
  try: await r2_service_global.save_system_logs_async({"application_shutdown": True}); print("โœ… Shutdown log saved")
 
629
  signal.signal(signal.SIGINT, signal_handler); signal.signal(signal.SIGTERM, signal_handler)
630
 
631
  if __name__ == "__main__":
632
+ print("๐Ÿš€ Starting AI Trading Bot with 3-Layer Analysis System (Learning Hub V4.0)...")
633
  uvicorn.run( application, host="0.0.0.0", port=7860, log_level="info", access_log=True )