Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
|
@@ -752,14 +752,13 @@ def should_send_signal(symbol, timeframe, proba):
|
|
| 752 |
|
| 753 |
last_signals_sent[key] = (proba, now)
|
| 754 |
return True
|
| 755 |
-
# --- ⚖️ JUDGE API V31 (
|
| 756 |
def run_judge_api(live_prices_json="{}"):
|
| 757 |
try:
|
| 758 |
import json
|
| 759 |
try:
|
| 760 |
raw_prices = json.loads(live_prices_json) if isinstance(live_prices_json, str) else {}
|
| 761 |
live_prices = {k.lower(): v for k, v in raw_prices.items()}
|
| 762 |
-
if live_prices: print(f"📡 [PRIX REÇUS DU BRAS] : {live_prices}")
|
| 763 |
except:
|
| 764 |
live_prices = {}
|
| 765 |
|
|
@@ -767,12 +766,11 @@ def run_judge_api(live_prices_json="{}"):
|
|
| 767 |
conn.row_factory = sqlite3.Row
|
| 768 |
cursor = conn.cursor()
|
| 769 |
|
| 770 |
-
# 🔥 ON PREND TOUS LES TRADES (Confirmés ou non)
|
| 771 |
cursor.execute("SELECT * FROM signals WHERE status = 'EN_COURS'")
|
| 772 |
trades = cursor.fetchall()
|
| 773 |
|
| 774 |
closed_trades = []
|
| 775 |
-
watching_info = []
|
| 776 |
current_time = datetime.now(timezone.utc)
|
| 777 |
max_age_minutes = {"1m": 5, "5m": 10, "15m": 30, "1h": 60}
|
| 778 |
|
|
@@ -782,15 +780,12 @@ def run_judge_api(live_prices_json="{}"):
|
|
| 782 |
epic = sym_db.replace("/", "").replace("USDT", "USD").lower()
|
| 783 |
if not epic.endswith("m"): epic += "m"
|
| 784 |
|
| 785 |
-
# 1. EST-CE QUE LE MT5 A CE TRADE OUVERT ?
|
| 786 |
is_live = epic in live_prices
|
| 787 |
|
| 788 |
-
# 🎯 LA MAGIE : Si MT5 a le trade, on l'Auto-Confirme !
|
| 789 |
if is_live and t['confirmed'] == 0:
|
| 790 |
cursor.execute("UPDATE signals SET confirmed = 1 WHERE id = ?", (t['id'],))
|
| 791 |
-
print(f"✅ [AUTO-CONFIRM]
|
| 792 |
|
| 793 |
-
# 🗑️ Si MT5 NE L'A PAS
|
| 794 |
if not is_live:
|
| 795 |
date_str = t['date'].replace('Z', '+00:00')
|
| 796 |
signal_time = datetime.fromisoformat(date_str)
|
|
@@ -798,38 +793,29 @@ def run_judge_api(live_prices_json="{}"):
|
|
| 798 |
max_age = max_age_minutes.get(t['timeframe'], 60)
|
| 799 |
|
| 800 |
if t['confirmed'] == 1:
|
| 801 |
-
# Il était confirmé mais a disparu de MT5 (TP/SL touché en local)
|
| 802 |
cursor.execute("UPDATE signals SET status = 'FERMÉ PAR MT5 🛑' WHERE id = ?", (t['id'],))
|
| 803 |
-
|
| 804 |
-
closed_trades.append({"symbol": t['symbol'], "id": t['id']})
|
| 805 |
elif age_minutes > max_age:
|
| 806 |
-
# Il n'a jamais été pris et il est vieux
|
| 807 |
cursor.execute("UPDATE signals SET status = 'EXPIRÉ ⏰' WHERE id = ?", (t['id'],))
|
| 808 |
-
|
| 809 |
-
continue # On stoppe ici pour ce trade, on passe au suivant
|
| 810 |
|
| 811 |
-
#
|
| 812 |
-
# ⚖️ 2. LE TRAILING STOP (Puisque is_live est True)
|
| 813 |
-
# ==========================================
|
| 814 |
current_price = float(live_prices[epic])
|
| 815 |
-
|
| 816 |
sl_dyn, peak = t['sl'], t['peak_price']
|
| 817 |
new_peak = max(peak, current_price) if t['direction'] == 'HAUSSIER' else min(peak, current_price)
|
| 818 |
-
|
| 819 |
dist_totale = abs(t['tp'] - t['price'])
|
| 820 |
|
| 821 |
if t['direction'] == 'HAUSSIER':
|
| 822 |
mouvement = current_price - t['price']
|
| 823 |
-
else:
|
| 824 |
mouvement = t['price'] - current_price
|
| 825 |
|
| 826 |
progression = mouvement / dist_totale if (dist_totale > 0 and mouvement > 0) else 0
|
| 827 |
-
watching_info.append(f"{sym_db} ({current_price}$) -> Prog: {round(progression*100, 1)}%")
|
| 828 |
|
| 829 |
nouveau_sl = sl_dyn
|
| 830 |
dist_sl_initial = abs(t['price'] - sl_dyn)
|
| 831 |
|
| 832 |
-
# LOGIQUE AGRESSIVE
|
| 833 |
if t['direction'] == 'HAUSSIER':
|
| 834 |
if progression >= 0.60: nouveau_sl = max(sl_dyn, t['price'] + (dist_totale * 0.50))
|
| 835 |
elif progression >= 0.40: nouveau_sl = max(sl_dyn, t['price'] + (dist_totale * 0.20))
|
|
@@ -842,13 +828,8 @@ def run_judge_api(live_prices_json="{}"):
|
|
| 842 |
elif progression >= 0.10: nouveau_sl = min(sl_dyn, t['price'] + (dist_sl_initial * 0.50))
|
| 843 |
|
| 844 |
cursor.execute("UPDATE signals SET peak_price = ?, sl = ? WHERE id = ?", (new_peak, nouveau_sl, t['id']))
|
| 845 |
-
# 🔥 AJOUTE CETTE LIGNE pour envoyer les coordonnées au Bras
|
| 846 |
-
watching_info.append({"id": t['id'], "symbol": t['symbol'], "sl": nouveau_sl, "prog": progression})
|
| 847 |
-
|
| 848 |
-
# 🚨 ALERTE SI LE SL A BOUGÉ
|
| 849 |
-
if nouveau_sl != sl_dyn:
|
| 850 |
-
print(f"🛡️ [CLOUD-SL] {t['symbol']} ID {t['id']} | Le SL avance à {round(nouveau_sl, 5)} (Prog: {round(progression*100,1)}%)")
|
| 851 |
|
|
|
|
| 852 |
outcome, reward = None, 0
|
| 853 |
if t['direction'] == 'HAUSSIER':
|
| 854 |
if current_price >= t['tp']: outcome, reward = "GAGNÉ ✅", 3
|
|
@@ -858,19 +839,30 @@ def run_judge_api(live_prices_json="{}"):
|
|
| 858 |
elif current_price >= nouveau_sl: outcome, reward = ("GAGNÉ (PARTIEL) 💸", 1) if nouveau_sl < t['price'] else ("PERDU ❌", -5)
|
| 859 |
|
| 860 |
if outcome:
|
| 861 |
-
# Si le Juge clôture la position par lui-même
|
| 862 |
mutate_agent(t['symbol'], t['timeframe'], t['regime'], success=(reward>0))
|
| 863 |
cursor.execute("UPDATE signals SET status=? WHERE id=?", (outcome, t['id']))
|
| 864 |
-
|
| 865 |
-
|
| 866 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 867 |
except Exception as e:
|
| 868 |
print(f"⚠️ Erreur Trade ID {t['id']}: {e}")
|
| 869 |
-
|
| 870 |
conn.commit()
|
| 871 |
-
return {"status": "updates", "data": closed_trades, "watching": watching_info} if closed_trades else {"status": "waiting", "watching": watching_info}
|
| 872 |
-
except Exception as e: return {"status": "error", "message": str(e)}
|
| 873 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 874 |
# --- 📡 LECTURE RADAR OPTIMISÉE ---
|
| 875 |
def get_active_signals():
|
| 876 |
try:
|
|
|
|
| 752 |
|
| 753 |
last_signals_sent[key] = (proba, now)
|
| 754 |
return True
|
| 755 |
+
# --- ⚖️ JUDGE API V31 (VERSION NETTOYÉE POUR SL PHYSIQUE) ---
|
| 756 |
def run_judge_api(live_prices_json="{}"):
|
| 757 |
try:
|
| 758 |
import json
|
| 759 |
try:
|
| 760 |
raw_prices = json.loads(live_prices_json) if isinstance(live_prices_json, str) else {}
|
| 761 |
live_prices = {k.lower(): v for k, v in raw_prices.items()}
|
|
|
|
| 762 |
except:
|
| 763 |
live_prices = {}
|
| 764 |
|
|
|
|
| 766 |
conn.row_factory = sqlite3.Row
|
| 767 |
cursor = conn.cursor()
|
| 768 |
|
|
|
|
| 769 |
cursor.execute("SELECT * FROM signals WHERE status = 'EN_COURS'")
|
| 770 |
trades = cursor.fetchall()
|
| 771 |
|
| 772 |
closed_trades = []
|
| 773 |
+
watching_info = [] # 🎯 Contiendra uniquement des dicts pour le Bras
|
| 774 |
current_time = datetime.now(timezone.utc)
|
| 775 |
max_age_minutes = {"1m": 5, "5m": 10, "15m": 30, "1h": 60}
|
| 776 |
|
|
|
|
| 780 |
epic = sym_db.replace("/", "").replace("USDT", "USD").lower()
|
| 781 |
if not epic.endswith("m"): epic += "m"
|
| 782 |
|
|
|
|
| 783 |
is_live = epic in live_prices
|
| 784 |
|
|
|
|
| 785 |
if is_live and t['confirmed'] == 0:
|
| 786 |
cursor.execute("UPDATE signals SET confirmed = 1 WHERE id = ?", (t['id'],))
|
| 787 |
+
print(f"✅ [AUTO-CONFIRM] ID: {t['id']}")
|
| 788 |
|
|
|
|
| 789 |
if not is_live:
|
| 790 |
date_str = t['date'].replace('Z', '+00:00')
|
| 791 |
signal_time = datetime.fromisoformat(date_str)
|
|
|
|
| 793 |
max_age = max_age_minutes.get(t['timeframe'], 60)
|
| 794 |
|
| 795 |
if t['confirmed'] == 1:
|
|
|
|
| 796 |
cursor.execute("UPDATE signals SET status = 'FERMÉ PAR MT5 🛑' WHERE id = ?", (t['id'],))
|
| 797 |
+
closed_trades.append({"symbol": t['symbol'], "id": t['id'], "direction": t['direction']})
|
|
|
|
| 798 |
elif age_minutes > max_age:
|
|
|
|
| 799 |
cursor.execute("UPDATE signals SET status = 'EXPIRÉ ⏰' WHERE id = ?", (t['id'],))
|
| 800 |
+
continue
|
|
|
|
| 801 |
|
| 802 |
+
# --- CALCUL DU TRAILING ---
|
|
|
|
|
|
|
| 803 |
current_price = float(live_prices[epic])
|
|
|
|
| 804 |
sl_dyn, peak = t['sl'], t['peak_price']
|
| 805 |
new_peak = max(peak, current_price) if t['direction'] == 'HAUSSIER' else min(peak, current_price)
|
|
|
|
| 806 |
dist_totale = abs(t['tp'] - t['price'])
|
| 807 |
|
| 808 |
if t['direction'] == 'HAUSSIER':
|
| 809 |
mouvement = current_price - t['price']
|
| 810 |
+
else:
|
| 811 |
mouvement = t['price'] - current_price
|
| 812 |
|
| 813 |
progression = mouvement / dist_totale if (dist_totale > 0 and mouvement > 0) else 0
|
|
|
|
| 814 |
|
| 815 |
nouveau_sl = sl_dyn
|
| 816 |
dist_sl_initial = abs(t['price'] - sl_dyn)
|
| 817 |
|
| 818 |
+
# LOGIQUE AGRESSIVE
|
| 819 |
if t['direction'] == 'HAUSSIER':
|
| 820 |
if progression >= 0.60: nouveau_sl = max(sl_dyn, t['price'] + (dist_totale * 0.50))
|
| 821 |
elif progression >= 0.40: nouveau_sl = max(sl_dyn, t['price'] + (dist_totale * 0.20))
|
|
|
|
| 828 |
elif progression >= 0.10: nouveau_sl = min(sl_dyn, t['price'] + (dist_sl_initial * 0.50))
|
| 829 |
|
| 830 |
cursor.execute("UPDATE signals SET peak_price = ?, sl = ? WHERE id = ?", (new_peak, nouveau_sl, t['id']))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 831 |
|
| 832 |
+
# --- DÉCISION DE CLÔTURE ---
|
| 833 |
outcome, reward = None, 0
|
| 834 |
if t['direction'] == 'HAUSSIER':
|
| 835 |
if current_price >= t['tp']: outcome, reward = "GAGNÉ ✅", 3
|
|
|
|
| 839 |
elif current_price >= nouveau_sl: outcome, reward = ("GAGNÉ (PARTIEL) 💸", 1) if nouveau_sl < t['price'] else ("PERDU ❌", -5)
|
| 840 |
|
| 841 |
if outcome:
|
|
|
|
| 842 |
mutate_agent(t['symbol'], t['timeframe'], t['regime'], success=(reward>0))
|
| 843 |
cursor.execute("UPDATE signals SET status=? WHERE id=?", (outcome, t['id']))
|
| 844 |
+
closed_trades.append({"symbol": t['symbol'], "id": t['id'], "direction": t['direction']})
|
| 845 |
+
else:
|
| 846 |
+
# 🎯 ON N'AJOUTE DANS WATCHING QUE SI LE TRADE EST ENCORE OUVERT
|
| 847 |
+
watching_info.append({
|
| 848 |
+
"id": t['id'],
|
| 849 |
+
"symbol": t['symbol'],
|
| 850 |
+
"sl": round(nouveau_sl, 6),
|
| 851 |
+
"prog": round(progression, 4)
|
| 852 |
+
})
|
| 853 |
+
|
| 854 |
except Exception as e:
|
| 855 |
print(f"⚠️ Erreur Trade ID {t['id']}: {e}")
|
| 856 |
+
|
| 857 |
conn.commit()
|
|
|
|
|
|
|
| 858 |
|
| 859 |
+
# Retour propre : data contient les fermetures, watching contient les mises à jour SL
|
| 860 |
+
return {
|
| 861 |
+
"status": "updates" if closed_trades else "waiting",
|
| 862 |
+
"data": closed_trades,
|
| 863 |
+
"watching": watching_info
|
| 864 |
+
}
|
| 865 |
+
except Exception as e: return {"status": "error", "message": str(e)}
|
| 866 |
# --- 📡 LECTURE RADAR OPTIMISÉE ---
|
| 867 |
def get_active_signals():
|
| 868 |
try:
|