183 lines
6.8 KiB
Python
183 lines
6.8 KiB
Python
import re
|
|
import os
|
|
import time
|
|
import psutil
|
|
import sqlite3
|
|
from datetime import datetime, timedelta
|
|
|
|
from hts.HTS import HTS
|
|
from hts.OrderType import OrderType
|
|
|
|
from hts.BuySellChecker import BuySellChecker
|
|
from hts.OrderChecker import OrderChecker
|
|
from stock.util.TelegramBot import TelegramBot
|
|
from stock.analysis.StockStatus import StockStatus
|
|
|
|
class HTS_Stocks (HTS):
|
|
|
|
RESOURCE_PATH = None
|
|
orderChecker = None
|
|
buySellChecker = None
|
|
labelChecker = None
|
|
bot = None
|
|
stockStatus = None
|
|
analyzed_day = None
|
|
MAX_BUY_PRICE = None
|
|
|
|
conn_stock = None
|
|
cursor_stock = None
|
|
|
|
def __init__(self, RESOURCE_PATH):
|
|
super().__init__(RESOURCE_PATH)
|
|
self.bot = TelegramBot()
|
|
|
|
self.RESOURCE_PATH = RESOURCE_PATH
|
|
self.stockStatus = StockStatus(RESOURCE_PATH)
|
|
|
|
self.buySellChecker = BuySellChecker(RESOURCE_PATH)
|
|
self.orderChecker = OrderChecker(self.RESOURCE_PATH, "STOCK")
|
|
|
|
self.analyzed_day = 120
|
|
self.MAX_BUY_PRICE = 300000
|
|
|
|
return
|
|
|
|
def connect2StockDB(self):
|
|
|
|
self.conn_stock = sqlite3.connect(os.path.join(self.RESOURCE_PATH, "stock.db"))
|
|
self.cursor_stock = self.conn_stock.cursor()
|
|
|
|
return
|
|
|
|
def disconnectStockDB(self):
|
|
|
|
self.cursor_stock.close()
|
|
self.conn_stock.close()
|
|
return
|
|
|
|
def sellStocks(self, stock_code=None):
|
|
check = False
|
|
jangoDic = self.requstJango()
|
|
if jangoDic and len(jangoDic.keys()) > 0:
|
|
for code in jangoDic:
|
|
if stock_code is not None:
|
|
if code == "A" + stock_code:
|
|
if jangoDic[code]['매도가능'] > 0:
|
|
if 3.0 < jangoDic[code]['평가손익']:
|
|
self.requestOrder(OrderType.sell, code[1:], jangoDic[code]['매도가능'], jangoDic[code]['현재가'])
|
|
self.bot.sendMsg("Profit {} ({}): {:.2f} ({:.2f}%)".format(jangoDic[code]['종목명'], jangoDic[code]['종목코드'], (jangoDic[code]['현재가']-jangoDic[code]['장부가'])*jangoDic[code]['잔고수량'], jangoDic[code]['평가손익']))
|
|
check = True
|
|
else:
|
|
if 10.0 < jangoDic[code]['평가손익']:
|
|
self.requestOrder(OrderType.sell, code[1:], jangoDic[code]['매도가능'], jangoDic[code]['현재가'])
|
|
self.bot.sendMsg("Profit {} ({}): {:.2f} ({:.2f}%)".format(jangoDic[code]['종목명'], jangoDic[code]['종목코드'], (jangoDic[code]['현재가']-jangoDic[code]['장부가'])*jangoDic[code]['잔고수량'], jangoDic[code]['평가손익']))
|
|
check = True
|
|
return check
|
|
|
|
def buyRealTime(self, today, n = 200):
|
|
print ("START...")
|
|
THIS_TIME = datetime.now()
|
|
|
|
today_stock = self.get_today_stock()
|
|
|
|
while datetime.strptime(today + " 070000", '%Y%m%d %H%M%S') < THIS_TIME < datetime.strptime(today + " 153100", '%Y%m%d %H%M%S'):
|
|
|
|
# 1515 까지만 매수를 시도한다.
|
|
if datetime.strptime(today + " 080000", '%Y%m%d %H%M%S') < THIS_TIME < datetime.strptime(today + " 151500", '%Y%m%d %H%M%S'):
|
|
|
|
if len(today_stock) < 1:
|
|
self.sellStocks()
|
|
time.sleep(600)
|
|
continue
|
|
|
|
buy_stock = []
|
|
for idx, stock_code in enumerate(today_stock):
|
|
|
|
time.sleep(0.1)
|
|
|
|
stock = self.stockStatus.fetchLastData(self.cursor_stock, stock_code, n)
|
|
|
|
self.getRealTime_DailyCheck(today, stock_code, stock)
|
|
data = self.stockStatus.analyze(stock, self.analyzed_day)
|
|
|
|
|
|
# 매도
|
|
if not data['avg60'][-1] < data['avg20'][-1] < data['avg5'][-1]:
|
|
self.sellStocks(stock_code)
|
|
|
|
# 매수
|
|
bs_buy_price = data["close"][-1]
|
|
|
|
if 150000 < bs_buy_price:
|
|
buy_count = 1
|
|
else:
|
|
buy_count = 150000 // bs_buy_price
|
|
|
|
# 매수를 주문한다.
|
|
orderNum = self.requestOrder(OrderType.buy, stock_code, buy_count, bs_buy_price)
|
|
self.orderChecker.buy(today, "A" + stock_code, buy_count, bs_buy_price, orderNum)
|
|
|
|
# bot에 메시지를 보냄
|
|
self.bot.sendMsg('BUY {} {} ({})'.format(stock_code, bs_buy_price, buy_count))
|
|
|
|
buy_stock.append( stock_code )
|
|
|
|
# 로그 출력
|
|
print("BUY", THIS_TIME.strftime('%Y%m%d %H%M%S'), orderNum, stock_code, '', bs_buy_price, buy_count)
|
|
|
|
# 매수 후 제거
|
|
for stock_code in buy_stock:
|
|
today_stock.remove(stock_code)
|
|
|
|
if int(THIS_TIME.strftime("%M")) in (10, 40):
|
|
vm = psutil.virtual_memory()
|
|
vm_item = dict()
|
|
vm_item['free'] = vm.available // (1024 * 1024)
|
|
vm_item['idle'] = vm.available / vm.total * 100
|
|
hts.bot.sendMsg("Alive... close: {}, mem: {:.1f}".format(str(close_data), vm_item['idle']))
|
|
|
|
time.sleep(600)
|
|
THIS_TIME = datetime.now()
|
|
|
|
return
|
|
|
|
def updteTodayStock(self, db_filename, stock_code, today_str):
|
|
bsLine, data = self.labelChecker.makeCandidate(stock_code, today_str)
|
|
self.labelChecker.updateLabel(db_filename, stock_code, bsLine, data, today_str)
|
|
return
|
|
|
|
def get_today_stock(self):
|
|
today_stock = set()
|
|
file_list = os.listdir(os.path.join(self.RESOURCE_PATH, 'analysis', '종목선택'))
|
|
for filename in file_list:
|
|
# '20240130_2_daily_최적_타이밍_후보__1162_넥스틸_092790.html'
|
|
#pattern = '([0-9]+)_[1-9]_daily_최적_타이밍_후보__[0-9]+_([ㄱ-ㅎ가-힣a-zA-Z0-9]+)_([0-9]+)\.html'
|
|
pattern = '([0-9]+)_[1-9]_daily_final_candidate__[0-9]+_.*_([0-9]+)\.html'
|
|
info = re.search(pattern, filename)
|
|
if info is None:
|
|
continue
|
|
|
|
date_str = datetime.strptime(info.group(1), "%Y%m%d").strftime("%Y%m%d")
|
|
if date_str == datetime.today().strftime("%Y%m%d") or date_str == (datetime.today() - timedelta(days=1)).strftime("%Y%m%d"):
|
|
today_stock.add(info.group(2))
|
|
|
|
return list(today_stock)
|
|
|
|
if __name__ == "__main__":
|
|
today = datetime.today()
|
|
|
|
PROJECT_HOME = os.getcwd()
|
|
RESOURCE_PATH = os.path.join(PROJECT_HOME, "resources")
|
|
|
|
hts = HTS_Stocks(RESOURCE_PATH)
|
|
hts.connect2DB("hts.db")
|
|
hts.connect2StockDB()
|
|
|
|
today_str = today.strftime('%Y%m%d')
|
|
hts.buyRealTime(today_str)
|
|
|
|
hts.disconnectStockDB()
|
|
hts.disconnect()
|
|
|
|
print ("done...")
|