init
This commit is contained in:
42
config.py
42
config.py
@@ -50,6 +50,48 @@ KR_COINS = {
|
|||||||
"XRP": "XRP"
|
"XRP": "XRP"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
KR_COINS_1 = {
|
||||||
|
"ADA": "ADA",
|
||||||
|
"APE": "ApeCoin",
|
||||||
|
"ARB": "Arbitrum",
|
||||||
|
"BONK": "BONK",
|
||||||
|
}
|
||||||
|
|
||||||
|
KR_COINS_2 = {
|
||||||
|
"ENA": "ETHENA",
|
||||||
|
"HBAR": "HBAR",
|
||||||
|
"KAIA": "KAIA",
|
||||||
|
"LINK": "Chainlink",
|
||||||
|
}
|
||||||
|
|
||||||
|
KR_COINS_3 = {
|
||||||
|
"ONDO": "ONDO",
|
||||||
|
"PENGU": "Pudgy Penguins",
|
||||||
|
"PEPE": "PEPE",
|
||||||
|
"POL": "POL",
|
||||||
|
}
|
||||||
|
|
||||||
|
KR_COINS_4 = {
|
||||||
|
"SAND": "Sandbox",
|
||||||
|
"SEI": "SEI",
|
||||||
|
"SHIB": "Shiba Inu",
|
||||||
|
"STORJ": "Storj",
|
||||||
|
}
|
||||||
|
|
||||||
|
KR_COINS_5 = {
|
||||||
|
"SUI": "Sui Network",
|
||||||
|
"TON": "Toncoin",
|
||||||
|
"TRX": "TRON",
|
||||||
|
"UXLINK": "UXLINK",
|
||||||
|
}
|
||||||
|
|
||||||
|
KR_COINS_6 = {
|
||||||
|
"VIRTUAL": "Virtuals Protocol",
|
||||||
|
"WLD": "Worldcoin",
|
||||||
|
"XLM": "XLM",
|
||||||
|
"XRP": "XRP"
|
||||||
|
}
|
||||||
|
|
||||||
# 주식 설정
|
# 주식 설정
|
||||||
US_STOCKS = {
|
US_STOCKS = {
|
||||||
'VOO': 'Vanguard S&P 500 ETF',
|
'VOO': 'Vanguard S&P 500 ETF',
|
||||||
|
|||||||
161
monitor_coin_1.py
Normal file
161
monitor_coin_1.py
Normal file
@@ -0,0 +1,161 @@
|
|||||||
|
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_1[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) -> None:
|
||||||
|
print("[{}] KRW COINs: {}".format(datetime.now().strftime('%Y-%m-%d %H:%M:%S'), ','.join(KR_COINS_1.keys())))
|
||||||
|
for symbol in KR_COINS_1:
|
||||||
|
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:
|
||||||
|
continue
|
||||||
|
buy_success = self.buy_ticker(symbol, recent_data)
|
||||||
|
if not buy_success:
|
||||||
|
continue
|
||||||
|
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) -> None:
|
||||||
|
|
||||||
|
while True:
|
||||||
|
self.monitor_coins()
|
||||||
|
time.sleep(10)
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
MonitorCoin(cooldown_file='coins_buy_time_1.json').run_schedule()
|
||||||
161
monitor_coin_2.py
Normal file
161
monitor_coin_2.py
Normal file
@@ -0,0 +1,161 @@
|
|||||||
|
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_2[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) -> None:
|
||||||
|
print("[{}] KRW COINs: {}".format(datetime.now().strftime('%Y-%m-%d %H:%M:%S'), ','.join(KR_COINS_2.keys())))
|
||||||
|
for symbol in KR_COINS_2:
|
||||||
|
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:
|
||||||
|
continue
|
||||||
|
buy_success = self.buy_ticker(symbol, recent_data)
|
||||||
|
if not buy_success:
|
||||||
|
continue
|
||||||
|
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) -> None:
|
||||||
|
|
||||||
|
while True:
|
||||||
|
self.monitor_coins()
|
||||||
|
time.sleep(10)
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
MonitorCoin(cooldown_file='coins_buy_time_2.json').run_schedule()
|
||||||
161
monitor_coin_3.py
Normal file
161
monitor_coin_3.py
Normal file
@@ -0,0 +1,161 @@
|
|||||||
|
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_3[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) -> None:
|
||||||
|
print("[{}] KRW COINs: {}".format(datetime.now().strftime('%Y-%m-%d %H:%M:%S'), ','.join(KR_COINS_3.keys())))
|
||||||
|
for symbol in KR_COINS_3:
|
||||||
|
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:
|
||||||
|
continue
|
||||||
|
buy_success = self.buy_ticker(symbol, recent_data)
|
||||||
|
if not buy_success:
|
||||||
|
continue
|
||||||
|
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) -> None:
|
||||||
|
|
||||||
|
while True:
|
||||||
|
self.monitor_coins()
|
||||||
|
time.sleep(10)
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
MonitorCoin(cooldown_file='coins_buy_time_3.json').run_schedule()
|
||||||
161
monitor_coin_4.py
Normal file
161
monitor_coin_4.py
Normal file
@@ -0,0 +1,161 @@
|
|||||||
|
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_4[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) -> None:
|
||||||
|
print("[{}] KRW COINs: {}".format(datetime.now().strftime('%Y-%m-%d %H:%M:%S'), ','.join(KR_COINS_4.keys())))
|
||||||
|
for symbol in KR_COINS_4:
|
||||||
|
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:
|
||||||
|
continue
|
||||||
|
buy_success = self.buy_ticker(symbol, recent_data)
|
||||||
|
if not buy_success:
|
||||||
|
continue
|
||||||
|
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) -> None:
|
||||||
|
|
||||||
|
while True:
|
||||||
|
self.monitor_coins()
|
||||||
|
time.sleep(10)
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
MonitorCoin(cooldown_file='coins_buy_time_4.json').run_schedule()
|
||||||
161
monitor_coin_5.py
Normal file
161
monitor_coin_5.py
Normal file
@@ -0,0 +1,161 @@
|
|||||||
|
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_5[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) -> None:
|
||||||
|
print("[{}] KRW COINs: {}".format(datetime.now().strftime('%Y-%m-%d %H:%M:%S'), ','.join(KR_COINS_5.keys())))
|
||||||
|
for symbol in KR_COINS_5:
|
||||||
|
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:
|
||||||
|
continue
|
||||||
|
buy_success = self.buy_ticker(symbol, recent_data)
|
||||||
|
if not buy_success:
|
||||||
|
continue
|
||||||
|
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) -> None:
|
||||||
|
|
||||||
|
while True:
|
||||||
|
self.monitor_coins()
|
||||||
|
time.sleep(10)
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
MonitorCoin(cooldown_file='coins_buy_time_5.json').run_schedule()
|
||||||
161
monitor_coin_6.py
Normal file
161
monitor_coin_6.py
Normal file
@@ -0,0 +1,161 @@
|
|||||||
|
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_6[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) -> None:
|
||||||
|
print("[{}] KRW COINs: {}".format(datetime.now().strftime('%Y-%m-%d %H:%M:%S'), ','.join(KR_COINS_6.keys())))
|
||||||
|
for symbol in KR_COINS_6:
|
||||||
|
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:
|
||||||
|
continue
|
||||||
|
buy_success = self.buy_ticker(symbol, recent_data)
|
||||||
|
if not buy_success:
|
||||||
|
continue
|
||||||
|
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) -> None:
|
||||||
|
|
||||||
|
while True:
|
||||||
|
self.monitor_coins()
|
||||||
|
time.sleep(10)
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
MonitorCoin(cooldown_file='coins_buy_time_6.json').run_schedule()
|
||||||
Reference in New Issue
Block a user