Riy777 commited on
Commit
9dd6d6b
·
1 Parent(s): 2270a6d

Update simulation_engine/sim_runner.py

Browse files
Files changed (1) hide show
  1. simulation_engine/sim_runner.py +49 -36
simulation_engine/sim_runner.py CHANGED
@@ -1,5 +1,5 @@
1
  # simulation_engine/sim_runner.py
2
- # Close each trade at ~1h if >= breakeven, else force close by 2h. Single concurrent position.
3
 
4
  import asyncio
5
  import os
@@ -15,33 +15,36 @@ try:
15
  from .mock_kucoin import MockKuCoin
16
  from .virtual_exchange import VirtualExchange
17
  except ImportError:
18
- print("❌ [SimRunner] Missing mock components.", flush=True)
 
 
19
 
20
  SIM_CONFIG = {
 
21
  "START_DATE": "2025-09-10",
22
  "END_DATE": "2025-11-09",
23
 
24
- # Portfolio & execution
25
  "INITIAL_BALANCE": 10.0,
26
- "FEE_RATE": 0.001,
27
 
28
- # Entry cadence & quality
29
- "STEP_TF": "5m", # قرارات كل 5 دقائق
30
- "ENTRY_THRESHOLD": 0.25, # توازن مقبول لخفض الضوضاء
31
 
32
- # Position sizing & limits
33
- "POSITION_FRACTION": 0.50, # نصف الرصيد للصفقة الواحدة
34
- "MAX_CONCURRENT_POSITIONS": 1,
35
  "MIN_TRADE_USD": 0.10,
36
 
37
- # Exits
38
- "TP_PCT": 1.2, # 1.2% هدف
39
- "SL_PCT": 0.8, # 0.8% وقف
40
- "SOFT_TIME_STOP_BARS": 12, # ≈ 1 ساعة عند STEP_TF=5m
41
- "HARD_TIME_STOP_BARS": 24, # ≈ 2 ساعة كحد أقصى
42
- "COOLDOWN_BARS": 3, # تبريد بسيط لمنع إعادة الدخول الفوري
43
 
44
- # Universe
45
  "TEST_SYMBOLS": [
46
  "BTC/USDT","ETH/USDT","SOL/USDT","BNB/USDT","XRP/USDT",
47
  "DOGE/USDT","ADA/USDT","AVAX/USDT","LINK/USDT"
@@ -55,9 +58,10 @@ TF_MS = {'5m': 300_000, '15m': 900_000, '1h': 3_600_000, '4h': 14_400_000, '1d':
55
  REQUIRED_TFS = ['5m','15m','1h','4h','1d']
56
  FETCH_LIMIT = 500
57
 
 
58
  MIN_CANDLES_BASE = {'5m':220,'15m':220,'1h':220,'4h':220,'1d':60}
59
  MIN_CANDLES_REQ = dict(MIN_CANDLES_BASE)
60
- MIN_CANDLES_REQ['1d'] = 59
61
 
62
  async def run_realistic_simulation():
63
  SIM_STATUS["running"] = True
@@ -65,21 +69,23 @@ async def run_realistic_simulation():
65
  f"🚀 Sim {SIM_CONFIG['START_DATE']} -> {SIM_CONFIG['END_DATE']} | symbols={len(SIM_CONFIG['TEST_SYMBOLS'])}\n"
66
  f"STEP_TF={SIM_CONFIG['STEP_TF']} THR={SIM_CONFIG['ENTRY_THRESHOLD']} "
67
  f"TP/SL={SIM_CONFIG['TP_PCT']}/{SIM_CONFIG['SL_PCT']} "
68
- f"SOFT/HARD={SIM_CONFIG['SOFT_TIME_STOP_BARS']}/{SIM_CONFIG['HARD_TIME_STOP_BARS']} bars",
 
69
  flush=True
70
  )
71
 
72
  r2_service = R2Service()
73
- if not os.path.exists(SIM_CONFIG["LOCAL_DATA_DIR"]):
74
- print(f"❌ Missing data dir: {SIM_CONFIG['LOCAL_DATA_DIR']}", flush=True)
 
75
  SIM_STATUS["running"] = False
76
  return
77
 
78
  print("🛠️ Bootstrapping...", flush=True)
79
- mock_exchange = MockKuCoin(SIM_CONFIG["LOCAL_DATA_DIR"])
80
  await mock_exchange.load_data(SIM_CONFIG["TEST_SYMBOLS"], REQUIRED_TFS)
81
 
82
- # Wallet with 1–2h time-stop logic
83
  step_ms = TF_MS.get(SIM_CONFIG["STEP_TF"], TF_MS['5m'])
84
  virtual_wallet = VirtualExchange(
85
  initial_balance=SIM_CONFIG["INITIAL_BALANCE"],
@@ -95,7 +101,7 @@ async def run_realistic_simulation():
95
  hard_time_stop_bars=SIM_CONFIG["HARD_TIME_STOP_BARS"],
96
  )
97
 
98
- # span detection
99
  min_ts, max_ts = None, None
100
  for sym in SIM_CONFIG["TEST_SYMBOLS"]:
101
  for tf in REQUIRED_TFS:
@@ -106,7 +112,7 @@ async def run_realistic_simulation():
106
  min_ts = mn if min_ts is None else min(min_ts, mn)
107
  max_ts = mx if max_ts is None else max(max_ts, mx)
108
  if min_ts is None or max_ts is None:
109
- print("❌ لا توجد بيانات صالحة في المخزن.", flush=True); SIM_STATUS["running"] = False; return
110
 
111
  boot_requirements_ms = []
112
  for tf in REQUIRED_TFS:
@@ -133,24 +139,26 @@ async def run_realistic_simulation():
133
 
134
  print("🧠 Initializing hybrid system...", flush=True)
135
  data_manager = DataManager(None, None, r2_service=r2_service, mock_exchange=mock_exchange)
136
- learning_hub = LearningHubManager(r2_service, None, data_manager, disable_llm=True)
137
  await learning_hub.initialize()
138
  processor = MLProcessor(None, data_manager, learning_hub)
139
  await processor.initialize()
140
 
 
141
  setattr(data_manager, 'HYBRID_ENTRY_THRESHOLD', float(SIM_CONFIG["ENTRY_THRESHOLD"]))
142
  print(f"✅ Ready. Threshold={getattr(data_manager, 'HYBRID_ENTRY_THRESHOLD', 'NA')}", flush=True)
143
 
 
144
  timeline = range(safe_start_ts, safe_end_ts, step_ms)
145
  total = len(timeline)
146
  bar = tqdm(timeline, desc="Simulating", unit="step")
147
 
148
- def log(msg):
149
  try: bar.write(msg)
150
  except Exception: print(msg, flush=True)
151
 
152
- # loop
153
  for i, ts in enumerate(bar):
 
154
  mock_exchange.set_time(ts)
155
 
156
  if i % 10 == 0:
@@ -158,17 +166,17 @@ async def run_realistic_simulation():
158
  SIM_STATUS["current_balance"] = virtual_wallet.get_balance()
159
  SIM_STATUS["trades_count"] = len(virtual_wallet.trade_history)
160
 
161
- # update open positions
162
  prices = {s:(await mock_exchange.fetch_ticker(s))['last'] for s in SIM_CONFIG["TEST_SYMBOLS"]}
163
  closed = virtual_wallet.update_positions(prices, ts)
164
  for tr in closed:
165
  log(f"[CLOSE] {tr['symbol']} reason={tr['close_reason']} pnl={tr['pnl_percent']:.2f}%")
166
  await learning_hub.analyze_trade_and_learn(tr, tr['close_reason'])
167
 
168
- # try entries (respect single concurrent position)
169
  if virtual_wallet.open_positions_count() < SIM_CONFIG["MAX_CONCURRENT_POSITIONS"]:
170
  for symbol in SIM_CONFIG["TEST_SYMBOLS"]:
171
- # availability check
172
  enough = True
173
  for tf in REQUIRED_TFS:
174
  candles = await mock_exchange.fetch_ohlcv(symbol, tf, limit=FETCH_LIMIT)
@@ -178,19 +186,24 @@ async def run_realistic_simulation():
178
  continue
179
 
180
  packet = {tf: await mock_exchange.fetch_ohlcv(symbol, tf, limit=FETCH_LIMIT) for tf in REQUIRED_TFS}
181
- res = await processor.process_and_score_symbol_enhanced({'symbol':symbol,'ohlcv':packet,'current_price':prices.get(symbol,0.0)})
 
 
 
182
  if not res:
183
  continue
184
 
185
  final_s = float(res['enhanced_final_score'])
186
  thr = getattr(data_manager, 'HYBRID_ENTRY_THRESHOLD', 0.75)
187
- log(f"[SCORE] {symbol} final={final_s:.3f} thr={thr:.3f} comps={dict(res.get('components',{}), final_score=final_s)}")
 
 
188
  if final_s >= thr and virtual_wallet.can_enter(symbol, ts):
189
- if virtual_wallet.execute_buy(symbol, res['current_price'], ts, {'final_score': final_s}):
190
- log(f"[BUY] {symbol} @ {res['current_price']} bal=${virtual_wallet.get_balance():.2f}")
191
  break # نحافظ على صفقة واحدة فقط
192
 
193
- # flush
194
  print("\n🏁 نهاية فترة المحاكاة. إغلاق الصفقات المتبقية...", flush=True)
195
  final_ts = safe_end_ts
196
  mock_exchange.set_time(final_ts)
 
1
  # simulation_engine/sim_runner.py
2
+ # V3.0 Balanced-Fast: more trades, better expectancy, single-position, 1–2h time stops.
3
 
4
  import asyncio
5
  import os
 
15
  from .mock_kucoin import MockKuCoin
16
  from .virtual_exchange import VirtualExchange
17
  except ImportError:
18
+ # إذا كانت البنية مختلفة، حدّث المسارات حسب مشروعك
19
+ from simulation_engine.mock_kucoin import MockKuCoin
20
+ from simulation_engine.virtual_exchange import VirtualExchange
21
 
22
  SIM_CONFIG = {
23
+ # نافذة الاختبار
24
  "START_DATE": "2025-09-10",
25
  "END_DATE": "2025-11-09",
26
 
27
+ # المحفظة والتنفيذ
28
  "INITIAL_BALANCE": 10.0,
29
+ "FEE_RATE": 0.001, # 0.1%
30
 
31
+ # سرعة القرار وجودته
32
+ "STEP_TF": "5m", # قرار كل 5 دقائق
33
+ "ENTRY_THRESHOLD": 0.22, # عتبة دخول متوازنة لرفع العدد دون ضوضاء مفرطة
34
 
35
+ # حجم الصفقة والقيود
36
+ "POSITION_FRACTION": 0.45, # 45% من الرصيد لكل صفقة
37
+ "MAX_CONCURRENT_POSITIONS": 1, # صفقة واحدة في نفس الوقت
38
  "MIN_TRADE_USD": 0.10,
39
 
40
+ # الخروج: هدف/وقف + إيقاف زمني مرن
41
+ "TP_PCT": 1.6, # 1.6%
42
+ "SL_PCT": 0.8, # 0.8%
43
+ "SOFT_TIME_STOP_BARS": 12, # ≈ 1 ساعة عند STEP_TF=5m: يغلق عند التعادل أو أفضل
44
+ "HARD_TIME_STOP_BARS": 24, # ≈ 2 ساعة: إغلاق قسري
45
+ "COOLDOWN_BARS": 1, # تبريد قصير لمنع إعادة الدخول الفوري
46
 
47
+ # الكون
48
  "TEST_SYMBOLS": [
49
  "BTC/USDT","ETH/USDT","SOL/USDT","BNB/USDT","XRP/USDT",
50
  "DOGE/USDT","ADA/USDT","AVAX/USDT","LINK/USDT"
 
58
  REQUIRED_TFS = ['5m','15m','1h','4h','1d']
59
  FETCH_LIMIT = 500
60
 
61
+ # الحد الأدنى للشموع المطلوبة لكل إطار
62
  MIN_CANDLES_BASE = {'5m':220,'15m':220,'1h':220,'4h':220,'1d':60}
63
  MIN_CANDLES_REQ = dict(MIN_CANDLES_BASE)
64
+ MIN_CANDLES_REQ['1d'] = 59 # مرونة بسيطة لبدء المحاكاة
65
 
66
  async def run_realistic_simulation():
67
  SIM_STATUS["running"] = True
 
69
  f"🚀 Sim {SIM_CONFIG['START_DATE']} -> {SIM_CONFIG['END_DATE']} | symbols={len(SIM_CONFIG['TEST_SYMBOLS'])}\n"
70
  f"STEP_TF={SIM_CONFIG['STEP_TF']} THR={SIM_CONFIG['ENTRY_THRESHOLD']} "
71
  f"TP/SL={SIM_CONFIG['TP_PCT']}/{SIM_CONFIG['SL_PCT']} "
72
+ f"SOFT/HARD={SIM_CONFIG['SOFT_TIME_STOP_BARS']}/{SIM_CONFIG['HARD_TIME_STOP_BARS']} bars "
73
+ f"| COOLDOWN={SIM_CONFIG['COOLDOWN_BARS']} | POS_FRAC={SIM_CONFIG['POSITION_FRACTION']}",
74
  flush=True
75
  )
76
 
77
  r2_service = R2Service()
78
+ data_dir = SIM_CONFIG["LOCAL_DATA_DIR"]
79
+ if not os.path.exists(data_dir):
80
+ print(f"❌ Missing data dir: {data_dir}", flush=True)
81
  SIM_STATUS["running"] = False
82
  return
83
 
84
  print("🛠️ Bootstrapping...", flush=True)
85
+ mock_exchange = MockKuCoin(data_dir)
86
  await mock_exchange.load_data(SIM_CONFIG["TEST_SYMBOLS"], REQUIRED_TFS)
87
 
88
+ # إنشاء المحفظة بمنطق الإيقاف الزمني المرن
89
  step_ms = TF_MS.get(SIM_CONFIG["STEP_TF"], TF_MS['5m'])
90
  virtual_wallet = VirtualExchange(
91
  initial_balance=SIM_CONFIG["INITIAL_BALANCE"],
 
101
  hard_time_stop_bars=SIM_CONFIG["HARD_TIME_STOP_BARS"],
102
  )
103
 
104
+ # تحديد مجال الزمن الآمن
105
  min_ts, max_ts = None, None
106
  for sym in SIM_CONFIG["TEST_SYMBOLS"]:
107
  for tf in REQUIRED_TFS:
 
112
  min_ts = mn if min_ts is None else min(min_ts, mn)
113
  max_ts = mx if max_ts is None else max(max_ts, mx)
114
  if min_ts is None or max_ts is None:
115
+ print("❌ لا توجد بيانات صالحة.", flush=True); SIM_STATUS["running"] = False; return
116
 
117
  boot_requirements_ms = []
118
  for tf in REQUIRED_TFS:
 
139
 
140
  print("🧠 Initializing hybrid system...", flush=True)
141
  data_manager = DataManager(None, None, r2_service=r2_service, mock_exchange=mock_exchange)
142
+ learning_hub = LearningHubManager(r2_service, None, data_manager, disable_llm=True) # NO_LLM
143
  await learning_hub.initialize()
144
  processor = MLProcessor(None, data_manager, learning_hub)
145
  await processor.initialize()
146
 
147
+ # تمرير عتبة الدخول للنظام الهجين
148
  setattr(data_manager, 'HYBRID_ENTRY_THRESHOLD', float(SIM_CONFIG["ENTRY_THRESHOLD"]))
149
  print(f"✅ Ready. Threshold={getattr(data_manager, 'HYBRID_ENTRY_THRESHOLD', 'NA')}", flush=True)
150
 
151
+ # حلقة المحاكاة
152
  timeline = range(safe_start_ts, safe_end_ts, step_ms)
153
  total = len(timeline)
154
  bar = tqdm(timeline, desc="Simulating", unit="step")
155
 
156
+ def log(msg):
157
  try: bar.write(msg)
158
  except Exception: print(msg, flush=True)
159
 
 
160
  for i, ts in enumerate(bar):
161
+ # تحديث الوقت
162
  mock_exchange.set_time(ts)
163
 
164
  if i % 10 == 0:
 
166
  SIM_STATUS["current_balance"] = virtual_wallet.get_balance()
167
  SIM_STATUS["trades_count"] = len(virtual_wallet.trade_history)
168
 
169
+ # إغلاقات قائمة (TP/SL/Soft/Hard)
170
  prices = {s:(await mock_exchange.fetch_ticker(s))['last'] for s in SIM_CONFIG["TEST_SYMBOLS"]}
171
  closed = virtual_wallet.update_positions(prices, ts)
172
  for tr in closed:
173
  log(f"[CLOSE] {tr['symbol']} reason={tr['close_reason']} pnl={tr['pnl_percent']:.2f}%")
174
  await learning_hub.analyze_trade_and_learn(tr, tr['close_reason'])
175
 
176
+ # فتح مركز جديد إن لم توجد صفقات مفتوحة
177
  if virtual_wallet.open_positions_count() < SIM_CONFIG["MAX_CONCURRENT_POSITIONS"]:
178
  for symbol in SIM_CONFIG["TEST_SYMBOLS"]:
179
+ # تحقق توافر حزمة الفريمات
180
  enough = True
181
  for tf in REQUIRED_TFS:
182
  candles = await mock_exchange.fetch_ohlcv(symbol, tf, limit=FETCH_LIMIT)
 
186
  continue
187
 
188
  packet = {tf: await mock_exchange.fetch_ohlcv(symbol, tf, limit=FETCH_LIMIT) for tf in REQUIRED_TFS}
189
+ cur_price = prices.get(symbol, 0.0)
190
+ res = await processor.process_and_score_symbol_enhanced({
191
+ 'symbol': symbol, 'ohlcv': packet, 'current_price': cur_price
192
+ })
193
  if not res:
194
  continue
195
 
196
  final_s = float(res['enhanced_final_score'])
197
  thr = getattr(data_manager, 'HYBRID_ENTRY_THRESHOLD', 0.75)
198
+ comps = dict(res.get('components', {})); comps['final_score'] = final_s
199
+ log(f"[SCORE] {symbol} final={final_s:.3f} thr={thr:.3f} comps={comps}")
200
+
201
  if final_s >= thr and virtual_wallet.can_enter(symbol, ts):
202
+ if virtual_wallet.execute_buy(symbol, cur_price, ts, comps):
203
+ log(f"[BUY] {symbol} @ {cur_price} bal=${virtual_wallet.get_balance():.2f}")
204
  break # نحافظ على صفقة واحدة فقط
205
 
206
+ # إغلاق ما تبقى عند نهاية النافذة
207
  print("\n🏁 نهاية فترة المحاكاة. إغلاق الصفقات المتبقية...", flush=True)
208
  final_ts = safe_end_ts
209
  mock_exchange.set_time(final_ts)