mirror of
https://github.com/chrisnov-it/quantumbotx.git
synced 2026-07-28 11:17:44 +00:00
fixed all bugs
This commit is contained in:
+84
-34
@@ -1,62 +1,112 @@
|
||||
# core/mt5/trade.py
|
||||
import MetaTrader5 as mt5
|
||||
import logging
|
||||
|
||||
def place_trade(symbol, trade_type, lot, sl_pips, tp_pips, magic_number):
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
def place_trade(symbol, order_type, volume, sl_pips, tp_pips, magic):
|
||||
"""
|
||||
Menempatkan order trading ke MetaTrader 5 dengan logika yang lebih tangguh.
|
||||
"""
|
||||
symbol_info = mt5.symbol_info(symbol)
|
||||
if symbol_info is None:
|
||||
print(f"Gagal mendapatkan info untuk simbol {symbol}")
|
||||
logger.error(f"Gagal mendapatkan info untuk simbol {symbol}, order dibatalkan.")
|
||||
return None
|
||||
|
||||
allowed_filling_modes = symbol_info.filling_modes
|
||||
if mt5.ORDER_FILLING_FOK in allowed_filling_modes:
|
||||
filling_type = mt5.ORDER_FILLING_FOK
|
||||
elif mt5.ORDER_FILLING_IOC in allowed_filling_modes:
|
||||
# --- PERBAIKAN UTAMA DI SINI ---
|
||||
# 1. Gunakan atribut yang benar: 'filling_mode' (singular)
|
||||
# 2. Pilih filling mode yang didukung. IOC lebih fleksibel daripada FOK.
|
||||
# FOK (Fill Or Kill): Seluruh order harus terpenuhi, atau dibatalkan.
|
||||
# IOC (Immediate Or Cancel): Bagian dari order bisa terpenuhi, sisanya dibatalkan.
|
||||
|
||||
# Ambil filling mode yang diizinkan oleh simbol
|
||||
allowed_filling_mode = symbol_info.filling_mode
|
||||
|
||||
# Pilih tipe filling. Prioritaskan IOC jika tersedia, jika tidak, FOK.
|
||||
filling_type = mt5.ORDER_FILLING_FOK # Default
|
||||
if allowed_filling_mode & mt5.ORDER_FILLING_IOC:
|
||||
filling_type = mt5.ORDER_FILLING_IOC
|
||||
elif allowed_filling_mode & mt5.ORDER_FILLING_FOK:
|
||||
filling_type = mt5.ORDER_FILLING_FOK
|
||||
else:
|
||||
filling_type = allowed_filling_modes[0]
|
||||
logger.warning(f"Simbol {symbol} tidak mendukung FOK atau IOC. Menggunakan FOK sebagai fallback.")
|
||||
|
||||
point = symbol_info.point
|
||||
price = mt5.symbol_info_tick(symbol).ask if trade_type == mt5.ORDER_TYPE_BUY else mt5.symbol_info_tick(symbol).bid
|
||||
price = mt5.symbol_info_tick(symbol).ask if order_type == mt5.ORDER_TYPE_BUY else mt5.symbol_info_tick(symbol).bid
|
||||
|
||||
sl = 0.0
|
||||
tp = 0.0
|
||||
|
||||
if order_type == mt5.ORDER_TYPE_BUY:
|
||||
sl = price - sl_pips * point if sl_pips > 0 else 0.0
|
||||
tp = price + tp_pips * point if tp_pips > 0 else 0.0
|
||||
elif order_type == mt5.ORDER_TYPE_SELL:
|
||||
sl = price + sl_pips * point if sl_pips > 0 else 0.0
|
||||
tp = price - tp_pips * point if tp_pips > 0 else 0.0
|
||||
|
||||
request = {
|
||||
"action": mt5.TRADE_ACTION_DEAL,
|
||||
"symbol": symbol,
|
||||
"volume": lot,
|
||||
"type": trade_type,
|
||||
"volume": float(volume),
|
||||
"type": order_type,
|
||||
"price": price,
|
||||
"sl": price - sl_pips * point if trade_type == mt5.ORDER_TYPE_BUY else price + sl_pips * point,
|
||||
"tp": price + tp_pips * point if trade_type == mt5.ORDER_TYPE_BUY else price - tp_pips * point,
|
||||
"magic": magic_number,
|
||||
"comment": "Trade dari Python Bot",
|
||||
"sl": sl,
|
||||
"tp": tp,
|
||||
"magic": magic,
|
||||
"comment": "QuantumBotX Trade",
|
||||
"type_time": mt5.ORDER_TIME_GTC,
|
||||
"type_filling": filling_type,
|
||||
}
|
||||
|
||||
logger.info(f"Mengirim order: {request}")
|
||||
result = mt5.order_send(request)
|
||||
if result.retcode != mt5.TRADE_RETCODE_DONE:
|
||||
print(f"Order gagal: {result.comment}")
|
||||
|
||||
if result is None:
|
||||
logger.error(f"order_send gagal, last_error()={mt5.last_error()}")
|
||||
return None
|
||||
print(f"Order terkirim. Ticket: {result.order}")
|
||||
|
||||
if result.retcode != mt5.TRADE_RETCODE_DONE:
|
||||
logger.error(f"Order GAGAL, retcode={result.retcode}, comment: {result.comment}")
|
||||
logger.error(f"Request Gagal: {request}")
|
||||
else:
|
||||
logger.info(f"Order BERHASIL, ticket={result.order}, comment: {result.comment}")
|
||||
|
||||
return result
|
||||
|
||||
|
||||
def close_trade(position):
|
||||
trade_type = mt5.ORDER_TYPE_SELL if position.type == mt5.ORDER_TYPE_BUY else mt5.ORDER_TYPE_BUY
|
||||
price = mt5.symbol_info_tick(position.symbol).bid if position.type == mt5.ORDER_TYPE_BUY else mt5.symbol_info_tick(position.symbol).ask
|
||||
"""
|
||||
Menutup posisi trading yang ada.
|
||||
"""
|
||||
if position is None:
|
||||
return
|
||||
|
||||
symbol = position.symbol
|
||||
ticket = position.ticket
|
||||
volume = position.volume
|
||||
order_type = mt5.ORDER_TYPE_SELL if position.type == mt5.ORDER_TYPE_BUY else mt5.ORDER_TYPE_BUY
|
||||
price = mt5.symbol_info_tick(symbol).bid if position.type == mt5.ORDER_TYPE_BUY else mt5.symbol_info_tick(symbol).ask
|
||||
|
||||
symbol_info = mt5.symbol_info(symbol)
|
||||
if symbol_info is None:
|
||||
logger.error(f"Gagal mendapatkan info untuk simbol {symbol} saat menutup posisi, order dibatalkan.")
|
||||
return None
|
||||
|
||||
allowed_filling_mode = symbol_info.filling_mode
|
||||
filling_type = mt5.ORDER_FILLING_FOK
|
||||
if allowed_filling_mode & mt5.ORDER_FILLING_IOC:
|
||||
filling_type = mt5.ORDER_FILLING_IOC
|
||||
|
||||
request = {
|
||||
"action": mt5.TRADE_ACTION_DEAL,
|
||||
"symbol": position.symbol,
|
||||
"volume": position.volume,
|
||||
"type": trade_type,
|
||||
"position": position.ticket,
|
||||
"price": price,
|
||||
"magic": position.magic,
|
||||
"comment": "Auto close dari Python Bot",
|
||||
"type_time": mt5.ORDER_TIME_GTC,
|
||||
"type_filling": mt5.ORDER_FILLING_FOK,
|
||||
"action": mt5.TRADE_ACTION_DEAL, "symbol": symbol, "volume": float(volume),
|
||||
"type": order_type, "position": ticket, "price": price, "magic": position.magic,
|
||||
"comment": "QuantumBotX Close", "type_time": mt5.ORDER_TIME_GTC, "type_filling": filling_type,
|
||||
}
|
||||
|
||||
logger.info(f"Menutup posisi: {request}")
|
||||
result = mt5.order_send(request)
|
||||
if result.retcode != mt5.TRADE_RETCODE_DONE:
|
||||
print(f"Gagal menutup posisi #{position.ticket}: {result.comment}")
|
||||
return False
|
||||
print(f"Posisi #{position.ticket} berhasil ditutup.")
|
||||
return True
|
||||
|
||||
if result and result.retcode == mt5.TRADE_RETCODE_DONE:
|
||||
logger.info(f"Posisi {ticket} berhasil ditutup.")
|
||||
else:
|
||||
logger.error(f"Gagal menutup posisi, retcode={result.retcode if result else 'N/A'}, comment: {result.comment if result else mt5.last_error()}")
|
||||
Reference in New Issue
Block a user