# -*- coding: utf-8 -*-
# =============================================================================
# AI TRADING ROBOT - REAL-TIME SCALPING M5 (ULTIMATE EDITION)
# - Data real-time streaming dengan resolusi tinggi
# - Ensemble AI dengan 7 model prediktif
# - Market microstructure analysis
# - Volatility adaptive filtering
# - Quantum-inspired optimization
# - Error correction feedback loop
# =============================================================================
import os
import asyncio
import logging
import json
import nest_asyncio
import numpy as np
import pandas_ta as ta
import [Link] as stats
import pandas as pd
from datetime import datetime, timedelta
from [Link] import (
RandomForestClassifier,
GradientBoostingClassifier,
VotingClassifier
)
from sklearn.model_selection import train_test_split
from [Link] import accuracy_score, f1_score, precision_score, recall_score
from [Link] import RobustScaler, PowerTransformer
from [Link] import make_pipeline
from [Link] import CalibratedClassifierCV
from sklearn.feature_selection import SelectKBest, f_classif
from xgboost import XGBClassifier
from lightgbm import LGBMClassifier
from catboost import CatBoostClassifier
import [Link] as genai
from twelvedata import TDClient
from openai import OpenAI
from telegram import Update, InlineKeyboardButton, InlineKeyboardMarkup
from [Link] import (
Application,
CommandHandler,
ContextTypes,
filters,
CallbackQueryHandler,
MessageHandler
)
# --- KONFIGURASI ---
TELEGRAM_BOT_TOKEN = "GANTI_DENGAN_TOKEN_BOT_TELEGRAM_BARU_ANDA"
GEMINI_API_KEY = "GANTI_DENGAN_API_KEY_GEMINI_BARU_ANDA"
GROQ_API_KEY = "GANTI_DENGAN_API_KEY_GROQ_BARU_ANDA"
TWELVEDATA_API_KEY = "GANTI_DENGAN_API_KEY_TWELVEDATA_BARU_ANDA"
# --- Konfigurasi Trading Scalping M5 ---
DEFAULT_TRADING_SYMBOL = "EUR/USD"
INTERVAL = "5min"
OUTPUT_SIZE_HISTORY = 1500 # Data historis lebih banyak
REALTIME_BUFFER_SIZE = 100 # Buffer real-time lebih besar
SCHEDULE_SECONDS = 300 # 5 menit
MAX_RETRIES = 5
MIN_ATR = 0.0005 # Filter volatilitas minimum
VOLUME_THRESHOLD = 1.5 # Threshold volume relatif
# --- Inisialisasi Klien API ---
try:
gemini_json_config =
[Link](response_mime_type="application/json")
[Link](api_key=GEMINI_API_KEY)
gemini_model = [Link]('gemini-1.5-flash-latest',
generation_config=gemini_json_config)
groq_client = OpenAI(api_key=GROQ_API_KEY,
base_url="[Link]
td = TDClient(apikey=TWELVEDATA_API_KEY)
except Exception as e:
[Link](f"Gagal menginisialisasi API: {e}")
exit()
# --- Setup Logging ---
[Link](
format="%(asctime)s - %(name)s - %(levelname)s - %(message)s",
level=[Link],
handlers=[
[Link]("ai_trading_robot.log"),
[Link]()
]
)
[Link]("httpx").setLevel([Link])
logger = [Link](__name__)
# --- GLOBAL STATE ---
realtime_data = {}
symbol_features = {}
model_performance = {'precision': 0.0, 'recall': 0.0, 'f1': 0.0}
active_monitoring = {} # {chat_id: symbol}
# --- MODEL MACHINE LEARNING TERBARU ---
base_models = {
'xgb': XGBClassifier(n_estimators=350, learning_rate=0.03, max_depth=7,
subsample=0.75, colsample_bytree=0.8, random_state=42,
eval_metric='logloss', use_label_encoder=False),
'lgbm': LGBMClassifier(n_estimators=350, learning_rate=0.03, max_depth=7,
subsample=0.75, colsample_bytree=0.8, random_state=42,
boosting_type='dart'),
'catboost': CatBoostClassifier(iterations=350, learning_rate=0.03, depth=7,
subsample=0.75, random_state=42, verbose=0,
loss_function='Logloss'),
'rf': RandomForestClassifier(n_estimators=350, max_depth=12,
min_samples_split=3, random_state=42,
class_weight='balanced_subsample'),
'gb': GradientBoostingClassifier(n_estimators=300, learning_rate=0.05,
max_depth=6, subsample=0.8, random_state=42)
}
# Model dengan kalibrasi probabilitas
calibrated_models = {}
for name, model in base_models.items():
calibrated_models[name] = make_pipeline(
PowerTransformer(),
RobustScaler(),
CalibratedClassifierCV(model, method='isotonic', cv=5)
)
# Model ensemble akhir dengan weighted voting
ensemble_model = VotingClassifier(
estimators=[(name, model) for name, model in calibrated_models.items()],
voting='soft',
weights=[1.25, 1.2, 1.15, 1.1, 1.0] # Berat berdasarkan kinerja
)
is_model_trained = False
def calculate_advanced_indicators(df):
"""Hitung 30+ indikator teknis untuk scalping M5"""
try:
# --- TREND INDICATORS ---
df['SMA_10'] = df['close'].rolling(window=10).mean()
df['SMA_30'] = df['close'].rolling(window=30).mean()
df['EMA_12'] = df['close'].ewm(span=12, adjust=False).mean()
df['EMA_26'] = df['close'].ewm(span=26, adjust=False).mean()
df['EMA_50'] = df['close'].ewm(span=50, adjust=False).mean()
# Ichimoku Cloud
ichimoku = [Link](df['high'], df['low'], df['close'])
df['ichi_conv'] = ichimoku['ITS_9']
df['ichi_base'] = ichimoku['IKS_26']
df['ichi_spanA'] = ichimoku['ICS_26']
df['ichi_spanB'] = ichimoku['IKS_26']
df['ichi_cloud'] = df['ichi_spanA'] - df['ichi_spanB']
# --- MOMENTUM INDICATORS ---
df['RSI'] = [Link](df['close'], length=14)
df['RSI_30'] = [Link](df['close'], length=30)
stoch = [Link](df['high'], df['low'], df['close'], k=14, d=3)
df['stoch_k'] = stoch['STOCHk_14_3_3']
df['stoch_d'] = stoch['STOCHd_14_3_3']
df['stoch_diff'] = df['stoch_k'] - df['stoch_d']
# MACD Triple
macd = [Link](df['close'], fast=12, slow=26, signal=9)
df['MACD'] = macd['MACD_12_26_9']
df['MACD_signal'] = macd['MACDs_12_26_9']
df['MACD_hist'] = macd['MACDh_12_26_9']
# Awesome Oscillator
df['ao'] = [Link](df['high'], df['low'])
# --- VOLATILITY INDICATORS ---
df['ATR'] = [Link](df['high'], df['low'], df['close'], length=14)
df['ATR_30'] = [Link](df['high'], df['low'], df['close'], length=30)
bb = [Link](df['close'], length=20, std=2)
df['Bollinger_upper'] = bb['BBU_20_2.0']
df['Bollinger_middle'] = bb['BBM_20_2.0']
df['Bollinger_lower'] = bb['BBL_20_2.0']
df['bollinger_pct'] = (df['close'] - df['Bollinger_lower']) / (
df['Bollinger_upper'] - df['Bollinger_lower'])
# Keltner Channels
keltner = [Link](df['high'], df['low'], df['close'], length=20, scalar=1.5)
df['keltner_upper'] = keltner['KCUe_20_1.5']
df['keltner_lower'] = keltner['KCLe_20_1.5']
# --- VOLUME INDICATORS ---
df['OBV'] = [Link](df['close'], df['volume'])
df['VWAP'] = [Link](df['high'], df['low'], df['close'], df['volume'])
df['volume_sma_20'] = df['volume'].rolling(window=20).mean()
df['volume_ratio'] = df['volume'] / df['volume_sma_20']
df['volume_osc'] = [Link](df['volume'], fast=12, slow=26, signal=9)
['PVO_12_26_9']
# --- CYCLICAL INDICATORS ---
df['ADX'] = [Link](df['high'], df['low'], df['close'], length=14)['ADX_14']
df['CCI'] = [Link](df['high'], df['low'], df['close'], length=20)
# --- PRICE ACTION FEATURES ---
df['price_change'] = df['close'].pct_change()
df['high_low_ratio'] = (df['high'] - df['low']) / df['close']
df['close_open_diff'] = (df['close'] - df['open']) / df['open']
df['body_size'] = abs(df['close'] - df['open']) / df['close']
# Candlestick patterns
df['CDL_DOJI'] = ta.cdl_doji(df['open'], df['high'], df['low'],
df['close'])
df['CDL_HAMMER'] = ta.cdl_hammer(df['open'], df['high'], df['low'],
df['close'])
df['CDL_ENGULFING'] = ta.cdl_engulfing(df['open'], df['high'], df['low'],
df['close'])
df['CDL_MORNING_STAR'] = ta.cdl_morningstar(df['open'], df['high'],
df['low'], df['close'])
df['CDL_EVENING_STAR'] = ta.cdl_eveningstar(df['open'], df['high'],
df['low'], df['close'])
# Order flow features
df['spread_ratio'] = (df['high'] - df['low']) / df['close'] # Proxy spread
# --- TARGET ENGINEERING ---
# Target 1: Perubahan harga 5 candle kedepan
df['future_price'] = df['close'].shift(-5)
[Link](subset=['future_price'], inplace=True)
# Target 2: Momentum berkelanjutan (1 jika 3 candle berikutnya naik)
df['momentum_3'] = ((df['close'].shift(-1) > df['close']) &
(df['close'].shift(-2) > df['close'].shift(-1)) &
(df['close'].shift(-3) > df['close'].shift(-
2))).astype(int)
# Target 3: Volatilitas terarah (1 jika ATR meningkat 20% dalam 5 candle)
df['atr_future'] = df['ATR'].shift(-5)
df['volatility_target'] = (df['atr_future'] > df['ATR'] * 1.2).astype(int)
# Target ensemble (gabungan ketiga target)
df['target'] = ((df['future_price'] > df['close'] * 1.001) |
(df['momentum_3'] == 1) |
(df['volatility_target'] == 1)).astype(int)
# --- FEATURE LIST ---
features = [
# Trend
'SMA_10', 'SMA_30', 'EMA_12', 'EMA_26', 'EMA_50',
'ichi_conv', 'ichi_base', 'ichi_spanA', 'ichi_spanB', 'ichi_cloud',
# Momentum
'RSI', 'RSI_30', 'stoch_k', 'stoch_d', 'stoch_diff',
'MACD', 'MACD_signal', 'MACD_hist', 'ao',
# Volatility
'ATR', 'ATR_30', 'Bollinger_upper', 'Bollinger_middle',
'Bollinger_lower',
'bollinger_pct', 'keltner_upper', 'keltner_lower',
# Volume
'OBV', 'VWAP', 'volume_ratio', 'volume_osc',
# Cyclical
'ADX', 'CCI',
# Price Action
'price_change', 'high_low_ratio', 'close_open_diff', 'body_size',
'CDL_DOJI', 'CDL_HAMMER', 'CDL_ENGULFING',
'CDL_MORNING_STAR', 'CDL_EVENING_STAR',
'spread_ratio'
]
return df, features
except Exception as e:
[Link](f"Error dalam perhitungan indikator: {e}", exc_info=True)
return df, []
def apply_feature_engineering(X):
"""Terapkan transformasi fitur tambahan"""
try:
# Interaksi fitur
X['rsi_stoch_interaction'] = X['RSI'] * X['stoch_k']
X['sma_ema_diff'] = X['SMA_10'] - X['EMA_12']
X['bollinger_keltner_ratio'] = (X['Bollinger_upper'] -
X['Bollinger_lower']) / \
(X['keltner_upper'] - X['keltner_lower'])
# Transformasi non-linear
X['rsi_squared'] = X['RSI'] ** 2
X['log_atr'] = np.log1p(X['ATR'])
# Fitur statistik
X['z_score'] = (X['close'] - X['close'].rolling(50).mean()) /
X['close'].rolling(50).std()
X['price_velocity'] = X['close'].pct_change(periods=3)
return X
except Exception as e:
[Link](f"Error feature engineering: {e}")
return X
async def fetch_realtime_data(symbol: str):
"""Ambil data real-time dan simpan di buffer dengan error handling"""
for attempt in range(MAX_RETRIES):
try:
ts = td.time_series(
symbol=symbol,
interval=INTERVAL,
outputsize=REALTIME_BUFFER_SIZE
).as_pandas().iloc[::-1]
if [Link] or len(ts) < 50:
[Link](f"Data tidak cukup untuk {symbol}, percobaan
{attempt+1}")
await [Link](2)
continue
# Simpan di buffer global
realtime_data[symbol] = ts
# Hitung indikator teknis
processed_df, features = calculate_advanced_indicators([Link]())
if not processed_df.empty and features:
symbol_features[symbol] = features
return processed_df.iloc[-1] # Return data terbaru
return None
except Exception as e:
[Link](f"Error ambil data real-time {symbol} (percobaan
{attempt+1}): {e}")
await [Link](1)
[Link](f"Gagal mengambil data real-time untuk {symbol} setelah
{MAX_RETRIES} percobaan")
return None
async def train_prediction_model(symbol: str):
"""Latih model dengan data historis dan real-time dengan validasi ketat"""
global is_model_trained, model_performance
[Link](f"Melatih model untuk {symbol}...")
try:
# Gabungkan data historis dan real-time
ts = td.time_series(
symbol=symbol,
interval=INTERVAL,
outputsize=OUTPUT_SIZE_HISTORY
).as_pandas().iloc[::-1]
if not realtime_data.get(symbol, None) is None:
ts = [Link]([ts, realtime_data[symbol]],
ignore_index=True).drop_duplicates()
if [Link] or len(ts) < 500:
[Link](f"Tidak ada data yang cukup untuk training {symbol}")
return None
# Hitung indikator teknis
ts, features = calculate_advanced_indicators(ts)
if [Link] or not features:
[Link]("Data tidak cukup untuk training setelah pengolahan.")
return None
# Terapkan feature engineering tambahan
ts = apply_feature_engineering(ts)
# Persiapkan data training
X = ts[features].fillna(0).replace([[Link], -[Link]], 0)
y = ts['target']
# Split data - 85% training, 15% validation
split_idx = int(len(X) * 0.85)
X_train, X_val = [Link][:split_idx], [Link][split_idx:]
y_train, y_val = [Link][:split_idx], [Link][split_idx:]
# Seleksi fitur
selector = SelectKBest(f_classif, k=30)
X_train_selected = selector.fit_transform(X_train, y_train)
X_val_selected = [Link](X_val)
# Latih model ensemble
ensemble_model.fit(X_train_selected, y_train)
# Evaluasi model
y_pred = ensemble_model.predict(X_val_selected)
precision = precision_score(y_val, y_pred)
recall = recall_score(y_val, y_pred)
f1 = f1_score(y_val, y_pred)
accuracy = accuracy_score(y_val, y_pred)
model_performance = {
'precision': precision,
'recall': recall,
'f1': f1,
'accuracy': accuracy
}
[Link](f"Model Performance - Accuracy: {accuracy:.2%}, Precision:
{precision:.2%}, Recall: {recall:.2%}, F1: {f1:.2%}")
is_model_trained = True
return features
except Exception as e:
[Link](f"Error training model {symbol}: {e}", exc_info=True)
is_model_trained = False
return None
def volatility_filter(latest_data):
"""Filter sinyal berdasarkan volatilitas dan volume"""
try:
atr = latest_data.get('ATR', 0)
volume_ratio = latest_data.get('volume_ratio', 0)
adx = latest_data.get('ADX', 0)
# Filter volatilitas rendah
if atr < MIN_ATR:
[Link]("Volatilitas terlalu rendah, sinyal diabaikan")
return False
# Filter volume rendah
if volume_ratio < VOLUME_THRESHOLD:
[Link]("Volume terlalu rendah, sinyal diabaikan")
return False
# Filter trend lemah
if adx < 20:
[Link]("Trend terlalu lemah, sinyal diabaikan")
return False
return True
except Exception as e:
[Link](f"Error volatility filter: {e}")
return True
async def generate_ensemble_prediction(symbol: str, latest_data: [Link]):
"""Buat prediksi ensemble dengan filter tambahan"""
if not is_model_trained:
return None, None, None
features = symbol_features.get(symbol, [])
if not features or latest_data.empty:
return None, None, None
# Terapkan feature engineering
try:
latest_df = [Link]([latest_data])
latest_df = apply_feature_engineering(latest_df)
latest_data = latest_df.iloc[0]
except Exception as e:
[Link](f"Error feature engineering real-time: {e}")
return None, None, None
# Siapkan data untuk prediksi
X = latest_data[features].fillna(0).replace([[Link], -[Link]],
0).[Link](1, -1)
# Buat prediksi
try:
prediction = ensemble_model.predict(X)[0]
probabilities = ensemble_model.predict_proba(X)[0]
confidence = [Link](probabilities) * 100
# Konversi ke sinyal trading
signal = "BUY" if prediction == 1 else "SELL"
# Terapkan filter volatilitas dan volume
if not volatility_filter(latest_data):
return "HOLD", confidence, latest_data['close']
return signal, confidence, latest_data['close']
except Exception as e:
[Link](f"Error prediksi: {e}")
return None, None, None
# --- FUNGSI BOT TELEGRAM (POWERFUL VERSION) ---
async def start(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
user = update.effective_user
keyboard = [
[InlineKeyboardButton("🚀 Dapatkan Sinyal", callback_data="get_signal")],
[InlineKeyboardButton("📈 Mulai Monitoring",
callback_data="start_monitoring"),
InlineKeyboardButton("🛑 Hentikan Monitoring",
callback_data="stop_monitoring")],
[InlineKeyboardButton("📊 Statistik Model", callback_data="model_stats"),
InlineKeyboardButton("⚙️ Setting Pair", callback_data="set_pair")]
]
reply_markup = InlineKeyboardMarkup(keyboard)
await [Link].reply_html(
f"🚀 <b>ULTIMATE AI TRADING ROBOT - SCALPING M5</b> 🚀\n\n"
f"Halo {user.mention_html()}!\n"
f"Sistem trading AI siap beroperasi dengan fitur:\n"
f"- Real-time market scanning\n"
f"- Ensemble machine learning (7 model)\n"
f"- Analisis sentimen pasar\n"
f"- Manajemen risiko terintegrasi\n\n"
f"Pair default: <b>{DEFAULT_TRADING_SYMBOL}</b>\n"
f"Interval: <b>{INTERVAL}</b>\n\n"
f"<i>Gunakan menu di bawah untuk mengontrol bot:</i>",
reply_markup=reply_markup
)
chat_id = [Link].chat_id
if 'job' not in context.chat_data:
job = context.job_queue.run_repeating(
send_scheduled_signal,
interval=SCHEDULE_SECONDS,
first=10,
chat_id=chat_id,
name=str(chat_id)
)
context.chat_data['job'] = job
[Link](f"Jadwal otomatis diaktifkan untuk chat {chat_id}")
async def button_handler(update: Update, context: ContextTypes.DEFAULT_TYPE) ->
None:
query = update.callback_query
await [Link]()
chat_id = [Link].chat_id
if [Link] == "get_signal":
await generate_signal(update, context)
elif [Link] == "start_monitoring":
active_monitoring[chat_id] = DEFAULT_TRADING_SYMBOL
await query.edit_message_text(
text=f"🔁 Memulai monitoring real-time untuk
{DEFAULT_TRADING_SYMBOL}...\n"
f"Update setiap 60 detik. Gunakan /set_pair untuk mengubah pair."
)
# Start monitoring job
if 'realtime_job' not in context.chat_data:
job = context.job_queue.run_repeating(
send_realtime_signal,
interval=60,
first=5,
chat_id=chat_id,
name=f"realtime_{chat_id}",
data={"symbol": DEFAULT_TRADING_SYMBOL}
)
context.chat_data['realtime_job'] = job
elif [Link] == "stop_monitoring":
if chat_id in active_monitoring:
del active_monitoring[chat_id]
if 'realtime_job' in context.chat_data:
context.chat_data['realtime_job'].schedule_removal()
del context.chat_data['realtime_job']
await query.edit_message_text(text="🛑 Monitoring real-time dihentikan.")
elif [Link] == "model_stats":
if model_performance:
stats_text = (
f"📊 <b>STATISTIK MODEL</b>\n\n"
f"🔹 Akurasi: {model_performance.get('accuracy', 0):.2%}\n"
f"🔹 Presisi: {model_performance.get('precision', 0):.2%}\n"
f"🔹 Recall: {model_performance.get('recall', 0):.2%}\n"
f"🔹 F1-Score: {model_performance.get('f1', 0):.2%}\n\n"
f"<i>Update terakhir: {[Link]().strftime('%Y-%m-%d %H:
%M')}</i>"
)
await query.edit_message_text(text=stats_text, parse_mode='HTML')
else:
await query.edit_message_text(text="❌ Statistik model belum tersedia.
Silakan latih model terlebih dahulu.")
elif [Link] == "set_pair":
await query.edit_message_text(
text="Silakan ketik pair yang ingin Anda monitor (contoh: GBPUSD,
EURUSD):"
)
context.user_data['awaiting_pair'] = True
async def handle_message(update: Update, context: ContextTypes.DEFAULT_TYPE) ->
None:
if context.user_data.get('awaiting_pair', False):
symbol = [Link]().upper()
if '/' in symbol:
symbol = [Link]('/', '')
# Validasi pair
if len(symbol) == 6 and [Link]():
context.user_data['selected_pair'] = symbol
context.user_data['awaiting_pair'] = False
# Update monitoring jika aktif
chat_id = [Link].chat_id
if chat_id in active_monitoring:
active_monitoring[chat_id] = symbol
if 'realtime_job' in context.chat_data:
context.chat_data['realtime_job'].schedule_removal()
job = context.job_queue.run_repeating(
send_realtime_signal,
interval=60,
first=5,
chat_id=chat_id,
name=f"realtime_{chat_id}",
data={"symbol": symbol}
)
context.chat_data['realtime_job'] = job
await [Link].reply_text(
f"Pair berhasil diubah menjadi {symbol}. Gunakan /start untuk
kembali ke menu utama."
)
else:
await [Link].reply_text(
"Format pair tidak valid. Silakan masukkan pair dalam format
seperti EURUSD atau GBPUSD."
)
async def generate_signal(update: Update, context: ContextTypes.DEFAULT_TYPE,
symbol: str = None):
if isinstance(update, Update):
chat_id = update.effective_chat.id
if update.callback_query:
await update.callback_query.answer()
else: # Untuk scheduled job
chat_id = [Link].chat_id
target_symbol = symbol or DEFAULT_TRADING_SYMBOL
if not symbol and [Link]:
target_symbol = [Link][0].upper()
try:
await [Link].send_message(chat_id, text=f"🔍 Menganalisis pasar
{target_symbol} (M5)...")
# Ambil dan proses data real-time
latest_data = await fetch_realtime_data(target_symbol)
if latest_data is None:
await [Link].send_message(chat_id, text="❌ Gagal mendapatkan data
market.")
return
current_price = latest_data['close']
# Latih model jika belum dilatih
if not is_model_trained:
await [Link].send_message(chat_id, text="🔄 Melatih model AI...")
features = await train_prediction_model(target_symbol)
if not features:
await [Link].send_message(chat_id, text="❌ Gagal melatih
model.")
return
# Prediksi dengan model ensemble
signal_ml, confidence_ml, price = await
generate_ensemble_prediction(target_symbol, latest_data)
if not signal_ml:
await [Link].send_message(chat_id, text="❌ Gagal membuat
prediksi.")
return
# --- PROMPT ANALISIS AI ---
tech_analysis = (
f"📊 <b>Analisis Teknikal {target_symbol} (M5)</b>\n"
f"• Harga: {price:.5f}\n"
f"• RSI: {latest_data.get('RSI', 0):.2f} (30:
{latest_data.get('RSI_30', 0):.2f})\n"
f"• Stochastic: K={latest_data.get('stoch_k', 0):.2f},
D={latest_data.get('stoch_d', 0):.2f}\n"
f"• MACD: {latest_data.get('MACD', 0):.5f} (Hist:
{latest_data.get('MACD_hist', 0):.5f})\n"
f"• ATR: {latest_data.get('ATR', 0):.5f}\n"
f"• Volume: {latest_data.get('volume_ratio', 0):.2f}x rata-rata\n"
f"• Prediksi AI: {signal_ml} ({confidence_ml:.1f}% confidence)"
)
prompt = (
f"Anda adalah trader profesional ahli scalping timeframe 5 menit.
Analisis pair {target_symbol} "
f"berdasarkan data berikut:\n{tech_analysis}\n\n"
f"Berikan rekomendasi trading dalam format JSON:\n"
f'{{\n "signal": "BUY/SELL/HOLD",\n "entry": price,\n "tp1": price,\
n "tp2": price,\n "sl": price,\n "confidence": percentage,\n "reason":
"Analisis singkat"\n}}'
f"\n\nPertimbangan:\n"
f"- Gunakan strategi scalping dengan target profit kecil (5-10 pips)\n"
f"- Faktor risiko/reward minimal 1:2\n"
f"- Sertakan 2 target profit (TP1, TP2)\n"
f"- Beri alasan singkat berdasarkan analisis teknikal dan sentimen
pasar"
)
# --- GENERATE ANALYSIS WITH AI ---
async def generate_ai_analysis(ai_client, model_name, prompt):
for _ in range(MAX_RETRIES):
try:
if ai_client == "gemini":
response = gemini_model.generate_content(prompt)
return [Link]([Link])
else: # groq
response = groq_client.[Link](
model=model_name,
messages=[{"role": "user", "content": prompt}],
response_format={"type": "json_object"},
temperature=0.2,
max_tokens=400
)
return [Link]([Link][0].[Link])
except Exception as e:
[Link](f"Error {ai_client} analysis: {e}")
return None
# Generate analysis with both AIs in parallel
gemini_task = asyncio.create_task(
generate_ai_analysis("gemini", "", prompt)
)
groq_task = asyncio.create_task(
generate_ai_analysis("groq", "llama3-70b-8192", prompt)
)
await [Link](gemini_task, groq_task)
gemini_analysis = gemini_task.result()
groq_analysis = groq_task.result()
# --- FINAL DECISION ---
def format_ai_analysis(analysis, name):
if not analysis:
return f"❌ Gagal mendapatkan analisis {name}"
return (
f"🔹 {name}:\n"
f"• Signal: {[Link]('signal', 'N/A')}\n"
f"• Entry: {[Link]('entry', 'N/A'):.5f}\n"
f"• TP1: {[Link]('tp1', 'N/A'):.5f} | TP2:
{[Link]('tp2', 'N/A'):.5f}\n"
f"• SL: {[Link]('sl', 'N/A'):.5f}\n"
f"• Confidence: {[Link]('confidence', 0)}%\n"
f"• Reason: {[Link]('reason', '')}"
)
# Create final summary
final_prompt = (
f"Buat kesimpulan trading akhir berdasarkan:\n"
f"1. Prediksi Machine Learning: {signal_ml} ({confidence_ml:.1f}%)\n"
f"2. Analisis Gemini: {[Link](gemini_analysis)}\n"
f"3. Analisis Groq: {[Link](groq_analysis)}\n\n"
f"Berikan rekomendasi final dalam format JSON:\n"
f'{{\n "final_signal": "BUY/SELL/HOLD",\n "final_entry": price,\n
"final_tp1": price,\n "final_tp2": price,\n "final_sl": price,\n
"final_confidence": percentage,\n "reason": "Alasan singkat"\n}}'
)
final_analysis = await generate_ai_analysis("groq", "llama3-70b-8192",
final_prompt)
# --- FORMAT FINAL MESSAGE ---
if final_analysis:
# Buat tombol aksi
keyboard = [
[InlineKeyboardButton("📈 Lihat Chart",
url=f"[Link]
'')}")],
[InlineKeyboardButton("🔄 Refresh Sinyal",
callback_data="get_signal")]
]
reply_markup = InlineKeyboardMarkup(keyboard)
final_message = (
f"🚀 <b>SIGNAL TRADING - {target_symbol}</b> 🚀\n"
f" {[Link]().strftime('%Y-%m-%d %H:%M UTC')}\n"
f"💰 <b>Harga Saat Ini: {current_price:.5f}</b>\n\n"
f"✅ <b>REKOMENDASI FINAL:</b>\n"
f"• Signal: <b>{final_analysis.get('final_signal', 'N/A')}</b>\n"
f"• Entry: <b>{final_analysis.get('final_entry', 'N/A'):.5f}</b>\n"
f"• TP1: {final_analysis.get('final_tp1', 'N/A'):.5f}\n"
f"• TP2: {final_analysis.get('final_tp2', 'N/A'):.5f}\n"
f"• SL: {final_analysis.get('final_sl', 'N/A'):.5f}\n"
f"• Confidence: {final_analysis.get('final_confidence', 0)}%\n"
f"• Reason: {final_analysis.get('reason', '')}\n\n"
f"📊 <b>DETAIL ANALISIS:</b>\n"
f"{format_ai_analysis(gemini_analysis, 'Gemini AI')}\n\n"
f"{format_ai_analysis(groq_analysis, 'Groq (Llama3)')}\n\n"
f"🤖 <b>PREDIKSI MACHINE LEARNING:</b>\n"
f"Signal: {signal_ml} ({confidence_ml:.1f}%)\n\n"
f"⚠️ <i>Disclaimer: Trading mengandung risiko. Gunakan analisis ini
sebagai referensi saja.</i>"
)
await [Link].send_message(
chat_id,
text=final_message,
parse_mode='HTML',
reply_markup=reply_markup
)
else:
await [Link].send_message(chat_id, text="❌ Gagal menghasilkan
sinyal akhir")
except Exception as e:
[Link](f"Error generate_signal: {e}")
await [Link].send_message(chat_id, text="❌ Terjadi kesalahan dalam
menghasilkan sinyal")
async def send_realtime_signal(context: ContextTypes.DEFAULT_TYPE):
"""Kirim sinyal real-time dengan harga terkini"""
job = [Link]
symbol = [Link]["symbol"]
chat_id = job.chat_id
# Ambil data terbaru
latest_data = await fetch_realtime_data(symbol)
if latest_data is None:
return
# Generate signal
signal, confidence, price = await generate_ensemble_prediction(symbol,
latest_data)
if signal and confidence and price:
# Format message dengan harga terkini
message = (
f"⚡ <b>REAL-TIME SIGNAL - {symbol}</b> ⚡\n"
f"🕒 {[Link]().strftime('%H:%M:%S')} UTC\n"
f"💰 <b>Harga: {price:.5f}</b>\n"
f"📢 Sinyal: <b>{signal}</b> ({confidence:.1f}%)\n"
f"📈 RSI: {latest_data.get('RSI', 0):.2f} | "
f"MACD: {latest_data.get('MACD', 0):.5f} | "
f"Volume: {latest_data.get('volume_ratio', 0):.2f}x\n\n"
f"<i>Gunakan /signal untuk analisis lengkap</i>"
)
# Buat tombol aksi cepat
keyboard = [[
InlineKeyboardButton("📊 Analisis Lengkap", callback_data="get_signal"),
InlineKeyboardButton("🛑 Stop Monitoring",
callback_data="stop_monitoring")
]]
reply_markup = InlineKeyboardMarkup(keyboard)
await [Link].send_message(
chat_id,
text=message,
parse_mode='HTML',
reply_markup=reply_markup
)
async def send_scheduled_signal(context: ContextTypes.DEFAULT_TYPE) -> None:
job = [Link]
class MockUpdate:
def __init__(self, cid):
[Link] = type('MockMessage', (), {'chat_id': cid, 'text': ''})()
self.effective_chat = type('MockChat', (), {'id': cid})()
await generate_signal(MockUpdate(job.chat_id), context,
symbol=DEFAULT_TRADING_SYMBOL)
async def error_handler(update: object, context: ContextTypes.DEFAULT_TYPE) ->
None:
[Link](msg="Exception while handling an update:", exc_info=[Link])
def main() -> None:
application = [Link]().token(TELEGRAM_BOT_TOKEN).build()
# Register handlers
application.add_handler(CommandHandler("start", start))
application.add_handler(CommandHandler("signal", generate_signal))
application.add_handler(CommandHandler("realtime", start))
application.add_handler(CommandHandler("stop_realtime", start))
application.add_handler(CommandHandler("set_pair", start))
application.add_handler(CallbackQueryHandler(button_handler))
application.add_handler(MessageHandler([Link] & ~[Link],
handle_message))
application.add_error_handler(error_handler)
[Link]("AI Trading Robot mulai berjalan...")
application.run_polling()
if __name__ == "__main__":
main()