Elizesel commited on
Commit
ef3b2ac
·
verified ·
1 Parent(s): 0a1c330

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +1 -1175
app.py CHANGED
@@ -1,1175 +1 @@
1
- #!/usr/bin/env python3
2
- """
3
- ICT Trading Bot - Версия 5.0 (ПОЛНАЯ)
4
- - Полные пояснения по ATR, FVG, волатильности
5
- - Логика London → NY (модели Нью-Йорка)
6
- - Фильтр мусорных сигналов (no trade day)
7
- - Нормальный вход по FVG
8
- - Нормальный RR (TP1/2/3)
9
- - Два сигнала: INFO + STRONG
10
- - Сопровождение сделки
11
- """
12
-
13
- import os
14
- import sys
15
- import json
16
- import time
17
- import ccxt
18
- import pandas as pd
19
- import numpy as np
20
- import requests
21
- from datetime import datetime
22
-
23
- # =====================
24
- # 1. КОНФИГУРАЦИЯ
25
- # =====================
26
- TOKEN = "7715180236:AAH52V597ZRZ-BQl4RCZH3AiixDH0E6pSLw"
27
- CHAT_ID = "-1003125714543"
28
-
29
- if not TOKEN or not CHAT_ID:
30
- print("❌ TELEGRAM_TOKEN или CHAT_ID не заданы!")
31
- sys.exit(1)
32
-
33
- BASE_SYMBOL = "BTC/USDT"
34
- CONFIRM_SYMBOL = "ETH/USDT"
35
- STATE_FILE = "state.json"
36
- SIGNAL_FILE = "last_signal.json"
37
-
38
- # Настройки фильтров
39
- NO_TRADE_DAYS = [0, 6] # 0 = понедельник, 6 = воскресенье (не торгуем)
40
- MIN_ATR_PERCENT = 0.5 # Минимальная волатильность 0.5%
41
- MIN_RATIO = 1.5 # Минимальное соотношение риск/прибыль
42
-
43
- # =====================
44
- # 2. РАБОТА С СОСТОЯНИЕМ
45
- # =====================
46
- def load_state():
47
- try:
48
- with open(STATE_FILE, "r") as f:
49
- return json.load(f)
50
- except:
51
- return {
52
- "active": False,
53
- "direction": None,
54
- "entry": None,
55
- "sl": None,
56
- "tp1": None,
57
- "tp2": None,
58
- "tp3": None,
59
- "entered": False,
60
- "tp1_hit": False,
61
- "tp2_hit": False,
62
- "tp3_hit": False,
63
- "sl_hit": False,
64
- "wins": 0,
65
- "losses": 0
66
- }
67
-
68
- def save_state(state):
69
- with open(STATE_FILE, "w") as f:
70
- json.dump(state, f, indent=4)
71
-
72
- def load_last_signal():
73
- try:
74
- with open(SIGNAL_FILE, "r") as f:
75
- return json.load(f)
76
- except:
77
- return {
78
- "timestamp": None,
79
- "direction": None,
80
- "h4_bias": None,
81
- "h1_zone": None,
82
- "candle_time": None
83
- }
84
-
85
- def save_last_signal(signal):
86
- with open(SIGNAL_FILE, "w") as f:
87
- json.dump(signal, f, indent=4)
88
-
89
- def is_new_signal(current_signal, last_signal):
90
- if last_signal["direction"] is None:
91
- return True
92
- if current_signal["direction"] != last_signal["direction"]:
93
- return True
94
- if current_signal["h4_bias"] != last_signal["h4_bias"]:
95
- return True
96
- if current_signal["h1_zone"] != last_signal["h1_zone"]:
97
- return True
98
- return False
99
-
100
- def stats_text(state):
101
- total = state["wins"] + state["losses"]
102
- if total == 0:
103
- return "📊 Winrate: 0% (0/0)"
104
- wr = state["wins"] / total * 100
105
- return f"📊 Winrate: {wr:.1f}% ({state['wins']}/{total})"
106
-
107
- # =====================
108
- # 3. TELEGRAM
109
- # =====================
110
- def send_telegram(msg, retry=3):
111
- for attempt in range(retry):
112
- try:
113
- r = requests.post(
114
- f"https://api.telegram.org/bot{TOKEN}/sendMessage",
115
- json={"chat_id": CHAT_ID, "text": msg, "parse_mode": "HTML"},
116
- timeout=30
117
- )
118
- if r.status_code == 200:
119
- print("✅ Отправлено")
120
- return True
121
- else:
122
- print(f"❌ Ошибка: {r.text}")
123
- except Exception as e:
124
- print(f"❌ Попытка {attempt+1}/{retry} не удалась: {e}")
125
- if attempt < retry - 1:
126
- time.sleep(5)
127
- return False
128
-
129
- # =====================
130
- # 4. ФИЛЬТРЫ И ЛОГИКА ДНЯ
131
- # =====================
132
-
133
- def get_day_name(weekday):
134
- days = ["понедельник", "вторник", "среда", "четверг", "пятница", "суббота", "воскресенье"]
135
- return days[weekday]
136
-
137
- def is_trade_day():
138
- """Проверяем, можно ли сегодня торговать"""
139
- today = datetime.utcnow().weekday()
140
- if today in NO_TRADE_DAYS:
141
- return False, f"📅 Сегодня {get_day_name(today)} - день без торгов (низкая ликвидность)"
142
- return True, f"📅 Сегодня {get_day_name(today)} - торгуем"
143
-
144
- def get_london_direction(df_m5):
145
- """
146
- Определяем направление СЕГОДНЯШНЕЙ Лондонской сессии (06:00-12:00 UTC)
147
- """
148
- today = datetime.utcnow().date()
149
-
150
- # Ищем свечи только за сегодня с 06:00 до 12:00
151
- london_bars = []
152
- for i, ts in enumerate(df_m5['ts']):
153
- if ts.date() == today and 6 <= ts.hour < 12:
154
- london_bars.append(i)
155
-
156
- if len(london_bars) < 10:
157
- return "range", "сег��дня Лондон ещё не начался или мало данных"
158
-
159
- first_idx = london_bars[0]
160
- last_idx = london_bars[-1]
161
-
162
- london_open = df_m5['o'].iloc[first_idx]
163
- london_close = df_m5['c'].iloc[last_idx]
164
- change_percent = ((london_close - london_open) / london_open) * 100
165
-
166
- if london_close > london_open * 1.002:
167
- return "bullish", f"📈 Лондон БЫЧИЙ (+{change_percent:.2f}%)"
168
- elif london_close < london_open * 0.998:
169
- return "bearish", f"📉 Лондон МЕДВЕЖИЙ ({change_percent:.2f}%)"
170
- else:
171
- return "range", f"📊 Лондон в РЕЙНДЖЕ ({change_percent:.2f}%)"
172
-
173
- def get_ny_model(london_direction, df_m5):
174
- """
175
- Модель Нью-Йорка на основе СЕГОДНЯШНЕГО направления Лондона
176
- """
177
- today = datetime.utcnow().date()
178
-
179
- # Находим свечу открытия Нью-Йорка (12:00 UTC) за сегодня
180
- ny_open = None
181
- ny_open_price = None
182
- for i, ts in enumerate(df_m5['ts']):
183
- if ts.date() == today and ts.hour == 12 and ts.minute == 0:
184
- ny_open = i
185
- ny_open_price = df_m5['o'].iloc[i]
186
- break
187
-
188
- if ny_open is None:
189
- return "нет данных (NY ещё не открылся)", "⚠️"
190
-
191
- current_price = df_m5['c'].iloc[-1]
192
- price_change = (current_price - ny_open_price) / ny_open_price * 100
193
-
194
- if london_direction == "bullish":
195
- if price_change > 0:
196
- return "Модель 1: Лондон вверх → NY продолжает", "✅"
197
- else:
198
- return "Модель 2: Лондон вверх → NY разворачивается", "⚠️"
199
-
200
- elif london_direction == "bearish":
201
- if price_change < 0:
202
- return "Модель 1: Лондон вниз → NY продолжает", "✅"
203
- else:
204
- return "Модель 2: Лондон вниз → NY разворачивается", "⚠️"
205
-
206
- else:
207
- return "Лондон в диапазоне → ждём импульса NY", "📊"
208
-
209
- def is_quality_signal(direction, atr, current_price, h4_bias, h1_zone, london_direction):
210
- """
211
- Проверяем качество сигнала (только для ИНФО, НЕ БЛОКИРУЕТ сигнал)
212
- """
213
- reasons = []
214
- atr_percent = (atr / current_price) * 100
215
-
216
- # 1. ATR проверка
217
- if atr_percent < MIN_ATR_PERCENT:
218
- reasons.append(f"❌ ATR = {atr_percent:.2f}% (мин. {MIN_ATR_PERCENT}%) → волатильности нет")
219
-
220
- # 2. H1 зона
221
- if direction == "bullish" and h1_zone != "дискаунт":
222
- reasons.append(f"❌ Цена в {h1_zone.upper()} → покупать дорого (нужен DISCOUNT)")
223
- if direction == "bearish" and h1_zone != "премиум":
224
- reasons.append(f"❌ Цена в {h1_zone.upper()} → продавать дёшево (нужен PREMIUM)")
225
-
226
- # 3. Лондонское направление
227
- if london_direction != "range" and london_direction != direction:
228
- reasons.append(f"⚠️ Лондон был {london_direction.upper()}, а сигнал {direction.upper()} → возможен разворот")
229
-
230
- if reasons:
231
- return False, reasons
232
- return True, []
233
-
234
- # =====================
235
- # 5. ПОЯСНЕНИЯ
236
- # =====================
237
-
238
- def explain_atr(atr_value, current_price, direction):
239
- """Объяснение ATR"""
240
- volatility_pct = (atr_value / current_price) * 100
241
-
242
- if volatility_pct < 0.5:
243
- level = "🟢 ОЧЕНЬ НИЗКАЯ"
244
- comment = "Рынок спит, лучше не входить"
245
- color = "🟢"
246
- elif volatility_pct < 1.0:
247
- level = "🟡 НИЗКАЯ"
248
- comment = "Спреды узкие, движение вялое"
249
- color = "🟡"
250
- elif volatility_pct < 2.0:
251
- level = "🟠 СРЕДНЯЯ"
252
- comment = "Нормальный рынок, стопы комфортные"
253
- color = "🟠"
254
- else:
255
- level = "🔴 ВЫСОКАЯ"
256
- comment = "Осторожно! Возможны резкие движения"
257
- color = "🔴"
258
-
259
- return f"""
260
- {color} <b>ATR (Средний истинный диапазон) = ${atr_value:.0f}</b>
261
- ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
262
- ┌─ 📊 Волатильность: {volatility_pct:.2f}% ({level})
263
- ├─ 💡 {comment}
264
- └─ 📏 1 ATR = {volatility_pct:.2f}% от цены
265
-
266
- <b>Как используются уровни ATR:</b>
267
- 🛑 SL = 1x ATR → {volatility_pct:.2f}%
268
- 🎯 TP1 = 1.5x ATR → {volatility_pct*1.5:.2f}% (RR 1:1.5)
269
- 🎯 TP2 = 2.5x ATR → {volatility_pct*2.5:.2f}% (RR 1:2.5)
270
- 🎯 TP3 = 3.5x ATR → {volatility_pct*3.5:.2f}% (RR 1:3.5)
271
-
272
- <b>Что означает ATR = ${atr_value:.0f}:</b>
273
- → За последние 14 свечей цена проходила в среднем ${atr_value:.0f}
274
- → Если ATR растёт → волатильность увеличивается
275
- → Если ATR падает → рынок затихает перед импульсом
276
- """
277
-
278
- def explain_fvg(fvg_zone, direction, current_price):
279
- """Объяснение FVG"""
280
- if direction == "bullish":
281
- zone_type = "🟢 БЫЧИЙ FVG (Fair Value Gap)"
282
- explanation = """Цена резко пошла ВВЕРХ, оставив ценовой разрыв.
283
- Это зона, куда обычно возвращается цена перед продолжением движения.
284
- Вход в LONG происходит при возврате в эту зону."""
285
- action = "Ждём возврат цены в зону FVG для входа LONG"
286
- else:
287
- zone_type = "🔴 МЕДВЕЖИЙ FVG (Fair Value Gap)"
288
- explanation = """Цена резко пошла ВНИЗ, оставив ценовой разрыв.
289
- Это зона, куда обычно возвращается цена перед продолжением движения.
290
- Вход в SHORT происходит при возврате в эту зону."""
291
- action = "Ждём возврат цены в зону FVG для входа SHORT"
292
-
293
- distance = abs(fvg_zone[1] - current_price)
294
-
295
- return f"""
296
- {zone_type}
297
- ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
298
- ┌─ 📍 Верхняя граница: <b>${fvg_zone[1]:.0f}</b>
299
- ├─ 📍 Нижняя граница: <b>${fvg_zone[0]:.0f}</b>
300
- └─ 📏 Размер зоны: <b>${fvg_zone[1] - fvg_zone[0]:.0f}</b>
301
-
302
- <b>📖 Что такое FVG:</b>
303
- {explanation}
304
-
305
- <b>🎯 План входа:</b>
306
- {action}
307
- • Текущая цена: ${current_price:.0f}
308
- • Расстояние до зоны: ${distance:.0f}
309
- """
310
-
311
- def explain_entry_logic(direction, current_price, atr, sl, tp1, tp2, tp3):
312
- """Объяснение логики входа"""
313
- risk_pct = (abs(current_price - sl) / current_price) * 100
314
- reward1_pct = (abs(tp1 - current_price) / current_price) * 100
315
- reward3_pct = (abs(tp3 - current_price) / current_price) * 100
316
-
317
- if direction == "bullish":
318
- return f"""
319
- <b>🎯 ЛОГИКА ВХОДА LONG (покупка)</b>
320
- ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
321
-
322
- <b>📋 Условия входа (ICT концепции):</b>
323
- 1️⃣ <b>CHoCH</b> (Change of Character) - смена структуры
324
- └── Цена пробила предыдущий High → тренд развернулся вверх
325
-
326
- 2️⃣ <b>MSS</b> (Market Structure Shift) - подтверждение разворота
327
- └── Сформирован новый Higher High и Higher Low
328
-
329
- 3️⃣ <b>FVG</b> (Fair Value Gap) - ценовой разрыв
330
- └── Ожидаем возврат цены в зону FVG для входа
331
-
332
- <b>💰 Уровни сделки:</b>
333
- 🟢 ENTRY (вход): ${current_price:.0f}
334
- 🔴 SL (стоп-лосс): ${sl:.0f} (риск {risk_pct:.2f}%)
335
-
336
- 🎯 TP1: ${tp1:.0f} (+{reward1_pct:.2f}%) → закрыть 50%
337
- 🎯 TP2: ${tp2:.0f} (+{reward1_pct*1.67:.2f}%) → закрыть 30%
338
- 🎯 TP3: ${tp3:.0f} (+{reward3_pct:.2f}%) → закрыть 20%
339
-
340
- <b>📐 Соотношение риск/прибыль:</b>
341
- • TP1: 1 : {reward1_pct/risk_pct:.1f}
342
- • TP3: 1 : {reward3_pct/risk_pct:.1f}
343
- """
344
- else:
345
- return f"""
346
- <b>🎯 ЛОГИКА ВХОДА SHORT (продажа)</b>
347
- ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
348
-
349
- <b>📋 Условия входа (ICT концепции):</b>
350
- 1️⃣ <b>CHoCH</b> (Change of Character) - смена структуры
351
- └── Цена пробила предыдущий Low → тренд развернулся вниз
352
-
353
- 2️⃣ <b>MSS</b> (Market Structure Shift) - подтверждение разворота
354
- └── Сформирован новый Lower Low и Lower High
355
-
356
- 3️⃣ <b>FVG</b> (Fair Value Gap) - ценовой разрыв
357
- └── Ожидаем возврат цены в зону FVG для входа
358
-
359
- <b>💰 Уровни сделки:</b>
360
- 🟢 ENTRY (вход): ${current_price:.0f}
361
- 🔴 SL (стоп-лосс): ${sl:.0f} (риск {risk_pct:.2f}%)
362
-
363
- 🎯 TP1: ${tp1:.0f} (-{reward1_pct:.2f}%) → закрыть 50%
364
- 🎯 TP2: ${tp2:.0f} (-{reward1_pct*1.67:.2f}%) → закрыть 30%
365
- 🎯 TP3: ${tp3:.0f} (-{reward3_pct:.2f}%) → закрыть 20%
366
-
367
- <b>📐 Соотношение риск/прибыль:</b>
368
- • TP1: 1 : {reward1_pct/risk_pct:.1f}
369
- • TP3: 1 : {reward3_pct/risk_pct:.1f}
370
- """
371
-
372
- def explain_signal_strength(direction, h4_bias, h1_zone, h4_bias_str):
373
- """Объяснение силы ��игнала"""
374
- if direction == "bullish":
375
- ideal_h4 = "bullish"
376
- ideal_h1 = "дискаунт"
377
- h4_ok = h4_bias == ideal_h4
378
- h1_ok = h1_zone == ideal_h1
379
- else:
380
- ideal_h4 = "bearish"
381
- ideal_h1 = "премиум"
382
- h4_ok = h4_bias == ideal_h4
383
- h1_ok = h1_zone == ideal_h1
384
-
385
- text = f"""
386
- <b>🔍 АНАЛИЗ СИЛЫ СИГНАЛА (H4 + H1)</b>
387
- ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
388
-
389
- <b>📊 H4 (4-часовой таймфрейм) - тренд:</b>
390
- └── Текущий bias: <b>{h4_bias_str}</b>
391
- └── Идеал для {direction.upper()}: <b>{ideal_h4.upper()}</b>
392
- └── Статус: {'✅ СОВПАДАЕТ' if h4_ok else '❌ НЕ СОВПАДАЕТ'}
393
-
394
- <b>📍 H1 (1-часовой таймфрейм) - зона:</b>
395
- └── Текущая зона: <b>{h1_zone.upper()}</b>
396
- └── Идеал для {direction.upper()}: <b>{ideal_h1.upper()}</b>
397
- └── Статус: {'✅ СОВПАДАЕТ' if h1_ok else '❌ НЕ СОВПАДАЕТ'}
398
-
399
- <b>📌 ВЕРДИКТ:</b>
400
- """
401
- if h4_ok and h1_ok:
402
- text += """
403
- 🟢 <b>СИЛЬНЫЙ СИГНАЛ (STRONG)</b>
404
- ✅ H4 показывает правильный тренд
405
- ✅ H1 даёт хорошую цену для входа
406
- 🔥 Вероятность успеха - ВЫСОКАЯ
407
- 📈 Рекомендуемый риск: 1-2% депозита
408
- """
409
- elif h4_ok:
410
- text += """
411
- 🟡 <b>СРЕДНИЙ СИГНАЛ (MEDIUM)</b>
412
- ✅ H4 подтверждает направление
413
- ⚠️ H1 зона не идеальна
414
- 📊 Вероятность успеха - СРЕДНЯЯ
415
- 📉 Рекомендуемый риск: 0.5-1% депозита
416
- """
417
- elif h1_ok:
418
- text += """
419
- 🟡 <b>СРЕДНИЙ СИГНАЛ (MEDIUM)</b>
420
- ✅ H1 даёт хорошую цену
421
- ⚠️ H4 не подтверждает тренд
422
- 📊 Вероятность успеха - СРЕДНЯЯ
423
- 📉 Рекомендуемый риск: 0.5-1% депозита
424
- """
425
- else:
426
- text += """
427
- 🔴 <b>СЛАБЫЙ СИГНАЛ (WEAK)</b>
428
- ❌ Ни H4, ни H1 не подтверждают
429
- ⚠️ Лучше пропустить сделку
430
- 📊 Вероятность успеха - НИЗКАЯ
431
- 💡 Или использовать риск 0.25-0.5%
432
- """
433
- return text
434
-
435
- def explain_session(session):
436
- """Объяснение сессии"""
437
- sessions = {
438
- "АЗИЯ": {
439
- "hours": "00:00 - 06:00 UTC",
440
- "chars": "🐉 Низкая волатильность, диапазон, ложные пробои",
441
- "best_for": "Набор позиций, свинги, осторожная торговля",
442
- "ict": "Азиатская сессия - обычно не используется для ICT"
443
- },
444
- "ЛОНДОН": {
445
- "hours": "06:00 - 12:00 UTC",
446
- "chars": "🇬🇧 Высокая волатильность, трендовое движение",
447
- "best_for": "Лучшее время для ICT стратегий, начало движения",
448
- "ict": "Ключевая сессия для определения направления дня"
449
- },
450
- "НЬЮ-ЙОРК AM": {
451
- "hours": "12:00 - 18:00 UTC",
452
- "chars": "🇺🇸 Очень высокая волатильность, мощные движения",
453
- "best_for": "Продолжение или разворот Лондона, лучшие сигналы",
454
- "ict": "Самая важная сессия, пересечение с Лондоном"
455
- },
456
- "НЬЮ-ЙОРК PM": {
457
- "hours": "18:00 - 00:00 UTC",
458
- "chars": "🌙 Затишье, коррекции, закрытие позиций",
459
- "best_for": "Закрытие позиций, не входить в новые",
460
- "ict": "Пост-сессия, низкая ликвидность"
461
- }
462
- }
463
- s = sessions.get(session, sessions["АЗИЯ"])
464
- return f"""
465
- 🌍 <b>ТОРГОВАЯ СЕССИЯ: {session}</b>
466
- ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
467
- ┌─ ⏰ Время: {s['hours']}
468
- ├─ 📊 Характер: {s['chars']}
469
- ├─ 🎯 Лучше всего для: {s['best_for']}
470
- └─ 📖 ICT: {s['ict']}
471
- """
472
-
473
- def explain_risk_management(atr, current_price, direction, sl, tp1, tp3):
474
- """Объяснение риск-менеджмента"""
475
- risk_amount = (abs(current_price - sl) / current_price) * 100
476
- reward_tp1 = (abs(tp1 - current_price) / current_price) * 100
477
- reward_tp3 = (abs(tp3 - current_price) / current_price) * 100
478
-
479
- text = f"""
480
- <b>💰 РИСК-МЕНЕДЖМЕНТ</b>
481
- ━━━━━━━━━━━━━━━━━━━━━━━��━━━━━━━
482
-
483
- ┌─ 📉 Риск на сделку: <b>{risk_amount:.2f}%</b> депозита
484
- ├─ 📈 Потенциал TP1: <b>+{reward_tp1:.2f}%</b>
485
- ├─ 📈 Потенциал TP3: <b>+{reward_tp3:.2f}%</b>
486
- ├─ 📐 RR TP1: <b>1 : {reward_tp1/risk_amount:.1f}</b>
487
- └─ 📐 RR TP3: <b>1 : {reward_tp3/risk_amount:.1f}</b>
488
-
489
- <b>💡 Пример для депозита $1000:</b>
490
- • Риск 1% = $10
491
- • Объём позиции = $10 / ${abs(current_price - sl):.0f} = {10/abs(current_price - sl):.5f} BTC
492
- • TP1 даст +${reward_tp1/100 * 1000:.0f}
493
- • TP3 даст +${reward_tp3/100 * 1000:.0f}
494
-
495
- <b>⚠️ ВАЖНЫЕ ПРАВИЛА:</b>
496
- 1. Никогда не рискуйте больше 2% депозита
497
- 2. Соблюдайте соотношение RR не менее 1:1.5
498
- 3. Используйте частичное закрытие (50/30/20)
499
- 4. Передвигайте SL в безубыток после TP1
500
- """
501
- return text
502
-
503
- def explain_london_ny(london_direction, london_text, ny_model, ny_status):
504
- """Объяснение логики Лондон → Нью-Йорк"""
505
- return f"""
506
- <b>🔄 ЛОГИКА LONDON → NEW YORK</b>
507
- ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
508
-
509
- <b>🇬🇧 ЛОНДОНСКАЯ СЕССИЯ (06:00-12:00 UTC):</b>
510
- {london_text}
511
-
512
- <b>🇺🇸 НЬЮ-ЙОРК МОДЕЛЬ:</b>
513
- {ny_status} {ny_model}
514
-
515
- <b>📖 Как это работает:</b>
516
- • Лондон задаёт направление дня
517
- • Нью-Йорк либо продолжает, либо разворачивает
518
- • Модель 1 (продолжение) → сильный сигнал
519
- • Модель 2 (разворот) → осторожный сигнал
520
- """
521
-
522
- # =====================
523
- # 6. ДАННЫЕ И ИНДИКАТОРЫ
524
- # =====================
525
- def fetch_df(exchange, symbol, tf, limit=500):
526
- try:
527
- data = exchange.fetch_ohlcv(symbol, tf, limit=limit)
528
- df = pd.DataFrame(data, columns=['ts', 'o', 'h', 'l', 'c', 'v'])
529
- df['ts'] = pd.to_datetime(df['ts'], unit='ms')
530
- return df
531
- except Exception as e:
532
- print(f"Ошибка {symbol} {tf}: {e}")
533
- return pd.DataFrame()
534
-
535
- def calculate_atr(df, period=14):
536
- if len(df) < period:
537
- return 0
538
- high, low, close = df['h'], df['l'], df['c']
539
- tr1 = high - low
540
- tr2 = abs(high - close.shift())
541
- tr3 = abs(low - close.shift())
542
- tr = pd.concat([tr1, tr2, tr3], axis=1).max(axis=1)
543
- return tr.rolling(window=period).mean().iloc[-1]
544
-
545
- def get_session():
546
- h = datetime.utcnow().hour
547
- if 0 <= h < 6:
548
- return "АЗИЯ"
549
- elif 6 <= h < 12:
550
- return "ЛОНДОН"
551
- elif 12 <= h < 18:
552
- return "НЬЮ-ЙОРК AM"
553
- else:
554
- return "НЬЮ-ЙОРК PM"
555
-
556
- def find_swing_levels(df, lookback=50):
557
- if len(df) < lookback:
558
- return None, None
559
- highs = df['h'].values[-lookback:]
560
- lows = df['l'].values[-lookback:]
561
- swing_high = None
562
- swing_low = None
563
- for i in range(2, len(highs) - 2):
564
- if (highs[i] > highs[i-1] and highs[i] > highs[i-2] and
565
- highs[i] > highs[i+1] and highs[i] > highs[i+2]):
566
- if swing_high is None or highs[i] > swing_high:
567
- swing_high = highs[i]
568
- if (lows[i] < lows[i-1] and lows[i] < lows[i-2] and
569
- lows[i] < lows[i+1] and lows[i] < lows[i+2]):
570
- if swing_low is None or lows[i] < swing_low:
571
- swing_low = lows[i]
572
- if swing_high is None:
573
- swing_high = max(highs)
574
- if swing_low is None:
575
- swing_low = min(lows)
576
- return swing_high, swing_low
577
-
578
- def get_h4_bias(h4_high, h4_low):
579
- if h4_high is None or h4_low is None:
580
- return "RANGE"
581
- range_size = (h4_high - h4_low) / h4_low
582
- if range_size > 0.05:
583
- if h4_high > h4_low * 1.03:
584
- return "BULLISH"
585
- elif h4_low < h4_high * 0.97:
586
- return "BEARISH"
587
- return "RANGE"
588
-
589
- def get_h1_zone(h1_high, h1_low, current_price):
590
- if h1_high is None or h1_low is None:
591
- return "unknown", None
592
- mid = (h1_high + h1_low) / 2
593
- zone = "премиум" if current_price >= mid else "дискаунт"
594
- return zone, mid
595
-
596
- def mss_bullish(df):
597
- if len(df) < 20:
598
- return False
599
- highs = df['h'].values
600
- current_price = df['c'].iloc[-1]
601
- for i in range(len(df)-15, len(df)-3):
602
- if i < 2:
603
- continue
604
- if (highs[i] > highs[i-2] and highs[i] > highs[i-1] and
605
- highs[i] > highs[i+1] and highs[i] > highs[i+2]):
606
- if current_price > highs[i]:
607
- return True
608
- return False
609
-
610
- def mss_bearish(df):
611
- if len(df) < 20:
612
- return False
613
- lows = df['l'].values
614
- current_price = df['c'].iloc[-1]
615
- for i in range(len(df)-15, len(df)-3):
616
- if i < 2:
617
- continue
618
- if (lows[i] < lows[i-2] and lows[i] < lows[i-1] and
619
- lows[i] < lows[i+1] and lows[i] < lows[i+2]):
620
- if current_price < lows[i]:
621
- return True
622
- return False
623
-
624
- def choch_bullish(df):
625
- if len(df) < 10:
626
- return False
627
- highs = df['h'].values
628
- lows = df['l'].values
629
- closes = df['c'].values
630
- recent_low = min(lows[-5:])
631
- previous_low = min(lows[-10:-5])
632
- higher_low = recent_low > previous_low
633
- recent_high = max(highs[-7:-2])
634
- breakout = closes[-1] > recent_high
635
- return higher_low and breakout
636
-
637
- def choch_bearish(df):
638
- if len(df) < 10:
639
- return False
640
- highs = df['h'].values
641
- lows = df['l'].values
642
- closes = df['c'].values
643
- recent_high = max(highs[-5:])
644
- previous_high = max(highs[-10:-5])
645
- lower_high = recent_high < previous_high
646
- recent_low = min(lows[-7:-2])
647
- breakout = closes[-1] < recent_low
648
- return lower_high and breakout
649
-
650
- def check_smt(df_btc, df_eth):
651
- if len(df_btc) < 5 or len(df_eth) < 5:
652
- return False, "📡 Нет данных для SMT"
653
- btc_high = df_btc['h'].iloc[-5:].max()
654
- eth_high = df_eth['h'].iloc[-5:].max()
655
- btc_low = df_btc['l'].iloc[-5:].min()
656
- eth_low = df_eth['l'].iloc[-5:].min()
657
- btc_current = df_btc['c'].iloc[-1]
658
- eth_current = df_eth['c'].iloc[-1]
659
- btc_new_high = btc_current > btc_high * 0.99
660
- eth_new_high = eth_current > eth_high * 0.99
661
- btc_new_low = btc_current < btc_low * 1.01
662
- eth_new_low = eth_current < eth_low * 1.01
663
-
664
- if btc_new_high and not eth_new_high:
665
- return True, "📡 SMT: BTC делает新高, ETH нет → медвежья дивергенция"
666
- if btc_new_low and not eth_new_low:
667
- return True, "📡 SMT: BTC делает新低, ETH нет → бычья дивергенция"
668
- if eth_new_high and not btc_new_high:
669
- return True, "📡 SMT: ETH делает新高, BTC нет → медвежья дивергенция"
670
- if eth_new_low and not btc_new_low:
671
- return True, "📡 SMT: ETH делает新低, BTC нет → бычья дивергенция"
672
- return False, "📡 SMT: нет дивергенции между BTC и ETH"
673
-
674
- def check_eth_confirmation(df_btc, df_eth):
675
- if len(df_btc) < 20 or len(df_eth) < 20:
676
- return False, "🔗 Недостаточно данных для корреляции"
677
- btc_returns = df_btc['c'].pct_change().iloc[-20:]
678
- eth_returns = df_eth['c'].pct_change().iloc[-20:]
679
- correlation = btc_returns.corr(eth_returns)
680
- btc_direction = 1 if df_btc['c'].iloc[-1] > df_btc['c'].iloc[-5] else -1
681
- eth_direction = 1 if df_eth['c'].iloc[-1] > df_eth['c'].iloc[-5] else -1
682
- if correlation > 0.6 and btc_direction == eth_direction:
683
- return True, f"🔗 Корреляция с ETH: {correlation:.2f} (сильная, подтверждает)"
684
- else:
685
- return False, f"🔗 Корреляция с ETH: {correlation:.2f} (слабая, не подтверждает)"
686
-
687
- def find_fvg(df, direction='bullish'):
688
- if len(df) < 3:
689
- return None
690
- highs = df['h'].values[-10:]
691
- lows = df['l'].values[-10:]
692
- closes = df['c'].values[-10:]
693
- if direction == 'bullish':
694
- for i in range(2, len(closes)-1):
695
- if closes[i] > highs[i-1] and lows[i] > highs[i-2]:
696
- return (highs[i-2], lows[i])
697
- else:
698
- for i in range(2, len(closes)-1):
699
- if closes[i] < lows[i-1] and highs[i] < lows[i-2]:
700
- return (lows[i-2], highs[i])
701
- return None
702
-
703
- # =====================
704
- # 7. ОСНОВНОЙ АНАЛИЗ
705
- # =====================
706
- def analyze_and_signal():
707
- now = datetime.utcnow()
708
- current_candle_time = now.replace(minute=(now.minute // 15) * 15, second=0, microsecond=0)
709
- print(f"\n[{now.strftime('%Y-%m-%d %H:%M:%S')} UTC] 🔍 Проверка сигналов...")
710
-
711
- # Проверка дня
712
- trade_day_ok, trade_day_msg = is_trade_day()
713
- if not trade_day_ok:
714
- print(f"⏰ {trade_day_msg}")
715
- return
716
-
717
- session = get_session()
718
- # Торгуем во всех сессиях, кроме АЗИЯ
719
- if session not in ["ЛОНДОН", "НЬЮ-ЙОРК AM", "НЬЮ-ЙОРК PM"]:
720
- print(f"⏰ Пропускаем ({session})")
721
- return
722
-
723
- try:
724
- exchange = ccxt.htx({
725
- 'enableRateLimit': True,
726
- 'options': {'defaultType': 'spot'},
727
- 'timeout': 30000
728
- })
729
- except Exception as e:
730
- print(f"❌ Ошибка подключения: {e}")
731
- return
732
-
733
- print("📊 Загрузка данных...")
734
- df_h4 = fetch_df(exchange, BASE_SYMBOL, '4h', limit=100)
735
- df_h1 = fetch_df(exchange, BASE_SYMBOL, '1h', limit=100)
736
- df_m15 = fetch_df(exchange, BASE_SYMBOL, '15m', limit=300)
737
- df_m5 = fetch_df(exchange, BASE_SYMBOL, '5m', limit=500)
738
- df_eth = fetch_df(exchange, CONFIRM_SYMBOL, '15m', limit=100)
739
-
740
- if df_m5.empty or df_m15.empty:
741
- print("❌ Нет данных")
742
- return
743
-
744
- current_price = df_m5['c'].iloc[-1]
745
- print(f"💰 BTC: ${current_price:.0f}")
746
-
747
- # Лондонская сессия (только сегодняшняя)
748
- london_direction, london_text = get_london_direction(df_m5)
749
- print(f"🇬🇧 {london_text}")
750
-
751
- # Нью-Йорк модель (только сегодняшняя)
752
- ny_model = ""
753
- ny_status = ""
754
- if session in ["НЬЮ-ЙОРК AM", "НЬЮ-ЙОРК PM"]:
755
- ny_model, ny_status = get_ny_model(london_direction, df_m5)
756
- print(f"🇺🇸 NY модель: {ny_model}")
757
-
758
- # Сигналы MSS и CHoCH
759
- mss_bull = mss_bullish(df_m15)
760
- mss_bear = mss_bearish(df_m15)
761
- choch_bull = choch_bullish(df_m5)
762
- choch_bear = choch_bearish(df_m5)
763
-
764
- direction = None
765
- if mss_bull and choch_bull:
766
- direction = "bullish"
767
- elif mss_bear and choch_bear:
768
- direction = "bearish"
769
-
770
- if not direction:
771
- print("📊 Нет сигнала MSS+CHoCH")
772
- return
773
-
774
- print(f"📈 Направление: {direction.upper()}")
775
-
776
- # SMT и корреляция
777
- smt_yes, smt_msg = check_smt(df_m15, df_eth)
778
- eth_conf, eth_msg = check_eth_confirmation(df_m15, df_eth)
779
-
780
- # H4 и H1
781
- h4_high, h4_low = find_swing_levels(df_h4, 50)
782
- h1_high, h1_low = find_swing_levels(df_h1, 50)
783
-
784
- h4_bias_str = get_h4_bias(h4_high, h4_low)
785
- h1_zone, h1_mid = get_h1_zone(h1_high, h1_low, current_price)
786
-
787
- if h4_bias_str == "BULLISH":
788
- h4_bias = "bullish"
789
- elif h4_bias_str == "BEARISH":
790
- h4_bias = "bearish"
791
- else:
792
- h4_bias = "range"
793
-
794
- # Проверка нового сигнала
795
- last_signal = load_last_signal()
796
- current_signal = {
797
- "direction": direction,
798
- "h4_bias": h4_bias,
799
- "h1_zone": h1_zone,
800
- "candle_time": current_candle_time.isoformat()
801
- }
802
-
803
- if not is_new_signal(current_signal, last_signal):
804
- print(f"📭 Сигнал не новый")
805
- return
806
-
807
- print(f"🆕 НОВЫЙ СИГНАЛ!")
808
-
809
- # ATR и уровни
810
- atr = calculate_atr(df_m5, 14)
811
- if atr == 0:
812
- atr = current_price * 0.005
813
-
814
- if direction == "bullish":
815
- sl = current_price - atr * 1.0
816
- tp1 = current_price + atr * 1.5
817
- tp2 = current_price + atr * 2.5
818
- tp3 = h1_high if h1_high else current_price + atr * 3.5
819
- entry = current_price
820
- else:
821
- sl = current_price + atr * 1.0
822
- tp1 = current_price - atr * 1.5
823
- tp2 = current_price - atr * 2.5
824
- tp3 = h1_low if h1_low else current_price - atr * 3.5
825
- entry = current_price
826
-
827
- # Фильтр качества - ТОЛЬКО ДЛЯ ИНФО, НЕ БЛОКИРУЕТ СИГНАЛ
828
- quality_ok, quality_reasons = is_quality_signal(
829
- direction, atr, current_price, h4_bias, h1_zone, london_direction
830
- )
831
-
832
- # FVG
833
- fvg_zone = find_fvg(df_m5, direction)
834
- if not fvg_zone:
835
- if direction == "bullish":
836
- fvg_zone = (current_price - atr*0.5, current_price)
837
- else:
838
- fvg_zone = (current_price, current_price + atr*0.5)
839
-
840
- # Сильный сигнал?
841
- strong = False
842
- if direction == "bullish" and h4_bias == "bullish" and h1_zone == "дискаунт":
843
- strong = True
844
- elif direction == "bearish" and h4_bias == "bearish" and h1_zone == "премиум":
845
- strong = True
846
-
847
- # ========== ФОРМИРУЕМ ПОЛНОЕ СООБЩЕНИЕ ==========
848
-
849
- header = f"""
850
- {'🟢' if strong else '📊'} <b>ICT SETUP {BASE_SYMBOL}</b>
851
- {'🔥 СИЛЬНЫЙ СИГНАЛ 🔥' if strong else 'ИНФОРМАЦИОННЫЙ СИГНАЛ'}
852
- ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
853
- """
854
-
855
- basic_info = f"""
856
- <b>📌 НАПРАВЛЕНИЕ:</b> {'📈 LONG (покупка)' if direction == 'bullish' else '📉 SHORT (продажа)'}
857
- <b>💰 ТЕКУЩАЯ ЦЕНА:</b> ${current_price:.0f}
858
- <b>🎯 ТОРГОВАЯ СЕССИЯ:</b> {session}
859
- {trade_day_msg}
860
- """
861
-
862
- # ATR пояснение
863
- atr_explanation = explain_atr(atr, current_price, direction)
864
-
865
- # FVG пояснение
866
- fvg_explanation = explain_fvg(fvg_zone, direction, current_price)
867
-
868
- # Уровни
869
- levels = f"""
870
- <b>📊 УРОВНИ ВХОДА И ВЫХОДА</b>
871
- ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
872
- ┌─ 🟢 ENTRY (лимитный ордер): <b>${entry:.0f}</b>
873
- ├─ 🔴 SL (стоп-лосс): <b>${sl:.0f}</b>
874
- ├─ 🎯 TP1: <b>${tp1:.0f}</b> → закрыть 50% позиции
875
- ├─ 🎯 TP2: <b>${tp2:.0f}</b> → закрыть 30% позиции
876
- └─ 🎯 TP3: <b>${tp3:.0f}</b> → закрыть 20% позиции
877
- """
878
-
879
- # Логика входа
880
- entry_logic = explain_entry_logic(direction, current_price, atr, sl, tp1, tp2, tp3)
881
-
882
- # Сила сигнала
883
- strength_analysis = explain_signal_strength(direction, h4_bias, h1_zone, h4_bias_str)
884
-
885
- # Лондон → Нью-Йорк
886
- london_ny = explain_london_ny(london_direction, london_text, ny_model, ny_status) if session in ["НЬЮ-ЙОРК AM", "НЬЮ-ЙОРК PM"] else ""
887
-
888
- # Дополнительные факторы
889
- extra_factors = f"""
890
- <b>📡 ДОПОЛНИТЕЛЬНЫЕ ФАКТОРЫ</b>
891
- ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
892
- {smt_msg}
893
- {eth_msg}
894
- """
895
-
896
- # Фильтр качества (только инфо, не блокирует)
897
- quality_warning = ""
898
- if not quality_ok:
899
- quality_warning = f"""
900
- <b>⚠️ ФИЛЬТР КАЧЕСТВА НЕ ПРОЙДЕН (НО СИГНАЛ ОТПРАВЛЕН)</b>
901
- ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
902
- {chr(10).join(quality_reasons)}
903
-
904
- 💡 <b>Рекомендация:</b> Входить с осторожностью или уменьшить риск
905
- """
906
-
907
- # Риск-менеджмент
908
- risk_management = explain_risk_management(atr, current_price, direction, sl, tp1, tp3)
909
-
910
- # Сессия
911
- session_info = explain_session(session)
912
-
913
- # Время
914
- time_info = f"""
915
- ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
916
- 🕐 {now.strftime('%d.%m.%Y %H:%M')} UTC
917
- ⚠️ <b>Не является финансовой рекомендацией</b>
918
- """
919
-
920
- # Собираем всё
921
- full_message = (
922
- header + basic_info + atr_explanation + fvg_explanation + levels +
923
- entry_logic + strength_analysis + london_ny + extra_factors +
924
- quality_warning + risk_management + session_info + time_info
925
- )
926
-
927
- # Отправляем
928
- send_telegram(full_message)
929
-
930
- # Сильный сигнал - краткая версия
931
- if strong:
932
- strong_message = f"""
933
- 🟢 <b>🔥 СИЛЬНЫЙ СИГНАЛ {BASE_SYMBOL}</b>
934
- ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
935
-
936
- <b>📌 Направление:</b> {'📈 LONG' if direction == 'bullish' else '📉 SHORT'}
937
- <b>💰 Цена:</b> ${current_price:.0f}
938
-
939
- <b>УРОВНИ:</b>
940
- ┌─ 🟢 ENTRY: ${entry:.0f}
941
- ├─ 🔴 SL: ${sl:.0f}
942
- ├─ 🎯 TP1: ${tp1:.0f}
943
- ├─ 🎯 TP2: ${tp2:.0f}
944
- └─ 🎯 TP3: ${tp3:.0f}
945
-
946
- <b>✅ СОВПАДАЕТ:</b>
947
- • H4: {h4_bias_str}
948
- • H1: {h1_zone.upper()}
949
-
950
- {london_text}
951
-
952
- {smt_msg}
953
-
954
- 📐 RR TP3: {(abs(tp3 - current_price)/abs(current_price - sl)):.1f}:1
955
-
956
- 🕐 {now.strftime('%H:%M')} UTC
957
- """
958
- send_telegram(strong_message)
959
-
960
- # Сохраняем сигнал
961
- save_last_signal(current_signal)
962
-
963
- # Сохраняем сделку - ВСЕГДА, если есть сигнал
964
- state = load_state()
965
- if not state["active"]:
966
- state["active"] = True
967
- state["direction"] = direction
968
- state["entry"] = entry
969
- state["sl"] = sl
970
- state["tp1"] = tp1
971
- state["tp2"] = tp2
972
- state["tp3"] = tp3
973
- state["entered"] = False
974
- state["tp1_hit"] = False
975
- state["tp2_hit"] = False
976
- state["tp3_hit"] = False
977
- state["sl_hit"] = False
978
- save_state(state)
979
- print("📝 Новая сделка сохранена")
980
-
981
- # =====================
982
- # 8. СОПРОВОЖДЕНИЕ СДЕЛКИ
983
- # =====================
984
- def check_entry_and_targets():
985
- state = load_state()
986
- if not state["active"]:
987
- return
988
-
989
- try:
990
- exchange = ccxt.htx({'enableRateLimit': True, 'timeout': 30000})
991
- df_m5 = fetch_df(exchange, BASE_SYMBOL, '5m', limit=10)
992
- if df_m5.empty:
993
- return
994
- current_price = df_m5['c'].iloc[-1]
995
- except Exception as e:
996
- print(f"Ошибка получения цены: {e}")
997
- return
998
-
999
- direction = state["direction"]
1000
- entry = state["entry"]
1001
- sl = state["sl"]
1002
- tp1 = state["tp1"]
1003
- tp2 = state["tp2"]
1004
- tp3 = state["tp3"]
1005
-
1006
- if not state["entered"]:
1007
- if direction == "bullish" and current_price <= entry:
1008
- send_telegram(f"""
1009
- 🔔 <b>ENTRY LONG {BASE_SYMBOL}</b>
1010
- ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
1011
-
1012
- <b>✅ Цена вошла в зону FVG!</b>
1013
-
1014
- 💰 Цена входа: ${current_price:.0f}
1015
- 🛑 SL: ${sl:.0f}
1016
- 🎯 TP1: ${tp1:.0f}
1017
- 🎯 TP2: ${tp2:.0f}
1018
- 🎯 TP3: ${tp3:.0f}
1019
-
1020
- 📊 Риск: {abs(current_price - sl)/current_price*100:.2f}%
1021
- 📈 RR TP1: {abs(tp1 - current_price)/abs(current_price - sl):.1f}:1
1022
- """)
1023
- state["entered"] = True
1024
- save_state(state)
1025
- elif direction == "bearish" and current_price >= entry:
1026
- send_telegram(f"""
1027
- 🔔 <b>ENTRY SHORT {BASE_SYMBOL}</b>
1028
- ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
1029
-
1030
- <b>✅ Цена вошла в зону FVG!</b>
1031
-
1032
- 💰 Цена входа: ${current_price:.0f}
1033
- 🛑 SL: ${sl:.0f}
1034
- 🎯 TP1: ${tp1:.0f}
1035
- 🎯 TP2: ${tp2:.0f}
1036
- 🎯 TP3: ${tp3:.0f}
1037
-
1038
- 📊 Риск: {abs(current_price - sl)/current_price*100:.2f}%
1039
- 📈 RR TP1: {abs(tp1 - current_price)/abs(current_price - sl):.1f}:1
1040
- """)
1041
- state["entered"] = True
1042
- save_state(state)
1043
-
1044
- if not state["sl_hit"]:
1045
- if (direction == "bullish" and current_price <= sl) or (direction == "bearish" and current_price >= sl):
1046
- send_telegram(f"""
1047
- ❌ <b>SL HIT {BASE_SYMBOL}</b>
1048
- ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
1049
-
1050
- 💰 Цена: ${current_price:.0f}
1051
- 🛑 Стоп-лосс: ${sl:.0f}
1052
-
1053
- <b>Причина:</b> Структура рынка сломана
1054
-
1055
- {stats_text(state)}
1056
- """)
1057
- state["sl_hit"] = True
1058
- state["active"] = False
1059
- state["losses"] += 1
1060
- save_state(state)
1061
- return
1062
-
1063
- if not state["tp1_hit"]:
1064
- if (direction == "bullish" and current_price >= tp1) or (direction == "bearish" and current_price <= tp1):
1065
- send_telegram(f"""
1066
- 🎯 <b>TP1 HIT {BASE_SYMBOL}</b>
1067
- ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
1068
-
1069
- 💰 Цена: ${current_price:.0f}
1070
- 📊 Закрыто: 50% позиции
1071
-
1072
- ✅ Остаток позиции: 50%
1073
- 🎯 Следующая цель: TP2 (${tp2:.0f})
1074
- """)
1075
- state["tp1_hit"] = True
1076
- save_state(state)
1077
-
1078
- if not state["tp2_hit"]:
1079
- if (direction == "bullish" and current_price >= tp2) or (direction == "bearish" and current_price <= tp2):
1080
- send_telegram(f"""
1081
- 🎯 <b>TP2 HIT {BASE_SYMBOL}</b>
1082
- ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
1083
-
1084
- 💰 Цена: ${current_price:.0f}
1085
- 📊 Закрыто: 30% позиции
1086
-
1087
- ✅ Остаток позиции: 20%
1088
- 🎯 Следующая цель: TP3 (${tp3:.0f})
1089
- """)
1090
- state["tp2_hit"] = True
1091
- save_state(state)
1092
-
1093
- if not state["tp3_hit"]:
1094
- if (direction == "bullish" and current_price >= tp3) or (direction == "bearish" and current_price <= tp3):
1095
- send_telegram(f"""
1096
- 🏆 <b>TP3 HIT {BASE_SYMBOL}</b>
1097
- ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
1098
-
1099
- 💰 Цена: ${current_price:.0f}
1100
- 📊 Сделка полностью закрыта!
1101
-
1102
- ✅ Прибыль зафиксирована
1103
- {stats_text(state)}
1104
- """)
1105
- state["tp3_hit"] = True
1106
- state["active"] = False
1107
- state["wins"] += 1
1108
- save_state(state)
1109
- return
1110
-
1111
- # =====================
1112
- # 9. ОСНОВНОЙ ЦИКЛ
1113
- # =====================
1114
- def main_loop():
1115
- send_telegram("""
1116
- ✅ <b>ICT Trading Bot v5.0 ЗАПУЩЕН!</b>
1117
- ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
1118
-
1119
- 📌 <b>Режим работы:</b>
1120
- • Проверка каждые 15 минут
1121
- • Отправка только при НОВЫХ сигналах
1122
- • Торговые сессии: ЛОНДОН, НЬЮ-ЙОРК AM, НЬЮ-ЙОРК PM
1123
-
1124
- 📊 <b>Фильтры качества:</b>
1125
- • Неторговые дни: ПН, ВС
1126
- • Минимальный ATR: 0.5%
1127
- • Проверка H4 + H1 контекста
1128
-
1129
- 🎯 <b>Риск-менеджмент:</b>
1130
- • TP1/TP2/TP3 с частичным закрытием
1131
- • Соотношение RR от 1:1.5
1132
-
1133
- 📖 <b>В сообщениях будут пояснения:</b>
1134
- • Что такое ATR и как его использовать
1135
- • Что такое FVG и где вход
1136
- • Почему сильный или слабый сигнал
1137
- • Логика London → NY
1138
- """)
1139
-
1140
- state = load_state()
1141
- print(f"📊 {stats_text(state)}")
1142
-
1143
- last_candle_time = None
1144
-
1145
- while True:
1146
- now = datetime.utcnow()
1147
- current_candle = now.replace(minute=(now.minute // 15) * 15, second=0, microsecond=0)
1148
-
1149
- if last_candle_time != current_candle and now.second > 30:
1150
- last_candle_time = current_candle
1151
- print(f"\n{'='*50}")
1152
- print(f"[{now.strftime('%Y-%m-%d %H:%M:%S')}] 🕯 Закрылась 15M свеча")
1153
-
1154
- analyze_and_signal()
1155
- check_entry_and_targets()
1156
-
1157
- state = load_state()
1158
- print(f"📊 {stats_text(state)}")
1159
-
1160
- time.sleep(30)
1161
-
1162
- # =====================
1163
- # 10. ЗАПУСК
1164
- # =====================
1165
- if __name__ == "__main__":
1166
- try:
1167
- main_loop()
1168
- except KeyboardInterrupt:
1169
- print("\n👋 Бот остановлен")
1170
- sys.exit(0)
1171
- except Exception as e:
1172
- print(f"❌ Ошибка: {e}")
1173
- import traceback
1174
- traceback.print_exc()
1175
- sys.exit(1)
 
1
+ 1