# server_comm.py # # Deskripsi: # Versi ini telah disempurnakan untuk mendukung semua tipe order: # Market (Buy/Sell Entry), Stop (Buy/Sell Stop), dan Limit (Buy/Sell Limit). from __future__ import annotations import logging import requests from typing import Dict, Any def send_signal_to_server(**payload: Any) -> str: """Mengirim sinyal trading ke server dan mengembalikan status keberhasilan.""" # Ekstrak URL dan secret_key, lalu hapus dari payload server_url = payload.pop("server_url", None) secret_key = payload.pop("secret_key", None) if not server_url: logging.error("server_url tidak ditemukan di payload. Sinyal tidak dikirim.") return 'FAILED' headers = {} if secret_key: headers['X-Secret-Key'] = secret_key else: logging.warning("secret_key tidak ditemukan di payload. Mengirim tanpa otorisasi.") signal_json = payload.get("signal_json", {}) if not isinstance(signal_json, dict): logging.error("Tipe data signal_json tidak valid (harus dictionary). Sinyal tidak dikirim.") return 'FAILED' order_type = payload.get("order_type", "WAIT") symbol = payload.get("symbol", "UNKNOWN") # Menentukan `signal_type` umum berdasarkan `order_type` if "CANCEL" in order_type.upper() or "DELETE" in order_type.upper(): payload['signal'] = "CANCEL" elif "BUY" in order_type.upper(): payload['signal'] = "BUY" elif "SELL" in order_type.upper(): payload['signal'] = "SELL" else: payload['signal'] = "WAIT" try: response = requests.post(server_url, json=payload, headers=headers, timeout=10) log_message = f"Sinyal {payload.get('signal', 'UNKNOWN')} untuk {symbol} dikirim." if response.status_code == 200: logging.info(f"✅ {log_message} Status: BERHASIL.") return 'SUCCESS' elif 400 <= response.status_code < 500: logging.error(f"❌ {log_message} Status: DITOLAK. Respons: {response.text}") return 'REJECTED' else: logging.error(f"❌ {log_message} Status: GAGAL. Kode: {response.status_code}, Respons: {response.text}") return 'FAILED' except requests.exceptions.RequestException as e: logging.error(f"❌ Error koneksi saat mengirim sinyal: {e}") return 'FAILED' def cancel_signal(signal_id: str, active_signals: Dict[str, Dict[str, any]], api_key: str, server_url: str, secret_key: str) -> None: """Membangun dan mengirim sinyal pembatalan untuk semua tipe order (Market, Limit, Stop).""" if signal_id not in active_signals: return original = active_signals[signal_id]['signal_json'] symbol = original.get("Symbol") entry_val = (original.get("BuyEntry") or original.get("SellEntry") or original.get("BuyStop") or original.get("SellStop") or original.get("BuyLimit") or original.get("SellLimit")) if not symbol or not entry_val: logging.error(f"Data tidak lengkap untuk membatalkan sinyal ID {signal_id}.") return cancel_json = { "Symbol": symbol, "DeleteLimit/Stop": entry_val, "BuyEntry": "", "BuySL": "", "BuyTP": "", "SellEntry": "", "SellSL": "", "SellTP": "", "BuyStop": "", "BuyStopSL": "", "BuyStopTP": "", "SellStop": "", "SellStopSL": "", "SellStopTP": "", "BuyLimit": "", "BuyLimitSL": "", "BuyLimitTP": "", "SellLimit": "", "SellLimitSL": "", "SellLimitTP": "", } payload = { "symbol": symbol, "signal_json": cancel_json, "api_key": api_key, "server_url": server_url, "secret_key": secret_key, "order_type": "CANCEL_ORDER" } send_signal_to_server(**payload) del active_signals[signal_id]