mirror of
https://github.com/chrisnov-it/quantumbotx.git
synced 2026-07-27 18:57:47 +00:00
207 lines
8.5 KiB
Python
207 lines
8.5 KiB
Python
# core/routes/api_bots.py
|
|
|
|
import json
|
|
import logging
|
|
from flask import Blueprint, jsonify, request
|
|
import MetaTrader5 as mt5
|
|
from core.bots import controller
|
|
from core.db import queries
|
|
from core.utils.mt5 import get_rates_mt5
|
|
from core.utils.mt5 import TIMEFRAME_MAP
|
|
from core.strategies.strategy_map import STRATEGY_MAP, resolve_strategy_class
|
|
|
|
api_bots = Blueprint('api_bots', __name__)
|
|
logger = logging.getLogger(__name__)
|
|
|
|
@api_bots.route('/api/strategies', methods=['GET'])
|
|
def get_strategies_route():
|
|
try:
|
|
strategies = []
|
|
for key, strategy_class in STRATEGY_MAP.items():
|
|
strategies.append({
|
|
'id': key,
|
|
'name': getattr(strategy_class, 'name', key.replace('_', ' ').title()),
|
|
'description': getattr(strategy_class, 'description', 'No description available.')
|
|
})
|
|
return jsonify(strategies)
|
|
except Exception as e:
|
|
logger.error(f"Gagal memuat daftar strategi: {e}", exc_info=True)
|
|
return jsonify({"error": "Gagal memuat daftar strategi"}), 500
|
|
|
|
@api_bots.route('/api/strategies/<strategy_id>/params', methods=['GET'])
|
|
def get_strategy_params_route(strategy_id):
|
|
"""Mengembalikan parameter yang bisa diatur untuk sebuah strategi."""
|
|
strategy_class = resolve_strategy_class(strategy_id)
|
|
if not strategy_class:
|
|
return jsonify({"error": "Strategi tidak ditemukan"}), 404
|
|
|
|
# Panggil metode class untuk mendapatkan parameter
|
|
if hasattr(strategy_class, 'get_definable_params'):
|
|
params = strategy_class.get_definable_params()
|
|
|
|
# Normalize parameter format for frontend compatibility
|
|
# Frontend expects 'label' but some strategies use 'display_name'
|
|
normalized_params = []
|
|
for param in params:
|
|
normalized_param = param.copy()
|
|
# If display_name exists but label doesn't, use display_name as label
|
|
if 'display_name' in param and 'label' not in param:
|
|
normalized_param['label'] = param['display_name']
|
|
# If neither exists, create a label from the name
|
|
elif 'label' not in param and 'display_name' not in param:
|
|
normalized_param['label'] = param['name'].replace('_', ' ').title()
|
|
normalized_params.append(normalized_param)
|
|
|
|
return jsonify(normalized_params)
|
|
|
|
return jsonify([]) # Kembalikan array kosong jika tidak ada parameter
|
|
|
|
@api_bots.route('/api/bots', methods=['GET'])
|
|
def get_bots_route():
|
|
"""Mengambil semua bot."""
|
|
bots = queries.get_all_bots()
|
|
# Perkaya data bot dengan nama strategi yang mudah dibaca
|
|
for bot in bots:
|
|
strategy_key = bot.get('strategy')
|
|
strategy_class = resolve_strategy_class(strategy_key) # pyright: ignore[reportArgumentType]
|
|
if strategy_class:
|
|
bot['strategy_name'] = getattr(strategy_class, 'name', strategy_key)
|
|
else:
|
|
bot['strategy_name'] = strategy_key # Fallback jika tidak ditemukan
|
|
return jsonify(bots)
|
|
|
|
@api_bots.route('/api/bots/<int:bot_id>', methods=['GET'])
|
|
def get_single_bot_route(bot_id):
|
|
"""Mengambil detail satu bot."""
|
|
bot = queries.get_bot_by_id(bot_id)
|
|
if bot and bot.get('strategy_params'):
|
|
# Ubah string JSON menjadi objek untuk frontend
|
|
bot['strategy_params'] = json.loads(bot['strategy_params'])
|
|
# Convert enable_strategy_switching to integer for frontend
|
|
if bot and 'enable_strategy_switching' in bot:
|
|
bot['enable_strategy_switching'] = int(bot['enable_strategy_switching'])
|
|
return jsonify(bot) if bot else (jsonify({"error": "Bot tidak ditemukan"}), 404)
|
|
|
|
@api_bots.route('/api/bots', methods=['POST'])
|
|
def add_bot_route():
|
|
"""Membuat bot baru."""
|
|
data = request.get_json()
|
|
params_json = json.dumps(data.get('params', {}))
|
|
|
|
# Get strategy switching setting
|
|
enable_strategy_switching = int(data.get('enable_strategy_switching', False))
|
|
|
|
new_bot_id = queries.add_bot(
|
|
name=data.get('name'), market=data.get('market'), lot_size=data.get('risk_percent'),
|
|
sl_pips=data.get('sl_atr_multiplier'), tp_pips=data.get('tp_atr_multiplier'), timeframe=data.get('timeframe'),
|
|
interval=data.get('check_interval_seconds'), strategy=data.get('strategy'),
|
|
strategy_params=params_json, enable_strategy_switching=enable_strategy_switching
|
|
)
|
|
if new_bot_id:
|
|
controller.add_new_bot_to_controller(new_bot_id)
|
|
return jsonify({"message": "Bot berhasil dibuat", "bot_id": new_bot_id}), 201
|
|
return jsonify({"error": "Gagal menyimpan bot"}), 500
|
|
|
|
@api_bots.route('/api/bots/<int:bot_id>', methods=['PUT'])
|
|
def update_bot_route(bot_id):
|
|
"""Memperbarui pengaturan bot."""
|
|
bot_data = request.get_json()
|
|
|
|
bot_instance = controller.get_bot_instance_by_id(bot_id)
|
|
bot_was_running = bot_instance and bot_instance.status == 'Aktif'
|
|
|
|
# Get strategy switching setting
|
|
enable_strategy_switching = int(bot_data.get('enable_strategy_switching', False))
|
|
|
|
success, result = controller.perbarui_bot(bot_id, bot_data)
|
|
|
|
# Update the database with the strategy switching setting
|
|
if success:
|
|
queries.update_bot(
|
|
bot_id=bot_id,
|
|
name=bot_data.get('name'),
|
|
market=bot_data.get('market'),
|
|
lot_size=bot_data.get('risk_percent'),
|
|
sl_pips=bot_data.get('sl_atr_multiplier'),
|
|
tp_pips=bot_data.get('tp_atr_multiplier'),
|
|
timeframe=bot_data.get('timeframe'),
|
|
interval=bot_data.get('check_interval_seconds'),
|
|
strategy=bot_data.get('strategy'),
|
|
strategy_params=json.dumps(bot_data.get('params', {})),
|
|
enable_strategy_switching=enable_strategy_switching
|
|
)
|
|
|
|
if bot_was_running:
|
|
controller.mulai_bot(bot_id)
|
|
return jsonify({"message": "Bot berhasil diperbarui."}), 200
|
|
|
|
return jsonify({"error": result or "Gagal memperbarui bot"}), 500
|
|
|
|
@api_bots.route('/api/bots/<int:bot_id>', methods=['DELETE'])
|
|
def delete_bot_route(bot_id):
|
|
"""Menghapus bot."""
|
|
if controller.hapus_bot(bot_id):
|
|
return jsonify({"message": "Bot berhasil dihapus."}), 200
|
|
else:
|
|
return jsonify({"error": "Gagal menghapus bot dari database"}), 500
|
|
|
|
@api_bots.route('/api/bots/<int:bot_id>/start', methods=['POST'])
|
|
def start_bot_route(bot_id):
|
|
"""Memulai bot."""
|
|
success, message = controller.mulai_bot(bot_id)
|
|
return jsonify({'message': message}) if success else (jsonify({'error': message}), 500)
|
|
|
|
@api_bots.route('/api/bots/<int:bot_id>/stop', methods=['POST'])
|
|
def stop_bot_route(bot_id):
|
|
"""Menghentikan bot."""
|
|
success, message = controller.hentikan_bot(bot_id)
|
|
return jsonify({'message': message}) if success else (jsonify({'error': message}), 500)
|
|
|
|
@api_bots.route('/api/bots/start_all', methods=['POST'])
|
|
def start_all_bots_route():
|
|
"""Memulai semua bot yang dijeda."""
|
|
success, message = controller.mulai_semua_bot()
|
|
return jsonify({'message': message}) if success else (jsonify({'error': message}), 400)
|
|
|
|
@api_bots.route('/api/bots/stop_all', methods=['POST'])
|
|
def stop_all_bots_route():
|
|
"""Menghentikan semua bot yang aktif."""
|
|
success, message = controller.hentikan_semua_bot()
|
|
return jsonify({'message': message}) if success else (jsonify({'error': message}), 400)
|
|
|
|
@api_bots.route('/api/bots/<int:bot_id>/analysis', methods=['GET'])
|
|
def get_analysis_route(bot_id):
|
|
"""Mendapatkan data analisis terakhir."""
|
|
data = controller.get_bot_analysis_data(bot_id)
|
|
return jsonify(data if data else {"signal": "Data belum tersedia"})
|
|
|
|
@api_bots.route('/api/bots/<int:bot_id>/history', methods=['GET'])
|
|
def get_bot_history_route(bot_id):
|
|
"""Mengembalikan riwayat aktivitas untuk bot."""
|
|
history = queries.get_history_by_bot_id(bot_id)
|
|
return jsonify(history)
|
|
|
|
@api_bots.route('/api/rsi_data', methods=['GET'])
|
|
def get_rsi_data_route():
|
|
"""Menyediakan data RSI untuk grafik di dashboard."""
|
|
symbol = request.args.get('symbol', 'EURUSD', type=str)
|
|
timeframe_str = request.args.get('timeframe', 'H1', type=str)
|
|
|
|
timeframe = TIMEFRAME_MAP.get(timeframe_str.upper(), mt5.TIMEFRAME_H1)
|
|
|
|
df = get_rates_mt5(symbol, timeframe, 100)
|
|
|
|
if df is None or df.empty:
|
|
return jsonify({"error": f"Tidak dapat mengambil data untuk {symbol}"}), 404
|
|
|
|
df.ta.rsi(length=14, append=True)
|
|
df.dropna(inplace=True)
|
|
|
|
last_50_rows = df.tail(50)
|
|
|
|
chart_data = {
|
|
'timestamps': [ts.strftime('%H:%M') for ts in last_50_rows.index],
|
|
'rsi_values': list(last_50_rows.iloc[:, -1])
|
|
}
|
|
return jsonify(chart_data)
|