Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #!/usr/bin/env python3
- import requests
- import json
- import pandas as pd
- import matplotlib.pyplot as plt
- import matplotlib.dates as mdates
- import asyncio
- from datetime import datetime
- from mplfinance.original_flavor import candlestick_ohlc
- from telegram import Update, ReplyKeyboardMarkup
- from telegram.ext import (
- Application,
- CommandHandler,
- MessageHandler,
- filters,
- ContextTypes
- )
- class CryptoAnalyzer:
- def __init__(self):
- self.config = self.load_config()
- self.base_url = "https://indodax.com/api"
- self.scheduler = None
- """=======================
- MODUL KONFIGURASI
- ======================="""
- def load_config(self):
- try:
- with open('config.json') as f:
- return json.load(f)
- except Exception as e:
- print(f"Error loading config: {e}")
- exit(1)
- """=======================
- MODUL DATA MARKET
- ======================="""
- def fetch_market_data(self, pair='btc_idr', timeframe='1h', limit=100):
- """Ambil data OHLC dari API Indodax"""
- try:
- response = requests.get(f"{self.base_url}/{pair}/trades")
- response.raise_for_status()
- trades = response.json()
- df = pd.DataFrame(trades)
- df['date'] = pd.to_datetime(df['date'].astype(float), unit='s')
- df = df.set_index('date')
- return df['price'].resample(timeframe).ohlc().reset_index()
- except Exception as e:
- print(f"Error fetching data: {e}")
- return None
- """=======================
- MODUL ANALISIS TEKNIKAL
- ======================="""
- def detect_patterns(self, ohlc_data):
- patterns = []
- if len(ohlc_data) < 5: # Minimum 5 candle untuk analisis
- return patterns
- # Prepare data
- closes = ohlc_data['close'].values
- highs = ohlc_data['high'].values
- lows = ohlc_data['low'].values
- opens = ohlc_data['open'].values
- # 1. Pola Reversal Bearish
- if self._is_double_top(highs):
- patterns.append('Bearish Double Top')
- if self._is_head_and_shoulders(highs, lows):
- patterns.append('Bearish Head and Shoulders')
- if self._is_rising_wedge(ohlc_data):
- patterns.append('Bearish Rising Wedge')
- if self._is_expanding_triangle(highs, lows, bearish=True):
- patterns.append('Bearish Expanding Triangle')
- if self._is_triple_top(highs):
- patterns.append('Bearish Triple Top')
- # 2. Pola Reversal Bullish
- if self._is_double_bottom(lows):
- patterns.append('Bullish Double Bottom')
- if self._is_inverse_head_and_shoulders(highs, lows):
- patterns.append('Bullish Inverted H&S')
- if self._is_falling_wedge(ohlc_data):
- patterns.append('Bullish Falling Wedge')
- if self._is_expanding_triangle(highs, lows, bearish=False):
- patterns.append('Bullish Expanding Triangle')
- if self._is_triple_bottom(lows):
- patterns.append('Bullish Triple Bottom')
- # 3. Pola Continuation
- if self._is_bullish_flag(ohlc_data):
- patterns.append('Bullish Flag')
- if self._is_bullish_pennant(ohlc_data):
- patterns.append('Bullish Pennant')
- if self._is_ascending_triangle(highs, lows):
- patterns.append('Ascending Triangle')
- if self._is_descending_triangle(highs, lows):
- patterns.append('Descending Triangle')
- if self._is_symmetrical_triangle(highs, lows):
- patterns.append('Symmetrical Triangle')
- # 4. Pola Candlestick (3 candle terakhir)
- if len(ohlc_data) >= 3:
- latest_candles = ohlc_data.iloc[-3:]
- patterns.extend(self._detect_candlestick_patterns(latest_candles))
- return patterns
- """=======================
- MODUL ANALISIS TEKNIKAL - POLA UTAMA
- ======================="""
- def _is_double_top(self, highs, lookback=20, tolerance=0.02):
- if len(highs) < lookback:
- return False
- peak1 = max(highs[-lookback:-lookback//2])
- peak2 = max(highs[-lookback//2:])
- return abs(peak1 - peak2) < tolerance * peak1
- def _is_head_and_shoulders(self, highs, lows, lookback=30):
- """Deteksi Head and Shoulders pattern"""
- if len(highs) < lookback:
- return False
- left_shoulder = max(highs[-lookback:-lookback//2])
- head = max(highs[-lookback//2:-lookback//4])
- right_shoulder = max(highs[-lookback//4:])
- neckline = (min(lows[-lookback:-lookback//2]) + min(lows[-lookback//4:])) / 2
- return (left_shoulder < head and right_shoulder < head and right_shoulder > neckline and left_shoulder > neckline)
- # Implement other pattern detection methods similarly...
- """=======================
- DETEKSI POLA CHART
- ======================="""
- def _is_double_top(self, highs, lookback=20, tolerance=0.02):
- """Detect double top pattern"""
- if len(highs) < lookback:
- return False
- peak1 = max(highs[-lookback:-lookback//2])
- peak2 = max(highs[-lookback//2:])
- return abs(peak1 - peak2) < tolerance * peak1
- def _is_head_and_shoulders(self, highs, lows, lookback=30):
- # Implementasi sederhana H&S pattern
- if len(highs) < lookback:
- return False
- left_shoulder = highs[-lookback:-lookback//2].max()
- head = highs[-lookback//2:-lookback//4].max()
- right_shoulder = highs[-lookback//4:].max()
- neckline = (lows[-lookback:-lookback//2].min() +
- lows[-lookback//4:].min()) / 2
- return (left_shoulder < head and right_shoulder < head and
- right_shoulder > neckline and left_shoulder > neckline)
- def _is_rising_wedge(self, ohlc_data, lookback=15):
- highs = ohlc_data['high'].values[-lookback:]
- lows = ohlc_data['low'].values[-lookback:]
- # Hitung garis trend
- high_slope = (highs[-1] - highs[0]) / lookback
- low_slope = (lows[-1] - lows[0]) / lookback
- return high_slope > low_slope > 0 and (highs[-1] - lows[-1]) < (highs[0] - lows[0])
- """=======================
- DETEKSI POLA CANDLESTICK
- ======================="""
- def detect_patterns(self, ohlc_data):
- """Detect all technical patterns"""
- patterns = []
- if len(ohlc_data) < 5: # Minimum 5 candles needed
- return patterns
- # Prepare data
- closes = ohlc_data['close'].values
- highs = ohlc_data['high'].values
- lows = ohlc_data['low'].values
- opens = ohlc_data['open'].values
- # Bearish Patterns
- if self._is_double_top(highs):
- patterns.append('Bearish Double Top')
- if self._is_head_and_shoulders(highs, lows):
- patterns.append('Bearish Head and Shoulders')
- # Bullish Patterns
- if self._is_double_bottom(lows):
- patterns.append('Bullish Double Bottom')
- if self._is_inverse_head_and_shoulders(highs, lows):
- patterns.append('Bullish Inverted H&S')
- # Candlestick Patterns (last 3 candles)
- if len(ohlc_data) >= 3:
- latest = ohlc_data.iloc[-3:]
- if self._is_three_black_crows(latest):
- patterns.append('Three Black Crows')
- if self._is_morning_star(latest.iloc[0], latest.iloc[1], latest.iloc[2]):
- patterns.append('Morning Star')
- return patterns
- def _is_double_top(self, highs, lookback=20, tolerance=0.02):
- """Detect double top pattern"""
- if len(highs) < lookback:
- return False
- peak1 = max(highs[-lookback:-lookback//2])
- peak2 = max(highs[-lookback//2:])
- return abs(peak1 - peak2) < tolerance * peak1
- def _is_double_bottom(self, lows, lookback=20, tolerance=0.02):
- """Detect double bottom pattern"""
- if len(lows) < lookback:
- return False
- trough1 = min(lows[-lookback:-lookback//2])
- trough2 = min(lows[-lookback//2:])
- return abs(trough1 - trough2) < tolerance * trough1
- def _is_three_black_crows(self, candles):
- """Detect three black crows pattern"""
- return (all(c['close'] < c['open'] for c in candles) and
- candles.iloc[0]['open'] > candles.iloc[1]['open'] > candles.iloc[2]['open'] and
- candles.iloc[0]['close'] > candles.iloc[1]['close'] > candles.iloc[2]['close'])
- def _is_morning_star(self, c1, c2, c3):
- """Detect morning star pattern"""
- return (c1['close'] < c1['open'] and # First candle is bearish
- abs(c2['close'] - c2['open']) < 0.01 * c2['open'] and # Second is doji
- c3['close'] > c3['open'] and # Third is bullish
- c3['close'] > c1['close']) # Closes above first candle
- def _is_evening_star(self, c1, c2, c3):
- return (c1['close'] > c1['open'] and # Candle hijau
- abs(c2['close'] - c2['open']) < 0.01 * c2['open'] and # Doji
- c3['close'] < c3['open'] and # Candle merah
- c3['close'] < c1['close'] * 0.98) # Penutupan di bawah 98% sebelumnya
- def _is_three_black_crows(self, candles):
- return all(c['close'] < c['open'] for c in candles) and (
- candles[0]['open'] > candles[1]['open'] > candles[2]['open'] and
- candles[0]['close'] > candles[1]['close'] > candles[2]['close'])
- """=======================
- MODUL VISUALISASI
- ======================="""
- def create_chart(self, ohlc_data, patterns=None):
- """Buat grafik candlestick dengan anotasi pola"""
- plt.figure(figsize=(14, 7))
- ax = plt.subplot()
- # Plot candlestick
- ohlc_data['date_num'] = mdates.date2num(ohlc_data['date'])
- candlestick_ohlc(
- ax,
- ohlc_data[['date_num', 'open', 'high', 'low', 'close']].values,
- width=0.6,
- colorup='#27ae60',
- colordown='#c0392b'
- )
- # Anotasi untuk pola terdeteksi
- if patterns:
- self._annotate_patterns(ax, ohlc_data, patterns)
- ax.xaxis.set_major_formatter(mdates.DateFormatter('%d-%m %H:%M'))
- plt.xticks(rotation=45)
- plt.title('Analisis BTC/IDR - ' + datetime.now().strftime('%d %b %Y'))
- plt.tight_layout()
- chart_path = 'latest_chart.png'
- plt.savefig(chart_path, dpi=100)
- plt.close()
- return chart_path
- def _annotate_patterns(self, ax, ohlc_data, patterns):
- """Tambahkan anotasi pola ke chart"""
- for pattern in patterns:
- if 'Double Top' in pattern:
- self._mark_double_top(ax, ohlc_data)
- elif 'Head and Shoulders' in pattern:
- self._mark_head_and_shoulders(ax, ohlc_data)
- # Tambahkan anotasi untuk pola lainnya...
- """=======================
- MODUL LAPORAN
- ======================="""
- def generate_report(self, patterns, ohlc_data):
- """Buat laporan analisis dengan klasifikasi pola"""
- current_price = ohlc_data.iloc[-1]['close']
- report = {
- 'timestamp': datetime.now().strftime('%d-%m-%Y %H:%M'),
- 'current_price': f"Rp {current_price:,.0f}",
- 'volatility': f"{self._calculate_volatility(ohlc_data):.2f}%",
- 'patterns': self._classify_patterns(patterns),
- 'recommendation': self._generate_recommendation(patterns)
- }
- return report
- def _classify_patterns(self, patterns):
- """Klasifikasikan pola berdasarkan jenisnya"""
- classified = {
- 'Reversal Bullish': [],
- 'Reversal Bearish': [],
- 'Continuation': [],
- 'Candlestick': []
- }
- pattern_types = {
- 'Bullish Double Bottom': 'Reversal Bullish',
- 'Bullish Inverted H&S': 'Reversal Bullish',
- 'Morning Star': 'Candlestick',
- 'Bearish Double Top': 'Reversal Bearish',
- 'Bearish Head and Shoulders': 'Reversal Bearish',
- 'Evening Star': 'Candlestick',
- 'Bullish Flag': 'Continuation',
- 'Ascending Triangle': 'Continuation'
- # Tambahkan mapping lainnya...
- }
- for pattern in patterns:
- for p_type, p_list in pattern_types.items():
- if p_type in pattern:
- classified[p_list].append(pattern)
- break
- return classified
- def _generate_recommendation(self, patterns):
- """Buat rekomendasi berdasarkan pola terdeteksi"""
- strength = 0
- for pattern in patterns:
- if 'Bullish' in pattern:
- strength += 1
- elif 'Bearish' in pattern:
- strength -= 1
- if strength >= 3:
- return "🟢 STRONG BUY (Bullish Strong)"
- elif strength >= 1:
- return "🟢 BUY (Bullish)"
- elif strength <= -3:
- return "🔴 STRONG SELL (Bearish Strong)"
- elif strength <= -1:
- return "🔴 SELL (Bearish)"
- return "🟡 HOLD (Neutral)"
- """=======================
- MODUL TELEGRAM
- ======================="""
- async def send_report(self, context):
- """Kirim laporan ke Telegram"""
- try:
- # Dapatkan data dan buat laporan
- ohlc_data = self.fetch_market_data()
- patterns = self.detect_patterns(ohlc_data)
- chart_path = self.create_chart(ohlc_data)
- report = self.generate_report(patterns, ohlc_data)
- # Format pesan
- message = (
- f"🕒 **Laporan {report['timestamp']}**\n"
- f"📊 Pola Terdeteksi: {', '.join(report['patterns']) or 'Tidak ada'}\n"
- f"💰 Harga Terkini: {report['current_price']}\n"
- f"📈 Volatilitas: {report['volatility']}\n"
- f"📌 Rekomendasi: {report['recommendation']}"
- )
- # Kirim melalui Telegram
- await context.bot.send_photo(
- chat_id=self.config['telegram']['chat_id'],
- photo=open(chart_path, 'rb'),
- caption=message,
- parse_mode='Markdown'
- )
- except Exception as e:
- print(f"Error sending report: {e}")
- """=======================
- MODUL SCHEDULER
- ======================="""
- async def schedule_updates(self, context):
- """Jadwalkan pengiriman setiap 1 jam"""
- while True:
- await self.send_report(context)
- await asyncio.sleep(3600) # 1 jam
- async def start(self, update: Update, context: ContextTypes.DEFAULT_TYPE):
- """Handler command /start"""
- await update.message.reply_text(
- "Bot Analisis Crypto Aktif!\n"
- "Laporan akan dikirim otomatis setiap 1 jam",
- reply_markup=self._main_menu()
- )
- # Mulai scheduler
- asyncio.create_task(self.schedule_updates(context))
- def _main_menu(self):
- """Tampilan menu utama"""
- return ReplyKeyboardMarkup(
- [["🔄 Update Sekarang", "⚙️ Settings"]],
- resize_keyboard=True
- )
- """=======================
- MAIN PROGRAM
- ======================="""
- def run(self):
- application = Application.builder().token(self.config['telegram']['token']).build()
- # Registrasi handler
- application.add_handler(CommandHandler("start", self.start))
- application.add_handler(MessageHandler(filters.Regex("🔄 Update Sekarang"), self.send_report))
- application.run_polling()
- if __name__ == "__main__":
- analyzer = CryptoAnalyzer()
- analyzer.run()
Advertisement
Add Comment
Please, Sign In to add comment