This commit is contained in:
dsyoon
2023-10-24 00:15:18 +09:00
parent 1314c20f9d
commit 6537525a0a
6 changed files with 108 additions and 1206 deletions

View File

@@ -1,8 +1,7 @@
import time
import os
import math
import sqlite3
from datetime import datetime, timedelta
from datetime import datetime
from hts.HTS import HTS
from hts.OrderType import OrderType
@@ -16,7 +15,9 @@ from stock.analysis.StockStatus import StockStatus
class HTS_etf(HTS):
RESOURCE_PATH = None
SELL_GAP = None
stock_code = None
stock_name = None
buy_count = None
orderChecker = None
buySellChecker = None
@@ -24,12 +25,15 @@ class HTS_etf(HTS):
slackBot = None
stockStatus = None
def __init__(self, RESOURCE_PATH):
def __init__(self, RESOURCE_PATH, stock_code, stock_name, SELL_GAP):
super().__init__(RESOURCE_PATH)
self.RESOURCE_PATH = RESOURCE_PATH
self.orderChecker = OrderChecker(self.RESOURCE_PATH, "ETF")
self.SELL_GAP = SELL_GAP
self.stock_code = stock_code
self.stock_name = stock_name
self.orderChecker = OrderChecker(self.RESOURCE_PATH, self.stock_code)
self.buySellChecker = BuySellChecker()
self.labelChecker = LabelChecker(RESOURCE_PATH)
self.slackBot = SlackBot()
@@ -37,18 +41,21 @@ class HTS_etf(HTS):
return
def connect2StockDB(self):
def getTodayRSI(self, dbfile_name="stock.db"):
try:
conn = sqlite3.connect(os.path.join(self.RESOURCE_PATH, dbfile_name))
cursor = conn.cursor()
self.conn_stock = sqlite3.connect(os.path.join(self.RESOURCE_PATH, "resources/stock.db"))
self.cursor_stock = self.conn_stock.cursor()
cursor.execute('SELECT rsi FROM stock_analysis WHERE CODE=? order by ymd desc', (self.stock_code,))
db_result = cursor.fetchall()
cursor.close()
conn.close()
return
def disconnectStockDB(self):
self.cursor_stock.close()
self.conn_stock.close()
return
if db_result is not None:
return db_result[0][0]
except:
return 100
return 100
def sellStocks(self, stock_code=None, bs_sell_price=None):
check = False
@@ -56,23 +63,24 @@ class HTS_etf(HTS):
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.slackBot.post_to_slack(code, jangoDic[code]['종목명'], "SELL", bs_sell_price,
jangoDic[code]['매도가능'])
check = True
else:
continue
if code == "A" + stock_code:
if bs_sell_price is not None:
if jangoDic[code]['매도가능'] > 0:
if jangoDic[code]['평가손익'] < -1.5 or 1 < jangoDic[code]['평가손익'] or self.SELL_GAP < jangoDic[code]['평가금액']-jangoDic[code]['매입금액']:
# 1.5% 손해 혹은 2% 이상 시 수익 매도
self.requestOrder(OrderType.sell, code[1:], jangoDic[code]['매도가능'], bs_sell_price)
check = True
else:
if jangoDic[code]['매도가능'] > 0:
if jangoDic[code]['평가손익'] < -1.5 or 1 < jangoDic[code]['평가손익'] or self.SELL_GAP < jangoDic[code]['평가금액']-jangoDic[code]['매입금액']:
# 1.5% 손해 혹은 2% 이상 시 수익 매도
self.requestOrder(OrderType.sell, code[1:], jangoDic[code]['매도가능'], jangoDic[code]['현재가'])
check = True
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.slackBot.post_to_slack(code, jangoDic[code]['종목명'], "SELL", currentStock['close'],
jangoDic[code]['매도가능'])
if jangoDic[code]['평가손익'] < -1.5 or 1 < jangoDic[code]['평가손익'] or self.SELL_GAP < jangoDic[code]['평가금액']-jangoDic[code]['매입금액']:
# 1.5% 손해 혹은 2% 이상 시 수익 매도
self.requestOrder(OrderType.sell, code[1:], jangoDic[code]['매도가능'], jangoDic[code]['현재가'])
check = True
return check
@@ -89,8 +97,7 @@ class HTS_etf(HTS):
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)
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)
@@ -122,247 +129,86 @@ class HTS_etf(HTS):
return result
def getSlowK(self, stock_code):
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
return slow_k, p_slow_k, slow_k_week, p_slow_k_week, slow_k_month, p_slow_k_month
def getBuyCount(self, stock_code, bs_buy_price, slow_k_kospi, p_slow_k_kospi, slow_k_week_kospi,
p_slow_k_week_kospi, slow_k_month_kospi, p_slow_k_month_kospi):
base_price = 10000
# kospi 상태 파악
type_kospi = {'day': 1, 'week': 1, 'month': 1}
if slow_k_kospi < p_slow_k_kospi:
if slow_k_kospi < 20: type_kospi['day'] = 4
if 20 < slow_k_kospi < 30: type_kospi['day'] = 3
if 30 < slow_k_kospi < 40: type_kospi['day'] = 2
if slow_k_week_kospi < p_slow_k_week_kospi:
if slow_k_week_kospi < 20: type_kospi['week'] = 4
if 20 < slow_k_week_kospi < 30: type_kospi['week'] = 3
if 30 < slow_k_week_kospi < 40: type_kospi['week'] = 2
if slow_k_month_kospi < p_slow_k_month_kospi:
if slow_k_month_kospi < 20: type_kospi['month'] = 4
if 20 < slow_k_month_kospi < 30: type_kospi['month'] = 3
if 30 < slow_k_month_kospi < 40: type_kospi['month'] = 2
type_stock = {'day': 1, 'week': 1, 'month': 1}
slow_k, p_slow_k, slow_k_week, p_slow_k_week, slow_k_month, p_slow_k_month = self.getSlowK(stock_code)
if slow_k < p_slow_k:
if slow_k < 20: type_stock['day'] = 4
if 20 < slow_k < 30: type_stock['day'] = 3
if 30 < slow_k < 40: type_stock['day'] = 2
if slow_k_week < p_slow_k_week:
if slow_k_week < 20: type_stock['week'] = 4
if 20 < slow_k_week < 30: type_stock['week'] = 3
if 30 < slow_k_week < 40: type_stock['week'] = 2
if slow_k_month < p_slow_k_month:
if slow_k_month < 20: type_stock['month'] = 4
if 20 < slow_k_month < 30: type_stock['month'] = 3
if 30 < slow_k_month < 40: type_stock['month'] = 2
if (type_kospi['day'] == 1 and type_kospi['week'] == 1 and type_kospi['month'] == 1 and
type_stock['day'] == 1 and type_stock['week'] == 1 and type_stock['month'] == 1):
return 0
if stock_code == "252670": # "KODEX 200선물인버스2X"
base_price = 100000
max_price = math.log(
type_kospi['day'] * type_kospi['week'] * type_kospi['month'] * type_stock['day'] * type_stock['week'] *
type_stock['month'], 1.3) * base_price
if stock_code == "122630": # "KODEX 레버리지"
base_price = 100000
max_price_tmp = math.log(
type_kospi['day'] * type_kospi['week'] * type_kospi['month'] * type_stock['day'] * type_stock['week'] *
type_stock['month'], 1.3) * base_price
max_price = max_price_tmp - max_price
buy_count = int(math.floor(max_price / bs_buy_price))
return buy_count
def buyRealTime(self, today, stocks, analyzed_day=1000):
def buyRealTime(self, today, analyzed_day=1000, MAX_PRICE=10000, logFp=None):
rsi = self.getTodayRSI()
if rsi > 79:
self.slackBot.sendMsg("exit... {} ({}) RSI: {}".format(self.stock_code, self.stock_name, rsi))
return
print("START...")
THIS_TIME = datetime.now()
slow_k_kospi, p_slow_k_kospi, slow_k_week_kospi, p_slow_k_week_kospi, slow_k_month_kospi, p_slow_k_month_kospi = self.getSlowK(
"^KS11")
LAST_DATA = self.getLastData(self.stock_code, today)
LAST_DATA = {}
for stock in stocks:
LAST_DATA[stock['stock_code']] = self.getLastData(stock['stock_code'], today)
while datetime.strptime(today + " 063000", '%Y%m%d %H%M%S') < THIS_TIME < datetime.strptime(today + " 153100",'%Y%m%d %H%M%S'):
if THIS_TIME < datetime.strptime(today + " 085500", '%Y%m%d %H%M%S'):
self.slackBot.sendMsg("WAIT... {} ({}) RSI: {}".format(self.stock_code, self.stock_name, rsi))
if datetime.strptime(today + " 090000", '%Y%m%d %H%M%S') < THIS_TIME < datetime.strptime(today + " 090100", '%Y%m%d %H%M%S'):
self.slackBot.sendMsg("START... {} ({}) RSI: {}".format(self.stock_code, self.stock_name, rsi))
logFp.write("START {} ({}) RSI: {}\n".format(self.stock_code, self.stock_name, rsi))
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'):
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()
self.sellStocks(self.stock_code)
for idx, stock in enumerate(stocks):
time.sleep(0.1)
time.sleep(0.1)
try:
# 데이터를 가지고 온다.
result = self.getRealTime(self.stock_code, today, LAST_DATA)
except:
print("#ERROR:", self.stock_code)
continue
print("%5d: %8s, %-50s" % (idx, stock['stock_code'], stock['stock_name']))
data = self.buySellChecker.analyze(result)
data.drop(data.index[:len(data) - analyzed_day], inplace=True)
try:
# 데이터를 가지고 온다.
result = self.getRealTime(stock['stock_code'], today, LAST_DATA[stock['stock_code']])
except:
print("#ERROR:", stock['stock_code'], stock['stock_name'])
continue
# 사야 할 시점과 팔아야 할 시점을 체크한다.
bsLine = self.buySellChecker.checkTransaction(self.stock_code, data, None, None, isRealTime=True)
bs_buy_price = bsLine['buy'][0]
bs_buy_weight = bsLine['buy_weight'][0]
bs_sell_price = bsLine['sell'][0]
result_5 = self.makeTickData(result, mins=5)
result_30 = self.makeTickData(result, mins=30)
if len(result_30['time']) < 100:
continue
# 미체결 기록을 가져와서 10분 이상 된 매수 주문을 취소 한다.
ORDER_LIST = self.requestOrderList()
orderListToCancel = self.orderChecker.cancel(today, "A" + self.stock_code, ORDER_LIST, mins=10)
if len(orderListToCancel) > 0:
self.cancelOrderList(orderListToCancel)
data = self.buySellChecker.analyze(result)
data.drop(data.index[:len(data) - analyzed_day], inplace=True)
if bs_buy_price > 1000:
# 5분 이동평균, RSI, MACD, 일목균형, 볼린저밴드 상/하단을 계산한다.
data_5 = self.buySellChecker.analyze(result_5)
# 분석일 데이터만 활용한다 (이전 데이터는 제거)
data_5.drop(data_5.index[:len(data_5) - analyzed_day], inplace=True)
#if not self.orderChecker.exist(today, "A" + self.stock_code, hours=9):
buy_count = int(MAX_PRICE / bs_buy_price)
# 30분 이동평균, RSI, MACD, 일목균형, 볼린저밴드 상/하단을 계산한다.
data_30 = self.buySellChecker.analyze(result_30)
# 분석일 데이터만 활용한다 (이전 데이터는 제거)
data_30.drop(data_30.index[:len(data_30) - analyzed_day], inplace=True)
if buy_count > 0:
# 매수를 주문한다.
orderNum = self.requestOrder(OrderType.buy, self.stock_code, buy_count, bs_buy_price)
self.orderChecker.buy(today, "A" + self.stock_code, buy_count, bs_buy_price, orderNum)
# 사야 할 시점과 팔아야 할 시점을 체크한다.
bsLine = self.buySellChecker.checkTransaction(data, data_5, data_30, isRealTime=True)
bs_buy_price = bsLine['buy'][0]
bs_buy_weight = bsLine['buy_weight'][0]
bs_sell_price = bsLine['sell'][0]
# 로그 출력
print("BUY", THIS_TIME.strftime('%Y%m%d %H%M%S'), orderNum, self.stock_code, bs_buy_price, buy_count)
logFp.write("{} BUY {} {} {}\n".format(THIS_TIME.strftime('%Y%m%d %H%M%S'), self.stock_code, bs_buy_price, buy_count))
# 미체결 기록을 가져와서 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_sell_price > 1000:
check = self.sellStocks(self.stock_code, bs_sell_price)
if bs_buy_price > 1000:
if check:
# 로그 출력
print("SELL", THIS_TIME.strftime('%Y%m%d %H%M%S'), self.stock_code, self.stock_name, bs_sell_price)
logFp.write("{} SELL {} {} {}\n".format(THIS_TIME.strftime('%Y%m%d %H%M%S'), self.stock_code, bs_buy_price, bs_sell_price))
if not self.orderChecker.exist(today, "A" + stock['stock_code'], hours=9):
buy_count = self.getBuyCount(stock['stock_code'], bs_buy_price, slow_k_kospi,
p_slow_k_kospi, slow_k_week_kospi, p_slow_k_week_kospi,
slow_k_month_kospi, p_slow_k_month_kospi)
# 로그 출력
print("TIMECHECK: %s, code: %s, buy: %d, sell: %d, open: %d, close: %d, high: %d, low: %d, macd: %.2f" %
(str(THIS_TIME), self.stock_code, bs_buy_price, bs_sell_price, data["open"][len(data["open"])-1], data["close"][len(data["close"])-1], data["high"][len(data["high"])-1], data["low"][len(data["low"])-1], data["macd"][len(data["macd"])-1]))
logFp.write("TIMECHECK: %s, code: %s, buy: %d, sell: %d, open: %d, close: %d, high: %d, low: %d, macd: %.2f\n" %
(str(THIS_TIME), self.stock_code, bs_buy_price, bs_sell_price, data["open"][len(data["open"])-1], data["close"][len(data["close"])-1], data["high"][len(data["high"])-1], data["low"][len(data["low"])-1], data["macd"][len(data["macd"])-1]))
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)
if (int(THIS_TIME.strftime("%M")) % 50 == 0 or int(THIS_TIME.strftime("%M")) % 20 == 0):
self.slackBot.post_live_to_slack(self.stock_code, self.stock_name, data["close"][len(data["close"])-1], data["macd"][len(data["macd"])-1])
# slackbot에 메시지를 보냄
self.slackBot.post_to_slack(stock['stock_code'], stock['stock_name'], "BUY",
bsLine['buy'][len(bsLine['buy']) - 1], 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)
if bs_sell_price > 1000:
check = self.sellStocks(stock['stock_code'], bs_sell_price)
if check:
# slackbot에 메시지를 보냄
self.slackBot.post_to_slack(stock['stock_code'], stock['stock_name'], "SELL", bs_sell_price,
'ALL')
# 로그 출력
print("SELL", THIS_TIME.strftime('%Y%m%d %H%M%S'), stock['stock_code'], stock['stock_name'],
bs_sell_price)
# 로그 출력
print(
"TIMECHECK: %s, code: %s, name: %s, buy: %d, sell: %d, avg5: %.2f, avg30: %.2f, open: %d, high: %d, low: %d, slow_k: %.2f, slow_k_5: %.2f, slow_k_30: %.2f" %
(str(THIS_TIME), stock['stock_code'], stock['stock_name'], bs_buy_price, bs_sell_price,
data["avg5"][0], data["avg30"][0],
data["open"][0], data["high"][0], data["low"][0], data["slow_k"][0], data_5["slow_k"][0],
data_30["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)
logFp.flush()
time.sleep(60)
THIS_TIME = datetime.now()
return True
@@ -371,74 +217,3 @@ class HTS_etf(HTS):
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"},
{"stock_code": "122630", "stock_name": "KODEX 레버리지"},
{"stock_code": "305720", "stock_name": "KODEX 2차전지산업"},
{"stock_code": "102780", "stock_name": "KODEX 삼성그룹"},
{"stock_code": "139260", "stock_name": "TIGER 200 IT"},
{"stock_code": "091180", "stock_name": "KODEX 자동차"},
{"stock_code": "401470", "stock_name": "KODEX K-메타버스액티브"},
{"stock_code": "329200", "stock_name": "TIGER 리츠부동산인프라"},
{"stock_code": "091170", "stock_name": "KODEX 은행"},
{"stock_code": "091160", "stock_name": "KODEX 반도체"},
{"stock_code": "161510", "stock_name": "ARIRANG 고배당주"},
{"stock_code": "228800", "stock_name": "TIGER 여행레저"},
{"stock_code": "150460", "stock_name": "TIGER 중국소비테마"},
{"stock_code": "143860", "stock_name": "TIGER 헬스케어"},
{"stock_code": "228810", "stock_name": "TIGER 미디어컨텐츠"},
{"stock_code": "139220", "stock_name": "TIGER 200 건설"},
{"stock_code": "139280", "stock_name": "TIGER 경기방어"},
{"stock_code": "322400", "stock_name": "HANARO e커머스"},
{"stock_code": "157490", "stock_name": "TIGER 소프트웨어"},
{"stock_code": "228790", "stock_name": "TIGER 화장품"},
{"stock_code": "139230", "stock_name": "TIGER 200 중공업"},
{"stock_code": "396500", "stock_name": "TIGER Fn반도체TOP10"},
{"stock_code": "365000", "stock_name": "TIGER KRX인터넷K-뉴딜"},
{"stock_code": "102970", "stock_name": "KODEX 증권"},
{"stock_code": "117680", "stock_name": "KODEX 철강"},
{"stock_code": "244580", "stock_name": "KODEX 바이오"},
{"stock_code": "266360", "stock_name": "KODEX 미디어&엔터테인먼트"},
{"stock_code": "375770", "stock_name": "KODEX 탄소효율그린뉴딜"},
{"stock_code": "364990", "stock_name": "TIGER KRX게임K-뉴딜"},
{"stock_code": "388420", "stock_name": "KBSTAR 비메모리반도체액티브"},
{"stock_code": "117460", "stock_name": "KODEX 에너지화학"},
{"stock_code": "300950", "stock_name": "KODEX 게임산업"},
{"stock_code": "266410", "stock_name": "KODEX 필수소비재"},
{"stock_code": "140700", "stock_name": "KODEX 보험"},
{"stock_code": "139270", "stock_name": "TIGER 200 금융"},
{"stock_code": "395160", "stock_name": "KODEX Fn시스템반도체"},
{"stock_code": "140710", "stock_name": "KODEX 운송"},
{"stock_code": "139240", "stock_name": "TIGER 200 철강소재"},
{"stock_code": "395150", "stock_name": "KODEX Fn웹툰&드라마"},
{"stock_code": "307510", "stock_name": "TIGER 의료기기"},
{"stock_code": "315270", "stock_name": "TIGER 200커뮤니케이션서비스"},
{"stock_code": "132030", "stock_name": "KODEX 골드선물(H)"},
{"stock_code": "144600", "stock_name": "KODEX 은선물(H)"},
{"stock_code": "261220", "stock_name": "KODEX WTI원유선물(H)"},
{"stock_code": "271050", "stock_name": "KODEX WTI원유선물인버스(H)"},
{"stock_code": "138910", "stock_name": "KODEX 구리선물(H)"}
]
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...")

View File

@@ -1,224 +1,6 @@
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.SlackBot import SlackBot
from stock.analysis.StockStatus import StockStatus
class HTS_etf(HTS):
RESOURCE_PATH = None
SELL_GAP = None
stock_code = None
stock_name = None
buy_count = None
orderChecker = None
buySellChecker = None
labelChecker = None
slackBot = None
stockStatus = None
def __init__(self, RESOURCE_PATH, stock_code, stock_name, SELL_GAP):
super().__init__(RESOURCE_PATH)
self.RESOURCE_PATH = RESOURCE_PATH
self.SELL_GAP = SELL_GAP
self.stock_code = stock_code
self.stock_name = stock_name
self.orderChecker = OrderChecker(self.RESOURCE_PATH, self.stock_code)
self.buySellChecker = BuySellChecker()
self.labelChecker = LabelChecker(RESOURCE_PATH)
self.slackBot = SlackBot()
self.stockStatus = StockStatus(RESOURCE_PATH)
return
def getTodayRSI(self, dbfile_name="stock.db"):
try:
conn = sqlite3.connect(os.path.join(self.RESOURCE_PATH, dbfile_name))
cursor = conn.cursor()
cursor.execute('SELECT rsi FROM stock_analysis WHERE CODE=? order by ymd desc', (self.stock_code,))
db_result = cursor.fetchall()
cursor.close()
conn.close()
if db_result is not None:
return db_result[0][0]
except:
return 100
return 100
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:
if bs_sell_price is not None:
if jangoDic[code]['매도가능'] > 0:
if jangoDic[code]['평가손익'] < -1.5 or 1 < jangoDic[code]['평가손익'] or self.SELL_GAP < jangoDic[code]['평가금액']-jangoDic[code]['매입금액']:
# 1.5% 손해 혹은 2% 이상 시 수익 매도
self.requestOrder(OrderType.sell, code[1:], jangoDic[code]['매도가능'], bs_sell_price)
check = True
else:
if jangoDic[code]['매도가능'] > 0:
if jangoDic[code]['평가손익'] < -1.5 or 1 < jangoDic[code]['평가손익'] or self.SELL_GAP < jangoDic[code]['평가금액']-jangoDic[code]['매입금액']:
# 1.5% 손해 혹은 2% 이상 시 수익 매도
self.requestOrder(OrderType.sell, code[1:], jangoDic[code]['매도가능'], jangoDic[code]['현재가'])
check = True
else:
if jangoDic[code]['매도가능'] > 0:
if jangoDic[code]['평가손익'] < -1.5 or 1 < jangoDic[code]['평가손익'] or self.SELL_GAP < jangoDic[code]['평가금액']-jangoDic[code]['매입금액']:
# 1.5% 손해 혹은 2% 이상 시 수익 매도
self.requestOrder(OrderType.sell, code[1:], jangoDic[code]['매도가능'], 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 buyRealTime(self, today, analyzed_day=1000, MAX_PRICE=10000, logFp=None):
rsi = self.getTodayRSI()
if rsi > 79:
self.slackBot.sendMsg("exit... {} ({}) RSI: {}".format(self.stock_code, self.stock_name, rsi))
return
print("START...")
THIS_TIME = datetime.now()
LAST_DATA = self.getLastData(self.stock_code, today)
while datetime.strptime(today + " 063000", '%Y%m%d %H%M%S') < THIS_TIME < datetime.strptime(today + " 153100",'%Y%m%d %H%M%S'):
if THIS_TIME < datetime.strptime(today + " 085500", '%Y%m%d %H%M%S'):
self.slackBot.sendMsg("WAIT... {} ({}) RSI: {}".format(self.stock_code, self.stock_name, rsi))
if datetime.strptime(today + " 090000", '%Y%m%d %H%M%S') < THIS_TIME < datetime.strptime(today + " 090100", '%Y%m%d %H%M%S'):
self.slackBot.sendMsg("START... {} ({}) RSI: {}".format(self.stock_code, self.stock_name, rsi))
logFp.write("START {} ({}) RSI: {}\n".format(self.stock_code, self.stock_name, rsi))
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(self.stock_code)
time.sleep(0.1)
try:
# 데이터를 가지고 온다.
result = self.getRealTime(self.stock_code, today, LAST_DATA)
except:
print("#ERROR:", self.stock_code)
continue
data = self.buySellChecker.analyze(result)
data.drop(data.index[:len(data) - analyzed_day], inplace=True)
# 사야 할 시점과 팔아야 할 시점을 체크한다.
bsLine = self.buySellChecker.checkTransaction(self.stock_code, data, None, None, isRealTime=True)
bs_buy_price = bsLine['buy'][0]
bs_buy_weight = bsLine['buy_weight'][0]
bs_sell_price = bsLine['sell'][0]
# 미체결 기록을 가져와서 10분 이상 된 매수 주문을 취소 한다.
ORDER_LIST = self.requestOrderList()
orderListToCancel = self.orderChecker.cancel(today, "A" + self.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" + self.stock_code, hours=9):
buy_count = int(MAX_PRICE / bs_buy_price)
if buy_count > 0:
# 매수를 주문한다.
orderNum = self.requestOrder(OrderType.buy, self.stock_code, buy_count, bs_buy_price)
self.orderChecker.buy(today, "A" + self.stock_code, buy_count, bs_buy_price, orderNum)
# 로그 출력
print("BUY", THIS_TIME.strftime('%Y%m%d %H%M%S'), orderNum, self.stock_code, bs_buy_price, buy_count)
logFp.write("{} BUY {} {} {}\n".format(THIS_TIME.strftime('%Y%m%d %H%M%S'), self.stock_code, bs_buy_price, buy_count))
if bs_sell_price > 1000:
check = self.sellStocks(self.stock_code, bs_sell_price)
if check:
# 로그 출력
print("SELL", THIS_TIME.strftime('%Y%m%d %H%M%S'), self.stock_code, self.stock_name, bs_sell_price)
logFp.write("{} SELL {} {} {}\n".format(THIS_TIME.strftime('%Y%m%d %H%M%S'), self.stock_code, bs_buy_price, bs_sell_price))
# 로그 출력
print("TIMECHECK: %s, code: %s, buy: %d, sell: %d, open: %d, close: %d, high: %d, low: %d, macd: %.2f" %
(str(THIS_TIME), self.stock_code, bs_buy_price, bs_sell_price, data["open"][len(data["open"])-1], data["close"][len(data["close"])-1], data["high"][len(data["high"])-1], data["low"][len(data["low"])-1], data["macd"][len(data["macd"])-1]))
logFp.write("TIMECHECK: %s, code: %s, buy: %d, sell: %d, open: %d, close: %d, high: %d, low: %d, macd: %.2f\n" %
(str(THIS_TIME), self.stock_code, bs_buy_price, bs_sell_price, data["open"][len(data["open"])-1], data["close"][len(data["close"])-1], data["high"][len(data["high"])-1], data["low"][len(data["low"])-1], data["macd"][len(data["macd"])-1]))
if (int(THIS_TIME.strftime("%M")) % 50 == 0 or int(THIS_TIME.strftime("%M")) % 20 == 0):
self.slackBot.post_live_to_slack(self.stock_code, self.stock_name, data["close"][len(data["close"])-1], data["macd"][len(data["macd"])-1])
logFp.flush()
time.sleep(60)
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
from datetime import datetime
from HTS_etf import HTS_etf
if __name__ == "__main__":
today = datetime.today()

View File

@@ -1,224 +1,6 @@
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.SlackBot import SlackBot
from stock.analysis.StockStatus import StockStatus
class HTS_etf(HTS):
RESOURCE_PATH = None
SELL_GAP = None
stock_code = None
stock_name = None
buy_count = None
orderChecker = None
buySellChecker = None
labelChecker = None
slackBot = None
stockStatus = None
def __init__(self, RESOURCE_PATH, stock_code, stock_name, SELL_GAP):
super().__init__(RESOURCE_PATH)
self.RESOURCE_PATH = RESOURCE_PATH
self.SELL_GAP = SELL_GAP
self.stock_code = stock_code
self.stock_name = stock_name
self.orderChecker = OrderChecker(self.RESOURCE_PATH, self.stock_code)
self.buySellChecker = BuySellChecker()
self.labelChecker = LabelChecker(RESOURCE_PATH)
self.slackBot = SlackBot()
self.stockStatus = StockStatus(RESOURCE_PATH)
return
def getTodayRSI(self, dbfile_name="stock.db"):
try:
conn = sqlite3.connect(os.path.join(self.RESOURCE_PATH, dbfile_name))
cursor = conn.cursor()
cursor.execute('SELECT rsi FROM stock_analysis WHERE CODE=? order by ymd desc', (self.stock_code,))
db_result = cursor.fetchall()
cursor.close()
conn.close()
if db_result is not None:
return db_result[0][0]
except:
return 100
return 100
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:
if bs_sell_price is not None:
if jangoDic[code]['매도가능'] > 0:
if jangoDic[code]['평가손익'] < -1.5 or 1 < jangoDic[code]['평가손익'] or self.SELL_GAP < jangoDic[code]['평가금액']-jangoDic[code]['매입금액']:
# 1.5% 손해 혹은 2% 이상 시 수익 매도
self.requestOrder(OrderType.sell, code[1:], jangoDic[code]['매도가능'], bs_sell_price)
check = True
else:
if jangoDic[code]['매도가능'] > 0:
if jangoDic[code]['평가손익'] < -1.5 or 1 < jangoDic[code]['평가손익'] or self.SELL_GAP < jangoDic[code]['평가금액']-jangoDic[code]['매입금액']:
# 1.5% 손해 혹은 2% 이상 시 수익 매도
self.requestOrder(OrderType.sell, code[1:], jangoDic[code]['매도가능'], jangoDic[code]['현재가'])
check = True
else:
if jangoDic[code]['매도가능'] > 0:
if jangoDic[code]['평가손익'] < -1.5 or 1 < jangoDic[code]['평가손익'] or self.SELL_GAP < jangoDic[code]['평가금액']-jangoDic[code]['매입금액']:
# 1.5% 손해 혹은 2% 이상 시 수익 매도
self.requestOrder(OrderType.sell, code[1:], jangoDic[code]['매도가능'], 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 buyRealTime(self, today, analyzed_day=1000, MAX_PRICE = 10000, logFp=None):
rsi = self.getTodayRSI()
if rsi > 79:
self.slackBot.sendMsg("exit... {} ({}) RSI: {}".format(self.stock_code, self.stock_name, rsi))
return
print("START...")
THIS_TIME = datetime.now()
LAST_DATA = self.getLastData(self.stock_code, today)
while datetime.strptime(today + " 063000", '%Y%m%d %H%M%S') < THIS_TIME < datetime.strptime(today + " 153100",'%Y%m%d %H%M%S'):
if THIS_TIME < datetime.strptime(today + " 085500", '%Y%m%d %H%M%S'):
self.slackBot.sendMsg("WAIT... {} ({}) RSI: {}".format(self.stock_code, self.stock_name, rsi))
if datetime.strptime(today + " 090000", '%Y%m%d %H%M%S') < THIS_TIME < datetime.strptime(today + " 090100", '%Y%m%d %H%M%S'):
self.slackBot.sendMsg("START... {} ({}) RSI: {}".format(self.stock_code, self.stock_name, rsi))
logFp.write("START {} ({}) RSI: {}\n".format(self.stock_code, self.stock_name, rsi))
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(self.stock_code)
time.sleep(0.1)
try:
# 데이터를 가지고 온다.
result = self.getRealTime(self.stock_code, today, LAST_DATA)
except:
print("#ERROR:", self.stock_code)
continue
data = self.buySellChecker.analyze(result)
data.drop(data.index[:len(data) - analyzed_day], inplace=True)
# 사야 할 시점과 팔아야 할 시점을 체크한다.
bsLine = self.buySellChecker.checkTransaction(self.stock_code, data, None, None, isRealTime=True)
bs_buy_price = bsLine['buy'][0]
bs_buy_weight = bsLine['buy_weight'][0]
bs_sell_price = bsLine['sell'][0]
# 미체결 기록을 가져와서 10분 이상 된 매수 주문을 취소 한다.
ORDER_LIST = self.requestOrderList()
orderListToCancel = self.orderChecker.cancel(today, "A" + self.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" + self.stock_code, hours=9):
buy_count = int(MAX_PRICE / bs_buy_price)
if buy_count > 0:
# 매수를 주문한다.
orderNum = self.requestOrder(OrderType.buy, self.stock_code, buy_count, bs_buy_price)
self.orderChecker.buy(today, "A" + self.stock_code, buy_count, bs_buy_price, orderNum)
# 로그 출력
print("BUY", THIS_TIME.strftime('%Y%m%d %H%M%S'), orderNum, self.stock_code, bs_buy_price, buy_count)
logFp.write("{} BUY {} {} {}\n".format(THIS_TIME.strftime('%Y%m%d %H%M%S'), self.stock_code, bs_buy_price, buy_count))
if bs_sell_price > 1000:
check = self.sellStocks(self.stock_code, bs_sell_price)
if check:
# 로그 출력
print("SELL", THIS_TIME.strftime('%Y%m%d %H%M%S'), self.stock_code, self.stock_name, bs_sell_price)
logFp.write("{} SELL {} {} {}\n".format(THIS_TIME.strftime('%Y%m%d %H%M%S'), self.stock_code, bs_buy_price, bs_sell_price))
# 로그 출력
print("TIMECHECK: %s, code: %s, buy: %d, sell: %d, open: %d, close: %d, high: %d, low: %d, macd: %.2f" %
(str(THIS_TIME), self.stock_code, bs_buy_price, bs_sell_price, data["open"][len(data["open"])-1], data["close"][len(data["close"])-1], data["high"][len(data["high"])-1], data["low"][len(data["low"])-1], data["macd"][len(data["macd"])-1]))
logFp.write("TIMECHECK: %s, code: %s, buy: %d, sell: %d, open: %d, close: %d, high: %d, low: %d, macd: %.2f\n" %
(str(THIS_TIME), self.stock_code, bs_buy_price, bs_sell_price, data["open"][len(data["open"])-1], data["close"][len(data["close"])-1], data["high"][len(data["high"])-1], data["low"][len(data["low"])-1], data["macd"][len(data["macd"])-1]))
if (int(THIS_TIME.strftime("%M")) % 50 == 0 or int(THIS_TIME.strftime("%M")) % 20 == 0):
self.slackBot.post_live_to_slack(self.stock_code, self.stock_name, data["close"][len(data["close"])-1], data["macd"][len(data["macd"])-1])
logFp.flush()
time.sleep(60)
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
from datetime import datetime
from HTS_etf import HTS_etf
if __name__ == "__main__":
today = datetime.today()

View File

@@ -1,224 +1,6 @@
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.SlackBot import SlackBot
from stock.analysis.StockStatus import StockStatus
class HTS_etf(HTS):
RESOURCE_PATH = None
SELL_GAP = None
stock_code = None
stock_name = None
buy_count = None
orderChecker = None
buySellChecker = None
labelChecker = None
slackBot = None
stockStatus = None
def __init__(self, RESOURCE_PATH, stock_code, stock_name, SELL_GAP):
super().__init__(RESOURCE_PATH)
self.RESOURCE_PATH = RESOURCE_PATH
self.SELL_GAP = SELL_GAP
self.stock_code = stock_code
self.stock_name = stock_name
self.orderChecker = OrderChecker(self.RESOURCE_PATH, self.stock_code)
self.buySellChecker = BuySellChecker()
self.labelChecker = LabelChecker(RESOURCE_PATH)
self.slackBot = SlackBot()
self.stockStatus = StockStatus(RESOURCE_PATH)
return
def getTodayRSI(self, dbfile_name="stock.db"):
try:
conn = sqlite3.connect(os.path.join(self.RESOURCE_PATH, dbfile_name))
cursor = conn.cursor()
cursor.execute('SELECT rsi FROM stock_analysis WHERE CODE=? order by ymd desc', (self.stock_code,))
db_result = cursor.fetchall()
cursor.close()
conn.close()
if db_result is not None:
return db_result[0][0]
except:
return 100
return 100
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:
if bs_sell_price is not None:
if jangoDic[code]['매도가능'] > 0:
if jangoDic[code]['평가손익'] < -1.5 or 1 < jangoDic[code]['평가손익'] or self.SELL_GAP < jangoDic[code]['평가금액']-jangoDic[code]['매입금액']:
# 1.5% 손해 혹은 2% 이상 시 수익 매도
self.requestOrder(OrderType.sell, code[1:], jangoDic[code]['매도가능'], bs_sell_price)
check = True
else:
if jangoDic[code]['매도가능'] > 0:
if jangoDic[code]['평가손익'] < -1.5 or 1 < jangoDic[code]['평가손익'] or self.SELL_GAP < jangoDic[code]['평가금액']-jangoDic[code]['매입금액']:
# 1.5% 손해 혹은 2% 이상 시 수익 매도
self.requestOrder(OrderType.sell, code[1:], jangoDic[code]['매도가능'], jangoDic[code]['현재가'])
check = True
else:
if jangoDic[code]['매도가능'] > 0:
if jangoDic[code]['평가손익'] < -1.5 or 1 < jangoDic[code]['평가손익'] or self.SELL_GAP < jangoDic[code]['평가금액']-jangoDic[code]['매입금액']:
# 1.5% 손해 혹은 2% 이상 시 수익 매도
self.requestOrder(OrderType.sell, code[1:], jangoDic[code]['매도가능'], 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 buyRealTime(self, today, analyzed_day=1000, MAX_PRICE = 10000, logFp=None):
rsi = self.getTodayRSI()
if rsi > 79:
self.slackBot.sendMsg("exit... {} ({}) RSI: {}".format(self.stock_code, self.stock_name, rsi))
return
print("START...")
THIS_TIME = datetime.now()
LAST_DATA = self.getLastData(self.stock_code, today)
while datetime.strptime(today + " 063000", '%Y%m%d %H%M%S') < THIS_TIME < datetime.strptime(today + " 153100",'%Y%m%d %H%M%S'):
if THIS_TIME < datetime.strptime(today + " 085500", '%Y%m%d %H%M%S'):
self.slackBot.sendMsg("WAIT... {} ({}) RSI: {}".format(self.stock_code, self.stock_name, rsi))
if datetime.strptime(today + " 090000", '%Y%m%d %H%M%S') < THIS_TIME < datetime.strptime(today + " 090100", '%Y%m%d %H%M%S'):
self.slackBot.sendMsg("START... {} ({}) RSI: {}".format(self.stock_code, self.stock_name, rsi))
logFp.write("START {} ({}) RSI: {}\n".format(self.stock_code, self.stock_name, rsi))
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(self.stock_code)
time.sleep(0.1)
try:
# 데이터를 가지고 온다.
result = self.getRealTime(self.stock_code, today, LAST_DATA)
except:
print("#ERROR:", self.stock_code)
continue
data = self.buySellChecker.analyze(result)
data.drop(data.index[:len(data) - analyzed_day], inplace=True)
# 사야 할 시점과 팔아야 할 시점을 체크한다.
bsLine = self.buySellChecker.checkTransaction(self.stock_code, data, None, None, isRealTime=True)
bs_buy_price = bsLine['buy'][0]
bs_buy_weight = bsLine['buy_weight'][0]
bs_sell_price = bsLine['sell'][0]
# 미체결 기록을 가져와서 10분 이상 된 매수 주문을 취소 한다.
ORDER_LIST = self.requestOrderList()
orderListToCancel = self.orderChecker.cancel(today, "A" + self.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" + self.stock_code, hours=9):
buy_count = int(MAX_PRICE / bs_buy_price)
if buy_count > 0:
# 매수를 주문한다.
orderNum = self.requestOrder(OrderType.buy, self.stock_code, buy_count, bs_buy_price)
self.orderChecker.buy(today, "A" + self.stock_code, buy_count, bs_buy_price, orderNum)
# 로그 출력
print("BUY", THIS_TIME.strftime('%Y%m%d %H%M%S'), orderNum, self.stock_code, bs_buy_price, buy_count)
logFp.write("{} BUY {} {} {}\n".format(THIS_TIME.strftime('%Y%m%d %H%M%S'), self.stock_code, bs_buy_price, buy_count))
if bs_sell_price > 1000:
check = self.sellStocks(self.stock_code, bs_sell_price)
if check:
# 로그 출력
print("SELL", THIS_TIME.strftime('%Y%m%d %H%M%S'), self.stock_code, self.stock_name, bs_sell_price)
logFp.write("{} SELL {} {} {}\n".format(THIS_TIME.strftime('%Y%m%d %H%M%S'), self.stock_code, bs_buy_price, bs_sell_price))
# 로그 출력
print("TIMECHECK: %s, code: %s, buy: %d, sell: %d, open: %d, close: %d, high: %d, low: %d, macd: %.2f" %
(str(THIS_TIME), self.stock_code, bs_buy_price, bs_sell_price, data["open"][len(data["open"])-1], data["close"][len(data["close"])-1], data["high"][len(data["high"])-1], data["low"][len(data["low"])-1], data["macd"][len(data["macd"])-1]))
logFp.write("TIMECHECK: %s, code: %s, buy: %d, sell: %d, open: %d, close: %d, high: %d, low: %d, macd: %.2f\n" %
(str(THIS_TIME), self.stock_code, bs_buy_price, bs_sell_price, data["open"][len(data["open"])-1], data["close"][len(data["close"])-1], data["high"][len(data["high"])-1], data["low"][len(data["low"])-1], data["macd"][len(data["macd"])-1]))
if (int(THIS_TIME.strftime("%M")) % 50 == 0 or int(THIS_TIME.strftime("%M")) % 20 == 0):
self.slackBot.post_live_to_slack(self.stock_code, self.stock_name, data["close"][len(data["close"])-1], data["macd"][len(data["macd"])-1])
logFp.flush()
time.sleep(60)
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
from datetime import datetime
from HTS_etf import HTS_etf
if __name__ == "__main__":
today = datetime.today()

View File

@@ -1,225 +1,6 @@
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.SlackBot import SlackBot
from stock.analysis.StockStatus import StockStatus
class HTS_etf(HTS):
RESOURCE_PATH = None
SELL_GAP = None
stock_code = None
stock_name = None
buy_count = None
orderChecker = None
buySellChecker = None
labelChecker = None
slackBot = None
stockStatus = None
def __init__(self, RESOURCE_PATH, stock_code, stock_name, SELL_GAP):
super().__init__(RESOURCE_PATH)
self.RESOURCE_PATH = RESOURCE_PATH
self.SELL_GAP = SELL_GAP
self.stock_code = stock_code
self.stock_name = stock_name
self.orderChecker = OrderChecker(self.RESOURCE_PATH, self.stock_code)
self.buySellChecker = BuySellChecker()
self.labelChecker = LabelChecker(RESOURCE_PATH)
self.slackBot = SlackBot()
self.stockStatus = StockStatus(RESOURCE_PATH)
return
def getTodayRSI(self, dbfile_name="stock.db"):
try:
conn = sqlite3.connect(os.path.join(self.RESOURCE_PATH, dbfile_name))
cursor = conn.cursor()
cursor.execute('SELECT rsi FROM stock_analysis WHERE CODE=? order by ymd desc', (self.stock_code,))
db_result = cursor.fetchall()
cursor.close()
conn.close()
if db_result is not None:
return db_result[0][0]
except:
return 100
return 100
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:
if bs_sell_price is not None:
if jangoDic[code]['매도가능'] > 0:
if jangoDic[code]['평가손익'] < -1.5 or 1 < jangoDic[code]['평가손익'] or self.SELL_GAP < jangoDic[code]['평가금액']-jangoDic[code]['매입금액']:
# 1.5% 손해 혹은 2% 이상 시 수익 매도
self.requestOrder(OrderType.sell, code[1:], jangoDic[code]['매도가능'], bs_sell_price)
check = True
else:
if jangoDic[code]['매도가능'] > 0:
if jangoDic[code]['평가손익'] < -1.5 or 1 < jangoDic[code]['평가손익'] or self.SELL_GAP < jangoDic[code]['평가금액']-jangoDic[code]['매입금액']:
# 1.5% 손해 혹은 2% 이상 시 수익 매도
self.requestOrder(OrderType.sell, code[1:], jangoDic[code]['매도가능'], jangoDic[code]['현재가'])
check = True
else:
if jangoDic[code]['매도가능'] > 0:
if jangoDic[code]['평가손익'] < -1.5 or 1 < jangoDic[code]['평가손익'] or self.SELL_GAP < jangoDic[code]['평가금액']-jangoDic[code]['매입금액']:
# 1.5% 손해 혹은 2% 이상 시 수익 매도
self.requestOrder(OrderType.sell, code[1:], jangoDic[code]['매도가능'], 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 buyRealTime(self, today, analyzed_day=1000, MAX_PRICE = 100000, logFp=None):
rsi = self.getTodayRSI()
if rsi > 79:
self.slackBot.sendMsg("exit... {} ({}) RSI: {}".format(self.stock_code, self.stock_name, rsi))
return
print("START...")
THIS_TIME = datetime.now()
LAST_DATA = self.getLastData(self.stock_code, today)
while datetime.strptime(today + " 063000", '%Y%m%d %H%M%S') < THIS_TIME < datetime.strptime(today + " 153100",'%Y%m%d %H%M%S'):
if THIS_TIME < datetime.strptime(today + " 085500", '%Y%m%d %H%M%S'):
self.slackBot.sendMsg("WAIT... {} ({}) RSI: {}".format(self.stock_code, self.stock_name, rsi))
if datetime.strptime(today + " 090000", '%Y%m%d %H%M%S') < THIS_TIME < datetime.strptime(today + " 090100", '%Y%m%d %H%M%S'):
self.slackBot.sendMsg("START... {} ({}) RSI: {}".format(self.stock_code, self.stock_name, rsi))
logFp.write("START {} ({}) RSI: {}\n".format(self.stock_code, self.stock_name, rsi))
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(self.stock_code)
time.sleep(0.1)
try:
# 데이터를 가지고 온다.
result = self.getRealTime(self.stock_code, today, LAST_DATA)
except:
print("#ERROR:", self.stock_code)
continue
data = self.buySellChecker.analyze(result)
data.drop(data.index[:len(data) - analyzed_day], inplace=True)
# 사야 할 시점과 팔아야 할 시점을 체크한다.
bsLine = self.buySellChecker.checkTransaction(self.stock_code, data, None, None, isRealTime=True)
bs_buy_price = bsLine['buy'][0]
bs_buy_weight = bsLine['buy_weight'][0]
bs_sell_price = bsLine['sell'][0]
# 미체결 기록을 가져와서 10분 이상 된 매수 주문을 취소 한다.
ORDER_LIST = self.requestOrderList()
orderListToCancel = self.orderChecker.cancel(today, "A" + self.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" + self.stock_code, hours=9):
buy_count = int(MAX_PRICE / bs_buy_price)
if buy_count > 0:
# 매수를 주문한다.
orderNum = self.requestOrder(OrderType.buy, self.stock_code, buy_count, bs_buy_price)
self.orderChecker.buy(today, "A" + self.stock_code, buy_count, bs_buy_price, orderNum)
# 로그 출력
print("BUY", THIS_TIME.strftime('%Y%m%d %H%M%S'), orderNum, self.stock_code, bs_buy_price, buy_count)
logFp.write("{} BUY {} {} {}\n".format(THIS_TIME.strftime('%Y%m%d %H%M%S'), self.stock_code, bs_buy_price, buy_count))
if bs_sell_price > 1000:
check = self.sellStocks(self.stock_code, bs_sell_price)
if check:
# 로그 출력
print("SELL", THIS_TIME.strftime('%Y%m%d %H%M%S'), self.stock_code, self.stock_name, bs_sell_price)
logFp.write("{} SELL {} {} {}\n".format(THIS_TIME.strftime('%Y%m%d %H%M%S'), self.stock_code, bs_buy_price, bs_sell_price))
# 로그 출력
print("TIMECHECK: %s, code: %s, buy: %d, sell: %d, open: %d, close: %d, high: %d, low: %d, macd: %.2f" %
(str(THIS_TIME), self.stock_code, bs_buy_price, bs_sell_price, data["open"][len(data["open"])-1], data["close"][len(data["close"])-1], data["high"][len(data["high"])-1], data["low"][len(data["low"])-1], data["macd"][len(data["macd"])-1]))
logFp.write("TIMECHECK: %s, code: %s, buy: %d, sell: %d, open: %d, close: %d, high: %d, low: %d, macd: %.2f\n" %
(str(THIS_TIME), self.stock_code, bs_buy_price, bs_sell_price, data["open"][len(data["open"])-1], data["close"][len(data["close"])-1], data["high"][len(data["high"])-1], data["low"][len(data["low"])-1], data["macd"][len(data["macd"])-1]))
if (int(THIS_TIME.strftime("%M")) % 50 == 0 or int(THIS_TIME.strftime("%M")) % 20 == 0):
self.slackBot.post_live_to_slack(self.stock_code, self.stock_name, data["close"][len(data["close"])-1], data["macd"][len(data["macd"])-1])
logFp.flush()
time.sleep(60)
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
from datetime import datetime
from HTS_etf import HTS_etf
if __name__ == "__main__":
today = datetime.today()

View File

@@ -274,10 +274,10 @@ if __name__ == "__main__":
#"122630": ['20230930'],
#"122630": ['20210901','20210902','20210903','20210906','20231012','20231013']
#"122630": ['20210901', '20210902', '20210903', '20210906', '20210907', '20210908', '20210909', '20210910', '20210913', '20210914', '20210915', '20210916', '20210917', '20210923', '20210924', '20210927', '20210928', '20210929', '20210930', '20211001', '20211005','20231012','20231013'],
"233740": ['20231019'],
"252670": ['20231019'],
"251340": ['20231019'],
"122630": ['20231019']
"233740": ['20231023'],
"252670": ['20231023'],
"251340": ['20231023'],
"122630": ['20231023']
}
#simulation.simulate(stock_codes)
simulation.simulate(stock_codes)