Files
DeepStock/HTS_etf_short.py
dsyoon 1489508d8e init
2023-10-26 23:03:30 +09:00

359 lines
15 KiB
Python

import time
import os
import math
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.LabelChecker import LabelChecker
from stock.util.TelegramBot import TelegramBot
from stock.analysis.StockStatus import StockStatus
class HTS_etf (HTS):
RESOURCE_PATH = None
stock_code = None
buy_count = None
orderChecker = None
buySellChecker = None
labelChecker = None
bot = None
stockStatus = None
def __init__(self, RESOURCE_PATH):
super().__init__(RESOURCE_PATH)
self.RESOURCE_PATH = RESOURCE_PATH
self.orderChecker = OrderChecker(self.RESOURCE_PATH, "ETF")
self.buySellChecker = BuySellChecker()
self.labelChecker = LabelChecker(RESOURCE_PATH)
self.bot = TelegramBot()
self.stockStatus = StockStatus(RESOURCE_PATH)
return
def connect2StockDB(self):
self.conn_stock = sqlite3.connect(os.path.join(self.RESOURCE_PATH, "resources/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, bs_sell_price=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 and bs_sell_price is not None:
if jangoDic[code]['매도가능'] > 0:
if 2 < jangoDic[code]['평가손익']:
self.requestOrder(OrderType.sell, code[1:], jangoDic[code]['매도가능'], bs_sell_price)
self.bot.post(code, jangoDic[code]['종목명'], "SELL", bs_sell_price, jangoDic[code]['매도가능'])
check = True
else:
continue
else:
if jangoDic[code]['매도가능'] > 0:
if 3 < jangoDic[code]['평가손익']:
# 3% 이상 시 수익 매도
currentStock = self.currentStock(code[1:])
self.requestOrder(OrderType.sell, code[1:], jangoDic[code]['매도가능'], currentStock['close'])
self.bot.post(code, jangoDic[code]['종목명'], "SELL", currentStock['close'], jangoDic[code]['매도가능'])
check = True
return check
def getSellingPrice(self, log_time, stock_code, final_price, without_loss=False):
# final_price와 diff를 받으면, 해당 가격으로 그냥 매도한다는 의미
# final_price와 diff가 None이면 장부가와 final 중 max로 팔겠다는 의미
# final_price가 0이고 diff가 None이면 장부가로 팔겠다는 의미임
orderNum = None
jangoDic = self.requstJango()
if jangoDic and len(jangoDic.keys()) > 0:
for code in jangoDic:
if jangoDic[code]['매도가능'] > 0:
if without_loss:
if jangoDic[code]['장부가']*0.07 < jangoDic[code]['장부가'] - final_price:
sell_price = jangoDic[code]['장부가']
if code == "A" + stock_code:
orderNum = self.requestOrder(OrderType.sell, stock_code, jangoDic[code]['매도가능'], sell_price)
return orderNum, log_time.strftime('%Y%m%d %H%M%S'), jangoDic[code]['매도가능'], sell_price
else:
max_price = max(jangoDic[code]['장부가'], final_price)
sell_price = (int(max_price) - int(max_price) % 5) + 5
if code == "A"+stock_code:
orderNum = self.requestOrder(OrderType.sell, stock_code, jangoDic[code]['매도가능'], sell_price)
return orderNum, log_time.strftime('%Y%m%d %H%M%S'), jangoDic[code]['매도가능'], sell_price
return orderNum, None, None, None
def makeTickData(self, data, mins=30):
result = {"check": set(),
"time": [],
"open": [],
"close": [],
"high": [],
"low": [],
"vol": [],
"label": []}
for i in range(mins, len(data['time'])+1):
result["check"].add(data['time'][i-1])
result["time"].append(data['time'][i-1])
result["open"].append(data['open'][i-mins])
result["close"].append(data['close'][i-1])
result["high"].append(max(data['high'][i - mins: i]))
result["low"].append(min(data['low'][i - mins: i]))
result["vol"].append(sum(data['vol'][i - mins: i]))
return result
def getStockType(self, stock_code, short=False):
slow_k, p_slow_k, slow_k_week, p_slow_k_week, slow_k_month, p_slow_k_month = -1, -1, -1, -1, -1, -1
self.cursor_stock.execute('select stochastic_slow_k, max(ymd) from stock_analysis where code=? group by 1 order by ymd desc',(stock_code,))
items = self.cursor_stock.fetchall()
if items is not None and len(items) > 1:
for i, item in enumerate(items):
if i == 0:
slow_k = item[0]
elif i == 1:
p_slow_k = item[0]
else:
break
self.cursor_stock.execute('select stochastic_slow_k, max(ymd) from stock_analysis_weekly where code=? group by 1 order by ymd desc', (stock_code, ))
items = self.cursor_stock.fetchall()
if items is not None and len(items) > 1:
for i, item in enumerate(items):
if i == 0:
slow_k_week = item[0]
elif i == 1:
p_slow_k_week = item[0]
else:
break
self.cursor_stock.execute('select stochastic_slow_k, max(ymd) from stock_analysis_monthly where code=? group by 1 order by ymd desc',(stock_code,))
items = self.cursor_stock.fetchall()
if items is not None and len(items) > 1:
for i, item in enumerate(items):
if i == 0:
slow_k_month = item[0]
elif i == 1:
p_slow_k_month = item[0]
else:
break
if slow_k is None or p_slow_k is None:
slow_k , p_slow_k = -1, -1
if slow_k_week is None or p_slow_k_week is None:
slow_k_week, p_slow_k_week = -1, -1
if slow_k_month is None or p_slow_k_month is None:
slow_k_month, p_slow_k_month = -1, -1
type_stock = {'day':1, 'week':10, 'month':100}
if short:
if slow_k < 10: type_stock['day'] = 10
if 10 < slow_k < 15: type_stock['day'] = 7.5
if 15 < slow_k < 20: type_stock['day'] = 5
if 20 < slow_k < 25: type_stock['day'] = 2.5
if slow_k_week < 10: type_stock['week'] = 100
if 10 < slow_k_week < 15: type_stock['week'] = 75
if 15 < slow_k_week < 20: type_stock['week'] = 50
if 20 < slow_k_week < 25: type_stock['week'] = 25
if slow_k_month < 10: type_stock['month'] = 1000
if 10 < slow_k_month < 15: type_stock['month'] = 750
if 15 < slow_k_month < 20: type_stock['month'] = 500
if 20 < slow_k_month < 25: type_stock['month'] = 250
else:
if slow_k > 90: type_stock['day'] = 10
if 85 < slow_k < 90: type_stock['day'] = 7.5
if 80 < slow_k < 85: type_stock['day'] = 5
if 75 < slow_k < 80: type_stock['day'] = 2.5
if slow_k_week > 90: type_stock['week'] = 100
if 85 < slow_k_week < 90: type_stock['week'] = 75
if 80 < slow_k_week < 85: type_stock['week'] = 50
if 75 < slow_k_week < 80: type_stock['week'] = 25
if slow_k_month > 90: type_stock['month'] = 1000
if 85 < slow_k_month < 90: type_stock['month'] = 750
if 80 < slow_k_month < 85: type_stock['month'] = 500
if 75 < slow_k_month < 80: type_stock['month'] = 250
return type_stock
def getBuyCount(self, bs_buy_price, kospi_type, stock_type):
base_price = 10000
log_base = 1.2
p_k_m, p_k_w, p_k_d, p_s_m, p_s_w, p_s_d = 0.3, 0.2, 0.05, 0.25, 0.18, 0.02
weight_1, weight_2, weight_3, weight_4, weight_5 = 0.5, 0.3, 0.14, 0.05, 0.01
kospi_weight = weight_5
if kospi_type['day'] == 10: kospi_weight = weight_1
if kospi_type['day'] == 7.5: kospi_weight = weight_2
if kospi_type['day'] == 5: kospi_weight = weight_3
if kospi_type['day'] == 2.5: kospi_weight = weight_4
stock_weight = weight_5
if stock_type['day'] == 10: stock_weight = weight_1
if stock_type['day'] == 7.5: stock_weight = weight_2
if stock_type['day'] == 5: stock_weight = weight_3
if stock_type['day'] == 2.5: stock_weight = weight_4
max_price = math.log(
kospi_weight * p_k_m * kospi_type['month'] +
kospi_weight * p_k_w * kospi_type['week'] +
kospi_weight * p_k_d * kospi_type['day'] +
stock_weight * p_s_m * stock_type['month'] +
stock_weight * p_s_w * stock_type['week'] +
stock_weight * p_s_d * stock_type['day'], log_base) * base_price
buy_count = 0
if max_price > 1:
buy_count = int(math.floor(max_price / bs_buy_price))
return buy_count
def buyRealTime(self, today, stocks, analyzed_day=1000):
print ("START...")
THIS_TIME = datetime.now()
kospi_type = self.getStockType("^KS11", short=False)
LAST_DATA = {}
for stock in stocks:
LAST_DATA[stock['stock_code']] = self.getLastData(stock['stock_code'], today)
while datetime.strptime(today + " 070000", '%Y%m%d %H%M%S') < THIS_TIME < datetime.strptime(today + " 153100", '%Y%m%d %H%M%S'):
if datetime.strptime(today + " 090000", '%Y%m%d %H%M%S') < THIS_TIME < datetime.strptime(today + " 151500", '%Y%m%d %H%M%S'):
# 매도를 체크한다.
# self.sellStocks()
for idx, stock in enumerate(stocks):
time.sleep(0.1)
print("%5d: %8s, %-50s"%(idx, stock['stock_code'], stock['stock_name']))
try:
# 데이터를 가지고 온다.
data = self.getRealTime(stock['stock_code'], today, LAST_DATA[stock['stock_code']])
except:
print("#ERROR:", stock['stock_code'], stock['stock_name'])
continue
# 현재 매수가
bs_buy_price = data["close"][len(data["close"]) - 1]
# 미체결 기록을 가져와서 10분 이상 된 매수 주문을 취소 한다.
ORDER_LIST = self.requestOrderList()
orderListToCancel = self.orderChecker.cancel(today, "A" + stock['stock_code'], ORDER_LIST, mins=10)
if len(orderListToCancel) > 0:
self.cancelOrderList(orderListToCancel)
if bs_buy_price > 1000:
if not self.orderChecker.exist(today, "A" + stock['stock_code'], hours=5):
stock_type = self.getStockType(stock['stock_code'], short=True)
buy_count = self.getBuyCount(bs_buy_price, kospi_type, stock_type)
if buy_count > 0:
# 매수를 주문한다.
orderNum = self.requestOrder(OrderType.buy, stock['stock_code'], buy_count , bs_buy_price)
self.orderChecker.buy(today, "A" + stock['stock_code'], buy_count, bs_buy_price, orderNum)
# bot에 메시지를 보냄
self.bot.post(stock['stock_code'], stock['stock_name'], "BUY", bs_buy_price, buy_count)
# 로그 출력
print("BUY", THIS_TIME.strftime('%Y%m%d %H%M%S'), orderNum, stock['stock_code'], stock['stock_name'], bs_buy_price, buy_count)
# 로그 출력
print("TIMECHECK: %s, code: %s, name: %s, buy: %d, avg5: %.2f, avg30: %.2f, open: %d, high: %d, low: %d, slow_k: %.2f" %
(str(THIS_TIME), stock['stock_code'], stock['stock_name'], bs_buy_price, data["avg5"][0], data["avg30"][0],
data["open"][0], data["high"][0], data["low"][0], data["slow_k"][0]))
"""
elif datetime.strptime(today + " 151530", '%Y%m%d %H%M%S') < THIS_TIME < datetime.strptime(today + " 151600", '%Y%m%d %H%M%S'):
# 3시 15분 30초부터 3시 16분 사이는 잔량을 매도한다.
if not final_sell_check:
####
# 손해 보지 않는 가격에 매도한다.
####
for stock in stocks:
# 주문 리스트를 가져온다.
orderList = self.requestOrderList()
# 15:10:00 이후라면 모든 미체결 취소한다.
self.cancelOrderList(orderList)
# 매도 가격을 가져온다.
result = self.getRealTime(stock['stock_code'], today, LAST_DATA[stock['stock_code']])
final_price = result["close"][len(result["close"]) - 1]
orderNum, sell_time, jango, sell_price = self.getSellingPrice(THIS_TIME, stock['stock_code'], final_price, without_loss=True)
# 로그 출력
print("SELL", sell_time, stock['stock_code'], stock['stock_name'], final_price, str(orderNum), jango, sell_price)
final_sell_check = True
"""
time.sleep(3600)
THIS_TIME = datetime.now()
return True
def updteTodayStock(self, stock_code, today_str):
bsLine, data = self.labelChecker.makeCandidate(stock_code, today_str)
self.labelChecker.updateLabel(stock_code, bsLine, data, today_str)
return
if __name__ == "__main__":
today = datetime.today()
PROJECT_HOME = os.getcwd()
RESOURCE_PATH = os.path.join(PROJECT_HOME, "resources")
# KODEX 인버스 * 2
stocks = [
{"stock_code": "252670", "stock_name": "KODEX 200선물인버스2X"}
]
hts = HTS_etf(RESOURCE_PATH)
hts.connect2DB("hts.db")
hts.connect2StockDB()
today_str = today.strftime('%Y%m%d')
hts.buyRealTime(today_str, stocks, analyzed_day=1000)
db_filename = os.path.join(RESOURCE_PATH, "hts.db")
hts.insertStockData(stocks, today)
hts.disconnectStockDB()
hts.disconnect()
print ("done...")