import pandas as pd from dateutil.relativedelta import relativedelta from datetime import datetime import sqlite3 import time import requests import json from config import * from monitor import Monitor class MonitorCoin (Monitor): """자산(코인/주식/ETF) 모니터링 및 매수 실행 클래스""" def __init__(self, cooldown_file: str = 'coins_buy_time.json') -> None: super().__init__(cooldown_file) # ------------- Data fetch ------------- def get_coin_data(self, symbol: str, interval: int = 60, to: str | None = None, retries: int = 3) -> pd.DataFrame | None: for attempt in range(retries): try: if to is None: url = ("https://api.bithumb.com/v1/candles/minutes/{}?market=KRW-{}&count=200").format(interval, symbol) else: url = ("https://api.bithumb.com/v1/candles/minutes/{}?market=KRW-{}&count=200&to={}").format(interval, symbol, to) headers = {"accept": "application/json"} response = requests.get(url, headers=headers) json_data = json.loads(response.text) df_temp = pd.DataFrame(json_data) df_temp = df_temp.sort_index(ascending=False) if 'candle_date_time_kst' not in df_temp: return None data = pd.DataFrame() data['datetime'] = pd.to_datetime(df_temp['candle_date_time_kst'], format='%Y-%m-%dT%H:%M:%S') data['Open'] = df_temp['opening_price'] data['Close'] = df_temp['trade_price'] data['High'] = df_temp['high_price'] data['Low'] = df_temp['low_price'] data['Volume'] = df_temp['candle_acc_trade_volume'] data = data.set_index('datetime') data = data.astype(float) data["datetime"] = data.index if not data.empty: return data print(f"No data received for {symbol}, attempt {attempt + 1}") time.sleep(0.5) except Exception as e: print(f"Attempt {attempt + 1} failed for {symbol}: {str(e)}") if attempt < retries - 1: time.sleep(5) continue return None def get_coin_more_data(self, symbol: str, interval: int, bong_count: int = 3000) -> pd.DataFrame: to = datetime.now() data: pd.DataFrame | None = None while data is None or len(data) < bong_count: if data is None: data = self.get_coin_data(symbol, interval, to.strftime("%Y-%m-%d %H:%M:%S")) else: previous_count = len(data) df = self.get_coin_data(symbol, interval, to.strftime("%Y-%m-%d %H:%M:%S")) data = pd.concat([data, df], ignore_index=True) if previous_count == len(data): break time.sleep(0.3) to = to - relativedelta(minutes=interval * 200) data = data.set_index('datetime') data = data.sort_index() data = data.drop_duplicates(keep='first') data["datetime"] = data.index return data def get_coin_saved_data(self, symbol: str, interval: int, data: pd.DataFrame) -> pd.DataFrame: conn = sqlite3.connect('coins.db') cursor = conn.cursor() for i in range(1, len(data)): cursor.execute( "SELECT * from " + symbol + " where CODE = ? and ymdhms = ? and interval = ?", (symbol, data['datetime'].iloc[-i].strftime('%Y-%m-%d %H:%M:%S'), interval), ) arr = cursor.fetchone() if not arr: cursor.execute( "INSERT INTO " + symbol + " (interval, CODE, NAME, ymdhms, ymd, hms, close, open, high, low, volume) VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", ( interval, symbol, KR_COINS[symbol], data['datetime'].iloc[-i].strftime('%Y-%m-%d %H:%M:%S'), data['datetime'].iloc[-i].strftime('%Y%m%d'), data['datetime'].iloc[-i].strftime('%H%M%S'), data['Close'].iloc[-i], data['Open'].iloc[-i], data['High'].iloc[-i], data['Low'].iloc[-i], data['Volume'].iloc[-i], ), ) else: break cursor.execute( "select * from (SELECT Open,Close,High,Low,Volume,ymdhms as datetime from " + symbol + " order by ymdhms desc limit 5000) subquery order by datetime" ) result = cursor.fetchall() conn.commit() cursor.close() conn.close() df = pd.DataFrame(result) df.columns = ['Open', 'Close', 'High', 'Low', 'Volume', 'datetime'] df = df.set_index('datetime') df = df.sort_index() df['datetime'] = df.index return df def get_coin_some_data(self, symbol: str, interval: int) -> pd.DataFrame: data = self.get_coin_data(symbol, interval) data_1 = self.get_coin_data(symbol, interval=1) data_1.at[data_1.index[-1], 'Volume'] = data_1['Volume'].iloc[-1] * 60 saved_data = self.get_coin_saved_data(symbol, interval, data) data = pd.concat([data, saved_data, data_1.iloc[[-1]]], ignore_index=True) data['datetime'] = pd.to_datetime(data['datetime'], format='%Y-%m-%d %H:%M:%S') data = data.set_index('datetime') data = data.sort_index() data = data.drop_duplicates(keep='first') data["datetime"] = data.index return data def monitor_coins(self, symbol) -> None: print("[{}] {}".format(datetime.now().strftime('%Y-%m-%d %H:%M:%S'), symbol)) interval = 60 data = self.get_coin_some_data(symbol, interval) if data is not None and not data.empty: try: data = self.calculate_technical_indicators(data) recent_data = self.check_buy_point(symbol, data) if recent_data['buy_point'].iloc[-1] != 1: return buy_success = self.buy_ticker(symbol, recent_data) if not buy_success: return except Exception as e: print(f"Error processing data for {symbol}: {str(e)}") else: print(f"Data for {symbol} is empty or None.") time.sleep(0.5) return # ------------- Scheduler ------------- def run_schedule(self, ticker) -> None: while True: self.monitor_coins(symbol) time.sleep(1) if __name__ == "__main__": symbol = 'BONK' cooldown_file = './resources/coins_buy_'+symbol+'.json' MonitorCoin(cooldown_file).run_schedule(symbol)